NarraLeaf

Game

Nodes that drive the running game — start and quit it, advance dialog, read and write player preferences, and manage saves and history.

The Game category is the seam between a blueprint and the running story. Everything here talks to the live NarraLeaf runtime: the playthrough itself, the dialog on screen, the player's preferences, the project's local saves, and the dialogue history. A title screen, a config screen, a save/load grid and a backlog are all built out of this page.

Every node here needs the running game. The editor canvas has none — a Game node placed there fails with Host API unavailable (use Dev Mode), and a Blueprint Value that reads one previews as empty. Verify all of it in Dev Mode.

Conventions

  • Pure or latent, near enough. Forty-one getters are Pure and may appear in event, function and macro graphs, and back a Blueprint Value. Forty-seven are Latent, so event and macro only — a latent node has nowhere to hand a pending result inside a function. Clear Visited is the eighty-ninth and the odd one: effectful but synchronous, so it is event and macro like a latent node without being one.
  • A host API is not a playthrough. List Saves, Get Save Metadata, Get Save Time, Get Save Playtime, Get Save Preview, Delete Save, List Auto Saves and Get Latest Auto Save read the project's save store and work between playthroughs, with no game running. So do the endings, visited, DLC and build-variant readers — an endings gallery is opened from the title screen, before any game exists. Everything that serializes, deserializes or commands the live game needs one, and fails without it.
  • State getters degrade; preference getters do not. Every pure state read — Is In Game, Is Game Overlay, Get Nametag, Get Speaker Avatar, Get Speaker Color, Get Dialog Text, Is Narrator, Is Dialog Waiting, Get Choice Count, Get Notifications, Is NVL Mode, Is Text Read, Has Read Text, Can Undo History, Can Redo History, Get Track Volume, both playtime reads, and the endings, visited, DLC, build-variant and character readers — answers with a neutral value when nothing is playing: false, null, 0, an empty array, opaque white for a colour, unity for a track volume. That is what lets one shared Page branch on them, and what lets a gallery row bind a locked look straight to a pin. The sixteen preference getters are the exception: they read the live GamePreference and fail when there is no game. Is Dialog Shown is one of them — it reads the showDialog preference and is named for the question rather than the key.
  • Initialise preferences from On Game Ready, not App Boot. App Boot can run before the LiveGame exists, and a preference write with no live game fails. See Events.
  • Save ids are validated. An id is trimmed, may not be empty, and may not contain path separators or control characters. The file on disk is named from a hash of it; the id you chose is kept inside the record's metadata.

The playthrough

Start Game and Quit Game are tail nodes: they hand control to the runtime and have no exec output, so whatever should happen next belongs in the story, or on the Page they open.

Start Game

blueprint.game.startStory · Latent

Starts the Story and Scene picked on the card and switches to the game stage. Once the first frame is ready the current Page stack is hidden beneath the game, so a later Go Page layers on top of the stage instead of replacing it.

PinDirectionTypeNotes
inin · exec
storyIdin · datastringOptional. Wired wins over the card.
sceneIdin · datastringOptional. Wired wins over the card — this is the pin Import Progress hands its Scene to.
startBlockIdin · datastringOptional, labelled From Row and wire-only. Enters the scene at that row instead of at its start.

On-card fields

FieldWhat
StoryThe story to run. Required unless storyId is wired.
SceneThe scene to enter. The list is filtered to the chosen story. Required unless sceneId is wired.

The picker is what an author reaches for nine times in ten: it lists the project's own stories and cannot be spelled wrong. The pins are for the tenth, where the target is not known when the graph is written — a Continue button that resumes wherever the player was.

Quit Game

blueprint.game.quit · Latent

Ends the playthrough and opens the Page picked on the card. One call does all of it: drop the live game and its session, cancel any start request still pending, clear the dialog nametag, restore the ordinary Page display, then navigate — you do not wire a Go Page after it.

PinDirectionTypeNotes
inin · exec

On-card fields

FieldWhat
PageThe Surface to open once the game is gone. Required.

Is In Game

blueprint.game.isInGame · Pure

True while the game stage is showing and a session exists — including when a Page overlay is open above it. False in an ordinary Page preview, before the first Start Game, and after Quit Game.

PinDirectionTypeNotes
isInGameout · databoolean

Is Game Overlay

blueprint.game.isGameOverlay · Pure

Whether this Surface instance is running as a UI layer above the game. A Page opened with Go Page after Start Game or Load Save reports true, as do the built-in game UI Surfaces such as the dialog slot; a Page embedded through nl.frame inherits its parent's answer. Ordinary application Pages, Page previews and the Page that Quit Game opens report false.

PinDirectionTypeNotes
isGameOverlayout · databoolean

The answer is locked when the Page instance is created, so a pause menu still playing its exit animation reports true even though Quit Game has already begun tearing the session down. Ask Is In Game whether the runtime is still there; ask this one what a shared Page should show.

Advancing the story

Next

blueprint.game.next · Latent

Fires the runtime's virtual click. It clicks the dialog wrapper's own target when there is one, which leaves the engine to decide between "finish the sentence being typed" and "go to the next step"; with no dialog target it falls back to clicking the player's main content. It never forces a skip.

