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.