Documentation

The client

v3 · Preview

Framework v3 is an opt-in preview available to everyone. New games use the stable framework by default.

Animate game changes

API

Hook Contract
useLastChange() LastChange: { actorPlayerId?; own: boolean; coalesced: boolean; direction: "forward" | "back"; steps: WasmStepView[]; undo?: WasmLastUndo | null }. Each step's lines are FormattedLines.
useStepDuration(duration) void. duration is milliseconds per change at 1x, a number or (change: LastChange) => number, while the component is mounted. When several components set one, the one mounted last applies. Boardweaver shows each step for the longer of this time and the time to read and see it (Step time).

What changed

useLastChange() gives the last change: steps, each with actorPlayerId, lines and movements, or an undo. Each line is a FormattedLine: the line's message (Changing the state) in the language the frame shows your game in. Its playerId is the line's seat (null for none), its kind is the game's label, and its parts are a string, a player { playerId, name } or a link { key, parts } each. lineText joins a line's parts into one string, with each player's name:

const step = useLastChange().steps.at(-1);
const text = (step?.lines ?? []).map(lineText).join(" ");

Draw the parts yourself to style a player or a link. useDraft() gives the steps of the player's open decision with their lines in the same form.

Each movement is Moved, Added, Removed, Flipped or Shuffled, with positions as { type: "At", spaceId, index }, or { type: "Hidden", spaceId } for a hidden piece. Animate them in your own components, with boardweaver/motion (Client libraries). Forward over a game log row of several steps, such as a piece dragged across squares before it is placed, comes as one step with the row's lines and its net movements: each piece moves once, from where it was to where the row left it, so animate it as any other step. When coalesced is true, the board jumped (first load, reconnect, undo, skip to now, step back, a jump to a move on a replay's slider or move log, or a Forward over a row whose pieces cannot be followed, such as one that shuffles a deck or flips a card inside a hidden group): show the new board without animating. direction is back when the player stepped or jumped back: show the earlier board, and never play its movements in reverse.

While reviewing moves, the match bar offers Back, Play or Pause, Forward, and Skip to now, with Rules and match actions alongside.
While reviewing moves, the match bar offers Back, Play or Pause, Forward, and Skip to now, with Rules and match actions alongside. Example data from the local development UI. Select the image to enlarge.

Step time

At 1x, Boardweaver shows each step of other players for at least this time:

The step has Time at 1x
log lines 800 ms, plus 55 ms for each character of their text, from 1500 ms to 5000 ms
movements and no log lines 700 ms, plus 100 ms for each movement after the first, up to 1500 ms
no log lines and no movements 250 ms

An undo stays for 600 ms. The speed divides each time: at 2x, a step of 1800 ms stays for 900 ms.

Call useStepDuration in every client that animates a change, such as a piece that slides or a card that flips. Give it the time your animations take. Boardweaver shows each step for the longer of your time and the time in the table. Without it, the next step can start before your animation ends.

Give every step one time:

useStepDuration(1200);

Or compute the time from your animations. This client slides a piece for 450 ms and flips a piece for 300 ms. It adds 400 ms so the player sees the result:

import type { LastChange } from "boardweaver/react";

const SLIDE_MS = 450;
const FLIP_MS = 300;
const SETTLE_MS = 400;

export const stepTime = (change: LastChange) =>
  change.steps.reduce((total, step) => {
    const slides = step.movements.filter((movement) => movement.type === "Moved").length;
    const flips = step.movements.filter((movement) => movement.type === "Flipped").length;
    return total + slides * SLIDE_MS + flips * FLIP_MS + SETTLE_MS;
  }, 0);

Then call useStepDuration(stepTime) in the component that draws the board.

Need a hand with this?

Join our Discord