The glass board is open to everyone: the gate and its word are gone, and the toggle shows under the flat boards at every table and on the told game

The flat boards stay the default; the glass board is a tap away.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CCLa2PaEeCj8njQZSWGqHx
This commit is contained in:
Eric WagonerandClaude Fable 5.1 committed 2026-10-27 12:54:54 -04:00
1 parent 9a43952ad1
commit 5099cf67e7
5 files changed
+5 -49

No files matched your search

+3 -3
View File
@@ -34,9 +34,9 @@ tables, the Peanut Gallery, the ledgers and the ops tools are the kit's;
takes the same taps as the flat boards. The figures in `static/figures/`
are glTF, one per kind, with a `livery` material the view recolours per
side; `docs/figures-brief.md` is what they were made from. three.js and
the figures load only when the view is opened. Until the keeper opens it
to everyone, the view shows only to a browser let in through
`src/lib/glass.svelte.ts`.
the figures load only when the view is opened. The flat boards are the
default; the glass board is offered under them at the table and on the
told game.
- The guide's figures are screenshots in `static/guide/`, taken from the
running site at 960 pixels wide.
+1 -4
View File
@@ -14,7 +14,6 @@
} from '$lib/game';
import type { Room } from '$lib/net/room.svelte';
import { prefs, reducedMotion } from '$lib/prefs.svelte';
import { glass } from '$lib/glass.svelte';
let { room }: { room: Room } = $props();
@@ -218,9 +217,7 @@
{/if}
{#if room.error}<p class="warning">{room.error}</p>{/if}
{#if glass.open}
<p class="muted small glass-way"><button type="button" class="link plain" disabled={fetching} aria-busy={fetching} onclick={() => seeGlass(!onGlass)}>{fetching ? 'Fetching the glass board…' : onGlass ? 'Back to the flat boards' : 'See the glass board'}</button></p>
{/if}
<p class="muted small glass-way"><button type="button" class="link plain" disabled={fetching} aria-busy={fetching} onclick={() => seeGlass(!onGlass)}>{fetching ? 'Fetching the glass board…' : onGlass ? 'Back to the flat boards' : 'See the glass board'}</button></p>
{#if onGlass && Glass}
<Glass {g} {mySide} {selected} {targets} {reach} {shownSquares} {shownCaptured} {checkSquare} {calm} {tap} />
{:else}
-1
View File
@@ -8,7 +8,6 @@
import TallyBoard from './Tally.svelte';
import Preferences from './Preferences.svelte';
import { prefs, setPref } from '$lib/prefs.svelte';
import '$lib/glass.svelte';
import { allSeats, doubtSeat, forgetSeat, rememberSeat, ServerError, trustSeat } from '$lib/net/client';
import { api, NAME_MAX, playerName, rememberName, Room } from '$lib/net/room.svelte';
import { unreadTalk } from '$lib/net/talk';
-37
View File
@@ -1,37 +0,0 @@
// The glass board, the three-dimensional view of a game, is shown only to
// a browser that has been let in. A visit to any page with ?glass=<word>
// opens it for that browser, if the word's hash is the one kept here; the
// word itself is nowhere in the site. Until the keeper decides the view is
// ready for everyone, this is the whole of the gate.
const KEY = 'wyrm:glass';
const GATE = 'eec81ab3bd646536b3464bb0411aea9b2e92e6387c6a04ef15743191ac4d142f';
function remembered(): boolean {
try {
return localStorage.getItem(KEY) === '1';
} catch {
return false;
}
}
/** Whether this browser may open the glass board. */
export const glass = $state({ open: typeof localStorage !== 'undefined' && remembered() });
/** Let the browser in if the address carries the word, and remember it. */
export async function claimGlass(): Promise<void> {
if (glass.open || typeof location === 'undefined') return;
const word = new URLSearchParams(location.search).get('glass');
if (!word) return;
const digest = await crypto.subtle.digest('SHA-256', new TextEncoder().encode(word));
const hex = Array.from(new Uint8Array(digest), (b) => b.toString(16).padStart(2, '0')).join('');
if (hex !== GATE) return;
glass.open = true;
try {
localStorage.setItem(KEY, '1');
} catch {
// Opened for this visit only.
}
}
if (typeof location !== 'undefined') void claimGlass();
+1 -4
View File
@@ -7,7 +7,6 @@
import { narrate } from '$lib/game/chronicle';
import { notation, kingSquare, inCheck, movesFrom, legalMovesFrom, sideOf } from '$lib/game';
import { prefs, reducedMotion } from '$lib/prefs.svelte';
import { glass } from '$lib/glass.svelte';
/** The glass board, loaded the first time it is asked for. */
let Glass = $state<typeof import('$lib/components/Glass.svelte').default | null>(null);
@@ -79,9 +78,7 @@
<section class="stage">
<div class="boards">
{#if glass.open}
<p class="muted small"><button type="button" class="link plain" disabled={fetching} aria-busy={fetching} onclick={() => seeGlass(!onGlass)}>{fetching ? 'Fetching the glass board…' : onGlass ? 'Back to the flat boards' : 'See the glass board'}</button></p>
{/if}
<p class="muted small"><button type="button" class="link plain" disabled={fetching} aria-busy={fetching} onclick={() => seeGlass(!onGlass)}>{fetching ? 'Fetching the glass board…' : onGlass ? 'Back to the flat boards' : 'See the glass board'}</button></p>
{#if onGlass && Glass}
<Glass {g} {shownSquares} {shownCaptured} {checkSquare} selected={inspected} {reach} {calm} {tap} />
{:else}