Skip to main content

UI

Retained mode and DOM-style API to render interactive user-interfaces, with a Solid.js-inspired UI framework built on top.

It's recommended to either use the out-of-the-box UI framework (or build your own) instead of working with the retained mode API directly. Retained mode has been chosen to significantly reduce the overhead of communicating between Lua and the engine for mostly static UIs.

Constants

UI.SCREEN

Root DOM element rendered to the screen in 2D. Shared by all screenspace UI, so you'll want to further restrict/abstract this if exposed to addons in your game.

UI.SCREEN: Element

Functions

UI.createElement

Creates a new containing element.

UI.createElement(): Element

Returns

NameTypeDescription
elementElementNo description

UI.createTextElement

Creates a new text element.

UI.createTextElement(textContent: string): TextElement

Parameters

NameTypeDescription
textContentstringInitial text content of the element.

Returns

NameTypeDescription
elementTextElementNo description

UI.createRichTextElement

Creates a new rich text element designed for user input.

UI.createRichTextElement(): RichTextElement

Returns

NameTypeDescription
elementRichTextElementNo description

UI.getId

Gets the unique ID for this element (can be used for equality).

UI.getId(element: Element | TextElement | RichTextElement): number

Parameters

NameTypeDescription
elementElement | TextElement | RichTextElementNo description

Returns

NameTypeDescription
idnumberUnique ID for this element.

UI.isTextElement

Returns whether the given parameter is a text UI element.

UI.isTextElement(value: any): boolean

Parameters

NameTypeDescription
valueanyThe value to check.

Returns

NameTypeDescription
isTextElementbooleanWhether the value is a text element.

UI.isRichTextElement

Returns whether the given parameter is a rich text UI element.

UI.isRichTextElement(value: any): boolean

Parameters

NameTypeDescription
valueanyThe value to check.

Returns

NameTypeDescription
isRichTextElementbooleanWhether the value is a rich text element.

UI.removeElement

Removes the element from its parent. No-op if the element has no parent.

UI.removeElement(child: Element | TextElement | RichTextElement)

Parameters

NameTypeDescription
childElement | TextElement | RichTextElementNo description

UI.appendElement

Appends an element to the end of another element's children. Removes the child element from its current parent if it has one.

UI.appendElement(parent: Element, child: Element | TextElement | RichTextElement)

Parameters

NameTypeDescription
parentElementElement to append to.
childElement | TextElement | RichTextElementElement to be appended.

UI.getChildren

Returns a list of the element's children. This is a copy, so will not update if the children of the element change (nor will the element's children change if this list is modified).

UI.getChildren(element: Element): (Element | TextElement | RichTextElement)[]

Parameters

NameTypeDescription
elementElementNo description

Returns

NameTypeDescription
children(Element | TextElement | RichTextElement)[]No description

UI.getElementName

Returns the debug name of the element.

UI.getElementName(element: Element | RichTextElement): string

Parameters

NameTypeDescription
elementElement | RichTextElementNo description

Returns

NameTypeDescription
namestringNo description

UI.setElementName

Sets the debug name of the element.

UI.setElementName(element: Element | RichTextElement, name: string)

Parameters

NameTypeDescription
elementElement | RichTextElementNo description
namestringNo description

UI.getTextContent

Returns the contents of a text element.

UI.getTextContent(element: TextElement | RichTextElement): string

Parameters

NameTypeDescription
elementTextElement | RichTextElementNo description

Returns

NameTypeDescription
textContentstringNo description

UI.setTextContent

Updates the contents of a text element.

UI.setTextContent(element: TextElement, textContent: string)

Parameters

NameTypeDescription
elementTextElementNo description
textContentstringNo description

UI.setStyle

Sets a style on the element when in the specified state.

Styles are used in the order Clicked -> Hovered -> Always -> Engine Defaults. The first state as per the order above which has a style set will be used.

UI.setStyle(element: Element | RichTextElement, style: UI.Style, value: boolean | number | string | Colour | UI.SizeMode | UI.ChildAlignment | UI.Direction | UI.TextWrapping | UI.TextAlignment | UI.Display | UI.Overflow, when: UI.StyleMode)

Parameters

NameTypeDescription
elementElement | RichTextElementNo description
styleUI.StyleNo description
valueboolean | number | string | Colour | UI.SizeMode | UI.ChildAlignment | UI.Direction | UI.TextWrapping | UI.TextAlignment | UI.Display | UI.OverflowAccepted type depends on the style being set.
whenUI.StyleModeIn which state the style will be used.

UI.removeStyle

Removes the style from the element when in the specified state.

Styles are used in the order Clicked -> Hovered -> Always -> Engine Defaults. Removing a style from one of the layers means the first set style in a lower state (as above) will be used instead.

