> ## Documentation Index
> Fetch the complete documentation index at: https://docs.tableverse.io/llms.txt
> Use this file to discover all available pages before exploring further.

# tabletop-engine

> The runtime for board game rules engines.

<div className="relative overflow-hidden">
  <div className="max-w-5xl mx-auto px-6 pt-10 pb-16 lg:pt-16 lg:pb-24 text-center">
    <img src="https://mintcdn.com/tableverse/VsZXio1smxeIgT8r/logo/icon-light.svg?fit=max&auto=format&n=VsZXio1smxeIgT8r&q=85&s=147e02e545f5ec29fd2f85de5d2bad5f" alt="tabletop-engine" className="block dark:hidden mx-auto h-32 lg:h-48 w-auto mb-10" width="34" height="34" data-path="logo/icon-light.svg" />

    <img src="https://mintcdn.com/tableverse/VsZXio1smxeIgT8r/logo/icon-dark.svg?fit=max&auto=format&n=VsZXio1smxeIgT8r&q=85&s=80e81b39f88a8e1894886ca6b6066416" alt="tabletop-engine" className="hidden dark:block mx-auto h-32 lg:h-48 w-auto mb-10" width="34" height="34" data-path="logo/icon-dark.svg" />

    <h1 className="text-5xl lg:text-7xl font-semibold tracking-tight text-[#111110] dark:text-[#f0f0ee]">
      The runtime for

      <br />

      <span className="text-[#d47c3a] dark:text-[#e8893f]">board game rules engines.</span>
    </h1>

    <p className="mt-8 text-lg lg:text-xl text-stone-600 dark:text-stone-400 max-w-2xl mx-auto leading-relaxed">
      Express your game's state, commands, and turn flow as plain TypeScript.
      tabletop-engine handles validation, execution, hidden information, and
      deterministic replay — so you can ship the rules with confidence.
    </p>

    <div className="mt-10 flex flex-wrap items-center justify-center gap-3">
      <a href="/quick-start/introduction" className="inline-flex items-center justify-center px-6 py-3 rounded-full text-base font-medium bg-[#d47c3a] text-white hover:bg-[#b86a30] transition-colors no-underline">
        Get started
      </a>

      <a href="/engine/overview" className="inline-flex items-center justify-center px-6 py-3 rounded-full text-base font-medium bg-stone-100 dark:bg-stone-800 text-[#111110] dark:text-[#f0f0ee] hover:bg-stone-200 dark:hover:bg-stone-700 transition-colors no-underline">
        API reference
      </a>

      <a href="https://github.com/VincentBai-dotcom/tabletop-engine" className="inline-flex items-center justify-center px-6 py-3 rounded-full text-base font-medium text-stone-700 dark:text-stone-300 hover:text-[#111110] dark:hover:text-[#f0f0ee] transition-colors no-underline">
        View on GitHub →
      </a>
    </div>
  </div>
</div>

<div className="border-t border-stone-200 dark:border-stone-800">
  <div className="max-w-6xl mx-auto px-6 py-20 lg:py-28">
    <div className="grid grid-cols-1 lg:grid-cols-2 gap-12 lg:gap-16 items-center">
      <div>
        <h2 className="text-3xl lg:text-4xl font-semibold tracking-tight text-[#111110] dark:text-[#f0f0ee]">
          Model state with decorators.
        </h2>

        <p className="mt-6 text-lg text-stone-600 dark:text-stone-400 leading-relaxed">
          Describe your game's data model with `@State()` and `@field()`. The
          engine compiles a type-safe canonical schema, hydrates a working
          facade for execution, and projects per-player views for hidden
          information — all from one declaration.
        </p>

        <a href="/engine/game-state" className="mt-6 inline-block text-[#d47c3a] dark:text-[#e8893f] font-medium hover:underline">
          Learn about state →
        </a>
      </div>

      <div>
        ```ts theme={null}
        @State()
        class GameState {
          @field(t.array(t.string()))
          playerOrder: string[] = [];

          @field(t.state(() => BoardState))
          board!: BoardState;

          getNextPlayer(playerId: string): string {
            const index = this.playerOrder.indexOf(playerId);
            if (index === -1) throw new Error(`unknown_player:${playerId}`);
            return this.playerOrder[(index + 1) % this.playerOrder.length]!;
          }
        }
        ```
      </div>
    </div>
  </div>
