100 Commits
Author SHA1 Message Date
Eric WagonerandClaude Fable 5 0d2b25ad74 Go Away routs 'as straight a line as possible' (rules rev 36)
The card's line bends: a victim shoved against a wall moved zero
squares and just lost the turn, because GO AWAY borrowed waterbolt's
straight-line knockback. Its own rout now holds the heading while open,
bends around walls, sidesteps when no ground can be gained, rolls the
D4 only when options tie, and stops early only when truly cornered.
Waterbolt's physical shove stays straight, as a shove should. Ledgers
verified before deploy.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0138A8CjeQRpvzKxuMfz1Bqc
2026-08-20 11:15:19 -04:00
Eric WagonerandClaude Fable 5 76dd019d5d Ambushed teleports carry their destination; room 59UN unstuck (rev 35)
An ambush springing TELEPORT OPPONENT opened a stack with params null —
the spring bypasses cast validation and nothing ever asked where the
victim goes — and resolution crashed on the missing cell, wedging the
room 'waiting on Automaton'. Three layers:
- Crash guards: teleport-opponent and mental-force fizzle gracefully on
  a destination-less stack (ungated: no stored command had resolved one).
- The trap commits its destination when laid: setAmbush carries a cell
  ('wherever you say', said in advance), the spring passes it into the
  stack, and the client's arming flow asks for the click.
- Rev 35 refuses arming those spells without a destination; older
  ledgers armed blind and their springs fizzle.
All ledgers verified before deploy.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0138A8CjeQRpvzKxuMfz1Bqc
2026-08-20 10:51:16 -04:00
Eric WagonerandClaude Fable 5 e8c25ddc19 Stone Dead counts only the stones in play (rules rev 34)
Same reading as fireball's rev 33: 'carrying' means displayed. Counting
hidden hand stones both inflated the damage and broadcast the secret
count in the total. The automatons' estimate (displayed as the visible
floor) is now simply the truth. All production ledgers verified clean
before deploy.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0138A8CjeQRpvzKxuMfz1Bqc
2026-08-19 22:22:45 -04:00
Eric WagonerandClaude Fable 5 b67f2a4c8a Fireball burns only the stones in play (rules rev 33)
'Destroys all magical stones an opponent is CARRYING' — the owner's
ruling: a stone hidden in the hand is a secret card, not a carried
stone. Only displayed stones burn; the old all-hand burning also leaked
hidden information by announcing cards nobody knew existed. Earlier
games replay their broader fire. All 42 production ledgers verified
before deploy.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0138A8CjeQRpvzKxuMfz1Bqc
2026-08-19 22:19:20 -04:00
Eric WagonerandClaude Fable 5 1cf5d0a68d The determinism harness moves into deploy/ for real
deploy/verify-ledgers.sh fetches every production ledger and strictly
replays it against the local engine (any refusal or crash fails; a
lobby that never dealt is trivially clean). Run from the repo root
before deploying engine changes — the check both of tonight's replay
breaks would have caught.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0138A8CjeQRpvzKxuMfz1Bqc
2026-08-19 22:06:56 -04:00
Eric WagonerandClaude Fable 5 c87b8cb28d Hotfix: the wrap gains its vintage gate; every ledger verified
Same lesson twice in one night: the toroidal dread applied at every rev
and QD3S (recorded flat) refused seq 76 again on restore. rev >= 32
wraps; older vintages measure the flat diamond they were played under.
This time verified properly: a strict replay harness (any refused
command is a hard failure) ran all 41 production ledgers against the
new engine before deploy — 0 failures. That harness now lives in the
repo as the pre-deploy determinism check it always should have been.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0138A8CjeQRpvzKxuMfz1Bqc
2026-08-19 22:03:21 -04:00
Eric WagonerandClaude Fable 5 0a0108c48c The dread wraps: fear's diamond continues from the opposite rim
The maze is a torus — a wizard walking through walls off one edge
arrives at the other, so the crow flies around the wrap too.
dreadDistance measures toroidal manhattan; the aura's wash wraps with
it. No rev-32 game has cast fear yet, so the measure corrects in
place; older vintages replay flat as they were played.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0138A8CjeQRpvzKxuMfz1Bqc
2026-08-19 22:00:29 -04:00
Eric WagonerandClaude Fable 5 bcd2155fe0 IDIOT's duty spelled out, like FEAR's
The engine already steers every step and bars items, attacks, and
non-aiding casts; the one honor-bound piece is spending the movement at
all. The afflicted now see the card's demand in an urgent slip the
moment their turn opens, matching the FEAR pattern: bots comply
mechanically, humans get the words.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0138A8CjeQRpvzKxuMfz1Bqc
2026-08-19 21:53:01 -04:00
Eric WagonerandClaude Fable 5 6ec9d6ab55 FEAR's rout: bots flee it, humans are told their duty
'Players or monsters must move away from you on their turn if within
range, if they can.' Automatons caught in the dread now spend their
legs escaping before any other marching — the step that most increases
distance, a true dead end excusing them per the card. Humans keep their
freedom but get the compulsion spelled out in an urgent slip (move
away, even by card or through danger; only a dead end excuses you),
with the maze trusting the table to honor it — the owner's chosen
depth of enforcement.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0138A8CjeQRpvzKxuMfz1Bqc
2026-08-19 21:51:22 -04:00
Eric WagonerandClaude Fable 5 fdb44ab09f Fear measures as the card says: through walls, never diagonal, no warps
The FAQ is exact: 'The 3 spaces away is measured as a Wizard walks (if
he could walk through walls), not diagonally' — manhattan, at every
vintage. The walking-distance detour is reverted (no rev-32 ledger ever
recorded under it); the rev-32 gains stand: monsters, warp-steps, and
teleports all honor the dread. The aura returns to the true diamond,
now as a wash on its member squares.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0138A8CjeQRpvzKxuMfz1Bqc
2026-08-19 21:46:44 -04:00
Eric WagonerandClaude Fable 5 724d178636 Hotfix: fear's new metric leaked into old vintages and broke replay
QD3S failed to restore ('replay failed at seq 76: an unnatural dread
keeps you away'): the walkingDistance switch ran at every rev, refusing
a move that was legal under the crow-flies rule when it was played.
fearRepels now measures walked spaces at rev 32+ and as the crow flies
below, so every stored ledger replays its own vintage. No data was
lost; the room's ledger was intact throughout.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0138A8CjeQRpvzKxuMfz1Bqc
2026-08-19 21:40:48 -04:00
Eric WagonerandClaude Fable 5 410ebc0135 Fear's spaces are walked, not flown — warps carry the dread
The owner caught the metric: a wizard eight squares away as the crow
flies stood three WALKED spaces away through a warp, and the manhattan
check waved it through (while falsely blocking approaches manhattan-
near through solid walls). fearRepels now measures walkingDistance —
the same BFS the maze walks, warps included, walls respected. The
board's aura follows suit: the diamond becomes a violet wash on every
square within three walked spaces, computed by the same BFS, warp
mouths included. No rev-32 ledger existed yet, so the metric corrects
inside rev 32.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0138A8CjeQRpvzKxuMfz1Bqc
2026-08-19 21:34:15 -04:00
Eric WagonerandClaude Fable 5 644d651ae0 Fear wears its bubble: a breathing dashed diamond at three spaces
The dread was invisible, so a wizard legally circling at four squares
read as a rules failure (QD3S: no wizard ever actually breached the
bubble — only the monster, fixed at rev 32). Every feared player now
radiates a manhattan-3 diamond, dashed violet, breathing slowly; what
the engine refuses, the board now shows.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0138A8CjeQRpvzKxuMfz1Bqc
2026-08-19 21:29:31 -04:00
Eric WagonerandClaude Fable 5 0e9d482495 Fear repels every willing step (rules rev 32)
Room QD3S: Kestrel cast Fear and a Democratic Monster warp-stepped from
eight squares away to ONE — moveCreature never knew the card existed.
'No player or monster will move to within 3 spaces of you' now guards
every willing move: walking wizards (as before), commanded monsters
(walks, wall-passes, and warp mouths alike), dimensional warp-steps,
and self-teleports. Forced movement — knockback, waves, Mental Force,
Teleport Opponent — is not willing, and still throws you anywhere.
The shared fearRepels helper replaces the inline wizard-only check.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0138A8CjeQRpvzKxuMfz1Bqc
2026-08-19 21:23:47 -04:00
Eric WagonerandClaude Fable 5 172fbc6ff8 Marching the Democratic Monster onto yourself takes two taps
Its card claws WHOEVER's square it enters, mover included — the owner
learned this standing beside a troll it could not touch. The client now
warns on the first tap ('it will claw YOU') and commits on the second;
no warning when its round's claw is already spent, when the walk is
safe.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0138A8CjeQRpvzKxuMfz1Bqc
2026-08-19 20:39:42 -04:00
Eric WagonerandClaude Fable 5 75d3d44c6c The Ward is played in the moment (rules rev 31)
'When a player picks up one of your treasures, you may play at that
time (out of turn) this card on him' — the owner read the card and is
right: no arming ahead. When a treasure whose owner holds WARD is
grabbed, the grab hangs (new wardPending phase, outranking all other
input) and the owner alone answers: spring it (3 damage, card spent)
or let them go (card kept, silence). Automatons always spring it on a
thief of their gold. The arming mechanic is refused at rev 31 and its
button hidden; rev 3-30 games keep their armed wards and rev 1-2 keep
the automatic spring, replaying unchanged. The window does reveal that
the owner holds SOMETHING - as it would at any real table when the
room turns to look at them.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0138A8CjeQRpvzKxuMfz1Bqc
2026-08-19 20:17:43 -04:00
Eric WagonerandClaude Fable 5 b7f93fe454 Name and color join the preferences
Your wizard's name pre-fills the lobby (and is remembered whenever you
create or join), and a preferred color — six swatches in the slip, tap
again for none — is claimed quietly in any lobby where it is free and
you have not chosen. First-come still wins a contested color; the
preference never bumps anyone.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0138A8CjeQRpvzKxuMfz1Bqc
2026-08-19 18:53:44 -04:00
Eric WagonerandClaude Fable 5 62c4680d1f The fallen drop what they carry, however they fall (rev 30)
A wizard eliminated by treasuresLost took any carried treasure into the
void with them — the killed path drops it, but checkVictory's branch
never did. At rev 30 the treasure lands where they stood, with the
usual treasureDropped event (onHomeOf included, so a capture completed
by the falling is honored in the same breath). Stored games replay the
vanishing unchanged.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0138A8CjeQRpvzKxuMfz1Bqc
2026-08-19 12:25:41 -04:00
Eric WagonerandClaude Fable 5 f1743e6fe5 Modal ink: .attack-title and pref rows stop inheriting the table's cream
'Preferences', 'Token art', and the checkbox labels were cream on cream
- .attack-title never had a color rule, so modals inherited the dark
table's pale text. Explicit dark ink; the illusion-test modal shared
the class and heals with it.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0138A8CjeQRpvzKxuMfz1Bqc
2026-08-19 10:05:07 -04:00
Eric WagonerandClaude Fable 5 6aae40ad5f Player preferences: art set, auto-grab, flourishes
A ⚙ preferences slip in the masthead, saved to this device:
- Token art, all or nothing: the photographed cardboard or the
  hand-drawn vectors (the workshop's per-category query params stay as
  the undocumented editing override).
