Repository navigation
EN Create Chapters
Français · Type: reference + explanation · Audience: author · Context: engine repository, created project · Status: ready · Applies from: 4.1.14
A long game is easier to check, and to play, in parts. Three declarations of game.ts cut it: checkpoints with
goals (the chapters the solver proves one by one), invariants (what must never happen), and objectives (what
the player has to do, shown in the quest journal). This page is their reference, and says why they are separate.
The tools are written by name below (solve, validate). In a created project they run as
npx quest-n-click solve …; in the engine repository as GAME=<id> npm run solve -- ….
A checkpoint is a ready-made state: a room, an inventory, flags, unlocked places, prop states, where the moving
characters are, and for a game with several playable characters who is active and where the others stand. In
development you can jump to one; the solver can start from one (solve --from=<checkpoint>).
A checkpoint with goals is the end of a chapter. solve --chapters proves each chapter on its own,
from the previous checkpoint (or a new game) until its goals hold, then from the last checkpoint to the ending: a long
game is checked in small bounded searches, and a broken chapter is named.
checkpoints: {
garden: { room: 'garden', inventory: ['token'], goals: [{ has: 'token' }] },
market: { room: 'market', …, goals: ['tank_drained', { unlocked: 'market' }] },
},
// Must never become true (the solver reports the path that makes one true):
invariants: [{ all: [{ not: { has: 'token' } }, '!flowers_done'] }],| Field | Meaning |
|---|---|
room (required) |
The room the state is in. |
inventory, flags, unlocked, props
|
The state's inventory, flags, unlocked map places and prop states (<room>.<prop> keys). |
where |
Where the moving characters are (character → room); the others are in their starting room. |
active, players
|
Several playable characters: who is active, and the others' room, inventory and used items. |
used, seen
|
Items already used, and the topics, listeners and choices already seen (seen keys by id, such as topic.<id>). |
goals |
Conditions that must all hold when the chapter ending here is done. Only a checkpoint with goals ends a chapter. |
invariants is a list of conditions of game.ts that must never become true. The solver reports the path that
makes one true.
# in the created project
npx quest-n-click solve --chapters
# in the engine repository
GAME=<id> npm run solve -- --chaptersWith --prove, --chapters proves each chapter from every reachable boundary state of the previous one (deduped by
what the chapter reads), not from the hand-written checkpoint; that checkpoint must then be one of those boundary
states (used and seen let it name what the boundary state holds). A game without any checkpoint with goals is
proved by the global search (--prove), and that is not a failure. The options are on
Solver options.
Limit ·
chapters-hand-written-startWithout--prove, each chapter starts from its hand-written checkpoint. If that checkpoint is not a state the previous chapter can actually reach, the chapter's proof says nothing about the real game: use--proveto check it.
objectives names what the player has to do. Since 4.1.12 it feeds three things:
- the pause menu's Objectives list (a step under its parent, ✓ done, ○ open, a side objective in italics);
- the semantic journal:
objectiveCompleted, once, the first timedoneholds after an action; - the solver:
solve --goal=100%searches for a state where every objective that is notoptionalholds, instead of the ending.
objectives: {
key: { title: 'Find the pantry key', done: { any: [{ has: 'key' }, 'pantry_open'] } },
tank: { title: 'Drain the water tank', done: 'tank_drained', parent: 'key' },
pantry: { title: 'Open the pantry', done: 'pantry_open' },
guess: { title: 'Guess what is in the pantry', done: 'guess', optional: true },
},| Field | Meaning |
|---|---|
title (required) |
What the journal shows. Translated under objectives/<id>.title. |
done (required) |
The condition that completes it. |
optional |
A side objective: not part of 100 %. |
parent |
The objective this one is a step of: the journal shows it under its parent. |
Write done as a condition that stays true once true (a flag set once, an item kept). The journal never takes a
completion back, but a game loaded later counts as done only what holds then.
validate refuses:
- an id other than letters, digits and
. _ -, or longer than 64; - a missing
titleordone; - a
donethat can never hold (a flag nothing sets, an item nothing gives), with the reason; - an unknown
parent, and a cycle of parents.
It warns when a done that is not optional can be taken back by the content: the journal keeps it completed, but
--goal=100% needs every objective to hold at the same time.
The titles are translated like every text, and the menu's row is ui.objectives (English default "Objectives"). The
Studio's Language tab edits them (Language and objectives); the MCP tool
set_value writes them with id: "@game". Every condition and command, with its shape, is in the
DSL reference.
speedrun (4.1.14) declares speedrun categories and splits as content: triggers on the semantic events (a room
entered, an item acquired, an objective completed, the ending), the rules of each category (saves, pauses, hints,
reloads, Reality, the fingerprint components a run must match, the inputs), and the rules' version. validate
checks it; the guide is Speedrun for authors.
-
A checkpoint is for the author and the solver; the player never sees it. Its goals cut the proof into bounded searches, so a long game is not one search that runs out of states.
-
An objective is for the player. It says what to do next, and the journal records when it is done. It is not a chapter: objectives may be completed in any order, and a side objective never blocks the ending.
-
An invariant is a safety property: something the content must never allow, whatever the player does. The solver checks it on every state it explores.
-
The set of completed objectives is not in the save. What already holds when a game starts, loads or jumps to a checkpoint is counted done silently. The save format did not change for objectives, and the solver's state did not grow; the cost is that an objective whose condition held once and no longer does is open again after a load, hence the advice to write
doneas a condition that stays true.
Why objectives are their own primitive (a checkpoint is a place to start from, a flag says a fact, neither says that a player finished something) and when the engine completes them is ADR 0014.
-
solveand its options--chapters,--prove,--from,--goal=100%: Solver options, What the solver proves. - Conditions (
has,unlocked,all,any,not,flag): Conditions. - The semantic journal and
objectiveCompleted: Execution model.
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