Skip to main content

UI Scripting

Every User Interface file has two sides. The Designer is where you lay the interface out. Behind it sits a second node canvas where the interface comes alive: elements fire events, nearly every property has a Set and a Get node, and the same variables, arrays, maps and enums you use in your story are available here too.

Overview

A User Interface file's script graph is an event graph. There is no Start node and no single entry point. Instead, chains hang off events: a button was clicked, a slider moved, a dialogue line was reached, the interface was just created. Each event runs its own chain when it fires.

What you can do here:

  • React to clicks, hovers, value changes, focus, drags and drops on any element
  • Read and write almost every property in Element Settings, from colors and images to visibility, text and slider ranges
  • Use the same global variables your story scripts use, plus local variables that belong to this one interface
  • Loop over an array or over an element's children
  • Spawn copies of another User Interface file at runtime and reach into their elements and variables
  • Play and stop animations
  • Answer dialogue tags, dialogue text completion and option lists

One File, Two Canvases

The Designer and the script graph are two views of the same file. They share an undo history, a save and a file tab. Deleting an element in the Designer cleans up the nodes that referenced it, and renaming one updates the node labels.

Switching to Script Mode

While a User Interface file is the active tab, a pair of buttons appears in the toolbar: Designer and Script. Click Script to swap the whole editing area for the node canvas, and Designer to swap back.

The keyboard equivalent is Ctrl + E (Cmd + E on macOS), which flips the active tab between the two modes. The command is called Toggle Designer / Script Mode and is rebindable under Settings → Keybindings, in the User Interface Editor group.

The mode is remembered per tab, so two open interfaces can sit in different modes at once.

Jumping Between the Two

You rarely need to flip modes by hand. Clicking Create or Focus on an event row in Element Settings switches to Script mode and centres the canvas on that node, and double-clicking a Get Element node jumps back to the Designer with the element selected.

The Script Workspace

Script mode uses the same three-column arrangement as the story script editor, minus the Flows panel. Every panel here is dockable and resizable like the rest of the editor - see Workspace & Layout.

  • Variables (Left): This file's local variables and the project's global variables, with the same create, edit, rename, reorder and delete behaviour as the story script editor. Below them sit two more lists: Elements (every element you exposed to the graph) and Animations (every animation in this file). Drag any row onto the canvas to create the matching node.
  • Canvas (Center): The node graph. Right-click for the create-node menu, drag connections between pins, box-select and use the same navigation, duplication and nudging gestures described in Canvas Editing.
  • Details (Right): Context for the current selection. Selecting an element row shows its Events list, so you can create or focus an event node without going back to the Designer.

Exposing an Element

Most script nodes act on an element, and they get at it through an element reference. To make an element reachable from the graph, select it in the Designer and tick Is Variable at the top of Element Settings.

An exposed element appears in the Script mode Variables panel under Elements, and in the create-node menu's Elements section. Picking it places a Get Element node: a small pill carrying the element's name and its type icon, with a single element-reference output. Wire that output into the Target pin of any property, animation or instance node.

  • Double-click a Get Element node to jump back to the Designer with that element selected
  • The pill always shows the element's current name, so renaming in the Designer updates every reference
  • An element's own event node already knows which element it belongs to, so you do not need a Get Element node to act on the element that fired

Unticking Is Variable Removes Nodes

If script nodes still reference an element, unticking Is Variable asks for confirmation first and tells you how many other files also use it. Confirming deletes those reference nodes and their connections.

Element Events

An event node is an entry point: an execution output and no execution input. Its chain runs whenever the element fires that event.

Creating one: select the element, open the Events section of Element Settings and click the button beside the event you want. It reads Create when no node exists yet and Focus once one does, so an event can never end up with two nodes racing each other. Either way the editor switches to Script mode and centres the canvas on the node.

Which Element Fires What

Which events an element offers depends on its type. Containers and plain text do not fire pointer events, which is the reason to wrap something in a Box when you want a clickable region around it.

Element Events it adds
Button On Click, On Pressed, On Released, On Hover, On Unhover, On Double Click, On Right Click
Box On Click, On Pressed, On Released, On Double Click
Image On Click, On Pressed, On Double Click
Text On Typewriter Finished
Text Input On Value Changed, On Text Committed, On Focus, On Blur
Checkbox On Value Changed
Dropdown On Value Changed, On Opened
Slider On Value Changed, On Drag Start, On Drag End
Every element On Drag Detected, On Drag Enter, On Drag Leave, On Dropped, On Moved, On Drag Cancelled

