Skip to main content
@openturn/react wraps @openturn/core in a React-shaped API. One function turns a game definition into typed hooks: createOpenturnBindings. The same component runs unchanged across openturn dev (local development) and openturn-cloud (production). The runtime is declared once at bindings-creation time, and the provider auto-detects everything else.

One configuration, every environment

The provider is then zero-prop everywhere it appears:
That same expression runs locally under openturn dev and in production behind openturn-cloud — there is nothing to switch.

Local play

useMatch() returns a mode-discriminated MatchView<TGame>. Narrow on view.mode === "local" and read view.state for:
  • snapshot — the current game state. Subscribes the component to every state change.
  • dispatch — the typed dispatch map (dispatch.placeMark(playerID, args) is type-checked).
  • reset, lastBatch, replayData, status, game — lifecycle and metadata.
  • getPlayerView(playerID) — the view shaped for a specific seat (hidden-info safe).
The dispatch map is typed from your game’s events. Local mode passes playerID because the in-process session represents every seat. For local-runtime apps, the host shell (openturn dev locally, openturn-cloud in production) wraps your Page in <OpenturnProvider> automatically — your Page is a thin renderer of the experience, and any descendant can call useMatch().

Multiplayer play

Use useMatch when you only need the in-game UI (no lobby):
Differences from local:
  • dispatch.placeMark(args) does not take a player ID. The server knows who you are from the room token.
  • match.snapshot can be null until the initial sync.
  • match.status reflects the connection lifecycle (idle | connecting | connected | disconnected | error).
  • match.canDispatch.placeMark gates the button based on server-reported active players and result state.

Lobby + game together

When your app needs a lobby first, use useRoom instead of useMatch. It exposes the full HostedRoomState (phase, lobby, game, bridge, invite URL):
room.phase walks through idle → connecting → lobby → transitioning → game. See how-to: build a lobby.

Tests and Storybook

The provider’s optional match prop forces in-process mode with a fixture you control — useful for tests, Storybook, or a load-saved-game flow inside your dev shell. It overrides whatever the bindings declared:
Each call to createLocalMatch produces a fresh in-process store, so tests stay isolated.

A flagship reference app

examples/games/splendor/app is the production-polish reference for <OpenturnProvider> + useRoom against hosted multiplayer — 2–4 player variable seating, hidden per-player state through views.player, lobby with three difficulty-tiered bots, framer-motion animations, and a Tailwind v4 tabletop UI. It also ships a single-tab ?preview=local mode that mounts a no-lobby LocalPreview (both seats local, camera toggle in the header) so you can iterate on UI without a full lobby + websocket round-trip.