PinDirectionTypeNotes
inin · exec
nextout · execFires once the advance request completed.

Fails when no game runtime is active.

Skip

blueprint.game.skip · Latent

Skips the current dialog line. This is the explicit author-provided Skip action; the default dialog template does not bind it for you.

PinDirectionTypeNotes
inin · exec
nextout · exec

Fails when no game runtime is active.

Select Choice

blueprint.game.choose · Latent

Picks an option in the active choice menu by its original index. Hidden options are filtered out of what the player sees but are still counted, so the indices a menu hands you are not necessarily contiguous — feed back the index the item carries rather than its position in the list. The host re-checks the target's hidden and disabled state and silently refuses an illegal pick.

PinDirectionTypeNotes
inin · exec
nextout · exec
indexin · dataintegerMust be a non-negative integer. Accepts an on-card literal.

Fails when no choice menu is open.

Get Choice Count

blueprint.game.getChoiceCount · Pure

How many options the active choice menu shows. Hidden options are not counted. Returns 0 once the menu closes.

PinDirectionTypeNotes
countout · datainteger

Dialog

Dialog-bound elements are flushed whenever the dialog's text, speaker or completion state changes, so a widget that reads one of these getters from On Flush stays current as the story advances without remounting.

Get Nametag

blueprint.game.getNametag · Pure

The current speaker's name. null for narration, for a line with no speaker, and for a speaker whose name is empty or blank.

PinDirectionTypeNotes
nametagout · datastringnull when there is no speaker.

The default dialog template drives a plain nl.text nametag from that widget's own blueprint — Init and On Flush into Get Nametag, then a null check onto the text and its opacity. No special nametag widget is involved.

Get Speaker Avatar

blueprint.game.getSpeakerAvatar · Pure

The speaking character's dialog avatar. The engine resolves it off that character's live portrait, so it already reflects the differential the character is currently wearing and stays right across undo, load and skip. An avatar URL the project cannot map back to an asset resolves to null rather than to a guess.

PinDirectionTypeNotes
avatarout · dataImageAsset|nullFeed to an image node or an image Blueprint Value.

Get Dialog Text

blueprint.game.getDialogText · Pure

The line currently on screen, as text. Empty string when nothing is speaking.

PinDirectionTypeNotes
textout · datastring

Get Speaker Color

blueprint.game.getSpeakerColor · Pure

The speaking character's accent colour, for tinting a nametag or a name plate.

PinDirectionTypeNotes
colorout · dataRGBAColorOpaque white when nobody is speaking. The pin is a non-nullable colour, so there is no "absent" it could carry.

Is Narrator

blueprint.game.isNarrator · Pure

Whether the line on screen is narration rather than a character speaking. The clean way to swap a dialog box's whole look for narration, instead of null-checking Get Nametag.

PinDirectionTypeNotes
isNarratorout · databoolean

Is Dialog Waiting

blueprint.game.isDialogWaiting · Pure

Whether the line has finished typing and the game is waiting for the player to advance. This is the pin a "click to continue" indicator binds to.

PinDirectionTypeNotes
isWaitingout · databooleanfalse with no host and with no line on screen — the indicator has to lay out before any game exists.

Get Character

blueprint.game.getCharacter · Pure

The project's record for one character, picked on the card. Unlike the three speaker reads above, this one is not about who is talking — it is how a character sheet, a relationship screen or a cast gallery draws somebody who is not on stage.

PinDirectionTypeNotes
nameout · datastringEmpty when nothing is picked or the character is gone.
characterColorout · dataRGBAColorThe default colour when there is no record.
characterAvatarout · dataImageAsset|null
foundout · databoolean

On-card fields

FieldWhat
CharacterOne of the project's characters.

Is NVL Mode

blueprint.game.isNvlMode · Pure

Whether the game is currently in NVL mode.

PinDirectionTypeNotes
isNvlModeout · databoolean

Get Notifications

blueprint.game.getNotifications · Pure

The notifications the runtime is currently showing, mirrored from the engine's notification component. Empty array when there are none.

PinDirectionTypeNotes
notificationsout · dataarray

Entry fields

FieldWhat
idNotification id.
messageNotification text.

The default notification template does not use this node: its list item template reads message off the item props instead.

Show Dialog

blueprint.game.showDialog · Latent

Sets the showDialog preference to true, bringing the dialog UI back. It changes runtime preference only — not the UI document, and not the story position.

PinDirectionTypeNotes
inin · exec
nextout · exec

Fails when no game runtime is active.

Hide Dialog

blueprint.game.hideDialog · Latent

Sets showDialog to false. The dialog wrapper keeps its interaction semantics while hidden, so Next, Skip and a later Show Dialog still work.

PinDirectionTypeNotes
inin · exec
nextout · exec

Fails when no game runtime is active.

Toggle Dialog Display

blueprint.game.toggleDialogDisplay · Latent

Reads showDialog and writes the opposite — one node for a single UI control. It touches nothing else: not the dialog text, not the nametag, not the sentence speed.

PinDirectionTypeNotes
inin · exec
nextout · exec

Fails when no game runtime is active.

Is Dialog Shown

blueprint.game.isDialogShown · Pure

