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: FormattedLine[] }[]; 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 }. |
useMessageText() |
(message: Message) => string: writes a message from the game logic that is not a log line, such as an offer's label or a GAME refusal's reason, in the language the frame shows the game in, each player it names by name. A message the catalogs lack is its key, as is one whose text names {player}, which only a log line fills. See Failures. |
useLastChange() |
LastChange: { actorPlayerId?; own: boolean; coalesced: boolean; direction: "forward" | "back"; steps: WasmStepView[]; undo?: WasmLastUndo | null }. Each step's lines are FormattedLines. |
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. Boardweaver shows each step for the longer of this time and the time to read and see it (Step time). |
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 in the player's language, 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. |
useLogLinks(handler) |
void. While the component is mounted, handler gets a LogLinkEvent, { type: "enter" | "leave" | "click"; key: string }, each time a player's pointer or focus first reaches a link in Boardweaver's game log (enter), both have left it (leave) or the player clicks it (click). key is the link's key from link(key, text). See Links in the log. |
useHistory(options?) |
options is { ownPanel?: boolean }: true hides Boardweaver's game log panel while the component is mounted, and Boardweaver's history button then opens and closes the game's log. Returns { entries: HistoryItem[]; more: boolean; open: boolean; setOpen: (open: boolean) => void }. entries is the match's log, oldest first, read from the opening to now and then each new row. more is true while later rows are still to be read. open is the game's log's state, always false while no mounted component passes ownPanel: true. See The log in the game. |
<History style? kindStyles? renderLink? /> draws the match's log with Boardweaver's own log component: style is a CSSProperties without display and flexDirection over the list, kindStyles a Record<string, CSSProperties> over each line by its kind, and renderLink(link: LinkPart): ReactNode draws a link's content in place of its parts. A tap on a row moves the board there, and its links reach useLogLinks. See The log in the game.
type HistoryItemStep = { index: number; lines: FormattedLine[]; endsLogRow: boolean; position: number | null };
type HistoryItem =
| { kind: "opening"; historyId: HistoryId; lines: FormattedLine[]; position: number | null }
| { kind: "decision"; historyId: HistoryId; actorPlayerId: PlayerId | null; createdAt: Timestamp; steps: HistoryItemStep[] }
| { kind: "undo"; historyId: HistoryId; actorPlayerId: PlayerId | null; createdAt: Timestamp; undoes: UndoneStep; position: number | null };
lineText(line: FormattedLine): string is a log line's parts as one string, with each player's name and each link's text: "Ana plays the Fireball".
apiVersion is the module's version, "4.1.0". Within a major version 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?: Message | null; 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: FormattedLine[]; movements: ViewedMovement[] }), FormattedLine, LinePart, PlayerPart, LinkPart, WasmLastUndo, ViewedMovement, Spot.
type FormattedLine = { playerId: number | null; kind: string | null; parts: LinePart[] };
type LinePart = string | PlayerPart | LinkPart;
type PlayerPart = { playerId: number; name: string };
type LinkPart = { key: string; parts: LinePart[] };
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.refused is NOT_OFFERED, INPUT_DOES_NOT_FIT, GAME (with the game logic's reason, a Message), NEEDS_SERVER, ENDS_DECISION, DECISION_OPEN or UNRESOLVED.
Messages: Message ({ key: string; args?: Record<string, Arg> }) and Arg ({ player } | { message } | { link: { key, text } } | { number } | { text }), the text the game logic writes, which useMessageText() writes out.
Platform: PlaybackOptions, HistoryOptions, HistoryControl, HistoryItem, HistoryItemStep, HistoryProps, LogLinkEvent, PlayerProfile, MatchStatus, ColorMode, GameTheme, Sounds, SoundType, PlaySoundOptions, SoundHandle, AudioSettings.