Make a point-and-click adventure for the browser: write it as data, shape it in a visual Studio, check that it can be finished, and ship it as a web game that installs on a phone and plays offline.
| 🎮 Play | The Pantry Key, the sample game, on a phone in landscape or on a desktop |
| 🛠 Studio | Open the Studio in demo mode: edit the sample game, your edits stay in your browser |
| ⏱ Start | Your own game in its own folder, then a first room in fifteen minutes |
Start
Node 22.12 or newer and Python 3 with Pillow (npm run assets prepares the art with them), on Windows, macOS or
Linux. The engine installs from a release's archive (npm publishing comes
in a later 4.2.x):
T=https://github.com/wanoo/web-scumm/releases/download/v4.2.0/web-scumm-4.2.0.tgz npx --package=$T web-scumm create my-game "My Game" --engine=$T cd my-game && npm install npm run assets && npm run dev # play it; then npm run verify, npm run build
npm run build writes dist/, a static site any host serves. ffmpeg serves the sound pipeline and is optional;
npx web-scumm doctor says what is missing. PACKAGE is the whole guide;
TUTORIAL walks the first room.
Build a game
The content is data. Rooms, props with states, characters, items, rules, conversations, hints, scripts and events are plain TypeScript objects, with no code in them, so every tool can read, check and play them:
export const garden: RoomDef = { id: 'garden', name: 'The garden', decor: 'garden', props: { tank: { name: 'water tank', states: { full: 'tank_full', empty: 'tank_empty' } } }, exits: { back_door: { name: 'back door', to: 'house', entry: 'garden' } }, on: [ { verb: 'use', a: 'pipe', b: 'tank', if: '!tank_drained', do: [{ minigame: 'pipes' }, { lose: 'pipe' }, { set: 'tank_drained' }, { prop: ['tank', 'empty'] }] }, ], hints: [{ until: 'tank_drained', lines: ['Use the pipe on the water tank.'] }], };
A rule is a verb, a target, a condition and a list of commands. What a game needs beyond them, a custom command, is TypeScript of its own: trusted code, named in the game and hashed with it (CONTENT_GUIDE, ENGINE). Famous mechanics of the genre are written this way in CLASSICS.
The Studio is the real engine with an editor on top: rooms with their placements, the storyboard panel by panel, every sprite sheet and where it is used, the checks after every save, a play tab that explains a rule and replays a session, and notes shared with an AI assistant (STUDIO).
Art, sound and languages. A prompt for every sprite sheet, object and backdrop in one style, sheets cut into sprites (PROMPTS); chip-tune music arranged from a MIDI and sound effects from one palette (AUDIO); every line translatable, a missing translation found before release.
Prove and ship it
- Validated: broken references, unreachable rooms and untranslated lines are found before anyone plays.
- Solved: the solver runs the real engine (no second model of the content).
npm run verifyasks for a witness, a path to an ending;npx web-scumm solve --proveexplores every reachable state and fails on a softlock or a truncated search. These are two different promises, and the release asks for the second (BENCH says what the proof can and cannot do). - Replayed: a session is the unit of reproduction; saves load across versions, one frozen save per release from 3.0.0 on.
- Shipped: a PWA that installs and plays offline after the first visit, with what a phone has to download held by a budget and every file accounted for with its licence.
- Accessible as far as a machine can tell: axe-core on every screen, keyboard and touch play in CI. That is not a WCAG conformance claim: screen-reader and real-device passes are a person's to make (FIELD).
Further
- Several playable characters, a world map, minigames playable by touch or keyboard, cutscenes and phone calls, autosave and save slots.
- Remix: worlds generated from a seed, each one validated and solved before it ships (REMIX).
- Speedrun: runs recorded, sealed and verified by a replay; leaderboards on the Bridge.
- Reality: a game reacts to a fact from the world (an email answered, a terminal command, a badge) through a signed signal from a Bridge, without its content touching the network (REALITY, REALITY-OPS).
What is stable
Each surface is promised only as far as its proofs go (SUPPORT, GO / NO-GO 4.2):
| Stable | Limited | Experimental |
|---|---|---|
| the content format and its tools; the desktop Chromium PWA; the Reality Bridge on SQLite | the DOM player on phones and screen readers (untried by a person); the Safari PWA; Firefox (the PWA only); speedrun and Remix; voices; the four package archives (until a person installs them) | the Canvas painter; the Bridge on Postgres (distributed); the four connectors |
What only people and real devices can check is listed, not claimed: FIELD, and each release's notes say which passes were made.
How it is made
src/engine/ core (the DSL, the engine), tools (validate, solve, lint, i18n…), dom (the player), minigames, reality
games/demo/ the sample game: rooms, layouts, art, audio, locales, storyboard
games/_template/ copied by npm run new-game
tools/ the commands, the Studio, the MCP server, the art and audio pipelines, the Vite plugins
bridge/ the Reality Bridge (the package web-scumm-bridge)
connectors/ the connectors of the world outside (the package web-scumm-connectors)
docs/en docs/fr the documentation; docs/dev: the work log, the decisions, each release's passes
The engine, the solver and the replay share one code path; ARCHITECTURE and a half-hour CODE_TOUR explain how it fits together.
Made with an AI assistant, reviewed by people. The content is declarative, so an assistant reads and writes it
like any other file (AGENTS.md holds the rules); every operation is a command and an MCP tool
(MCP); after each change it can validate, solve, replay and take a screenshot, so it sees its own
mistakes before a person does. Every result stays reviewable, in the Studio and in Git.
CONTRIBUTING says how to change it.
In numbers
Measured on this commit of main by the automated gates (npm run quality:baseline writes these figures):
mutation testing; the reference game proved in 288 states; the player's first visit 133 KB of JavaScript, gzipped. Each release is built from the commit its candidate tested. The candidate makes the four package archives, the Bridge's image, the SBOMs, the runs and the baseline, and the release publishes those very files; the release makes only the built game, its assets manifest, the proved Remix catalogues, the reference speedrun and the sums, from the same commit. Every file is published with its SHA-256 sum and a provenance attestation (the list).
Documentation
Every page exists in English (docs/en/) and French (docs/fr/), and a test keeps the two in step: the
TUTORIAL, the WORKFLOW from the first idea to the release, every
command in TOOLS, what changed in the CHANGELOG, moving to a new version in
UPGRADING, and where it comes from in the ROADMAP.
Current release: v4.2.0 "Stable World". It restores strict SemVer after the 4.1.x incubation line: a minor adds, a major removes. Its public API follows strict SemVer (SUPPORT). It ships before the people's passes: of the surfaces above, only the Stable column is promised; the passes are made on it, and a later 4.2.x promotes what they prove (GO / NO-GO 4.2, D38).
Licences
Code: MIT. Sample artwork, sound effects and theme: CC BY 4.0 (attribution "Wano"); the theme is Tchaikovsky's Swan
Lake (public domain), written out and arranged for the project. Fonts: SIL OFL. See CREDITS.md.
web-scumm is an independent project. "SCUMM-style" names a kind of game; the project is not affiliated with, endorsed by or derived from LucasArts, Lucasfilm, Disney or the ScummVM project, and ships none of their code, data or art.

