Commit Graph
163 Commits
Author SHA1 Message Date
Eric WagonerandClaude Fable 5 0530ecb039 The helm yields the glass while a card is aimed
The drive chevrons are buttons over the canvas edges, and the
back-stride strip owns the bottom band — exactly where an adjacent
square's floor renders. With a card selected, hovering there showed
no target and a click would have STEPPED backward instead of casting
(the tacks report: the pane refused what the map allowed). While a
card is aimed the strips now fade and stop catching the pointer, so
every pixel of the pane hovers and clicks as a target; the arrow keys
still steer throughout.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015RCWSTnb1KYTPyL4GmhGnF
2026-08-27 15:21:05 -04:00
Eric WagonerandClaude Fable 5 728f9fc28a The feet tray learns hazards and the warp step
Two blind spots close. The active body — wizard or ridden mount —
standing on a dimensional-warp token gets a "step through the warp"
button in the feet tray, dispatching warpStep for the wizard and
creatureWarpStep for the mount (the command the RNRX troll report
earned). And whatever you stand IN shows as a warning chip: tacks,
slime, dust, a pit, the ooze — the near plane's last secrets told.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015RCWSTnb1KYTPyL4GmhGnF
2026-08-27 15:19:22 -04:00
Eric WagonerandClaude Fable 5 e499df22d7 The facing ribbon rides the mount
While the pane possesses a creature, the keymap's golden ribbon moves
to the mount's token — same shallow triangle, sized to the smaller
body, turning with the borrowed eyes — and leaves the wizard's brow
until the rider returns.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015RCWSTnb1KYTPyL4GmhGnF
2026-08-27 15:02:28 -04:00
Eric WagonerandClaude Fable 5 1595118410 Possession: ride your creature's eyes; the cockpit stops flinching
The pane learns the menagerie. On your turn, a "ride" button appears
for each creature you command with moves or claws unspent; mounting
seats the camera in its skull facing its longest corridor, hides its
own hide from its eyes, and hands it the helm — chevrons and arrows
stride IT, an adjacent floor click steps it, and clicking an enemy
sharing its square lands its blow. A banner shows the mount's
remaining legs; one tap (or the turn passing, or the mount dying)
returns you to your own eyes, where the director reseats you fresh.

Two cockpit-dignity fixes from live play ride along: a cutaway to
your own body now plays only for things done TO you — dropping a
dagger no longer flings your eyes out of your skull — and a standing
camera is never "rescued" off a wall you deliberately faced; the
deepest-corridor default applies only to fresh cuts.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015RCWSTnb1KYTPyL4GmhGnF
2026-08-27 14:56:29 -04:00
Eric WagonerandClaude Fable 5 19752e55e1 Forfeit legs earn no scolding; the pane sees your boots
Picking up an object ends the turn's actions AND movement — yet the
end-turn caution still tallied the unspendable points as regret. The
unspent-movement reason now stays quiet once actions have ended:
those points cannot be spent, only mourned.

And the raycaster has no downward pitch, so whatever lay in your own
square — a treasure, a dropped blade — was invisible from inside the
cockpit. An "at your feet" tray now rides the pane's bottom edge on
your turn: your square's floor treasures and objects as clickable
icons, each a one-tap pickup through the same commands the board's
buttons send.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015RCWSTnb1KYTPyL4GmhGnF
2026-08-27 13:51:27 -04:00
Eric WagonerandClaude Fable 5 22c443d2c5 The crosshair answers before the click commits
Hovering the pane now shows what a click would do: a wizard or
creature outlines in gold with its name at the crosshair, a wall or
door face lights across every column it owns, and a floor square
draws its perspective-true quad on the ground. Warp-bent ground still
targets truly but labels itself "through the warp" rather than
drawing a quad in the wrong geometry. And when a cell-target card is
selected, the ineligible ground dims in the 3D view itself — the same
litCells the board's shadow uses, rasterized into the floor pass.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015RCWSTnb1KYTPyL4GmhGnF
2026-08-26 12:35:12 -04:00
Eric WagonerandClaude Fable 5 42d872df6d Milestone two: the pane becomes the wand hand
Clicks in the first-person view now act. The renderer keeps what the
last frame knew — per-column depth, warp bends, every wall hit's edge,
every sprite's screen rect with its identity — and hitTest inverts the
projection: the nearest visible sprite answers as its wizard or
creature, a struck wall or door answers as its edge, and the ground
answers as the square under the pixel, warp-bent columns mapping their
virtual floor back to real cells through the warp's own rigid motion.
The pane hands each target to the very functions the top-down board's
clicks use, so pane and map can never disagree: click the floor ahead
and you walk there; click a door with a key selected and the lock
turns; click a wizard with an attack and the spell flies.

