Install and hosting

Running it#

You need Node.js 22.5 or newer (24 recommended) and pnpm. With Nix, nix develop provides both.

git clone https://github.com/dntAtMe/dnd-table.git
cd dnd-table
pnpm install
pnpm build
pnpm start

The server prints the addresses to open:

  dnd-table server listening on 0.0.0.0:3000 (data: …/dnd-table/data)
  Open on this computer:  http://localhost:3000
  Open on your network:   http://192.168.0.12:3000

Players on the same Wi-Fi open the network address on their phones. Create an account, start a campaign (you become its GM) and share the invite code from the sidebar. The user guide covers the rest.

Configuration#

Set these as environment variables, e.g. SIGNUP_CODE=dragons pnpm start.

Variable Default Meaning
PORT 3000 HTTP port
HOST 0.0.0.0 Interface to listen on (127.0.0.1 keeps it off the network)
DATA_DIR data Where the database and uploads live (relative to the repository)
SIGNUP_CODE (none) If set, creating an account needs this code. Set it on any public server
COOKIE_SECURE false Set to true when served over HTTPS
LOG_REQUESTS false Log every HTTP request

Your data#

Everything is in data/: one SQLite database (dnd-table.db) and uploaded images and audio (uploads/). To back up, copy the folder while the server is stopped. To upgrade, pull the new version, then run pnpm install, pnpm build and pnpm start again; the database is migrated automatically on start.

Hosting it online#

For remote players, run it on a server behind an HTTPS reverse proxy that passes WebSockets through. With Caddy, which fetches certificates by itself:

table.example.com {
	reverse_proxy 127.0.0.1:3000
}
HOST=127.0.0.1 COOKIE_SECURE=true SIGNUP_CODE=your-secret pnpm start

Uploads are limited to 30 MB per image and 50 MB per audio file, so allow request bodies that large if your proxy limits them.

Development#

pnpm install
pnpm dev           # Vite on :5173 (open this) + API server on :3000, both reloading on change
pnpm test          # rules engine and server integration tests (vitest)
pnpm typecheck
pnpm screenshots   # regenerate docs/screenshots from a seeded demo campaign
pnpm site          # build the website (site/ and the docs) into _site/

pnpm screenshots builds the client, starts a throwaway server with a demo campaign and drives headless Chromium through it. It needs Playwright's browser once: pnpm exec playwright install --only-shell chromium.

apps/server        Fastify + WebSockets + SQLite (node:sqlite): accounts, campaigns, the live game
apps/web           React + Vite client: GM, player and table display views
packages/rules     The 2024 rules shared by client and server: dice, grid and fog, walls and movement,
                   vision, area templates, characters, combat, monsters, the knowledge base index
packages/protocol  REST bodies and WebSocket messages (zod schemas and types)
scripts            SRD import and screenshot tooling

The server is the source of truth. Clients send intents ("roll 2d20kh1+3, GM only", "move this token here"); the server checks them, resolves them and sends each connection only what its role may see. The database migrates itself on start-up (PRAGMA user_version).

Something unclear or out of date? Edit this page on GitHub.