Have more questions? Join our Discord

boardweaver/react reference

Every hook and helper a client can import from boardweaver/react. How to use them together is in The React client. Every hook throws outside a match.

Hooks

Hook Returns
useMatch() { ready: boolean; status: "waiting" | "in_progress" | "finished" | "locked" | null; viewer: PlayerId | null; isGameOver: boolean; online: boolean }. ready is false until the match, the seat's saved draft and the first page of the steps the seat has not seen have arrived.
useBoard() State | null: the seat's view with its draft and its decision on its way applied.
useOffers() Offer[]: the seat's offers on that board.
useAct() (action: Action | Action[]) => Outcome: takes one step on the board of this render, or a list of steps from one event.
useDraft() DraftView: { steps: { action, intent, lines }[]; reopenedSteps: number }.
useUndo() { available: "draft" | "server" | "none"; undo: () => Outcome }.
usePending() { pending: PendingView | null; deferred: string[] }. PendingView is { id; kind: "decision" | "undo"; predicted: boolean; historyId? }. deferred lists ids whose result the connection lost.
useFailures() { failures: CoreFailure[]; dismiss: (id: string) => void }.
useLastChange() LastChange: { actorPlayerId?; own: boolean; coalesced: boolean; direction: "forward" | "back"; steps: WasmStepView[]; undo?: WasmLastUndo | null }.
usePlayback(options?) options is { ownControls?: boolean }: true hides Boardweaver's return card, the bubble with each step's log lines, and the step controls while the component is mounted. Returns { status: "now" | "playing" | "paused"; behind: number; more: boolean; fetching: boolean; canStepBack: boolean; speed: PlaybackSpeed; setSpeed; play; pause; stepForward; stepBack; skipToNow }, where PlaybackSpeed is 0.5 | 1 | 2 | 4 | 8. Boardweaver's bar plays at 1, and a finished match's replay page offers 1 to 8. behind counts the steps read after the one on the board, and more is true when steps past those are not read yet. See Other players' steps.
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. The default is 600 ms per step.
useScores() Scores: Record<string, { publicPoints: number[]; privatePoints: number[] }>, keyed by player id as a string.
useSelf() { playerId: PlayerId; isActive: boolean } | null. null for a spectator.
usePlayers() PlayerProfile[]: { id: number; name: string; avatarUrl?: string | null; bot?: { id: string; difficulty?: "easy" | "standard" | "hard" }; abandoned?: boolean }, in the order of the state's players. id is the seat's player id. name is the person's username or the bot's name, and bot is set only on a bot's seat. abandoned is true on a seat whose player left the match. A player leaving ends the match, so the match can be over while useMatch().isGameOver is still false.
useImage(key) string | undefined: the URL of the game's art key.
useSounds() Sounds: { play(key: string, options: PlaySoundOptions): SoundHandle; stopAll(type?: SoundType): void }, the same object for the whole match. PlaySoundOptions is { type: "music" | "effect"; loop?: boolean; volume?: number } and SoundHandle is { stop(): void }. play throws for a key the game has no sound for. See Sounds.
useAudioSettings() AudioSettings: { music: boolean; effects: boolean }, what the player hears now. useSounds() already applies it.
useGameTheme() GameTheme: the game's /theme.json.
useColorMode() "light" | "dark", following the player's setting.
useViewport() Viewport: { width: number; height: number }, the size of the client's area in CSS pixels. It changes when that area is resized. See Layout.
useMatchEnd() { startsNextMatch: boolean; nextMatchPending: boolean; nextMatch: () => void; returnToGames: () => void }. For GameOver.

lineText(line: LogLine): string is a log line's text with its links' text, as one string: "plays the Fireball". Boardweaver's bubble and step bar read lines with it too.

apiVersion is the module's version, "2.3.0". The module only grows: a later version adds hooks and fields and never removes them.

Types

Import any of these with import type { ... } from "boardweaver/react".