The keymap token now wears a golden wedge showing the camera's compass
quadrant — the cockpit and the chart always agree on which way you
face. Verified live: a floor click became a real move command in the
room ledger, edge clicks resolve and defer correctly, and the wedge
tracks quarter-turns.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015RCWSTnb1KYTPyL4GmhGnF
2026-08-26 12:28:51 -04:00
Eric Wagoner aac06dd2b5 Merge branch 'main' into first-person-play 2026-08-26 12:13:13 -04:00
Eric WagonerandClaude Fable 5 9af7bd80ce The host clears seats and closes rooms
Two lobby-lifecycle gaps from tonight's duels (a token lost to a
client bug left an unkickable ghost seat holding a chair in VQJW).
kickSeat: the host removes any other seat from an unstarted room —
the kick is a ledger line so restarts replay it, and a kicked live
socket is set adrift with notice. abandonRoom: the host dissolves a
lobby or a finished game; every member is notified and detached, and
the ledger is archived to rooms-abandoned/ — moved, never deleted.
The lobby shows hosts a ✕ per seat and an abandon-room control.
Proven live: kick with notice, kick surviving a server restart, and
abandonment archiving its ledger.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015RCWSTnb1KYTPyL4GmhGnF
2026-08-26 11:05:42 -04:00
Eric WagonerandClaude Fable 5 dd87f1d843 Monsters ride the wormhole; mental force fails loudly (rules rev 5)
Two findings from the first human-vs-Claude duel (room 9UA6). A
creature standing on a DIMENSIONAL WARP token had no way through it —
warpStep obeys only wizards. The new creatureWarpStep command steps a
commanded creature through the tokens under the walker's rules: one
move spent, solid stone refuses it, FEAR holds the beast, touch
effects greet whoever shares the landing; the board taps the paired
token like a rim mouth. Replay-safe ungated — a new command widens
nothing that was recorded.

