Skip to content

User interface

A game’s menus and HUD are UI documents: text files of markup that say what is on a screen, much like a web page. A UI theme styles them. Scripts show documents, fill in their text, and answer their buttons.

Make one with Create > UI > UI Document in the Assets panel. Its page is a text editor with a live preview beside it, drawn the way the game will draw it; the preview catches up a moment after you stop typing. Save it to use it in the game.

A pause menu:

<screen mode="modal" transition="fade" default-focus="resume-btn">
<Flex direction="vertical" justify="center" align="center">
<Panel padding="24" class="card">
<Flex direction="vertical" align="stretch" spacing="10" width="400">
<Label text="Paused" font-size="36"/>
<Button id="resume-btn" text="Resume" height="44"/>
<Button id="quit-btn" text="Leave to the title" height="44"/>
</Flex>
</Panel>
</Flex>
</screen>

Elements nest: layouts hold other elements, and controls are what the player sees and uses. An element’s attributes are its settings, written in lower case with dashes (font-size, default-focus). Give an element an id to reach it from a script.

A document that a script shows starts with <screen>. Its mode says how it sits over what is below:

  • overlay: the screens below show, and clicks pass through. A HUD.
  • modal (the default): the screens below show, but take no input. A pause menu.
  • opaque: the screens below are hidden. A title screen.

transition animates it in and out: fade, slide-left, slide-right, slide-up, slide-down or scale (in-transition and out-transition set each way apart). default-focus names the element a keyboard or gamepad starts on, so menus work without a mouse.

Layouts Flex (a row or column), Grid, Dock, Flow, Frame, Absolute
Containers Panel, ScrollView
Text Label, EditText, PasswordBox, NumericField
Buttons Button, IconButton, ContentButton, ToggleButton, CheckBox, RadioButton, RadioGroup, ToggleSwitch
Values Slider, ProgressBar, ComboBox
Pictures ImageView, ColorView
Structure TabView, Expander, ListView, TreeView, GridView, Spacer, Separator

A UI theme (Create > UI > UI Theme) is a style sheet. Rules pick elements by type, or by a class you give them, and set how they look:

Label { text-color: #2A251F; }
.card {
background: rounded-rect(#F4ECD8, radius=6, border=#2A251F, border-width=3);
box-shadow: 6 8 0 rgba(42, 37, 31, 0.45);
}

Its page edits the sheet beside a preview, and Preview Document shows one of your documents in it. Set the project’s theme in Project > Project Settings…, on the UI tab, as Default UI theme. A project theme replaces the built-in one, so style everything the game shows. An element can also carry its own style="...".

Import .ttf, .otf or .ttc fonts. The UI tab of Project Settings has the Default UI font, and Other UI fonts for more families, which an element picks with font-family.

Scripts show documents as a stack of screens, with ui:

local Pause = Guid.new("628098f1-29ea-4b5e-bdea-e6a828da27f5") -- a UI document's ID
function Game:pause()
local screen = ui.push(Pause)
screen:findButton("resume-btn"):onClick(function() ui.pop() end)
end
function Game:showLives(lives)
ui.findLabel("hud-lives"):setText("x " .. lives)
ui.findProgressBar("hud-health"):setValue(0.75)
end
  • push(document) shows a document on top; pop() removes the top one, and back() removes it unless it is the last. replace(document) swaps the top one, and clear() empties the stack.
  • findLabel, findButton, findProgressBar, findSlider, findTextBox, findImage and findGroup find an element by its id, on ui or within a screen. If there is none of that type, the result’s isValid() is false, and calls on it do nothing.
  • Every element can setVisible, setEnabled, setOpacity, and animate: fadeTo, moveTo, scaleTo and rotateTo take a time in seconds and an optional easing (Ease.OutBack, Ease::OutBounce and so on); pulse(peak, seconds) swells it briefly, to draw the eye.
  • A label has setText and setTextColor; a progress bar setValue from 0 to 1; a slider setValue, setRange and onChanged; an image setSource.
  • A button’s onClick runs on the frame after the click.

Three components show a document from an entity instead.

UI Canvas shows a document on the screen while its scene is loaded, a HUD that belongs to a level. Order puts one canvas above another. Its Scaler Mode sizes it: ConstantPixel keeps one UI pixel to one screen pixel, and ReferenceResolution scales the whole document as if the screen were the Reference Resolution (1920 by 1080), so it looks the same on every display. With Render Mode RenderTexture it draws into a texture instead, for a screen on a computer in the world.

UI Billboard floats a document over the entity, such as a name or a health bar. Offset lifts it, and with Scale Mode Distance it shrinks as the entity gets further away, between Min Scale and Max Scale. Billboards cannot be clicked.

UI World Panel puts a document on a flat panel in the world, Size Meters across, in the entity’s plane. With Interactive on, the player can click it.

A script reaches a component’s document through its root():

local panel = UICanvasComponent.of(self.entity):root()
panel:findLabel("score"):setText("0")

UIBillboardComponent and UIWorldPanelComponent work the same way.

A document set as Loading screen on the Startup tab of Project Settings shows while the first scene loads.