S&box Wiki

UI Basics

There's 2 good ways to make UI right now in s&box. You can either use Razor, or make Panels yourself. We recommend using Razor.

Making a Panel

Here's an example panel that has a Label which counts up forever.

MyPanel.cs

[UseTemplate] public class MyPanel : Panel { public Label MyLabel { get; set; } public override void Tick() { Label.Text = $"{Time.Now}"; } }

[UseTemplate] will load a template with the same class name (MyPanel.html).

MyPanel.html

<link rel="stylesheet" href="MyPanel.scss"/> <div> <label class="name" @ref="MyLabel">Placeholder Text</label> </div>

<link rel="stylesheet" href="MyPanel.scss"/> will load a stylesheet with the file name that you specify. It works on relative paths from your .html file.

MyPanel.scss

MyPanel { position: absolute; left: 64px; top: 64px; .name { font-family: Poppins; color: white; font-size: 32px; } }

Tips and Tricks

  • You can set Panel classes - See Panel.SetClass, and Panel.BindClass

  • If a panel is not behaving as expected you can troubleshoot it using the Panel Inspector. While in Editor Mode, open the Explorer and hit Panels.

image.png

Scaling

By default, UI is scaled based on 1080p.

To change how scaling works, override your hud's UpdateScale() method as such:

using Sandbox; using Sandbox.UI; public class Hud : RootPanel { protected override void UpdateScale( Rect screenSize ) { // Completely disables scaling Scale = 1; } }

Drawing Polygons

Example:

public class MyGUI : RootPanel { public override void DrawBackground(ref RenderState state) { // Obviously, don't declare this here every frame. But you get the idea. Span<Vertex> vertices = new Vertex[] { new Vertex( new Vector3( 100, 100 ), new Vector4( 0, 0, 0, 0 ), new Color32(255, 0, 0 ) ), new Vertex( new Vector3( 300, 100 ), new Vector4( 0, 0, 0, 0 ), new Color32(0, 255, 0 ) ), new Vertex( new Vector3( 300, 300 ), new Vector4( 0, 0, 0, 0 ), new Color32(0, 0, 255 ) ), }; var attribs = new RenderAttributes(); attribs.Set( "Texture", Texture.White ); Graphics.Draw( vertices, 3, Material.UI.Basic, attribs, Graphics.PrimitiveType.Triangles ); } }
image.png

Examples

These examples may be obsolete.

Example: HUD w/ health display

Down below you can see an example from our Sandbox gamemode.

SandboxHud implements the HudEntity<RootPanel> class and loads a stylesheet and all other UI components.

The Health class implements Panel and adds a bunch of stuff to the UI within its constructor. It also has access to the local player's health within the Tick-override, so the UI can be updated accordingly.

using Sandbox; using Sandbox.UI; [Library] public partial class SandboxHud : HudEntity<RootPanel> { public SandboxHud() { if ( !IsClient ) return; RootPanel.StyleSheet.Load( "/ui/SandboxHud.scss" ); RootPanel.AddChild<NameTags>(); RootPanel.AddChild<CrosshairCanvas>(); RootPanel.AddChild<ChatBox>(); RootPanel.AddChild<VoiceList>(); RootPanel.AddChild<KillFeed>(); RootPanel.AddChild<Scoreboard<ScoreboardEntry>>(); RootPanel.AddChild<Health>(); RootPanel.AddChild<InventoryBar>(); RootPanel.AddChild<CurrentTool>(); RootPanel.AddChild<SpawnMenu>(); } }

Source: sandbox - SandboxHud.cs

using Sandbox; using Sandbox.UI; using Sandbox.UI.Construct; public class Health : Panel { public Label Label; public Health() { Label = Add.Label( "100", "value" ); } public override void Tick() { var player = Local.Pawn; if ( player == null ) return; Label.Text = $"{player.Health.CeilToInt()}"; } }

Source: sandbox - Health.cs

Example: Interacting with UI

We are able to interact with the stylesheet from the c# file. We can for exemple - AddClass to a panel/Label - RemoveClass to a panel/Label

In the exemple below we are removing the health hud if the player is in a car by using (Panel, Label or this).AddClass(string classname) and (Panel, Label or this).RemoveClass(string classname).

using Sandbox; using Sandbox.UI; using Sandbox.UI.Construct; public class Health : Panel { public Label Label; public Health() { Label = Add.Label( "100", "health-label active" ); } public override void Tick() { var player = Local.Pawn; if ( player == null ) return; if (player.Health.CeilToInt() == -1) { Label.RemoveClass("active") } else { Label.AddClass("active") } Label.Text = $"{player.Health.CeilToInt()}"; } }
.health-label { position: absolute; background-color: rgba( black, 0.5 ); right: 100px; bottom: 48px; font-size: 40px; font-weight: bold; color: white; height: 80px; padding: 0 20px; align-items: center; opacity: 0; &.active { opacity: 1; } }