What each one means:

  • On Click: Fires when the player clicks this element
  • On Pressed: Fires the moment the mouse button goes down on this element
  • On Released: Fires when the mouse button is released over this element
  • On Hover: Fires when the cursor moves onto this element
  • On Unhover: Fires when the cursor leaves this element
  • On Double Click: Fires on a quick double click
  • On Right Click: Fires on a right click
  • On Value Changed: Fires whenever the value changes, carrying the new value on its pin
  • On Text Committed: Fires when the text is confirmed with Enter or by leaving the field, carrying the final text
  • On Focus: Fires when the field gains keyboard focus
  • On Blur: Fires when the field loses keyboard focus
  • On Opened: Fires when the dropdown list opens
  • On Drag Start: Fires once when the player grabs the slider handle
  • On Drag End: Fires once when the player lets go of the slider handle
  • On Typewriter Finished: Fires when this element's typewriter finishes revealing its text, whether it finishes naturally or is skipped by a click. It does not fire when the typewriter is disabled

Slider: Continuous vs. Once

A slider's On Value Changed fires continuously while the player drags. On Drag Start and On Drag End fire once per grab and release, which is what you want for something expensive like previewing a sound at the new volume.

On Value Changed

The value controls all share one event, and its output pin is typed to match what the control produces:

  • Text Input and Dropdown: a string
  • Checkbox: a boolean
  • Slider: a float

So the pin connects only to inputs of that type, exactly like any other typed connection. If you later swap an element's type with Replace With, event nodes whose event or value type no longer fit that element are removed along with their connections rather than left behind lying about what they carry.

Drag & Drop Events

Every element type offers the six drag and drop events, because any element can start a drag and any element can receive one.

  • On Drag Detected: Fires on this element when the player starts dragging it. It needs Is Draggable turned on, set in the Designer or with a Set Is Draggable node
  • On Drag Enter: Fires when a dragged item moves onto this element and its Drag Tags are accepted, carrying them as typed plus the dragged element
  • On Drag Leave: Fires when a dragged item moves off this element
  • On Dropped: Fires when a dragged item is released on this element, carrying its Drag Tags as typed plus the dragged element. Wiring this is what makes the element a drop target
  • On Moved: Fires when the player drops this element after dragging it with the Move behavior. Read the new spot with Get Position X and Get Position Y
  • On Drag Cancelled: Fires on the dragged element when the drag ends nowhere, released over empty space or cancelled with Escape

Enter and Leave Need a Target

On Drag Enter and On Drag Leave only fire on elements that actually are drop targets, which means elements with On Dropped wired up. A graph with only an Enter node never fires, so a purely decorative hover reaction cannot accidentally swallow a drop that should fall through to whatever is underneath.

Graph-Level Events

Some events belong to the interface rather than to one element. They are placed from the create-node menu instead of from Element Settings, and like element events they are entry points with an execution output and no input.

  • On Construct: Fires once when this interface is created at runtime, and once per spawned instance, each in its own scope. This is where first-run setup goes
  • On Options Updated: Fires when a dialogue line presents its options, carrying their texts as a string array. Empty on lines with no options
  • On Text Revealed: Fires when the dialogue text finishes revealing, or immediately if there is no typewriter
  • On Dialogue Updated: Fires when a new dialogue line is shown, carrying its text on a string pin
  • On Variable Changed: Bound to one global variable at creation, and fires when that variable's value actually changes. Scalar and enum variables expose the new value on a typed pin; array and map variables fire without one
  • On Dialogue Tag Reached: Bound to one dialogue tag, and fires when a dialogue line carrying that tag is entered. See Dialogue Tags

Alongside them sit two dialogue commands you can call from a chain: Choose Option, which picks the option at a given index in the list On Options Updated announced, and Advance Dialogue, which advances the line the way a click would when no options are showing. Together they are what lets a custom interface drive the dialogue rather than only display it.

One Per Graph

