diff --git a/CONVENTIONS.md b/CONVENTIONS.md index c111ea7..5e5e543 100644 --- a/CONVENTIONS.md +++ b/CONVENTIONS.md @@ -63,6 +63,11 @@ README. - **Send word** is the contact paragraph: mail, Bluesky and Mastodon, and where the keeper roosts. It lives in the about panel; the colophons, the rules page and the guide each carry a one-line mail link. +- **The family list** in the about panel, *More games in Kestrel's Hall*, + comes from `family.json` and its heading links to the family's landing + page, gamehall.kestrelsnest.social. A new game is added to the kit's + `family.json` and given a card on that page in the blog repo; both are + hand-kept. - **The hosting line** follows the family list in the about panel: the games are free and will stay free, the servers cost a few dollars a month, and ko-fi.com/kestrelsnest is where anyone may chip in. It says diff --git a/README.md b/README.md index 1a77b6e..d9245f2 100644 --- a/README.md +++ b/README.md @@ -71,8 +71,14 @@ interruptions, Wiz-War's shape, does not fit and keeps its own server. ## The family `family.json` lists every game of Kestrel's Hall: slug, name, address, -one-line pitch, player count and origin. Each game ships a copy as -`static/family.json` (the deploy script takes the kit's latest when the kit -is beside the game) and its about panel lists the others under *More games -in Kestrel's Hall*. Add a game here, then deploy the games; nothing -else needs to know. +one-line pitch, player count and origin, plus `hall`, the address of the +family's landing page. Each game ships a copy as `static/family.json` (the +deploy script takes the kit's latest when the kit is beside the game) and +its about panel lists the others under *More games in Kestrel's Hall*, the +heading linking to the family's landing page. Add a game here, then +deploy the games. + +That landing page, https://gamehall.kestrelsnest.social, is one static page +in the blog repo (`~/Sites/blog/static/gamehall/index.html`) with a card +per game, written by hand, and it deploys with the blog. A new game is not +in the family until it has its card there too. diff --git a/family.json b/family.json index f9e6d33..48572da 100644 --- a/family.json +++ b/family.json @@ -1,5 +1,6 @@ { "family": "Kestrel's Hall", + "hall": "https://gamehall.kestrelsnest.social", "games": [ { "slug": "wizwar", diff --git a/new-game.sh b/new-game.sh index a69a9b1..4905ce1 100755 --- a/new-game.sh +++ b/new-game.sh @@ -45,5 +45,10 @@ Next: 4. Create a Sentry project (the Sentry MCP can) and put its DSN and project id in deploy/$SLUG.service and deploy/sentry-slack-alert.sh. 5. deploy/deploy.sh -docs/conventions.md is the house style every game follows. + 6. Put the game in the family: add it to the kit's family.json (every game's + about panel lists the others from that file at its next deploy), then give + it a card on the family's landing page, Kestrel's Hall, hand-written HTML in + the blog repo at ~/Sites/blog/static/gamehall/index.html, and deploy the blog. + Card art is the game's own drawing; never a publisher's logo or scan. +CONVENTIONS.md in the kit is the house style every game follows. MSG diff --git a/template/src/lib/components/Hall.svelte b/template/src/lib/components/Hall.svelte index 61a9fff..7758164 100644 --- a/template/src/lib/components/Hall.svelte +++ b/template/src/lib/components/Hall.svelte @@ -3,7 +3,7 @@ // bot, open a table, join by code, the ledger of your tables, and the // about panel with the rules, the guide and a way to reach the keeper. import { goto } from '$app/navigation'; - import { otherGames, type FamilyGame } from '$lib/family'; + import { loadFamily, type FamilyGame } from '$lib/family'; import Preferences from './Preferences.svelte'; import { prefs, setPref } from '$lib/prefs.svelte'; import { allSeats, doubtSeat, forgetSeat, rememberSeat, ServerError, trustSeat } from '$lib/net/client'; @@ -33,8 +33,12 @@ const hours = (minutes: number) => (minutes < 90 ? `${minutes} minutes` : `${Math.round(minutes / 60)} hours`); /** The other games of Kestrel's Hall, for the about panel. */ let family = $state([]); + let hall = $state(''); $effect(() => { - void otherGames('__SLUG__').then((g) => (family = g)); + void loadFamily('__SLUG__').then((f) => { + family = f.games; + hall = f.hall; + }); }); /** Reports this browser's seats have filed, with the keeper's replies. */ let reports = $state([]); @@ -282,7 +286,7 @@

{/if} {#if family.length} -

More games in Kestrel's Hall

+

More games in {#if hall}Kestrel's Hall{:else}Kestrel's Hall{/if}

    {#each family as g (g.slug)}
  • {g.name}: {g.pitch} {g.players} players; {g.origin}.
  • diff --git a/template/src/lib/family.ts b/template/src/lib/family.ts index b706a6b..596072d 100644 --- a/template/src/lib/family.ts +++ b/template/src/lib/family.ts @@ -1,6 +1,7 @@ // The other games of Kestrel's Hall, 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. +// table can find the next, and the hall's front door. This game is left out +// of its own list. export interface FamilyGame { slug: string; @@ -11,13 +12,19 @@ export interface FamilyGame { origin: string; } -export async function otherGames(self: string): Promise { +/** The family list: the hall's front door and every game but this one. */ +export interface Family { + hall: string; + games: FamilyGame[]; +} + +export async function loadFamily(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); + if (!res.ok) return { hall: '', games: [] }; + const data = (await res.json()) as { hall?: string; games?: FamilyGame[] }; + return { hall: data.hall ?? '', games: (data.games ?? []).filter((g) => g.slug !== self) }; } catch { - return []; + return { hall: '', games: [] }; } } diff --git a/template/static/family.json b/template/static/family.json index 2e69a05..48572da 100644 --- a/template/static/family.json +++ b/template/static/family.json @@ -1,5 +1,6 @@ { "family": "Kestrel's Hall", + "hall": "https://gamehall.kestrelsnest.social", "games": [ { "slug": "wizwar", @@ -16,6 +17,14 @@ "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" + }, + { + "slug": "hnefatafl", + "name": "Hnefatafl", + "url": "https://tafl.kestrelsnest.social", + "pitch": "The Viking board game. One king, one throne, four corners, and a ring of attackers closing in.", + "players": "2", + "origin": "the Norse tafl game, reconstructed from Linnaeus's 1732 notes; Copenhagen rules or Tablut" } ] }