UI.removeStyle(element: Element, style: UI.Style, when: UI.StyleMode)

Parameters

NameTypeDescription
elementElementNo description
styleUI.StyleNo description
whenUI.StyleModeIn which state the style will be removed.

UI.createComponent

Creates a component from the given function. This sets up the component function as stateful and normalises its parameters.

UI.createComponent(componentFn: fun(props: table, children: fun(): (Element | TextElement)[]): function): fun(props?: table, children?: fun(): array): fun(): (Element | TextElement)[]

Parameters

NameTypeDescription
componentFnfun(props: table, children: fun(): (Element | TextElement)[]): functionNo description

Returns

NameTypeDescription
componentfun(props?: table, children?: fun(): array): fun(): (Element | TextElement)[]The normalised component function.

UI.render

Resolves the component tree and appends all root nodes to the given element. Should be called only once when initialising the UI.

UI.render(component: fun(props?: table, children?: (fun(): (Element | TextElement)[])[]): fun(): (Element | TextElement)[], element: Element)

Parameters

NameTypeDescription
componentfun(props?: table, children?: (fun(): (Element | TextElement)[])[]): fun(): (Element | TextElement)[]Root component of the application.
elementElementUI element to mount the components to.

UI.toString

Stringifies the element and its children into a format resembling HTML/XML Useful for debugging and snapshot testing.

UI.toString(element: Element | TextElement | RichTextElement, indent?: integer): string

Parameters

NameTypeDescription
elementElement | TextElement | RichTextElementNo description
indentinteger?Number of spaces to indent all lines by. Defaults to 0.

Returns

NameTypeDescription
elementMarkupstringNo description

UI.addEventListener

Adds an event listener. A list of events can be found here.

UI.addEventListener(eventType: string, callback: function): function

Parameters

NameTypeDescription
eventTypestringThe event to listen for.
callbackfunctionThe callback to use.

Returns

NameTypeDescription
callbackfunctionThe callback that was registered.

UI.removeEventListener

Removes an event listener.

UI.removeEventListener(eventType: string, callback: function)

Parameters

NameTypeDescription
eventTypestringThe event to remove the listener from.
callbackfunctionThe callback to remove.

Functions - Debugging

UI.enableDebugger

Enables the Clay debugger.

UI.enableDebugger()

UI.disableDebugger

Disables the Clay debugger.

UI.disableDebugger()

UI.isDebuggerEnabled

Returns whether the Clay debugger is enabled.

UI.isDebuggerEnabled(): boolean

Returns

NameTypeDescription
debuggerEnabledbooleanNo description

Functions - Rich Text

UI.getNumLines

Gets the number of lines in the rich text element (not including visual wrapping).

UI.getNumLines(element: RichTextElement): number

Parameters

NameTypeDescription
elementRichTextElementNo description

Returns

NameTypeDescription
numLinesnumberNo description

UI.getNumCharacters

Gets the number of characters in the rich text element's line (not including visual wrapping).

UI.getNumCharacters(element: RichTextElement, line: number): number

Parameters

NameTypeDescription
elementRichTextElementNo description
linenumberLine to get the length of. Throws if out of range.

Returns

NameTypeDescription
numCharactersnumberNo description

UI.setTokens

Overwrites a selection in the rich text element with the given tokens, splitting and merging tokens as needed.

Shifts the caret vertically if the number of lines to write is different to the number selected and the caret is after the selection. Does not shift the caret within or before the selection. i.e. you must manually move the caret when applying user input.

UI.setTokens(element: RichTextElement, tokens: RichTextToken[], start: number[], end: number[])

Parameters

NameTypeDescription
elementRichTextElementNo description
tokensRichTextToken[]No description
startnumber[][line, character] of the selection's start (0-indexed).
endnumber[][line, character] of the selection's end (0-indexed).

UI.setCaret

Sets the position of the caret within the rich text element, if the element is focused.

UI.setCaret(element: RichTextElement, newCaret: number[])

Parameters

NameTypeDescription
elementRichTextElementNo description
newCaretnumber[][line, character] of the new caret position.

UI.getCaret

Gets the position of the caret within the rich text element, or nil if the element isn't focused.

UI.getCaret(element: RichTextElement): number[]?

Parameters

NameTypeDescription
elementRichTextElementNo description

Returns

NameTypeDescription
caretnumber[]?[line, character] of the caret position, if focused.

UI.moveCaret

Moves the rich text element's caret the given number of lines and characters, if the element is focused.

Vertical caret movement maintains the horizontal pixel position of the caret as close as possible, and preserves it across lines of varying lengths until the next horizontal movement.

UI.moveCaret(element: RichTextElement, delta: number[])

