README: the hall, rooms, and the duel server

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
Eric Wagoner
2026-09-22 17:16:37 -04:00
co-authored by Claude Fable 5.1
parent 605f8c511b
commit 40fcf31faa
+23 -6
View File
@@ -17,8 +17,12 @@ npm install
npm run dev
```
You duel a heuristic bot. Each turn, choose a gesture per hand, pick which completed spell
(if any) each hand casts and at whom, and reveal. The rules are at `/rules`.
The hall at `/` offers two ways in: play the bot at `/play`, or duel a person. A duel between
people has a four-letter room code; `/join/CODE` is both the invite link and the place it is
played. Turns are taken whenever each player has a moment, and the page refreshes itself when
the other wizard moves. An empty seat can be given to the bot. Each turn, choose a gesture per
hand, pick which completed spell (if any) each hand casts and at whom, and reveal. The rules
are at `/rules`.
Around the two hands:
@@ -31,9 +35,19 @@ Around the two hands:
knowing, and a one-time explanation when a rule decided something surprising;
- the full chronicle and the spell sheet in the sidebar.
The duel is saved to the browser's local storage after every change, so it survives reading
the rules, a refresh, or a phone putting the tab to sleep. Starting a new duel asks first if
one is under way. Nothing is rendered on the server.
A duel against the bot is saved to the browser's local storage after every change, so it
survives reading the rules, a refresh, or a phone putting the tab to sleep. Starting a new one
asks first if one is under way. The seats this browser holds at shared duels are remembered the
same way and listed in the hall with whose move it is. Nothing is rendered on the server.
## The duel server
`server/` is a small Node process, run from source with tsx (`npm run server` beside `npm run
dev`; Vite proxies `/api` and `/ws` to it). A room is an append-only ledger of seats and turns
in `data/rooms/CODE.jsonl`; the engine is deterministic given the seed and the recorded inputs,
so a restart replays every room. A turn resolves once every seat that must move has moved, bots
included, and each seat is sent a view filtered to what the rules let it see. The engine seats
two to four wizards; the interface is built for two.
## Layout
@@ -42,7 +56,10 @@ one is under way. Nothing is rendered on the server.
- `src/lib/game/state.ts` the duel's state and the seeded random source
- `src/lib/game/resolve.ts` simultaneous turn resolution
- `src/lib/game/bot.ts` the opponent
- `src/lib/game/duel.svelte.ts` reactive store binding the engine to the UI, saved to local storage
- `src/lib/game/duel.svelte.ts` reactive store binding the engine to the UI, for a local duel or a seat at a room
- `src/lib/game/client.ts` the browser's side of the duel server, and the seats it holds
- `src/lib/game/view.ts` what one seat may know
- `server/` the duel server: rooms, ledgers, the HTTP and WebSocket front door
- `src/lib/components/` the ledger, hand pickers, status panels, result strip, chronicle, spell sheet, and the sticky bar for phones
- `src/routes/rules/` the rules page, rendered from the spell book and the transcription in `docs/`