Appearance
Plugins overview
Plugins are the support half of the extension ecosystem: opt-in engine policies that make a game practical to ship — saving, offline catch-up — without touching its rules. Like mechanics, each one is a factory returning an Extension<T> behind its own public subpath.
Browser-specific bridges (page lifecycle, rAF frames, screen info) are not plugins — they live in @idlekitjs/browser.
The catalog
| Plugin | Solves |
|---|---|
| Autosave | Progress lost when the tab dies without a recent save |
| Offline progress | "I was away 3 hours, where's my production?" |
The standard shipping stack
Most browser games install both, plus the page lifecycle bridge; they were designed to compose:
ts
import { autosave } from "@idlekitjs/plugins/autosave";
import { offlineProgress } from "@idlekitjs/plugins/offline-progress";
import { pageLifecycle } from "@idlekitjs/browser/page-lifecycle";
engine.use(pageLifecycle());
engine.use(offlineProgress({ maxMs: 8 * 60 * 60 * 1000 }));
engine.use(autosave({ manager: save, getState: () => engine.state, intervalMs: 15_000 }));How they interlock:
- The player hides the tab → page-lifecycle pauses the loop (no battery burn) and autosave writes a save (the tab may never come back).
- The player returns → page-lifecycle resumes and emits
resumewith the elapsed milliseconds. - offline-progress hears
resume(andloaded, afterengine.load) and callsengine.advancewith the elapsed time, capped by your policy.
Each is independently optional — a headless simulation uses none of them.
Why these are not in core
Nothing pauses or saves behind your back unless you installed the thing that does it: these behaviors are policy, and @idlekitjs/core ships no policy. offlineProgress listens to engine events. autosave drives a SaveManager and includes browser lifecycle triggers (setInterval, visibilitychange, pagehide) in its current implementation; use it for browser games.