@fusiondevstudio/dinosaur-sdk
v0.1.0
Published
The platform contract for building games on Dinosaur — a free, open-source, self-hosted platform for tiny multiplayer party games.
Maintainers
Readme
@fusiondevstudio/dinosaur-sdk
The platform contract for building games on Dinosaur — a free, open-source, self-hosted platform for tiny multiplayer party games.
A Dinosaur game is small: a state machine on the server, a few React screens on the client, and prefixed wire messages. The platform owns everything universal — rooms and invite codes, reconnect grace, host transfer/kick, snapshot rehydration, leaderboards, reactions, voice, feedback — and this package is the only surface a game touches. The platform can refactor freely behind it.
Entry points
| Import | What you get |
| --- | --- |
| @fusiondevstudio/dinosaur-sdk | Shared protocol types: PlatformSnapshot, PublicPlayer, LeaderboardEntry, GameResultRow, platform constants |
| @fusiondevstudio/dinosaur-sdk/server | BaseGameEngine, GameModule, PlatformEngineDeps, broadcast helpers, Player |
| @fusiondevstudio/dinosaur-sdk/client | createGameClient, usePlatformStore, send, feedback + sounds, shared hooks, cross-game UI primitives (PlayerRoster, Leaderboard, JoinQR, …) |
A game in three pieces
Server — extend the engine base and expose a module:
import { BaseGameEngine, type GameModule, type InboundMessage } from "@fusiondevstudio/dinosaur-sdk/server";
class TapRaceEngine extends BaseGameEngine<TapRaceGameState> {
protected buildGameState(forPlayerId: string): TapRaceGameState { /* … */ }
protected handleGameMessage(playerId: string, msg: InboundMessage): void { /* … */ }
}
export const tapRaceModule: GameModule = {
id: "tap-race",
displayName: "Tap Race",
describe: () => ["tap-race: ready"],
createEngine: (deps) => new TapRaceEngine("tap-race", deps.leaderboard),
};Client — a zustand store with applyGameState + reset, wrapped by the
factory that enforces the platform's reconnect contract:
import { createGameClient } from "@fusiondevstudio/dinosaur-sdk/client";
export const tapRaceClient = createGameClient<TapRaceGameState>({
id: "tap-race",
displayName: "Tap Race",
GameView,
store: useTapRaceStore,
handleServerMessage,
});Wire messages — always prefixed (tr:*), sent with send() from
@fusiondevstudio/dinosaur-sdk/client; durable state always travels on the snapshot, never in
ad-hoc messages, so reconnects rehydrate for free.
The contract that matters
The server's snapshot is the single source of truth. On every welcome and
state:sync the platform hands your game its slice via applyGameState;
after that call returns, your UI must reflect the snapshot exactly. The
createGameClient factory makes this structurally hard to get wrong (it
requires onSnapshot/onReset to be symmetric).
Building a full game
Start from the platform repo's building-games guide, or scaffold a complete runnable game with the CLI:
dinosaur new-game tap-race --name "Tap Race"
dinosaur dev --games .Server-side games are typed against Node and ws; have @types/node in your
devDependencies (ws types ship with the SDK).
License
MIT
