From 40fcf31faa24da2c65b0db842e2ce8e2711f9e05 Mon Sep 17 00:00:00 2001 From: Eric Wagoner Date: Tue, 22 Sep 2026 17:16:37 -0400 Subject: [PATCH] README: the hall, rooms, and the duel server Co-Authored-By: Claude Fable 5.1 --- README.md | 29 +++++++++++++++++++++++------ 1 file changed, 23 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index e88c63d..3f759bd 100644 --- a/README.md +++ b/README.md @@ -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/`