Set up a game
gameConfig (required)
type GameStateConfigFn = (params: { numPlayers: number }) => GameStateConfigObject;
export const gameConfig: GameStateConfigFn = ({ numPlayers }) => ({ /* ... */ });
Called once per game. Returns the initial config object : see source-files for the field list. Deterministic: same params → same output (so reconnects and replays match).
preGameInitialization (optional)
type PreGameInitializationFn<MetaData = Record<string, unknown>> =
((gameState: GameState<MetaData>) => void) | undefined;
export const preGameInitialization: PreGameInitializationFn = (state) => {
state.activePlayerIds = [state.players()[0].playerId];
};
Called once, after gameConfig and before any action. May mutate gameState. Use for randomized setup (deck shuffle, hand draw) : gameConfig runs in a deterministic builder context, preGameInitialization runs in the same mutating context as applyActions.
gameConfig return shape
GameStateConfigFn is (params: { numPlayers: number }) => GameStateConfigObject. The returned object:
type GameStateConfigObject = {
startingPlayerStrategy: "Random" | "All";
pieces: Record<string, PieceDef>; // top-level pieces, instantiated at game start
spaces: Record<string, SpaceDef>; // top-level spaces, instantiated at game start
player?: {
spaces?: Record<string, SpaceDef>; // per-player spaces (one set per seat)
publicState?: Record<string, unknown>; // default per-player public state
privateState?: Record<string, unknown>; // default per-player private state
def?: PlayerDef; // optional per-player Def (rare)
};
pieceDefs?: Record<string, PieceDef>; // register kinds used only via state.addPiece
spaceDefs?: Record<string, SpaceDef>; // register kinds used only via state.addSpace
metaData?: Record<string, unknown>; // initial gameState.metaData
scoreLabels?: string[]; // labels for the score columns shown in UI
};
Map keys ("0", "1", ...) become the initial pieceId / spaceId. Per-player spaces synthesize ids ${playerId}/space/${key}.