On Construct, On Options Updated, On Text Revealed and On Dialogue Updated are limited to one node each per graph, and On Variable Changed and On Dialogue Tag Reached to one per variable and per tag. A second copy would run the same chain twice. A taken one is hidden from the create menu, and these nodes cannot be copied or duplicated.

Set & Get Property Nodes

Almost everything you can edit in Element Settings has a matching pair of nodes. There are 142 properties in the catalog, and all but one of them offer both a Set and a Get node.

Shape of a property node:

  • Set: an execution input and output, a Target pin that takes an element reference and a typed Value pin. While nothing is wired into Value, the node shows an inline editor for it, so simple cases need no extra nodes. Color properties get the same swatch picker used in the Designer, and image properties get the Designer's image selector
  • Get: a pure reference pill with a Target pin and a typed output, no execution pins

What the catalog covers:

  • Visibility, Is Enabled, Opacity, Z Order, Cursor and Rotation
  • Position X and Y, Width, Height, Scale and Max Width
  • Background Color, Background Opacity, Background Image, Border Color and Border Width, per side or in one value
  • Padding, Margin and Border Radius, per side or corner as well as uniform
  • Text, Font Family, Font Size, Text Color, Text Align, Line Height, Bold, Italic, Underline, Text Transform, plus text outline and drop shadow
  • Image Source, Fit, Object Position, Tint Color and Tint Opacity
  • Container arrangement: Gap, Justify, Align, Grid Columns, Scroll Orientation and Scroll Visibility
  • Control parts: checkbox Box and Check Mark, slider and progress Track, Fill and Thumb, dropdown Arrow and Options, plus Min, Max, Step, Slider Value, Checked, Active Index and Placeholder
  • Per-state colors for the hover, pressed, disabled and focused states
  • Behavior: Tooltip Text, Is Draggable and Drag Tags

Drag a Pin to Find the Right Node

Drag out of a Get Element node's output and drop it on empty canvas. The create menu opens filtered to the properties that actually apply to that element's type, and the node you pick is wired to the reference automatically. Dragging out of a typed value pin filters the same way by type.

Set Options is the one Set-only entry. It replaces a dropdown's item list from a wired string array, and has no Get counterpart.

Variables, Arrays, Maps & Enums

A User Interface file can read and write the project's global variables, and it can also define local variables of its own. Locals belong to that one file, so a reusable interface can carry its own state without polluting the project.

Both scopes use the same nodes you already know from the story script editor. Booleans, integers, floats and strings use the literal story-editor Get and Set nodes, and so do array and map variables. Enum, image, character and audio variables get their own Get and Set nodes with matching pins and colors.

Drag a variable from the Variables panel onto the canvas and a small menu asks whether you want Get or Set, exactly like the story canvas. Map operations (Get Value, Set Value, Has Key, Size, Keys, Values, Remove Key and Clear) are in the create menu's Map section and adopt their key and value types from the map you wire in.

Which Scope Wins

Globals are the channel between your story scripts and your interface: a story script sets a global, and On Variable Changed in an interface reacts to it. Local variables have no change event, because nothing outside the file can alter them.

Loops

For Each Loop comes in one flavour per array element type: boolean, integer, float, string, image, character and audio. Wire an array into the input, and the Loop Body output runs once per element with the element and its index on typed pins, then Completed runs once at the end. For Each Map does the same over a map's key and value pairs.

For Each Child is the element-typed sibling. Wire a container into its Container pin and the Loop Body runs once per child with the child element and its index, then Completed. A Recursive checkbox on the node switches it from direct children only to every descendant.

Together with Create Instance, For Each is how a save-slot row or an inventory grid becomes one element repeated instead of a dozen hand-placed copies.

Operators & Conversions

The script canvas reuses the operator set from the story script editor, so the nodes look and behave identically and the Node Types reference documents each one in full. The create menu groups them into sections:

  • Flow: Branch, Random Branch, Delay, For Each Child and Comment
  • Logic: Not, And, Or and Equal
  • Math: Plus, Minus, Multiply, Divide, Modulo, Random and the five integer comparisons
  • Float: the same arithmetic and comparisons for floats
  • Text: Concatenate, Length, To Upper Case, To Lower Case, Equal and Contains
  • Convert: conversions between boolean, integer and float, plus integer and float to and from string
  • Enum: Equal Enum
  • Image: Equal Image, which returns true when two image references point at the same file
  • Arrays: the For Each loops, plus Length for string arrays
  • Map: Get Value, Set Value, Has Key, Size, Keys, Values, Remove Key, Clear and For Each Map, all detailed under Map Operations
  • Audio: Play Audio
  • Dialogue: the dialogue events and commands described above
  • System: Is Desktop App, Quit Game, Reset Game, Open URL and On Construct

