Repository navigation
Development And Contributing
This page is for developers and contributors who want to run Local VTT locally, understand the project structure, test changes, or prepare releases.
For user-facing setup, see Getting Started.
Local VTT is an Electron desktop app with a React renderer and Canvas 2D scene rendering.
The app is local-first and stores campaign data in portable local folders.
The runtime is split into:
- Electron main process code.
- A secure preload bridge.
- Shared TypeScript models and validation.
- React GM View.
- React Player View.
- Canvas-based scene rendering.
Development requires:
- Node.js.
- npm.
- Git.
The release workflow currently uses Node 24 in GitHub Actions.
From the project root, install dependencies:
npm installStart the app in development mode:
npm run devThis builds the Electron files, starts the Vite dev server, waits for the local dev URL, and launches Electron.
Build renderer and Electron files:
npm run buildThis runs TypeScript checks, builds Electron files, and builds the Vite renderer output.
Run ESLint:
npm run lintRun the Vitest suite:
npm testRun the full local verification pass:
npm run checkThis runs TypeScript typechecking, ESLint, and Vitest tests.
After a production build, run the Electron smoke test:
npm run smoke:electronThe smoke test builds the app, launches the production Electron entrypoint, verifies the GM preload bridge, opens Player View through IPC, sends a Player View idle state, and checks Electron display enumeration.
To create a Windows package:
npm run package:winSuccessful Windows packaging creates output in the release/ folder, including the installer and unpacked app.
To create a macOS package:
npm run package:macmacOS signing and notarization are not currently configured.
Important project areas include:
electron/
main.ts
preload.ts
persistenceCodecs.ts
assetProtocol.ts
src/
shared/
renderer/
src/renderer/
views/
components/
canvas/
hooks/
lib/
styles/
docs/
architecture.md
codebase-audit.md
layer-ownership-rules.md
release-process.md
tests/
electron/
renderer/
shared/
The Electron main process handles:
- Application lifecycle.
- Secure window creation.
- Campaign folder IO.
- Asset import and copy operations.
- Metadata backups.
- Player View window control.
- Native filesystem interactions.
Key files include:
electron/main.tselectron/assets.tselectron/assetProtocol.tselectron/persistenceCodecs.tselectron/metadataErrors.ts
The preload bridge exposes a typed API to the renderer through Electron's contextBridge.
The renderer does not receive unrestricted filesystem access.
Key file:
electron/preload.ts
Shared TypeScript code defines campaign and scene models, validation, defaults, schema normalization, and Player View-safe scene projection.
Key area:
src/shared/
Campaign and scene data include schema versions so future migrations have an explicit upgrade path.
Only bump schema versions when the saved campaign or scene JSON shape changes.
The renderer contains the React GM View, React Player View, canvas rendering code, hooks, feature libraries, and styles.
Key areas include:
src/renderer/views/src/renderer/components/src/renderer/canvas/src/renderer/hooks/src/renderer/lib/src/renderer/styles/
Local VTT uses Canvas 2D for most map and scene rendering.
Canvas rendering covers:
- Static maps.
- Video maps.
- Pan and zoom.
- Grids.
- Fog of war.
- Tokens.
- Drawings.
- Templates.
- Weather.
- Animated effects.
- Ruler measurement.
- Scene overlays.
Three.js is used where 3D rendering is needed, such as dice.
Layer responsibilities are intentionally narrow so tools, rendering, visibility, and persistence stay predictable.
For detailed layer rules, see:
docs/layer-ownership-rules.md
General guidance:
- Put visibility and reveal logic in Fog of War.
- Put environmental visuals in Effects.
- Put annotations and templates in Drawings.
- Put movable map markers in Tokens.
- Keep GM-only prep content private.
- Do not overload reserved future layers.
Player View receives a filtered scene payload.
Player-safe projection should prevent GM-only data from leaking into the Player View.
When adding features, make sure Player View visibility rules are handled centrally and tested.
Use focused tests for small changes and broader tests for cross-cutting behavior.
Important test areas include:
- Campaign actions.
- Persistence normalization.
- Player View sync.
- Scene editing.
- Token behavior.
- Fog and visibility.
- Map calibration.
- Measurement.
- Dice.
- Turn order.
- Effects.
- Electron metadata and asset behavior.
Tests live in:
tests/shared/tests/renderer/tests/electron/
Application icons live in the build/ folder:
build/
icon.svg
icon.ico
icon.icns
The editable icon source is build/icon.svg.
To regenerate icon files after changing the source artwork:
npm run generate:iconWindows packaging uses build/icon.ico.
macOS packaging uses build/icon.icns.
Release builds are created by GitHub Actions when a version tag matching v*.*.* is pushed.
A typical release flow:
- Create or update a release branch.
- Bump the app version.
- Update
CHANGELOG.md. - Run local verification.
- Commit release metadata.
- Push the release branch.
- Create and push the version tag.
- Confirm the GitHub Actions release build succeeds.
- Check the GitHub Release assets.
For detailed steps, see:
docs/release-process.md
The app version is stored in:
package.jsonpackage-lock.json
Use npm to update both:
npm version 0.1.9 --no-git-tag-versionOnly bump campaign or scene schema versions when saved data shape changes.
Schema constants live in:
src/shared/localvtt.ts
Published GitHub release assets may be immutable.
If a release has already been published for a version tag, create a new patch version and tag rather than trying to replace the existing release assets.
For example, if v0.1.8 is already published, use v0.1.9 for a corrected build.
Before opening a pull request, run:
npm run check
npm run buildFor changes affecting Electron, packaging, Player View, or release behavior, also run:
npm run smoke:electronFor packaging changes, test the relevant package command:
npm run package:winor:
npm run package:macWhen contributing:
- Keep changes focused.
- Follow existing project structure.
- Add or update tests for behavior changes.
- Avoid moving unrelated files.
- Keep Player View visibility rules in mind.
- Preserve local-first campaign portability.
- Do not introduce unrestricted renderer filesystem access.
- Update docs when workflows or user-facing behavior changes.
Project docs include:
docs/architecture.mddocs/codebase-audit.mddocs/layer-ownership-rules.mddocs/release-process.md
These are useful references for architectural decisions, release flow, and feature placement.