Save System
A save in StoryFlow captures the exact moment the player is in: the line they are reading, every variable, your characters and the state of your interface. Loading puts all of it back and carries on from that same line, mid-conversation included.
Overview
Saving is built from nodes on the script canvas of a User Interface file. There is no save system to switch on and no fixed save menu to work around: you decide what a slot is called, when the game saves, what the player sees and what happens after a load. The create-node menu groups all of it under a Save System section.
These nodes belong to StoryFlow's own runtime, so they work in the HTML export, the Desktop App export and in Play in Editor. If you export to a game engine instead, that engine's plugin brings its own save and load API.
The Exact Moment, Not the Nearest Checkpoint
A save can be made at any point the player is able to act: partway through a conversation, inside a script another script called, with menus and spawned elements on screen. Loading restores that position rather than rewinding to the start of a scene, so a player who saves mid-dialogue comes back to the same line with the same choices in front of them.
What a Save Contains
Stored in every save:
- The line the player is on, plus the chain of scripts that led there, so a save made deep inside a called script still returns to its caller when that script ends
- Every variable, global and local, including arrays, maps and enums
- Your characters, with any per-character values your story has changed
- Which one-time options the player has already used up
- The background image and the audio that were playing
- Interface state: copies spawned at runtime, properties your script nodes changed and each interface's own local variables. Looping animations come back too, starting again from the beginning
- The time it was made, an optional label and an optional screenshot
Deliberately not stored:
- Typewriter progress. Loading enters the saved line afresh, so a player who saved partway through a reveal watches it type out again from the start
- Delay nodes that were counting down. They are cleared and do not resume
- Elements the player had dragged somewhere
- Audio volume. It is a player setting, so it persists on its own and outlives any slot
The Save System Nodes
Right-click the script canvas and open the Save System section, or type "save" into the search box. Restart Game is the one exception: it sits in the System section beside Reset Game and Quit Game, since it is useful well beyond saving.
| Node | Kind | What it does |
|---|---|---|
| Save Game | Action | Saves into the named slot with an optional label |
| Capture Screenshot | Action | Takes the picture the next save will store |
| Load Game | Action | Loads the named slot, replacing the running game |
| Delete Save | Action | Deletes the named slot, doing nothing when it is empty |
| Restart Game | Action | Resets everything and returns to the script your project starts from, like a fresh launch |
| On Game Loaded | Event | Fires once a save has finished loading |
| Does Save Exist | Query | True when the named slot holds a save |
| Get Save Slots | Query | The slot names that currently hold a save, newest first |
| Get Save Label | Query | The label stored with a slot |
| Get Save Time | Query | When a slot was saved, ready to display |
| Get Save Screenshot | Query | The picture stored with a slot |
Every node that works on one slot has a Slot input. Type the name straight onto the node, or wire the pin when the name is only known while the game runs, which is how each row in a spawned list of saves knows the slot it belongs to. A wired pin wins over a typed name.
Saving
- Save Game takes the slot name, an optional Label and returns Success. Saving to a slot that already holds a save replaces it
- Capture Screenshot takes a picture of the screen and holds it for the next save. Execution continues once the picture has actually been taken, so the rest of the chain is free to open a menu without ending up in the shot
Success means the save was accepted, which is what you show a "Game saved" message on. It comes back false when the slot name is empty or the game has no content loaded yet. The write itself finishes a fraction later, so a Does Save Exist check further down the same chain still reports what was true before the save. Read it on a later click instead.
A save can be triggered from anywhere the graph runs: a button, a dialogue tag for an autosave at a chapter break, or On Value Changed on a variable. When the request arrives partway through a running chain, the capture waits for that chain to finish, so a slot always holds a moment the game can genuinely resume from.
Loading
- Load Game replaces everything currently running with the contents of the slot: variables, characters, the interface and the player's position
- On Game Loaded fires once the loaded game has drawn its first frame. It carries two booleans, Stale and Version Mismatch, both covered under When the Story Changes. Only one of these events can exist per graph
Nothing Runs After a Successful Load
Load Game has a single execution output, labeled Failed, and it runs only when nothing was loaded: an empty slot, an unreadable one or a save written in a newer format than this build understands. On success the world that chain was running in no longer exists, so the chain stops there. Put everything that should happen after a load, such as closing the menu or refreshing a HUD, on On Game Loaded.
Reading a Slot
These five have no execution pins. They read straight from storage whenever something asks them for a value, which makes them safe to wire into a Branch, into text or into an Image element.
- Does Save Exist returns a boolean. Use it to grey out a Continue or Load button when there is nothing to load
- Get Save Slots returns a string array, sorted newest first, so a list built straight from it is already in the order players expect
- Get Save Label returns the label stored with the slot, or empty text when the slot has none
- Get Save Time returns the moment the slot was written, formatted for the player's own language and region, for example "Aug 12, 2026, 4:30 PM". It reads correctly in the browser and in the Desktop App on Windows, macOS and Linux alike
- Get Save Screenshot returns an image you can wire straight into Set Image Source on an Image element
All five treat an empty or unreadable slot as absent, returning false or empty text rather than an error, so a menu that reads a slot the player just deleted keeps working.
Slots and Labels
A slot is a name you choose. There is no fixed number of them and no built-in numbering: 1, quicksave and chapter-2-autosave are all equally valid, and the set of slots is whichever ones currently hold a save.
That leaves the shape of your save screen entirely up to you. A fixed set of numbered slots is the familiar option: name them 1 to 4, check each with Does Save Exist and write into the first empty one. An open-ended list is just as easy, since Get Save Slots tells you what exists without you having to track it.
The Label is free text stored alongside the save. A chapter title, the current location, the name the player typed at the start: anything that helps them tell one slot from another later. It is optional, and Get Save Label reads it back.
Screenshots
A save can carry a picture of the screen as it was when the player saved. Fire Capture Screenshot first, then Save Game, and the picture is stored in the slot. Get Save Screenshot reads it back for display.
Only the most recent picture is held, and storing it in a slot does not use it up, so several saves made during one visit to the menu all share the same shot of the game behind it. If nothing has been captured, Save Game takes the picture itself at the moment of saving, which is the right behavior for an autosave that fires during play.
Capture Before You Dim
Put Capture Screenshot at the very start of the chain that opens your pause menu, before the chain shows the dimmer or the panel. That way the thumbnail shows the game the player was in rather than the menu they opened, and every save made from that menu reuses it.
Screenshots are stored around 640 pixels wide as JPEG, which keeps a slot small enough to sit comfortably in storage. Capturing is best effort: if it fails for any reason the save still succeeds, just without a picture, and Get Save Screenshot returns empty for that slot.
Building a Save Menu
The example project that ships with the editor has a working pause and save menu built from these pieces, in a User Interface file of its own, with the slot rows in a second one. Create a new project from the example and open them to see one way to wire it. The recipe below is that shape, step by step.
- Opening the menu: on the menu button's On Click, fire Capture Screenshot, then show your panel
- Saving: a Save button runs Save Game with your slot name and a label. Use Success to show a short confirmation
- Listing the saves: feed Get Save Slots into a For Each Loop, and inside the loop use Create Instance to spawn one row interface per save into a vertical box. Set a variable on each spawned row to its slot name
- Filling each row: inside the row interface, read its own slot name with Get Save Label, Get Save Time and Get Save Screenshot and push those into its text and image elements
- Loading: the row's Load button runs Load Game on its slot name. Remember that nothing after it runs when the load succeeds
- After the load: put an On Game Loaded event in the interface that owns the menu, and use it to close the panel and refresh anything the loaded world needs
- Deleting, if you want it: a Delete button runs Delete Save, then rebuilds the list with Clear Children and the same loop. The example project has no delete button, so this is the one step you will be adding yourself
One Row Interface, Any Number of Slots
Build the row once as its own User Interface file with a slot-name variable, and let the loop spawn as many as there are saves. The row fills itself in from that one variable, so adding a fifth slot is a matter of the player making a fifth save, not of you laying out another row.
Where Saves Live
Saves are written into the storage the player's own device gives your game, so there is no save file to choose a folder for. Nothing is ever uploaded: a save never leaves the machine it was made on.
| Where the game runs | Where its saves are kept |
|---|---|
| HTML export on the web, itch.io or a local file | The browser's storage for that address. Per browser and per address, so a player who switches browser or device starts fresh |
| Desktop App export | Inside the app's own data folder on the player's machine, isolated from their browser and from your other games. The same on Windows, macOS and Linux |
| Play in Editor | Kept by the editor, so you can test saving while you build. These stay in the editor and are never carried into an export |
Each project's saves are filed under a name derived from the project itself, so two of your games published to the same address never see each other's slots.
When the Story Changes
Players save, you release an update, and their old saves meet a story that has moved on. StoryFlow restores as much as it still can rather than refusing the save, and tells your graph what it had to compromise on.
- Variables are matched by identity, not by name, so renaming one keeps its saved value. A variable whose type you changed keeps its current default instead of a value that no longer fits it, and one you deleted is ignored. Variables added since the save start at their default
- Stale is true when the player's exact position could not be restored. That happens when the line the save was parked on no longer exists, when the script holding it has been deleted or when one of the scripts in the chain that led there has. Everything else, including variables, characters and the interface, is still restored. The story picks up from the start of that script, or from the script your project starts from when the whole script has vanished
- Version Mismatch is true when the save came from a different export of the game than the one now running
Version Mismatch Is a Hint, Not an Error
Any change to the story sets it, down to a fixed typo, so it is far too common to treat as a failure. It is there so you can warn a player that a save predates the update they just installed, which is worth doing before a long session. Stale is the stronger signal, since it means the player's exact position genuinely could not be found. In Play in Editor there is no export to compare against, so Version Mismatch never fires while you are testing.
Both flags arrive on On Game Loaded. One case is refused outright rather than flagged: a save written in a newer save format than the running build understands, which happens when a player's save came from a build made with a later version of StoryFlow. That one surfaces on Load Game's Failed output.
Limits and Good Practice
Saves Live in the Player's Browser Storage
In the HTML export, clearing site data or browsing history removes every save along with it, and browsers limit how much a single page may keep. This is normal for a browser game, but it is worth being modest with slot counts if your game keeps screenshots, and worth telling players in a web build that their saves are tied to that browser. The Desktop App export does not have this problem: its storage is the app's own.
- There is no save file to move between machines yet. Saves cannot currently be exported, imported or synced
- Success means accepted, not written. If storage is full or unavailable, the write fails a moment after Save Game already reported Success, and the reason is written to the browser console. Slot counts in the single digits keep you well clear of this
- Autosave with a fixed slot name. A dialogue tag on a chapter-opening line, wired to On Tag Reached and a Save Game with the slot
autosave, gives you an autosave without any extra bookkeeping - Do not save in the middle of a chain that has visible side effects. The save waits for the chain to finish, so a message or animation your chain starts may be captured mid-flight. One-shot animations are a safer way to confirm a save than changing an element's visibility, since visibility changes are part of the interface state a save records
- Test in a real export before release. Play in Editor is enough for wiring, but the screenshot is captured differently in the browser export, so give the exported build one save and load pass
Deleting an Interface a Save Refers To
A save records copies of interfaces that were spawned at runtime. If a later version of your game removes one of those files, older saves come back without those copies rather than failing to load. The same goes for an element the save had changed and you have since deleted.
Saving in Game Engines
The Save System nodes belong to StoryFlow's own runtime. When your story is driven by a game engine instead, that engine owns saving, and each plugin exposes its own API for capturing and restoring story state alongside the rest of your game's save data:
Next Steps
- UI Scripting - The canvas these nodes live on, and the loops and instances a save menu is built from
- HTML Export - Publishing the build your players will save in
- Desktop App Export - Saves kept in the app's own storage
- Variables - What a save restores, and how renaming one keeps its value