Case study · Personal project
Cartomancer
A map-first campaign manager for Dungeon Masters, with Spark, an optional AI librarian that files what happened at the table, keeps a ledger of what's true in the world and flags contradictions. The DM always has the final word, and the whole thing works without AI.
- Role
- Solo design and build, directing a team of AI coding agents
- Status
- Live · still building
- Built with
- React · TypeScript · Vite · Leaflet · Dexie.js · Zustand · Supabase · MCP

1,596
automated tests
- 01 Brief
- Most D&D tools are either a wiki you fill in by hand or an AI that writes lore for you. I wanted a librarian: something that files what happened at the table, keeps the record straight, and leaves the DM with the final word.
- 02 Approach
- Map-first and local-first. Spark, the optional AI, files session notes into a canon ledger and flags contradictions, and everything it suggests waits in one review inbox to keep, edit or undo. I built it solo, directing AI coding agents through written specs, reviews and browser verification.
- 03 Outcome
- Live at cartomancer-phi.vercel.app: about 90,000 lines of TypeScript and 750+ commits, with 1,596 automated tests. I use it to run my own campaign.
01What sets it apart
- 01
Canon you can trust
Every fact records when it's true (timeless, backstory, played in Session 4, or planned) and who may know it, and a permanent changelog shows which sentences Spark wrote and which the DM did.
- 02
Nothing lands without the DM's say
Spark's suggestions arrive marked in one review inbox. Keep, edit or discard them, and undo any batch in one step.
- 03
Works without AI
Every Spark feature has a manual path, so it's a complete campaign manager with no API key at all.
- 04
Bring your own key, see the cost first
AI calls go straight from the browser to the provider, every action shows its estimated price before it runs, and a spend cap stops surprises.
- 05
The DM owns the data
Worlds live on the device, back up to a folder the DM chooses, and can sync through the DM's own server. Export is always open.
- 06
Built from how DMs actually prep
Planning follows Mulligan's toy method and Matt Mercer's scene prep: situations, not scripts, with arcs as seasons and sessions as episodes.
02Engineering highlights
- Local-first data safety. Multi-step writes run in single transactions, and undo uses compare-and-swap so it never overwrites newer edits.
- Sync without data loss. Last-write-wins with a base-version guard, so a device that has never synced can't overwrite the cloud copy, plus 20 retained snapshots per world.
- Provenance. Every AI-written sentence is tagged until kept, and a changelog records Spark and DM edits side by side.
- AI cost discipline. Model tiers matched to each task, prompt caching of the world context, estimates before every call, and untrusted text wrapped before it enters a prompt.
- Quality process. 1,596 automated tests, a golden-set evaluation for fact extraction, a coverage ledger of what was last tested and at which commit, and multi-agent reviews including panels of simulated DMs.
- Accessibility. A UI-scale setting, no text under 12px, and theme tokens throughout, tested at 140% scale on tablet and phone widths.