Skip to main content
Browser-targeted. The React layer. The runtime is declared once in createOpenturnBindings, and a zero-prop <OpenturnProvider> auto-resolves transport so the same component runs unchanged under openturn dev and openturn-cloud.

Install

Authoring surface

createOpenturnBindings(game, options)

Turns a game definition into a typed binding bundle. The runtime + initial match are declared once at the call site.
options is required on the first call for a given game definition. Subsequent calls (e.g. an experience component sharing the same game import) may omit options and reuse the cached bindings.

CreateOpenturnBindingsOptions<TGame>

OpenturnBindings<TGame>

The return type. Exposes the provider, the match-store factory, the consolidated hooks, and the resolved runtime literal.

The consolidated API

<OpenturnProvider>

Zero-prop in normal app code:
The provider auto-resolves what to do based on the runtime declared in createOpenturnBindings:
  • runtime: "local" → in-process session backed by the bindings’ match.
  • runtime: "multiplayer" → connects via the #openturn-bridge=… URL fragment that the host shell injects (openturn dev locally, openturn-cloud in production).
The single optional prop is match — pass an OpenturnMatchStore to override the in-process session for tests, Storybook, or a load-saved-game flow:
If runtime: "multiplayer" is declared but no bridge fragment is present (and no hosted.readInit was set), the provider throws — so “I forgot to launch under a host shell” surfaces at mount instead of silently doing nothing.

useMatch()

Returns a mode-discriminated MatchView<TGame> for the active match:
Branch on view.mode and read the right fields without knowing the transport. Throws if no match is active yet (pre-connect in hosted mode); call useRoom() instead if you need to render a pre-game UI.

useRoom()

In runtime: "multiplayer" bindings rendered under a host shell, returns the full HostedRoomState — phase, lobby, game, bridge handle, invite URL. Throws when called outside a multiplayer provider.
Subscribe to host-driven shell controls via room.bridge.shellControl.on(({ control, phase }) => …) — see BridgeShellControlChannel. Shell controls (save, load, reset, return-to-lobby, …) are declared in the deployment manifest and implemented by the host adapter; games subscribe to react (e.g. clear local UI on reset) but do not register them.

useInspector(options?)

Build the inspector timeline + interaction state for the active match. Returns UseInspectorResult | null (null when no match is connected yet). The result is structurally compatible with InspectorContextValue from @openturn/inspector-ui, so it can drive any custom inspector UI.
One hook covers both local and hosted modes, picking the correct timeline source from useMatch().

useReplayInspector(source, options?)

Standalone replay viewer. Takes either a saved-replay envelope or a pre-materialized timeline; returns the same shape as useInspector. No live match required:

UseInspectorResult

Shape returned by useInspector/useReplayInspector:
Structurally compatible with InspectorContextValue from @openturn/inspector-ui.

Local match store

createLocalMatch(options)

Build an OpenturnMatchStore<TGame> from a match and session options. Wrap the store in <OpenturnProvider match={store} /> and read it with useMatch().

OpenturnMatchStore<TGame, TMatch>

The underlying store. { dispatch, getLastBatch, getReplayData, getSnapshot, getPlayerView, getStatus, subscribe, reset? }. You typically do not touch it; useMatch() wraps it.

OpenturnMatchState<TGame>

Shape of useMatch().state when match.mode === "local":
Narrow on the discriminant before reading:

Hosted state types

HostedMatchState<TGame, TPublicState, TResult>

Surfaced via useMatch() (hosted/dev mode) and useRoom().game.

HostedDispatchMap<TGame> / HostedCanDispatchMap<TGame>

Typed dispatch map and per-event availability flags. Each dispatcher returns Promise<HostedDispatchResult> — awaiting it surfaces the server’s real ack or rejection, matching the { ok, error } shape from the local session:

HostedMatchStatus

"idle" | "connecting" | "connected" | "disconnected" | "error".

HostedLastAction<TGame>

A discriminated shortcut on hostedMatch.lastAction that carries the most recent player-authored action in a form that narrows by event name:
Replaces manually drilling into lastBatch.steps.find(s => s.kind === "action")?.event.payload. Narrow on lastAction.event to type the payload:
null when the match has not produced a player action yet (initial connect, or last batch contained only internal events).

HostedDispatchResult

The resolved value of dispatch.<event>(payload) promises: { ok: true; clientActionID } on ack, or { ok: false; error; reason?; details?; clientActionID? } on rejection, disconnect, or send failure.

