Room file API
@irtio/room defines the authoritative half of your game. A room file exports a
single defineRoom(schema, handlers).
Signature
function defineRoom<S>(schema: S, handlers: RoomHandlers<S>): Room<S>;
interface RoomHandlers<S> {
onJoin?(state: State<S>, ctx: Ctx): void;
onLeave?(state: State<S>, ctx: Ctx): void;
validate?: { [entity: string]: (prev, next, ctx) => Next | void };
rpc?: { [name: string]: (state, args, ctx) => unknown };
tick?(state: State<S>, dt: number, ctx: Ctx): void;
} Handlers
| Handler | Runs | Use for |
|---|---|---|
onJoin / onLeave | on membership change | create/remove entities |
validate.<entity> | before a client write is broadcast | clamp or reject |
rpc.<name> | when a client calls it | arbitrated actions |
tick | fixed rate on the server | continuous simulation |
The context object
interface Ctx {
clientId: string; // caller / joiner
meta: Record<string, unknown>;
env: Record<string, string>; // secrets & config, server-only
now: number; // deterministic clock (use instead of Date.now)
random(): number; // seeded RNG (use instead of Math.random)
kick(clientId: string, reason?: string): void;
broadcast(event: string, payload: unknown): void;
} Always read time from
ctx.nowand randomness fromctx.random()— that’s what makes simulated-player tests deterministic.
Ownership helpers
import { SERVER } from '@irtio/room';
state.match = { phase: 'lobby', owner: SERVER }; // server-owned
state.pieces[id].owner = ctx.clientId; // hand to a client Next steps
Placeholder reference.