Getting Started (New Developer Guide)

Audience: Someone who just cloned the repo and wants to understand the codebase.

See also: Architecture Overview, Extension Points, Expressions and Scripts, Security Model.

Prerequisites

  • Node.js ≥ 24 (see engines in package.json)
  • Git
  • A local Foundry VTT v14+ installation (for testing in-browser)

Setup

git clone <repo-url>
cd Song-of-Heroic-Lands-FoundryVTT
cp .env.local.example .env.local
# Edit .env.local to set FOUNDRYVTT_DEV_DATA, FOUNDRYVTT_QA_DATA, etc.
npm ci
npm run build

If the build succeeds, you’re ready. If tests fail, check tests/setup.ts — it configures the mock Foundry environment.

Key commands

CommandWhat it does
npm run buildFull pipeline: types → test → bundle
npm run build:typesTypeScript compilation only (fast check)
npm run testRun vitest
npm run test:watchWatch mode
npm run push:qaSync build to QA Foundry instance
npm run docsGenerate TypeDoc

How to read the codebase

Start here

  1. Architecture Overview — the mental model. Read this first.
  2. SohlLogic — the abstract base for all Logic classes. The class-level JSDoc explains the phase-batched lifecycle.
  3. Pick one item type and trace through its three classes:
    • Logic: src/document/item/logic/SkillLogic.ts (business rules) —
    • DataModel: src/document/item/foundry/SkillDataModel.ts (persisted schema)
    • Sheet: src/document/item/foundry/SkillSheet.ts (UI)

See the Being sheet end to end, in-app. Launch a world and run the Create a Character guided tour (offered on first load, or any time from Settings → Tour Management). It walks the full character-creation flow — Facade, Profile, Skills, Gear, Combat, Mysteries, and containers — and doubles as a live map of the Being sheet. See Writing Guided Tours for how it is built.

The mental model

The design and rationale live in the concept docs — read them there rather than duplicated here, so there’s a single source of truth that can’t drift:

  • Three-class pattern — every actor/item type splits into a Foundry-free Logic class (game rules), a DataModel (persisted schema), and a Sheet (UI), plus how to reach a document’s data via logic.data.
  • Phase-batched lifecycle and SohlLogic — how initialize → evaluate → finalize map onto Foundry’s prepare* hooks, and the barriers that let sibling items depend on one another.
  • Domain objects — the src/entity/ value objects (modifiers, results, body, movement, actions), rebuilt from persisted data each preparation cycle.
  • FoundryHelpers shim — how Logic stays Foundry-free: the fvtt prefix convention, and sohl.log.uiWarn / sohl.log.uiError for notifications.

How to make a change

Bug fix or small feature

  1. Read the relevant Logic class and its tests.
  2. Write a failing test first (TDD).
  3. Make the minimal code change.
  4. Run npm run build:types && npm run test.
  5. Update JSDoc if you changed public API.

New item type

See Extension Points — Item type extension for the full checklist.

Adding a domain object

Follow the pattern in src/entity/body/:

  1. Create the class with a Data interface for the persisted shape.
  2. Construct it during initialize() from DataModel data.
  3. Add updatePath and array helper methods if it wraps persisted arrays.
  4. Write tests in tests/domain/.

Testing

Tests use vitest with a Node environment — no Foundry VTT running.

  • Logic classes are tested by providing mock parent objects.
  • Domain objects (modifiers, results, body structure) are tested directly.
  • Foundry globals are shimmed via the FoundryHelpers mock.

See Testing Guide for the full setup.

Documentation structure

docs/
├── concepts/     Architecture, lifecycle model, security model
├── how-to/       Extension points, hooks, actions, testing, this guide
├── reference/    Type catalog, modifier model, combat pipeline, body structure,
│                 effects integration, runtime contracts
└── contributing/ Contribution workflow, changesets, system development

User guide content is authored in this repository as Markdown under assets/content/ (frontmatter type: doc), and compiled into Foundry journal entries during build (see Build & Deployment §5). It is source, not generated output: edit it here (#1445).

Where to find things

I want to…Look at…
Understand the architectureArchitecture
See all actor/item typesType Catalog
Understand how values are trackedModifier Model
Understand combat resolutionCombat Pipeline
Understand hit locationsBody Structure
Add house rules via moduleLifecycle Hooks
Add per-item behaviorMacros and Actions
Write testsTesting
Understand active effectsEffects Integration