Skip to main content

UI

Balaur has two UI layers, both script-facing.

Widgets: game HUDs as scene nodes

The widget component turns a node into a HUD element — label, button, or panel — anchored to a screen corner or the center:

[[nodes]]
name = "Score"

[nodes.widget]
kind = "label"
text = "Score 0"
anchor = "top_left"
x = 20
y = 16
font_size = 22
text_color = "#2b2b2b"

Widgets live in the scene tree like any node, so they are saved with the scene, editable in the editor (which previews them in its viewport), and updatable from scripts through node:get_component("widget") / set_component. ui.set_widget_layer scopes and toggles the layer.

The ui module: immediate-mode UI

For tools and anything beyond a HUD, the ui module exposes immediate-mode egui to scripts. A script implements a draw_ui lifecycle method, which runs once per frame inside the egui pass:

function Tool:draw_ui()
ui.left_panel("outline", { width = 260, fill = colors.bg }, function()
ui.label("Nodes", { size = 14, color = colors.text })
if ui.pill("Add node", { fill = colors.accent }) then
-- ...
end
end)
end

Panel and container calls take a callback and push their child UI around it, so a script composes layouts exactly like Rust egui code. The widget set includes panels, labels, pills, toggles, sliders, drag values, selects, text fields, modals, scroll areas, menus, shortcuts, and ui.code_editor — an editable, Luau-syntax-highlighted buffer.

Widgets take colors per call, so complete themes live in scripts and hot reload with them. Fonts load from <project>/fonts/*.ttf, with the named families heading / ui / mono always available.

All dimensions are design pixels: ui.set_scale(f) multiplies every metric and the query functions divide back, so scripts author against the design's pixel values at any zoom. HiDPI is separate and automatic.

The editor's entire interface is built with this module; see The editor.