- Ending a turn on a lone grabbable treasure picks it up on the way
  out — never on your own home, never when two share the square.
- Spell flourishes on or off, honored by the live board and the
  replay reel alike (trap notices still fire; they are information).
Preferences change what you see or what routine commands the client
sends for you — never what is legal.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0138A8CjeQRpvzKxuMfz1Bqc
2026-08-19 09:45:12 -04:00
Eric WagonerandClaude Fable 5 5310fbdca9 No movement number is spent on a turn that ends at a grab
Room M9QJ, seq 190: a berserker played a 5 to charge a distant enemy,
walked two squares, crossed a treasure, and the gold-underfoot rung —
which outranks everything — ended its actions with six paid moves
unwalked. Before spending a number, the march now checks whether any
goal treasure lies within the free legs: if the turn is going to end at
a grab, the number stays in hand. (Even a charging berserker stoops
for loot; it just shouldn't pay toll first.)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0138A8CjeQRpvzKxuMfz1Bqc
2026-08-18 16:50:17 -04:00
Eric WagonerandClaude Fable 5 63e8d4c545 Mental Force becomes castable: the destination step it never got
The card prints no LOS and the engine asks none — but the client never
offered the two-step flow (click the victim, then click where they go),
so every cast arrived without a destination and was refused. It joins
teleport-opponent and shift-wand in the destination gate, with a hint
naming the three-space walk limit and the no-sight freedom.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0138A8CjeQRpvzKxuMfz1Bqc
2026-08-18 16:21:09 -04:00
Eric WagonerandClaude Fable 5 4720ec25ff A bare wand lights a single charge
'ANY CARD MAY BE PLAYED WITHOUT A NUMBER CARD, but its power is only 1.'
The wand first-use gate was the engine's one remaining missing-number
refusal — everything else already defaults its power to 1. A wand cast
bare now charges to one, fires once, and crumbles; the client hint says
so. Ungated: the refused casts never reached a ledger.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0138A8CjeQRpvzKxuMfz1Bqc
2026-08-18 10:47:05 -04:00
Eric WagonerandClaude Fable 5 1e5b7ee985 The game's own vocabulary: 'points' for segments, 'life-points' for the living
Wiz-War never says hitpoints. Walls and doors quote the rulebook's own
phrasing ('20 points to destroy', '13 of 20 points left'), and the
Mega-Monster boost button says life-points, as its card does.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0138A8CjeQRpvzKxuMfz1Bqc
2026-08-18 10:44:12 -04:00
Eric WagonerandClaude Fable 5 0f91d30a3e Press-and-hold peeks a segment — the tooltip, for hands without a mouse
The same 450ms hold that peeks a square now works on walls, doors, and
fire walls: the segment's full description (state, lock, hitpoints, the
fire's burn warning) rises in the peek scrim. Shimmering illusions keep
their richer tap modal.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0138A8CjeQRpvzKxuMfz1Bqc
2026-08-18 10:40:55 -04:00
Eric WagonerandClaude Fable 5 497c2245a3 Every segment states its hitpoints in the tooltip
'a wall — 20 hitpoints'; battered, 'a wall — 13 of 20 hitpoints left';
doors the same against their 15, lock states included ('held open by a
standing wizard — 15 hitpoints'). The crack overlay already told the
damage; now the wall itself tells what still stands.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0138A8CjeQRpvzKxuMfz1Bqc
2026-08-18 10:37:57 -04:00
Eric WagonerandClaude Fable 5 9eeb89caca Every edge answers a hover: tooltips for walls, doors, fire, illusions
Only the special door lock states carried titles. Now plain walls ('a
wall'), locked doors, the wall of fire (with its 4-damage warning), the
untested shimmer ('tap to test your eyes'), the known-illusion ghost,
and battle cracks (damage taken so far) all speak on hover. The
firewall's hover target is its bar; the flames stay click-through.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0138A8CjeQRpvzKxuMfz1Bqc
2026-08-18 10:36:41 -04:00
Eric WagonerandClaude Fable 5 d8b8f8fd53 Wall-segment 'tokens' retire; the gallery shows edges as the maze draws them
The game has never used token art for edge effects — created walls,
doors and their lock states, fire walls, illusions are all vector edge
treatments. The ten unreferenced file pairs (wall, wall-2, door,
fire-wall, illusion-wall, destroy-wall, jam-lock, lock-gone,
redirection-a/b) are gone from both art sets, and the Token Workshop
gains 'Walls & doors — as the maze draws them': every edge state
(locked, ajar, held, removed, jammed), the standing fire, and both
faces of an illusion, rendered by the same EdgeGlyph / FirewallEdge /
IllusionShimmer components the board mounts. EdgeGlyph is newly
extracted from Board so the display cannot drift.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0138A8CjeQRpvzKxuMfz1Bqc
2026-08-18 10:16:28 -04:00
Eric WagonerandClaude Fable 5 e1aeeaabff The Token Workshop: every token, twice, at /?tokens
All 45 tokens in both arts — the photographed physical set beside the
hand-drawn contingency — grouped (wizards, treasures, monsters, terrain,
objects & markers), each at board size and close-up. The drawn column
renders through TokenArt, so it previews exactly as the board inlines
it. Cross-linked with the flourish workshop.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0138A8CjeQRpvzKxuMfz1Bqc
2026-08-18 09:16:46 -04:00
Eric WagonerandClaude Fable 5 ed7a58a698 The workshop gains 'The standing fires': board furniture on display
FirewallEdge (both orientations), the illusion shimmer, and the sight
trace (direct and through-a-warp) join the /?fx gallery — and to keep
the display honest, the shimmer and sight trace were extracted from
Board.svelte's inline markup into IllusionShimmer.svelte and
SightTraceOverlay.svelte, so the workshop mounts the very components
the live board does. No copies to drift.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0138A8CjeQRpvzKxuMfz1Bqc
2026-08-18 09:13:31 -04:00
Eric WagonerandClaude Fable 5 ce556b5508 Wall of Fire burns like it means it
The pulsing red rectangle becomes a standing fire: a glowing gradient
bar seated on the wall line, five tongues of flame licking on staggered
beats, and embers drifting off the top. Pure CSS on a handful of shapes
- no turbulence filters, which stay budgeted for the one-shot Fireball,
since firewalls burn indefinitely. Vertical walls flame just as well as
horizontal ones; reduced motion stills the fire but keeps it visible.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0138A8CjeQRpvzKxuMfz1Bqc
2026-08-18 09:07:36 -04:00
Eric WagonerandClaude Fable 5 b1f03fee81 Ask the automatons: the council of three offers hints from your seat
The owner's idea for teaching novices: a hints button runs all three
temperaments' brains against YOUR view — the same cards and board you
see, nothing hidden — and each says what it would do in your robes.
The Hunter (eyes on the gold), the Berserker (eyes on the blood), the
Worrier (eyes on the exits). Available on your turn and while under
fire (counter advice included); purely advisory, computed client-side,
nothing dispatched. hints.ts translates any Command into plain words.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0138A8CjeQRpvzKxuMfz1Bqc
2026-08-18 02:19:32 -04:00
Eric WagonerandClaude Fable 5 5ac1c9ed70 One-tap discard from the hand: select a card, 'Discard it'
Shedding a single card meant entering discard mode, marking, and
confirming. Now any selected card offers 'Discard it' right in its
action strip — beside 'Drop it here' when the card is an object, so
the drop-or-discard choice sits in one place. The bulk discard flow
stays for multi-card sheds.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0138A8CjeQRpvzKxuMfz1Bqc
2026-08-18 02:12:39 -04:00
Eric WagonerandClaude Fable 5 d5b2b92f2c Illusion walls shimmer until YOU test them (rules rev 29)
Per the owner's design — and truer to a real table, where the cast is
public: every illusion wall's location is open knowledge, rendered as a
shimmering wall to any player whose eyes have not yet ruled on it.
Testing is an explicit act: tap the shimmer (or bump into it) and a
modal explains the 50/50 and offers 'Roll to test your eyes' — the new
testIllusion command rolls once, then the wall either hardens or
dissolves for you alone. Nobody's verdict is moved by watching someone
else stroll through (the Q3WZ mystery: an automaton walking through
its own round-1 fake). Untested walls block movement and sight without
consuming RNG; the pre-29 lazy belief roll is preserved for stored
games. Automatons doubt free shimmers on their best crossing before
spending any card on that wall.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0138A8CjeQRpvzKxuMfz1Bqc
2026-08-18 01:54:53 -04:00
Eric WagonerandClaude Fable 5 500d9a7154 How-to-play gains 'The automatons': temperaments, tiers, mysteries
The help never explained the clockwork — hunter/berserker/worrier
moods, the mystery deal and its end-of-game unmasking, and what the
difficulty tiers actually change (resources and repertoire, never
fairness).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0138A8CjeQRpvzKxuMfz1Bqc
2026-08-18 01:03:28 -04:00
Eric WagonerandClaude Fable 5 7d97bb1093 Bots stop wasting counters on what cannot be countered
Per the owner's ruling: EMPATHY mirrors only delivered damage, so a
damage-less curse gives it nothing — the berserker keeps it sheathed
against afflictions (an automaton burned one on SLOW DEATH). And the
permanent curses (slow death, walking dead, idiot) ride no duration
pipe, so BLUNT and shieldstone numbers can't shorten them: only a full
stop or REMOVE CURSE answers those, and the ladder now knows it.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0138A8CjeQRpvzKxuMfz1Bqc
2026-08-18 00:57:31 -04:00
Eric WagonerandClaude Fable 5 3323f81fba Roster rows wrap instead of truncating the temperament
The name cell was a fixed-height nowrap/ellipsis line, clipping even
plain 'archmage hunter' mid-game. The temper tag now wraps below the
name as one piece and the row grows to fit.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0138A8CjeQRpvzKxuMfz1Bqc
2026-08-18 00:48:37 -04:00
Eric WagonerandClaude Fable 5 b650e1e636 The unmasking fits the row: a mask glyph instead of prose
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0138A8CjeQRpvzKxuMfz1Bqc
2026-08-18 00:46:01 -04:00
Eric WagonerandClaude Fable 5 55c76cf20e Game over unmasks the mystery machines
Hands already go face-up when the maze is won; now the roster does
too — a secret automaton's row reads 'archmage berserker (was a
mystery)' once the game finishes, broadcast with the final command
from either a human or the bot pump. Mid-game, the mood stays its
own business.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0138A8CjeQRpvzKxuMfz1Bqc
2026-08-18 00:38:42 -04:00
Eric WagonerandClaude Fable 5 5243a173a8 Stone soaks show their work in the damage line
'Takes 2 damage' from a 3-point bolt read as broken arithmetic unless
you remembered the bloodstone. The damaged event now carries its soaks
(bloodstone's flat point, soulstone's spell-damage clamp) and the log
prints them: 'takes 2 damage (lightning-blast (reflected) — bloodstone
soaks 1)'. A blow the bloodstone drinks entirely — previously silent —
announces itself too. Events are derived, so replays gain the notes
retroactively.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0138A8CjeQRpvzKxuMfz1Bqc
2026-08-18 00:02:07 -04:00
Eric WagonerandClaude Fable 5 1d7407cb20 A reflected Lightning Blast ends the caster's turn on the spot (rev 28)
FAQ: 'If this gets FULLY REFLECTED, you lose the rest of your turn and
cannot draw cards (in addition to damage).' When the returned bolt
stuns its own caster mid-turn, their remaining actions end at once and
the end-of-turn draw comes up empty (new turn.drawForbidden flag); the
normal stun still costs them the next turn. The affected player sees
'Your own bolt has left you reeling' in place of the usual spent-turn
slip. Older revisions played on and stored games replay so.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0138A8CjeQRpvzKxuMfz1Bqc
2026-08-17 23:47:25 -04:00
Eric WagonerandClaude Fable 5 67157ad3a2 Ledger chests tap open full-size, like the table's other peeks
The carried-treasure chest in the scoresheet is now a button: tapping
it raises the big-peek scrim with the chest at full size and a note
naming whose treasure sits in whose arms.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0138A8CjeQRpvzKxuMfz1Bqc
2026-08-17 23:31:01 -04:00
Eric WagonerandClaude Fable 5 f4355a60c6 Ledger chest doubled — big enough to read the color at a glance
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0138A8CjeQRpvzKxuMfz1Bqc
2026-08-17 23:28:15 -04:00
Eric WagonerandClaude Fable 5 1069730880 The ledger's money bag becomes the owner's chest too
The scoresheet's carrier mark now shows whose gold is being hauled —
the same colored SVG chest as the board badge, inline at text height.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0138A8CjeQRpvzKxuMfz1Bqc
2026-08-17 23:26:10 -04:00
Eric WagonerandClaude Fable 5 4a5baed853 The carried-treasure dot becomes the owner's chest
A gold dot said 'carrying' but never whose. The badge on the carrier's
shoulder is now the treasure owner's colored chest — always the drawn
SVG chest, which stays legible at badge size in either art mode. The
dot survives only as a fallback for a treasure the view cannot resolve.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0138A8CjeQRpvzKxuMfz1Bqc
2026-08-17 23:23:55 -04:00
Eric WagonerandClaude Fable 5 3dcdf50498 Nightly ledger backup to DO Spaces (deploy/wizwar-backup.sh)
Installed on the droplet at /usr/local/bin/wizwar-backup.sh, cron 07:17
UTC daily: mirrors /var/lib/wizwar to spaces:kestrel-wizwar-backups/
wizwar/current and keeps 90 days of dated snapshots. Ledgers are
append-only, so no service stop is needed. The script no-ops with a
log line until Spaces credentials land in /root/.config/rclone/
rclone.conf.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0138A8CjeQRpvzKxuMfz1Bqc
2026-08-17 23:15:28 -04:00
Eric WagonerandClaude Fable 5 e412463aae Thumb of God gets its ceremony: prompt, sighted dimming, and the die
The cast always worked (click a square), but nothing guided it and
nothing marked its arrival. Now: a targeting prompt, eligibility
dimming to the caster's sighted squares (the engine demands LOS to the
aim point), and a flourish — the aiming mark, a shadow gathering, the
die crashing down out of a clear sky with a bounce and flung grit, a
drift line when fate moves it, and every scattered token streaking to
where it lands. In the /?fx gallery as die-drop.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0138A8CjeQRpvzKxuMfz1Bqc
2026-08-17 23:09:40 -04:00
Eric WagonerandClaude Fable 5 5351e345c3 Object-ness comes from the card face, not a parallel list
'This is most certainly an object' (WIZARDBLADE's FAQ) — and the card
data already says so: every physical item bears the OBJECT subtype on
its face. isMovableObject now reads it from there, retiring the
hand-kept list — which had missed MASTER KEY and HANDFUL OF TACKS,
both object-marked. Ungated: no stored ledger holds a swap or drop
this widens (verified against production), and refused commands are
never recorded.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0138A8CjeQRpvzKxuMfz1Bqc
2026-08-17 22:39:46 -04:00
Eric WagonerandClaude Fable 5 2bb2ca62d8 Reflected Swap Meet: the reflector chooses the trade (rev 27)
'FULL REFLECTION lets the other player decide which objects, if any,
will be swapped' — the reflector's choice now rides their counteract
(params.cardId, reflector's item first), resolved with the roles
swapped when the reflection settles; 'none' or no choice trades
nothing. The client walks the reflector through the same give-and-take
picker, with a 'swap nothing' refusal.

Also from room XRT7: the trade picker now honors each room's own rules
revision (older rooms trade only object-typed cards), so it can no
longer offer a wizardblade a rev-25 engine will quietly refuse — and a
fizzled swap finally says so in the log instead of vanishing.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0138A8CjeQRpvzKxuMfz1Bqc
2026-08-17 22:36:00 -04:00
Eric WagonerandClaude Fable 5 3aef6694f3 Swap Meet trades treasures — a carried treasure is a carried item
The trade grammar gains a 'treasure' token (never present in stored
ledgers, so no gate needed): a dagger can buy back the treasure in a
thief's arms, or two armfuls of gold can change hands outright. The
one-treasure carry limit and WEAKNESS both hold in a trade as at a
grab — a one-way treasure needs an open slot and an able back. The
picker offers each side's carried treasure alongside displayed items,
withholding theirs when your own arms are already full.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0138A8CjeQRpvzKxuMfz1Bqc
2026-08-17 22:19:29 -04:00
Eric WagonerandClaude Fable 5 00517e08b1 Pacts are honored; Swap Meet trades items, not card names (rev 26)
The pact fix: a clockwork no longer attacks a wizard it holds a BUDDY
pact on — Eric watched one sign the pact and punch him the next turn.
A pact is torn up for exactly one thing: a kill. And the post-attack
pact is signed only by a wizard who wants OUT of the fight (hauling
gold, bleeding, or with other enemies left) — a healthy duelist keeps
its options, and mutual-pact stalemates stay out of bot wars.

Swap Meet drops the 'name a card' prompt for a real trade picker:
click the other trader, choose one of your carried items, then claim
one of their displayed items. Rules rev 26 widens the engine's match
from object-typed cards to every movable object (daggers, rocks,
wands, stones); older games matched narrowly and replay so.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0138A8CjeQRpvzKxuMfz1Bqc
2026-08-17 22:14:57 -04:00
Eric WagonerandClaude Fable 5 06faea0c79 The reflected-attack window (rules rev 25)
A FULL REFLECTION's returned spell is a fresh attack on its own caster —
who, per the owner's ruling, gets a defender's counteraction window
against it (absorb the blast, shield it, or FULL REFLECTION again: the
ping-pong war ends when the cards run out). The reflection now settles
into a new stack with the roles swapped and the damage pre-priced
(numbers, amplifies, and surviving counters already applied); the blow
returns to its sender unerringly, with no fresh hit rolls. onResolved
effects run with the swapped roles, so a reflected IDIOT now afflicts
its own caster. Earlier revisions land the blow instantly and stored
games replay unchanged.

Automatons price the incoming reflected damage off the stack; the attack
modal announces 'Your own spell comes screaming back!' with the inbound
total.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0138A8CjeQRpvzKxuMfz1Bqc
2026-08-17 22:02:16 -04:00
Eric WagonerandClaude Fable 5 dcaf358a93 Right the dimensional warp token — its caption stood on its head
The physical-set crop was rotated 180; sips -r 180 sets it upright.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0138A8CjeQRpvzKxuMfz1Bqc
2026-08-17 21:12:13 -04:00
Eric WagonerandClaude Fable 5 21884fa26e The fireball-then-buddy lockout
Per the owner's favorite play: the pact only breaks when its caster
attacks the target, so a blow landed BEFORE the pact leaves it intact.
After spending its attack, a non-berserker bot with BUDDY in hand signs
it onto the weakest visible unpacted enemy — the one it likely just
burned — barring their revenge. The berserker skips it: it would only
break its own pact tomorrow.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0138A8CjeQRpvzKxuMfz1Bqc
2026-08-17 21:03:40 -04:00
Eric WagonerandClaude Fable 5 3087f00bdc Round two of the owner's tactics: exile, wand-slip, finishers, boosts
- TELEPORT OPPONENT exiles a delivery in progress — the thief of the
  bot's gold, or any carrier within six of home — to the square farthest
  (by walking distance) from the victim's own home; a sealed pocket wins
  outright. No LOS needed for the destination, per the card.
- WARP WAND joins the roadwork: a wall slips open for a 4+-step shortcut
  when the crossing fits this turn's remaining legs (the wall returns at
  end of turn); charges itself with the smallest number on first use.
- ADRENALINE is the finisher: cast when no single attack in hand kills
  the target but the top two together do; the attack window now honors
  the second swing.
- STRENGTH doubles a thrown dagger or rock exactly when that turns a
  wound into a kill.
- EXTEND rides afflictions, doubling the misery's stay.
- MEGA-MONSTER doubles a pet's stride (movement over life) so the
  menagerie actually catches people.
All six leave the bottom discard tier.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0138A8CjeQRpvzKxuMfz1Bqc
2026-08-17 20:33:45 -04:00
Eric WagonerandClaude Fable 5 4bda6087b1 The automatons learn Eric's tactics: roadwork, denial, bursts, breathing room
Per the owner's briefing on how these cards are actually played:
- Roadwork on the march: DISPEL CREATION un-creates conjured walls and
  filled squares; STONE TO WATER melts walls and stone blocks (cast only
  from outside its own wave); CREATE DOOR plus a lock-opener turns a wall
  into a doorway; DIMENSIONAL WARP folds a 6+-step detour into one step,
  and the bot steps through its tokens when the far side is closer.
- Path denial grows: JAM LOCK seals doors on a threat's road, ILLUSION
  WALL stands in for CREATE WALL, the full nuisance shelf (pit, slime,
  ooze, rosebush, tacks, dust cloud) joins stone and thornbush, and a
  BOOBYTRAP lands mid-path when nothing can reroute the thief.
- Bursts: ADD joins a second number to the march; MAD DASH doubles the
  sprint to gold (never while carrying); POWER RUN buys the last spaces
  of a winning delivery with blood.
- Breathing room when pressed (worrier, treasure-carrier, or bleeding):
  FEAR at three paces, UGLY when they crowd in, BUDDY to pacify the hound.
- AROUND THE CORNER: an enemy one bend out of sight can be attacked; new
  bentSightFor mirrors the engine's bentLos from the viewer's knowledge.
- GameView gains createdEdges (public — the table watched them conjured).
All newly playable cards leave the bottom discard tier via USEFUL_NEUTRALS.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0138A8CjeQRpvzKxuMfz1Bqc
2026-08-17 20:14:55 -04:00
Eric WagonerandClaude Fable 5 4e14926c0c Discard valuation knows whose hand it is; the shed spares the playbook
The end-of-turn shed was eating cards the brain itself casts: BIG MAN,
MIST BODY, SHRINK, LIFESAVER, and STONE DEAD all sat at or below the shed
threshold. But worth is contextual — LIFESAVER is genuinely dead at a
two-seat table, BIG MAN outside the berserker's book — so discardValue now
takes the view and style: STONE DEAD joins the attacks tier outright, the
rest are kept exactly by the wizard who can play them.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0138A8CjeQRpvzKxuMfz1Bqc
2026-08-17 19:57:26 -04:00
Eric WagonerandClaude Fable 5 78085e26fb Automatons wield Pass Through Wall and deny roads with terrain
Pass Through Wall joins the march: the bot banks a crossing when stepping
through one wall beats the walk by 4+ steps (or no road exists), walks to
the chosen wall, and spends the charge stepping through. passWallCharges
is now in PlayerPublicView — the cast is public at a physical table.

Path denial for guardGold tiers: when an enemy carries the bot's treasure
toward home, or closes on its gold on the floor, the bot reconstructs the
threat's shortest path and prices every corridor line and empty square on
it; CREATE WALL, FILL SQUARE WITH STONE, or THORNBUSH lands wherever the
detour costs the enemy 3+ steps, legality mirrored from the engine
(sighted, empty, off homes and warp tokens).

All five cards leave the bottom discard tier (2 -> 6).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0138A8CjeQRpvzKxuMfz1Bqc
2026-08-17 19:50:41 -04:00
Eric WagonerandClaude Fable 5 2d53ba4bc0 Waves spend their force as they travel (rev 24); bots wield Destroy Wall
Rules rev 24: a waterwall wave that finds a victim dist cells from its
source has only range-dist spaces of push left — a range-2 wave throws its
adjacent victim two spaces but a victim at its far edge only one, and
spent force never converts into crush damage. Applies to WATERWALL and
both STONE TO WATER waves; older revisions keep the flat full-range wash
so stored games replay unchanged.

Automatons now use DESTROY WALL on the march: two BFS distance maps (from
the bot, from its objectives) price every visible wall by the shortcut its
removal opens; the bot blasts when it saves 4+ steps of walking — or when
no road exists at all — never standing beside the blast unless trapped
and healthy. The card also leaves the shed pile: discardValue 2 -> 6.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0138A8CjeQRpvzKxuMfz1Bqc
2026-08-17 19:40:41 -04:00
Eric WagonerandClaude Fable 5 dfd7a2ff56 Stone to Water's targeting aid honors sight and its wall targets
The cast validation demands LOS to a stone block, but the dimming aid lit
every stone square on the map — including ones the caster cannot see. Now
only sighted blocks light; and since the card equally targets stone walls
(edges the cell-shadow cannot express), no sighted block means no shadow
at all rather than a maze dimmed away from its true targets.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0138A8CjeQRpvzKxuMfz1Bqc
2026-08-17 19:31:26 -04:00
Eric WagonerandClaude Fable 5 77c5a6342f Purge expansion2 card rows — a set this edition does not have
The 5e-inherited card database carried 85 rows tagged expansion2; 6e has
only the basic deck and Expansion Set #1, and buildDeck never dealt them.
They kept leaking into things that cite the database (rulebook text, the
IDIOT aid list), so the rows are gone and CardSet no longer names the set.
Other editions can reintroduce their own sets when they arrive.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0138A8CjeQRpvzKxuMfz1Bqc
2026-08-17 19:12:15 -04:00
Eric WagonerandClaude Fable 5 c013ba7e86 Trim IDIOT_AIDS to cards that exist in the 6e deck
vampire, werewolf, flight, and exploding-door are expansion2 rows in the
card database — a set this edition does not have; buildDeck never deals
them. Listing them as idiot-permitted aids cited cards that cannot occur.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0138A8CjeQRpvzKxuMfz1Bqc
2026-08-17 19:06:10 -04:00
Eric WagonerandClaude Fable 5 cdeb3d5103 Idiot enforces its card (rev 23) + attack sight-line tracing
Rules rev 23 — IDIOT, per the card and FAQ:
- No handling items: pick up / drop of treasures and objects refused
  (dropping was the exploit: capturing a stolen treasure on your own home,
  or dropping your own treasure underfoot for an instant cure)
- No punching, no thrown dagger / large rock (attacks on players)
- No effect on a victim already carrying one of their own treasures
Ungated (permissive): counteractions are now castable while idiotized (the
one thing the card expressly allows — the gate wrongly blocked them), and
goal-aiding spells (IDIOT_AIDS: destroy-wall, teleport, mad-dash, ...) per
the FAQ's 'you could, however, destroy a wall'.

Sight tracing: while an LOS attack sits on the stack, the board draws the
line it traveled — straight when direct, leg by leg through both warp
mouths (with pulsing rings) when the maze's wraparound carried it. Engine
traceSight/traceSightFor/stackSightTrace; overlay in Board.svelte; shown
live and in replays. Verified against H3PC's cross-board Idiot cast.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0138A8CjeQRpvzKxuMfz1Bqc
2026-08-17 19:03:09 -04:00
Eric WagonerandClaude Fable 5 7372bfc5e8 Rev 22: the self-stack resolves — one wizard cannot bounce to himself
A democratic monster touching its own creator opens a stack where one
player wears both hats, and doPass matched the attacker first: every
pass "bounced the exchange to the defender" — the same wizard —
forever. Room 928D livelocked there at seq 83; once the boot kick
revived its pump, the automaton politely passed 389 times. At rev 22
a self-stack pass RESOLVES (the claw lands, the game moves on);
older ledgers hold their recorded bounces and replay so. 928D itself
was repaired by truncating the no-op run and lifting it to rev 22,
verified clean and unstuck on a copy before installation.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-17 18:14:18 -04:00
Eric WagonerandClaude Fable 5 4a75370de5 Restored rooms wake their automatons
The bot pump only ran when a command or join arrived, so a server
restart landing mid-bot-turn left the restored room waiting forever
for a human to poke it — room 928D sat exactly there, its automaton
holding a perfectly answerable stack. Boot now kicks the pump for
every restored still-running room, two seconds after restore.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-17 18:07:33 -04:00
Eric WagonerandClaude Fable 5 2ac046611d ADD explains itself instead of dead-ending
Two numbers for movement work by playing them one after another, the
Add spending itself on the second — but clicking the ADD card itself,
the natural first instinct, showed nothing but a cancel button. It
now says how the ride works; a second number without an Add in hand
says what is missing instead of offering a doomed button; and the
button's label says "spends your Add" at the moment it does.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-17 17:59:39 -04:00
Eric WagonerandClaude Fable 5 7df58d29fa Rev 21: collapsing walls crush anyone — monsters included
DESTROY WALL's "anyone in either square next to the wall takes 4
points" swept only wizards; a troll leaned on the falling masonry
untouched. The expansion sheet is explicit — "if a card specifies
'Opponent' or 'Anyone' as a target, this includes Monsters" — so the
collapse now crushes creatures in both squares, at the rim breach's
far side too. Earlier ledgers keep their charmed monsters.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-17 17:47:14 -04:00
Eric WagonerandClaude Fable 5 6380fae134 The rulebook itself joins the shelf, verbatim
The rules tab carried a paraphrase and the FAQ; now the court of
final appeal sits between them — the full base rulebook text (the
5th-edition wording the 6th shipped with) and the Expansion Set 1
sections, word for word from the designer's own wizwar.com, with
copyright and provenance shown rather than hidden. This edition has
no Expansion 2 — Artifacts and Transformations do not exist here and
are not included. The text moves out of research/ into real source.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-17 17:40:00 -04:00
Eric WagonerandClaude Fable 5 8d308bc606 Rev 20: the junction wall rolls for its allegiance
The rulebook (Cards And Actions That Change The Map): a CREATE WALL
or DESTROY WALL alteration on a junction between sectors rolls a
50-50 when "some other moron" rotates one of them — 1-2 stays with
the standing sector, 3-4 travels with the moving one, per the book's
own low/high convention. Both rotation and relocation roll (the same
seam tears either way), demolished holes roll alongside conjured
walls, the pips land loud in the chronicle, and a traveling edge
rides anchored to its in-sector cell. Rev-gated: the roll consumes
dice that stored games never spent.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-17 17:34:33 -04:00
Eric WagonerandClaude Fable 5 a17b5238f0 Rev 19: breaching the rim opens a new warp across the maze
Destroying a wall on the board's outer edge used to leave a one-sided
hole into nothing. The table's physics prevail: the outer rim wraps,
so the breach goes clean through — the opposite perimeter wall in the
same row or column crumbles too (collapse damage and all), and a new
warp pair opens between the two edges, shimmering at both mouths.
Rev-gated: stored games hold one-sided breaches and replay so. Sector
moves recompute the wraparounds and forget improvised openings, as
the maze's own reshaping always has.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-17 17:25:25 -04:00
Eric WagonerandClaude Fable 5 766ec0a726 A warp mouth is a wallable line — and the tunnel seals whole
Create Wall refused the board-edge openings: no far cell, so "walls
must be created between two spaces". But bricking over a lettered
opening is a classic play, and the far space is the tunnel itself.
A warp mouth now counts as wallable — with the wall raised at BOTH
mouths, since a tunnel has one passage: no walking in from the far
board, no warp sight through a sealed pair, and tearing down either
end reopens both. The client grows edge hitboxes at the perimeter
mouths so the line is clickable at all.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-17 17:22:49 -04:00
Eric WagonerandClaude Fable 5 bed7d849eb The cruel draw gets its modal, and its own words
GIFT FROM BELOW bit for three in the middle of end-of-turn noise and
nobody saw it — not live, not in the replay, where its log line even
claimed "lose a turn" (the other trap's fate). The trapSprung event
now names its card; drawing a trap YOURSELF raises the full modal —
the card, what it did, "Curse the deck" — and the chronicle tells
each trap's true consequence. The amplify narration was already
fixed; replays re-derive events, so both now show in old games'
reels too.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-17 17:13:36 -04:00
Eric WagonerandClaude Fable 5 028ff813f3 Amplify announces itself
Room 9BBV's "impossible" 14-point powerthrust was an archmage playing
correctly: 2 + 5, AMPLIFIED. The engine's math was honest and its
narration was not — neither the log line nor the attack modal
mentioned the amplify, so a legal kill read as a bug. The spellCast
event now carries its amplify count, the chronicle says "casts
Powerthrust with a 5, AMPLIFIED, at Kestrel", and the modal's power
line shows "powered by a 5 — AMPLIFIED ×2" while there is still time
to respect it.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-17 17:10:06 -04:00
Eric WagonerandClaude Fable 5 b4adb97536 The mid-round democratic monster claws when its turn comes
Every creature is born with attackUsed spent — the right way to say
"cannot attack the turn created" for monsters whose flag refreshes
next turn. But the democratic monster's flag budgets its ROUND, so a
mid-round summon arrived pre-spent and bumped harmlessly until the
round rolled over. Creation-turn pacifism now rides justCreated
alone for the monster (checked at the touch), and its round-claw
starts live — folded into rev 18 with the boundary refresh.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-17 16:53:28 -04:00
Eric WagonerandClaude Fable 5 3b0aa01867 Rev 18: the democratic monster's claw outlives the first wizard
Its one-attack-per-round refreshed inside beginTurnFor when the turn
index matched the roll-off winner's seat — and only the living begin
turns, so once that wizard fell the claw never refreshed again: one
attack, then a lifetime of harmless bumping. The refresh now lives at
the true round boundary in the turn-advance loop, which passes dead
seats without skipping the count. Earlier ledgers keep their gummed
monster and replay so.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-17 16:51:44 -04:00
Eric WagonerandClaude Fable 5 d89d995daf The sector ghost slides where the sector actually went
The relocation flourish corrected its coordinates against the view —
but effects are mapped when the events arrive, one message before
the new state, so the correction read the PRE-move board and the
ghost slid between unrelated squares. The sectorRelocated event now
carries its origins in final coordinates, computed after the maze
renormalizes, and the flourish trusts the event alone.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-17 16:48:20 -04:00
Eric WagonerandClaude Fable 5 e57307efbe Rev 17: the wave carries monsters as it carries wizards
Stone to Water's wave (and every waterwall collapse) washed wizards
back and crushed them against the maze — while a skeleton in the
same water stood dry. The wave only knew creatures well enough to
drown fire imps. From rev 17 it carries them all: washed back along
the surge, one point of crush per space the maze refuses, fire imps
still destroyed outright. Earlier ledgers keep their dry monsters
and replay so.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-17 15:07:34 -04:00
Eric WagonerandClaude Fable 5 aef88d892a Two treasures, one square: the taker names their prize
pickUpTreasure grabbed whichever treasure the list offered first —
with two on a square, no choice and sometimes the wrong one. The
command now takes an optional treasureId (absent in every stored
ledger, so old replays keep their old grab), and when the square
holds more than one, the button asks "whose?" before dispatching.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-17 15:03:34 -04:00
Eric WagonerandClaude Fable 5 794b809a1b Swapping homes stops announcing a body swap
SWAP HOME BASES traded homes correctly but borrowed the
positionsSwapped event, so the chronicle claimed the wizards
themselves changed places. It now speaks its own event — "swap home
bases — the maze's loyalties shift!" — and both hearths shimmer as
their allegiance changes.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-17 15:01:07 -04:00
Eric WagonerandClaude Fable 5 e7c8ddc0b3 Creatures walk open doorways, and the interruption gets its fanfare
Player movement asked the full question of a door — removed, keyed
this turn, or held — while creature movement only saw "door" and
refused, so a skeleton balked at a doorway its master had unlocked
for good. One doorIsOpen() now answers for both, and an open doorway
costs a wraith none of its wall passes.

And the interruption window earns the modal it deserved: "The maze
holds its breath" — the card shown, the instruction plain, dismissed
with "Seize it". No more hunting the rail for a slip while time
stands parted.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-17 13:50:38 -04:00
Eric WagonerandClaude Fable 5 44c14f5ce1 The interruption window opens for actual casting
OPPORTUNITY FIRE and INTERRUPT bought a moment the client would not
honor: every selection and targeting gate asked "is it your turn?",
and mid-interruption it is not — so the window's holder could click
attack cards into silence while the engine sat ready to accept the
cast. A window is now yourMoment: hand selection, player/creature/
cell/edge targeting, and the dimming aid all open exactly as on your
own turn, and the slip says what to do with it ("pick an attack card
and a target") instead of the cryptic "cast now".

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-17 13:45:52 -04:00
Eric WagonerandClaude Fable 5 94ec714e35 Rev 16: empathy mirrors the blows that resolve by their own hand
A believed ILLUSIONARY ATTACK, the goat's ram, and the hurled
treasure all deal their damage inside the attack's own resolution
hook — past the pipeline where the empathy mirror lived, so a linked
caster walked away unbloodied. One resolvedBlow helper now carries
the mirror to all three: "any attack done in ANY form" means these
too. Rev-gated: proactive empathy predates this, so stored ledgers
may hold unmirrored blows and replay them as struck.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-17 13:37:37 -04:00
Eric WagonerandClaude Fable 5 89ba225fe5 Illusions show their face, and empathy answers the call
An automaton's ILLUSIONARY ATTACK arrived as a mystery: the modal
showed only the illusion card, never the spell being faked — though
the stack has always carried it face-up. The defender now sees both
cards side by side, the caption names the fake ("an ILLUSIONARY
Fireball — it bites only if believed"), and the hint bar says which
spell to weigh a counter against.

And EMPATHY — corner: COUNTERACTION — was refused at the door like
INVISIBLE before it, while the automatons' own counter ladder had
been reaching for it and silently failing into the fallback all
along. It now raises mid-stack: the blow lands on both wizards, the
link lingers for its NUMBER card's turns, and ANTI-ANTI severs it
cleanly (empathy is no escape). The number-riding-a-counter idiom is
one shared helper now. Permissive both ways: no stored ledger
contains either play, so no rev gate.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-17 13:33:24 -04:00
Eric WagonerandClaude Fable 5 ea3b9e5bd6 The clockwork reads absorb's fine print
An automaton answered NO SPELL with an Absorb — which "has no effect
on duration-based spells." Afflictions sat outside the price table
and drew the phantom two-point default, tripping the point-soaking
rungs. An affliction's weight is now its duration, and the two
counters that touch only points — ABSORB and REVERSE — stand aside
for it, leaving the ones that genuinely bite durations: full shield,
remove curse, blunt, reflection, shieldstone numbers. Pinned: under
NO SPELL with both in hand, the bot blunts, never absorbs.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-17 13:27:14 -04:00
Eric WagonerandClaude Fable 5 adf463effa Rev 15: the held doorway carries sight — the whole point of holding it
The table holds doors open to cast back through them at pursuers;
our held door opened for feet but not for eyes. From rev 15 a held
door is an open doorway to sight — casting at players, creatures,
and squares sees through it, the client's dimming aid and the
automatons alike (they share sightedCellsFor). REMOVE LOCK's "still
considered to block L.O.S." stands: that speaks of a CLOSED door,
and an unheld unlocked door still blocks. Rev-gated because rev-14
ledgers may already contain holds and must replay blind.

Pinned three ways: the holder blasts a pursuer through the held
doorway; an unheld unlocked door still blocks; rev 14 stays blind.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-17 13:20:45 -04:00
Eric WagonerandClaude Fable 5 a0c65413ef The door can be held open, as both key cards always promised
MASTER KEY and PICK LOCK each read: "You may 'hold the door open' for
others, if you wish" — and the engine always slammed it at end of
turn. Now the cast takes a hold param: the door stays unlocked past
the turn, for anyone, as long as its holder stands adjacent and
alive. A step away, a shove, a teleport, or a killing blow lets it
swing shut — swept after every command, since anything can move a
wizard. New state, new param: no old ledger contains either, so no
rev gate is needed.

The client offers a "hold the door open" checkbox when either card is
selected; a held door shows pale with a green jamb ("held open by a
standing wizard"), and the chronicle records the holding and the
shutting. Pinned: a held door outlives the turn and admits the other
wizard; walking away releases it.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-17 13:15:57 -04:00
Eric WagonerandClaude Fable 5 d2b40ec6f8 Credibility pass: the seams get sanded
Scoped to everything since the last pass (3308850). Three blind
reviews, every finding verified before touching anything.

Confirmed and fixed: two identical comment-splitting insertions left
doc comments orphaned from their fields (net and local alike); a
51-line CSS fossil of the pre-extraction inline effects survived in
Board.svelte; the rev-13 miss-roll test asserted tautologies while
its comment claimed a check the code never made — it now proves the
die was consumed, and the skeleton is no longer returned as trollId;
the sprite registry's `as never` silently disabled the completeness
its annotation advertised (now a mapped type, one cast at the
dispatch seam); a dead ternary guarded a union that doesn't exist;
Bolt carried a duplicate .fork rule from a color iteration; fxTtl
contradicted three sprites' real animation lengths; the permanence
sentinel was reinvented as a magic 9000 (the engine now exports
isPermanentDuration); CELL was declared thrice (fx.ts now imports
it); App and Replay ran two divergent fx schedulers (one scheduleFx
now, cancellable — stale flourishes can no longer fire after leaving
a game); TokenArt retried missing files forever; the anti-anti
escape guards merge with the gate asymmetry explained; wall-of-fire's
rev-12 carve-out is marked; overLimit ignored a displayed BRAINSTONE
(bots over-discarded by two); botRemark's header mis-stated its own
branches; deliverGold fired on any drop, not a home-base delivery;
escape and win banter never fired from the steps that carry them.

Rejected: "as a human would" (house voice); FxGallery's dev-harness
framing (trimmed one plea, kept the facts).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-17 12:12:03 -04:00
Eric WagonerandClaude Fable 5 4528c66057 The peeked token joins its card — and stops hiding behind it
Clicking a board token now shows the thing itself, enlarged, above
its card in the peek modal — whichever art is active, photograph or
SVG. The art tables move to art.ts so the board renderer and the
modal share one source.

First cut overlapped: the card scales 2.1x out of its layout box, so
flow neighbors sat underneath its visual footprint (the note had been
compensating with a 6.8rem margin hack). A card-stage now reserves
the card's TRUE visual size; token above, note below, nothing buried.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-17 11:58:25 -04:00
Eric WagonerandClaude Fable 5 1d015681d3 SVG tokens render as vectors, not bitmaps of vectors
An svg referenced through an <image> element is rasterized once at
its layout size in user units — about 29 pixels for a wizard — and
scales as a blurry bitmap thereafter, defeating the entire point of
vector art. TokenArt.svelte now fetches each file once, namespaces
its ids (45 tokens' worth of filter and pattern defs share one
document), and inlines it as a nested <svg>: live vector at any
zoom, verified crisp at 3x device scale. PNG art keeps the <image>
path untouched, and the token style family goes :global to reach the
component's elements.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-17 11:36:49 -04:00
Eric WagonerandClaude Fable 5 c62c3b4f05 The SVG tokens join the source proper
The symlink into research/ becomes real files: public/tokens-svg now
owns the hand-drawn set, edited in place and served as-is by the dev
server. The research folder is scaffolding with a demolition date,
not a place for shipped assets to live.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-17 11:29:42 -04:00
Eric WagonerandClaude Fable 5 e0e96ca5ca The art workshop's side door
The hand-drawn SVG token set wires in behind deliberately
undocumented query params — svgPlayers, svgCreatures, svgTerrain,
svgObjects, each =true — swapping that category's art everywhere it
draws: board tokens, lobby standees, roster. public/tokens-svg
symlinks research/tokens-svg, so under the dev server an edit to the
source art shows on the next refresh, and the production build copies
real files through the link. Nobody finds the door unless handed the
key; the photographed set remains the face of the game.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-17 11:27:28 -04:00
Eric WagonerandClaude Fable 5 93bdbb403a Travelling effects fly token to token
Projectiles flew cell-center to cell-center, launching from the
caster's feet and landing under the target's chin — tokens sit high
in their squares and fan sideways when crowded. Every travelling
effect (fireball, waterbolt, bolt, streak, and the reflection's
return flight) now resolves token anchors that mirror the board's
exact positioning, fan-out included: caster's center to target's
center, wizard or creature. Spots with no token to aim at fall back
to sensible cell points, and wash/knockback streaks end on the
carried wizard wherever they fanned to.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-17 11:00:09 -04:00
Eric WagonerandClaude Fable 5 126f003156 Wizards walk; portals stay instantaneous
Tokens jumped square to square, which made the portal shimmer look
late — the wizard had already re-appeared before the threshold lit.
Wizards and creatures are now identity-keyed movers positioned by a
transform, so the DOM node survives a move and a single step glides
(260ms). Anything farther than a step — teleports, warps, drags,
sector moves — snaps as before, because sliding a wizard across the
whole maze would tell a false story; the warp's instant jump beside
its threshold shimmer is now the point, not the bug. Replays glide
the same way, and reduced motion stills it all.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-17 10:56:41 -04:00
Eric WagonerandClaude Fable 5 64709f6c9c Stone to water splashes like it means it
The transmutation fired no flourish: its event carried no coordinates
for the wall case and the mapper knew neither it nor the wave it
raises. The event now carries its edge; the burst splashes both sides
of the vanished wall (or the freed square, for a block), and every
wizard the collapsing wave carries leaves a wash streak — which also
gives the plain WATERWALL's wave its motion for free.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-17 10:47:42 -04:00
Eric WagonerandClaude Fable 5 ca55f7d00b The fireworks get the stage before the victory modal takes it
Winning raised the modal on the same frame the fireworks lit,
covering them. The modal now waits behind the curtain for 2.4
seconds — three volleys over the winner's home, seen — then takes
the stage.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-17 10:40:11 -04:00
Eric WagonerandClaude Fable 5 c6d73550df The optional final polish: five refinements
The bolt deepens to saturated gold over a dark amber glow; the splash
throws a wider crown of five droplets over a broader pool; the
fireworks lose their protractor — uneven angles, lengths, sizes, and
staggered timing, as a real burst has; the portal-cell's void gains
turning swirl arms so the dark center reads as motion, not blur; the
streak narrows and softens so its peak frame no longer resembles a
drawn white line.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-17 10:37:57 -04:00
Eric WagonerandClaude Fable 5 e713d69582 Round two of the outside eye: contrast, scale, and travel
The whiff darkens to slate and sweeps longer; the portal-cell opens
a dark void behind its collapsing rings — an opening in space, not a
selected square; the tacks grow half again and recoil harder; the
streak's reveal slows so the travel reads even in a sampled frame;
dust lifts its contrast a step without turning heavy. The sector
ghosts stay board-machinery on purpose — the reviewer allowed it,
and the maze grinding IS an operation, not a spell.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-17 10:34:02 -04:00
Eric WagonerandClaude Fable 5 bcaa06251a The review lands: twelve sprites get their motion stories
The outside review's diagnosis was right — the weak sprites had one
element doing one motion. Now each tells its story: the whiff is
three air streaks sweeping past a dodger with a wobble; the hit is a
contact flash, a compressed ring punched outward, and flying debris;
the streak's head visibly travels, drawing a tapered trail that
collapses into the destination; the sparkle snaps white-hot between
counter-rotating glints and sheds motes; the tacks are drawn
silhouettes now, points up as a tack on the floor menaces, hopping in
sequence; the claw slashes reveal one by one along their length with
a bright leading edge while the whole strike rakes sideways.

The sector ghosts keep their dashed frames but earn motion arcs,
directional chevrons, corner dust, and a grinding shudder as they
settle. The portal opens wide, ripples along its length, and pinches
shut; cell mouths collapse rings of energy inward. The thornbush
springs actual branches with thorn spurs. The slime is an asymmetric
blob that grips, with elastic strands snapping toward the caught.
Dust gains contrast, varied grain, and blows perpendicular to the
wall that shed it.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-17 10:30:48 -04:00
Eric WagonerandClaude Fable 5 a88cae3a0e The pit reads as depth, not a dot
Its hole was a near-black disc that sat on the parchment like spilled
ink. Now an earthen gradient ellipse, offset toward the far wall,
with the far lip catching the light — a hole you look INTO.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-17 10:19:28 -04:00
Eric WagonerandClaude Fable 5 308f1b6ff9 The fireball sets the bar, and the rest of the catalog rises to it
Eric's fireball lands as the house style — layered construction,
gradient core, glow halo, a directional tail riding rotate="auto" —
with its defs scoped per instance via $props.id(), so simultaneous
fireballs cannot steal each other's gradients. The rest of the
catalog is rebuilt in its image: the waterbolt becomes its cold
sibling (spray tail, no turbulence — one heavy filter stack is
enough); lightning grows a glowing core and branching forks; the
burst blooms through a fire gradient with a shockwave and flying
embers; the splash throws a crown of droplets; the shield raises a
gradient dome with a rim strike; the pow star flashes white and
radiates speed dashes; claws leave tapered gashes; the absorbed card
spirals in along a pull ring; the soul is a proper little ghost with
eyes, swaying as it rises; fireworks ride colored trails; Chaos
catches card slips in its vortex; the pit opens a gradient hole that
swallows a faller; ooze splats and flings blobs; the thornbush sheds
leaves; slime closes over and pops bubbles; masonry dust goes soft
with falling grit. Whiff, tacks, portal, and the sector ghosts keep
their simpler forms on purpose — restraint is part of the style.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-17 10:16:01 -04:00