Players and turns
Top-level
| Property | Type | Mutable |
|---|---|---|
currentPlayer |
Player<MetaData> |
no : server-set, the viewer this call runs for |
activePlayerIds |
number[] |
yes : this is whose turn it is |
metaData |
MetaData |
yes : free-form game-wide scratch state |
scoreLabels |
string[] | undefined |
yes |
scoreLabels names each entry of the points arrays your getPlayerScores returns, in order. The labels head the columns of the final scores table that players see at the end of a match and in their Recently played history, and of the score table on the studio Matches page. Studio Stats also uses them for "Points by category", which compares how many points winners and everyone else score in each label. Points are matched to labels by name, so keep a label's name stable across versions to compare it over time. An entry with no label is shown as "Score 1", "Score 2", and so on.

Scoped lookups
Player has the same piece / pieces / space / spaces / *OfKind methods, scoped to spaces that player owns and the pieces inside them:
const me = state.currentPlayer;
me.pieces("card", (c) => c.isSelected);
me.ensureSpaceOfKind("hand");
Per-player spaces get synthesized ids like ${playerId}/space/${configKey}, so player.space("hand") (an id match) usually misses : use player.spaceOfKind("hand").
Space scopes the same way over its contents:
space.pieces("card");
space.ensurePiece("p1");
And you can walk upward:
piece.space; // Space | undefined
piece.ensureSpace(); // throws if unattached
piece.player; // Player | undefined
space.player; // Player | undefined
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.