MENTAL FORCE ate its card silently when the destination lay beyond
the victim's three walked spaces — the caster spent an attack and
learned nothing (ask me how I know). Rev 5 refuses the impossible
destination up front with the card kept; when the victim slips out of
range between cast and resolution, a mentalForceFizzled event tells
the table what happened instead of nothing. All 20 production ledgers
verified, the duel's own among them; 283 tests.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015RCWSTnb1KYTPyL4GmhGnF
2026-08-25 23:59:31 -04:00
Eric WagonerandClaude Fable 5 64e4e243dc The MASTER KEY earns its display
"Display Immediately," says the card — now the key lives up to it.
Cast bare (a new Display button beside the hold-the-door checkbox),
it goes straight on display; once displayed, it turns in every lock
its bearer walks through — no more casting at each door — with the
door relocking behind them at turn's end like any picked lock, and
the doorUnlocked event still swinging the door in the reels. Cast at
an adjacent door it still works one lock like PICK LOCK, including
holding the door open for others. A JAMmed LOCK refuses it as ever,
and the adjacent peek through workable locks already rode the rev-2
sight rules. Replay-safe ungated: bare casts were never recorded
(they were refused), displayed cards still count against the hand
limit, and walking through a locked door only widens what is
accepted.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015RCWSTnb1KYTPyL4GmhGnF
2026-08-25 20:46:23 -04:00
Eric WagonerandClaude Fable 5 b16bbe82a6 The masthead wears its deploy stamp
A small yyyy.mm.dd.hh.mm mark beside the edition line, baked in at
build time — and the deploy builds moments before it ships, so the
stamp reads as deploy time.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015RCWSTnb1KYTPyL4GmhGnF
2026-08-25 14:34:06 -04:00
Eric WagonerandClaude Fable 5 b8bb60cf6d Milestone one: the pane becomes the cockpit
FPV play begins. On your turn the pane takes the helm: arrows or WASD
— quarter-turns are free camera, a stride issues a REAL move command
through the same cautions and refusals as a board click, and a wall
bounces you with the table's own toast. While the player steers, the
director keeps its hands off the idle facings; your own magic still
turns your head, and cutaways still fire. The layout inverts to match
the mode: the 3D view is the primary window into the game, the
top-down board reduced to a keymap beneath it, with the control hint
in the pane's corner. Typing in chat is never hijacked.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-24 00:02:16 -04:00
Eric WagonerandClaude Fable 5 c7109fcddf The pane sits square on the board's shoulders
Eric's layout call: the first-person pane wears exactly the board's
width, directly above it. A shrink-wrapped column stacks the two, with
the pane held out of the intrinsic sizing (width:0, min-width:100%) so
the BOARD alone decides how wide the column is; the canvas keeps its
aspect as it scales.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-23 23:46:20 -04:00
Eric WagonerandClaude Fable 5 e6ef5f6315 First person comes to the living table (branch work)
A pane above the board plays the game through your own eyes while you
play it — the board below stays the tactical truth. One new module,
fpv/director.ts, extracts the reel's directorial instincts (the aim
ladder, the hurl test, the glide gatherer) so the replay and the live
pane share one eye and can never drift; Replay is refactored onto it
unchanged. LiveFirstPerson.svelte feeds the shared FirstPerson
renderer from the live event stream: every batch plays through the
same fx pipeline as the instant replay — projectiles, door swings,
conjurations growing — while the camera walks your strides, turns to
your aims and to actors in your sight, cuts away (with your own body
in frame) to deeds beyond it, and never idles nose-to-brick. Bodies
glide between server views. A ✕ hides the pane; the liveFp preference
(on by default) brings it back.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-23 23:29:03 -04:00
Eric WagonerandClaude Fable 5 7a32370ccb Credibility pass: the reel's scars sanded, the veil finally hung
Three blind reviews over the first-person arc, every finding verified
against the source. History-narrating comments made timeless or cut;
the stacked BUDDY comment collapsed to one voice. Dead code out: the
orphaned FACE copy, the DIR_ANGLE duplicate, the dead loop-counter
poke, the impossible-state sentinel. The never-produced "warp" hit
kind resolved the right way — warp mouths now hang a translucent veil
of the painted warp texture, so art that never rendered finally does.
Types tightened (SlabStrike named once, ShareData rides CatchUpStep,
botTier loses its casts), the gallery reads MATERIALS instead of a
hand-copied list, the chronicle resets through one helper, a
superseded share mint rejects instead of stranding, and the conjured
safe gains the growth key its siblings had. Tests lose a triple
assignment, a tautology, and two self-swallowing regex alternatives.
The sprite spec — which still told the artist to paint for additive
compositing the renderer no longer uses — now describes the renderer
that exists.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-23 21:41:11 -04:00
Eric WagonerandClaude Fable 5 5fc5805354 Odds, ends, and every missing effect: doorways dressed, victory earns its fireworks
The audit Eric called for, delivered whole. Open doors are DOORWAYS
now: stone jamb posts at both ends and a lintel hung across the top
(paintable as textures/doorframe.png), the way through open to the eye.
Battle damage shows — the engine's per-edge wallDamage wears painted
cracks into any wall, heavier as harm mounts. The wall safe stands as
a strongbox volume instead of a flat token. Hedges take root: an
underbrush floor decal covers the whole square beneath them (Eric's
report — a billboard at center depth can't reach the floor trapezoid's
near edge), and the hedge itself widens past the cell. Rubble
stretches across the fallen wall's full gap, corner piles landing at
the posts, exactly as its art was painted.

