NarraLeaf

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 then reads one field of the runtime event payload, keyed by the pin id. A field the dispatch did not set reads null — not 0, 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 Click and Right Click placed on a Surface blueprint report that Surface's design space instead.
  • Blueprint Value heads. A Blueprint Value graph accepts exactly two heads: Init and On 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.

OwnerHeads 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 blueprintOn 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 typeHeads
every widget with a private blueprintInit, 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.textsthe nine mouse heads, Focus, Blur, List Item Refresh
nl.videothe nine mouse heads, Focus, Blur, Playback Ended
nl.puppetthe nine mouse heads, Focus, Blur
nl.switchthe nine mouse heads, Focus, Blur, Changed, Turned On, Turned Off
nl.list, nl.notification.list, nl.choice.list, nl.nvl.listScroll, Scroll End, Item Render, Item Click, Item Hover, Selection Changed
nl.sliderDrag Start, Value Changed, Drag End
nl.textInputValue Changed, Submit, Focus, Blur
nl.framePage 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 Leave and Mouse Move stay 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, Submit and 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 Wheel head 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 Click or Right 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 Click or Right Click for 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.

PinDirectionTypeNotes
thenout · 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.

PinDirectionTypeNotes
thenout · 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.

PinDirectionTypeNotes
thenout · exec—
isFullscreenout · databooleanThe 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.

PinDirectionTypeNotes
thenout · exec—
isFocusedout · databooleanThe 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.

PinDirectionTypeNotes
thenout · 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.

PinDirectionTypeNotes
thenout · 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.

PinDirectionTypeNotes
thenout · exec—

Before Surface Exit

blueprint.event.head.beforeSurfaceExit

Fires just before the current Page — or an embedded sub-Page — starts its exit animation.

PinDirectionTypeNotes
thenout · 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.

PinDirectionTypeNotes
thenout · 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.

PinDirectionTypeNotes
thenout · 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.

PinDirectionTypeNotes
thenout · 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.

PinDirectionTypeNotes
thenout · exec—
elementout · dataelementThe 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.

PinDirectionTypeNotes
thenout · exec—
xout · datafloat
yout · datafloat

Mouse Double Click

blueprint.event.head.mouseDoubleClick

Fires on a completed double click on the element.

PinDirectionTypeNotes
thenout · exec—
xout · datafloat
yout · datafloat

Mouse Down

blueprint.event.head.mouseDown

Fires when a mouse button goes down on the element.

PinDirectionTypeNotes
thenout · exec—
xout · datafloat
yout · datafloat
buttonout · dataintegerMouse button number.

Mouse Up

blueprint.event.head.mouseUp

Fires when a mouse button is released on the element.

PinDirectionTypeNotes
thenout · exec—
xout · datafloat
yout · datafloat
buttonout · dataintegerMouse button number.

Mouse Enter

blueprint.event.head.mouseEnter

Fires when the pointer enters the element's area.

PinDirectionTypeNotes
thenout · exec—
xout · datafloat
yout · datafloat

Mouse Leave

blueprint.event.head.mouseLeave

Fires when the pointer leaves the element's area.

PinDirectionTypeNotes
thenout · exec—
xout · datafloat
yout · datafloat

Mouse Move

blueprint.event.head.mouseMove

Fires as the pointer moves over the element.

PinDirectionTypeNotes
thenout · exec—
xout · datafloat
yout · datafloat

Mouse Wheel

blueprint.event.head.mouseWheel

Fires when the wheel scrolls over the element.

PinDirectionTypeNotes
thenout · exec—
xout · datafloat
yout · datafloat
deltaXout · datafloatHorizontal scroll amount.
deltaYout · datafloatVertical 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.

PinDirectionTypeNotes
thenout · exec—
xout · datafloat
yout · datafloat

Focus

Focus

blueprint.event.head.focus

Fires when the element takes keyboard, mouse or gamepad focus.

PinDirectionTypeNotes
thenout · exec—

Blur

blueprint.event.head.blur

Fires when the element loses focus.

PinDirectionTypeNotes
thenout · 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 notification slot.

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.

PinDirectionTypeNotes
thenout · exec—

On-card fields

FieldWhat
KeyThe 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.

PinDirectionTypeNotes
thenout · exec—

On-card fields

FieldWhat
KeySame 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.

PinDirectionTypeNotes
thenout · exec—
keyout · datastringThe key's semantic value, matching KeyboardEvent.key.
altKeyout · databoolean
ctrlKeyout · databoolean
shiftKeyout · databoolean
metaKeyout · databooleanMeta / Command / Windows.

Any Key Up

blueprint.event.head.anyKeyUp

Fires on every key-up the runtime window receives.

