Appearance
Autosave
Drives saving for the lifetime of the game: on a periodic interval, when the tab goes to the background, and on page close. Install it once and stop thinking about save calls.
ts
import { autosave } from "@idlekitjs/plugins/autosave";Browser lifecycle triggers
autosave drives a generic SaveManager, and its default triggers are browser lifecycle APIs (setInterval, visibilitychange, pagehide). Use it for browser games. Generic page lifecycle bridging lives in @idlekitjs/browser.
Usage
ts
import { SaveManager } from "@idlekitjs/core";
import { LocalStorageAdapter } from "@idlekitjs/storage/local-storage";
import { autosave } from "@idlekitjs/plugins/autosave";
const save = new SaveManager<State>({
key: "my-game",
version: 1,
adapter: new LocalStorageAdapter(),
});
engine.use(
autosave({
manager: save,
getState: () => engine.state,
intervalMs: 15_000, // periodic safety net; 0 or omitted disables it
}),
);When it saves
| Trigger | Why it matters |
|---|---|
Every intervalMs (if > 0) | Safety net against crashes |
Tab hidden (visibilitychange) | On mobile, a backgrounded tab may be killed without any further event |
Page close (pagehide) | More reliable than beforeunload, notably on mobile Safari |
With the synchronous LocalStorageAdapter, the close-time write completes before the page actually unloads.
Missing manager or getState throws at wiring time — a clear startup failure instead of silently losing saves later.
Options
| Option | Required | Role |
|---|---|---|
manager | ✓ | The SaveManager to drive |
getState | ✓ | Returns the live state (() => engine.state) |
intervalMs | Periodic autosave interval; 0/omitted disables |
SaveScheduler
The scheduling core behind the plugin is public from the same subpath — use it when you need an imperative save outside the automatic triggers (a "Save now" button, saving after a milestone):
ts
import { SaveScheduler } from "@idlekitjs/plugins/autosave";
const scheduler = new SaveScheduler<State>({
manager: save,
getState: () => engine.state,
intervalMs: 15_000,
});
scheduler.start(); // attach interval + lifecycle listeners
await scheduler.save(); // immediate save
scheduler.stop(); // detach everythingThe autosave plugin is exactly this object tied to the extension lifecycle (setup → start, teardown → stop).
Event-driven saves
For "save on meaningful progress", prefer the mechanics' callbacks — onComplete, onPurchase, onChange — calling save.save(state). Autosave is the safety net, not the only writer.
Common pitfalls
getState: () => snapshot— captures one stale object forever. Always return the liveengine.state.- Relying on
beforeunload— that's why the plugin usespagehideandvisibilitychange; don't add your ownbeforeunloadwriter on top.
Related
- Saving your game — the full persistence stack.
- Save & load recipe.