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
enginesinpackage.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
| Command | What it does |
|---|---|
npm run build | Full pipeline: types → test → bundle |
npm run build:types | TypeScript compilation only (fast check) |
npm run test | Run vitest |
npm run test:watch | Watch mode |
npm run push:qa | Sync build to QA Foundry instance |
npm run docs | Generate TypeDoc |
How to read the codebase
Start here
- Architecture Overview — the mental model. Read this first.
- SohlLogic — the abstract base for all Logic classes. The class-level JSDoc explains the phase-batched lifecycle.
- 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)
- Logic:
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 → finalizemap onto Foundry’sprepare*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
fvttprefix convention, andsohl.log.uiWarn/sohl.log.uiErrorfor notifications.
How to make a change
Bug fix or small feature
- Read the relevant Logic class and its tests.
- Write a failing test first (TDD).
- Make the minimal code change.
- Run
npm run build:types && npm run test. - 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/:
- Create the class with a
Datainterface for the persisted shape. - Construct it during
initialize()from DataModel data. - Add
updatePathand array helper methods if it wraps persisted arrays. - 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
FoundryHelpersmock.
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 architecture | Architecture |
| See all actor/item types | Type Catalog |
| Understand how values are tracked | Modifier Model |
| Understand combat resolution | Combat Pipeline |
| Understand hit locations | Body Structure |
| Add house rules via module | Lifecycle Hooks |
| Add per-item behavior | Macros and Actions |
| Write tests | Testing |
| Understand active effects | Effects Integration |