From 4212bf9419d3c3fa135bae78947b407c056700aa Mon Sep 17 00:00:00 2001 From: Eric Wagoner Date: Mon, 26 Oct 2026 18:12:46 -0400 Subject: [PATCH] Tap any piece and a panel tells what it is, what it can do from where it stands, how it moves, why Gygax put it in, and how to play it Co-Authored-By: Claude Fable 5.1 Claude-Session: https://claude.ai/code/session_01CCLa2PaEeCj8njQZSWGqHx --- src/lib/components/Board.svelte | 56 +++++++++- src/lib/components/BoardArtwork.svelte | 18 ++- src/lib/components/PiecePanel.svelte | 146 +++++++++++++++++++++++++ src/lib/game/lore.ts | 127 +++++++++++++++++++++ src/routes/guide/+page.svelte | 2 + static/guide/panel.png | Bin 0 -> 91887 bytes 6 files changed, 344 insertions(+), 5 deletions(-) create mode 100644 src/lib/components/PiecePanel.svelte create mode 100644 src/lib/game/lore.ts create mode 100644 static/guide/panel.png diff --git a/src/lib/components/Board.svelte b/src/lib/components/Board.svelte index 72ba834..fbf2f5a 100644 --- a/src/lib/components/Board.svelte +++ b/src/lib/components/Board.svelte @@ -4,9 +4,10 @@ // strip says whose move it is; beside them the record, each move a click // from being shown on the boards, and the talk. import TableTalk from './TableTalk.svelte'; + import PiecePanel from './PiecePanel.svelte'; import BoardArtwork, { type Token } from './BoardArtwork.svelte'; import { - describe, legalMovesFrom, squareName, sideOf, kindOf, kingSquare, inCheck, levelOf, fileOf, rankOf, idx, frozen, notation, NAMES, FILES, RANKS, LEVELS, + describe, legalMovesFrom, movesFrom, squareName, sideOf, kindOf, kingSquare, inCheck, levelOf, fileOf, rankOf, idx, frozen, notation, NAMES, FILES, RANKS, LEVELS, type Move, type Side } from '$lib/game'; import type { Room } from '$lib/net/room.svelte'; @@ -100,6 +101,15 @@ // --- Choosing and moving --------------------------------------------------- let selected = $state(null); const targets = $derived(selected === null ? [] : legalMovesFrom(g.cells, selected, g.setup)); + /** Any piece, tapped to read about it; the panel beside the boards tells what it is and what it can do from there. */ + let inspected = $state(null); + $effect(() => { + // A piece that moved or was taken is no longer where the panel looked. + void g.moves.length; + inspected = null; + }); + /** Where the inspected piece could go, shown faintly when it is not yours to move. */ + const reach = $derived(inspected !== null && inspected !== selected && g.cells[inspected] !== '' && !g.over ? movesFrom(g.cells, inspected, g.setup) : []); let liveText = $state(''); function announce(text: string) { liveText = text; @@ -117,8 +127,14 @@ const wordFor = (i: number) => `${sideOf(g.cells[i]) === 'gold' ? 'Gold' : 'Scarlet'} ${NAMES[kindOf(g.cells[i])]}`; async function tap(i: number) { - if (!yourMove || room.sending || animating) return; + if (room.sending || animating) return; reviewing = null; + if (!yourMove) { + // Not your move, or no seat: a tap on a piece still opens its panel. + inspected = g.cells[i] !== '' ? (inspected === i ? null : i) : null; + if (inspected !== null) announce(`${wordFor(i)} on ${label(i)}. About this piece is shown beside the boards.`); + return; + } if (selected !== null && targets.includes(i)) { if (prefs.confirmMoves === true) { pending = { from: selected, to: i }; @@ -129,8 +145,10 @@ return; } pending = null; + inspected = g.cells[i] !== '' ? (inspected === i && selected === i ? null : i) : null; if (sideOf(g.cells[i]) === mySide) { selected = selected === i ? null : i; + if (selected === null) inspected = null; if (selected !== null) { const to = legalMovesFrom(g.cells, i, g.setup); const why = frozen(g.cells, i) ? ' It is frozen by the Basilisk beneath it.' : ''; @@ -166,6 +184,7 @@ void tap(i); } else if (e.key === 'Escape') { selected = null; + inspected = null; reviewing = null; pending = null; announce('Selection cleared.'); @@ -207,7 +226,7 @@ {#if room.error}

{room.error}

{/if}
- +

{liveText}

@@ -216,11 +235,16 @@ Back to the hall {:else if yourMove} -

Tap a piece, then a square on any board. With a keyboard: arrows to move about a board, Page Up and Page Down to change boards, Enter to pick up and to set down, Escape to cancel.

+

Tap a piece, then a square on any board. Tap any piece, yours or not, to read what it is and what it can do. With a keyboard: arrows to move about a board, Page Up and Page Down to change boards, Enter to pick up and to set down, Escape to cancel.

{/if}