Utility Nodes

  • Delay: Waits the given number of seconds, then continues the chain. The duration is an editable value on the node (0.5 seconds by default) or a wired float
  • Open URL: Opens a website in the player's browser. A new tab in the HTML export, and the system browser in the Desktop App
  • Quit Game: Closes the exported Desktop App. It does nothing in the HTML export or in Play
  • Is Desktop App: A pure boolean that is true when the game runs as the exported Desktop App and false in the HTML export and in Play. Wire it into a Branch to hide a Quit button where it would not work
  • Reset Game: Restores every variable, character and element to its as-loaded state, like restarting the app. Execution continues to the next node
  • Play Audio: The story editor's audio node, reused here, so a menu can have its own click and hover sounds
  • Comment: The same resizable annotation box as the story canvas, which drags the nodes inside it and does nothing at runtime

Reusable Interfaces from the Graph

Any User Interface file can be placed inside another as an element. The graph adds the runtime half of that: spawning them, clearing them and reaching inside them.

  • Create Instance: spawns a copy of another User Interface file into a container at runtime. The node is bound to a file when you create it, and the create menu lists one Create row per other interface in your project. It has execution pins, a Target container pin, wireable Width and Height with a px or % unit dropdown each, plus an element output that hands you the spawned copy's root so the rest of the chain can style or position it. A percent value only resolves against a container that has a definite size
  • Clear Children: removes the instances spawned into a container. Elements you placed in the Designer are left alone
  • Get Element, Get Var and Set Var on an instance: drag out of an instance's element pin and the menu offers that file's exposed elements and variables as bound member nodes. Each carries the member's identity, so it stays correct across files. If the referenced file loses the member, the node outlines amber rather than silently doing nothing

A Row of Save Slots

Put a For Each Loop over an array of save names in front of a Create Instance node targeting a vertical box, then use Set Var on the spawned instance to fill in each slot's label. One interface file, one loop and the row builds itself at whatever length the array happens to be.

Creating Nodes

Right-click the canvas to open the create-node menu. It is the same menu as the story canvas, with sections tailored to interfaces: Variables, Elements, Properties, Instances, Animation and Tags, followed by the operator sections listed above. Any instance already placed in this interface also gets a section of its own, listing that file's members. Type in the search box to filter across all of them.

Other ways to place a node:

  • Drop a connection on empty canvas: the menu opens filtered to nodes that can accept what you dragged, and the node you pick is wired up automatically. A Compatible checkbox at the top reveals the rest
  • Drag a variable, element or animation from the Variables panel onto the canvas
  • Drag a User Interface file from the Content Browser onto the canvas to place a Create Instance node bound to it
  • Element Settings: the Create button on an event row
  • Your own shortcut: assign a chord to a node type under Settings → Keybindings, in the User Interface Editor group under Script → Create Nodes. These shortcuts are scoped to this canvas, so the same chord can spawn something different on the story canvas

Reroute Points

Double-click a connection line to insert a reroute point and bend the wire around whatever is in the way. It works exactly as it does on the story canvas: the point adopts the connection's type and color, chains with other points, costs one undo step and is removed either on its own with Delete or all at once with Clean Up Reroutes in the canvas Settings menu.

Reroute Points Are Cosmetic

A reroute point carries no behaviour: a connection enters and the same connection leaves. They are saved in the file so the bend survives a save, but they are spliced away before the graph leaves the editor - in the HTML and Desktop exports, in both Play lanes and in the Designer's own options dry run - so the running game never sees one. Full details are in Connections.

Next Steps

Keep going:
  • UI Animations - Keyframe an interface and drive it with Play Animation and On Animation Finished
  • Dialogue Tags - Let a line of dialogue cue the interface
  • Variables - Arrays, maps and enums, all reusable here
  • Connections - How typed pins and reroute points behave

Need Help?

Join our Discord community to ask questions, share your projects, report bugs, and get support from the team and other users.

Join Discord