An interactive map application for Dungeons & Dragons campaigns. Built with React (TypeScript), Django/GraphQL, and PostgreSQL, containerized with Docker.
- Interactive map viewing and editing
- Support for Underdark and Elturel maps (easily extensible to more)
- Edit mode for dungeon masters
- AI-powered map analysis agent to detect missing or mismatched location pins
- Frontend: React, TypeScript
- Backend: Django, GraphQL (Strawberry/Graphene)
- Database: PostgreSQL
- Infrastructure: Docker, Docker Compose
Open your web browser and navigate to:
Frontend (Main App): http://localhost:3000
Backend API/GraphQL: http://localhost:8000
- Docker Desktop installed and running
- Copy
.env.exampleto.envand fill in the values:
cp backend/.env.example backend/.env
- Then edit
backend/.envwith your actualDB_PASSWORD,SECRET_KEY, etc.
Running the frontend natively (outside Docker) avoids WSL2 overhead and filesystem polling lag on Windows. Keep the backend and database in Docker, run Vite locally.
Terminal 1 — backend + database:
docker compose up db backend
Wait until you see:
database system is ready to accept connections(database ready)Watching for file changes with StatReloader(backend ready)
Terminal 2 — frontend:
cd frontend
npm run dev
Then open http://localhost:3000 in your browser.
Press Ctrl+C in both terminals, then tear down the Docker services:
docker compose down
Only needed if you've changed requirements.txt or a Dockerfile:
docker compose up db backend --build
To run frontend tests (React/TypeScript with Jest):
cd frontend
npm test
To run backend tests (Django with PostgreSQL):
- Ensure the app is running:
docker-compose up --build - Run tests:
docker-compose exec backend python manage.py test
The analyze_map management command uses Claude vision to scan a map image, compare
identified locations against database pins, and report (or auto-create) missing entries.
docker compose exec backend python manage.py analyze_map --map underdark
| Flag | Description |
|---|---|
--map |
Map slug to analyze (underdark, elturel, …). Default: underdark |
--threshold |
Normalised distance tolerance for matching pins (default: 0.06) |
--display-width |
Viewport width used when pins were created (default: native image width) |
--create-pins |
Write missing locations to the database |
--create-issues |
Post a GitHub issue for each inconsistency found |
--image-path |
Override the path to the map image |
If the database is ever wiped, restore all location pins with:
docker compose exec backend python manage.py loaddata mapdata/fixtures/locations.json
After adding new pins (via Edit Mode or --create-pins), export them for CI:
docker compose exec backend python manage.py dumpdata mapdata.location --indent 2 > backend/mapdata/fixtures/locations.json