Files
wizwar6e/deploy
Eric WagonerandClaude Fable 5.1 7223f8eb0d The reel slates a change of eyes and captions the wizard's state
Two things for a viewer who has never seen the game. When the reel's
pov passes to another wizard, the cut used to be instant — one wizard
apparently teleporting. Now a slate wipes across the pane: a dark band
sweeps in over the old sight, holds with the new wizard's standee and
THROUGH THE EYES OF <name>, and sweeps off to reveal theirs. It is an
FpFx ("slate") drawn by the renderer on the reel's own clock, so the
harness and the film see the same frames.

The caption grows a right-hand column: strides left to spend this turn
as a countdown, ♥ life, and chips for what the wizard carries,
displays, or suffers — a treasure, displayed cards, spells on them
with turns remaining, lost turns, banked Pass Wall, attack spent. The
save-video composite carries the same column.

All thirty scene goldens re-blessed: the caption is inside every
frame. The 3D panes are pixel-identical to the previous goldens.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Jm2auWk6RP71CjaAb4FMoG
2026-09-02 13:21:04 -04:00
..

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, tag wizwar), 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

  1. doctl compute droplet create wizwar --region nyc3 --size s-1vcpu-1gb \ --image ubuntu-24-04-x64 --ssh-keys <your-key-ids> --tag-name wizwar --wait
  2. scp deploy/setup-droplet.sh root@<ip>:/root/ && ssh root@<ip> \ "bash /root/setup-droplet.sh wizwar.<ip>.sslip.io"
  3. deploy/deploy.sh <ip>

Operations

  • Logs: ssh root@<ip> journalctl -u wizwar -f
  • Restart: ssh root@<ip> systemctl restart wizwar
  • Nightly backups: wizwar-backup.sh runs from root's crontab at 07:17 UTC, pushing /var/lib/wizwar to the kestrel-wizwar-backups Space (nyc3) via rclone. It is installed at /usr/local/bin/wizwar-backup.sh on the droplet; setup-droplet.sh does 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