Have more questions? Join our

Framework v3: rules in Rust

Framework v3 is a preview. A v3 game ships two files:

  • /src/lib.rs: the game's rules, written in Rust against the boardweaver_live SDK (see v3-rust-sdk). Other /src/*.rs files are modules you declare from lib.rs with mod name;.
  • /src/frontend.tsx: the React client, on v3's own boardweaver/react: the same UI and animation libraries as v2 and the same no-props default export, but reading the view of the state its player may see. See v3-react-client.

A game is pinned to v3 when it is created with create_game and frameworkMajor: 3. It starts as tic-tac-toe, and get_example with tic-tac-toe-rust shows the same seed.

How a v3 game is built and run

  • Built with Cargo. validate_code, start_game and commit compile /src/lib.rs to WebAssembly. The SDK owns Cargo.toml: a game uses Rust's standard library, boardweaver_live, serde and serde_json, and nothing else. A compile error comes back as /src/lib.rs:LINE:COL: error[...].
  • Run by the game runner. Each match keeps one live instance of the game's module. Starting a match loads the state once; after that each move sends only the action and gets back what changed. Every move is held to a time and memory budget, and a move that panics fails with the panic's message, leaving the match as it was.
  • Served per player. Every viewer receives their own view of the state, with everything they may not see removed, by the same function the runner uses. A piece has no id: it lives in its space, and the platform names it by its position there.
  • Predicted in the browser. The client runs the same module to work out its player's legal actions and scores, and to show a move before the server confirms it. Two moves are never predicted: one that draws randomness (Rng), whose seed is the server's, and one that picks from a group the player cannot tell apart, which the server draws from at random.
  • Recorded for replay and for bots. Every move's history row keeps the action the game was handed, its intent (choice, confirm, cancel, undo), the seed it drew from, and the log lines it wrote.

What a game may and may not do

  • Change state only through Table. Reads are free (table.state()); every change goes through a Table method, which is how the platform learns what changed.
  • Be a pure function of its state. The same state, action and seed must give the same result. Keep nothing in static or global variables: a match can be reloaded from its state at any time, and anything kept outside it is lost.
  • Use Rng for anything random. There is no clock and no other source of randomness.
  • Allow undo and write a log where they help. table.allow_undo() lets a player take a move back and table.log(...) writes the game log; see "Undo" and "Game log" in v3-rust-sdk.
  • Keep secrets in private state. meta_data reaches every client. A player's hidden picks, hands and bids go in private state or a private space (see "Hidden information" in v3-rust-sdk).
  • Say what each piece looks like from outside. public_kind is what everyone sees; what it really is goes in private_kind, which only its viewers receive.

Not available yet

  • render_game does not run on preview environments.
  • The studio's in-browser preview does not build v3 games; play them through start_game and apply_action, or in a real match.
  • There is no TypeScript type checking of /src/frontend.tsx for v3 games; validate_code checks that it bundles.