arcade epic #41: several typing/arcade games live as single pages (or small
asset sets) inside this Jekyll repo, under sethshoultes.com/<path>. Each one
is being moved to its own subdomain on hetzner-sites — <slug>.adventurebuildr.com
— as a plain static site, off Jekyll and off this domain.
This covers the repo-side half only: build config and the shared deploy script. The box side (nginx vhost, DNS, cert, first sync) is the arcade lead’s, per game.
One script for every game here: scripts/deploy-game.sh <slug> <source-path>.
Do not write a second near-identical script for the next game — extend this
one’s build step if a future game needs something this one doesn’t (e.g. a
directory of assets instead of a single file).
scripts/deploy-game.sh typerunner typing-games/typerunner.html
slug — short name. Becomes build/<slug>/ locally and, by default, the
CloudPanel site-user + domain: /home/<slug>/htdocs/<slug>.adventurebuildr.com.
Override with GAME_DEPLOY_PATH if a game’s slug doesn’t match its
site-user/domain 1:1.source-path — path (relative to repo root) to the game’s file or
directory.Build step: no Jekyll processing. A source file becomes
build/<slug>/index.html; a source directory is copied whole into
build/<slug>/ (and must already contain its own index.html). build/ is
gitignored — it’s regenerated from source-path every run, never committed.
This dev has no ssh access and doesn’t run this script itself; the arcade
lead does, after the box side (nginx vhost, DNS, cert, first sync) is ready.
Reads $HOME/.config/dev-secrets/arcade/secrets.env if present, same as
every other arcade game’s deploy script.
Source: typing-games/typerunner.html, one self-contained HTML file — inline
<style>, one inline <script> (game logic + WASD movement + Canvas
rendering), no <link>/<img>/external src= of any kind, no CDN. Confirmed
by grepping the file for src=, href=, url(, fetch(, import — zero
matches outside the one inline <script> tag itself. Game state (high
scores, settings) is localStorage, client-side only — nothing server-side
to replicate.
No Jekyll front matter — the file starts directly with <!DOCTYPE html>,
no --- block, so Jekyll would have copied it byte-for-byte anyway; this
confirms it’s safe to lift out and serve standalone with zero translation.
Build:
scripts/deploy-game.sh typerunner typing-games/typerunner.html
produces build/typerunner/index.html — the whole servable root, one file.
Target: /home/typerunner/htdocs/typerunner.adventurebuildr.com (CloudPanel
layout, given directly for arcade#44 — matches this script’s default for
slug typerunner, no override needed).
Source: typing-games/typinginvaders.html, one self-contained HTML file —
inline <style>, one inline <script> (game logic + Canvas rendering).
Grepping the file for src=, href=, url(, fetch(, import, cdn.,
https?:// returns zero matches — no external assets or CDN calls of
any kind, not even the file’s own <style>/<script> tag attributes.
Two localStorage reads/writes for high-score state, client-side only.
No Jekyll front matter — confirmed via od -c on the first bytes: the
file starts directly with <!DOCTYPE html>, no --- block.
Fixed: the source file was missing <meta charset="UTF-8"> in <head>,
which rendered the HUD’s “♥” lives indicator as “♥” mojibake. Added the
tag directly to typing-games/typinginvaders.html (typo-class, visible to
players) and re-verified.
Build — no script changes needed, same single-file path as Typewrunner:
scripts/deploy-game.sh typinginvaders typing-games/typinginvaders.html
produces build/typinginvaders/index.html — the whole servable root, one
file.
Local verification: served build/typinginvaders/ from a local static
server and loaded it with headless Playwright (chromium) — zero console
errors, zero page errors. HUD (Score/Lives/Level/Active) rendered correctly,
including the fixed “♥♥♥” lives indicator (was “♥♥♥” before the charset
fix above; re-checked post-fix and confirmed clean).
Target: /home/typinginvaders/htdocs/typing-invaders.adventurebuildr.com.
Site-user typinginvaders has no hyphen but the domain
typing-invaders.adventurebuildr.com does, so the script’s default
$SLUG.adventurebuildr.com formula can’t produce both from one slug —
needs the GAME_DEPLOY_PATH override, same as Speed Typing Adventure:
GAME_DEPLOY_PATH=/home/typinginvaders/htdocs/typing-invaders.adventurebuildr.com \
scripts/deploy-game.sh typinginvaders typing-games/typinginvaders.html
Source: typing-games/typing-game.html, one self-contained HTML file —
inline <style>, one inline <script> (WASD player movement, timed word
spawns, DOM-rendered — no Canvas). Grepping the file for src=, href=,
url(, fetch(, import, cdn., https?:// finds exactly one match:
<script src="https://cdn.tailwindcss.com"></script> — a CDN dependency,
not a sibling-path one, so it’s safe to lift out and serve standalone (the
CDN script keeps loading fine off any domain). No localStorage reads or
writes — no client-side state to replicate.
Not a duplicate of Word Runner (arcade#55), despite the filename pairing
(typing-game-1.html beside typing-game.html, the shape of a saved
variant elsewhere in this repo, e.g. flappybird-1.html/flappybird.html).
Read both files side by side: Canvas rendering here vs. Word Runner’s DOM
overlay; player is a drawn star that moves directly in canvas coordinates
vs. Word Runner’s floating circle positioned in the DOM; words are
FloatingWord instances that drift with their own physics and trigger by
proximity collision vs. Word Runner’s fixed word list spawned on a random
timer; word theme is AI/ML terms (GPT, BERT, LLM, model/company
names) vs. Word Runner’s general programming terms; scoring formula and
scale also differ. Genuinely a separate game — hosted as its own game, not
folded into Word Runner’s manifest.
Source: typing-games/typing-game-1.html, one self-contained HTML file —
inline <style>, one inline <script> (Canvas rendering, WASD movement,
proximity-based word collision). Grepping the file for src=, href=,
url(, fetch(, import, cdn., https?:// finds exactly one match,
the same CDN dependency as Word Runner:
<script src="https://cdn.tailwindcss.com"></script> — not a sibling-path
dependency, safe to serve standalone. No localStorage reads or writes.
No Jekyll front matter — confirmed via od -c on the first bytes: the
file starts directly with <!DOCTYPE html>, no --- block.
Live in a second place: this same game is also served at
adventurebuildr.com/arcade/typing-game.html, inside the WordPress site’s
own /arcade/ mini-game hub (docs/INVENTORY.md in the arcade repo records
that hub as an unrelated name collision with the arcade dashboard project).
That site is out of scope here (CLAUDE.md: “The WordPress site at
adventurebuildr.com stays as is”) — noted for the arcade lead to decide
whether the WordPress copy is left alone, redirected, or removed once this
copy is live.
Build — no script changes needed, same single-file path as Typewrunner and Typing Invaders:
scripts/deploy-game.sh word-runner typing-games/typing-game.html
produces build/word-runner/index.html — the whole servable root, one file.
Verified by replicating the script’s build step directly (build/ output
non-empty, 5009 bytes).
Local verification: served build/word-runner/ from a local static server
and loaded it with headless Playwright (chromium) — zero console errors,
zero page errors.
Target: /home/word-runner/htdocs/word-runner.adventurebuildr.com — matches
this script’s default $SLUG.adventurebuildr.com formula exactly for slug
word-runner, no GAME_DEPLOY_PATH override needed.
Build — no script changes needed, same single-file path as the others:
scripts/deploy-game.sh ai-typing-star typing-games/typing-game-1.html
produces build/ai-typing-star/index.html — the whole servable root, one
file. Verified by replicating the script’s build step directly (build/
output non-empty, 6952 bytes).
Local verification: served build/ai-typing-star/ from a local static
server and loaded it with headless Playwright (chromium) — zero console
errors, zero page errors.
Target: /home/ai-typing-star/htdocs/ai-typing-star.adventurebuildr.com —
matches this script’s default $SLUG.adventurebuildr.com formula exactly
for slug ai-typing-star, no GAME_DEPLOY_PATH override needed.