The Doozer Brainlive from the knowledge bundle · v2.2.697 · 2026-10-29 10:59 ETall pages · one page

Doozer Games rooms and relay (phones as touchpads)

systems/games-relay.md · System · doozer-games, zen-garden, relay, rooms, websocket, durable-objects, fail2ban, z1, z2

status: stable · written by claude-opus-5-5 on 2026-10-25 · stale after 2027-04-01

How a TV and up to four phones share a room on doozer.games. The code, the TV-authoritative message protocol, the interim long-poll relay on the origin, the Cloudflare Worker waiting to replace it, and the rules that keep it from ever being the server's load or getting a venue banned.

Doozer Games rooms and relay

Z1 and Z2 of Doozer Games, live in v2.2.656 (Oct 25 2026).

The loop

  1. A TV opens doozer.games/tv. It makes a room: a four letter code and a QR for
  2. doozer.games/<CODE> (the existing ?e=qr). Codes use BCDFGHJKMNPQRSTVWXZ: no vowels, so no words; no I, L, O, U or Y to misread. With nobody playing, four gardens rake themselves.

  3. A phone scans it, picks a nickname (a gentle default is filled in) and a color. No account.
  4. The phone becomes a touchpad for its own garden. One player gets the whole TV, two split it,
  5. three or four get a quarter each; an open garden keeps raking. A fifth phone is told all four gardens are in use. A taken color or a repeated nickname ("Moss 2") is adjusted and the player is told. Away for two minutes, the garden opens up again.

The code on the screen is the only way in. It is never published anywhere else (not on The One, not in a sitemap). /tv, /join and /<CODE> are noindex and the landing links /tv nofollow. robots.txt disallows /tv, /join and the relay. GOTCHA (fixed v2.2.659): index.php answers /robots.txt and /sitemap.xml for every host first; doozer.games and doozer.shop are now handed to their own includes there, so edit those, not the generic branch. Cloudflare caches robots.txt. The room cap counts only TVs heard in the last minute, so a crawler that opens /tv and leaves cannot keep a venue waiting.

Files

File What
includes/doozer-zen.php the garden; $zenRoom (route /tv) adds the room: players, Hand, labels, join card
includes/doozer-pad.php the phone: code entry (/join), join screen, touchpad, tray, minimap
assets/js/doozer-relay.js DZRelay.tv() / DZRelay.phone(), both carriers behind one API
games-relay.php + includes/games-relay.php the interim relay, a root file Apache runs directly
cloudflare/games-relay/ the Worker + Durable Object (not deployed until Jon connects Cloudflare)
game_rooms one row per room: code, live_code (unique while live), game, business_id (Z3), state, joins, players_peak. Never who played.

The protocol: the TV is authoritative

Phones send intent only, allowlisted and re-encoded by the relay: h {s: [[x, y, down, dt]...]} (hand samples, 0..10000 across the garden), tool, lift, spawn, rot, smooth, hello, leave; for the menu and Town Trivia, pick {g}, town {id}, start, again, ans {a}. join is written by the relay, never by a phone. The TV answers with welcome (garden, color, deduped nickname, hand), state (that garden's objects for the phone's minimap, 4/s at most), tick (lift/set, for haptics), hand (a new stone landed beside you: move onto it), full, who (the TV reloaded: join again).

The phone owns its hand position (a relative touchpad with mild acceleration, like a laptop's): slide moves, hold 220 ms then slide presses (rake or push), hold still 560 ms on a stone lifts it. The press sample must be sent the moment the press begins, before any slide: the TV only lifts from a press it has seen, and a lift that arrives first is ignored (found in testing: the stone was pushed instead). The TV plays each hand back through a 90 ms jitter buffer keyed by the phone's own sample spacing, so strokes keep their shape over a bumpy network, and catches up if it falls more than 420 ms behind.

Two carriers, one API

Rules that keep it safe (each one learned)

Checking it

curl -H "X-Dev-Token: …" https://doozer.work/games-relay.php?stats=1 (or through doozer.games): live rooms, the week's counts, caps; ?stats=1&relay=off|on is the switch; &sweep=1 sweeps. In a TV's console, dzZenRoom() shows the carrier and who sits where. Verify by LOOKING: headless Chrome over the DevTools protocol, a TV tab and real phone tabs driven with Input.dispatchMouseEvent, screenshots of the TV (the harness lives in the session scratchpad; rebuild it from this description).

Related: The 521 Root Cause, Shortlinks and QR, Doozer Games and Doozer Shop.

← Doozer Digest (AI daily newsletter)Doozer Town and the Board Game view →