From 9d087ccaa19f2b182741128c9e1778f277e9aa76 Mon Sep 17 00:00:00 2001 From: Eric Wagoner Date: Wed, 23 Sep 2026 12:26:49 -0400 Subject: [PATCH] The front page and the about page point to the other games of the Kestrel's Nest The list is the kit's family.json, shipped as /family.json and refreshed at deploy when the kit is beside this checkout. Co-Authored-By: Claude Fable 5.1 Claude-Session: https://claude.ai/code/session_01Jm2auWk6RP71CjaAb4FMoG --- deploy/deploy.sh | 4 ++++ packages/web/public/family.json | 21 +++++++++++++++++++++ packages/web/src/App.svelte | 12 ++++++++++++ packages/web/src/Help.svelte | 17 +++++++++++++++++ packages/web/src/family.ts | 23 +++++++++++++++++++++++ 5 files changed, 77 insertions(+) create mode 100644 packages/web/public/family.json create mode 100644 packages/web/src/family.ts diff --git a/deploy/deploy.sh b/deploy/deploy.sh index aba9e20..3562aa1 100755 --- a/deploy/deploy.sh +++ b/deploy/deploy.sh @@ -3,6 +3,10 @@ set -euo pipefail HOST="${1:?usage: deploy.sh }" +# The family list is the kit's; the site deploys with the kit's latest copy when the kit is beside this checkout. +KIT_FAMILY="$(dirname "$0")/../../game-kit/family.json" +[ -f "$KIT_FAMILY" ] && cp "$KIT_FAMILY" packages/web/public/family.json + npm run build --workspace=@wizwar/web # Old hashed chunks stay a week: a page loaded before this deploy can still # fetch the module it was built against instead of failing mid-game. diff --git a/packages/web/public/family.json b/packages/web/public/family.json new file mode 100644 index 0000000..10d4a2e --- /dev/null +++ b/packages/web/public/family.json @@ -0,0 +1,21 @@ +{ + "family": "the Kestrel's Nest", + "games": [ + { + "slug": "wizwar", + "name": "Wiz-War", + "url": "https://wizwar.kestrelsnest.social", + "pitch": "Steal treasure. Blast through walls. Outwit your friends.", + "players": "2 to 6", + "origin": "Tom Jolly's board game, sixth edition, 1993" + }, + { + "slug": "waving-hands", + "name": "Waving Hands", + "url": "https://hands.kestrelsnest.social", + "pitch": "Duelling wizards. Two hands each. The right run of gestures is a spell.", + "players": "2 to 12", + "origin": "Richard Bartle's pencil-and-paper duel, 1977" + } + ] +} diff --git a/packages/web/src/App.svelte b/packages/web/src/App.svelte index 20053f2..e63e1c6 100644 --- a/packages/web/src/App.svelte +++ b/packages/web/src/App.svelte @@ -10,6 +10,7 @@ import Card from "./Card.svelte"; import Help from "./Help.svelte"; import { HELP_TABS, type HelpTab } from "./help-state"; + import { otherGames, type FamilyGame } from "./family"; import { summarizeMissed } from "./catchup"; import Replay from "./Replay.svelte"; import FxGallery from "./FxGallery.svelte"; @@ -26,6 +27,11 @@ net.startGamePolling(); let name = $state(prefs.wizardName); + /** The other games of the Kestrel's Nest, for the front page. */ + let family = $state([]); + $effect(() => { + void otherGames("wizwar").then((g) => (family = g)); + }); let joinCode = $state(""); let claimPhrase = $state(""); /** A /join/ recruiting link. The visitor lands looking at the @@ -2561,6 +2567,10 @@ Through a wizard's eyes: an ambush watches its corridor through a wormhole watch clips from the labyrinth + {#if family.length} +

Also at the Kestrel's Nest: + {#each family as g, i (g.slug)}{i > 0 ? ", " : " "}{g.name}{/each}

+ {/if}
@@ -4108,6 +4118,8 @@ margin-bottom: 1.2rem; } .about-link:hover { color: #43331f; } + .family-line { margin: 0.5rem 0 0; font-size: 0.85rem; color: #7b6a51; } + .family-line a { color: #5a4630; } .clips-link { display: inline-block; margin: 0 0 0.9rem; } .field { display: block; text-align: left; margin-bottom: 1rem; } .field span { diff --git a/packages/web/src/Help.svelte b/packages/web/src/Help.svelte index 8bd11e1..9931037 100644 --- a/packages/web/src/Help.svelte +++ b/packages/web/src/Help.svelte @@ -3,6 +3,7 @@ // body, the card library with proper entries, the house rulings, the // story of the table, and the tally. Every section and card has a link // a player can send; the desk remembers where the reader was. + import { otherGames, type FamilyGame } from "./family"; import { cardDef } from "@wizwar/engine"; import { tick } from "svelte"; import Card from "./Card.svelte"; @@ -127,6 +128,11 @@ if (initialAnchor) void jumpTo(initialAnchor); else if (bodyEl) bodyEl.scrollTop = helpState.scroll[tab] ?? 0; }); + /** The other games of the Kestrel's Nest, for the about page. */ + let family = $state([]); + $effect(() => { + void otherGames("wizwar").then((g) => (family = g)); + }); {#snippet section(s: RefSection, withSource: boolean)} @@ -311,6 +317,14 @@ The keeper of this table roosts at kestrelsnest.social.

+ {#if family.length} +

More games at the Kestrel's Nest

+
    + {#each family as g (g.slug)} +
  • {g.name}: {g.pitch} {g.players} players; {g.origin}.
  • + {/each} +
+ {/if}

Wiz-War © Tom Jolly. Sixth edition published by Chessex, 1993. Built by Eric and a very enthusiastic AI, 2026. @@ -691,4 +705,7 @@ .entry-card :global(.card:hover) { transform: none; } .contents { columns: 1; } } + .family { margin: 0.4rem 0 0.8rem 1.2rem; padding: 0; } + .family li + li { margin-top: 0.3rem; } + .family-note { color: #7b6a51; } diff --git a/packages/web/src/family.ts b/packages/web/src/family.ts new file mode 100644 index 0000000..c18054f --- /dev/null +++ b/packages/web/src/family.ts @@ -0,0 +1,23 @@ +// The other games of the Kestrel's Nest, from the family list the kit keeps +// (family.json, one copy shipped with every game), so a player who liked one +// table can find the next. This game is left out of its own list. + +export interface FamilyGame { + slug: string; + name: string; + url: string; + pitch: string; + players: string; + origin: string; +} + +export async function otherGames(self: string): Promise { + try { + const res = await fetch('/family.json', { cache: 'no-cache' }); + if (!res.ok) return []; + const data = (await res.json()) as { games?: FamilyGame[] }; + return (data.games ?? []).filter((g) => g.slug !== self); + } catch { + return []; + } +}