Skip to content

How it works

game page (room.js + game.js) --postMessage, private port--> relay.js (trusted page) --1 WebSocket--> hub (Node)
Part File Job
Hub src/hub.ts Rooms in memory, membership, host election and terms, change order, rates and sizes, data budgets, fan-out 20 times a second on a 10 ms sub-tick, restart hand-over. Pure logic: no sockets, injected clock.
Node adapter src/node.ts ws sockets to the hub, heartbeat, same-site check, one-time tickets, anonymous passes.
Relay client/relay.js Runs in the trusted page around the game (or in the game’s own window). Owns the socket: reconnects with jitter, tells the server when the tab is hidden, pings.
Room client client/room.js In the game page: state mirrors, sends own state at most 12 times a second (10 in rooms over 8 players), eases others’ movement, clock, actions.
Game shell client/game.js Game({...}): board fitting, input (keys, swipe, touch pad, held directions), no phone zoom on fast taps, tap-then-hold, pinch or long press, screens; with multiplayer the lobby, teams, invite link, notices and the host loop.

The game page never needs network access: it can run in <iframe sandbox="allow-scripts"> and still play, because the relay outside it holds the socket. The page never sees a ticket, a pass or an address.