PinDirectionTypeNotes
thenout · exec—
keyout · datastringThe key's semantic value, matching KeyboardEvent.key.
altKeyout · databoolean
ctrlKeyout · databoolean
shiftKeyout · databoolean
metaKeyout · databooleanMeta / 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.

PinDirectionTypeNotes
thenout · exec—
sourceout · datastringWhich family of input raised it: pointer, key, gamepad, or touch.
xout · datafloatWhere the gesture landed, in the same coordinates the mouse heads report.
yout · datafloat

On-card fields

FieldWhat
ActionOne 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.

PinDirectionTypeNotes
thenout · exec—
elementout · dataelementThe 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.

PinDirectionTypeNotes
thenout · exec—
elementout · dataelementThe bound element that was clicked.
xout · datafloatIn the local design coordinates of the bound element.
yout · datafloatIn the local design coordinates of the bound element.
buttonout · dataintegerMouse 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.

PinDirectionTypeNotes
thenout · exec—
indexout · datainteger
countout · dataintegerItems rendered in this pass.
keyout · datastringFrom the List's itemKeyPath when set.
itemout · datajsonThe 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.

PinDirectionTypeNotes
thenout · exec—
indexout · datainteger
countout · dataintegerItems rendered in this pass.
keyout · datastringFrom the List's itemKeyPath when set.
itemout · datajsonThe 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.

PinDirectionTypeNotes
thenout · exec—
indexout · datainteger
countout · dataintegerItems rendered in this pass.
keyout · datastringFrom the List's itemKeyPath when set.
itemout · datajsonThe 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.

PinDirectionTypeNotes
thenout · exec—
indexout · dataintegerThe newly selected item.
previousIndexout · datainteger-1 when nothing was selected.
countout · dataintegerItems rendered in this pass.
keyout · datastringKey of the newly selected item.
itemout · datajsonData 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.

PinDirectionTypeNotes
thenout · exec—
offsetout · datafloatCurrent scroll position.
maxOffsetout · datafloatMaximum scroll position.
progressout · datafloatNormally 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.

PinDirectionTypeNotes
thenout · exec—
offsetout · datafloatCurrent scroll position.
maxOffsetout · datafloatMaximum scroll position.
progressout · datafloatNormally 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.

PinDirectionTypeNotes
thenout · exec—
propsout · datajsonThe item itself when it is an object, otherwise { value: item }.
itemout · datajsonThe item's data. A row of the List's struct, so a wire dragged off it offers the row's fields.
indexout · datainteger
countout · dataintegerItems rendered in this pass.
keyout · datastring

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.

PinDirectionTypeNotes
thenout · exec—
valueout · datafloatMapped 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.

PinDirectionTypeNotes
thenout · exec—
valueout · datafloatMapped value.
previousValueout · datafloatMapped value.

Drag End

blueprint.event.head.sliderDragEnd

Fires when a drag on the handle ends.

PinDirectionTypeNotes
thenout · exec—
valueout · datafloatMapped 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

PinDirectionTypeNotes
thenout · exec—
checkedout · databooleanThe new state.
previousCheckedout · databoolean

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.

PinDirectionTypeNotes
thenout · exec—

Turned Off

blueprint.event.head.switchTurnedOff

PinDirectionTypeNotes
thenout · 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.

PinDirectionTypeNotes
thenout · exec—
valueout · datastring
previousValueout · datastring

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.

PinDirectionTypeNotes
thenout · exec—
valueout · datastringThe 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.

PinDirectionTypeNotes
thenout · exec—
eventout · datastringEvent name the sub-Page emitted.
dataout · datajsonEvent 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.

PinDirectionTypeNotes
thenout · 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.

PinDirectionTypeNotes
thenout · exec—
valueout · datajsonThe 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.
previousValueout · datajsonThe runtime's cached previous value, same type as value. null when this session has no earlier snapshot for the key.

On-card fields

FieldWhat
PreferenceThe 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.

PinDirectionTypeNotes
thenout · exec—
keyout · datastringThe canonical key name that changed, e.g. bgmVolume.
valueout · datajsonThe new value; runtime type follows key.
previousValueout · datajsonSame 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.

PinDirectionTypeNotes
thenout · exec—
dataout · datajsonThe broadcast payload.
senderout · datastringElement id of the sender; empty string when there is none.

On-card fields

FieldWhat
EventThe 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.

PinDirectionTypeNotes
thenout · exec—
eventout · datastringThe broadcast name.
dataout · datajsonThe broadcast payload.
senderout · datastringElement 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.

PinDirectionTypeNotes
inin · exec—
nextout · exec—
eventin · datastringAccepts an on-card literal.
datain · datajson

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.

PinDirectionTypeNotes
eventin · datastringAccepts an on-card literal.
countout · datainteger

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.

PinDirectionTypeNotes
thenout · exec—

On this page