The read half of those three. It is a preference getter under a state getter's name — the value it reads is showDialog — so it fails when there is no live game rather than degrading.

PinDirectionTypeNotes
isShownout · databoolean

Preferences

Each pair below maps to one field of the engine's GamePreference on the live game. The getter is pure and safe inside a Blueprint Value; the setter is latent and validates before it writes — a bad value fails the node rather than being clamped. showDialog has no pair here; Show Dialog, Hide Dialog, Toggle Dialog Display and Is Dialog Shown cover it.

Every setter here fails when no game runtime is active, and so does every getter except Get Track Volume, which reads the engine's bus mixer rather than GamePreference. To seed a new playthrough's preferences, hang the setters off On Game Ready, which runs after the LiveGame exists and before the first line plays.

Get Sentence Speed

blueprint.game.getCps · Pure

Reads cps, the characters per second at which a sentence types out.

PinDirectionTypeNotes
cpsout · datafloat

Set Sentence Speed

blueprint.game.setSentenceSpeed · Latent

Writes cps. Must be a finite number greater than 0.

PinDirectionTypeNotes
inin · exec
nextout · exec
cpsin · datafloatAccepts an on-card literal.

Get Auto Forward

blueprint.game.getAutoForward · Pure

Reads autoForward, whether the game advances on its own once a line finishes.

PinDirectionTypeNotes
autoForwardout · databoolean

Set Auto Forward

blueprint.game.setAutoForward · Latent

Writes autoForward. Must be a boolean.

PinDirectionTypeNotes
inin · exec
nextout · exec
autoForwardin · databoolean

Get Auto Forward Delay

blueprint.game.getAutoForwardDelay · Pure

Reads autoForwardDelay, how long auto-forward waits on a finished line before advancing.

PinDirectionTypeNotes
autoForwardDelayout · datafloat

Set Auto Forward Delay

blueprint.game.setAutoForwardDelay · Latent

PinDirectionTypeNotes
inin · exec
nextout · exec
autoForwardDelayin · datafloatAccepts an on-card literal.

Get Skip

blueprint.game.getSkip · Pure

Reads skip, whether skipping is allowed at all.

PinDirectionTypeNotes
skipout · databoolean

Set Skip

blueprint.game.setSkip · Latent

Writes skip. Must be a boolean.

PinDirectionTypeNotes
inin · exec
nextout · exec
skipin · databoolean

Get Skipping

blueprint.game.getSkipping · Pure

Reads skipping, whether the game is skipping right now. skip above is the setting that permits it; this is the state.

PinDirectionTypeNotes
skippingout · databoolean

Set Skipping

blueprint.game.setSkipping · Latent

Turns skipping on or off from the graph — a skip button that latches, rather than the hold-to-skip Skip action.

PinDirectionTypeNotes
inin · exec
nextout · exec
skippingin · databoolean

Get Skip Read Text

blueprint.game.getSkipReadText · Pure

Reads skipReadText, whether skipping stops at a line the player has not seen before. What it means by "read" is the record behind Text read.

PinDirectionTypeNotes
skipReadTextout · databoolean

Set Skip Read Text

blueprint.game.setSkipReadText · Latent

PinDirectionTypeNotes
inin · exec
nextout · exec
skipReadTextin · databoolean

Get Skip Delay

blueprint.game.getSkipDelay · Pure

Reads skipDelay in milliseconds — how long the player holds before skipping starts.

PinDirectionTypeNotes
skipDelayout · datafloat

Set Skip Delay

blueprint.game.setSkipDelay · Latent

Writes skipDelay. Must be a finite number greater than or equal to 0, in milliseconds.

PinDirectionTypeNotes
inin · exec
nextout · exec
skipDelayin · datafloatAccepts an on-card literal.

Get Skip Interval

blueprint.game.getSkipInterval · Pure

Reads skipInterval in milliseconds — the gap between two skipped lines.

PinDirectionTypeNotes
skipIntervalout · datafloat

Set Skip Interval

blueprint.game.setSkipInterval · Latent

Writes skipInterval. Must be a finite number greater than 0, in milliseconds.

PinDirectionTypeNotes
inin · exec
nextout · exec
skipIntervalin · datafloatAccepts an on-card literal.

Get Game Speed

blueprint.game.getGameSpeed · Pure

Reads gameSpeed, the global speed multiplier.

PinDirectionTypeNotes
gameSpeedout · datafloat

Set Game Speed

blueprint.game.setGameSpeed · Latent

Writes gameSpeed. Must be a finite number greater than 0.

PinDirectionTypeNotes
inin · exec
nextout · exec
gameSpeedin · datafloatAccepts an on-card literal.

Get Global Volume

blueprint.game.getGlobalVolume · Pure

Reads globalVolume, the master volume every other channel is scaled by.

PinDirectionTypeNotes
globalVolumeout · datafloat

Set Global Volume

blueprint.game.setGlobalVolume · Latent

Writes globalVolume. Must be a finite number greater than or equal to 0.

PinDirectionTypeNotes
inin · exec
nextout · exec
globalVolumein · datafloatAccepts an on-card literal.

Get BGM Volume

blueprint.game.getBgmVolume · Pure

