Skip to content

Development And Contributing

Errors edited this page Jun 24, 2026 · 8 revisions

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.

[insert image]

Project Overview

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.

Requirements

Development requires:

  • Node.js.
  • npm.
  • Git.

The release workflow currently uses Node 24 in GitHub Actions.

Install Dependencies

From the project root, install dependencies:

npm install

Run In Development

Start the app in development mode:

npm run dev

This builds the Electron files, starts the Vite dev server, waits for the local dev URL, and launches Electron.

Build The App

Build renderer and Electron files:

npm run build

This runs TypeScript checks, builds Electron files, and builds the Vite renderer output.

Run Lint

Run ESLint:

npm run lint

Run Tests

Run the Vitest suite:

npm test

Run The Full Local Check

Run the full local verification pass:

npm run check

This runs TypeScript typechecking, ESLint, and Vitest tests.

Electron Smoke Test

After a production build, run the Electron smoke test:

npm run smoke:electron

The 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.

Package For Windows

To create a Windows package:

npm run package:win

Successful Windows packaging creates output in the release/ folder, including the installer and unpacked app.

Package For macOS

To create a macOS package:

npm run package:mac

macOS signing and notarization are not currently configured.

Project Structure

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/

Electron Main Process

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.ts
  • electron/assets.ts
  • electron/assetProtocol.ts
  • electron/persistenceCodecs.ts
  • electron/metadataErrors.ts

Preload Bridge

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 Models

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.

Renderer

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/

Canvas Rendering

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 Ownership

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 Projection

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.

Testing Guidance

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/

Icons

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:icon

Windows packaging uses build/icon.ico.

macOS packaging uses build/icon.icns.

Release Process

Release builds are created by GitHub Actions when a version tag matching v*.*.* is pushed.

A typical release flow:

  1. Create or update a release branch.
  2. Bump the app version.
  3. Update CHANGELOG.md.
  4. Run local verification.
  5. Commit release metadata.
  6. Push the release branch.
  7. Create and push the version tag.
  8. Confirm the GitHub Actions release build succeeds.
  9. Check the GitHub Release assets.

For detailed steps, see:

  • docs/release-process.md

Version Numbers

The app version is stored in:

  • package.json
  • package-lock.json

Use npm to update both:

npm version 0.1.9 --no-git-tag-version

Only bump campaign or scene schema versions when saved data shape changes.

Schema constants live in:

  • src/shared/localvtt.ts

GitHub Release Assets

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.

Pull Request Checklist

Before opening a pull request, run:

npm run check
npm run build

For changes affecting Electron, packaging, Player View, or release behavior, also run:

npm run smoke:electron

For packaging changes, test the relevant package command:

npm run package:win

or:

npm run package:mac

Contributor Notes

When 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.

Useful Documentation

Project docs include:

  • docs/architecture.md
  • docs/codebase-audit.md
  • docs/layer-ownership-rules.md
  • docs/release-process.md

These are useful references for architectural decisions, release flow, and feature placement.

Related Pages

Clone this wiki locally