UI / UIObject
A node in the 2D UI scene graph: a transform expressed in both absolute pixels and
parent-relative fractions, an anchor, a place in the parent → child hierarchy, a lifecycle
(active / inactive / destroyed), responder/interaction state, and a native per-property animation
system. Components — UIText, UITexture, UIButton — attach to a UIObject and render inside its
computed rectangle.
Types
The global is named UI, but the handle it hands back is the metatable type UIObject.
You create and fetch through the global (UI.Create(), UI.Get(name) — dot calls), and you call
instance methods on the returned handle with colon syntax (uiObject:SetPixelSize(...)). There is
no global named UIObject; the name only appears as the userdata’s type and in tostring.
UIObject — an opaque handle (userdata) to a UI node. A handle may be null or stale (its
object destroyed); it is safe to keep and pass around. Calling a method on a null/stale handle
returns nil (getters) or warns and no-ops (mutators) — it never raises. Passing a value that is
not a UIObject at all (a number, a foreign handle) does raise a type error.
tostring(uiObject) yields the object’s ID (its name), or the literal "UIObject" if the handle is
dead or unnamed.
Screen space is Y-down (origin top-left): +x is right, +y is down. All pixel positions,
sizes, and readbacks use this convention. Positions and sizes come in two flavors that add together:
pixel units (absolute px) and relative units (a fraction of the parent’s unscaled size).
Rotations are in radians.
Creation & Destruction
UI.Create( ) : UIObject
Creates a new, active UIObject as a UI root at the origin. Returns nil and logs an error if the UI
scene pool is exhausted. New objects are recorded in the ambient zone’s spawn ledger, so they unload
with the zone.
UI.CreateInactive( ) : UIObject
Same as Create, but the object starts disabled (its components do not run until activated).
UI.Instantiate( UIObject source ) : UIObject
Recursively clones source and its children. source must be a UIObject handle (raises otherwise);
returns nil and logs a warning if the clone fails.
UI.Get( string name ) : UIObject
Finds a UIObject by its unique name (ID). Returns nil and logs a warning if no match exists.
UI.Exists( UIObject object ) : boolean
Returns true if the handle refers to a live object. Safe on any value — a null/stale handle or a
non-UIObject returns false — and it never warns.
uiObject:Destroy( ) : void
Destroys the object (and its children). Destruction is deferred to the next safe point, so calling
it on self from a callback is safe.
Functions
Read-only queries. Every getter returns nil and (for the delegated ones) logs a warning on a
null/stale handle unless noted.
Hierarchy
Same shape as GameObject — the tree is navigated identically.
uiObject:Active( ) : boolean
The object’s own enabled flag, ignoring ancestors.
uiObject:ActiveInHierarchy( ) : boolean
true only if this object and every ancestor are active.
uiObject:Parent( ) : UIObject
The parent, or nil if the object is a UI root (a root is not an error — no warning).
uiObject:Root( ) : UIObject
The topmost ancestor (itself if already a root).
uiObject:Children( ) : table
An array (1-based) of the direct children.
uiObject:ChildCount( ) : integer
Number of direct children (returns 0 on a dead handle).
uiObject:GetChild( integer index ) : UIObject
The child at index (1-based); nil if out of range.
uiObject:FindChild( string name ) : UIObject
Search for a descendant named name; nil if none.
uiObject:IsChildOf( UIObject parent ) : boolean
true if parent is this object’s ancestor (returns false on a dead handle).
uiObject:IsRoot( ) : boolean
true if the object has no parent.
uiObject:FirstChild( ) : UIObject
First direct child, or nil.
uiObject:NextSibling( ) : UIObject
Next sibling under the shared parent, or nil.
uiObject:PreviousSibling( ) : UIObject
Previous sibling, or nil.
World-space readbacks
The final values after the layout, anchor, and hierarchy passes resolve. Read-only — there are no
setters (you set the local inputs above; the engine computes these each frame).
uiObject:WorldPosition( ) : Vector2
Final computed screen position, in pixels (Y-down from top-left).
uiObject:WorldSize( ) : Vector2
Final computed size in pixels (unscaled_size × world scale).
uiObject:WorldRotation( ) : number
Accumulated world rotation, in radians.
uiObject:WorldScale( ) : number
Accumulated world scale.
uiObject:WorldOpacity( ) : number
Accumulated world opacity, [0, 1].
uiObject:WorldDepth( ) : integer
Accumulated world depth (sort key).
uiObject:LayoutOffset( ) : Vector2
The offset applied to this child by the parent’s auto-layout pass; zero when the parent has no
layout. Read-only (recomputed each frame by the layout post-pass).
Responder state
Engine-driven interaction state, updated as the pointer moves. Read-only.
uiObject:HoverTime( ) : number
Seconds the pointer has been hovering this object (0 if not hovered).
uiObject:PressTime( ) : number
Seconds since the current press began.
uiObject:DownPosition( ) : Vector2
Screen position where the active press started.
uiObject:PressDelta( ) : Vector2
Pointer movement since the press started.
Properties (get / set)
Paired accessors. Setters return void and no-op with a warning on a null/stale handle. Setters
that take a position or size accept a Vector2 or two numbers.
ID
uiObject:ID( ) : string — the object’s unique name.
uiObject:SetID( string name ) : void — renames the object.
PixelPosition
uiObject:PixelPosition( ) : Vector2 — pixel offset from the anchor-derived local position.
uiObject:SetPixelPosition( Vector2 position ) : void
RelativePosition
uiObject:RelativePosition( ) : Vector2 — offset as a fraction of the parent’s unscaled size.
uiObject:SetRelativePosition( Vector2 position ) : void
PixelSize
uiObject:PixelSize( ) : Vector2 — absolute pixel contribution to size.
uiObject:SetPixelSize( Vector2 size ) : void
RelativeSize
uiObject:RelativeSize( ) : Vector2 — size as a fraction of the parent’s unscaled size.
uiObject:SetRelativeSize( Vector2 size ) : void
Anchor
uiObject:Anchor( ) : string — the anchor setting, by name (e.g. "MiddleCenter").
uiObject:SetAnchor( string anchor ) : void — one of the nine anchor names (see
Enum names). An unrecognized name raises.
Rotation
uiObject:Rotation( ) : number — local rotation, in radians.
uiObject:SetRotation( number radians ) : void
LocalScale
uiObject:LocalScale( ) : number — uniform local scale (default 1).
uiObject:SetLocalScale( number scale ) : void
Opacity
uiObject:Opacity( ) : number — local opacity, [0, 1] (default 1).
uiObject:SetOpacity( number opacity ) : void
Depth
uiObject:Depth( ) : integer — local depth (a sort key; combined up the hierarchy into
WorldDepth).
uiObject:SetDepth( integer depth ) : void
Padding
uiObject:Padding( ) : number, number, number, number — inner content inset
left, top, right, bottom. Children’s relative position/size reference this padded rect.
uiObject:SetPadding( number left, number top, number right, number bottom ) : void
uiObject:SetPaddingUniform( number value ) : void — convenience: sets all four sides to
value (no matching getter — read back with Padding).
Margin
uiObject:Margin( ) : number, number, number, number — outer spacing
left, top, right, bottom consumed by the parent’s layout pass.
uiObject:SetMargin( number left, number top, number right, number bottom ) : void
LayoutMode
uiObject:LayoutMode( ) : string — auto-layout mode for this container’s direct children, by
name: "None", "Vertical", or "Horizontal".
uiObject:SetLayoutMode( string mode ) : void — an unrecognized name raises.
LayoutSpacing
uiObject:LayoutSpacing( ) : number — gap between children in the layout.
uiObject:SetLayoutSpacing( number spacing ) : void
LayoutAlignment
uiObject:LayoutAlignment( ) : string — child alignment along the layout axis, by name:
"Center", "Start", or "End".
uiObject:SetLayoutAlignment( string alignment ) : void — an unrecognized name raises.
Layer
uiObject:Layer( ) : integer — the UI layer index.
uiObject:SetLayer( integer layer ) : void
PseudoState
uiObject:PseudoState( ) : string — the responder pseudo-state used for styling, by name:
"None", "NonInteractive", "Hover", "Activated", "Held", "Released", "Focus".
uiObject:SetPseudoState( string state ) : void — an unrecognized name raises. Getter and
setter use the same spellings, so a:SetPseudoState(b:PseudoState()) round-trips.
Interactive
uiObject:Interactive( ) : boolean — true only for the three responding types
("Button", "Drag", "TextField"). The three hit-testing-only types — "HitTarget", "Block",
"Pass" — report false here even though they do take part in hit-testing.
uiObject:SetInteractive( string responseType ) : void — sets the responder response type by
name (see Enum names); an unrecognized name raises. Asymmetric: the getter
returns a boolean, so unlike the other enum properties this pair does not round-trip — there is no
getter that returns the response-type name.
ScriptTarget
uiObject:GetScriptTarget( ) : string — the name of the script object that receives this
element’s UI callbacks, or nil if unset.
uiObject:SetScriptTarget( string name ) : void
Methods
Actions that mutate the object. All no-op with a warning on a null/stale handle.
uiObject:Activate( ) : void
Enables the object and recursively updates children.
uiObject:Deactivate( ) : void
Disables the object and recursively updates children.
uiObject:SetParent( UIObject parent ) : void
Reparents the object under parent. parent must be a UIObject handle — unlike
GameObject:SetParent, there is no string-name overload.
uiObject:MakeRoot( ) : void
Detaches from the current parent, making the object a UI root. Re-homes zone ownership so the fresh
root unloads with the ambient zone instead of leaking.
uiObject:DetachChildren( ) : void
Unparents every direct child, making each a root.
Property animation
Every animatable property has a triple — Animate<P>, Cancel<P>Anim, Is<P>Animating — plus
one global CancelAllAnimations(). Animate<P> tweens the property to a target over duration
seconds using an interp easing-curve name (see Enum names); the optional
smoothTime (default 0) adds critically-damped smoothing on top. interp is required and an
unrecognized name raises. Vec2-valued targets accept a Vector2 or two numbers; scalar targets take
one number.
- Vec2:
uiObject:Animate<P>( Vector2 target, number duration, string interp, number smoothTime = 0 ) : void
- Scalar:
uiObject:Animate<P>( number target, number duration, string interp, number smoothTime = 0 ) : void
uiObject:Cancel<P>Anim( ) : void — stop the animation on that property, leaving it at its current value.
uiObject:Is<P>Animating( ) : boolean — whether that property is currently animating.
| Property |
Value |
Animate |
Cancel |
Query |
| PixelPosition |
Vector2 |
AnimatePixelPosition |
CancelPixelPositionAnim |
IsPixelPositionAnimating |
| RelativePosition |
Vector2 |
AnimateRelativePosition |
CancelRelativePositionAnim |
IsRelativePositionAnimating |
| PixelSize |
Vector2 |
AnimatePixelSize |
CancelPixelSizeAnim |
IsPixelSizeAnimating |
| RelativeSize |
Vector2 |
AnimateRelativeSize |
CancelRelativeSizeAnim |
IsRelativeSizeAnimating |
| Opacity |
number |
AnimateOpacity |
CancelOpacityAnim |
IsOpacityAnimating |
| Rotation |
number |
AnimateRotation |
CancelRotationAnim |
IsRotationAnimating |
| Scale |
number |
AnimateScale |
CancelScaleAnim |
IsScaleAnimating |
uiObject:CancelAllAnimations( ) : void
Cancels every active property animation on the object at once.
Enum names
Every enum argument above is a string, matched exactly against the spellings below —
one spelling each, no case folding and no aliases ("vertical" and "VERTICAL" are both rejected;
only "Vertical" is accepted). An unrecognized value raises a Lua error listing the valid
spellings, and numbers are rejected the same way. The getters return these same strings, so
a:SetAnchor(b:Anchor()) round-trips.
The UI.* integer constants were deleted (2026-07) — all 39 of UI.LAYOUT_*, UI.ALIGN_*,
UI.ANCHOR_*, UI.INTERP_*, and UI.RESPONSE_*. They are simply absent from the UI table
now, so a stale call like panel:SetAnchor(UI.ANCHOR_MIDDLE_CENTER) passes nil and raises.
They were not reinstated as string constants on purpose: a mistyped table field
(UI.ANCHOR_LOWER_RIGTH) is nil and indistinguishable from an omitted argument, while a
present-but-wrong string can always be rejected by name.
Layout mode (SetLayoutMode / LayoutMode): "None", "Vertical", "Horizontal".
Layout alignment (SetLayoutAlignment / LayoutAlignment): "Center", "Start", "End".
Anchor (SetAnchor / Anchor) — top-to-bottom / left-to-right:
| |
Left |
Center |
Right |
| Upper |
"UpperLeft" |
"UpperCenter" |
"UpperRight" |
| Middle |
"MiddleLeft" |
"MiddleCenter" |
"MiddleRight" |
| Lower |
"LowerLeft" |
"LowerCenter" |
"LowerRight" |
Pseudo-state (SetPseudoState / PseudoState): "None", "NonInteractive", "Hover",
"Activated", "Held", "Released", "Focus".
Response type (SetInteractive):
| Name |
Behavior |
"None" |
Not interactive; does not participate in hit-testing. |
"Button" |
Responds to press/release. |
"Drag" |
Responds to drag (movement while pressed). |
"TextField" |
Editable text field (focuses on click, receives text events). |
"HitTarget" |
Hit-tests; propagates the hit up to the first interactive ancestor. |
"Block" |
Hit-tests; absorbs the hit with no response or propagation. |
"Pass" |
Hit-tests; masks lower-depth objects but does not consume input. |
Interpolation (the interp argument of every Animate* call):
| Name |
|
Name |
|
Name |
"None" |
|
"CubicIn" |
|
"QuinticIn" |
"Linear" |
|
"CubicOut" |
|
"QuinticOut" |
"QuadraticIn" |
|
"CubicInOut" |
|
"QuinticInOut" |
"QuadraticOut" |
|
"QuarticIn" |
|
"SinIn" |
"QuadraticInOut" |
|
"QuarticOut" |
|
"SinOut" |
| |
|
"QuarticInOut" |
|
"SinInOut" |
Example
-- Build a full-screen panel, then fade + slide it in.
-- (Adapted from data/scripts/ui_setup.lua.)
local panel = UI.CreateInactive()
panel:SetID("main_menu_panel")
panel:SetAnchor("MiddleCenter")
panel:SetPixelSize(Screen.UIPixelWidth(), Screen.UIPixelHeight())
panel:SetInteractive("Block") -- swallow clicks behind the menu
-- Attach a background texture (see the UITexture page).
local tex = UITexture.Create(panel)
tex:SetMaterial(Material.Get("ui_default"))
-- Start hidden and offset upward, then animate to rest.
panel:SetOpacity(0)
panel:SetPixelPosition(0, -40)
panel:Activate()
panel:AnimateOpacity(1.0, 0.25, "CubicOut") -- fade in
panel:AnimatePixelPosition(0, 0, 0.25, "CubicOut") -- slide down (x, y, dur, interp)
-- Later, in an update, react to hover:
if panel:HoverTime() > 0 and not panel:IsOpacityAnimating() then
panel:AnimateScale(1.05, 0.1, "QuadraticOut")
end