quest'n'click 4.5.0 · r1

Built for quest'n'click 4.5.0, revision r1. Whether it is published, and which one is current, is recorded at publication.json.

Build and release a game

Français · Type: how-to · Audience: author · Context: engine repository, created project · Status: ready · Applies from: 4.2.5

npm run build turns a game into a static folder, dist/, that any web host can serve: the game, its assets, its service worker and its licences. A release build adds the gates a game must pass before people play it: provenance locked, budgets, translations, voices, playtests and the exhaustive proof. This page says what each command checks, in which folder it runs, and what to look at before you send the link.

What you get

A dist/ folder, checked file by file, ready to upload: an installable web app (PWA) that plays offline after the first visit, whose every file is accounted for with its licence under dist/licenses/.

Context and versions

The same game builds in two places, with different commands:

Created project (quest-n-click create)Engine repository (games/<id>/)
Everyday buildnpm run buildnpm run build
Release buildnpm run releasenpm run verify:release after npm run build
Release that may be soldnpm run release -- --commercialnpm run verify:commercial
Exhaustive proofinside npm run releasenpm run prove:game
Sealed endingnot available (seal is not a quest-n-click command)npm run seal, npm run check:spoilers
Serve dist/npm run preview (local only)npm run preview, or npm start (any interface, $PORT)

The page applies from 4.2.5, when the command became quest-n-click (before, web-scumm). The created project and its build and release commands exist since 3.9.0; npm start is a Node launcher since 4.1.8.

Prerequisites

Where to run the commands

Steps

  1. Prepare the assets when images or sounds changed.

    # in the engine repository (public/assets is committed there: commit what this writes)
    npm run assets
    

    In a created project, public/assets is not committed (its .gitignore lists it) and npm run build runs assets itself.

  1. Build.

    # in the created project
    npm run build
    

    It runs, and stops at the first failure: assets; verify (validate, solve, translations status, lint, playtests); the Vite build into dist/; then the check that every file of dist/ is accounted for.

    # in the engine repository
    npm run build
    

    It runs check (types, the Node tests) then build:game: verify:game (validate, solve, solve by chapter, variants, translations status, lint, playtests), the Vite build, verify:dist, check:spoilers and audit:assets.

  1. Run the release gates before a public release.

    # in the created project
    npm run release                 # or: npm run release -- --commercial
    

    release runs assets, verify and the build, then: validate --release (the provenance lock, placeholders, ids), weight --release (what a phone downloads, against the game's assetBudgets), i18n status, voices check --release, playtests --strict, solve --prove (every reachable state), solve-reality, and with --commercial validate --commercial --errors (no exception, no placeholder, no non-commercial licence); last, the check of dist/.

    # in the engine repository
    npm run verify:release          # or: npm run verify:commercial
    npm run prove:game
    

    The template's art is a placeholder: a release refuses it until each file is replaced, reviewed and locked (npx quest-n-click provenance --lock in a created project, npm run provenance -- --lock in the engine repository). See Asset provenance.

  1. Seal the ending, only for a game with a sealed ending, in the engine repository: seal the real outcome, build, commit, then deploy. The whole procedure is in The sealed ending.

    # in the engine repository, with games/<id>/private/ending.config.ts filled in
    npm run seal -- --outcome=<key>
    npm run build
    
  1. Upload dist/ to a static host (next section), then play the live version.

    # in the engine repository: plays the deployed game to its ending, in a phone-sized browser
    node scripts/e2e.mjs https://<your-site>/
    

    scripts/e2e.mjs is in the engine repository only; in a created project, play the live site by hand to the end.

What the build ships

npm run build type-checks (in the engine repository), tests, bundles and audits the output. The result is a PWA:

The pause menu tells the player whether the whole game is cached. The details are in Sub-path, cache and service worker.

Every build ends by removing from dist/assets the files that are not this game's and writing dist/licenses/: the engine's LICENSE, LICENSE-ASSETS, CREDITS.md from the game's provenance, THIRD_PARTY_NOTICES.txt and assets-manifest.json (each file's path, author, source, licence, SHA-256 and status). The check that follows refuses any other file in dist/, and a locked file or a notice that is missing.

Deploying

dist/ is static: any static host serves it.

Under a sub-path (https://<user>.github.io/<repo>/), build with BASE_PATH=/<repo>/; at the root of a domain, no BASE_PATH. Every path (scripts, styles, manifest, icons, service worker, the sealed ending's file) follows it:

# in the created project or the engine repository: the same build as Pages, locally
BASE_PATH=/my-repo/ npm run build

What goes wrong under a sub-path, with the cache or with a half-uploaded site: Sub-path, cache and service worker, incomplete deploys, going back.

In the engine repository, games/<id>/private/ (photos, raw sheets, the sealed ending's configuration) is never sent: .gitignore excludes it, and nothing in it is copied into dist/. A created project's .gitignore lists only node_modules, dist, .cache and public/assets: keep private files outside game/, or add them to it.

Limit · release-proof-not-witness npm run build and npm run verify ask the solver for a witness: one way to an ending. Only the release (npm run release in a created project, npm run prove:game in the engine repository) asks for the exhaustive proof, which fails on a softlock or a truncated search. What the solver proves says what each lets you conclude.

Limit · accessibility-machine-only The CI checks accessibility as far as a machine can (axe-core on every screen, play by keyboard and by touch). That is not a WCAG conformance claim: a screen reader and real devices are passes a person makes.

Expected result, and how to check it

Common errors

SymptomCauseFix
python3 not found, or No module named 'PIL'The asset step needs Python 3 and Pillowpip install -r node_modules/quest-n-click/requirements.txt (created project) or pip install -r requirements.txt (engine repository)
provenance.lock.json › missing: a release ships the files that were reviewedNo lock yetReview the assets, then lock them (step 3)
A placeholder refused by validate --releaseThe template's art is still thereReplace it, or name it in releaseExceptions with a reason (refused by --commercial)
audio.scores › ffprobe not foundA release measures the stemsInstall ffmpeg, then npx quest-n-click doctor
A file of dist/ not accounted forA stray file in public/, or an asset not this game'sRemove it, or declare it (a data file the game names)
A blank page once online, under /<repo>/Built without BASE_PATHSub-path

Files or data changed

Recovery or going back

A build changes nothing you cannot rebuild: delete dist/ and run it again. To put an earlier version back online, deploy the build of an earlier commit; what players' caches and saves do then is in Going back.

References


Edit the source of this page · Report an error