Skip to main content

Progress & saves

The SDK gives you account-bound cloud save with an automatic offline fallback. Use the built-in gamma.storage adapter — it handles the boilerplate (ready-waiting, fallback, and one-shot migration of an old localStorage save into the account).

await gamma.storage.init(); // resolve host once
const state = (await gamma.storage.load()) // account-bound in-app, localStorage outside
?? {schemaVersion: 1};

// ... play ...

await gamma.storage.save(state); // returns true on success
  • In-app: reads/writes the player's account, synced across devices.
  • Outside the app: transparently uses localStorage, so offline play works.
  • First in-app launch: if there's a legacy localStorage save and no account save yet, it migrates the local save into the account once, then clears it.

Set the localStorage key (and other options) before the first call:

gamma.configure({storageKey: 'mygame_save'});

Always include a schemaVersion

Every persisted payload should carry an integer schemaVersion so future game versions can migrate old saves forward without corrupting them.

const CURRENT_SCHEMA = 3;

function migrate(state) {
if (state.schemaVersion < 2) {
state.coinsEarned = 0; // field added in v2
state.schemaVersion = 2;
}
if (state.schemaVersion < 3) {
state.levels = state.stages ?? {}; // renamed in v3
delete state.stages;
state.schemaVersion = 3;
}
return state;
}

const raw = await gamma.storage.load();
const state = migrate(raw ?? {schemaVersion: CURRENT_SCHEMA});

What to save (and what not to)

Save derived, durable state:

  • ✅ Level number, per-level stars, unlock flags, cosmetic choices, counters
  • ✅ Quest/mission progress, tutorial completion
  • ✅ Settings the player explicitly changes (music on/off, control scheme)

Do not save reconstructible, transient state:

  • ❌ Sprite positions, velocities, particle buffers, audio cursors
  • ❌ Camera offsets, UI animation state
  • ❌ Any cached coin balance — call getCoins when you need it

Save cadence & limits

  • Debounce routine saves (≈1000 ms trailing); save at meaningful milestones.
  • Force-save on visibilitychange → hidden / pagehide — mobile can kill the page at any time.
document.addEventListener('visibilitychange', () => {
if (document.visibilityState === 'hidden') gamma.storage.save(state);
});
  • Max encoded save size: 100 KB. If you're close, you're probably persisting reconstructible state (see above) — compact into ids/bitfields.

Low-level API

gamma.storage is built on gamma.loadProgress() / gamma.saveProgress(data), which talk to the account directly (no localStorage fallback). Prefer the adapter unless you need full control. See the API reference.

Ask:View .md