Documentation

Game logic

v2 · Stable

Set up a game

gameConfig (required)

type GameStateConfigFn = (params: { numPlayers: number }) => GameStateConfigObject;

Called once. Deterministic : same params, same output. See v2-game-source for the config object's fields.

preGameInitialization (optional)

type PreGameInitializationFn<MetaData = Record<string, unknown>> =
  ((gameState: GameState<MetaData>) => void) | undefined;

Runs once, after gameConfig, before any action. May mutate. This is where randomized setup goes : shuffling a deck, dealing hands, choosing a start player : because gameConfig has to stay deterministic and this does not.

gameConfig and the config object

gameConfig({ numPlayers }) runs once and returns the table's starting layout. It must be deterministic : same params, same output : because reconnects and replays re-run it. Randomized setup (shuffling, dealing) belongs in preGameInitialization.

export const gameConfig: GameStateConfigFn = () => {
  const config: GameStateConfigObject = {
    startingPlayerStrategy: "Random",
    scoreLabels: ["Points"],
    spaces: {
      "0": new GridCell({ x: 0, y: 0 }),
      "1": new GridCell({ x: 135, y: 0 }),
    },
    pieces: {},
    pieceDefs: {
      "x-token": new XToken({ order: 1 }),
    },
  };
  return config;
};
Field Holds
spaces Starting spaces, keyed by spaceId.
pieces Starting pieces, keyed by pieceId. May be empty if you create pieces during play.
pieceDefs Every piece kind the game can ever create, keyed by kind. Registers the class so state.addPiece can resolve it at runtime.
scoreLabels Names the entries in each player's publicPoints array, in order.
startingPlayerStrategy How the first active player is chosen, e.g. "Random".
player Optional per-player setup : spaces each player owns (a hand, a board side).

A kind you only create at runtime must still appear in pieceDefs. state.addPiece throws if the kind isn't registered.

Need a hand with this?

Join our Discord