Skip to main content
This tutorial builds a React client with the typed HappyOyster SDK. By the end, the app can:
  • open an Adventure or Directing session
  • create a world and show build progress
  • save and reattach a world
  • stream the live world into a video element
  • expose controls appropriate to the selected experience
For a complete project, see the HappyOyster example.

Install the SDK

The package exports the plain client at @reactor-models/happy-oyster and React bindings at @reactor-models/happy-oyster/react.

Mint a client token

Keep the Reactor API key on your server. Exchange it for a short-lived JWT and return only the JWT to the browser:
Use a resolver in the client so the SDK can request a fresh token for later Reactor API calls. A session can only be operated by the exact token that created it, so the resolver memoizes the token itself and only re-mints once it’s close to expiring — re-minting on every call would hand a later call a fresh token with no sessions bound to it, and it 403s. See Authentication for the full pattern:

Mount the provider

The mode belongs on the provider, not on createWorld(). Use "adventure" for movement controls or "directing" for text steering:
The provider owns one client for its lifetime. To switch from Adventure to Directing, remount it:

Create a world

createWorld() accepts parameters for the provider’s mode and resolves when the world reaches ready.
Adventure parameters:
Directing parameters:
The client mode determines which parameter set is valid. createWorld() does not take a mode field.

Reopen a saved world

Worlds persist beyond a session. Reopen one by its encrypted id:
The world must belong to the provider’s selected mode. Attach an Adventure world through an Adventure provider and a Directing world through a Directing provider.

Start and stop a travel

Mount <HappyOysterVideo /> before starting. Once the current world is ready:
endTravelSession() ends the live travel but keeps the Reactor session and world ready. disconnect() closes the session; the world remains available for a later attachWorld().

Show the remaining travel time

An Adventure travel runs for up to 2 minutes, and the platform ends the stream when that budget runs out. The hook reports the granted length as maxExperienceTimeSec. Count down from it, with ADVENTURE_MAX_EXPERIENCE_SEC covering the render before a travel is open:
A Directing travel runs for up to 3 minutes and reports maxExperienceTimeSec as null. Count its clock down from that length and call endTravelSession() when it reaches zero.

Add Adventure controls

Adventure input is held state. Call move, look, or interact when an input begins, then release the corresponding axis when it ends:
The SDK maintains the resend cadence required for held controls. Send transitions instead of sending commands every animation frame.

Add Directing controls

Directing uses text instructions and playback controls:
Instructions and chapters arrive in the authoritative travel snapshot:
Use useHappyOysterTravelStatus() to track whether a Directing travel is running, paused, or completed.

Handle errors

Awaited setup calls reject on failure. Gate and upstream failures use HappyOysterActionError:
Useful codes include: Runtime stream errors are available through useHappyOysterTravelError().

Next steps