Repository navigation
EN Create Routes
Français · How-to · Published, written and self-checked by an AI, not reviewed by a person · Applies from: 4.6.0
Give any character an itinerary: walk to a spot, wait, go through a door into the next room, and so on, on the world's clock, whether the player watches or not. The player can cross the character, follow it, speak to it, or use its absence for a puzzle.
Audience, context, and the statuses of what this page rests on
Audience: author · Context: engine repository, created project
A character on its rounds through several rooms that keeps going off screen. It stops while the player talks to it, waits at a door that is shut, and goes back to its rounds after a detour the story sends it on. Saves and replays keep where it is, and the solver proves the occasions it opens stay open.
- A created project (
game/) or the engine repository (games/<id>/). - From 4.6.0 "Routes" (ADR 0031). On an older engine, a character changes rooms only with
moveActor(Moving characters). - The playable example is
games/routes("Lou's Rounds"):GAME=routes npm run devin the engine repository.
- The character declared with a
room(where it starts) and awalkpose (Moving characters). - An actor for that character in every room the route crosses, and a walk area in each (geometry).
- The exits the route takes, declared in the rooms (rooms).
- The route goes in
game.ts(scripts) and the points in the layouts, which you place in the editor (?edit=<room>, or the Studio's Rooms tab). - Check from the root of the project:
npm run validate,npm run solveandnpm run lintin the engine repository, ornpx quest-n-click validate,solveandlintin a created project.
-
Place the points. In the editor, open the room, type a name in "Entry and route points", then press "Add a
route point" and drag it where the character stops. The layout keeps it under
points. A route never holds coordinates: it names points, and the geometry stays in the layout.
-
Write the route in
game.ts, among the game'sscripts(a route belongs to the game, never to a room).whois the character,fromthe room of the first step, and each step has a stableidand is one of:-
walka point of the room it is in; -
waitmilliseconds, with an optionalfaceorpose; -
exitthrough one of the room's exits, into the room it leads to, at its entry.
scripts: [ { id: 'rounds', loop: true, route: { who: 'neighbor', from: 'hall', steps: [ { id: 'desk', walk: 'desk' }, { id: 'paperwork', wait: 3000, face: 'left' }, { id: 'out', exit: 'out' }, { id: 'stalls', walk: 'stalls' }, { id: 'inspect', wait: 2500, face: 'right' }, { id: 'to-kitchen', exit: 'kitchen_door' }, { id: 'hello', walk: 'hello' }, { id: 'chat', wait: 2500, do: [{ if: { room: 'kitchen' }, then: [{ say: ['neighbor', 'Evening, Grandma!'] }] }] }, { id: 'to-street', exit: 'windows' }, { id: 'home', exit: 'hall_door' }, ], }, }, ],
The room of each step follows from
fromand the exits before it. Alooproute must end infrom. -
-
Make its absence the puzzle. Rules read where the character is, as for any moving character:
{ actorIn: ['neighbor', 'hall'] }. For example, the map can be searched only while Lou is out:if: { all: ['!cable_taken', { not: { actorIn: ['neighbor', 'hall'] } }] }.
-
React to an arrival with the step's
do: it runs once the step is done (arrived, waited, entered). Arrival commands run one route at a time, never during the player's action, and the route waits for them. Guard a line with{ if: { room: '…' } }when it only makes sense if the player is there.
-
Change the routine from the story.
-
{ suspendScript: 'rounds' }stops the route where it is (its step, its place, the wait left). -
{ resumeScript: 'rounds' }takes it up again. -
{ startScript: 'detour' }starts another route of the same character and suspends the one it had. - A route marked
manual: truestarts only that way. - A detour must bring the character back to the room of the suspended step before resuming it, for example with a
last step whose
dois[{ resumeScript: 'rounds' }]. -
whileholds a route in place while it is false; unlike a script, it never rewinds.
-
-
Shut a door on it. An
exitstep goes through only when the exit'sifholds. Until then, the character waits in front of the door and goes through on the tick the door opens. A walk link whoseifis false (stage.links) holds it the same way.
-
Check.
validatenames a missing point, exit or actor in the room the step is walked in, a loop that does not come back tofromor never makes progress, and two automatic routes for one character.solvelets time pass until a route's next stop (the choice "Route " in a path).lintadds the four codes below.
Guarantee ·
routes-clock-steps· referenced · executed on95341b04ba59· scope reviewed The world moves by whole ticks:nticks at once leave exactly the same state asnticks one at a time, so a run does not depend on the frame rate.
Guarantee ·
routes-offscreen· referenced · executed on95341b04ba59· scope reviewed A route goes on whether its room is shown or not: after the same ticks, the character is at the same place and the same step.
Guarantee ·
routes-hold· referenced · executed on95341b04ba59· scope reviewed A click on a character on a route holds it from the click to the end of that action; the other routes go on.
Guarantee ·
routes-shut-door· referenced · executed on95341b04ba59· scope reviewed A shut exit holds the character in front of it; it goes through on the tick after the exit opens.
Guarantee ·
routes-suspend· referenced · executed on95341b04ba59· scope reviewed Suspended, a route keeps its step, its place and the wait left; a resume away from the step's room is refused and reported (route-resume-misplaced).
Guarantee ·
routes-arrival· referenced · executed on95341b04ba59· scope reviewed Two arrival commands never run at the same time, and never during the player's action.
Guarantee ·
routes-saves· referenced · executed on95341b04ba59· scope reviewed A save made in the middle of a walk, a wait or at a shut door loads into the same world; a save from before 4.6.0 loads, and its routes begin from it.
Guarantee ·
routes-replay· referenced · executed on95341b04ba59· scope reviewed A session whose actions overlap the world's clock replays to the same state.
Guarantee ·
routes-solver· referenced · executed on95341b04ba59· scope reviewed The solver lets time pass until a route's next stop and proves the occasions it opens stay reachable.
Limit ·
routes-no-timingThe proof is about where routes stop (which step, which room, held or not), never about timing. Two paths that differ only by where a character stands inside a walk are one state for the solver.
Limit ·
routes-frozenThe world stands still in the pause menu, during a cutscene, a minigame or a room transition, and while the page is hidden. Nothing catches up afterwards: an hour in the background is not walked. A slow frame loses at most 250 ms of the world.
Limit ·
routes-overlapA session replays exactly when its entries do not overlap. An ordinary script's step still running while the player acts is replayed after that action, as before 4.6.0.
- In the game, the character walks its rounds and is found wherever its clock put it when you enter a room.
-
npm run solvefinishes, with "Route " steps where waiting matters, andnpm run solve -- --provesays the ending stays reachable from every state. -
GAME=routes npm run e2e -- <url> --prodplays the example in a browser: the hold, the frozen menu, the absence, a reload in the middle of the rounds, the shut door.
| Symptom | Cause | Fix |
|---|---|---|
no point "x" in the layout of "room" |
The point is placed in another room, or not at all | Place it in the room that step is walked in (the one reached by the exits before it) |
<who> has no actor in room "room" |
The character has no actor where the route takes it | Add an actor for it in that room and place it |
loop route "id" ends in "room", not in "from" |
The last exits do not lead back | Add the exit steps back to from
|
two automatic routes for <who> |
Two routes of one character start with the game | Mark the detour manual: true and start it with startScript
|
route-resume-misplaced in solve or lint
|
A resume while the character is in another room | End the detour in the room of the suspended step, then resume |
route-script-conflict |
A script or a rule moves the character (walk, place, moveActor) while its route may run |
Suspend the route first, resume it once the character is back |
-
game.ts(scripts) andlayout/<room>.json(points). - A save gains
world(the clock, in ticks) and, for each route,scripts.<id>.route(the wait left, held at a door, arrival commands pending) andpaused. - A session records the world's ticks at each sync point of an entry (
wt), and two entries:{ world }and{ routeDo }.
- Removing a route is a content change like any other. An old save keeps its character where it was, and a save
whose route step disappeared drops that route's state when it loads (
save adjusted after a content update). - To rename a step, use
renameScriptStepin a migration (State and saves).
-
docs/dev/adr/0031-npc-routes.md,docs/dev/PLAN-4.6-ROUTES.md -
src/engine/core/world.ts(the clock, loaded by every game),src/engine/core/route-runtime.ts(the routes, loaded only by a game that has some),src/engine/core/nav/walk.ts(the path finder),src/engine/dom/world-loop.ts(the frames and the freezing) -
src/engine/tools/validate/routes.ts,src/engine/tools/lint-routes.ts -
games/routes/(the example),tests/route-runtime.test.ts,tests/route-solve.test.ts
Generated publication · publication générée — current documentation · documentation courante: quest'n'click 4.6.0 r1, documentation revision · révision de la documentation 95341b04ba5991ace3b1a885e31250bc080fdb21.
Latest documentation · dernière documentation: https://quest-n-click.cleverapps.io/docs · https://quest-n-click.cleverapps.io/fr/docs; earlier versions · versions précédentes: each release's quest-n-click-docs-<version>.tar.gz · l'archive quest-n-click-docs-<version>.tar.gz de chaque release, https://github.com/Quest-n-Click/quest-n-click/releases
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 (19)
- Requirements
- Install from the release archive
- Install from npm
- 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.5
- Upgrade notes: 4.6
- 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 (56)
- 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
- Routes: a character's rounds through rooms
- 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