Have more questions? Join our

This documents framework v1, which is deprecated. Games already on it keep running and their authors can keep editing them, but new games are created on the current framework — start with React frontends.

Building rules pages

You are building the rules pages for a BoardWeaver game: the styled, illustrated pages a player reads to learn how to set up and play. Each page is a file at /src/rules/<slug>.bwss — a JSON document holding a BWSS tree. At commit time the platform compiles every .bwss source into a standalone HTML page; you never write HTML yourself.

This is reference-and-art work, not gameplay logic. A rules page renders no live state and dispatches no actions — it is static, themed presentation: headings, prose, diagrams, piece illustrations, and links between pages.

Begin by locking the game

Work against a single, already-selected game.

  • If you don't have a game_definition_id yet, call list_my_games and have the author pick one. Only ever touch that one game.
  • Call get_game to read the game's name, description, mood, and voice, and list_files to see what already exists under /src — existing rules pages, a theme, the game code.
  • If there is a plain-text /src/rules/index.md, read it: it is the author's written rules and the best source for what the pages must cover. (index.md is ordinary markdown text — separate from the styled .bwss pages you build here.)

Step 1 — Develop the theme first

Rules pages should look like they belong to the game. If the game has no theme yet, develop one before writing any rules. Building rules first means redoing them once the visual world exists.

  • Check for /src/theme.html (the visual style reference) and /theme.json (the structured theme document with $-tokens). Read design-theme-instructions and game-themes for how these are produced.
  • If neither exists, pause and develop the theme — offer to run the theme workflow (the design-game / theme step), or do it now. A theme gives you a palette, typography, and mood to design the rules pages against, and /theme.json $-tokens you can reference directly in BWSS styles.
  • If the author explicitly wants to skip theming, you may proceed with restrained, neutral styling — but say so, and prefer theme tokens over hardcoded colors so the pages pick up the theme later.

Step 2 — Align on the outline with the author

Before writing a single .bwss file, agree with the author on the outline: what pages exist and what each one covers. Don't guess the structure — converge on it together.

  • Propose a page list as slugs with a one-line purpose each, e.g.
    • index — overview, components, and the goal of the game
    • setup — how to set up the board
    • play — turn structure and the actions a player can take
    • scoring — how the game ends and how to win
  • Each slug becomes a file: /src/rules/<slug>.bwss → compiled page <slug>.html. Pages link to each other by slug (see Anchor below). index is the conventional landing page.
  • Confirm the level of detail, the reading order, and how pages cross-link. Get explicit agreement on the outline, then build to it. Revise the outline with the author rather than silently restructuring mid-build.

Step 3 — Author the pages as BWSS

Each /src/rules/<slug>.bwss file is one JSON value: a single root BWSS node (almost always a Box) with nested children. Write the file with write_file, passing the game_definition_id and the full JSON.

The rules surface allows four node types:

type Purpose
"Box" Generic flex container. children are nested nodes or plain text strings.
"Image" { src: GameImageKey, alt?, style? } — a game image by key. Unknown keys render nothing.
"Svg" { viewBox: {width,height}, paths: [{d, fill?, ...}], style? } — inline vector art. Only <svg> + <path> are emitted.
"Anchor" { href, style?, children? } — a hyperlink. Rules pages are the only surface with links.

Text is a plain string child inside a Box (or Anchor) — there is no Text node. Style text by setting typography fields (fontSize, fontWeight, color, textAlign, …) on the enclosing Box.

Styling is the standard BWSS allow-list — the same strict, structured style object used by piece and space render(). Read styling for the full property list and value grammar. The essentials:

  • Strict allow-list: an unknown style property throws (no border/background/font shorthands).
  • Colors: hex, rgb()/rgba(), named colors, or a $-token ($colors.surface.canvas). No url(), var(), calc().
  • Lengths: a number (px), a <number>(px|%|em|rem) string, or a $-token. No vh/vw/calc().
  • Prefer theme tokens ($colors.*, $semanticTokens.*, $spacing.*, $fonts.*) over hardcoded values so pages track the theme. Tokens resolve against /theme.json; with no theme, $-tokens resolve to nothing, so supply concrete fallbacks if you skip theming.

Linking between pages — Anchor

Anchor.href is validated to internal targets only. Allowed shapes:

  • setup — a bare sibling page slug (the filename of another .bwss, without extension). Compiles to setup.html.
  • setup#step-2 — a slug plus a fragment.
  • #overview — a same-page fragment.

Everything else is rejected: http(s):, javascript:, data:, protocol-relative //host, absolute /path, and ... You cannot link off-site.

Fragment targets — the id field. To make a #fragment link land somewhere, give the destination node an id: set id on the Box (or Anchor) you want to jump to, then link to it with href: "#that-id" on the same page or href: "slug#that-id" from another page. An id must be a fragment identifier — a letter, then letters / digits / _ / - (e.g. "scoring", "step-2"). id is a rules-surface field on Box and Anchor only; to anchor to an Image or Svg, wrap it in a Box with an id.

{ "type": "Box", "children": [
  { "type": "Anchor", "href": "#scoring", "children": ["Jump to scoring"] },
  { "type": "Box", "id": "scoring", "children": ["Scoring rules…"] }
] }

An Anchor wraps content like a Box — its children can be text, an Image, or nested styled boxes (e.g. a card-shaped link to another page).

A minimal page

{
  "type": "Box",
  "style": {
    "display": "flex",
    "flexDirection": "column",
    "gap": 16,
    "padding": 24,
    "backgroundColor": "$colors.surface.canvas",
    "color": "$semanticTokens.fg.default"
  },
  "children": [
    {
      "type": "Box",
      "style": { "fontSize": 28, "fontWeight": "bold", "fontFamily": "$fonts.display" },
      "children": ["How to Play"]
    },
    {
      "type": "Box",
      "children": ["On your turn, place one tile, then draw back up to three."]
    },
    {
      "type": "Anchor",
      "href": "scoring",
      "style": { "color": "$colors.accent.default", "fontWeight": "bold" },
      "children": ["Next: Scoring →"]
    }
  ]
}

Step 4 — Commit to compile

Rules pages compile at commit time, not on save. After writing the .bwss files:

  • Commit with the commit tool — a developer message (e.g. "Add setup and scoring rules pages") and a player-facing changelogMessage (e.g. "Added illustrated rules.").
  • On commit, every /src/rules/*.bwss source is validated and rendered to a hidden /rules/<slug>.html artifact. The compile uses the committed theme and game images, so it tracks the current look.
  • If any .bwss is invalid JSON or violates the rules-surface schema, the commit fails with RULES_COMPILE_FAILED and rolls back — nothing partial is committed. Read the error (it names the file and the reason), fix the tree, and commit again.
  • Editing or deleting a .bwss and re-committing regenerates the pages; stale pages for deleted sources disappear.

Checklist

  • One game locked (game_definition_id); existing files reviewed.
  • Theme developed first (or skip explicitly acknowledged; tokens preferred regardless).
  • Page outline agreed with the author before authoring.
  • Each page is one JSON BWSS tree using only Box / Image / Svg / Anchor; text as string children.
  • Cross-page links use bare slugs; in-page #fragment links have a matching id on their target; styles use theme tokens where possible.
  • Committed; RULES_COMPILE_FAILED errors resolved.