Repository navigation
EN Contribute Dev Loop
Français · Type: how-to · Audience: contributor · Context: engine repository · Status: ready · Applies from: 4.1.11
How to change the engine one small step at a time, and how to carry a change through every place that reads it. The worked case is the hardest common one: adding or changing a command of the DSL.
A change that compiles, whose own tests pass, that the validator, the solver, the Studio and the MCP all understand, and that you have looked at in the browser, before you run the full list of Before a pull request.
The engine repository, on your machine. The command table (HANDLERS, src/engine/core/command-handlers.ts) exists
since 4.1.5; the catalogue src/engine/core/cmds.ts since 4.1.0. This page describes the code as of 4.4.0.
- A prepared repository: Developer setup.
- The map of the code: Architecture; the walk through it: Code tour.
In the engine repository, on your machine. GAME=<id> picks another game than the current one
(Developer setup).
-
Run the tests closest to what you change, not the whole suite, while you work.
# in the engine repository npx vitest run tests/core.test.ts # one file npx vitest run tests/core.test.ts -t "fixture game" # one test by name npx vitest tests/cmds.test.ts # watch mode: re-runs on save
Which tests run when says which file tests what.
-
Type-check as you go: the catalogue and the command table refuse a command you forgot, at compile time.
# in the engine repository npm run -s tsc -- --noEmit npm run -s tsc -- --noEmit -p tsconfig.strictest.json # every index access checked in src/
-
Ask the game. After a change that a game can feel, the truth commands answer in seconds:
# in the engine repository npm run validate && npm run solve && npm run lint
validatenames broken ids and values,solveproves the game can still be finished from New Game,lint(the content lint) finds conditions nothing sets, hidden rules and actions never run.
-
Look at it.
npm run devserves the game athttp://localhost:5173/;npm run studioopens the local Studio, which shows each room rendered by the real engine and reloads when a file changes. A visual change is looked at, not assumed:?dev&at=<checkpoint>starts the game at a checkpoint (Dev URL parameters).
-
Changing a command, end to end. A command (
Cmd) is read by the engine, the validator, the solver, the puzzle graph, the texts, the Studio and the MCP. Touch each in this order; the type check or a test refuses what you forget:-
Type. Its variant of
Cmdinsrc/engine/core/types/content.ts, with a doc comment. -
Catalogue. Its key in
CMD_KEYS(src/engine/core/cmds.ts): a variant missing from it, or a key no variant has, does not compile. Add it toCHANGESif it changes the state (the solver and the no-op memo read that set), toCONTAINERSandsubListsif it holds command lists. -
Engine. Its handler in
HANDLERS(src/engine/core/command-handlers.ts), whichstep(src/engine/core/command-runtime.ts) looks up by key; the type of the table refuses a missing handler. The screen is reached through aPresentermethod (src/engine/core/ports.ts), implemented byDomPresenter(src/engine/dom/presenter.ts) and byFakePresenter. If it touches the state, what it reads and writes is recorded (Engine.readsandEngine.writes). -
Validator. Its references and values checked in
src/engine/tools/validate.ts. -
Solver and puzzle graph. Nothing to do if the catalogue is right; a command that branches or waits needs a
look at
src/engine/tools/puzzle.tsandsrc/engine/tools/solve/expansion.ts. -
Texts. A command that carries a line needs its branch in the texts walker,
src/engine/tools/i18n.ts(extraction, locales), besidesay,toast,guideandchoice. -
Studio. Its form in
src/studio/schema.ts; the MCP reads the same schemas (MCP tools). -
Tests. An example in the table of
tests/cmds.test.ts(every key must have one), a behaviour test intests/core.test.ts, and a validator case. -
Docs. The wiki pages of the command, in both languages (Game commands,
DSL reference), and the branch's fragment under
changes/(Conventions).
A review of such a change reads these files in this order.
-
Type. Its variant of
-
Worked example:
{ shake: ms }, the screen shaking for a moment.- The type is
| { shake: number }incore/types/content.ts. -
'shake'is inCMD_KEYSbut not inCHANGES: it changes nothing the solver keys on, so a shake is a no-op for a proof. - Its handler in
command-handlers.tscallseng.ui.shake(c.shake)unless a cutscene is being skipped (ctx.fast).DomPresenter.shakeadds the scene'sshakeCSS class for that many milliseconds;FakePresenterignores it. - The validator accepts it inside a looping animation's frame events, with
sfx, and nothing else (tools/validate.ts: "a looping animation only plays sounds and shakes at a frame"). - The Studio offers it as "Shake (ms)", from 0 to 5000 in steps of 50 (
src/studio/schema.ts). -
tests/cmds.test.tsholdsshake: { shake: 2 }.
- The type is
Limit ·
no-function-in-gamesA game holds no function. Logic a game needs beyond the DSL is a custom command or a minigame, trusted code declared beside the content and reached by name (Custom code); it is not a new engine command.
-
npm run -s tsc -- --noEmitis silent; the test files you touched pass. -
npm run validate && npm run solveend green on the sample game (and onGAME=referenceif your change reaches staging or several characters). - What you changed looks right in the browser or the Studio.
Then go through Before a pull request.
| Symptom | Cause | Fix |
|---|---|---|
'a Cmd variant is missing from CMD_KEYS' at compile time |
The variant was added to Cmd, not to the catalogue |
Add its key to CMD_KEYS in core/cmds.ts
|
'CMD_KEYS names a key no Cmd has' |
The key was added to the catalogue only | Add the variant to Cmd
|
A type error on HANDLERS
|
No handler for the new key | Add it to the table in core/command-handlers.ts
|
tests/cmds.test.ts fails on the new key |
No example in its table | Add one |
quality:baseline -- --check reports a moved digest |
The change altered what the engine does on a frozen game | Intended: rewrite the baseline and say so in the fragment; not intended: find the regression (The quality baseline) |
The source files above; tests/; the wiki pages of the command; changes/<slug>.md. A command that the solver reads
can move tests/quality-baseline.json, which is then rewritten on purpose.
Everything is in Git: git restore <file> or git stash undoes a local change. GAME=demo npm run game puts the .cache/game
link back when a GAME= experiment left it elsewhere.
- Architecture, Code tour, Import boundaries.
- Which tests run when, Before a pull request.
- ADR 0002, declarative content; ADR 0003, the solver runs the engine.
Generated publication · publication générée — current documentation · documentation courante: quest'n'click 4.4.0 r1, documentation revision · révision de la documentation 8dc717c69acb62c4742b69c54a7e7dfb620f75d8.
Earlier versions and permalinks · versions précédentes et liens permanents: https://wanoo.github.io/quest-n-click/docs/
An edit made in this wiki is overwritten at the next publication · une modification faite dans ce wiki est écrasée à la publication suivante.
Edit the source · Modifier la source · Report an error · Signaler une erreur
Index (6)
Start (6)
Play (9)
Install (17)
- Requirements
- Install from the release archive
- Install from npm, once published
- Install from the repository to work on the engine
- doctor: checking your machine
- Image toolchain
- Audio toolchain: ffmpeg, fluidsynth, Furnace, uv
- Upgrade
- Upgrade notes: 4.4
- Upgrade notes: 4.3
- Upgrade notes: 4.2
- Upgrade notes: 4.1
- Upgrade notes: v3
- Upgrade notes: v2 to v3
- Coming from web-scumm
- Package reference
- Install troubleshooting
Create a game (55)
- Your first game
- Layout of a created project and of the engine repository
- The working loop
- Content principles and the identity contract
- Rooms
- Geometry: placement, walk zones, masks, layers, camera
- Something is visible but unreachable
- Reactions
- Game commands
- Conditions
- Flags, variables and events: which to use
- Custom code
- Characters
- Items and inventory
- World map
- Dialogues
- Scripts and events
- Moving characters: patrols and walks
- Exits
- Chapters and objectives
- State and saves: persistent or temporary, renaming an id, migrations
- Staging: wide rooms and animations
- The stage: lights, particles, floors
- Skin and fonts
- Title and credits
- Heroes: several characters and hero choice
- Built-in minigames
- A custom minigame
- Translations
- Music in stems
- Sound effects
- Voices: per language and per hero
- Images: prompts, cutting sheets, transparency, scale
- Asset provenance
- The storyboard, source of truth
- Puzzle design
- Classic mechanics
- Review pages
- DSL reference
- Checking your game
- What the solver proves
- Solver options
- Playtests
- Remix
- Speedrun for authors
- The sealed ending
- Production template
- Example games
- Working with an AI
- Build and release a game
- Publish on GitHub Pages
- The static game on Clever Cloud
- Other static hosts
- Sub-path, cache and service worker, incomplete deploys, going back
- Testing on a phone over the LAN
Local Studio (24)
- The local Studio: overview and launch
- Edit a room
- Placement and stage
- Preview, apply, undo
- Storyboard
- Assets and cutting
- Check: validator, solver, critical path, heat, health, coverage
- Before and after captures
- Semantic diff
- Play and replay a session
- Rule explainer
- Language and objectives
- Voices and the heroes × languages matrix
- Map
- Notes
- Remix in the Studio
- Music
- The Assistant: bring your own key
- Demo mode and studio-apply
- Local and LAN security
- Studio API
- Local MCP: setting up each client
- MCP tools
- Studio troubleshooting
Team Studio (21)
- What runs where
- Concepts: revision, transaction, span, lease, preview, build
- Starting as an invited dev
- Working together day to day
- Roles and actions: the full matrix
- Invitations
- Managing members
- Write refused on the hosted Studio: stale base revision (409)
- Write refused on the hosted Studio: span locked (423)
- Recovering after a lost lease, a disconnection or a stale preview
- Comments
- Map and semantic diff
- Publishing builds
- Remote MCP
- The game in Git
- Upgrading the engine of a hosted game
- Hosted assets
- The server's command line
- Health and metrics routes
- Trying it locally with compose.yml
- Known limits
Clever Cloud (23)
- Clever Cloud: overview, cost and prerequisites
- Apps and add-ons
- Domains and TLS
- Keycloak
- Generic OIDC and GitLab
- Configuration
- First deployment
- Backups
- RPO and RTO
- Restore the Studio on a fresh installation
- Redeploys
- Upgrading the server and checking state after a migration
- Limits of going back
- Monitoring
- Security
- Rotating keys
- Recovering admin access
- Changing domain or OIDC provider
- Worker, PostgreSQL or Cellar down
- Exporting the game and leaving the installation
- Retention
- Clever Cloud troubleshooting
- Costs and teardown
Reality Bridge and connectors (16)
- The Reality Bridge: what it is
- Quick start
- Guarantees
- Install and run the Bridge
- Backup and restore
- Several tenants
- Signals and the manifest
- The Bridge's command line
- Connectors overview
- Email connector
- Telnet connector
- SSH connector
- Open Badges connector
- The connector SDK
- Security: Biscuit and signatures
- Bridge and connector troubleshooting
Contribute (25)
- Welcome
- Developer setup
- The dev loop
- Before a pull request
- Conventions
- Writing documentation
- Architecture
- Code tour
- Import boundaries
- Which tests run when
- Mutation testing
- The coverage ratchet
- The quality baseline
- CI explained
- Field passes
- Benchmarks
- Releasing
- npm packages
- Decisions and ADRs
- Governance
- Bot pull requests
- Contributing with AI agents
- Security policy
- Code of conduct
- Licences and credits