# Copilot Instructions — fvtt-chroniques-de-l-etrange FoundryVTT v13 game system for *Les Chroniques de l'Étrange* (Antre-Monde Éditions). The codebase is entirely in **ES modules** (`"type": "module"`) bundled with esbuild. There are no tests. ## Build commands ```bash npm run build # compile LESS → CSS and bundle src/system.js → dist/system.js npm run build:css # LESS only npm run build:js # esbuild bundle only npm run build:watch # rebuild on file changes npm run build:full # compile compendiums then build npm run pack:compile # compile packs-src/ → packs/ (LevelDB) npm run pack:extract # extract packs/ → packs-src/ (YAML source) ``` The built output goes to `dist/system.js` (sourced via the unbuilt `src/system.js` in `system.json` `esmodules`). ## Architecture The entry point is `src/system.js`, which wires up all FoundryVTT hooks (`init`, `ready`, `renderChatLog`, etc.). ### Layer structure | Layer | Path | Purpose | |---|---|---| | **Config** | `src/config/` | Constants, i18n pre-localization, runtime config, settings | | **Data Models** | `src/data/` | `TypeDataModel` subclasses defining actor/item schemas | | **Documents** | `src/documents/` | `CDEActor`, `CDEItem`, `CDEMessage` — thin document class overrides | | **UI / Sheets** | `src/ui/sheets/` | ApplicationV2 sheets for actors and items | | **UI / Apps** | `src/ui/apps/` | Standalone apps: `CDELoksyuApp`, `CDETinjiApp` (singletons) | | **UI / Core** | `src/ui/` | Rolling engine, dice registration, Handlebars helpers, initiative | ### Key domain concepts - **Wu Xing cycle**: Five aspects (metal, water, earth, fire, wood) drive all dice resolution. Each aspect maps to two d10 faces (see `ASPECT_FACES` in `constants.js`). `WU_XING_CYCLE` maps an active aspect to the five result categories: successes / auspicious / noxious / **loksyu** / **tinji**. - **Loksyu / Tin Ji**: Persistent world-level counters stored in game settings (`loksyuData`, `tinjiData`). Managed via `CDELoksyuApp` / `CDETinjiApp` singleton apps; updated from roll results in `ui/apps/singletons.js`. - **Three Treasures** (`threetreasures`): The character's Hei-Yang and Hei-Yin pools plus dice-level branches — used as the primary/secondary token attribute. - **Magics**: Five schools (`internalcinnabar`, `alchemy`, `masteryoftheway`, `exorcism`, `geomancy`), each with five specialities. Fully defined in `MAGICS` constant. ### Data model pattern All data models live in `src/data/` and extend `foundry.abstract.TypeDataModel`. Schema fields are defined with local factory helpers (`numberField`, `stringField`, `boolField`, `htmlField`) — prefer reusing these helpers when adding new fields. ### Sheet pattern Actor and item sheets extend `HandlebarsApplicationMixin(ActorSheetV2)` via `CDEBaseActorSheet` (`src/ui/sheets/actors/base.js`). Key conventions: - `static DEFAULT_OPTIONS` with `form: { submitOnChange: true }` — forms auto-save on every change. - Tab state is manually restored in `_onRender` by iterating `this.tabGroups` and calling `this.changeTab()` (AppV2 does not persist tab state natively). - Sheet actions (create/edit/delete item, editImage) are static private methods registered in `DEFAULT_OPTIONS.actions`. - `_prepareContext()` exposes both `system` and `systemData` (same reference) for template compatibility. ### Compendium source Human-editable compendium content lives in `packs-src/` as YAML. Use `npm run pack:compile` before building when pack content has changed, and `npm run pack:extract` after importing new data in Foundry. ## Key conventions - All user-visible strings go through i18n with the `CDE.` prefix namespace. New labels must be added to `lang/fr-cde.json`. - Handlebars templates live in `templates/` and are referenced by their full system path (`systems/fvtt-chroniques-de-l-etrange/templates/...`). Partials are pre-registered from `TEMPLATE_PARTIALS` in `constants.js`. - The system ID constant (`SYSTEM_ID = "fvtt-chroniques-de-l-etrange"`) is used everywhere — never hardcode the string. - CSS is authored in LESS (`css/cde-theme.less`) and compiled to `css/cde-theme.css`. Do not edit the `.css` file directly. - Global macro access is via `game.cde` (exposes `CDELoksyuApp` and `CDETinjiApp`). - The `dist/` directory is generated — do not commit it manually; it is rebuilt by `npm run build`.