Design pass: the client becomes Eric's table

The design system is the physical set itself, taken from the scans:
card-stock cream, warm ink, and the six wizard marker colors, laid on
a dark leather tabletop. Cards in your hand are now the actual cards —
vertical corner rails (ATTACK / L.O.S. / ADJACENT), condensed gothic
titles, brown body text on cream, number cards as big bordered
numerals with per-value border styles; selecting lifts a card from
the fan. The board matches the physical tiles: ink-outlined white
brick walls on cracked flagstone, plank doors, eight-point home stars
in each wizard's color, swirled treasure discs, warp arrows. The
sidebar is paper: a turn slip, the rulebook's own hand-scrawled
life-points score sheet (Caveat over ruled lines), and a typewritten
chronicle that scrolls itself. The lobby is the box lid. Type:
Oswald condensed display / Archivo Narrow body / Courier Prime log.
Buttons are ink stamps. Board height-caps so board, actions, and the
full hand share one screen; responsive stack below 900px; reduced
motion respected. Verified with live screenshots at 1440x900.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Eric Wagoner
2026-08-15 23:21:03 -04:00
co-authored by Claude Fable 5
parent c9524a37db
commit 9501a85be4
4 changed files with 705 additions and 243 deletions
+55 -24
View File
@@ -91,17 +91,28 @@
<!-- homes & treasure spaces -->
{#each view.players as p (p.id)}
<text
x={p.home.x * CELL + CELL / 2} y={p.home.y * CELL + CELL / 2 + 2}
class="home" fill={playerColor(p.id)}
>✦</text>
{@const hx = p.home.x * CELL + CELL / 2}
{@const hy = p.home.y * CELL + CELL / 2}
{@const R = CELL * 0.36}
{@const r = CELL * 0.14}
<polygon
points={Array.from({ length: 16 }, (_, i) => {
const rad = (Math.PI / 8) * i - Math.PI / 2;
const len = i % 2 === 0 ? R : r;
return `${hx + Math.cos(rad) * len},${hy + Math.sin(rad) * len}`;
}).join(" ")}
class="home-star" fill={playerColor(p.id)}
/>
{/each}
{#each view.treasures as t (t.id)}
{#if t.position}
<circle
cx={t.position.x * CELL + CELL / 2} cy={t.position.y * CELL + CELL * 0.72}
r={7} class="treasure" fill={playerColor(t.owner)}
/>
{@const tx = t.position.x * CELL + CELL / 2}
{@const ty = t.position.y * CELL + CELL * 0.72}
<g class="treasure-g">
<circle cx={tx} cy={ty} r={8} class="treasure" fill={playerColor(t.owner)} />
<circle cx={tx} cy={ty} r={4.5} class="treasure-swirl" />
<circle cx={tx} cy={ty} r={1.6} class="treasure-core" />
</g>
{/if}
{/each}
@@ -210,7 +221,7 @@
onkeydown={() => {}}
class="wizard"
>
<circle {cx} {cy} r={12} fill={playerColor(p.id)} stroke="#111" stroke-width="1.5" />
<circle {cx} {cy} r={12} fill={playerColor(p.id)} stroke="#2b2218" stroke-width="2" />
<text x={cx} y={cy + 4} class="wizard-label">{p.id[0]?.toUpperCase()}</text>
{#if p.carriedTreasureId}
<circle cx={cx + 9} cy={cy + 9} r={5} class="carried" />
@@ -256,21 +267,38 @@
<style>
.board {
width: 100%;
max-width: 640px;
background: #d8d2c4;
border: 3px solid #4a4438;
border-radius: 4px;
max-width: 680px;
background: #e3dcc7;
border: 7px solid #2b2218;
border-radius: 3px;
box-shadow:
0 0 0 2px #b7ad92,
0 12px 34px rgba(0, 0, 0, 0.6);
}
.floor {
fill: #e8e2d4;
stroke: #b8b0a0;
stroke-width: 1;
fill: #e3dcc7;
stroke: #b7ad92;
stroke-width: 1.1;
stroke-dasharray: 4 2.5;
cursor: pointer;
}
.floor:hover { fill: #f2ecda; }
.wall { fill: #4a4438; }
.door { fill: #8b5a2b; }
.firewall { fill: #e0442a; }
.floor:hover { fill: #efe8d2; }
.wall {
fill: #f2ecd8;
stroke: #2b2218;
stroke-width: 1.6;
}
.door {
fill: #8b5a2b;
stroke: #2b2218;
stroke-width: 1.4;
rx: 2;
}
.firewall {
fill: #d0342c;
stroke: #7c1a14;
stroke-width: 1.2;
}
.stone { fill: #6a6458; stroke: #3a362e; stroke-width: 2; }
.bush { fill: #2e7d32; stroke: #1b4d1e; stroke-width: 2; }
.rose { fill: #2e7d32; stroke: #b0245a; stroke-width: 3; }
@@ -289,12 +317,15 @@
.creature-body { fill: #3b3428; stroke-width: 2.5; }
.creature-body.selected { fill: #6b5a34; }
.creature-label { font-size: 11px; font-weight: bold; fill: #f4ead2; text-anchor: middle; pointer-events: none; }
.home { font-size: 26px; text-anchor: middle; dominant-baseline: middle; opacity: 0.85; }
.treasure { stroke: #111; stroke-width: 1.2; }
.warp { font-size: 13px; text-anchor: middle; fill: #6a5f4b; font-weight: bold; }
.home-star { stroke: #2b2218; stroke-width: 1.4; opacity: 0.92; }
.treasure { stroke: #2b2218; stroke-width: 1.3; }
.treasure-swirl { fill: none; stroke: #2b2218; stroke-width: 1.2; stroke-dasharray: 5 2.2; }
.treasure-core { fill: #2b2218; }
.warp { font-size: 14px; text-anchor: middle; fill: #2b2218; font-weight: bold; opacity: 0.65; }
.wizard { cursor: pointer; }
.wizard-label {
font-size: 13px; font-weight: bold; fill: white;
font-family: "Oswald", sans-serif;
font-size: 13px; font-weight: 600; fill: #f4ead2;
text-anchor: middle; pointer-events: none;
}
.carried { fill: gold; stroke: #111; stroke-width: 1; }