# Arena — real-time multiplayer sumo (★★★)

Build a real-time multiplayer game that friends join with a four-letter room code. Up to eight players are discs on a round platform. You steer with the keys or a thumb joystick and dash with a button. Bump other players off the edge. The platform shrinks over time, and the last one standing wins the round. One Cloudflare Durable Object per room runs the game: it holds the state, talks to every phone over WebSockets, and steps the physics 20 times a second, so the server decides what happened and nobody can cheat by editing their own copy. Extra people can watch as spectators. If a phone drops off Wi-Fi for a moment, it reconnects and keeps its place.

## Done looks like

- The home screen has "Create room" and "Join" with a code box. Creating a room shows a code like `KTVM` and a share link `/?room=KTVM`.
- Up to 8 players per room, each with a name (up to 12 letters or digits) and a colour. A ninth person joins as a spectator and sees the game but cannot move.
- Controls: arrow keys or WASD and Space to dash on a laptop. On a phone, drag on the left half for a joystick and tap a dash button on the right. Dash has a 2 second cooldown shown on the button.
- The server runs the game at 20 ticks per second. Players have momentum and push each other. Falling off the edge eliminates you for the round.
- The platform radius shrinks steadily after 20 seconds. Last player standing wins. A scoreboard counts round wins. A new round starts 5 seconds later.
- Other players move smoothly on screen, not in jumps, even though the server only sends 20 updates a second.
- A debug overlay (press F3) shows ping, server tick, players connected and snapshot age.
- Pull a phone off Wi-Fi for 5 seconds: it reconnects and the player is still in the game.
- An empty room stops ticking. It is cleaned up after 10 minutes with nobody in it.
- Live at the address `npx wrangler deploy` prints, on the Cloudflare free plan.

## Constraints

- One Cloudflare Worker with static assets, plus a Durable Object class `Room` (SQLite-backed, which is what the free plan offers). Use wrangler.
- Routes: `POST /api/rooms` makes a new code and returns it. `GET /ws/<code>` upgrades to a WebSocket and is forwarded to the `Room` named by the code (`idFromName(code)`).
- Room codes: 4 letters from `BCDFGHJKMNPQRSTVWXZ` (consonants only, so no rude words and no lookalikes).
- Server authority: clients send only inputs, `{"t":"in","seq":n,"x":-1..1,"y":-1..1,"dash":bool}`, at most 30 a second and only when they change. The room keeps the latest input per player, steps physics every 50 ms, and broadcasts `{"t":"st","tick":n,"ring":r,"p":[[id,x,y,vx,vy,alive],...]}`.
- Clients draw other players about 100 ms in the past, interpolating between the two snapshots around that time.
- On join the server gives each player a random token, kept in `sessionStorage`. Reconnect with backoff (0.5, 1, 2, 4 seconds, then every 5). The room keeps a disconnected player's slot for 15 seconds.
- Stop the tick loop when nobody is connected, so an empty room does not use your free allowance.
- Validate every message on the server: right shape, numbers in range, names cleaned. Drop anything else. Close a socket that sends more than 60 messages a second.
- Canvas 2D for drawing. No game engine, no frameworks, no build step for the front end.
- No accounts, no tracking. Phone works.

## Milestones

1. **The game, offline.** Single-player version in the browser: the platform, your disc with momentum, dash with cooldown, falling off, three dumb bots that drift around. Keyboard and phone joystick.
   Check: on a phone you can steer with your thumb, dash into a bot and knock it off the edge.
> Milestone 1 is a game you can play on your own. Everything after it is the server that lets friends play together, which is the point of this project.
2. **Room and socket.** The Worker, the `Room` Durable Object and the two routes. Each socket gets a hello message and the room broadcasts how many sockets are connected.
   Check: open the room link in three tabs; each tab shows "3 connected", and closing one makes the others show 2.
3. **Lobby.** Join with a name. A player list with colours. Up to 8 players, the rest become spectators.
   Check: with nine tabs open, eight are players in the list and the ninth says "Watching".
4. **Server-run game.** Move the physics from milestone 1 into the room. Clients send inputs and draw snapshots straight away, with no smoothing yet.
   Check: two browsers in one room can push each other off, and both screens agree on who fell.
5. **Smooth movement.** Interpolation 100 ms in the past and the debug overlay.
   Check: other players glide instead of stepping, and the overlay shows 20 ticks a second and a ping number.
6. **Rounds.** Shrinking ring, eliminations, last one standing, round wins, countdown to the next round.
   Check: a full round plays out on its own: the ring shrinks, the winner's name shows, a new round starts after 5 seconds.
7. **Reconnect, cleanup, bots.** Tokens and reconnect with backoff. Stop ticking when empty, clean up after 10 minutes. A `bots.mjs` script (Node 22 has `WebSocket` built in) that joins a room with N bots pressing random inputs.
   Check: `node bots.mjs KTVM 7` fills the room to 8 with you; turn your phone's Wi-Fi off for 5 seconds and on again, and you are back in the same game.
8. **Go live.** Deploy. Play a real game with friends on their own phones on mobile data.
   Check: three people on three different networks finish a round, and nobody sees other players jump or freeze.

## Stretch

- Client prediction for your own disc: apply your input at once, then correct towards the server snapshot using `seq`.
- A tag mode: one player is "it", touching passes it on, whoever is "it" the least time wins.
- Power-ups that spawn on the platform: heavy (harder to push), bouncy, speed.
- Sound with Web Audio for bumps, dashes and falls.
- Room settings for the creator: ring speed, round count, private room that hides the share link.
- Quick emotes (a few fixed words, no free text chat).

## Leave out

- Accounts, global leaderboards, matchmaking between strangers.
- Free text chat.
- Anti-cheat beyond server authority and message checks.
- Game engines, Phaser, frameworks.

Start by reading WRITING.md and the guide chapter on data if you need storage.
