Files
game-kit/new-game.sh
T
Eric WagonerandClaude Opus 5.5 bbbe8ec312 Writing for players: the editing passes' lessons, and the template written by them
The conventions gain a list of the habits players read as generated text
(a semicolon in every paragraph, statement-colon-explanation, "The" plus
an abstract noun as a heading, clipped fragments in threes, closing
aphorisms, "X, not Y", the page talking about itself), and of the errors
that come from inherited text: hidden information where there is none,
points where there are none, "both" at a larger table, unchecked claims,
and ledger-stored words reworded. new-game.sh points at the list.

The template follows it: the about link loses 'a labor of love', the
tabs are Origins and Games so far, and the hall, lobby, room, report
slip, table talk, guide and demo board read as Waving Hands' and
Hnefatafl's now do. The landing page and family.json carry the two
games' new taglines and lose their semicolons and the tip jar's aphorism.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0141G6xqLeNRYEtviLWSB5Up
2026-10-11 10:34:08 -04:00

58 lines
3.7 KiB
Bash
Executable File

#!/usr/bin/env bash
# Stamp out a new game from the template.
# ./new-game.sh <slug> "<Name>" [port] [domain]
# e.g. ./new-game.sh tumbleweed "Tumbleweed" 8791 tumbleweed.kestrelsnest.social
# Ports so far: wizwar 8787, waving-hands 8788, hnefatafl 8789, dip 8790. The
# games share one host (deploy/README.md), so a new game takes the next free port.
set -euo pipefail
SLUG="${1:?usage: new-game.sh <slug> \"<Name>\" [port] [domain]}"
NAME="${2:?usage: new-game.sh <slug> \"<Name>\" [port] [domain]}"
PORT="${3:-8789}"
DOMAIN="${4:-$SLUG.kestrelsnest.social}"
case "$SLUG" in *[!a-z0-9-]*) echo "slug: lowercase letters, digits and hyphens" >&2; exit 1;; esac
DEST="$(cd "$(dirname "$0")/.." && pwd)/$SLUG"
[ -e "$DEST" ] && { echo "$DEST already exists" >&2; exit 1; }
KIT="$(cd "$(dirname "$0")" && pwd)"
rsync -a --exclude node_modules --exclude .svelte-kit --exclude build --exclude data "$KIT/template/" "$DEST/"
# File names carry the slug (unit, cron, backup, rollup, skills).
find "$DEST" -depth -name '*__SLUG__*' | while read -r f; do
mv "$f" "$(dirname "$f")/$(basename "$f" | sed "s/__SLUG__/$SLUG/g")"
done
# Then the placeholders inside. __IP__ and the Sentry ids stay until they exist.
find "$DEST" -type f \( -name '*.ts' -o -name '*.svelte' -o -name '*.json' -o -name '*.md' -o -name '*.sh' -o -name '*.py' -o -name '*.tmpl' -o -name '*.service' -o -name '*.cron' -o -name '*.html' -o -name '*.css' -o -name '.gitignore' \) -print0 \
| xargs -0 sed -i '' -e "s/__SLUG__/$SLUG/g" -e "s/__NAME__/$NAME/g" -e "s/__PORT__/$PORT/g" -e "s/__DOMAIN__/$DOMAIN/g"
cp "$KIT/CONVENTIONS.md" "$DEST/docs-conventions.md" 2>/dev/null || true
mkdir -p "$DEST/docs" && mv "$DEST/docs-conventions.md" "$DEST/docs/conventions.md"
cd "$DEST"
git init -q && git add -A && git commit -q -m "Begin $NAME from the game kit"
npm install --no-audit --no-fund >/dev/null 2>&1 && (cd server && npm install --no-audit --no-fund >/dev/null 2>&1) && echo "dependencies installed" || echo "npm install failed; run it by hand (root and server/)"
cat <<MSG
$NAME is at $DEST (port $PORT, $DOMAIN).
Next:
1. Replace src/lib/game/index.ts with your game, keeping the GameSpec shape,
and src/lib/components/Board.svelte with its board. Keep the tests green.
2. Fill in the hall's pitch, tag and about panel (src/lib/components/Hall.svelte),
the rules page, the guide, src/app.html's description, and the palette in src/app.css.
Write every line a player reads in the game's own voice: an image with each
fact (docs/conventions.md, "The voice"). Then read every page against
"Writing for players" in the same file, the template's own lines included.
Add static/og.png (1200 by 630) and static/apple-touch-icon.png (180 by 180):
app.html already points at them, and the static fallback serves the hall's
HTML for a missing file, so a share card without the image breaks quietly.
3. Add the game to the shared host (deploy/README.md), after replacing __IP__ with its address:
grep -rl __IP__ . --exclude-dir=node_modules | xargs sed -i '' 's/__IP__/159.203.115.252/g'
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 <ip>
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 kit's gamehall/site/index.html, and publish it: gamehall/deploy.sh <host>.
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