diff --git a/CONVENTIONS.md b/CONVENTIONS.md index 66d8559..1ea8e39 100644 --- a/CONVENTIONS.md +++ b/CONVENTIONS.md @@ -294,6 +294,10 @@ and read each new page against this list before it ships. deliberate triplet as its tagline when the energy is the point, as Wiz-War's "Steal treasure. Blast through walls. Outwit your friends." does. Once is a choice, and a pattern is a tell. +- **No one sentence shape for a whole list.** Thirty chronicle lines that + each run image, colon, consequence read as a template however good the + images are. Let the fact come first in some, in its own sentence in others, + and joined by "and" or "which" in the rest. - **No closing aphorisms.** A paragraph ends on its last fact, not on a line meant to sound wise ("This is the whole art", "Nothing is unlocked by it and nothing is withheld without it"). @@ -351,6 +355,11 @@ opened its mouth.") as long as the fact survives. - `npm install --omit=optional` on the droplet breaks Vite; the server carries its own small `package.json` and installs only that. - A dynamic `/join/[code]` route must set `prerender = false`. +- The hall, the rules and the guide set `ssr = true` in their own `+page.ts`, + so view-source, a crawler and a reader without scripts get the text; the + rest stays an empty shell. The adapter's fallback is `shell.html`, not + `index.html`, because a fallback named `index.html` overwrites the + prerendered hall, and Caddy's `try_files` ends in `/shell.html`. - Two tabs on one origin share a seat; test a second player from `127.0.0.1` against `localhost` (Vite needs `--host`). - Svelte proxies do not `structuredClone`: hand the engine `$state.snapshot`. diff --git a/drift.sh b/drift.sh index 9b15985..03ed601 100755 --- a/drift.sh +++ b/drift.sh @@ -11,6 +11,7 @@ SLUG="${2:-$(basename "$(cd "$GAME" && pwd)")}" KIT="$(cd "$(dirname "$0")" && pwd)" MAP="$KIT/drift-map/$SLUG.txt" SHARED="server/src/index.ts server/src/rooms.ts server/src/store.ts server/src/reports.ts server/src/ratelimit.ts server/src/tally.ts +src/routes/+layout.ts src/routes/+page.ts src/routes/rules/+page.ts src/routes/guide/+page.ts vite.config.ts src/lib/game/spec.ts src/lib/net/client.ts src/lib/net/talk.ts src/lib/net/view.ts src/lib/net/room.svelte.ts src/lib/components/TableTalk.svelte src/lib/components/ReportSlip.svelte src/lib/components/TabbedDialog.svelte src/lib/components/Tabs.svelte src/lib/components/Announcement.svelte deploy/deploy.sh deploy/setup-droplet.sh deploy/setup-server.sh deploy/Caddyfile.tmpl deploy/verify-ledgers.sh diff --git a/family.json b/family.json index 15fd16c..81980f2 100644 --- a/family.json +++ b/family.json @@ -31,7 +31,7 @@ "name": "Dip", "url": "https://dip.kestrelsnest.social", "pitch": "Seven powers share one map, and none of them has to keep its word.", - "players": "2 to 7", + "players": "2 to 10, depending on the map", "origin": "Allan B. Calhamer's Diplomacy, 1959; an unofficial rebuild" }, { diff --git a/gamehall/site/index.html b/gamehall/site/index.html index 9f9e9a8..0f2da6d 100644 --- a/gamehall/site/index.html +++ b/gamehall/site/index.html @@ -4,7 +4,7 @@
Free board games in the browser. Play alone against the house right away, or start a table and send friends the link. No accounts, no adverts, no timers, and nothing sold.
-New here? Wiz-War is the friendliest place to start, and a game can be over in minutes. Dip is the long game.
Steal treasure. Blast through walls. Outwit your friends.
2 to 6 players, or solo against the automaton
An unofficial rebuild of Tom Jolly's 1993 board game
- -Wizards duel with their hands, and the right run of gestures is a spell.
2 to 12 players, or solo against a rival wizard
Richard Bartle's pencil-and-paper duel, 1977
- -The Viking board game of a king breaking for safety and a ring of attackers closing in.
2 players, or solo against the housecarl
The Norse tafl game, by the Copenhagen rules or Linnaeus's 1732 Tablut
- -Seven powers share one map, and none of them has to keep its word. Other maps seat five or ten.
2 to 10 players, depending on the map, or solo against the house's envoys
An unofficial rebuild of Allan B. Calhamer's 1959 Diplomacy
- -Chess on three boards, with a Dragon in the air above your King and a Basilisk in the earth below.
2 players, or solo against the drake
An unofficial rebuild of Gary Gygax's 1985 Dragonchess, from Dragon Magazine No. 100
- -The games are free and will stay free. They run on small servers that cost a few dollars a month, and anyone who wants to chip in toward the hosting can do so at ko-fi.com/kestrelsnest. Chipping in unlocks nothing, and nothing is held back without it.
+The games are free and will stay free. They run on small servers that cost a few dollars a month, and anyone who wants to chip in toward the hosting can do so at ko-fi.com/kestrelsnest. Chipping in unlocks nothing, and the games are the same for everyone.
diff --git a/template/deploy/Caddyfile.tmpl b/template/deploy/Caddyfile.tmpl index 9b270fb..356ad54 100644 --- a/template/deploy/Caddyfile.tmpl +++ b/template/deploy/Caddyfile.tmpl @@ -43,7 +43,7 @@ __HOST__ { header @immutable Cache-Control "public, max-age=31536000, immutable" @mutable not path /_app/immutable/* header @mutable Cache-Control "no-cache" - try_files {path} {path}.html /index.html + try_files {path} {path}.html /shell.html file_server } } diff --git a/template/deploy/deploy.sh b/template/deploy/deploy.sh index b2c9bc7..594267a 100755 --- a/template/deploy/deploy.sh +++ b/template/deploy/deploy.sh @@ -25,7 +25,7 @@ rsync -az --delete --filter='P _app/immutable/*' \ # it needs only its code and the engine. Ledgers live outside this tree. rsync -az --delete --exclude='/server/node_modules' \ --include='/server/***' --include='/src/' --include='/src/lib/' --include='/src/lib/game/***' --include='/src/lib/net/' --include='/src/lib/net/view.ts' \ - --include='/deploy/' --include='/deploy/__SLUG__.service' --include='/deploy/__SLUG__.cron' --include='/deploy/*.sh' --include='/deploy/traffic.py' \ + --include='/deploy/' --include='/deploy/__SLUG__.service' --include='/deploy/__SLUG__.cron' --include='/deploy/*.sh' --include='/deploy/Caddyfile.tmpl' --include='/deploy/traffic.py' \ --exclude='*' \ ./ "root@$HOST:/opt/__SLUG__/app/" @@ -60,6 +60,12 @@ ssh "root@$HOST" ' systemctl daemon-reload systemctl enable --now __SLUG__ systemctl restart __SLUG__ + # The site file is rendered from the template on every deploy, with the address line the box was set up with. + ADDR=$(head -1 /etc/caddy/sites/__SLUG__.caddy | sed "s/ {\$//") + sed "s|__HOST__|$ADDR|" /opt/__SLUG__/app/deploy/Caddyfile.tmpl > /etc/caddy/sites/__SLUG__.caddy + caddy validate --config /etc/caddy/Caddyfile >/dev/null + # Validation as root touches the access logs; Caddy runs as caddy and must own them. + chown -R caddy:caddy /var/lib/caddy systemctl reload caddy # "active" means only that the process started: wait for it to answer HTTP, # so a server that dies loading its code fails the deploy instead of looping. diff --git a/template/src/lib/components/Hall.svelte b/template/src/lib/components/Hall.svelte index 8bd05c7..415ad5f 100644 --- a/template/src/lib/components/Hall.svelte +++ b/template/src/lib/components/Hall.svelte @@ -324,7 +324,7 @@ {/snippet} {#snippet aboutTally()} {#if told} -Counting…
{/if} @@ -340,7 +340,7 @@ {/if}The games of Kestrel's Hall are free and will stay free. They run on small servers that cost a few dollars a month, and anyone who wants to chip in toward the hosting can do so at - ko-fi.com/kestrelsnest. Chipping in unlocks nothing, and nothing is held back without it. + ko-fi.com/kestrelsnest. Chipping in unlocks nothing, and the games are the same for everyone.
__NAME__ is its designer's.
diff --git a/template/src/routes/+layout.ts b/template/src/routes/+layout.ts index a3ded22..64db8f3 100644 --- a/template/src/routes/+layout.ts +++ b/template/src/routes/+layout.ts @@ -1,4 +1,5 @@ -// Everything happens in the browser against the game server, so nothing is rendered on the -// server. Each route is prerendered as an empty shell that the client fills in. +// Everything happens in the browser against the game server, so by default a route is +// prerendered as an empty shell that the client fills in. The hall, the rules and the guide +// turn rendering on in their own +page.ts, since their text is the same for everyone. export const ssr = false; export const prerender = true; diff --git a/template/src/routes/+page.ts b/template/src/routes/+page.ts new file mode 100644 index 0000000..3634166 --- /dev/null +++ b/template/src/routes/+page.ts @@ -0,0 +1,3 @@ +// The page is text that reads the same for everyone, so it is rendered at build time and served whole; +// the browser-only state it shows (held seats, the saved name) fills in once the script runs. +export const ssr = true; diff --git a/template/src/routes/guide/+page.ts b/template/src/routes/guide/+page.ts new file mode 100644 index 0000000..3634166 --- /dev/null +++ b/template/src/routes/guide/+page.ts @@ -0,0 +1,3 @@ +// The page is text that reads the same for everyone, so it is rendered at build time and served whole; +// the browser-only state it shows (held seats, the saved name) fills in once the script runs. +export const ssr = true; diff --git a/template/src/routes/rules/+page.ts b/template/src/routes/rules/+page.ts new file mode 100644 index 0000000..3634166 --- /dev/null +++ b/template/src/routes/rules/+page.ts @@ -0,0 +1,3 @@ +// The page is text that reads the same for everyone, so it is rendered at build time and served whole; +// the browser-only state it shows (held seats, the saved name) fills in once the script runs. +export const ssr = true; diff --git a/template/vite.config.ts b/template/vite.config.ts index 9b8c1e4..4a01a0b 100644 --- a/template/vite.config.ts +++ b/template/vite.config.ts @@ -10,7 +10,9 @@ export default defineConfig({ runes: ({ filename }) => (filename.split(/[/\\]/).includes('node_modules') ? undefined : true) }, // A static build: Caddy serves files and proxies /api and /ws to the game server. - adapter: adapter({ fallback: 'index.html' }) + // The fallback is the empty shell Caddy serves for a room address; it is not index.html, so the + // hall's own prerendered page is not overwritten by it. + adapter: adapter({ fallback: 'shell.html' }) }) ], server: {