Reads bgmVolume, the background music channel.

PinDirectionTypeNotes
bgmVolumeout · datafloat

Set BGM Volume

blueprint.game.setBgmVolume · Latent

Writes bgmVolume. Must be a finite number greater than or equal to 0.

PinDirectionTypeNotes
inin · exec
nextout · exec
bgmVolumein · datafloatAccepts an on-card literal.

Get SFX Volume

blueprint.game.getSoundVolume · Pure

Reads soundVolume, the sound-effect channel.

PinDirectionTypeNotes
soundVolumeout · datafloat

Set SFX Volume

blueprint.game.setSoundVolume · Latent

Writes soundVolume. Must be a finite number greater than or equal to 0.

PinDirectionTypeNotes
inin · exec
nextout · exec
soundVolumein · datafloatAccepts an on-card literal.

Get Voice Volume

blueprint.game.getVoiceVolume · Pure

Reads voiceVolume, the voice-over channel.

PinDirectionTypeNotes
voiceVolumeout · datafloat

Set Voice Volume

blueprint.game.setVoiceVolume · Latent

Writes voiceVolume. Must be a finite number greater than or equal to 0.

PinDirectionTypeNotes
inin · exec
nextout · exec
voiceVolumein · datafloatAccepts an on-card literal.

Get Voice Fade Duration

blueprint.game.getVoiceFadeDuration · Pure

Reads voiceFadeDuration in milliseconds — how long a voice clip takes to fade when the line ends.

PinDirectionTypeNotes
voiceFadeDurationout · datafloatLabelled Voice Fade on the card.

Set Voice Fade Duration

blueprint.game.setVoiceFadeDuration · Latent

Writes voiceFadeDuration. Must be a finite number greater than or equal to 0, in milliseconds.

PinDirectionTypeNotes
inin · exec
nextout · exec
voiceFadeDurationin · datafloatLabelled Voice Fade on the card. Accepts an on-card literal.

Get Voice End Mode

blueprint.game.getVoiceEndMode · Pure

Reads voiceEndMode: what happens to a voice clip that is still playing when its line ends.

PinDirectionTypeNotes
voiceEndModeout · datastringOne of "fade", "stop", "none".

Set Voice End Mode

blueprint.game.setVoiceEndMode · Latent

Writes voiceEndMode. Must be exactly "fade", "stop" or "none".

PinDirectionTypeNotes
inin · exec
nextout · exec
voiceEndModein · datastringAccepts an on-card literal.

Get Track Volume

blueprint.game.getTrackVolume · Pure

The player's volume for one of the project's audio tracks. The mixer is a tree of tracks the project declares — a bus per character if you want one — and this pair is what a settings screen with a row per track is built from.

It is the odd one in this section: the value comes off the engine's bus mixer rather than out of GamePreference, so it does not fail without a live game. Nothing picked, or nothing to ask, reads as unity — a slider bound to it sits at the top rather than collapsing to zero while the page is still being wired.

PinDirectionTypeNotes
audioTrackIdin · datastringOptional. Wired wins over the card.
volumeout · datafloat1 when no track is named.

On-card fields

FieldWhat
TrackOne of the project's audio tracks.

Set Track Volume

blueprint.game.setTrackVolume · Latent

PinDirectionTypeNotes
inin · exec
nextout · exec
audioTrackIdin · datastringOptional. Wired wins over the card.
volumein · datafloatAccepts an on-card literal.

On-card fields

FieldWhat
TrackOne of the project's audio tracks.

Saves

Saves are project-local and keyed by an id you choose. Writing the same id twice overwrites.

List Saves returns player slots only. Autosaves live in a reserved id namespace — @autosave.<n> — and are listed by List Auto Saves instead; the two sets never overlap. That is deliberate: a save/load grid built on List Saves never has to filter Studio's own bookkeeping rows out, and an autosave screen never has to hide the player's slots. An autosave id is still an ordinary save id everywhere else, so it feeds Load Save, Get Save Preview, Get Save Metadata and Delete Save unchanged.

Save fields

A save carries two kinds of data. The engine writes one of them on every save: the line the save resumes from, who spoke it, and the timestamps. The other is yours, and Save fields is where you declare it.

Open it from the button at the bottom of a Save Game or Get Save Metadata card. Each field has a name, a type and a default value.

Declared fields become named pins: an input on Save Game, an output on Get Save Metadata. The list belongs to the project rather than to the node it was opened from, so every save node in the project shows the same fields and a field is declared once for all of them.

Renaming a field relabels its pins and keeps every connection. Changing its type resets its default.

BehaviourResult
A field is read from a save written before it was declaredThe field's default value
A field is deletedValues already written under it stay in the save files that hold them
A field is declared and left empty on a Save Game that runsProject lint reports blueprint/save-field-empty as an error

The metadata pin stays on both nodes. On Save Game the declared fields are written over whatever it carries, so a key you declare wins over the same key inside it. On Get Save Metadata it still returns the whole stored object.

Save Game

blueprint.game.save.write · Latent

Serializes the live game into the project's local save store. With Capture set to true it also takes a PNG of the stage and stores it as that save's preview; a capture that fails is reported but does not lose the save.

