/ recent work / dungeon-jerks

Dungeon Jerks

Snarky tile-and-card board game on the web — pass-and-play or async multiplayer, 110 tiles, pre-generated narration, CPU bots that wait their turn.

Year
2026
Role
Solo build
Status
live
Stack
  • SvelteKit
  • Svelte 5
  • TypeScript
  • Netlify
  • Netlify Blobs
  • Airtable
  • ElevenLabs

A web-playable version of Adam’s PG-13 party board game — “D&D for ADHD” energy, 3–8 players, tiles you land on, characters with abilities, and action cards that read like a roast. The site is the game: not a landing page with a download link.

The problem

The physical game works at a table. Getting eight people in one room with the box is the hard part. We wanted a version that runs in a browser, feels like the cardboard experience (dice, narration, character art), and doesn’t require everyone to install anything.

The approach

SvelteKit + committed content. Tiles, characters, and actions sync from Airtable at build time into JSON — no live CMS calls in the hot path. Art lives in static/art/ (~294 WebP frames). Audio lives in static/audio/ (~1600 MP3s) with on-demand TTS only for roll outcomes that weren’t pre-baked.

Pass-and-play first, async second. v1 is one device passed around the table. v2 shipped: token-in-URL multiplayer via Netlify Blobs (/api/games), 3s polling, canonical GameState on the server while animations and dice stay client-side.

Typed effect atoms. HP, GP, move, statuses, gags — parsed into a small catalog so card text isn’t a pile of special cases. Roll tables use ranges (1–5 / 6–15 / 16–20), not twenty unique rows.

What we built

  • 110 tiles, 89 characters (heroes, villains, NPCs), 105 actions on a 2D grid keyed "x,y".
  • CPU bots with roll-table decisions, special abilities, and pacing that waits for narration to finish before the next bot acts — otherwise async games feel like a slot machine.
  • SEO layer: VideoGame + FAQ + Breadcrumb JSON-LD, changelog RSS, IndexNow under canonical www, apex 301s to www.
  • Vitest coverage on store logic and extracted nextBotAction — character-specific tests boot with fixed seeds.
  • Marketing roster art pipeline: crop to bridge ratio (2.25:3.5), match scripts from Dropbox → repo, optional R2 mirror.

Trade-offs

Pre-generating narration costs repo size and build time. It buys instant tile read-aloud without hammering ElevenLabs on every landing. Dynamic TTS stays behind /api/tts for the long tail of roll lines.

We killed the Supabase plan early. Blobs + polling is boring and shippable; websockets would have been a second product.

What’s ongoing

Status effects are partly stubbed — pills render, full mechanical hooks still landing. Gold transfer between players is a v1.1 extension. Art gaps are tracked in-repo (docs/missing-art.md). Deploys are gated: push to main only when Adam says go — Netlify deploys on every push.

Results

The game is live and playable at dungeonjerks.com. Recent sessions surfaced real UX wins: footer contrast to WCAG AA, slower bot cadence, canonical host cleanup. The funnel we care about is “open /play, finish a round, send the link to friends” — and that loop works.