The first-person effect gaps close: victory now throws SIX fireworks
climbing over the winner's home with gold washing the screen; sector
rotations flash violet and heave the whole world; the Thumb of God
lands with a burst and a shudder; walls conjured from nothing rise in
stone dust; and every hazard pratfall plays — pit falls (with a dark
drop and jolt for the faller's own eyes), ooze slips, tack yelps,
thorn snaps, slime, dust. Dying in first person fades long and dark.

And the whole tale travels: a finished game's full replay carries the
share button too — turn -1 mints a link to every turn of the game,
each through its wizard's own eyes, titled for the winner's triumph.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-23 19:32:42 -04:00
Eric WagonerandClaude Fable 5 a28d27eedc The camera always wears the turn-taker's eyes, and knows whose turn zero is
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>
2026-08-23 18:56:02 -04:00
Eric WagonerandClaude Fable 5 6788de2f6e The chronicle remembers everything, and holds still while you read it
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>
2026-08-23 18:35:15 -04:00
Eric WagonerandClaude Fable 5 4838996cf0 Share a turn with the world: /watch links, cards and chrome included
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>
2026-08-23 17:34:00 -04:00
Eric WagonerandClaude Fable 5 f52d0d88a9 The instant replay: a chronicle line's eye relives the turn, firsthand
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>
2026-08-23 16:05:07 -04:00
Eric WagonerandClaude Fable 5 3c479eddbb The maze through a wizard's eyes: the first-person raycaster (/?fpv)
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>
2026-08-23 12:19:03 -04:00
Eric WagonerandClaude Fable 5 813f92d419 The full telepath audit: every private glimpse held up, every silence voiced
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>
2026-08-23 11:53:17 -04:00
Eric WagonerandClaude Fable 5 6165d43639 Unspent legs are no regret atop another wizard's gold
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-23 11:10:23 -04:00
Eric WagonerandClaude Fable 5 ef921a0c2b Three more cautions: the un-grabbed chest, the biting ground, the starved draw
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>
2026-08-23 11:04:05 -04:00
Eric WagonerandClaude Fable 5 6e1ccb0195 "Hold on —": cautions before easy-to-regret plays, and a house bot tier
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>
2026-08-23 10:59:26 -04:00
Eric WagonerandClaude Fable 5 bde68aa85c Telepath's glimpse gets held up to the light
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>
2026-08-23 10:49:35 -04:00
Eric WagonerandClaude Fable 5 76207c6264 Strength gets its grip: tear a treasure from a wizard's arms
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>
2026-08-21 13:44:50 -04:00
Eric WagonerandClaude Fable 5 4a91d56d24 Credibility pass: the collapse loses its scaffolding
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>
2026-08-21 13:04:01 -04:00
Eric WagonerandClaude Fable 5 8a50ff7f36 The great simplification: every vintage gate collapses, the count restarts at 1
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>
2026-08-21 12:45:35 -04:00
Eric WagonerandClaude Fable 5 2afc4e3973 Stone to Water melts doors too (rules rev 38)
"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>
2026-08-21 11:43:27 -04:00
Eric WagonerandClaude Fable 5 118bfd236b IDIOT trusts the feet and yields to a jailbreak drop (rules rev 37)
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>
2026-08-21 11:11:25 -04:00
Eric WagonerandClaude Fable 5 6adcbe23b5 Credibility pass: the accretion sanded smooth
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>
2026-08-21 10:58:08 -04:00
Eric WagonerandClaude Fable 5 3445d12206 The Peanut Gallery: nameless read-only spectators, counted but never named
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>
2026-08-21 10:41:33 -04:00
Eric WagonerandClaude Fable 5 db0eeebcd5 A sprung Ward earns its victim a modal, not a buried log line
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-20 21:21:00 -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 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 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 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 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 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 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