PinDirectionTypeNotes
inin · exec
nextout · exec
idin · datastringAccepts an on-card literal.
metadatain · datajsonOptional. Anything JSON — object, array, string, number, boolean or null. Written as null when unwired.
screenshotin · databooleanOptional. Labelled Capture on the card. Accepts an on-card literal.
one per declared fieldin · datathe field's typeNamed after the field. Accepts an on-card literal for the types that take one.

Fails when no game session is active.

Load Save

blueprint.game.save.load · Latent

Reads a save and abandons the current progress for it: the router and its history are cleared, a fresh game instance is created and deserialized, and once the router has exited the Page stack is hidden beneath the stage again — so a Go Page after this opens an overlay above the game.

PinDirectionTypeNotes
inin · exec
idin · datastringAccepts an on-card literal.
failedout · execRuns when the save is missing or unreadable, or when no game runtime is active.

There is no next: a load that succeeds replaces the running game, so there is nothing left of this graph to carry on with. failed is the only way out, and it is the branch where a game says so.

Delete Save

blueprint.game.save.delete · Latent

Removes one save. Deleting an id that is not there still counts as success, so a delete button does not need to check first. Needs the project's save namespace only — no running game.

PinDirectionTypeNotes
inin · exec
nextout · exec
idin · datastringAccepts an on-card literal.

List Saves

blueprint.game.save.listIds · Latent

The ids of the project's player saves. Order is not guaranteed. Files that are corrupt, or whose metadata is not a player save, are skipped rather than reported.

PinDirectionTypeNotes
inin · exec
nextout · exec
idsout · dataarrayArray of string.

Get Save Metadata

blueprint.game.save.getMetadata · Latent

Reads a save's author data. Each declared field comes out on its own pin; the metadata pin returns the whole stored object, including any key no field declares. System fields are not part of either: the id, the record type, createdAt, updatedAt and the preview are read with Get Save Time and Get Save Preview.

PinDirectionTypeNotes
inin · exec
nextout · exec
idin · datastringAccepts an on-card literal.
metadataout · datajsonnull when the save is missing or carries no user metadata.
one per declared fieldout · datathe field's typeNamed after the field. The field's default value when the save does not carry it.

Get Save Time

blueprint.game.save.getTime · Latent

When a slot was written. The save store stamps every record it writes, and this node reads those stamps back. A save screen does not need to put a time into its own metadata and keep the two in step.

PinDirectionTypeNotes
inin · exec
nextout · exec
idin · datastringAccepts an on-card literal.
savedAtout · datafloatWhen the slot was last written. 0 when the save is missing.
createdAtout · datafloatWhen the slot was first written. 0 when the save is missing.
existsout · databoolean

Both times are milliseconds since 1 January 1970 UTC, the unit List Auto Saves reports and every Time node accepts.

Read exists to identify an empty slot. A missing save gives savedAt 0, and 0 is also a valid moment in 1970.

Get Save Line

blueprint.game.save.getLine · Latent

The line a save resumes from, and who spoke it. The engine records both every time it serializes, and this node reads them back. A save screen does not need to read the backlog at save time and write the last entry into its own fields.

PinDirectionTypeNotes
inin · exec
nextout · exec
idin · datastringAccepts an on-card literal.
lineout · datastringEmpty when the save is missing, or when it was taken before any line played.
speakerout · datastringEmpty for narration, and for a save with no line yet.
existsout · databoolean

This is not the newest backlog entry. The backlog holds the last line shown; these two fields hold the line the save resumes from. Saving from an overlay, or from a point where non-dialogue actions followed the last line, moves the two apart.

Get Save Playtime

blueprint.game.save.getPlaytime · Latent

How long the playthrough in a slot had been played when it was written — the "12h 34m" a save grid puts under the thumbnail.

PinDirectionTypeNotes
inin · exec
nextout · exec
idin · datastringAccepts an on-card literal.
playtimeSecondsout · datafloat
playtimeMillisecondsout · datafloat
recordedout · databooleanfalse for a save written before playtime was tracked — the slot exists, the number does not.
existsout · databoolean

Format it with Format Duration from Time.

Get Save Preview

blueprint.game.save.getPreview · Latent

Turns a save's stored screenshot into an ImageAsset for the current session. The image is not imported into the project's resources; wire it straight into Set Image Asset or an image Blueprint Value.

PinDirectionTypeNotes
inin · exec
nextout · exec
idin · datastringAccepts an on-card literal.
previewout · dataImageAsset|nullnull when the save is missing or has no screenshot.

Auto saves

Autosaving is configured per project, under Project → Game: on or off, the interval, and how many slots the ring keeps. It ships with the project. The graph does not schedule anything — the scheduler runs on its own and only writes when the story has advanced since the last one, so an idle game costs nothing however short the interval is. Writes rotate through the ring, oldest first, so autosaving forever costs a bounded amount of disk.

Auto Save

blueprint.game.autoSave.write · Latent

Writes one autosave right now, into the next slot of the same ring the scheduler uses, screenshot included. It ignores both the on/off setting and the "story advanced" gate — the author asked for this one explicitly — and the result is indistinguishable from a scheduled autosave afterwards. Execution continues: an autosave does not disturb the playthrough.

