diff --git a/src/lib/components/Board.svelte b/src/lib/components/Board.svelte index 4a521b7..f49068c 100644 --- a/src/lib/components/Board.svelte +++ b/src/lib/components/Board.svelte @@ -3,15 +3,16 @@ // on them as tokens that slide and fade, and two taps or a keyboard to // move. Above it, a strip says whose move it is and what the side is // for; beside it, the record of moves, each one a click from being shown - // on the board. Copenhagen is fresh oak and clean stone; Tablut, the - // older game, is grey, bleached and a little uneven, by the tokens under - // data-set and a heavier grain and warp in the filters. + // on the board. Copenhagen is a newly crafted oak reenactment set; + // Tablut evokes an excavated stone board and worn counters. This is an + // artistic treatment, not a claim to reconstruct a particular find. import TableTalk from './TableTalk.svelte'; import { beyond, cellOf, cornersOf, isEdge, movesFrom, rulesetOf, sideOf, throneOf, type Move, type Side } from '$lib/game'; import type { Room } from '$lib/net/room.svelte'; import { prefs, reducedMotion } from '$lib/prefs.svelte'; let { room }: { room: Room } = $props(); + const artId = $props.id(); const g = $derived(room.state!); const set = $derived(rulesetOf(g)); @@ -54,7 +55,7 @@ const chips = $derived.by(() => { if (!worn) return [] as { x: number; y: number; r: number; d: string }[]; const spots = [ - [1, 0, 3], [size - 1, 2, 0], [3, size - 1, 1], [size - 2, size - 2, 2], [0, size - 3, 3], [size - 4, 0, 1], [2, 4, 0] + [0, 0, 0], [size - 1, 2, 1], [3, size - 1, 2], [0, size - 3, 3], [size - 4, 0, 1] ] as const; return spots.map(([cx, cy, corner]) => { const x = PAD_L + cx * CELL + (corner === 1 || corner === 2 ? CELL : 0); @@ -71,8 +72,8 @@ const w = PAD_L + size * CELL; const h = PAD_T + size * CELL; return [ - `M${PAD_L + CELL * 0.6} ${PAD_T + 2} c 6 14, -4 22, 8 36 s 2 18, 14 26 s 4 10, 2 22`, - `M${w - 3} ${h - CELL * 2.4} c -12 4, -18 -6, -30 2 s -14 12, -26 8 s -12 -4, -18 6` + `M${PAD_L + 22} ${PAD_T} l3 11 -2 7 5 12 -1 9 4 8 -2 12 m-1 -29 -8 5 -3 7`, + `M${w} ${h - 62} l-12 3 -6 -2 -9 6 -7 1 -5 6 -10 3 m22 -10 -2 -7 -5 -4` ]; }); @@ -270,31 +271,55 @@
- - - - + + + + + + + + + - - - + + + - - - - + + + + + {#each ['attacker', 'defender', 'king'] as kind (kind)} + + + + + + {/each} - + + {#if worn} - + + {:else} + {#each [0.22, 0.51, 0.79] as part (part)} + + {/each} {/if} + {#each showCoords ? Array.from({ length: size }, (_, n) => n) : [] as n (n)} {String.fromCharCode(97 + n)} {size - n} {/each} - + {#each g.cells as piece, i (i)} {@const c = cellOf(size, i)} {@const x = PAD_L + c.x * CELL} @@ -323,11 +348,12 @@ {/if} {/each} - {#each chips as chip (chip.d)} - - {/each} - {#each cracks as crack (crack)} - + {#each [throne, ...corners] as place (place)} + {@const c = cellOf(size, place)} + {/each} {#each tokens as t (t.id)} {@const c = cellOf(size, t.at)} @@ -340,11 +366,21 @@ style="transform: translate({cx}px, {cy}px)" pointer-events="none" > - - - {#if t.piece === 'k'} - - {/if} + + + + + + + + {#if worn} + + {/if} + {#if t.piece === 'k'} + + + {/if} + {/each} @@ -400,16 +436,22 @@ padding: 0 var(--gutter); max-width: 1280px; margin: 0 auto; - /* Copenhagen: fresh oak, clean stone. */ - --wood: #8a5a2b; + /* Copenhagen: a crafted oak board, polished counters and brass inlay. */ + --surface-light: #bd935c; + --surface-dark: #79502d; + --rim-light: #e0bf84; + --attacker-light: #63564a; + --defender-light: #fff4d8; + --king-light: #ffe4a0; + --wood: #a77945; --wood-line: rgba(30, 16, 6, 0.55); - --coord: rgba(255, 240, 210, 0.55); + --coord: #302216; --square: rgba(255, 240, 210, 0.08); --square-edge: rgba(255, 250, 235, 0.11); --throne: rgba(240, 165, 58, 0.35); - --corner: rgba(224, 101, 92, 0.35); + --corner: rgba(109, 52, 29, 0.22); --attacker: #2a2320; - --attacker-rim: #0d0a08; + --attacker-rim: #211a15; --defender: #ece4d0; --defender-rim: #b9ab8b; --king: #f0d58a; @@ -417,17 +459,23 @@ --crown: #6b4a0f; } - /* Tablut: the older game, cut in stone and kept in a long hall for a thousand years. */ + /* Tablut: an excavated-object aesthetic, with limestone and aged counters. */ .board[data-set='tablut'] { + --surface-light: #aaa18b; + --surface-dark: #797564; + --rim-light: #c4b99e; + --attacker-light: #625e51; + --defender-light: #e2d5b3; + --king-light: #e5cc92; --wood: #8a8578; --wood-line: rgba(36, 32, 27, 0.45); - --coord: rgba(30, 26, 20, 0.5); + --coord: #37362c; --square: rgba(255, 250, 235, 0.05); --square-edge: rgba(255, 250, 235, 0.09); --throne: rgba(120, 100, 70, 0.4); --corner: transparent; --attacker: #3d3530; - --attacker-rim: #1c1714; + --attacker-rim: #29281f; --defender: #cfc4ad; --defender-rim: #8c8069; --king: #c9b27a; @@ -510,12 +558,12 @@ } .wood { - fill: var(--wood); - transition: fill 1.2s ease; + stroke: var(--surface-dark); + stroke-width: 1.4; } .stain { - fill: rgba(120, 110, 96, 0.22); + fill: #fff; pointer-events: none; } @@ -528,8 +576,8 @@ .crack { fill: none; - stroke: rgba(24, 20, 16, 0.55); - stroke-width: 0.9; + stroke: rgba(43, 39, 29, 0.48); + stroke-width: 0.5; stroke-linecap: round; pointer-events: none; } @@ -538,13 +586,14 @@ fill: var(--coord); font-family: var(--font); font-size: 9px; + font-weight: 600; pointer-events: none; } .square { fill: var(--square); stroke: var(--wood-line); - stroke-width: 1; + stroke-width: 0.65; cursor: default; transition: fill 0.3s ease; } @@ -594,40 +643,29 @@ opacity: 0; } - .piece .shadow { - fill: rgba(0, 0, 0, 0.35); - } + .board-rim { fill: none; stroke: var(--rim-light); stroke-width: 0.7; opacity: 0.65; pointer-events: none; } + .join { fill: none; stroke: #50351f; stroke-width: 0.6; opacity: 0.18; pointer-events: none; } + .surface-wear { pointer-events: none; } + .crack-light { fill: none; stroke: #e1d6bd; stroke-width: 0.55; opacity: 0.45; } + .inlay { fill: none; stroke: var(--rim-light); stroke-width: 0.8; opacity: 0.75; pointer-events: none; } + .board[data-set='tablut'] .inlay { stroke: #494638; opacity: 0.45; } - .piece .body { - stroke-width: 2; - transition: - fill 1.2s ease, - stroke 1.2s ease; - } - - .piece.attacker .body { - fill: var(--attacker); - stroke: var(--attacker-rim); - } - - .piece.defender .body { - fill: var(--defender); - stroke: var(--defender-rim); - } - - .piece.king .body { - fill: var(--king); - stroke: var(--king-rim); - } - - .piece .crown { - fill: var(--crown); - } - - .piece.selected .body { - stroke: var(--frost); - stroke-width: 3; - } + .piece { --piece-rim: var(--defender-rim); } + .piece.attacker { --piece-rim: var(--attacker-rim); } + .piece.king { --piece-rim: var(--king-rim); } + .piece .shadow { fill: #16130e; opacity: 0.28; } + .piece .base { fill: var(--piece-rim); } + .piece .body { stroke: var(--piece-rim); stroke-width: 0.65; } + .bevel-light { fill: none; stroke: #fff1cc; stroke-width: 0.9; opacity: 0.48; stroke-linecap: round; } + .bevel-dark { fill: none; stroke: #211d16; stroke-width: 0.8; opacity: 0.3; stroke-linecap: round; } + .turned { fill: none; stroke: var(--piece-rim); stroke-width: 0.45; opacity: 0.35; } + .counter-wear { fill: none; stroke: #534b37; stroke-width: 0.5; opacity: 0.3; stroke-linecap: round; } + .attacker .counter-wear { stroke: #d6c6a3; opacity: 0.23; } + .board[data-set='tablut'] .bevel-light { opacity: 0.25; stroke-width: 1.1; } + .board[data-set='tablut'] .turned { opacity: 0.12; } + .piece .crown { fill: var(--crown); stroke: var(--crown); stroke-width: 0.7; stroke-linejoin: round; } + .piece .crown-gleam { fill: #f8e5b2; stroke: #f8e5b2; stroke-width: 0.9; opacity: 0.7; } + .piece.selected .body { stroke: var(--frost); stroke-width: 2.5; } .how { max-width: 620px; diff --git a/src/routes/guide/+page.svelte b/src/routes/guide/+page.svelte index 1176922..5d666de 100644 --- a/src/routes/guide/+page.svelte +++ b/src/routes/guide/+page.svelte @@ -1,5 +1,10 @@ @@ -8,9 +13,9 @@
- Back to the hall · The rules + {#if room}Back to your game · {/if}Back to the hall · The rules

How to play

-

A walk through the page, from the hall to a first game. The game's own rules are on the rules page.

+

A walk through the page, from the hall to a first game. The game's own rules are on the rules page.