SavedGame
This page is under construction.
Beta feature, subject to change.
interface SavedGame {
name: string;
meta: SavedGameMetaData;
game: {
store: { [key: string]: SerializedNamespaceData; };
elementStates: RawData<ElementStateRaw>[];
stage: PlayerStateData;
services: { [key: string]: unknown; };
stackModel: StackModelRawData;
asyncStackModels: StackModelRawData[];
history?: SerializedGameHistory[];
};
}Note: The save format is versioned through
meta.version(currently3). Saves written before the backlog was persisted omithistoryand load with an empty backlog.
Save format v3 (0.26.0): an older engine cannot read a v3 save correctly. It applies the
elementStates entries and skips the reset the format now relies on, so elements the save
leaves out keep whatever the running session put in them. The other direction is fine — v1 and
v2 saves load unchanged in 0.26.0.
name
The name of the saved game
meta
The metadata of the saved game, see SavedGameMetaData
game
Game data of the saved game
store
Every namespace's contents, keyed by namespace name. Values are stored in their tagged form, see SerializedNamespaceData.
This covers both the namespaces registered with story.registerPersistent and the scene locals behind scene.local.
Read this through Storable / Namespace rather than by hand. A stored value is not the value itself but a {type, data} wrapper, which is what lets a Date survive JSON.
elementStates
The elements whose state differs from what the script wrote, each entry carrying the element's id alongside its data.
Leaving an element out is not a loss of information: loading resets every element before applying the save, so an element the save does not name is restored by being reset rather than left holding whatever the running session put in it. What differs at any moment is small, because leaving a scene already returns everything that scene put on stage to its authored state — in practice this is the current scene's elements plus the few that outlive a scene by design, such as the story camera and sounds still playing.
Before 0.26.0 this listed every element of every scene the story can reach, so a project's whole cast was written into every save and into every per-line history snapshot besides, at a cost that grew with the size of the project rather than with what was on stage.
An element written from outside the engine's action dispatch is not seen. An element is
considered for the save when an action runs against it; a host that writes element state
directly — through DevTools, say —
should call element.markDirty(). With app.debug: true, the engine periodically walks every
element and warns, naming any whose state has drifted with nothing marking it, and marks them
so the next save carries them.
A generated element id describes a position in the action tree rather than an identity, so an
application that restores saves should name its cast through
DevTools.setElementStaticId.
This matters more since 0.26.0, because characters now occupy save entries too.
stage
The state of the player, including the scenes and displayable elements currently on stage.
services
The serialized state of every service registered with story.registerService.
stackModel
The main execution stack, which is where the game resumes from when the save is loaded.
asyncStackModels
The execution stacks running alongside the main one — the actions started by Control.doAsync and Control.allAsync.
history
The persisted backlog (save format v2+). Each entry pairs the rendered say/menu content with a stable action id and a self-contained snapshot of the game at that line, which is what lets liveGame.getHistory() return a full backlog after a load and liveGame.restoreToHistory(token) jump back to any of these lines. Optional: legacy saves have no history, and a save whose story has since changed drops entries whose action no longer exists.