Find, create, and mutate UI from Lua.
HUD API
HUD stands for heads-up display: the on-screen interface layer — health bars, score, menus, touch buttons. In DemiEngine the HUD is an authored document of named nodes that scripts can find, update, animate, and query for tests.
What a HUD node is
A HUD is a tree of nodes (labels, bars, buttons, panels). Every node has a stable ID from the authored document, so scripts address nodes by name instead of hunting through a hierarchy. The demi.hud module is how a script finds a node and changes what the player sees.
local Hud = require("demi.hud")
local bar = Hud.find("skyforge_health_bar") -- node handle, or nil if the ID is unknown
Hud.find(id) returns a generation-checked handle, or nil when the ID is missing. Structural operations and tweens use handles; content and state setters use ID strings.
Creating and structuring nodes
local Hud = require("demi.hud")
local row, err = Hud.create("skyforge_menu", {
type = "panel",
id = "skyforge_row_1",
text = "Continue",
width = 240, height = 48,
})
if not row then print(err) end
if row then
local copy, clone_err = Hud.clone(row, "skyforge_row_2")
if copy then Hud.reparent(copy, "skyforge_other_panel") end
end
local kids = Hud.children("skyforge_menu") -- array of child IDs
Hud.clear_children("skyforge_menu") -- invalidates handles to its children
Hud.create(parent_id, def)— atomically creates a native subtree or UI-prefab instance. It accepts HUD layout fields, nestedchildren, colors and target-basedoverrides. Returns a root handle ornil, plus an error string. Olderx/y/width/heightfields remain available for native node definitions.Hud.apply_action(name)— applies declared show/hide/focus effects and relayouts the HUD. Returns whether the action exists; prefab-local names are qualified with the instance ID.Hud.clone(source_handle, new_root_id, parent_id?)— copies a subtree. Returns handle ornil, plus an error string.Hud.remove(handle)— deletes a node and its subtree. Returns success boolean plus an error string.Hud.reparent(handle, parent_id)— moves a node. Returns success boolean plus an error string.Hud.clear_children(parent_id)— removes all children. Returns success boolean plus an error string.Hud.children(parent_id)— returns an array of child ID strings.
Content and appearance
local Hud = require("demi.hud")
Hud.set_text("skyforge_score", "0")
print(Hud.get_text("skyforge_score")) -- "0"
Hud.set_font("skyforge_score", "asset://fonts/skyforge_ui")
Hud.set_font_size("skyforge_score", 18)
Hud.set_color("skyforge_score", 1, 1, 1, 1)
Hud.set_background_color("skyforge_score", 0, 0, 0, 0.5)
Hud.set_image("skyforge_portrait", "asset://textures/skyforge_ace", 0, 0, 256, 256)
Hud.set_opacity("skyforge_score", 0.8)
| Call | Takes | Returns |
|---|---|---|
Hud.set_text(id, text) | ID string, text string | boolean |
Hud.get_text(id) | ID string | String, or nil when the node is missing |
Hud.set_font(id, uri) | ID string, asset:// font URI or empty string for fallback | boolean |
Hud.set_font_size(id, size) | ID string, number in canvas units | boolean |
Hud.set_color(id, r, g, b, a?) | ID string, 0…1 color components | boolean |
Hud.set_background_color(id, r, g, b, a?) | ID string, 0…1 color components | boolean |
Hud.set_image(id, uri, x, y, w, h) | ID string, texture URI, source rectangle | boolean |
Hud.set_opacity(id, alpha) | ID string, number 0…1 | boolean |
Lua color setters take separate red, green, blue, and optional alpha numbers from 0 to 1. JSON color fields can use arrays or hex strings. Sizes and positions use HUD canvas units.
Hud.set_value("skyforge_health_bar", 0.75) -- progress-style nodes: 0…1 (or the node's range)
Hud.set_checked("skyforge_mute_toggle", true)
Hud.set_disabled("skyforge_play_button", true)
Hud.set_visible("skyforge_warning", false)
Hud.set_position("skyforge_banner", 40, 12)
Hud.set_size("skyforge_banner", 200, 48)
Hud.set_value(id, number)— fills sliders and progress bars. Returns a success boolean.Hud.set_checked(node, boolean)— checkbox/toggle state.Hud.set_disabled(node, boolean)— blocks interaction and can grey out the look.Hud.set_visible(node, boolean)— shows or hides without destroying the node.Hud.set_position(id, x, y)/Hud.set_size(id, w, h)— canvas-unit layout overrides. Return success booleans.
Focus
Hud.focus_next()
print(Hud.focused()) -- focused node ID string, or "" when nothing has focus
Hud.focus_next(reverse?) moves keyboard/controller focus and returns whether it succeeded. Hud.focused() returns the focused node's ID string, or an empty string when nothing has focus.
Variables and localization
Variables are named values that text nodes can interpolate, so one script write updates every label bound to that name.
local Hud = require("demi.hud")
Hud.set_variable("score", "1200")
Hud.set_variables({ wave = "3", lives = "2" })
print(Hud.has_variable("score")) -- true
print(Hud.get_variable("score")) -- "1200", or nil when unset
Hud.reset_variables() -- clear runtime values
Hud.set_locale("de")
Hud.set_pseudo_locale(true) -- stretch text to spot overflow
Hud.set_variable(name, value)/Hud.set_variables(table)— assign declared names to string values. Return a success boolean plus an error string.Hud.has_variable(name)→ boolean.Hud.get_variable(name)→ the value, ornilwhen unset.Hud.reset_variables()— clears runtime values; unresolved markers remain visible.Hud.set_locale(tag)— selects a locale in the loaded HUD'slocalesobject; returns a boolean and error string.Hud.set_pseudo_locale(on)changes presentation without a return value.
Tweens and motion
A tween animates one property over time. Supported properties: opacity, x, y, scale.
local Hud = require("demi.hud")
local banner = Hud.find("skyforge_banner")
local handle, err = Hud.tween(banner, "opacity", 0, 0.35)
if not handle then print(err) end
Hud.cancel_tween(handle) -- stop mid-flight; returns true when cancelled
Hud.set_reduced_motion(true) -- honour accessibility preference
Hud.tween(handle, property, target, duration)→ tween ID and error string. Animatesopacity,x,y, orscaletowardtargetoverdurationseconds. Tweens cancel themselves when the node is removed.Hud.cancel_tween(handle)→ boolean.Hud.set_reduced_motion(enabled)— finishes presentation changes immediately for players who prefer fewer animations.
Virtualized lists
Long lists (a Skyforge server browser with hundreds of rows) should only build the rows on screen. Virtualization helpers report which rows are visible and recycle off-screen ones.
local Hud = require("demi.hud")
-- Which rows are on screen right now?
local first, count = Hud.visible_range(500, 44, scroll_offset, viewport_height)
-- first: one-based index of the first visible row
-- count: how many live rows the viewport needs
-- How tall is the whole list, and which rows fill it?
local layout, err = Hud.virtual_layout(row_extents) -- row_extents: array of numbers
if layout then
-- layout fields per the HudVirtualLayout stub
end
-- Reuse hidden template rows for stable keys:
local rows = Hud.recycle_rows("skyforge_server_list", row_template, keys, extents, scroll_offset, viewport_height)
-- rows: array of { key, index, node, offset, extent, rebound }
Hud.visible_range(item_count, item_extent, scroll_offset, viewport_extent, overscan?)→integer first, integer count. One-based logical index of the first visible row and how many live rows the screen needs.Hud.virtual_layout(item_extents)→layout, error— planning helper over per-row extents.Hud.recycle_rows(collection_id, row_template, keys, extents, scroll_offset, viewport_extent)→ recycled rows withkey,index, a livenodehandle,offset,extent, andrebound(true when the pool slot was reset for a new key).
Accessibility snapshot
local nodes = Hud.accessibility_snapshot()
-- nodes: array of accessibility nodes (possibly empty, never nil)
Hud.accessibility_snapshot() takes no arguments and describes the whole active document. Each entry carries id, parent, role (for example button, slider, static_text), label, description, numeric value/minimum/maximum plus display value_text, position and size (x, y, width, height), and state booleans (focused, disabled, checked, focusable, offscreen). The array is empty when nothing is announced — never nil.
Next steps
- Events & timers — wiring buttons with
ui_eventandui_submit. - E2E tests — driving HUD nodes from tests with
Test.touch. - Script lifecycle — the hooks that receive UI events.