Phaser AE

Saved data

Free packv3.0.0-3Logic

A small key-value store on `game.save` for what a game must remember between sessions: a high score, a settings screen, unlocked levels, a checkpoint. It writes to localStorage when it can and to memory when it cannot, and it never throws because the browser would not keep a score.

This is a Free pack. Every phaser.io account can use it in their games.

Released October 14, 2026 · updated October 20, 2026

Saved data: a screenshot of its demo
A note about these graphics

Expansion packs don't come with graphics. This screenshot is one way of drawing what the pack does, made for its demo: none of the sprites, tiles or backgrounds in it are in the pack.

That's by design. A pack is a game's logic, mechanics and effects, and it works with whatever art you give it. Some packs draw effects, backdrops or 3D scenes of their own, but none carries a game's sprites.

So the look is yours. Make the art on phaser.io, bring your own, or let your agent draw it in code: the same pack can look like anything.

What it does

read(key, fallback) returns the stored value, or the fallback when the key is missing or its text is not valid JSON, typed as the fallback. write(key, value) stores the value as JSON. keys, remove and clear work within the game's namespace and leave other namespaces alone, so clear wipes one game's data and nothing else.

Browsers do not always keep data: a private window, a full quota or a headless test run can all refuse. When a storage operation fails, the session switches to an in-memory copy of everything it had, and reads, writes and deletions carry on against it. persistent turns false, so a game can show "scores not saved" rather than lose them without a word.

Features

  • JSON values — numbers, strings, arrays and objects under a key, typed by the fallback you read them with.
  • A namespace per game — namespace prefixes every key; the default is phaser-ae.
  • A graceful fallback — localStorage when it is there, memory when it is not, with existing data mirrored so nothing already stored goes missing for the session.
  • A persistence flag — persistent says whether this session's writes will survive a reload.
  • Loud on bad values — a cycle, a BigInt or a value with no JSON form throws a TypeError before anything changes.
  • Reachable from other packs — through the registry, so a pack can save a value without importing this one.

Good for

  • High-score tables in arcade games.
  • Options screens for music, sound and controls.
  • Unlocked levels and worlds in a level-based game.
  • Checkpoints and continue screens, with the kernel's scene flow.

Make it yours

There is one option, namespace: give each game its own, as { "id": "save", "options": { "namespace": "my-game" } }, or two games on the same site share a store. Two different uses: an arcade game that keeps a single best score and shows it on the title screen; and a puzzle game that saves a settings object and a list of finished levels, reading each with a default so a first run starts clean.

A quick look

A best score, a settings object and a warning when nothing will be kept:

const best = game.save.read('best', 0);
game.save.write('best', Math.max(best, score));
const settings = game.save.read('settings', { music: 0.5, sfx: 1 });
game.save.write('settings', { ...settings, music: 0 });
if (!game.save.persistent) game.typography.label({ x: 8, y: 8, text: 'SCORES NOT SAVED' });

Works with

Good to know

  • Values must survive JSON.stringify: no functions, Map, Set or cyclic objects.
  • Every write is a JSON string in a store browsers cap at a few megabytes, so it is not for per-frame state or large data, and not for replays: the kernel's own record is the replay.
  • Memory-only values vanish on reload, and two tabs on one site do not see each other's writes until they read again.
  • There is no encryption or signing: a player can edit their own scores.

More Logic packs

Show all →