Skip to content

Graphics Pipeline

Nick Hamze edited this page Jul 17, 2026 · 2 revisions

Graphics Pipeline

The target is a tiny readable VN, not a large anime illustration squeezed into a handheld rectangle.

Hardware envelope

  • Screen: 224×144
  • Visible tile grid: 28×18 tiles of 8×8
  • Background: 224×144, normally 16 colors
  • Character portrait: up to 96×128
  • Character palette: 15 visible colors plus transparent index zero
  • Color model: RGB444-style 12-bit color; snap channels to 17-step values
  • Character tile budget: no more than 192 occupied 8×8 tiles
  • Hardware sprite limit: 128 total, 32 per scanline

WSC 4bpp color zero is transparent. It is not a free visible outline color.

Source art first

Use ImageGen for new pictorial production graphics, then generate or draw a strong high-resolution master for each pose. Preserve every useful source pass with a versioned filename. Do not generate neutral, talk, and blink as independent final images; even good generations redraw the face, hair, clothing, and silhouette.

Deterministic code remains appropriate for conversion, masks, palette locking, contact sheets, lettering, and runtime UI. It is not a substitute for ImageGen when the task is to create or replace backgrounds, characters, title art, inserts, covers, or other pictorial artwork.

Good source art has:

  • large readable eyes and graphic mouth shapes;
  • a bold hair and shoulder silhouette;
  • quiet costume detail;
  • one identity prop at most when it survives at 96×128;
  • a transparent or safely keyed background;
  • framing designed for the real final screen.

Locked master to animation family

  1. Crop and fit the master at 96×128.
  2. Quantize once to the final RGB444 palette and binary alpha mask.
  3. Duplicate that locked result for neutral, talk, and blink.
  4. Edit only the mouth box for talk.
  5. Derive blink from the locked neutral master. For people, draw a compact one-pixel eyelid arc inside each actual eye aperture and supply an explicit opaque skin sample for each eye. For robots, author tight per-character mono-eye, dual-eye, or visor masks plus sensor/socket sample points, then darken only the connected sensor pixels. Never reuse fixed face rectangles across character designs.
  6. Derive robot talk frames from the same locked neutral with derive_mechanical_talk: provide tight sensor masks, sensor seeds, and existing-palette pulse-color samples. Only connected sensor components may change. Reject broad black/white face or visor bars.
  7. Reuse palette colors; do not requantize each frame.
  8. Inspect the whole sprite and face crop at 1× and nearest-neighbor zoom.

The current hard blink bounds are zero alpha changes, zero changes outside the approved eye/sensor band, no more than 240 changed pixels, and no more than 18 pixels of vertical change. These metrics prevent face swaps; they do not replace visual review. Glasses, brows, hair, nose, pose, prop, palette, alpha, and silhouette must remain stable.

scripts/wscvn_sprite_family.py exposes derive_human_blink, derive_mechanical_blink, and derive_mechanical_talk. Builders must use those neutral-master paths rather than importing an independently ImageGen-authored animation cell from an old source sheet.

Use:

python3 scripts/audition_wscvn_sprite_sheet.py \
  --sheet-kind expression \
  --source hero=assets/my-game/sources/hero_expression_source_v1.png \
  --character hero \
  --labels worried,resolved,smile \
  --out assets/my-game/auditions/hero_expression_audition.png \
  --report-json assets/my-game/auditions/hero_expression_audition.json

Approve only a clean report with a stable audition image and exact covered runtime sprites.

The final approval must inspect the actual runtime PNGs, not a converted proxy. Assemble each 96x128 neutral/talk/blink family and run the audition with --sheet-kind animation --runtime-ready, then refresh and approve the hashes:

python3 scripts/refresh_wscvn_asset_provenance.py <slug>
python3 scripts/refresh_wscvn_sprite_auditions.py <slug> --approve \
  --reviewer codex --notes "Exact runtime family inspected at 1x and enlarged."

Backgrounds and titles

  • Compose every major background independently at the final 14:9 shape.
  • Leave quiet portrait lanes on both sides.
  • Keep important objects in the upper 224×88 stage; the opaque textbox owns the lower screen.
  • Do not bake a dark lower-third gradient into art when the runtime already supplies the textbox.
  • Give the title screen its own composition and a deliberate quiet field for deterministic lettering.
  • Use object inserts and empty establishing frames to break talking-head runs.

Review artifacts

Inspect these before release:

  • contact_sheet.png
  • expression_audition_sheet.png
  • scene_preview_sheet.png
  • storyboard_sheet.png
  • font-proof-sheet.png
  • text-preview-sheet.png
  • an all-scene native 224×144 review sheet
  • release-art proofs for cover and cartridge-label masters

The fastest test is distance: if speaker, mood, and eye direction are not obvious at a glance, the art is not done.

Contracts

python3 scripts/check_wscvn_graphics_contract.py \
  --asset-root assets/my-game \
  --project projects/my-game.wscvn.json

python3 scripts/check_wscvn_text_contract.py \
  --asset-root assets/my-game \
  --project projects/my-game.wscvn.json \
  --font runtime-local/src/font.h \
  --runtime-main runtime-local/src/main.c

python3 scripts/check_wscvn_visual_contract.py \
  --asset-root assets/my-game \
  --project projects/my-game.wscvn.json \
  --contract assets/my-game/visual-contract.json

Run the light-novel readiness gate after the graphics, text, visual, and QA reports are current.

Clone this wiki locally