The window's straddle commands hold more than the turn they open and
close: the opener carries the previous wizard's last draws, the closer
the next wizard's first upkeep — so every instant replay ran on into
the following turn (and, with the camera now following the turn-taker,
jumped into the next wizard's head for the overrun). momentSteps trims
both straddles at the boundary events: the reel opens on "X's turn
begins" and stops at X's turnEnded, keeping only what belongs to X.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Eric's rule, applied everywhere: every reel — moment, catch-up, whole
tale — follows the wizard whose turn it is, the pov switching at each
handover as boundaries scroll past. And the J8LL mystery dies with it:
turn zero's opening boundary lives in the DEAL, before any command, so
scanning a moment's steps found the NEXT turn's start instead and put
the camera in the wrong wizard's head. momentSteps now names the owner
from the very boundary that opened the turn — counted through the deal
— and carries it to the client and the share page, where it also fixes
the same latent mis-titling.
Also aboard: the cutaway shot. When the eyes aim at something they
cannot see — a wraith summoned across the maze, a spell through walls —
the camera cuts to the target's cell for that beat, standing back down
its deepest corridor, and cuts home on the next step. The wraith no
longer materializes off-screen.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The game log's sixty-line window was a render cap, not a limit of what
the client holds — a rejoin replays the whole game into memory. The
chronicle now renders every line back to the deal, and its auto-scroll
grows manners: it follows the newest line only while the reader sits at
the bottom, and holds its place once they scroll up into history.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The flat token billboards give way to terrain that inhabits the room.
Pits, slime, tacks, and the dimensional warp's rings are painted INTO
the flagstones — the home-tile decal pass grows into a general per-cell
overlay grid, one texture per cell, alpha-blended texel by texel. Thorn
and rose hedges fill their square wall to wall at half height, drawn
with a near-bias so the wizard standing among the thorns peeks over the
top. The killer ooze rises as a full translucent cube of jello, bricks
and bodies visible through it; dust billows; and each dimensional warp
mouth throws an additive pillar of violet light up from its floor ring.
Billboards learn aspect, translucency, glow, and draw-order bias to
carry it all.
Nine paintable starters ship — four floor decals under textures/, five
standing volumes under terrain3d/ (spec updated for the artist, hedges
wide, jello solid, warpglow as light) — shown in the token workshop,
rehearsable in place with /?fpv&terrain=thornbush@3,7;jello@4,7.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Host and x-forwarded-proto are attacker-writable and were interpolated
raw into the share page's meta attributes. The proto must now be
literally http or https, and the host is HTML-escaped like everything
else that reaches the head.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The share button lands on the instant replay. One click mints a slug —
persistent, unguessable, one per (room, turn) — and copies a /watch
link anyone can open: the server rebuilds exactly that turn for the
nameless SPECTATOR, public knowledge only, none of the rest of the
game visible. The page arrives with its OpenGraph card pre-baked into
the head (crawlers never run the app): the turn's title and round in
the text, and an og.png of the maze itself — cells, walls, doors, warp
mouths, homes, standees — painted server-side and PNG-encoded with
nothing but node's own zlib. The viewer page wears its chrome: the
WIZ-WAR masthead linking home, the turn's title, the reel opening
straight into the turn-owner's eyes with a "watch it again" loop, and
a footer that says what this table is and deals the visitor in.
The share page loads as its own entry so a shared link never drags the
full app's socket appetite along; the reel's modal scrim learns to
stand in a page instead of over one.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
A wizard who has seen through an illusion no longer walks toward empty
air where the board shows a dashed ghost: the ray records the first
known-illusion edge it crosses without stopping, and the renderer
stands a wall there at one-fifth opacity, violet ripple running through
it, drawn over the sprites so bodies show through its breath. Untested
illusions get the same tell the board gives — a faint shimmer on their
solid face, maybe stone, maybe not — while a believed illusion stays
honest brick. The workshop rehearses it with ?illusion=H:2,8.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
A9WK's mystery, solved by Eric: the wizard walked through an illusion
wall it disbelieves, and the viewer — still deceived — watched the
camera slide through solid stone. The deception stays intact, but the
crossing now performs: any body stepping through an edge the VIEWER
holds as wall (which can only be an illusion the mover saw through)
shimmers on both faces, with the stone-gray wash when the eyes
themselves cross. Same dressing Pass Wall wears.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Two more camera flaws, read straight out of A9WK's clip against its
ledger. The reel's first run measured the leap from the camera's
uninitialized origin as a stride and FACED ALONG IT — an arbitrary
heading that landed nose-first in a wall, and counted as aimed, so the
corridor fallback never ran. A stride only turns the eyes once the
camera is real. And idle beats are rescued generally: whenever nothing
aims the eyes and they would sit staring at a wall closer than a
stride, they turn down the deepest corridor instead — so pacing into a
dead-end cell no longer parks the whole screen inside brick.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
A9WK's clip showed the flaw: a turn owner who casts without moving left
the camera staring into the wall its default heading happened to face,
for the whole turn. The facing ladder grows two rungs: the eyes turn
toward their OWN magic — a cast's target or cell, an attack's defender,
a thrown object's landing — and when a reel opens on a stationary
wizard with nothing to aim at, the camera faces the longest corridor
from where they stand instead of hardcoded east.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Hitting record used to capture from wherever the reel stood — at the
end, the auto-stop fired a beat later and saved one second of the
final frame. Recording now rewinds to the top and rolls the whole
reel. And the container asks for MP4 (H.264) first, the format every
phone and platform plays, keeping WebM only where the browser cannot
mux it; the extension follows the container.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Entertainment polish for the instant replay, all through one wizard's
eyes. Doors now slide open along their own edge — Wolf3D style — when
anyone steps through in a reel, hold for the crossing, and swing shut;
the raycaster takes a per-edge openness map and doors carry their
texture with them, leaving a sliver of jamb at the far post. A wall
that dies bursts into stone and shakes the camera, then leaves a mound
of rubble at the fallen edge for the rest of the reel (a tenth
paintable sprite, drawn opaque — debris, not light). Jammed locks
seethe: a rusty pulse across the wood, keyed off the view's own door
states. Walking THROUGH a wall shimmers on both faces and washes the
walker's own screen stone-gray. And every home base wears its owner's
emblem on the flagstones — a near-white paintable overlay tinted by
wizard color per cell in the floor cast.
Testing surfaced a real ghost: a body standing near a far warp mouth
also rendered at its virtual position, which can overlap real
corridors — the depth buffer alone cannot clip it. Every column now
remembers whether its ray bent, and a sprite draws only where its warp
side matches the column's; projectile legs carry the same flag.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The dream feature lands, behind a preference that ships off for now.
The chronicle's lines grow structure — each knows its turn, counted by
the same boundary events on both ends of the wire (the server counts
the deal's own events too, or every number would sit one turn behind).
The first notable line of a turn — combat, spectacle, a targeted cast
— wears a small eye; clicking it asks the server for that one turn's
steps, rebuilt and redacted like any reel, and the replay opens
STRAIGHT into first person through the eyes of the wizard whose turn
it was: their position, the viewer's knowledge, nothing private leaked.
It plays that turn and stops. Save-video and the board toggle come
along for free.
Two camera bugs die with it: the replay tween effect tracked its own
writes, restarting the ease every frame until walks decayed into the
slow wall-piercing drift Eric saw — untracked reads run one tween per
step now. And the reel camera follows whichever eyes the reel wears,
not always your own.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
A stride into a warp mouth now carries the walker out of the paired
mouth mid-glide, body turned exactly as the rays turn — canWalk admits
a rim edge only where a mouth waits, and the crawler splits the stride
at the crossing. And with painted conjuration sprites arriving, the fx
pass composites them normally instead of additively: painted art is
ink, not light, and additive blending would bloom its outlines white.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Three polishes aimed at the instant-replay dream. Other wizards and
creatures now GLIDE between steps in first person instead of blinking
cell to cell — a stride tweens, a teleport still simply arrives. A
projectile whose sight line runs through a warp now flies as two
simultaneous legs under the mouths' rigid motion, so the fireball
plunges into the opening on one side and bursts from the pair on the
other, whichever room the camera stands in. And the saved video is no
longer a bare canvas grab: it composites into a shareable 1280x720
frame with the step's caption burned in — gold actor name, the reel's
own words — and the game's name in the corner, so a clip passed along
explains itself.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The reel's first-person mode now shows the fight, not just the rooms.
The board flourishes' event map is recast into world space (fx3d):
fireballs, bolts, and thrown things streak caster to target as glowing
billboards; landings swell and fade; blows that land on YOU wash the
screen red and jolt the camera; warp-steps and teleports flash violet;
a hurled body glides fast and straight with its eyes held steady. Nine
paintable conjuration sprites ship at public/fx3d (spec for the artist
in research/), shown in the token workshop beside the masonry.
Three rough edges sharpened along the way: sprites now project through
warp mouths under the same rigid motion the rays use, clipped by the
depth buffer to the opening; fire and warp surfaces pull a different
texture slice per world cell so a long blaze reads as one; and the
replay camera only turns toward an actor its eyes could actually see.
Two more gifts: the reel can record its first-person canvas straight
to a downloadable WebM (⏺ save video), and the About tab now shows
visitors the way into the three workshops.
One buried mine defused: rAF hands frame-start times that can precede
the tween's own clock, and a zero-length turn divided by it — one NaN
facing poisoned every ray black and re-triggered the camera effect
forever. The tween clamps and guards its phases now.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The loader walks MATERIALS to swap painted files over the procedural
bakes, and the two ground planes were never added to it — so floor.png
and ceiling.png sat served-but-unread while the renderer kept its own
flagstones. Eight materials in the list now, all eight paintable.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Zero-width planes vanish when seen end-on. Each wall edge now rises as
a thin box — masonry thickest, door joinery slimmer, fire a mere sheet
— so the ray march tests the slabs of every cell it passes through and
wall ENDS present a cap face. Corners, jambs, and junctions read as
stone with depth instead of paper. Warp traversal, stone cells, and
the rim keep their crossings; the frame budget doesn't notice.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
True floor-casting replaces the gradients and the projected seam lines:
every screen row lies at one depth, walked with a constant world-space
step and sampled from floor.png underfoot and ceiling.png overhead —
each maze cell wearing exactly one tile, so the artist's border IS the
cell seam. Distance shade and fog fold into the same per-pixel pass,
pixel buffers cache per texture (re-read when a painted file lands),
and the whole frame still clears 60fps with room to spare. Flagstones
and dark slabs ship as the starter files beside the other masonry.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Chiseled stone for the walls and rim, oak planks with a riveted iron
band for the doors, rough block for filled stone, licking flame, and a
violet spiral for the warps — dropped into public/textures/ with no
code touched, exactly as the pipeline intended.
The six materials move out of the renderer into public/textures/*.png —
repaint any of them (any size; the sampler reads each file's own scale)
and refresh, exactly as the token SVGs work. fpv/textures.ts keeps the
procedural bake as the shipped default and the stand-in while files
load, and the /?tokens gallery grows a masonry section showing the set
beside the tokens they will someday match.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Walls wear baked 64-texel textures sampled per column — running-bond
brick for the maze, darker courses for the rim, rough blocks for filled
stone, planked doors with an iron band and handle, flame-streaked fire,
swirling violet for the warps — drawn crisp with smoothing off, shaded
by distance and animated by overlay. The floor shows its tile seams:
grid lines projected onto the ground plane, occluded by the walls that
stand on them. And the workshop walks like the game plays: a tap glides
exactly one square with an eased stride, a turn swings a clean quarter,
held keys queueing the next move as each settles.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Sight now runs THROUGH the warps as the rules say: a ray reaching a
mouth re-enters at its pair and marches on, the far side swimming in
violet haze. The floor's furniture joins the scene — bushes stand tall,
safes squat, slime and tacks and pits lie low, dropped daggers glint.
And the replay reel gains a 👁 toggle: relive the catch-up or the whole
tale through your wizard's eyes, the camera turning before it strides,
easing between cells, cutting on teleports, and turning toward whoever
acted while you stood still. The /?fpv workshop grows &demo=1 — two
automatons play a stretch and the real Replay component reruns it.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Stage one of the replay vision: a canvas raycaster over the GameView —
walls on edges marched by DDA, doors with lintels, firewalls that
flicker, rim warp mouths that shimmer violet, token art billboarded and
occluded per column, torchlit vignette. It renders the view a player
would be SENT, so an illusion this wizard has not seen through stands as
solid as stone in first person too. The /?fpv workshop free-flies a
dealt maze with wall collision, a minimap eye-cone, and ?seed=&x=&y=&dir=
to stand the camera anywhere. Next: drive it from the replay reel.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
ui-coverage.test.ts fails the suite the moment an engine event has no
client handling (allowlist entries require a written reason) or a
cell/edge-targeting card is missing from the board's aim sets — the
one-at-a-time bug reports become a red test instead. The wizwar-audits
skill documents the three house audits (UI coverage, ledger inspection
by room code, the determinism gate); .claude/skills/ joins the repo so
they travel with it.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
A sweep of all 142 engine events against the client found three more
telepath-class drops and eight silent chronicle gaps. THOUGHT STEAL's
plunder and a kill's hand-spoils now get the reveal modal (generalized
from the mind-read one — title, note, the cards fanned out); your own
end-of-turn draw names its cards in the log. The mute events speak:
dispels, walls of fire rising/burning/guttering, filled squares,
crashing waterwalls, clattering thrown objects, and REUSE SPELL's
retrieval. Also verified clean: every param-taking card has collection
UI, and every cell/edge-targeting card is aimable on the board.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Ending a turn on a treasure nobody picked up now asks first (unless the
auto-grab preference is about to take it, or the grab would be refused —
laden arms, weakness, spent actions, glue, a locked safe, or your own
home where the chest already scores; the view learns gluedCells and
openSafes so the check is honest). Stepping onto ground that bites —
thornbush, tacks, pit, ooze — warns with the exact price, unless you are
mist. And the sticky draw picker no longer quietly starves anyone: a
draw below what would fit asks too.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
An optional confirmation (on by default, one checkbox to silence) catches
the classic table groans before they land: ending the turn with movement
unspent, ending it with a hand too full to take the draw, and walking off
— or ending on — your own home with a deliverable treasure still in your
arms. Preferences also learn a default automaton skill, remembered from
either the prefs panel or the lobby's tier picker.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The engine sent the caster a private handRevealedPrivate event carrying
the victim's cards; the client logged the public line and dropped the
private one on the floor. The stolen mind is now a modal — the cards
fanned out, once, until dismissed — in the trap-notice pattern.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Game 6XDY's prisoners expose a nest of turn-burners. The pathfinder
treated pits, ooze, bushes, and slime as walls in transit, so bots stood
"trapped" in pockets any human would wade out of: the march now falls
back to a teeth-gritted hazard route when no clean road exists. Bots no
longer aim attacks into (or out of) a thornbush's shelter the engine
refuses; WIZARDBLADE learns it is a blade (same square only); a cursed
IDIOT skips every rung the curse would refuse instead of burning turns
on them; BUDDY's orientation is righted — whoever pacted YOU is
untouchable, your own pacts are merely precious — and a thief standing
underfoot no longer becomes a null destination that freezes two laden
wizards on the same square forever.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The card's second power was never built. New tearTreasure command: with
STRENGTH on you, in the same square as a carrier, the tear spends your
attack; the victim keeps the treasure only on a D4 roll of 1. Per the
FAQ it is not a pickup (your turn's actions continue), and full or
weakened arms tear it loose onto the floor instead. A torn treasure's
warded owner gets their window, blind grabs flail like blind punches,
and the automatons wrestle too. A new command breaks no stored ledger,
so live games gain the grip at once.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Blind reviews over the rev-37..40 features and the gate collapse. The
scripted surgery's scars come out: bare brace blocks unwrapped (with one
hiding an unreachable scrambleHands), the amputated comment healed, the
dead events parameter unthreaded from the illusion-sight chain, the
laziness probe in perceivedBoard collapsed to the rule it always produced,
GameView.deckRev retired with its last reader, the ward's arming stub
told honestly, and every comment or test title still citing the retired
revision numbering reworded to the rule it guards. Rim mechanics unify on
rimWarpMouth and breachRim; the test suite gains plainRimWall and
pushSustained and loses its loop-shaped scars and rev-named helpers.
No behavior changes; 255 tests pass unchanged.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
All 50 rooms were retired (backed up on the droplet and in Spaces), so no
ledger needs an old branch to replay: forty revisions of deckRev gates
fold into one canonical ruleset — the newest behavior everywhere. The
ward's arming, the idiot's steering, the lazy illusion roll, the legacy
redirection swap, and the flat wave all leave with their gates; RULES_REV
restarts at 1 for whenever the rules fork again. Old-vintage test pins go
with them. The opening screen now quietly drops seats whose rooms the
server no longer knows, instead of listing them "unreachable" forever.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The full audit Wall of Fire started: WATERWALL crashes on a warp mouth,
washing both rims inward; ILLUSION WALL hangs its scrim on a mouth (the
create-wall bluff); STONE TO WATER melts a brick over a warp at both ends
and breaches a plain rim wall exactly as DESTROY WALL does — far side
washes out, a warp opens, the wave floods the fresh tunnel; the WARP WAND
bores a temporary wraparound that closes when its wall returns; and
CREATE DOOR stops hanging dead doors onto the void. Older ledgers keep
their refusals and danglings, and replay so.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
A warp mouth at the maze's edge is a corridor — the wraparound connects
it to the opposite rim — so the fire may bar it. It takes BOTH mouths
(each with its own burn-out clock), and the crossing steps through flame
for the usual 4 from either side. Older ledgers refused the cast and
replay so.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
"Small entryways in a stone wall" are stone: a door melts exactly as a
wall does — edge opens, lock state washes away, the two-point wave
crashes. Older ledgers had the refusal and replay so.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The per-step steering recalculated greedily, ping-ponging between routes
that tie at a corner and able to wall the victim off from the cure; rev 37
retires it — the march is the player's to honor, and the automatons steer
themselves. DROP OBJECT that shakes the victim's OWN treasure out of a
thief's arms is now an aid, not an attack: while carried, that treasure
cannot even be stood upon, so the curse could be unsatisfiable. Older
ledgers replay steered and strict.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Blind reviews over d2b40ec..HEAD (engine / web / server+deploy). Orphaned
doc comments rejoined their functions; the swap-meet tradables collapsed
from four pasted deriveds to one (killing the "the's treasure" label);
FEAR's aura and banner now share the engine's own dreadDistance; the
long-press peek got one home; rulebook.ts stopped wearing JSON quotes;
process-named tests and war-story comments now state the constraints they
pin; the protocol doc caught up to its handlers; verify-ledgers.sh can
actually count failures; the runbook learned about the determinism gate
and the nightly backups. No behavior changes — 255 tests and all 48
production ledgers replay identically.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Watch a room by code alone: no seat, no ledger line, no voice in chat.
Views and events are redacted for the empty viewer id (which no seat can
hold), so hands, wards, ambushes and boobytrap truths stay dark. The
table sees only a head count.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The guard-the-gold rung cast SAFE/GLUE at a floor treasure with no
line-of-sight check; the engine refused the cast and the fallback
burned the bot's whole turn.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
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
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
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
'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
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
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
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
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
'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
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
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
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
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
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
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
'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
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
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
'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
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
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
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
'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
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
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
'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
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
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
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
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
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
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
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
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
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
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
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
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
'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
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
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
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
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
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
'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
'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
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
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
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