Manual

UI & Widgets

Menus, HUDs and interactive screens — designed visually, wired with HorizonCode, driven from any script.

Standalone UI

UI Widgets

A UI Widget is a standalone asset: a tree of UI elements on a virtual 1920×1080 canvas, plus a HorizonCode graph for its logic. Live widgets exist outside the entity world — they belong to the app, not the scene — so a HUD or menu can survive scene changes and is always drawn on top.

Create one with Create ▸ UI Widget in the Content Browser and double-click it to open the widget editor with its two modes: Designer and Graph.

WYSIWYG

The Designer

The Widget Designer: element palette, canvas and per-element details

The Designer is a UMG-style layout editor:

  • Palette — the nine element types; click or drag onto the canvas. Dropping onto a Panel nests the new element inside it.
  • Hierarchy — the element tree; children move with their parents.
  • Canvas — WYSIWYG editing with drag-to-move, resize handles, zoom and pan.
  • Details — every property of the selected element, plus an Events section: clicking an event (e.g. + OnClicked) jumps to Graph mode and spawns the matching event node.

Layout: anchors & pivots

Every element has a position, size, pivot and a 9-point anchor (top-left … bottom-right). The anchor picks the reference corner inside the parent (root elements anchor to the canvas), the position offsets from it and the pivot shifts the element's own origin — so UIs scale cleanly to any resolution. A layer value orders siblings; visibility cascades down the tree.

Elements can also carry a node-graph material (animated backgrounds, procedural effects — parameters settable at runtime) and a custom font asset, and define their pointer behaviour: hit-testable or click-through, plus a hover cursor (arrow, hand, text, resize …).

Building blocks

Element Reference

ElementPropertiesEvents
Panel Color; container for nesting OnMouseEnter, OnMouseLeave, OnClicked
Image Tint (+ material slot) OnMouseEnter, OnMouseLeave, OnClicked
Text Text, FontSize, Color
Button Text, FontSize, Normal/Hovered/Pressed/Text Color OnClicked, OnPressed, OnReleased, OnHovered, OnUnhovered
CheckBox Checked, Label, FontSize, Box/Check/Text Color OnCheckChanged (Bool), OnHovered, OnUnhovered
Slider Value, Min, Max, Track/Fill/Handle Color OnValueChanged (Float)
ProgressBar Value (0–1), Back/Fill Color
TextInput Text, Placeholder, FontSize, Back/Text Color OnTextChanged, OnTextCommitted (String), OnFocused, OnUnfocused
ComboBox Options (list), Selected Index, FontSize, Back/Text/Highlight Color OnSelectionChanged (Int)

All elements additionally share the base properties — Visible, Hit Testable, Position, Size, Layer, Hover Cursor, Material, Font — and every property (base and type-specific) is reachable by name from Get/Set Property nodes and from scripts.

Behaviour

Widget Logic (Graph)

Switching the widget editor to Graph mode shows the widget's HorizonCode graph — an event graph plus user-defined functions and typed variables. The host fires Construct when the widget is created, Destruct when destroyed, Tick (with delta time) while visible, and one event per element interaction (OnClicked, OnValueChanged …). Get/Set Property nodes read and write any element property by name — update a health bar, swap a label, recolour a button.

Because all graphs share one runtime, a widget can call into the Game Instance, bind events on other classes, and expose public functions that scripts call from outside.

In game

Widgets at Runtime

Widgets are created and managed from any scripting frontend — Lua, Python or HorizonCode:

hud.lua
local M = {}

function M.onStart(self)
    -- spawn the HUD widget and keep its id
    self.hud = horizon.createWidget("UI/HUD")
    horizon.setWidgetZOrder(self.hud, 10)
end

function M.onUpdate(self, dt)
    if horizon.isWidgetVisible(self.hud) then
        horizon.callWidgetFunction(self.hud, "Refresh")
    end
end

return M
  • createWidget(path) / destroyWidget(id) — instantiate a widget asset, tear it down (fires Construct/Destruct).
  • showWidget / hideWidget / isWidgetVisible — visibility without destroying state.
  • setWidgetZOrder(id, z) — stacking between widgets; widgets always draw above in-world UI.
  • callWidgetFunction(id, name) — invoke a public function of the widget's graph.
  • showCursor() / hideCursor() — release or capture the mouse for menu vs. gameplay; hovering interactive elements shows each element's chosen cursor.

Text input is routed automatically to a focused TextInput element, and pointer events (hover, press, click) drive the elements' visual states and fire their graph events.

In the world

In-World Entity UI

For UI that belongs to the scene — a name tag over a character, a world-space info panel — entities can carry the canvas-based UI components: UI Canvas (screen-space or world-space, virtual resolution), UI Element (anchored rect with pivot, rotation and layer), UI Text, UI Image (material + tint) and UI Button (state colours + an on-click script function).

Scripts address these through the entity UI calls — setUIText, setUIColor, setUIVisible, setUIPosition, setUISize, setUIMaterialParam — and scripts on the entity receive onClick, onHoverEnter and onHoverExit.

Which one to use? Menus, HUDs and anything that should survive scene changes → UI Widgets. Labels and panels attached to things in the world → entity UI.