The board: State, Player, Space, Piece, Arrangement, PlayerId, Score, Scores.

type State = { activePlayerIds: number[]; players: Player[]; spaces: Space[]; metaData?: Record<string, unknown> };
type Space = { spaceId: string; kind: string; owner?: number; arrangement?: "ordered" | "collection"; pieces?: Piece[]; publicState?: Record<string, unknown>; privateState?: Record<string, unknown> };
type Piece = { publicKind: string; privateKind?: string; owner?: number; publicState?: Record<string, unknown>; privateState?: Record<string, unknown> };

Moves: Action, Offer, Intent, Input, InputValue, Outcome.

type Action =
  | { type: "SpaceClick"; spaceId: string }
  | { type: "PieceClick"; spaceId: string; index: number }
  | { type: "Command"; name: string; value?: string | number | null };
type Offer = { action: Action; intent: "choice" | "confirm" | "cancel"; label?: string; input?: Input | null; reveals?: boolean };
type Input = { type: "Text"; maxLen: number; suggestions: string[] } | { type: "Integer"; min: number; max: number; step?: number };

Outcome from act and undo is { id, type: "applied" }, { id, type: "sent" }, { id, type: "undone" } or { id, type: "failed", reason: FailureReason, applied? }, where applied counts the steps of a list that joined before one failed. The type also has committed and deferred, which act and undo never answer.

Changes: LastChange, Direction, PlaybackStatus, PlaybackView, PlaybackSpeed, WasmStepView ({ actorPlayerId?; intent?; lines: LogLine[]; movements: ViewedMovement[] }), LogLine, LinePlayer, LogSegment, WasmLastUndo, ViewedMovement, Spot.

type LogLine = { player: LinePlayer; kind?: string | null; segments: LogSegment[] };
type LinePlayer = "actor" | "none" | { seat: number };
type LogSegment = string | { key: string; text: string };
type Spot = { type: "At"; spaceId: string; index: number } | { type: "Hidden"; spaceId: string };
type ViewedMovement =
  | { type: "Moved"; from: Spot; to: Spot; piece: Piece }
  | { type: "Added"; at: Spot; piece: Piece }
  | { type: "Removed"; from: Spot; piece: Piece }
  | { type: "Flipped"; at: Spot; piece: Piece }
  | { type: "Shuffled"; spaceId: string };

Drafts and failures: DraftView, DraftStepView, PendingView, PendingKind, UndoAvailable, CoreFailure, FailureReason, Refusal, Unresolved, AbandonedStep, AbandonReason, HistoryId, Timestamp.

FailureReason.code is one of:

Code Means
NOT_PLAYING This client is a spectator, or the match takes no moves.
LOADING The match has not loaded yet.
WAITING Another decision or undo is on its way.
STALE The step was made on a board the player no longer sees.
PLAYING The board shows an earlier step, not now. Skip to now first.
UNPREDICTABLE The step cannot show before Boardweaver applies it.
DRAFT_FULL The decision already has 200 steps.
NOTHING_TO_UNDO Undo has nothing to take back.
REFUSED The game logic refused the step. refusal says how.
MODULE_FAILED The game logic failed while showing the step. message says how.
SERVER_REFUSED Boardweaver refused the decision. Carries status, message, the dropped steps and maybe a refusal.
NOT_APPLIED The decision was not applied. Carries the dropped steps.
DRAFT_DROPPED Draft steps no longer fit the board and were dropped. Carries the dropped steps.
DRAFT_LOAD_FAILED The saved draft did not load. Carries status and message.

Refusal.code is NOT_OFFERED, INPUT_DOES_NOT_FIT, GAME (with the game logic's reason), NEEDS_SERVER, ENDS_DECISION, DECISION_OPEN or UNRESOLVED.

Platform: PlaybackOptions, PlayerProfile, MatchStatus, ColorMode, GameTheme, Sounds, SoundType, PlaySoundOptions, SoundHandle, AudioSettings.