Sits on your D&D table, listens, and pops up cards when entities are mentioned: NPCs, locations, factions, items. No lookup, no tab-switching.
iPad app and web app at dndref.com.
- Load your world data in Settings (Kanka, Notion, Homebrewery, Google Docs, or file uploads)
- Tap Start and set the iPad on the table
- Cards appear as entities are mentioned
- Pin to keep a card visible; dismiss when done
- Toggle dark/light mode in Settings
Detection runs every 2 seconds using fuzzy matching against your loaded entities. No AI in the live path, just fast deterministic string matching.
You can have multiple sources active at once. Mix and match as needed.
| Source | What it loads | Notes |
|---|---|---|
| D&D 5e SRD | ~350 monsters + magic items | Enable per-source in Settings |
| Kanka | Characters, locations, factions, items | Requires API token + campaign ID |
| Homebrewery | Any public brew | Paste the share URL |
| Notion | Pages from your workspace | Requires integration token + page URLs |
| Google Docs | Any public doc | Paste the share URL |
| File upload | .md, .txt, .json files |
Obsidian exports, campaign notes, etc. |
| AI parsing | Paste text, Claude extracts entities | Requires Anthropic API key |
- Get your API token at kanka.io/en/profile/api
- Find your campaign ID in the URL:
kanka.io/en/campaign/12345
- Create an integration at notion.so/my-integrations
- Share each target page with the integration
- Paste page URLs (comma-separated) in Settings
Paste any campaign text and Claude pulls out named entities into a structured upload. Uses Haiku (~$0.001 per parse). Requires an Anthropic API key from console.anthropic.com.
Web Speech works in Chrome and Edge, no API key needed. Fine for quick testing.
Deepgram works on web and iPad. ~$0.004/min, about $0.72 for a 3-hour session. If you're actually running this at a table, Deepgram is more reliable. Get a key at console.deepgram.com.
Uses just. Run just with no args to list everything.
just dev # web dev server
just start # Expo with QR code for iPad/Expo Go
just check # TypeScript typecheck
just lint # ESLint linting
just build-web # export static build to dist/
just ship-web # build + deploy to Cloudflare Pages in one step
just proxy-dev # run CORS proxy locally (localhost:8787)
just proxy-deploy # deploy CORS proxy to Cloudflare Workers
just screenshot # Playwright screenshot tests (requires built dist/)
just screenshot-dark # Dark mode screenshot tests
just build-ios # EAS build for App Store (requires eas.json)
just build-ios-dev # EAS build for device testing
just submit-ios # submit to App StorePushes to main run GitHub Actions checks, build the web app, and deploy dist/
to Cloudflare Pages project dnd-ref. The CORS proxy Worker deploys from the
same workflow only when workers/cors-proxy/, package.json, or
package-lock.json changes. Manual deploy commands remain available through
just ship-web and just proxy-deploy.
Required GitHub repository secrets:
CLOUDFLARE_API_TOKEN
CLOUDFLARE_ACCOUNT_ID
Requires an Apple Developer account and EAS:
npm install -g eas-cli
eas login
eas build:configure # generates eas.json
just build-ios-dev # first buildNotion, Google Docs, and the Anthropic API block browser requests via CORS. On web, calls route through a Cloudflare Worker at proxy.dndref.com. On native (iOS), everything goes directly.
To deploy your own:
npx wrangler login
just proxy-dev # test locally at localhost:8787
just proxy-deploy # deploy to Cloudflare WorkersAfter deploying, add a CNAME in Cloudflare DNS: proxy -> dnd-ref-proxy.<account>.workers.dev. Then uncomment the [[routes]] block in workers/cors-proxy/wrangler.toml and redeploy.
app/
index.tsx -- session screen (card grid + controls)
settings.tsx -- data sources, STT, file uploads
debug.tsx -- transcript feed for troubleshooting
_layout.tsx -- tab layout + context providers
src/
entities/
index.ts -- Entity type + WorldDataProvider interface
detector.ts -- fuse.js fuzzy matching
ai-parser.ts -- Claude entity extraction
providers/
srd.ts -- D&D 5e SRD via Open5e API (cached)
kanka.ts -- Kanka campaign API
homebrewery.ts -- Homebrewery public brews
notion.ts -- Notion workspace pages
google-docs.ts -- Google Docs public export
markdown.ts -- Generic markdown parser
file-upload.ts -- AsyncStorage-backed file uploads
stt/
index.ts -- STTProvider interface
deepgram.ts -- Deepgram streaming WebSocket
web-speech.ts -- Web Speech API
context/
session.tsx -- Session state, STT lifecycle, entity detection
data-sources.tsx -- Data source settings + upload versioning
ui-settings.tsx -- Card size preference
proxy.ts -- CORS proxy URL (web only)
theme.ts -- Colors + fonts
workers/
cors-proxy/
index.ts -- Cloudflare Worker: proxies Notion, Google Docs, Anthropic
wrangler.toml -- Deployment config
React Native + Expo SDK 52, Expo Router, fuse.js for fuzzy matching, Deepgram or Web Speech for STT, AsyncStorage for settings and uploads. Hosted on Cloudflare Pages with a Cloudflare Worker handling CORS for the API calls that need it.