Skip to Content
SDK reference@plot/handler (ctx)
npm install -E @plot/handler

defineRoom

defineRoom<S, M = unknown>({ initialState: S, tickRate?: number, // 0–30 Hz; 0 disables onTick onCreate?(ctx), onJoin?(player, ctx), onMessage?(player, msg: M, ctx), onLeave?(player, ctx), onTick?(ctx), onTimer?(payload, ctx), })

player is { id: string; joinedAt: number }.

HandlerContext

MemberType / signatureNotes
ctx.stateSAuthoritative state; mutate freely.
ctx.roomCodestringThis room’s code.
ctx.appIdstringThe app this room belongs to.
ctx.regionstringThe region the room is running in.
ctx.playersPlayer[]Current players.
ctx.firstPlayerPlayer | undefinedConvenience.
ctx.broadcast(channel, data)voidSend to all.
ctx.sendTo(playerId, channel, data)voidSend to one.
ctx.kick(playerId, reason?)voidRemove a player.
ctx.profile.get/updateProfiles.
ctx.leaderboard(name).submit/top/aroundLeaderboards.
ctx.save.get/put/delete/listSave slots.
ctx.replay.enabled() / append(event)Replays.
ctx.assets.url(path)stringPublic immutable CDN URL, built offline. Assets.
ctx.assets.signedUrl(path, { ttl })Promise<string>Short-lived signed URL for a private asset.
ctx.assets.list(prefix?)Promise<AssetMeta[]>The app’s asset manifest.
ctx.ai.npc(id).say({ from, text })Promise<{ requestId }>Request an NPC line; arrives via onAiResult. AI NPCs.
ctx.ai.npc(id).forget(key?)Promise<void>Reset a conversation’s memory.
onAiResult(result, ctx)callbackRoom def callback: an NPC completion is ready.
ctx.scheduleTimer(payload, delayMs)stringDurable timer; returns id.
ctx.cancelTimer(id)voidCancel a timer.
ctx.rewindTo(targetTs, cb)Promise<T>Lag compensation.
ctx.log / warn / errorvoidStructured logging.

Execution model

Handlers run in an isolated tenant Worker (Workers for Platforms). The handler cannot call back into the room — every effect is expressed through ctx and applied by the platform after the call returns. This keeps tenant code sandboxed and lets the same handler run client-side for prediction.

Last updated on