@flayerlabs/gamemode-client
v0.9.1
Published
Browser and mock-room client for Flaunch Game Modes
Readme
@flayerlabs/gamemode-client
Use the SDK room while building offline or connecting a browser to a live Game Mode gate.
Requirements
Install the package with Node.js 20 or later:
pnpm add @flayerlabs/gamemode-client @flayerlabs/gamemode-specThe package runs in the browser. It has no React dependency.
Build against the offline room
Pass your real rules and config to createMockRoom. This example uses the number game created by
the Game Mode CLI:
import { createMockRoom } from '@flayerlabs/gamemode-client'
import { rules, type Action, type Config } from './game/rules.js'
const config: Config = {
rounds: 3,
ceiling: 10,
points: 500,
roundMs: 10_000,
}
const room = createMockRoom(rules, { config })
const unsubscribe = room.subscribe(({ publicView, playerView }) => {
console.log({ publicView, playerView })
})
await room.send({ guess: 7 } satisfies Action)The mock drives the same rules module as a live gate. It replaces only the network, wallet, chain
and real spending. Call unsubscribe(), then room.dispose() when the game closes.
Join from an embedded game
An embedded game first receives its context and restricted host services from the trusted parent:
import { connectHost, joinRoom } from '@flayerlabs/gamemode-client'
const embedded = await connectHost()
if (!embedded) throw new Error('open this game from its coin page')
const room = await joinRoom({
gateUrl: embedded.context.gateUrl,
roundId: embedded.context.roundId,
launch: embedded.context.launch,
host: embedded.host,
})Creator code sends game actions and reads room state. It cannot send a wallet transaction or create
Flaunch calldata. The trusted parent uses attachGameHost to provide the permitted wallet,
market and identity operations to one known iframe.
Buy calls default to a two-minute deadline, including wallet interaction. Configure buyTimeoutMs
on connectHost(), joinRoom() / joinEconomy() and the parent's attachGameHost() if needed.
A timeout returns try-again with diagnostic detail: 'buy-timeout' and any submitted transaction
hash. It clears the local buy lock, but does not undo a transaction; the allowance it drew on is
unchanged until the chain shows spend.
See the buy completion guidance.
Call room.dispose() and embedded.dispose() when the iframe closes. Outstanding buy waits settle
on disposal.
Every gm:hello the game sends names the client version it was built with, and embedded.sdk is
the same version as @flayerlabs/gamemode-client@<version>. The package also exports
CLIENT_VERSION and CLIENT_MARKER for diagnostics. The marker is a literal in every built game,
which is how the Flaunch dashboard confirms an uploaded build runs a current SDK. On the parent
side, attachGameHost({ onGameSdkVersion }) receives the reported version, or null from a game
built with a client older than 0.5.5.
Connect a game with its own server
Use joinEconomy() when your existing server owns gameplay and scoring:
import { connectHost, joinEconomy } from '@flayerlabs/gamemode-client'
const embedded = await connectHost()
if (!embedded) throw new Error('open this game from its coin page')
const gameMode = await joinEconomy({
gateUrl: embedded.context.gateUrl,
roundId: embedded.context.roundId,
launch: embedded.context.launch,
host: embedded.host,
})
const stop = gameMode.economy.subscribe(renderAllowance)
const { ticket } = await gameMode.joinTicket()
const socket = new WebSocket('wss://gate.example/game/live')
socket.addEventListener('open', () => {
socket.send(JSON.stringify({ type: 'join', ticket }))
})joinEconomy() signs the player into the SDK gate and provides launch and spending capabilities.
It does not send gameplay to your server or let the browser add points. Your game server must
verify the short-lived join ticket, run authoritative gameplay and use the gate's internal award
route.
The default ticket audience is the gate origin. Pass an explicitly registered game-server origin to
joinTicket() when the socket runs on another origin. On the platform gate Flaunch runs, your
server always has its own origin: list it in gamemode.json under server.origins and pass it
here. GET /rounds/:id on the gate answers the round's gameServerOrigins. Send the ticket in the first socket
message, not in the URL. It proves the wallet without exposing the SDK gate session or the server's
award token.
Call stop(), gameMode.dispose() and embedded.dispose() when the iframe closes.
Use room capabilities
Room provides:
subscribefor public and player-specific game viewssendfor proposed game actionsnowfor the server-corrected clocklaunchfor fixed launch detailstermsfor the round's fixed point ceiling, wallet cap, point rate and dollar pricingeconomyfor earned, spent and available allowancemarketandidentityfor data supplied by the trusted parentpresenceandsocialfor connected-player counts and cosmetic reactions
EconomyRoom provides the same launch, terms, connection, economy, market, identity, presence and
social capabilities, plus joinTicket() for a creator game server. It leaves out gameplay views and
send().
Use replayMarket
to build market presentation without a live chain.
Integrate the trusted parent
Read the trusted platform integration guide
before implementing attachGameHost, Host or a production joinRoom call.
The quiz example shows a live rules room. The external-server example shows two browser players connecting to a creator WebSocket and receiving allowance through the authenticated awards route.
The generated game source shows the offline room.
See what changed
This package ships CHANGELOG.md and MIGRATING.md, shared by all four Game Mode packages. Read
them on GitHub: changelog and
migration guide.