PinDirectionTypeNotes
inin · exec
nextout · exec

Fails when no game is running, like every other save write.

List Auto Saves

blueprint.game.autoSave.list · Latent

Every autosave in the reserved namespace, newest first. Slots left behind after lowering the ring size are still listed — a configuration change must not make the player's saves vanish — they simply stop being rotated into.

PinDirectionTypeNotes
inin · exec
nextout · exec
entriesout · dataarrayArray of objects; fields below.
countout · datainteger

Entry fields

FieldWhat
idThe save id. Feeds Load Save, Get Save Preview, Get Save Metadata and Delete Save directly.
slotIndex of the slot within the ring.
timestampLast written, epoch milliseconds.
createdAtFirst written, epoch milliseconds.
metadataWhatever the writer attached, null when none.

An entry carries the id, not the serialized game: a SavedGameData blob is inert inside a graph, whereas an id feeds straight into the save nodes that already exist.

Get Latest Auto Save

blueprint.game.autoSave.latest · Latent

The newest autosave. This is the Continue button's node — the same thing as the first entry of List Auto Saves, minus the index-and-field nodes it would take to get there.

PinDirectionTypeNotes
inin · exec
nextout · exec
idout · datastringEmpty string when there is no autosave.
hasAutoSaveout · databooleanWire it to disable Continue.
timestampout · datafloatLast written, epoch milliseconds. 0 when there is no autosave.

History

The dialogue history — the backlog — is the engine's own record of the lines and menus that have already gone by, and it can be replayed into.

It is a timeline with a play head on it, and these seven nodes are its two sides. Get History is everything up to the head: the lines already read, in order. Stepping back moves the head, and the lines it moved past become the future, which Get Future History returns and Redo Next History Entry steps back into. Can Undo History and Can Redo History are what a pair of backlog buttons disable themselves on.

Get History

blueprint.game.history.get · Latent

The backlog as a flat array, oldest first, ready to bind to a list widget.

PinDirectionTypeNotes
inin · exec
nextout · exec
entriesout · dataarrayArray of objects; fields below.
countout · datainteger

Entry fields

FieldWhat
idHistory token. Feed it to Restore From History.
type"say" for a spoken line, "menu" for a resolved choice.
textThe sentence, or the menu's prompt. Empty string when the source had none.
characterSpeaker nametag for a say entry; null for menus and narration.
voiceVoice clip id for a say entry; null when absent.
selectedThe chosen option's text for a menu entry; null for say entries and unresolved menus.
isPendingTrue for the line currently on screen, which has not been committed yet.

Empty array when no game is running.

Restore From History

blueprint.game.history.restore · Latent

Jumps the game back to one backlog entry, discarding everything after it. It restores from the entry's snapshot where the engine can, and falls back to an undo otherwise — which is why it still works on a game that was just loaded from a save, where the undo stack is empty.

PinDirectionTypeNotes
inin · exec
nextout · exec
idin · datastringLabelled Entry Id on the card. Required; a blank id fails the node. Accepts an on-card literal.

Fails when no game runtime is active.

Undo Last History Entry

blueprint.game.history.undoLast · Latent

Goes back one entry — Restore From History with no target. This is the "back" button on a backlog screen.

PinDirectionTypeNotes
inin · exec
nextout · exec

Fails when no game runtime is active.

Redo Next History Entry

blueprint.game.history.redoNext · Latent

Steps forward into the future the undos created — the "forward" button beside the back one. Advancing the story any other way discards that future, which is what makes this a redo rather than a second Next.

PinDirectionTypeNotes
inin · exec
nextout · exec

Fails when no game runtime is active.

Get Future History

blueprint.game.history.getFuture · Latent

The entries ahead of the play head, in the same shape Get History publishes. A backlog screen that lets the player see where they were before they stepped back binds this to a second list.

PinDirectionTypeNotes
inin · exec
nextout · exec
entriesout · dataarraySame entry fields as Get History.
countout · datainteger

Empty array when no game is running, and when nothing has been stepped back over.

Can Undo History

blueprint.game.history.canUndo · Pure

PinDirectionTypeNotes
canUndoout · databooleanfalse when no game is running.

Pure, so it backs a Blueprint Value directly: bind a back button's enabled to it and the button greys itself out at the start of the log without a graph running per frame.

Can Redo History

blueprint.game.history.canRedo · Pure

PinDirectionTypeNotes
canRedoout · databooleanfalse when no game is running.

Text read

A line is marked read the moment its text finishes displaying — typing done in ADV, awaiting advance in NVL. The record is keyed by the message's stable text id, so it survives edits to the story and spans every story in the project, and it is persisted at project level, independent of any save file. This is what a "skip read text only" option is built on.

Is Text Read

blueprint.game.isTextRead · Pure

True while a dialog line is on screen and its message is marked read — either seen in an earlier playthrough, or finished displaying just now. False when no line is showing.

PinDirectionTypeNotes
isReadout · databoolean

Clear Text Read

blueprint.game.clearTextRead · Latent

Wipes the read record, in memory and on disk, for every story in the project. A line still on screen that already finished displaying immediately marks itself read again — the player is looking at it.

PinDirectionTypeNotes
inin · exec
nextout · exec

