Top-level fields
The complete top-level shape of a Ruleset. Only a handful of fields are
required; the rest are opt-in features.
interface Ruleset { name: string; version: number; catalog?: { abstract: string; players?: string; thumbnail?: string }; teams: Team[]; minPlayers?: number; maxPlayers?: number; map: MapDefinition; rules: Rule[]; playerJoinStates?: Record<string, unknown>[]; onStart?: Initializer[]; theme?: GameTheme; teamAssignment?: { humanTeamId: string; botTeamId?: string }; bots?: BotClass[]; itemTypes?: ItemType[]; items?: ItemSpawnSpec[]; interactions?: InteractionSpec[]; countdownSeconds?: number; objectives?: ObjectiveRule[]; visibility?: VisibilityRule[];}Required fields
Section titled “Required fields”string — the display name shown in the catalog and on clients.
version
Section titled “version”number — the ruleset version. Bump it when you change a published game.
Team[] — the teams. Use [] for a free-for-all game (no teams).
interface Team { id: string; name: string; color?: string }Declaring teams enables auto-balancing (joiners spread across teams) and the
{ byTeam: id } selector. color is a hex string used for markers and UI.
MapDefinition — the zones, points, and annotations. See Map &
zones. Always required (even a single play-area
zone).
Rule[] — the game logic. May be empty ([]) for a pure sandbox, but that’s
rare.
interface Rule { id: string; when: Condition; do: Action[] }Each rule has a unique id, a when condition,
and an ordered do list of actions.
Catalog
Section titled “Catalog”catalog
Section titled “catalog”Optional listing metadata.
interface GameCatalogMetadata { abstract: string; // one-line pitch players?: string; // human-readable, e.g. "4+ players, 2 teams" thumbnail?: string; // filename inside the bundle}Player counts
Section titled “Player counts”minPlayers / maxPlayers
Section titled “minPlayers / maxPlayers”number (optional) — human-player count constraints enforced at game start. The
pre-flight checklist blocks starting outside this range. (Bots are counted
separately, by bot-class minimums.)
Starting state
Section titled “Starting state”playerJoinStates
Section titled “playerJoinStates”Record<string, unknown>[] (optional) — initial state objects applied to
players in join order. If more players join than there are entries, the
last entry is reused for everyone after.
playerJoinStates: - { it: true } # 1st joiner - { it: false } # 2nd joiner — and everyone after (last entry repeats)A single-entry list means “everyone starts identical.”
Duration
Section titled “Duration”countdownSeconds
Section titled “countdownSeconds”number (optional) — fixed game duration in seconds. When set, the engine
records a deadline at start and ends the game when it expires. Pause/resume
rolls the deadline forward so visible time-remaining doesn’t jump during a pause.
Feature blocks (each has its own page)
Section titled “Feature blocks (each has its own page)”| Field | Type | Page |
|---|---|---|
onStart | Initializer[] | onStart & initializers |
theme | GameTheme | Theme, objectives & visibility |
objectives | ObjectiveRule[] | Theme, objectives & visibility |
visibility | VisibilityRule[] | Theme, objectives & visibility |
teamAssignment | { humanTeamId; botTeamId? } | Bots & behavior trees |
bots | BotClass[] | Bots & behavior trees |
itemTypes | ItemType[] | Items & interactions |
items | ItemSpawnSpec[] | Items & interactions |
interactions | InteractionSpec[] | Items & interactions |
teamAssignment
Section titled “teamAssignment”{ humanTeamId: string; botTeamId?: string } (optional) — pins WebSocket joiners
to a specific team instead of auto-balancing. Required for asymmetric games like
Bots vs Humans. See Bots.