20 Commits
Author SHA1 Message Date
Eric WagonerandClaude Fable 5.1 40fcf31faa README: the hall, rooms, and the duel server
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-22 17:16:37 -04:00
Eric WagonerandClaude Fable 5.1 605f8c511b Caddy routes the duel server's paths with handle blocks, from one template
try_files ran before reverse_proxy and rewrote /api to the shell; handle
blocks are exclusive. Both setup scripts render deploy/Caddyfile.tmpl.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-22 17:15:58 -04:00
Eric WagonerandClaude Fable 5.1 29e908efeb The server carries its own manifest and runs from its own folder
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-22 17:13:18 -04:00
Eric WagonerandClaude Fable 5.1 6369765378 Rooms are served by the fallback shell, not prerendered
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-22 17:12:11 -04:00
Eric WagonerandClaude Fable 5.1 6c6edca4be The hall comes first, in the shape of wizwar's landing
The home page is a centred card: title and pitch, your name, play the
bot or continue the duel under way, create or join a duel by code, a
sample ledger, the duels this browser holds with whose move it is, and
the story of the game. The single-player board lives at /play. The
droplet gains the duel server as a systemd service behind Caddy.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-22 17:11:45 -04:00
Eric WagonerandClaude Fable 5.1 e1bda87987 Duels between people: rooms, the hall, and a games ledger
The store plays any seat, locally against the bot or remotely through
the server. A room has a four-letter code that is also its invite link;
the hall opens or joins one and lists the seats this browser holds with
whose move it is. The ledger and summary show every seat, threats name
their wizard, and the board is one component shared by the hall and the
room page.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-22 17:07:51 -04:00
Eric WagonerandClaude Fable 5.1 8366c9d7ff A duel server: rooms, seat tokens, ledgers, and resolution when all have moved
Plain HTTP for actions and a websocket that only says "fetch again". A
room is its append-only ledger replayed from the top; the engine is
deterministic given the seed and the recorded inputs. Each seat sees a
view filtered to what the rules let it know. Bot seats are filled at
resolution time.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-22 16:54:29 -04:00
Eric WagonerandClaude Fable 5.1 95a1915cae The engine seats any number of wizards
Seats are a list on the state; a spell with no named target goes at the
first opponent still standing; a wizard who dies or surrenders is out
and their creatures go with them; the duel ends when one wizard stands,
or when a surrender and a death coincide, as the rules decide. The bot
attacks the weakest opponent and reads threats from all of them. The
two-seat duel is unchanged.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-22 16:50:50 -04:00
Eric WagonerandClaude Fable 5.1 cf58193aac Share card: three lines, pencil and paper kept
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-22 16:45:12 -04:00
Eric WagonerandClaude Fable 5.1 4211cbfe85 Share card: the blurb stays clear of the divider
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-22 16:44:08 -04:00
Eric WagonerandClaude Fable 5.1 81acbd2172 The target dropdown starts on the likeliest subject
One module decides where a spell most likely goes given the field (a
fireball at an ice elemental, charm monster at their strongest creature,
remove enchantment at the wizard only if enchanted); the bot and the
dropdown both use it. The dropdown lists that subject first and marks
creatures by whose they are.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-22 16:42:44 -04:00
Eric WagonerandClaude Fable 5.1 dd6ff93606 A counter-spell aimed at the other wizard is explained, and named when it blocks
Blocked blows now say what blocked them (shield, counter-spell, dispel
magic or protection from evil), the first counter-spell cast at the
other wizard earns a one-time explanation that it protects its subject,
and the spell's description says to cast it on yourself.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-22 16:41:25 -04:00
Eric WagonerandClaude Fable 5.1 5de352db43 Credibility pass: one conflict check, one hostile list, one set of chrome
Duplicated logic and styling that had drifted apart is unified: the
gesture-sharing check, the hostile spell list, the enchanted test, the
plan limits, and the shared button, link, field and disabled styles.
Dead plumbing is gone: the always-true implemented flag, the unread
cast length, an unreachable guard, an impossible time-stop condition,
the unused sequence formatter and utility class, the template
placeholder. The counter-spell tests now put a counter-spell in front
of a spell, the test helpers live in one file, and the resolver's
sections are numbered in order. The deploy script's cache headers now
do what its comment says, and the README describes the screen rather
than listing features in the order they arrived.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-22 16:37:54 -04:00
Eric WagonerandClaude Fable 5.1 527820ee95 A hand forced by amnesia or paralysis still casts what it completes
The default cast was chosen only when a gesture was clicked, so a hand
bound to repeat its last gesture finished its spell and let it pass.
Defaults are now chosen at the start of every turn.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-22 16:07:21 -04:00
Eric WagonerandClaude Fable 5.1 0036eaf625 On a phone, a reveal scrolls to what happened
The result strip comes into view with the last two ledger rows above it,
so the revealed gestures and their outcome are the first thing seen.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-22 16:02:26 -04:00
Eric WagonerandClaude Fable 5.1 3716f49bbb Players can choose their own name
An inline editor in the standfirst; the name is remembered in the
browser, applied to the current duel, and used for every duel after.
The opponent is drawn from the list avoiding the player's name.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-22 15:48:47 -04:00
Eric WagonerandClaude Fable 5.1 d40734590b Share previews: Open Graph and Twitter tags, a share card and a touch icon
The tags live in app.html because link scrapers do not run the client,
and the card and icon are rendered from the site's own palette and the
Spellcast snap silhouette.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-22 15:44:54 -04:00
Eric WagonerandClaude Fable 5.1 8bb708f1b2 Deploy notes: the game answers at hands.kestrelsnest.social
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-22 15:40:46 -04:00
Eric WagonerandClaude Fable 5.1 4d361198cd Record the production droplet in the deploy notes
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-22 15:39:50 -04:00
Eric WagonerandClaude Fable 5.1 865555e911 Waving Hands: a browser duel after Bartle's 1977 game
SvelteKit 5 single-player version against a heuristic bot. The engine
resolves all forty spells simultaneously as the rules describe, the
ledger of gestures is the interface, and the duel is saved in the
browser. Tester feedback rounds added per-hand planning, threat
evidence, a result strip with one-time rule explanations, a phone
layout and a structured rules page. Deploys as a static site behind
Caddy.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-22 15:33:29 -04:00