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).
The adapter (recommended)
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
localStoragesave 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
getCoinswhen 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