Parameters

NameTypeDescription
elementRichTextElementNo description
deltanumber[][line, character] deltas to move the caret in.

Types

RichTextToken

An independently stylable chunk of text in a rich text element.

type RichTextToken = { .content: string, .style: RichTextTokenStyles }

Properties

FieldTypeDescription
contentstringNo description
styleRichTextTokenStylesNo description

RichTextTokenStyles

Styling properties for rich text tokens. All properties are optional and will default to the values defined on the element.

type RichTextTokenStyles = { .alignmentY: UI.ChildAlignment?, .textColour: Colour?, .backgroundColour: Colour?, .fontSize: number?, .letterSpacing: number?, .lineHeight: number?, .textWrapping: UI.TextWrapping? }

Properties

FieldTypeDescription
alignmentYUI.ChildAlignment?No description
textColourColour?No description
backgroundColourColour?No description
fontSizenumber?No description
letterSpacingnumber?No description
lineHeightnumber?No description
textWrappingUI.TextWrapping?No description

Enums

Style

Style properties of Elements.

Value
Width
MinWidth
MaxWidth
WidthMode
Height
MinHeight
MaxHeight
HeightMode
PaddingLeft
PaddingRight
PaddingTop
PaddingBottom
Gap
AlignmentX
AlignmentY
Direction
BackgroundColour
BackgroundImage
CornerRadiusTopLeft
CornerRadiusTopRight
CornerRadiusBottomLeft
CornerRadiusBottomRight
BorderColour
BorderLeft
BorderRight
BorderTop
BorderBottom
BorderBetween
TextColour
FontSize
LetterSpacing
LineHeight
TextWrapping
TextAlignment
OverflowX
OverflowY

StyleMode

When to apply a given style. Styles apply in the order Clicked -> Hovered -> Always -> Engine Defaults.

Value
Always
Hovered
Clicked

SizeMode

Determines how the Element will respond to changes in width/height by its parent and children. FixedPercent fixes the Element's width/height to a percentage (0-1) of the parent's size, using the first of Width, MaxWidth or MinWidth which is defined (and *Height for height).

Value
Shrink
Grow
FixedPercent

ChildAlignment

Alignment of children on a given axis relative to this Element's content box.

Value
Start
Centre
End

Direction

Direction that children are laid out in this Element.

Value
Horizontal
Vertical

TextWrapping

Where in the string it's valid to insert line breaks in order to prevent overflow.

Value
Words
Newlines
None

TextAlignment

Alignment of TextElements which are the immediate child of this Element.

Value
Left
Centre
Right

Display

Determines the visibility of the element and its children.

Value
Visible
ContentsHidden
Contents

Overflow

Visibility and scrolling behaviour of child content overflowing the content box.

Value
Visible
Scroll
Hidden

Events

"pressed"

Fires when the mouse or controller button bound to click is pressed on an element.

UI.addEventListener("pressed", fn(element) end)

Parameters

NameTypeDescription
elementElementNo description

"released"

Fires when the mouse or controller button bound to click is released on an element.

UI.addEventListener("released", fn(element) end)

Parameters

NameTypeDescription
elementElementNo description

"textEntry"

Fires when the user enters text into a rich text element.

UI.addEventListener("textEntry", fn(element, text) end)

Parameters

NameTypeDescription
elementRichTextElementNo description
textstringNo description

"keyPress"

Fires when the user presses a key in a rich text element.

Note this won't necessarily match the actual text that would be entered by the key press (e.g. when using a non-Latin alphabet). You should use the 'textEntry' event for inserting typed characters into the element, and this event for special keys like backspace.

UI.addEventListener("keyPress", fn(element, keyCode) end)

Parameters

NameTypeDescription
elementRichTextElementNo description
keyCodeKeyboard.KeyCodeNo description

"keyRepeat"

Fires when the Operating System repeats a held key in a rich text element.

Note this won't necessarily match the actual text that would be entered by the key press (e.g. when using a non-Latin alphabet). You should use the 'textEntry' event for inserting typed characters into the element, and this event for special keys like backspace.

UI.addEventListener("keyRepeat", fn(element, keyCode) end)

Parameters

NameTypeDescription
elementRichTextElementNo description
keyCodeKeyboard.KeyCodeNo description

"keyRelease"

Fires when the user releases a key in a rich text element.

Note this won't necessarily match the actual text that would be entered by the key press (e.g. when using a non-Latin alphabet). You should use the 'textEntry' event for inserting typed characters into the element, and this event for special keys like backspace.

UI.addEventListener("keyRelease", fn(element, keyCode) end)

Parameters

NameTypeDescription
elementRichTextElementNo description
keyCodeKeyboard.KeyCodeNo description