</div>

<div className="border-t border-stone-200 dark:border-stone-800 bg-[#f0f0ee]/40 dark:bg-stone-900/40">
  <div className="max-w-6xl mx-auto px-6 py-20 lg:py-28">
    <div className="grid grid-cols-1 lg:grid-cols-2 gap-12 lg:gap-16 items-center">
      <div className="lg:order-2">
        <h2 className="text-3xl lg:text-4xl font-semibold tracking-tight text-[#111110] dark:text-[#f0f0ee]">
          Author commands with validate and execute.
        </h2>

        <p className="mt-6 text-lg text-stone-600 dark:text-stone-400 leading-relaxed">
          Every player action is a command with a `validate` step and an
          `execute` step. The engine runs them transactionally, surfaces
          structured errors, and emits semantic events you can stream to
          clients.
        </p>

        <a href="/engine/commands" className="mt-6 inline-block text-[#d47c3a] dark:text-[#e8893f] font-medium hover:underline">
          Learn about commands →
        </a>
      </div>

      <div className="lg:order-1">
        ```ts theme={null}
        const defineGameCommand = createCommandFactory<GameState>();

        const buyCard = defineGameCommand({
          commandId: "buy_card",
          commandSchema: t.object({ cardId: t.number() }),
        })
          .validate(({ game, command }) => {
            const card = game.getCard(command.input.cardId);
            if (!card) return { ok: false, reason: "unknown_card" };
            if (!game.canAfford(command.actorId, card)) {
              return { ok: false, reason: "insufficient_funds" };
            }
            return { ok: true };
          })
          .execute(({ game, command }) => {
            game.buyCard(command.actorId, command.input.cardId);
          })
          .build();
        ```
      </div>
    </div>
  </div>
</div>

<div className="border-t border-stone-200 dark:border-stone-800">
  <div className="max-w-6xl mx-auto px-6 py-20 lg:py-28">
    <div className="grid grid-cols-1 lg:grid-cols-2 gap-12 lg:gap-16 items-center">
      <div>
        <h2 className="text-3xl lg:text-4xl font-semibold tracking-tight text-[#111110] dark:text-[#f0f0ee]">
          One executor for your rules.
        </h2>

        <p className="mt-6 text-lg text-stone-600 dark:text-stone-400 leading-relaxed">
          `createGameExecutor` gives you a single runtime that handles command
          dispatch, stage progression, deterministic RNG, snapshots, and
          replay. Use it to drive local tests, simulations, and game sessions
          from the same rule definitions.
        </p>

        <a href="/engine/executor" className="mt-6 inline-block text-[#d47c3a] dark:text-[#e8893f] font-medium hover:underline">
          Executor reference →
        </a>
      </div>

      <div>
        ```ts theme={null}
        const executor = createGameExecutor(game);
        const initial = executor.createInitialState("seed_1");

        const result = executor.executeCommand(initial, {
          type: "buy_card",
          actorId: "player_1",
          input: { cardId: 42 },
        });

        if (result.ok) {
          result.state;   // next canonical state
          result.events;  // semantic events to stream
        }

        executor.getView(result.state, "player_2"); // per-viewer sanitized state
        ```
      </div>
    </div>
  </div>
</div>

