Save, Back and story end
Lives in: game.json → session · save files next to the player · screen actions
A session is one playthrough from New Game / Continue / Load until you return to title (or quit). Progress lives next to the player as manual slots, one autosave, and a separate prefs file.
Early — not final UX. Multi-slot save/load grids and multi-story packs are shipped and usable, but menus, labels, hub screens, and overall player comfort are still a first cut. Prefer the simple one-slot
"save"/"load"wiring unless you need the grid or packs — In development.
Most stories
- Keep pause/title hooks as
"save"/"load"for a simple one-slot feel (always slot 1). - Or point menus at
screen:save/screen:loadfor a multi-slot picker — define your ownsave/loadscreens with thesave_slotsblock; none ship built-in. - Title Continue resumes the autosave.
- Set
session.allow_backif you want Back / rollback. - Set
session.post_story_screen(and usuallypost_story_return_to_title) for credits after the last line. - Changing node ids or restructuring the story can invalidate old saves — that is intentional.
Where this lives
| Idea | File / surface | Path |
|---|---|---|
| Back + story-end + slot count | game.json | session |
| Continue / Load visibility | screens.json | show_if: has_autosave / has_save |
| Slot picker UI | screens.json | your own save / load screens + save_slots block |
| Files on disk | Next to the player | see below |
{
"session": {
"allow_back": true,
"back_retype": false,
"back_limit": 0,
"save_slots": 9,
"boot": "title",
"hud_screen": "hud",
"post_story_screen": "credits",
"post_story_return_to_title": true
}
}
"hud_screen": "hud" (default) auto-shows that screens.json entry with role: "hud" when a session starts. Set "hud_screen": "" to disable. Extra HUD mid-story: screen command.
{ "label": "Save", "interaction": { "hooks": { "on_click": "save" } } }
{ "label": "Save game", "interaction": { "hooks": { "on_click": "screen:save" } } }
Players never write save files by hand. Authors configure session and the screen actions that read those files.
session keys
| Key | Type | Default | Effect |
|---|---|---|---|
allow_back | bool | false | Enable Back / history. History is only stored in saves when this is true |
back_retype | bool | false | After Back: false finishes typing instantly; true retypes the line |
back_limit | int | 0 | Max Back steps per forward stretch; 0 = unlimited |
save_slots | int | 9 | Manual slot count (clamped 1–99) |
default_story | string | first pack / main | Pack id for bare new_game — Several stories |
boot | string | "title" | Cold start: "title" or "new_game" (skip title) |
post_story_screen | string | "" | Screen id after the story ends (e.g. "credits") |
post_story_return_to_title | bool | true | End session and show title (then optionally the post-story screen) |
hud_screen | string | "hud" | HUD id at session start; "" disables |
If post_story_screen is empty and post_story_return_to_title is false, the runtime still returns to title.
Map: game.json → session.
Files on disk
| File | Role |
|---|---|
save-1.json … save-N.json (author) or save-N.sav (player build) | Manual slots |
autosave.json / autosave.sav | Continue only |
prefs.json | Volumes, display, UI prefs, last_used_slot, and (when using multi-story) last_story_id / campaign (always plain JSON) |
| Manual slot | Autosave | |
|---|---|---|
| Written by | Player Save / save_slot:N / key S | Runtime after progress; also after successful Back, Title/Quit flush, window close |
| Read by | Load / load_slot:N / key L (in play) | Continue only |
| Preferences | No — see prefs.json | No |
Immediate actions: "save" / "load" always use slot 1.
Keyboard: S quick-saves the last-used slot (fallback 1); L in play loads that slot. Title L still prefers Continue when an autosave exists.
New Game starts a fresh session; it does not delete these files.
Title buttons typically use show_if: "has_save" / "has_autosave". Those checks also require a compatible file, so broken or outdated saves hide Continue/Load. has_save is true if any slot is occupied and compatible.
Author vs player encode
| Mode | When | Slot / autosave format |
|---|---|---|
| Plain JSON | Editor and author-mode player | .json — readable for debugging |
| Obfuscated | Production game build | .sav — not casually readable in a text editor |
Obfuscation is comfort (raise the bar vs peeking), not DRM. Prefs stay plain so volumes/locale remain easy to inspect.
Where files live
| Context | Location |
|---|---|
| Player build (one shipped game) | saves/ next to the executable |
| Author player (many projects) | saves/<project-id>/ — id is a slug from game.json title |
| Web build | Browser storage — survives reload when storage is allowed; private mode and some iframe blocks do not |
Saves are player progress, not part of your project folder.
What a save holds
Story cursor: current node id, flags, shuffle seed, plus save_version, story_id (pack), and story_hash for compatibility.
Stage and chrome (restored in a fixed order): background, character layout profile, on-stage characters, BGM, sprites, objects, screen shader, running animations, panels, theme_style / choice_style overrides, cursor profile.
Also: rollback history (only if allow_back), dialogue backlog. Preferences live only in prefs.json (volumes, display, UI, last_used_slot, last_story_id, campaign unlock flags).
Node-local overrides are not kept; drivers re-sync after load or Back.
Multiple stories (early)
One shared slot list + one autosave for the whole game. Each save stamps story_id. Hub screen: new_game:<id> and optional show_if: story_unlocked:<id>. Slot labels can use {story} / {story_title}. Full contract: Several stories in one project.
Back / rollback
Requires allow_back, enough history, and room under back_limit.
- History snapshots are taken after a node’s command batch finishes.
- Back restores the previous snapshot and skips “transit” nodes (no text and no choices) so the player lands on something interactive.
- Successful Back also writes a live autosave.
- Backlog trims to the restored node.
Default Back key is remappable (dialogue_back in keybindings.json) — Keys.
Story end
When there is no valid next (or a choice targets null):
- Fade out.
- Clear autosave — Continue is gone for that finished run.
- End session (reset stage/flags; title if configured).
- Fade in.
- Optionally push
post_story_screen.
Manual slots and prefs are not cleared on story end.
Usually you need
| Want | Write |
|---|---|
| Allow Back | "allow_back": true |
| Skip title (test) | "boot": "new_game" |
| Credits after ending | "post_story_screen": "credits" |
| More save slots | "save_slots": 12 |
Related
Title, pause and settings screens · Gameplay HUD · save_slots content block · Sticky state and clear · Several stories