Has Read Text

blueprint.game.isTextReadById · Pure

Whether one named line has ever been read, asked by its text id rather than about whatever is on screen. Is Text Read above answers for the current line; this one answers for a line the player is not looking at, which is what an extras screen or a voice gallery needs.

PinDirectionTypeNotes
textIdin · datastringAccepts an on-card literal.
isReadout · databooleanfalse for an empty id, so a half-wired gallery row stays locked instead of taking the page down.

Playtime

Get Playtime

blueprint.game.getPlaytime · Pure

How long the running playthrough has been played. Both pins carry the same number in different units, so a screen that formats hours and one that does arithmetic in milliseconds each get what they want.

PinDirectionTypeNotes
playtimeSecondsout · datafloat
playtimeMillisecondsout · datafloat

0 when nothing is counting — a title screen asking how long this run has gone before any run exists is a fair question with a real answer, and the story preview has no stopwatch at all.

Get Total Playtime

blueprint.game.getTotalPlaytime · Pure

Seconds ever spent in this project, across every playthrough. This is the number a completion screen shows; Get Playtime is the one a pause menu shows.

PinDirectionTypeNotes
totalPlaytimeSecondsout · datafloat
totalPlaytimeMillisecondsout · datafloat

Route progress

Is Scene Visited and Is Option Picked read the record the story compiler writes as the player goes. It lives in the save, so it rewinds with a load — it answers "have I been down this route in this playthrough", which is what a one-shot choice and a mid-story unlock want. The endings record below is the opposite and lives in project persistence.

Both readers are pure, so a gallery row can bind a locked look straight to the pin instead of running a graph per row, and an empty id answers "no" rather than throwing.

This is not Has Read Text. The read record is written when a line is displayed, so every option of a menu the player merely opened counts as read. Is Option Picked is written on the pick.

Is Scene Visited

blueprint.game.isSceneVisited · Pure

PinDirectionTypeNotes
storyIdin · datastringOptional. Wired wins over the card.
sceneIdin · datastringOptional. Wired wins over the card.
isVisitedout · databoolean

On-card fields

FieldWhat
StoryThe story to ask about.
SceneThe scene, filtered to that story.

The picker covers nine cases in ten. The pins are for the tenth: one gallery card placed once per scene, reading which scene it is from its own params, instead of one card copied per scene.

Is Option Picked

blueprint.game.isOptionPicked · Pure

PinDirectionTypeNotes
storyIdin · datastringOptional. Wired wins over the card.
optionIdin · datastringOptional. Wired wins over the card.
isPickedout · databoolean

On-card fields

FieldWhat
StoryThe story to ask about.
OptionA choice option, filtered to that story.

Clear Visited

blueprint.game.clearVisited

Empties both records. Effectful but not latent — it clears two keys in the live Storable within the tick, unlike Clear Text Read, which writes host persistence and has to be awaited.

PinDirectionTypeNotes
inin · exec
nextout · exec

Endings

An /ending row in a story is the whole declaration, and its block id is the identity everything here keys on. These four are what an endings screen is built out of: which of them the player has found, and what the full set is to lay them out against.

The endings record sits in project persistence rather than in a save, and nothing rewinds it. An endings screen asks what this player has ever seen, so a gallery built on the saved record would re-lock entries in front of somebody who loaded an older save, and a "5 of 8" count would go down. That also means none of the four needs a running story — a title screen is exactly where an endings gallery is opened from.

Is Ending Reached

blueprint.game.isEndingReached · Pure

PinDirectionTypeNotes
isReachedout · databooleanfalse for an unpicked ending, so a half-wired row stays locked.

On-card fields

FieldWhat
StoryThe story to ask about.
EndingAn ending declared in that story.

Get Endings

blueprint.game.getEndings · Pure

Every ending the story declares, whether reached or not — the set a gallery lays out and counts against.

PinDirectionTypeNotes
endingsout · dataarrayEmpty when nothing is picked.

On-card fields

FieldWhat
StoryThe story whose endings to list.

Clear Ending State

blueprint.game.clearEndingState · Latent

Re-locks one ending.

PinDirectionTypeNotes
inin · exec
nextout · exec

On-card fields

FieldWhat
StoryThe story to ask about.
EndingThe ending to forget.

Clear Endings

blueprint.game.clearEndings · Latent

Re-locks all of them. Both wipes write host persistence, so both are latent.

PinDirectionTypeNotes
inin · exec
nextout · exec

Editions and extra content

Get Build Variant

blueprint.game.getAppTag · Pure

Which variant of the project this package is.

It is the one node in the catalogue whose value is decided before the game exists. A build produces one variant, its name is substituted here, whatever comparison consumes it is folded, and the branch this edition does not take is deleted — so the content behind a variant check is absent from the package rather than merely unreachable in it. A graph whose Get Build Variant does not end up deciding a branch is refused at the build gate, in every build including the release one: there is no play-time value to fall back on, so such a graph cannot be compiled at all.

That is also why it takes nothing and has no card field. Anything it could be given would be a second input to a question that already has one answer.

PinDirectionTypeNotes
appTagout · datastringThe variant's name. The full release is main.

Is DLC Installed

