Skip to content

onStart & initializers

onStart is a list of initializers — one-shot setup steps run once when the gamemaster starts the game (before any rules evaluate against the new state). They operate on the live player roster, which makes them the right place to set up cross-player relationships you can’t express in playerJoinStates.

onStart?: Initializer[];
type Initializer =
| { kind: "assign_cycle"; key: string; who?: PlayerSelector }
| { kind: "send_event"; to: PlayerSelector; event: Record<string, unknown> }
| { kind: "set_state_delayed"; who?: PlayerSelector; key: string; value: unknown; delayMs: number };
{ kind: "assign_cycle"; key: string; who?: PlayerSelector }

Generate a random single-cycle permutation over the selected players (default any) and set each player’s state[key] to the next player’s id. The last wraps to the first — exactly one cycle, no fixed points (when there are ≥ 2 players, nobody is assigned to themselves).

This is the engine behind target-chain games:

playerJoinStates:
- { alive: true, targetId: null }
onStart:
- { kind: assign_cycle, key: targetId }

Every player gets a unique target, and following the chain visits everyone once — the structure Assassin needs. Source: apps/wage-engine/src/games/assassin/game.json.

{ kind: "send_event"; to: PlayerSelector; event: Record<string, unknown> }

Send a game event to a selector of players at game-start — most commonly an opening countdown.

onStart:
- { kind: send_event, to: any, event: { type: countdown, from: 3 } }

Source: apps/wage-engine/src/games/bomb_tag/game.json.

{ kind: "set_state_delayed"; who?: PlayerSelector; key: string; value: unknown; delayMs: number }

Set a state key on a selector of players after delayMs milliseconds from start. Use it for a timed opening — e.g. release players from a “locked” start after a grace period.

onStart:
- { kind: set_state_delayed, who: any, key: locked, value: false, delayMs: 3000 }

When to use onStart vs. rules vs. join states

Section titled “When to use onStart vs. rules vs. join states”
  • playerJoinStates — per-player starting values that don’t depend on other players (you’re it / you’re not).
  • onStart — one-shot setup that does depend on the assembled roster (target chains, dealing roles across everyone, an opening countdown). Runs once at start.
  • Rules — anything ongoing, reacting to play as it unfolds.