🎲 Solo Dungeon Master
An AI-powered solo tabletop RPG app that runs entirely in your browser, using the Cypher System rules. Your API key never leaves your device — all requests go directly from your browser to the Anthropic API.
Live: apps.fuzzyworld.net/dm/
How it works
On your first visit you'll be asked for an Anthropic API key. The key is saved to your browser's localStorage (AES-GCM encrypted) so you only enter it once. After that, the game UI appears immediately on every return visit, resuming your previous adventure automatically.
The game is powered by claude-haiku-4-5-20251001 and uses Claude's tool-use API to maintain a structured character sheet (Might/Speed/Intellect pools, XP, cyphers, equipment) while generating freeform narrative. Costs roughly a few cents per session.
Features
- Cypher System character creation — pick a Descriptor (34 options), Type (Warrior, Adept, Explorer, Speaker), and Focus (69 options) to form the sentence "I am a Clever Warrior who Hunts."
- Setting selector — choose Classic Fantasy, Ninth World (Numenera), Modern Thriller, or Science Fiction at character creation; adjusts currency, tone, special-ability vocabulary, and available Foci
- Three stat pools — Might, Speed, and Intellect each with current/max and Edge displayed; colour-coded bars shift green → amber → red as pools deplete
- Damage track — one pool at 0 → Impaired; two at 0 → Debilitated; all at 0 → Dead
- Skills — starting skills populated from Type and Descriptor; sidebar section shows each skill with a colour-coded rank badge (green Trained / gold Specialized / red Inability); overlapping trained skills automatically promote to Specialized
- Cyphers — one-use items found during play; displayed in the sidebar with Cypher Limit enforcement
- Advancement modal — spending 4 XP opens a choice dialog: increase a pool max by 4, add +1 Edge to a stat, train a new skill, specialize in a trained skill, or describe a custom improvement; four improvements advance your Tier (max Tier 6)
- Session persistence — adventure state and conversation history saved to
localStorage; reloading the page resumes mid-scene; save version guard offers Markdown export before discarding incompatible sessions - Cost display — per-turn and session cost estimates shown in the sidebar (based on token counts from the SSE stream)
- Dice roller — d4 through d100, configurable count
- World Notes — orange-bordered GM meta-context panel for providing background lore, world physics, and house rules that Claude treats as absolute truth
- Share links — generate an encrypted
#k=…URL so someone else can use the app with your API key; they enter a passphrase you share separately; the key is never in the URL - Report Issue — in-game button that collects debug info (character state, recent errors, session cost) and opens a pre-filled bug-report email
Running locally
npm run dev # serves public/ on http://localhost:3000
Requires Node.js. No build step — the entire app is a single public/index.html.
Architecture
| Concern | Approach |
|---|---|
| AI backend | Anthropic Messages API, streaming SSE |
| Key storage | AES-GCM + PBKDF2 (Web Crypto API); falls back to XOR stream cipher on plain HTTP |
| Share links | AES-GCM encrypted blob in the URL hash (#k=); hash is never sent to the server |
| Session state | localStorage — character sheet, conversation history, rendered HTML |
| Analytics | metadata.user_id in each API request carries p_<playerId>:g_<gameId> for Anthropic Console |
| Deployment | apps.fuzzyworld.net — npm run deploy publishes public/ |
Why a single file?
public/index.html is currently ~3,500 lines of vanilla JS — no build step, no bundler, no TypeScript. This is intentional. The constraint keeps the CI pipeline trivial (push public/ → GitLab Pages deploys it) and makes the project easy to fork and self-host without a Node.js toolchain beyond the dev server.
The tradeoffs are real — no type safety, no module splitting, global state everywhere — but acceptable for a project of this size and pace. If the file grows significantly or type errors become a recurring problem, the natural upgrade path is Vite + TypeScript: split index.html into modules, add a vite.config.ts, update the CI script: step to run vite build, and point GitLab Pages at dist/ instead of public/. That migration is well-understood and can be done incrementally.
Reporting issues
Use the 🐛 Report button in the top bar — it collects debug info automatically.
License
The source code is licensed under the GNU Affero General Public License v3.0. If you run a modified version of this app as a network service, you must publish the modified source under the same license.
The game rules content (Cypher System types, descriptors, foci, mechanics) is used under the Cypher System Open License © Monte Cook Games. The CSRD is free for use in digital products; see the CSOL for full terms.
© 2026 Pavel Safronov
About
This game is written by Pavel asking Claude to implement features. This paragraph - written by Pavel - is the only hand-written code in this repo. Part of the experiment here is being able to create a complex RPG game with Claude, while also utilizing Claude in the game itself. Let's see how this goes. Enjoy!
