DocsGame integration

Players and saves

Keep player progress across sessions, handle conflicts and submit scores.

Player identity

looping.player() returns a display name and sign-in status. Games receive pseudonymous identities; they do not receive an account email, wallet or key.

A signed-in save follows its player across devices. A guest save belongs to that browser. Saves work in single-player games even when multiplayer rooms are disabled.

Save at checkpoints

Each player has one JSON save per game and environment, up to 32 KiB. Save after a level, unlock or settings change. Pass the value itself, without JSON-stringifying it.

JavaScript
const { data: progress, readOnly } = await looping.saves.load();

// At a checkpoint, after updating your game state:
if (!readOnly) {
  await looping.saves.save({ ...progress, level: 2 });
}

// showSaveStatus is your game's status UI.
looping.saves.on("error", (error) => showSaveStatus(error.code));
window.addEventListener("pagehide", () => looping.saves.flush());

The SDK merges writes inside a five-second window. When offline, it keeps a pending save for the same game, environment and player, then retries when it can. Display save errors instead of reporting success before a write completes.

Formats and conflicts

Use load({ format, migrate }) to upgrade an older save. A build that encounters a newer format opens it read-only.

If another device saves first, the conflict event lets the game choose how to merge the two values. Without a merge handler, the platform copy wins and the SDK rejects with stale. Earlier versions are available through saves.history() and saves.restore(id).

When a guest signs in, the project page offers to keep their progress. Listen for claimed and reload the save. Read the full SAVES.md guide with engine_docs.

A save is progress, not proof

Players can edit their own saves. Restore purchases from store.owned(); use verified rounds or authoritative room results for competitive scores.

Rounds and scores

startRound() mints a round and seed on the platform. Use that seed in the game, then submit a score with finishRound(score, { tape }).

Authoritative room results are verified. Single-player replay verification requires a deterministic sim.js, a platform-minted round, a recorded input tape and fully pinned engine versions. Other scores remain player-reported.

leaderboard_read reads the board. Creators can remove a score with score_remove. saves_stats reports save budgets and counts without exposing players' save contents.