Image toolchain
Français · Type: how-to · Audience: author · Context: engine repository, created project · Status: ready · Applies from: 4.3.0
The tools that turn generated or drawn sheets into a game's images are Python scripts the engine ships under
tools/: they cut a sheet into sprites, choose its background, and prepare every image a game names for the browser.
This page installs them and runs each once, in the engine repository and in a created project. What the art should
look like, and how the prompts are written, is on Images.
What you get
Python and its pinned modules installed, a sheet cut into keyed sprites under your game's art/, and those sprites
prepared into public/assets/ by npm run assets.
Context and versions
- The engine repository (a game under
games/<id>/) or a created project (the game undergame/, the tools undernode_modules/quest-n-click/tools/). The commands differ only by the path of the tool and its output. - From 4.3.0 the modules are Pillow 13.0.0, NumPy 2.4.6 and SciPy 1.18.1 (
requirements.txt); with that upgrade the sample game's images came out byte for byte the same (4.3 notes).
Prerequisites
- Python 3 (Requirements); CI uses 3.12.
- A game, with its
site.json(the template has one). - For sounds and videos in
npm run assets: ffmpeg (Requirements).
Where to run the commands
At the root of the engine repository, or at the root of the created project. Each block says which.
Steps
Install the pinned modules:
# in the engine repository python3 -m pip install -r requirements.txt# in a created project python3 -m pip install -r node_modules/quest-n-click/requirements.txt
Get one ready-to-paste prompt per sheet the game names, with the cut command of each (
--missingfor the sheets not cut yet). It writesprompts.mdin the game's folder:# in the engine repository: games/<id>/prompts.md npm run prompts# in a created project: game/prompts.md npx quest-n-click prompts
Cut a generated sheet into keyed sprites,
<out>/<sheet-id>/r<row>c<col>.png(a 6 × 4 grid by default,--gridto change it,--autofor figures not on a grid):# in the engine repository: writes games/<GAME>/art/hero/ python3 tools/cut-sheet.py hero_sheet.png hero# in a created project: name the output folder, the tool's default is the repository's games/<GAME>/art python3 node_modules/quest-n-click/tools/cut-sheet.py hero_sheet.png hero --out game/artWith
"artStyle": "pixel"insite.json(or--pixel), the cutter also scales each cell down 4× (--scale), limits it to 32 exact colours (--colors) and writes indexed PNGs;npm run assetsthen writes lossless WebP. A sheet on a transparent background ("sheetBackground": "transparent") is cut on its alpha, nothing keyed by colour.
Choose the sheets' background, once per image tool:
# in the engine repository (in a created project, prefix the tool with node_modules/quest-n-click/) python3 tools/check-alpha.py test_image.png python3 tools/pick-bg.py games/<id>/art/hero/check-alpha.pysays whether an image tool writes real alpha:TRANSPARENT,FAKE CHECKERBOARDorOPAQUE.pick-bg.pytakes sheets, sprite folders or reference images and ranks the flat colours by their distance to the drawing; its first line,BEST #RRGGBB, is thesheetBackgroundto use.
Prepare every image and sound the content names:
# in the engine repository, for the current game npm run assets# in a created project npm run assetstools/refs.tslists what the content cites (rooms, characters, items, the map, minigame parameters,skin, the title and credits screens,ending.scratch, andindex.ts'sextraImages), thentools/assets.pyprepares it intopublic/assets/. Only what changed is processed again. Where each image is read from, andsources.jsonto read it from elsewhere, are on Images.
Expected result, and how to check it
After step 3, the sheet's folder under art/ holds one PNG per cell. After step 5, public/assets/img/<sheet>/<cell>.webp
exists for each image the content names, and assets prints a warning for each one it could not find:
warning: missing images: … (and warning: missing sounds: …). No warning means every image the content names was
prepared.
Common errors
| Symptom | Cause | Fix |
|---|---|---|
ModuleNotFoundError: No module named 'PIL' (or numpy, scipy) | Step 1 not done, or done for another Python | Step 1 with the python3 that runs the tools; in a created project, PYTHON=<path> makes assets use another interpreter |
ModuleNotFoundError: No module named 'cv2' | A talking-mouth tool needs OpenCV, not in requirements.txt | Install OpenCV's Python module yourself |
The sprites land in games/<id>/art of a folder that does not exist | cut-sheet.py run in a created project without --out | Add --out game/art |
warning: missing images: … | The content names an image with no file | Cut or add it, or fix the name in the content |
Files or data changed
prompts.mdin the game's folder (step 2).art/<sheet-id>/in the game's folder (step 3);--cells r1c2,r3c1cuts only those cells again.public/assets/(not committed), the game'sassets.gen.json(the pixel sizes of the prepared images) and.cache/refs.json(step 5).
Recovery or going back
Commit the game's art/ before cutting a sheet again: the cutter overwrites the cells it writes. public/assets/ is
rebuilt from the sources by npm run assets at any time.
The talking-mouth tools
tools/talk-kit.py prepares a "talking kit" per character and pose (the validated sprite's head copied into a 3 × 2
grid), tools/talk-apply.py pastes the generated mouths back onto the sprite, and tools/talk-normalize.py makes one
row of a talking sheet match the validated sprite. The last two import OpenCV (cv2).
Limit ·
talk-tools-repository-layouttalk-kit.pyandtalk-apply.pyread and writegames/<GAME>/…from the current folder (games/<id>/talk-kits.json,games/<id>/private/talk_kits/): they work in the engine repository's layout only, not in a created project.talk-normalize.pytakes every path as an argument and works anywhere.
References
- Images (the pipeline,
sources.json, the art style), Sound effects - Requirements, Audio toolchain
tools/cut-sheet.py,tools/assets.py,tools/check-alpha.py,tools/pick-bg.py,requirements.txt