Skip to content
quest'n'click

ContributeReferenceFor contributorsApplies from 4.1.14

Import boundaries

Cette page en françaisThis page on the GitHub wiki

What each folder of src/engine/ may import, where each responsibility of the engine, the player and the solver lives, and what is public. The source is src/engine/BOUNDARIES.md; tests/boundaries.test.ts checks the rules on every run of the unit suite.

since 3.9.0

The layers and what they may import

Values

LayerFolderMay importNever
Corecore/itself, plain packages (zod/mini)the DOM, tools, dev, minigames, the Studio
Playerdom/, minigames/, ending/, boot.tscore, each other; tools/i18n (locales at boot); tools/replay and dev/ only through import()the solver, the validator, the linter, any other tool, the Studio, tweakpane
Scenescene/ (4.1.11)core (the painter's specs as types only)the DOM, tools, dev, the Studio, a painter
Realityreality/ (4.1.1)core, plain packages (zod/mini); WebCryptothe DOM, tools, dev, the Studio, the Bridge (bridge/)
Toolstools/corethe DOM (they run in Node, workers and tests)
Devdev/anythingbeing imported statically by the player

Outside src/engine/, the test also holds two rules of 4.1.1: the engine never imports the Bridge (Biscuit, keys and the server stay out of every game), and the Bridge reaches neither the Studio, the tools, nor a game: only the protocol it shares with the player.

The check does not sort packages: keeping the core's packages plain is left to review.

Constraints

  • The player's first visit is held to assetBudgets.initialJsKB (npm run verify:dist): the minigames load when one starts (minigames/meta.ts keeps what the tools read of them), the dev panel and the Studio on demand.
  • A painter (dom/render-*.ts, dom/renderer.ts, dom/frame-renderer.ts) never imports the engine, its ports or its runtime modules, not even as a type (4.1.11, D21): it is given frames and specs, and answers with intentions.
  • No cycle of static imports anywhere in src/engine (4.1.0): a module never imports itself back. Types (import type) are erased and do not count.

Behaviour on an unknown folder

A new folder under src/engine/ belongs to no layer of the test until one is written for it: add it to BOUNDARIES.md and to tests/boundaries.test.ts together.

since 4.1.0

Inside the core (4.1.0 "Clarity")

Engine (core/engine.ts) is the facade: its state, its lifecycle (new game, load, checkpoint) and one forwarding method per operation, in the same order of effects as before the split. What each operation does lives in a module of its own, a function taking the engine as its first argument:

ModuleWhat it does
core/session-runtime.tsthe session: entries opened and closed, the answers recorded, digests, replay's feed
core/event-runtime.tsemit: scripts waiting for the event, then the room's listeners, then the game's
core/script-runtime.tsscripts: their state, one step, loops, the scheduler
core/interactions.tsthe rule, kind or fallback that answers an action; lines, hints, the talk loop
core/command-runtime.tsexec and step: running Cmds, each through its handler in core/command-handlers.ts (4.1.5); where a command points in the room
core/world-queries.tsnames, kinds, visibility, prop states, targets, approach points
core/players.tsseveral playable characters: who is where, switch, swap, transfer
core/movement.tswalking, entering a room, the map and its travel, a teleport (4.1.1)
core/reality-runtime.tsa signal from outside: applied at most once, the cursor, the session entry (4.1.1)
core/engine-shared.tsthe context of a command, the journal's entry, small helpers
core/journal.tsthe semantic journal (4.1.11): what happened, in ids, numbered; emitted by the core alone
core/busy.tsthe busy owner (4.1.11): runs in progress, the tutorial step waited for, a skip
core/run-clock.tsthe run clock (4.1.14, ADR 0016): logical steps and time, told by the session and the commands; it never writes the state
core/prng.tsthe seeded generator (4.1.14): xoshiro128**, a stream per purpose; engine.random draws from logic
core/run-tape.tsa run's links (4.1.14): each entry with its events and the clock after it, the same live and replayed
core/journal-chunks.tsthe run's chunks chained by SHA-256 (4.1.14), written to a ChunkStore, read back checked
core/types/*.tsthe content format by subject; core/types.ts re-exports every name

The modules import Engine as a type only; tests/core-runtime.test.ts calls each directly.

since 4.1.0

Inside the player (4.1.0 "Clarity")

App (dom/app.ts) is the orchestration (4.1.11): its state, the constructor, and the composition of the engine, a Presenter (dom/presenter.ts) and the room view's renderer. The rest lives in modules called through forwarding methods, as in the core:

ModuleWhat it does
dom/presenter.tsthe Presenter the engine talks to (4.1.11): the scene's calls, lines, overlays, minigames, the ending; intent(), the one door of the player's input
dom/room.tsthe scene model: entities, walking, the camera; it makes the SceneFrame (scene/frame.ts) and paints it
dom/room-stage.tsa room's stage for the painter: conditions evaluated, images placed on the backdrop (4.1.11)
dom/frame-renderer.tsa painter (DOM or Canvas) as a Renderer: whole frames, an unchanged one skipped, a changed one by its differences
dom/shell.tsthe shell's elements, their layout for the screen, the accessible targets (from the frame's targets)
dom/side-fit.tsthe phone column's fit (pure): verb and slot heights that keep the tools row on a short screen
dom/input.tsverbs, the inventory bar, taps and double taps (verbFor, nearMiss), the keyboard, the action line
dom/speech.tslines with their voice, the transcript, phone calls, the choice of responses
dom/map-view.tsthe map and the travel animation
dom/menus.tstitle, pause (and the session export, through import()), save slots, restart, credits
dom/settings.tsthe player's preferences, their defaults and menu
dom/update.tsthe offline warm-ups and status, the update offered after a verified save
dom/storage.tsthe localStorage autosave and slots (when IndexedDB is missing)
dom/app-shared.tssmall helpers (element factory, tap timings, the FPS meter)
dom/reality-ui.tsthe world link (4.1.1): pairing, status, the client; loaded by import() only for a game with reality
dom/run-store.tsthe runs' IndexedDB store (4.1.14, web-scumm-runs): chunks and heads in one transaction, local records
dom/speedrun-ui.tsthe speedrun mode (4.1.14): the recorder on the app's engine, its timer, records, ghost, export; loaded by import() (it reaches tools/speedrun/ the same way)

since 4.1.0

Inside the solver (4.1.0 "Clarity")

tools/solve.ts re-exports what it exported before; the solver lives in tools/solve/:

ModuleWhat it does
src/engine/tools/solve/search.tssolve(): the frontier, the proof workers, termination and the verdict
src/engine/tools/solve/expansion.tsmakeExpander: every action worth trying from a state, run on the real engine; the no-op memo
src/engine/tools/solve/abstractions.tswhat a state is made of (dimensions), the canonical forms (players, mobility, ownership), dominance
src/engine/tools/solve/model.tsoptions, SearchNode, Expansion and a transition (TryRecord), with their invariants
src/engine/tools/solve/scenarios.tssignals from outside in a search: closed, a scenario, adversarial (4.1.1)
src/engine/tools/solve/report.tsthe result, its profile, the profile as text
src/engine/tools/solve/drive.tsan engine promise awaited, the guided tutorial's steps played meanwhile
src/engine/tools/solve/explosion.tsthe explosion profile (4.1.13): the states attributed to positions, inventories, flags, dialogues, scripts
src/engine/tools/solve/search/compact.tsthe store of the states seen (4.1.13, ADR 0015): by index, interned keys, parents, paths and session entries
src/engine/tools/solve/search/checkpoint.tsa search written down and taken up again (4.1.13): snapshot, header, fingerprint
src/engine/tools/solve/search/classify.tsthe verdict of a proof over the stored states: reverse reachability, softlocks and their causes
src/engine/tools/solve/search/dominance.tsdominance, symmetric items, independent sub-puzzles (4.1.13)
src/engine/tools/solve/search/partition.tsthe workers' shared visited table, the partition of a batch and work stealing (4.1.13)

The path of a proof reads solve() → solveOnce() (search) → makeExpander() (expansion) → the engine's act() → a TryRecord merged into the store and the frontier → the verdict.

File size

No file of src/ is over 800 lines but the exceptions tests/file-size.test.ts lists with their reason, each capped at its size: an exception never grows, and leaves the list once under the limit.

Public and internal

Public, and held to semantic versioning: the five entries of src/engine/api/, published as quest-n-click/content (the types and defineGame), quest-n-click/player (boot), quest-n-click/minigames, quest-n-click/testing (Engine, the fakes, the save envelope, solve) and quest-n-click/reality (since 4.1.1); the content format, the save envelope and the MCP tools. They are held by tests/api-surface.json and the support policy (Stability and support, Public API).

Internal: the modules behind the Engine and App facades (their members marked @internal), the solver's modules, the tools' code. They may move between minor versions.

  • npm run verify:dist (the first visit's budget), tests/boundaries.test.ts, tests/file-size.test.ts, tests/api-surface.json.
  • Architecture, Code tour.