Events
Event heads that start a graph, the payload each one carries, and the broadcast nodes that pass messages between blueprints.
An event head is where a graph begins. It has no execution input — the runtime enters the graph at the head and the chain runs from then. Everything else on this page hangs off that: a head's data outputs are the event's payload, and which heads you are even offered depends on where the blueprint lives.
Conventions
- A head has no exec input. There is nothing to wire into it. A graph may hold several heads, and each one runs its own chain when its event arrives. Every head listening for the same event, in one graph or in several, starts when the event arrives; none waits for another to finish, and one that fails does not stop the rest. Where the game waits for an event, as start-up waits for
On Game Ready, it waits for all of them. - Data outputs are the payload. Every output pin other than
thenreads one field of the runtime event payload, keyed by the pin id. A field the dispatch did not set readsnull— not0, not"". - Coordinates are design coordinates. An element's mouse heads report the element's own local design space. So does a head that runs because a press climbed from a descendant: it reads the point the press landed on in its own element's box, not in the box of the element under the pointer.
Mouse ClickandRight Clickplaced on a Surface blueprint report that Surface's design space instead. - Blueprint Value heads. A Blueprint Value graph accepts exactly two heads:
InitandOn Flush. - A disabled element stays silent. A widget that is disabled, or in text-editing state, does not dispatch its interaction heads at all.
- The keyboard heads are a family. While the palette is browsed, the four heads under Keyboard are one row, On Key. A search finds each head by its own name, and the ▾ beside a placed card's title switches it to another of the four. See Node families.
Where a head is offered
The palette filters heads by the blueprint's owner. A head that is not listed for your owner is not hidden behind a setting — it does not exist there.
| Owner | Heads offered |
|---|---|
App logic (globalMain) | App Boot, On Game Ready, On Fullscreen Changed, On Window Focus Changed, On Window Close Requested, On Action, the four keyboard heads, both preference heads |
Surface blueprint (surfaceMain) | Surface Init, Surface Unmount, Before Surface Exit, After Surface Enter, Mouse Click, Right Click, On Fullscreen Changed, On Window Focus Changed, On Window Close Requested, On Action, the four keyboard heads, both preference heads, both broadcast heads, Element Flush, Element Click |
Widget blueprint (widgetMain) | whatever that widget type declares; see the table below |
Widget inside a component definition (componentWidgetMain) | Init, On Flush, Unmount, Before Surface Exit, After Surface Enter and the heads its type declares in the table below. No keyboard, window, broadcast or bound element heads. |
Blueprint Value (widgetValue) | Init and On Flush |
| Story action blueprint | On Call |
For a widget the owner is only half the rule: each built-in widget type declares a set of event capabilities, and a head appears only if the widget's own capabilities list it. That is why a nl.list offers no Mouse Enter and a nl.container offers no Item Click.
| Widget type | Heads |
|---|---|
| every widget with a private blueprint | Init, On Flush, Unmount, Before Surface Exit, After Surface Enter, the four keyboard heads, On Fullscreen Changed, On Window Focus Changed, On Broadcast, On Any Broadcast, Element Flush, Element Click |
nl.container, nl.text, nl.image, nl.button, nl.dialog.sentence, nl.nvl.texts | the nine mouse heads, Focus, Blur, List Item Refresh |
nl.video | the nine mouse heads, Focus, Blur, Playback Ended |
nl.puppet | the nine mouse heads, Focus, Blur |
nl.switch | the nine mouse heads, Focus, Blur, Changed, Turned On, Turned Off |
nl.list, nl.notification.list, nl.choice.list, nl.nvl.list | Scroll, Scroll End, Item Render, Item Click, Item Hover, Selection Changed |
nl.slider | Drag Start, Value Changed, Drag End |
nl.textInput | Value Changed, Submit, Focus, Blur |
nl.frame | Page Event |
One further narrowing applies inside a widget blueprint: List Item Refresh is offered only when the element actually sits inside a List item template.
Event bubbling
Six pointer events climb the element tree: Mouse Click, Mouse Double Click, Mouse Down, Mouse Up, Mouse Wheel and Right Click. The event starts at the element under the pointer and passes through each parent in turn, up to the root of the Surface that element is drawn on. Every element on that path that has a head for the event runs it, and an element without one is passed over. An element with a head does not keep the event: its ancestors' heads run as well. Each head runs its own chain, so do not build a graph that depends on which of them runs first.
- What does not climb.
Mouse Enter,Mouse LeaveandMouse Movestay on the element the pointer is over. Keyboard, focus, flush and lifecycle events do not climb either, and neither do a widget's own events (Item Click,Value Changed,Changed,Submitand the rest). - Widgets without mouse heads. A list, slider, text input or frame offers no mouse heads and passes the six events up like any element without a head, so a container with a
Mouse Wheelhead hears the wheel over a list inside it. - Leaving a list. Inside an item template, a head runs for the row under the pointer. When the event climbs out of the list, that row is left behind: the elements above the list run with their own variables and read no row item.
- Leaving a component. From the root of a component, the event continues at the element that placed the component, so a container holding a placed component hears presses on it.
- The Surface. A click that reaches the Surface also runs the Surface blueprint's own
Mouse ClickorRight Click. - A Page in a Frame. A press on an element of a Page shown in a Frame climbs to the root of that Page and no further: the Frame and the elements around it do not hear it. The shown Page runs its own Surface
Mouse ClickorRight Clickfor the press, in its own design space, and then the Surface holding the Frame runs its own. A press on an empty part of the shown Page belongs to the Frame and climbs from there.
A graph cannot end the climb early. A script layer can, with ctx.stopPropagation(): the elements above do not hear the event, and the other heads on the same element still run. The heads of one element start together, and the climb moves on to its parent once they have finished. The nodes that used to steer bubbling, Continue Event Bubble and Stop Event Bubble, were removed. The one thing they were reliably used for, holding a window close open, is now Keep Window Open in the App category, which does that and nothing else.
App logic has no mouse heads. It hears pointer input through On Action, wherever the gesture lands, including where no interface takes it: a Page takes a press only where one of its elements is drawn, so a press on an empty part of a Page, or on a stage with nothing on it, still reaches the On Action heads of App logic.
While a Page or layer plays its exit animation, a press that no Page or layer takes is dropped. It does not reach the game stage or the Game UI on it, so it does not advance the story, and App logic does not hear it. A press on the Page arriving in its place reaches that Page as usual. The same holds inside a Frame while it changes page: the arriving Page's elements answer presses as usual, and no press goes further than the Frame, so none becomes a click on the Frame, the elements around it or the Surface.
While focus is in a text-entry element, keys reach no blueprint at all: the keyboard heads of App logic, Surfaces and widgets do not run and no input action is raised, so typing a name cannot advance dialogue on Space or open the menu on Escape. The field's own Value Changed and Submit heads still fire.
Application lifecycle
Entry points of App logic, plus the three window events that also reach Surfaces.
App Boot
blueprint.event.head.appBoot
Fires once when the UI runtime has finished starting and holds a runnable App logic blueprint.
| Pin | Direction | Type | Notes |
|---|---|---|---|
then | out · exec | — |
On Game Ready
blueprint.event.head.gameReady
Fires once per accepted NarraLeaf session: the LiveGame object exists and is stored in the Studio runtime, but liveGame.newGame() has not started the first scene yet.
The runtime initialises the NarraLeaf environment as a boot step, before the Surface system comes up. It mounts a Player on the compiled story of the Story library's default story entry scene, so LiveGame exists and that scene's assets begin preheating while the player is still on the main menu. Actually entering the game happens only on Start Game or a load, and it reuses that same initialised LiveGame: when Start Game targets the already-preheated default scene, entry is instant and this head does not fire again. Only a Start Game aimed at a different scene remounts the environment and fires it a second time. With no default story configured, an empty environment is mounted and the head still fires at boot.
| Pin | Direction | Type | Notes |
|---|---|---|---|
then | out · exec | — |
Initialise NarraLeaf preferences here — Set Auto Forward, Set Game Speed, Set Voice Volume, Set Sentence Speed — so they are in place before the player enters a game. Not in App Boot: despite the name it does not run first (On Game Ready fires ahead of it), and it carries no guarantee that a live game exists.
On Fullscreen Changed
blueprint.event.head.fullscreenChanged
Fires when the application window enters or leaves fullscreen, including a change made outside the game. It reaches App logic first, then every Surface on screen: the layers from the topmost down, the current Page, any Page shown in a Frame, and the Game UI Surfaces on the stage. On each of those Surfaces, every widget blueprint that places the head runs too. That is why a settings control can track the window without owning the Page.
| Pin | Direction | Type | Notes |
|---|---|---|---|
then | out · exec | — | |
isFullscreen | out · data | boolean | The state after the change. |
On Window Focus Changed
blueprint.event.head.windowFocusChanged
Fires when the application window gains or loses focus, for example when the player switches to another program and back. A desktop build follows its own window, which includes the window being sent behind by something outside the game; a web export follows the page's visibility and focus. It reaches the same blueprints as On Fullscreen Changed, in the same order. It is unrelated to the widget Focus and Blur heads, which are about which control holds the keyboard focus.
To read the current state from a graph that runs for some other reason, use Is Window Focused in the App nodes.
| Pin | Direction | Type | Notes |
|---|---|---|---|
then | out · exec | — | |
isFocused | out · data | boolean | The state after the change. |
On Window Close Requested
blueprint.event.head.windowCloseRequested
Fires when the player asks to close the window. The close is held open while App logic runs and then each Surface on screen, in the order On Fullscreen Changed describes. A Keep Window Open in any of them cancels the close, and the Surfaces after it are not asked. Absent one, the window proceeds to close. In Dev Mode this covers the Dev Mode window; in preview and production, the game window.
App logic and Surface blueprints only.
| Pin | Direction | Type | Notes |
|---|---|---|---|
then | out · exec | — |
Surface lifecycle and transitions
Surface Init and Surface Unmount belong to the Surface blueprint. The two transition heads also work in an element's private blueprint, but that element only receives them if it is mounted and alive at that moment.
Surface Init
blueprint.event.head.surfaceInit
Fires when a Page or Game UI Surface first enters the current runtime scope. A top-level Surface uses its own id as the scope; a sub-Page embedded through a Page component gets its own runtimeScopeId, so the same Page referenced by two Page components stays isolated.
| Pin | Direction | Type | Notes |
|---|---|---|---|
then | out · exec | — |
Surface Unmount
blueprint.event.head.surfaceUnmount
Fires when the Page or Game UI Surface leaves the current runtime scope, is replaced, or its embedding Page component instance unmounts.
| Pin | Direction | Type | Notes |
|---|---|---|---|
then | out · exec | — |
Before Surface Exit
blueprint.event.head.beforeSurfaceExit
Fires just before the current Page — or an embedded sub-Page — starts its exit animation.
| Pin | Direction | Type | Notes |
|---|---|---|---|
then | out · exec | — |
After Surface Enter
blueprint.event.head.afterSurfaceEnter
Fires after the current Page finishes its enter animation. With no animation, or under reduced motion, it fires once prepaint completes and the Surface settles into steady display.
| Pin | Direction | Type | Notes |
|---|---|---|---|
then | out · exec | — |
Element lifecycle
Init
blueprint.event.head.init
Fires once when an element that supports a private blueprint has completed its first render and mounted. It is not a pre-render hook. A Dev Mode bundle revision that remounts the Surface or the element fires it again. In a Blueprint Value it is the initial evaluation entry; later evaluations come from the hidden Element property dependencies, from a write to any variable the last evaluation read, or from an explicit On Flush.
| Pin | Direction | Type | Notes |
|---|---|---|---|
then | out · exec | — |
Unmount
blueprint.event.head.unmount
Fires when the element leaves the runtime element tree: the Surface closes or is replaced, a Frame switches sub-Page, a List item instance is removed, or visibility stops the element rendering at all. Runtime display: none only hides the element and keeps it mounted, so it does not fire.
| Pin | Direction | Type | Notes |
|---|---|---|---|
then | out · exec | — |
On Flush
blueprint.event.head.flush
Fires when this blueprint's own element has a property changed explicitly through the blueprint Host API and that change causes a redraw. Automatic CSS state styling — a hover or focus variant computed by the renderer — does not fire it. In a Blueprint Value it doubles as an explicit re-evaluation entry: the default Dialog Nametag refreshes as the dialogue advances through this head, without the Dialog remounting.
Flush is a batched post-commit notification. The runtime coalesces flushes for one element per frame, and a flush handler that writes to the element again lands its new flush in the next frame's batch — there is no synchronous re-entry.
| Pin | Direction | Type | Notes |
|---|---|---|---|
then | out · exec | — | |
element | out · data | element | The element that was flushed. |
Pointer
Available on the displayable widgets. Mouse Click and Right Click are additionally available on a Surface blueprint, where they mean "anywhere in this Surface". A Page takes a press only where one of its elements is drawn, so on a Page "anywhere" means anywhere on its elements. A Surface takes pointer input from the moment it is revealed, before its enter animation finishes, and stops when its exit animation begins. Six of these heads also run for input on the element's descendants; see Event bubbling.
Mouse Click
blueprint.event.head.mouseClick
Fires on a completed click on the element. On a Surface blueprint it means any click inside the Surface, and reports Surface design coordinates. A Page shown in a Frame runs its own for a click on one of its elements, before the Surface holding the Frame.
| Pin | Direction | Type | Notes |
|---|---|---|---|
then | out · exec | — | |
x | out · data | float | |
y | out · data | float |
Mouse Double Click
blueprint.event.head.mouseDoubleClick
Fires on a completed double click on the element.
| Pin | Direction | Type | Notes |
|---|---|---|---|
then | out · exec | — | |
x | out · data | float | |
y | out · data | float |
Mouse Down
blueprint.event.head.mouseDown
Fires when a mouse button goes down on the element.
| Pin | Direction | Type | Notes |
|---|---|---|---|
then | out · exec | — | |
x | out · data | float | |
y | out · data | float | |
button | out · data | integer | Mouse button number. |
Mouse Up
blueprint.event.head.mouseUp
Fires when a mouse button is released on the element.
| Pin | Direction | Type | Notes |
|---|---|---|---|
then | out · exec | — | |
x | out · data | float | |
y | out · data | float | |
button | out · data | integer | Mouse button number. |
Mouse Enter
blueprint.event.head.mouseEnter
Fires when the pointer enters the element's area.
| Pin | Direction | Type | Notes |
|---|---|---|---|
then | out · exec | — | |
x | out · data | float | |
y | out · data | float |
Mouse Leave
blueprint.event.head.mouseLeave
Fires when the pointer leaves the element's area.
| Pin | Direction | Type | Notes |
|---|---|---|---|
then | out · exec | — | |
x | out · data | float | |
y | out · data | float |
Mouse Move
blueprint.event.head.mouseMove
Fires as the pointer moves over the element.
| Pin | Direction | Type | Notes |
|---|---|---|---|
then | out · exec | — | |
x | out · data | float | |
y | out · data | float |
Mouse Wheel
blueprint.event.head.mouseWheel
Fires when the wheel scrolls over the element.
| Pin | Direction | Type | Notes |
|---|---|---|---|
then | out · exec | — | |
x | out · data | float | |
y | out · data | float | |
deltaX | out · data | float | Horizontal scroll amount. |
deltaY | out · data | float | Vertical scroll amount. |
Right Click
blueprint.event.head.rightClick
Fires on the element's context-menu event. On a Surface blueprint it means any right click inside the Surface, in Surface design coordinates; a Page shown in a Frame runs its own first, as with Mouse Click. When the event dispatches successfully, the default context menu is suppressed.
| Pin | Direction | Type | Notes |
|---|---|---|---|
then | out · exec | — | |
x | out · data | float | |
y | out · data | float |
Focus
Focus
blueprint.event.head.focus
Fires when the element takes keyboard, mouse or gamepad focus.
| Pin | Direction | Type | Notes |
|---|---|---|---|
then | out · exec | — |
Blur
blueprint.event.head.blur
Fires when the element loses focus.
| Pin | Direction | Type | Notes |
|---|---|---|---|
then | out · exec | — |
Keyboard
Keyboard events do not depend on element focus. A key goes first to App logic, then to the Surface that owns the keyboard, and each runs its own chain:
- With a modal layer on screen, the topmost modal layer owns the keyboard. No other Surface hears keys.
- Otherwise the current Page owns it. A layer that is not modal never takes the keyboard, so the Page beneath it keeps hearing keys.
- While the story is on screen with no Page or modal layer over it, the keyboard belongs to the stage, and every Game UI Surface there hears the key except the
notificationslot.
The widgets on the Surface that owns the keyboard hear the key through their own keyboard heads. Widgets on any other Surface do not.
A Surface hears keys from the moment it is revealed, through its enter animation, and stops when its exit animation begins. To ignore keys while a Surface is still entering, branch on the App category's Is Surface Entering.
Pick the filtered pair when you want one binding, and the Any Key pair when you want the key itself: On Key Down / On Key Up match a binding configured on the card and carry no payload, while Any Key Down / Any Key Up fire on every key and hand you key plus the modifier flags.
On Key Down
blueprint.event.head.keyDown
Fires when the runtime window receives a matching key-down. No element needs to hold focus.
| Pin | Direction | Type | Notes |
|---|---|---|---|
then | out · exec | — |
On-card fields
| Field | What |
|---|---|
Key | The key binding. The card shows the current binding; click it and a capture popover opens above the button — press any key to bind, with Ctrl / Alt / Shift / Meta combinations supported. A single key matches KeyboardEvent.key case-insensitively; a binding that includes modifiers also requires the modifier state to match. An empty binding never fires — use Any Key Down for "any key". |
On Key Up
blueprint.event.head.keyUp
Fires when the runtime window receives a matching key-up.
| Pin | Direction | Type | Notes |
|---|---|---|---|
then | out · exec | — |
On-card fields
| Field | What |
|---|---|
Key | Same binding control as On Key Down. An empty binding never fires — use Any Key Up for "any key". |
Any Key Down
blueprint.event.head.anyKeyDown
Fires on every key-down the runtime window receives.
| Pin | Direction | Type | Notes |
|---|---|---|---|
then | out · exec | — | |
key | out · data | string | The key's semantic value, matching KeyboardEvent.key. |
altKey | out · data | boolean | |
ctrlKey | out · data | boolean | |
shiftKey | out · data | boolean | |
metaKey | out · data | boolean | Meta / Command / Windows. |
Any Key Up
blueprint.event.head.anyKeyUp
Fires on every key-up the runtime window receives.
| Pin | Direction | Type | Notes |
|---|---|---|---|
then | out · exec | — | |
key | out · data | string | The key's semantic value, matching KeyboardEvent.key. |
altKey | out · data | boolean | |
ctrlKey | out · data | boolean | |
shiftKey | out · data | boolean | |
metaKey | out · data | boolean | Meta / Command / Windows. |
Input actions
On Action
blueprint.event.head.action
Fires when the input action picked on the card is raised, however the player raised it.
An action is a name the project gives to a gesture — "advance", "open the log", "dismiss" — and the bindings behind it live on the project's action vocabulary and on each Surface's answer to it, never on the graph. That is the point of the head: the author names the action, and which key or click means it stays the project's business. The card stores the action's id, so renaming the action leaves every graph pointing at it.
App logic and Surface graphs only. An action is panel-wide by construction, so it belongs to the two owners that speak for a whole panel: a Surface answers the actions it enables, and App logic answers a gesture that means the same thing on every page. A widget saying "a click here means advance" is the arrangement the vocabulary replaced — an element that wants the raw gesture still has its own mouse heads.
App logic hears every action in the vocabulary, before any Surface answers it. It hears a key whichever Surface owns the keyboard, and a pointer gesture wherever it lands. A Surface hears only the actions it answers: a key while it owns the keyboard, and a pointer gesture that lands on it. When both answer the same action, both run. Neither hears an input that was meant for a control. A pointer gesture on a button, switch, slider, text input or list raises no action, except a wheel over a list that cannot scroll any further that way, and neither does a key the focused control acts on, such as Enter on a focused button. A key held down raises its action once.
| Pin | Direction | Type | Notes |
|---|---|---|---|
then | out · exec | — | |
source | out · data | string | Which family of input raised it: pointer, key, gamepad, or touch. |
x | out · data | float | Where the gesture landed, in the same coordinates the mouse heads report. |
y | out · data | float |
On-card fields
| Field | What |
|---|---|
Action | One of the project's input actions. |
x and y are meaningless for a key or a gamepad binding and read null there, which is why source sits beside them: it is the pin that says whether the other two mean anything. The same action legitimately wants different behaviour depending — "advance" from a click has a place on screen to answer at, and "advance" from the space bar does not.
To ask whether an action is being held rather than react to it being raised, use Is Action Held in Input.
Bound element heads
These two heads bind a target widget on the same Surface — the way an Element node does — and then listen to that widget instead of their own. They also count as element bindings: an Element-targeted node only appears in the palette when the graph already holds a compatible Element, Element Flush or Element Click, and their element output can be wired straight into such a node's target input.
Element Flush
blueprint.event.head.elementFlush
Listens to the bound target's flush. When the target has a property changed explicitly through the Host API and redraws, this head runs in the current blueprint.
| Pin | Direction | Type | Notes |
|---|---|---|---|
then | out · exec | — | |
element | out · data | element | The bound element that was flushed. |
Element Click
blueprint.event.head.elementClick
Listens to the bound target's mouseClick. A real click on the target runs this head, and so does a click on any element inside the target, since the click climbs through it.
| Pin | Direction | Type | Notes |
|---|---|---|---|
then | out · exec | — | |
element | out · data | element | The bound element that was clicked. |
x | out · data | float | In the local design coordinates of the bound element. |
y | out · data | float | In the local design coordinates of the bound element. |
button | out · data | integer | Mouse button number. |
List
Heads on a list-like widget — nl.list and the Game UI wrappers nl.notification.list, nl.choice.list, nl.nvl.list. See the List nodes for reading and writing the runtime content. List Item Refresh is the odd one out: it fires on the private blueprints of the elements inside the item template, not on the list.
Item Render
blueprint.event.head.itemRender
Fires when the List renders one item instance, whether from bound data, the rows in List content, or Placeholder rows. The payload comes from that item's scope.
| Pin | Direction | Type | Notes |
|---|---|---|---|
then | out · exec | — | |
index | out · data | integer | |
count | out · data | integer | Items rendered in this pass. |
key | out · data | string | From the List's itemKeyPath when set. |
item | out · data | json | The item's data. A row of the List's struct, so a wire dragged off it offers the row's fields. |
Item Click
blueprint.event.head.itemClick
Fires when an item container is clicked. A click on a child element inside the item template is attributed to that item.
| Pin | Direction | Type | Notes |
|---|---|---|---|
then | out · exec | — | |
index | out · data | integer | |
count | out · data | integer | Items rendered in this pass. |
key | out · data | string | From the List's itemKeyPath when set. |
item | out · data | json | The item's data. A row of the List's struct, so a wire dragged off it offers the row's fields. |
Item Hover
blueprint.event.head.itemHover
Fires when the pointer enters an item container.
| Pin | Direction | Type | Notes |
|---|---|---|---|
then | out · exec | — | |
index | out · data | integer | |
count | out · data | integer | Items rendered in this pass. |
key | out · data | string | From the List's itemKeyPath when set. |
item | out · data | json | The item's data. A row of the List's struct, so a wire dragged off it offers the row's fields. |
Selection Changed
blueprint.event.head.selectionChanged
Fires when an item click moves the runtime selected index. The List seeds its selection from the selectedIndex property; clicking the already-selected item again within one runtime instance does not fire.
| Pin | Direction | Type | Notes |
|---|---|---|---|
then | out · exec | — | |
index | out · data | integer | The newly selected item. |
previousIndex | out · data | integer | -1 when nothing was selected. |
count | out · data | integer | Items rendered in this pass. |
key | out · data | string | Key of the newly selected item. |
item | out · data | json | Data of the newly selected item. A row of the List's struct, so a wire dragged off it offers the row's fields. |
Scroll
blueprint.event.head.scroll
Fires as the List's scroll container scrolls.
| Pin | Direction | Type | Notes |
|---|---|---|---|
then | out · exec | — | |
offset | out · data | float | Current scroll position. |
maxOffset | out · data | float | Maximum scroll position. |
progress | out · data | float | Normally 0 to 1. |
Scroll End
blueprint.event.head.scrollEnd
Fires when the scroll container reaches the end from somewhere else. It does not re-fire on further scroll events while already parked at the end; leave the end and return, and it fires again.
| Pin | Direction | Type | Notes |
|---|---|---|---|
then | out · exec | — | |
offset | out · data | float | Current scroll position. |
maxOffset | out · data | float | Maximum scroll position. |
progress | out · data | float | Normally 0 to 1. |
List Item Refresh
blueprint.event.head.listItemRefresh
Dispatched to the private blueprints of the elements under an item template whenever nl.list renders or refreshes that item. This is how a template child reads the current item's data. Each repeated item instance gets its own instance key and item scope, so two items sharing an element id do not share locals.
| Pin | Direction | Type | Notes |
|---|---|---|---|
then | out · exec | — | |
props | out · data | json | The item itself when it is an object, otherwise { value: item }. |
item | out · data | json | The item's data. A row of the List's struct, so a wire dragged off it offers the row's fields. |
index | out · data | integer | |
count | out · data | integer | Items rendered in this pass. |
key | out · data | string |
Slider
Heads on nl.slider. Every value here is the mapped value, matching props.value and the Slider nodes — the 0–1 normalized value is only available from the dedicated read node.
Drag Start
blueprint.event.head.sliderDragStart
Fires when a drag on the handle begins.
| Pin | Direction | Type | Notes |
|---|---|---|---|
then | out · exec | — | |
value | out · data | float | Mapped value. |
Value Changed
blueprint.event.head.sliderValueChanged
Fires when the runtime value changes. Dispatches are coalesced to one per animation frame, and while one chain is still running further changes collapse into a single pending dispatch — so a drag does not fire once per pixel, and previousValue spans everything that was coalesced. Writing the value with Set Slider Value does not dispatch this head.
| Pin | Direction | Type | Notes |
|---|---|---|---|
then | out · exec | — | |
value | out · data | float | Mapped value. |
previousValue | out · data | float | Mapped value. |
Drag End
blueprint.event.head.sliderDragEnd
Fires when a drag on the handle ends.
| Pin | Direction | Type | Notes |
|---|---|---|---|
then | out · exec | — | |
value | out · data | float | Mapped value. |
Switch
Three heads on nl.switch, and all three are about the player toggling it. Writing the state from a graph — Set Checked, Turn On, Turn Off, Toggle in Switch — does not dispatch any of them, so a graph that writes the switch it also listens to does not trigger itself.
One toggle raises Changed first and then exactly one of Turned On / Turned Off, in that order, each after the previous chain has finished. A toggle that lands on the state it was already in raises nothing.
Changed
blueprint.event.head.switchChanged
| Pin | Direction | Type | Notes |
|---|---|---|---|
then | out · exec | — | |
checked | out · data | boolean | The new state. |
previousChecked | out · data | boolean |
Turned On
blueprint.event.head.switchTurnedOn
The half of Changed that needs no branch — for the handler that only has something to do in one direction.
| Pin | Direction | Type | Notes |
|---|---|---|---|
then | out · exec | — |
Turned Off
blueprint.event.head.switchTurnedOff
| Pin | Direction | Type | Notes |
|---|---|---|---|
then | out · exec | — |
Text input
Heads on nl.textInput. See the Text input nodes for reading and writing the field.
Value Changed
blueprint.event.head.textInputValueChanged
Fires as the field's value changes.
| Pin | Direction | Type | Notes |
|---|---|---|---|
then | out · exec | — | |
value | out · data | string | |
previousValue | out · data | string |
Submit
blueprint.event.head.textInputSubmit
Fires when Enter is pressed in the field. An Enter that confirms an IME conversion does not submit. Keys typed into the field reach no keyboard head, so a widget On Key Down bound to Enter, on this field or any other widget, does not fire alongside Submit.
| Pin | Direction | Type | Notes |
|---|---|---|---|
then | out · exec | — | |
value | out · data | string | The value at submit time. |
Page
Page Event
blueprint.event.head.pageEvent
Fires in the private blueprint of the parent nl.frame when the sub-Page embedded in that Page component calls Emit Page Event. nl.frame is the only widget that offers it; the sending half lives in the App nodes.
| Pin | Direction | Type | Notes |
|---|---|---|---|
then | out · exec | — | |
event | out · data | string | Event name the sub-Page emitted. |
data | out · data | json | Event data the sub-Page emitted. |
Video
Playback Ended
blueprint.event.head.videoEnded
Fires in the private blueprint of a nl.video each time its clip plays to the end, once per play-through. It does not fire while Loop is on, when the clip is replaced, or when the page closes before the clip ends. A playing video moved to its end with Seek Video fires it as well. Playing the clip on the editor canvas does not fire it.
To start, stop or move the clip from a graph, use the Video nodes.
| Pin | Direction | Type | Notes |
|---|---|---|---|
then | out · exec | — |
Game preferences
Both heads subscribe to the active LiveGame's preference dispatcher. They are offered on App logic and Surface blueprints, and a change reaches App logic and then every Surface on screen, in the order On Fullscreen Changed describes. With no live game running there is no subscription and nothing fires; after On Game Ready the runtime re-subscribes on the new LiveGame. Preference setters like Set BGM Volume and NarraLeaf's own internal writes both trigger these heads, and a write of an identical value is not guaranteed to be deduplicated — so do not write a preference from the graph that listens to it, or you build a self-triggering loop. See the Game nodes for the getters and setters.
On Preference Changed
blueprint.event.head.preferenceChanged
Fires when the selected preference key changes.
| Pin | Direction | Type | Notes |
|---|---|---|---|
then | out · exec | — | |
value | out · data | json | The new value, typed by the selected key: boolean for autoForward / skip / skipping / skipReadText / showDialog / muteOnWindowBlur, string for voiceEndMode, float for the rest. It wires straight into a typed input such as Set Slider Value. |
previousValue | out · data | json | The runtime's cached previous value, same type as value. null when this session has no earlier snapshot for the key. |
On-card fields
| Field | What |
|---|---|
Preference | The key to watch, one of eighteen: autoForward, autoForwardDelay, skip, skipping, skipReadText, muteOnWindowBlur, showDialog, gameSpeed, cps, textRevealDuration, voiceVolume, voiceFadeDuration, voiceEndMode, bgmVolume, soundVolume, globalVolume, skipDelay, skipInterval. Empty subscribes to nothing; use On Any Preference Changed for "any key". |
On Any Preference Changed
blueprint.event.head.anyPreferenceChanged
Fires when any preference key changes. Use it to handle settings centrally — persisting the whole set, or refreshing an entire settings panel in one pass.
| Pin | Direction | Type | Notes |
|---|---|---|---|
then | out · exec | — | |
key | out · data | string | The canonical key name that changed, e.g. bgmVolume. |
value | out · data | json | The new value; runtime type follows key. |
previousValue | out · data | json | Same type as value; null with no earlier snapshot. |
Broadcast
Broadcast moves a named message between blueprints on the Surface it is sent from: the Surface's own blueprint plus every widget blueprint on it. A widget that a List repeats hears it once in each row on screen. It does not reach App logic and does not cross Surfaces, and the sender receives its own broadcast if it also listens. Targets are resolved from the document, not from the mounted React tree. All four nodes are offered on Surface and widget blueprints only.
On Broadcast
blueprint.event.head.onBroadcast
Fires when a broadcast with the configured name arrives.
| Pin | Direction | Type | Notes |
|---|---|---|---|
then | out · exec | — | |
data | out · data | json | The broadcast payload. |
sender | out · data | string | Element id of the sender; empty string when there is none. |
On-card fields
| Field | What |
|---|---|
Event | The broadcast name to listen for. Matched exactly, after trimming. |
On Any Broadcast
blueprint.event.head.onAnyBroadcast
Fires on every broadcast this blueprint receives, whatever its name.
| Pin | Direction | Type | Notes |
|---|---|---|---|
then | out · exec | — | |
event | out · data | string | The broadcast name. |
data | out · data | json | The broadcast payload. |
sender | out · data | string | Element id of the sender; empty string when there is none. |
Send Broadcast
blueprint.broadcast.send · Latent
Sends a broadcast to the running UI and continues from next once every listener chain has run. An empty or whitespace-only event name is an execution error, not a silent no-op. The sender id is filled in from the executing blueprint's element.
| Pin | Direction | Type | Notes |
|---|---|---|---|
in | in · exec | — | |
next | out · exec | — | |
event | in · data | string | Accepts an on-card literal. |
data | in · data | json |
Get Listener Count
blueprint.broadcast.getListenerCount · Pure
How many listeners are currently registered for a broadcast name on this Surface.
The count is of heads, not blueprints: a graph holding two matching heads counts twice, and an On Any Broadcast counts for every name. Heads are counted from the document, so an element that is not currently mounted still counts.
| Pin | Direction | Type | Notes |
|---|---|---|---|
event | in · data | string | Accepts an on-card literal. |
count | out · data | integer |
Story actions
On Call
blueprint.event.head.onCall
The single entry point of a Story Action Blueprint — a blueprint bound one-to-one to a story action. It is offered nowhere else. Story-action graphs are compiled into a NarraLeaf Script action and run through the story compiler, never through the UI event dispatch, which is why none of the UI heads on this page appear in that owner.
| Pin | Direction | Type | Notes |
|---|---|---|---|
then | out · exec | — |