blueprint.game.isDlcInstalled · Pure

Whether a piece of extra content is sitting beside the running game.

The question is deliberately about presence, not ownership. A DLC arrives as a file next to the game, put there by whatever the player bought it from, and whether it is here is a fact this build can see. Whether the player owns it is a storefront's fact and a storefront plugin's node to answer — and gating content on that would take an offline player's bought chapter away from them, which presence never does.

PinDirectionTypeNotes
isInstalledout · databooleanfalse when nothing is picked, so a half-wired menu row stays hidden.

On-card fields

FieldWhat
DLCOne of the project's declared DLCs.

Carrying progress between editions

A demo and the full game are separate packages with separate app ids, so they keep separate user-data directories and their asset protection keys differ on purpose: the release build cannot read the demo's save files and must not try. These two nodes are the channel that does cross, and it is deliberately not a save file — it is one plain JSON document per title holding the project-level variables, where the player had got to, and which scenes they had seen.

Where that document lives is decided by the shell, never by the graph: the desktop shells hand it to their main process, and the web export refuses because a page has no shared file to write. So both nodes carry a failure branch and a reason, and a graph has to be able to hear "no".

Export Progress

blueprint.game.progress.export · Latent

Writes everything this playthrough holds into the title's progress document. It takes nothing: what travels is the project's declared set, not a subset one graph picked for a document the other edition has to read.

PinDirectionTypeNotes
inin · exec
nextout · exec
failedout · execA shell that cannot write, a build with no progress key, or a disk that refused.
errorout · datastringWhich of those it was.

Import Progress

blueprint.game.progress.import · Latent

Reads the document and applies what it holds to the running game.

It does not jump. Scene comes out as data and the node stops there. Start Game is what starts a story, and a title screen usually has something to do first — a fade, a confirmation, a chapter select. A node that jumped by itself would be a second way to start a story that skipped all of that.

PinDirectionTypeNotes
inin · exec
foundout · exec
missingout · execNobody exported.
failedout · execA document that would not read.
sceneIdout · datastringWhere the player had got to. Empty when the document anchors nowhere. Wire it into Start Game.
errorout · datastring

Three ways out, because an author answers each differently. Missing is the ordinary state of everybody who never exported — a fresh install, a player who went straight to the full game — and it leads to "start a new game", not to an apology; folding it into Failed would put an error in front of every first-time player. Failed is a document that would not read: written by a newer build, belonging to another title, or corrupt.

Storage

Check Storage Durability

blueprint.game.storageDurability · Latent

Whether what this build writes stays written — the one thing about a player's saves that the shell knows and the game cannot work out for itself.

A packaged desktop game keeps files in a user-data directory nothing reclaims. A web export is a guest of the browser, where a site that has not been granted persistent storage may be evicted whole: saves, persistent variables and read text together. The page asks for that grant as it loads, and this is the answer it was given.

PinDirectionTypeNotes
inin · exec
durableout · exec
evictableout · exec
unknownout · exec

Three branches, because the three lead to different words. Evictable is "this browser may remove saved games"; Unknown is a browser that will not say, and telling a player the first when the truth is the second is a promise nobody made. Nothing is decided for you — a page whose storage may be reclaimed is still a page a game can be finished on, and whether the player hears anything about it belongs to the title.

On this page

ConventionsThe playthroughStart GameQuit GameIs In GameIs Game OverlayAdvancing the storyNextSkipSelect ChoiceGet Choice CountDialogGet NametagGet Speaker AvatarGet Dialog TextGet Speaker ColorIs NarratorIs Dialog WaitingGet CharacterIs NVL ModeGet NotificationsShow DialogHide DialogToggle Dialog DisplayIs Dialog ShownPreferencesGet Sentence SpeedSet Sentence SpeedGet Auto ForwardSet Auto ForwardGet Auto Forward DelaySet Auto Forward DelayGet SkipSet SkipGet SkippingSet SkippingGet Skip Read TextSet Skip Read TextGet Skip DelaySet Skip DelayGet Skip IntervalSet Skip IntervalGet Game SpeedSet Game SpeedGet Global VolumeSet Global VolumeGet BGM VolumeSet BGM VolumeGet SFX VolumeSet SFX VolumeGet Voice VolumeSet Voice VolumeGet Voice Fade DurationSet Voice Fade DurationGet Voice End ModeSet Voice End ModeGet Track VolumeSet Track VolumeSavesSave fieldsSave GameLoad SaveDelete SaveList SavesGet Save MetadataGet Save TimeGet Save LineGet Save PlaytimeGet Save PreviewAuto savesAuto SaveList Auto SavesGet Latest Auto SaveHistoryGet HistoryRestore From HistoryUndo Last History EntryRedo Next History EntryGet Future HistoryCan Undo HistoryCan Redo HistoryText readIs Text ReadClear Text ReadHas Read TextPlaytimeGet PlaytimeGet Total PlaytimeRoute progressIs Scene VisitedIs Option PickedClear VisitedEndingsIs Ending ReachedGet EndingsClear Ending StateClear EndingsEditions and extra contentGet Build VariantIs DLC InstalledCarrying progress between editionsExport ProgressImport ProgressStorageCheck Storage Durability