SessionStatus

"ready" | "syncing" | "disconnected" | "error". The status field on OpenturnMatchState (local mode).

DispatchResult / DispatchSuccessResult

DispatchResult = DispatchSuccessResult | GameErrorResult where DispatchSuccessResult = { ok: true }. The resolved value of a local-mode dispatch.<event>(payload) promise.

LocalSavedSnapshot<TGame>

Snapshot shape accepted by createLocalMatch({ initialSavedSnapshot }) to warm-start a local session from a decoded save envelope.

UseInspectorOptions<TGame> / UseReplayInspectorSource<TGame>

Option shapes accepted by useInspector(options?) and useReplayInspector(source, options?). UseReplayInspectorSource is { envelope } | { timeline }.

HostedMatchOptions

CreateGameBridgeOptions & { retainBatchHistory?, inspector? }. Passed as hosted: {...} on createOpenturnBindings. inspector: "deny" opts out of shell-owned inspector batch streaming.

HostedMatchOverride<TGame> / HostedMatchOverrideContext

Advanced: inject a synthetic HostedMatchState for testing or inspector previews. createFrozenHostedMatchState(...) builds a read-only state. Used internally by the HostedInspector component in @openturn/inspector-ui.

createFrozenHostedMatchState(...)

Build a frozen state object from a snapshot and history. Used by the hosted replay inspector.

Dispatch errors

formatDispatchError(outcome, options?)

Map a rejected dispatch outcome to a user-facing string. Covers the common ProtocolErrorCodes (game_over, inactive_player, invalid_event, stale_revision, disconnected, …) out of the box and lets you override per-reason.
Resolution order: options.byReason[reason]options.byError[error] → built-in default → options.fallback ("That move was rejected.").

DispatchErrorLike / FormatDispatchErrorOptions

Hosted room UI

<HostedRoom>

Phase-routing component that handles the standard missing_backend / connecting / lobby / game / closed / error tree. Pass render functions per phase; defaults fall through to a shared fallback.
Only room, lobby, and game are required; everything else falls back to fallback or null. Use HostedRoom whenever a component renders a full hosted-room shell — it keeps the phase-branching logic out of your game UI.

HostedRoomProps<TGame, TPublicState, TResult>

Full prop shape — see the IDE hover for each slot.

Rooms with lobbies

HostedRoomState<TGame, TPublicState, TResult>

Returned by useRoom(). Phase-aware — a single shape covering connecting, lobby, live game, closed.

HostedRoomPhase

"idle" | "missing_backend" | "connecting" | "lobby" | "transitioning" | "game" | "closed" | "error".

Lobby

Opinionated lobby UI component. Pass it room.lobby. Hosted shells render their own invite-share affordance via the copyInvite shell control rather than embedding it inside the lobby UI.

useLobbyChannel(options)

Low-level lobby WebSocket hook. Use when building a custom lobby UI.

buildLobbyView(channel)

Turn a raw lobby channel into a LobbyView (the same shape useRoom() exposes).

LobbyChannelHandle / LobbyChannelStatus

The handle returned by useLobbyChannel and its connection status ("idle" | "connecting" | "connected" | "disconnected" | "error"). Use buildLobbyView(handle) to project into the same shape useRoom() exposes.

Shell integration

Advanced — for dev shells and outer hosts that need to observe the hosted match state rendered by an inner user-authored <Page> without threading it through the page’s tree.

<HostedMatchShellObserver>

Wrap the user’s subtree. Activates the observer channel so hosted match state is published into a shared WeakMap keyed by the game definition.

useShellHostedMatch(game)

Call from outside the wrapped subtree to read the observed HostedMatchState<TGame> | null. Null until the inner subtree mounts a hosted provider. Normal app code should reach for useMatch() or useRoom() instead — this hook is for shell wrappers only.
Generated by openturn dev to render the dev-shell inspector alongside the user page.

Re-exports

For convenience, @openturn/react re-exports common types from its dependencies:
  • From @openturn/client: HostedConnectionDescriptor, HostedDispatchOutcome, HostedSnapshot, ProtocolValue.
  • From @openturn/protocol: BatchApplied.
  • From @openturn/core: MatchInput.
  • From ./lobby: Lobby, useLobbyChannel, buildLobbyView, LobbyChannelHandle, LobbyChannelStatus, LobbyView.

See also