Skip to content

Custom game recipe

This page is a source-backed pattern, not a promise of a generated game API. Start from the actual TypeScript Engine, Chronicle, Stack, Space, and ActionRegistry modules, and keep all persistent writes on the dispatch path.

Minimal state and dispatch

import { Engine } from "../engine/Engine.js";
import { ActionRegistry } from "../engine/actions.js";

ActionRegistry["game:advance"] = (engine, { playerId }, context) => {
  const game = engine.session.state.myGame;
  if (!game || game.phase !== "play") throw new Error("game is not active");
  if (game.currentPlayer !== playerId) throw new Error("not your turn");

  return context.mutate("game:setState", {
    key: "myGame",
    patches: [
      { path: ["turn"], value: game.turn + 1 },
      { path: ["currentPlayer"], value: (game.currentPlayer + 1) % game.players.length },
    ],
  });
};

const engine = new Engine();
await engine.dispatch("game:setState", {
  key: "myGame",
  value: { phase: "play", turn: 0, currentPlayer: 0, players: ["a", "b"] },
});
await engine.dispatch("game:advance", { playerId: 0 });

game:setState accepts either a whole-key value or nested patches; values must be JSON-serializable. The registered handler receives an execution context: use context.mutate() for internal registry mutations so the outer dispatch owns one history/policy/rule lifecycle. Validate before writing. Dispatch is not transactional if code mutates and then throws.

For cards, use Stack/Source and Space for canonical containers. For turns, use the real game-loop actions (game:loopStart, game:setActiveAgent, game:nextTurn, game:loopStop) rather than inventing action names. For rules, use RuleEngine; for persistence, use engine.useStorage(adapter), persist(), and resume().

Design checklist

Write down entities, invariants, visibility, conflict policy, authority, replay needs, document-growth limits, and failure behavior. Add fixed seeds to tests. Read engine/ACTIONS.md and docs/TESTING.md; do not call session.change() from ordinary game code.