<div className="border-t border-stone-200 dark:border-stone-800 bg-[#f0f0ee]/40 dark:bg-stone-900/40">
  <div className="max-w-6xl mx-auto px-6 py-20 lg:py-28">
    <div className="grid grid-cols-1 lg:grid-cols-2 gap-12 lg:gap-16 items-center">
      <div className="lg:order-2">
        <h2 className="text-3xl lg:text-4xl font-semibold tracking-tight text-[#111110] dark:text-[#f0f0ee]">
          Generate schemas and types from your rules.
        </h2>

        <p className="mt-6 text-lg text-stone-600 dark:text-stone-400 leading-relaxed">
          Use the CLI to derive JSON schemas and TypeScript declarations from
          your game definition. Keep runtime validation, generated types, and
          tests aligned with the rules your engine actually runs.
        </p>

        <a href="/cli/overview" className="mt-6 inline-block text-[#d47c3a] dark:text-[#e8893f] font-medium hover:underline">
          CLI reference →
        </a>
      </div>

      <div className="lg:order-1">
        ```bash theme={null}
        $ tt-kit generate schemas
        generated schemas:./generated/schemas.generated.json

        $ tt-kit generate types
        generated types:./generated/canonical-state.generated.d.ts
        ```
      </div>
    </div>
  </div>
</div>

<div className="border-t border-stone-200 dark:border-stone-800">
  <div className="max-w-6xl mx-auto px-6 py-20 lg:py-28">
    <div className="text-center mb-14">
      <h2 className="text-3xl lg:text-4xl font-semibold tracking-tight text-[#111110] dark:text-[#f0f0ee]">
        Built for real games.
      </h2>

      <p className="mt-4 text-lg text-stone-600 dark:text-stone-400 max-w-2xl mx-auto">
        Everything you need to model rules end-to-end — from the first turn to
        a reproducible runtime.
      </p>
    </div>

    <Columns cols={3}>
      <Card title="Hidden information" icon="eye-slash" href="/engine/hidden-information">
        Project a different view of state to each player. The engine sanitizes
        canonical state into per-seat views automatically.
      </Card>

      <Card title="Stage progression" icon="diagram-project" href="/engine/stages">
        Model setup, draft, action, and scoring phases as a progression graph.
        The engine handles transitions and lifecycle resolution.
      </Card>

      <Card title="Deterministic RNG" icon="dice" href="/engine/game-state">
        Seeded, replayable randomness baked into the runtime — shuffle decks
        and roll dice without breaking determinism.
      </Card>

      <Card title="Snapshots & replay" icon="clock-rotate-left" href="/engine/testing">
        Capture any state, replay any sequence of commands. Reproduce bugs
        from production logs in a single line.
      </Card>

      <Card title="Scenario testing" icon="flask" href="/engine/testing">
        A test harness designed for game logic. Drive games through full flows
        with concise, declarative scenarios.
      </Card>

      <Card title="Rules-first runtime" icon="plug" href="/engine/executor">
        Run setup, commands, stages, visibility, snapshots, and replay through
        one engine-owned execution path.
      </Card>
    </Columns>
  </div>
</div>

<div className="border-t border-stone-200 dark:border-stone-800">
  <div className="max-w-3xl mx-auto px-6 py-24 lg:py-32 text-center">
    <h2 className="text-4xl lg:text-5xl font-semibold tracking-tight text-[#111110] dark:text-[#f0f0ee]">
      Build your next game.
    </h2>

    <p className="mt-6 text-lg text-stone-600 dark:text-stone-400">
      Install the package, define a state, write a command, and run it. The
      first end-to-end game takes about ten minutes.
    </p>

    <div className="mt-10 flex flex-wrap items-center justify-center gap-3">
      <a href="/quick-start/create-your-project" className="inline-flex items-center justify-center px-6 py-3 rounded-full text-base font-medium bg-[#d47c3a] text-white hover:bg-[#b86a30] transition-colors no-underline">
        Install tabletop-engine
      </a>

      <a href="/quick-start/build-your-game" className="inline-flex items-center justify-center px-6 py-3 rounded-full text-base font-medium bg-stone-100 dark:bg-stone-800 text-[#111110] dark:text-[#f0f0ee] hover:bg-stone-200 dark:hover:bg-stone-700 transition-colors no-underline">
        Build your first game
      </a>
    </div>
  </div>
</div>
