For visitors: the landing shows a clip card of the maze before asking for a name; "Play now against a clockwork wizard" is one tap from the landing to the first turn (the room, the seat, and the flip each follow as the server confirms the last); pass-the-device and seat transfer fold behind "More ways to play". For a first game: automatons default to apprentice until this browser has seen a game through, then step up to adept unless the tier was picked by hand; the council speaks once unasked on a first turn; a finished game offers "play again" (the same bots re-seated in a fresh room) and "share the tale" (the whole replay as a link). For players who know the box: a House rulings tab in help — what the digital table does differently, every rulings revision (now exported from the engine as RULES_REVISIONS, which the deckRev doc block points at), and the 76 cards the FAQ has spoken on. And the arrow keys and WASD walk on the board as they already did in the first-person pane. The recorder's poster settle lengthens to outlast a change-of-eyes wipe; two cards had caught the title card instead of the maze. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Jm2auWk6RP71CjaAb4FMoG
Deploying Wiz-War
The game runs on a single DigitalOcean droplet: one Node process serves the built client and the websocket on port 8787; Caddy in front terminates TLS with automatic certificates. Room files persist in /var/lib/wizwar/rooms and survive deploys and reboots.
Current production
- Droplet:
wizwar(nyc3, s-1vcpu-1gb, tagwizwar), IP 104.236.96.198 - URLs: https://wizwar.kestrelsnest.social and https://wizwar.104.236.96.198.sslip.io (always works, zero DNS). Caddy serves both; NOTE: kestrelsnest.social's authoritative DNS is at HOVER (ns1/ns2.hover.com), not DigitalOcean — records must be added there. A matching record also sits in the DO zone in case nameservers ever move.
Everyday deploys
deploy/deploy.sh 104.236.96.198
Builds the client locally, rsyncs the repo (minus node_modules, data/, .git, research), installs dependencies on the droplet, and restarts the service. Games in progress survive: state lives in room files, and clients reconnect automatically.
Before any deploy that touches the engine, run the determinism gate:
deploy/verify-ledgers.sh 104.236.96.198
It fetches every production ledger and strictly replays it against the local engine; a single refused command fails the check. A room whose ledger no longer replays becomes unreachable after restart, so this is not optional.
New droplet from scratch
doctl compute droplet create wizwar --region nyc3 --size s-1vcpu-1gb \ --image ubuntu-24-04-x64 --ssh-keys <your-key-ids> --tag-name wizwar --waitscp deploy/setup-droplet.sh root@<ip>:/root/ && ssh root@<ip> \ "bash /root/setup-droplet.sh wizwar.<ip>.sslip.io"deploy/deploy.sh <ip>
Operations
- Logs:
ssh root@<ip> journalctl -u wizwar -f - Restart:
ssh root@<ip> systemctl restart wizwar - Nightly backups:
wizwar-backup.shruns from root's crontab at 07:17 UTC, pushing /var/lib/wizwar to thekestrel-wizwar-backupsSpace (nyc3) via rclone. It is installed at /usr/local/bin/wizwar-backup.sh on the droplet;setup-droplet.shdoes NOT install it — on a fresh droplet, copy the script, configure rclone (the script refuses to run while the config still holds its CHANGE_ME placeholder), and add the cron entry by hand. - One-off backup:
scp -r root@<ip>:/var/lib/wizwar/rooms ./rooms-backup