Skip to content

Latest commit

 

History

History
151 lines (117 loc) · 6.62 KB

File metadata and controls

151 lines (117 loc) · 6.62 KB

spritekit

spritekit builds deterministic, device-sized animation strips from tracked source PNGs and one tracked asset-set manifest. The source PNGs and manifest are the source of truth; everything under the adjacent build/ directory is a reproducible QA output or runtime candidate.

This tool handles transparent sprite-like assets: characters, drones, items, and detached effects. Opaque parallax backgrounds have a separate composition contract in assets/README.md; background_builder.py validates their loop and transition seams and builds a static composition contact sheet.

Pipeline contract

One asset set has one fixed output cell, explicit source origin, reference scale, transform, and indexed palette. Every animation therefore keeps the same coordinate system, apparent scale, and render anchor. The build fails instead of silently rescaling a large pose.

  • Each source PNG is one horizontal strip with exactly the declared frame count.
  • Every strip in an asset set has the same source-cell dimensions.
  • sourceOrigin is the one anchor shared by every source frame. The generated output maps it to the bottom-center origin recorded in build/manifest.json.
  • The chroma key comes from the manifest; keyed pixels do not influence the palette.
  • Character, drone, and item frames must contain pixels. Effects may opt into empty frames.
  • syncWith requires the effect and its owning animation to have identical frame counts, FPS, and playback. The effect uses the same cell, origin, scale, and draw rectangle as the hero, so it can be composed at (0, 0).
  • Scaling uses nearest-neighbor sampling. All output strips share one indexed palette.
  • Source paths must be relative PNG paths contained by the manifest directory.

Detached effects may share an asset set with their character when they require the same coordinates and timing, but they remain separate source and output strips. A scene-owned effect such as arrival owns a separate asset set.

Setup

From the repository root:

python3 -m venv tools/spritekit/venv
tools/spritekit/venv/bin/pip install -r tools/spritekit/requirements.txt

Dependencies are pinned in requirements.txt; the virtual environment is local and ignored.

Build and validate

Run the complete read-only verification path with:

tools/spritekit/venv/bin/python tools/spritekit/verify.py

It checks the generated scene contract header and native parser vector before discovering the spritekit tests.

tools/spritekit/venv/bin/python tools/spritekit/process.py \
  assets/sprites/hero/hero.json

tools/spritekit/venv/bin/python tools/spritekit/process.py \
  assets/sprites/hero/hero.json --check

The first command writes build/manifest.json, one indexed PNG per animation, and build/contact_sheet.png. The --check form performs the same validation and conversion in memory without writing generated files.

Asset-set manifests own only source art, geometry, palette, and animation timing. assets/scenes/expedition/scene.json is the sole owner of semantic state, cue, outcome, and presentation mappings.

Layered background build

Validate the shared far loop, transparent near loops, connector bands, and terminal/middle sequence, then build the static composition contact sheet:

tools/spritekit/venv/bin/python tools/spritekit/background_builder.py \
  assets/backgrounds/expedition/expedition.json

tools/spritekit/venv/bin/python tools/spritekit/background_builder.py \
  assets/backgrounds/expedition/expedition.json --check

The generated build/contact_sheet.png composites the repeating sequence terminal → middle → terminal over the shared far layer for static visual review. Exact seams and parallax parameters are validated from the manifest and pixel data.

Integrated expedition scene

Build or validate the single tracked expedition composition:

tools/spritekit/venv/bin/python tools/spritekit/scene_builder.py \
  assets/scenes/expedition/scene.json

tools/spritekit/venv/bin/python tools/spritekit/scene_builder.py \
  assets/scenes/expedition/scene.json --check

The normal build refreshes every referenced asset, validates its tracked manifest and source hashes, and writes:

  • assets/scenes/expedition/build/contact_sheet.png: integrated state and seam review frames.
  • firmware/stackchan/data/scene/: the generated LittleFS payload containing scene.json and raw .idx4 resources.
  • firmware/stackchan/test/test_scene_contract/scene_package_test_vector.generated.h: the tracked exact-manifest vector consumed by the production C++ parser test.

The device package uses at most 16 RGB565 palette entries per resource, index 0 transparency where applicable, and high-nibble-first row-major pixel pairs. Every package key and structural limit comes from protocol/scene-package.json; resource order and presentation bindings come from the tracked scene, while animation kind, playback, frames, and rate come from its pinned asset manifests. The same tracked lineage generates the firmware catalog. The builder rejects source drift, geometry or origin drift, invalid indices or byte counts, broken background connectors, unsafe decision-control overlap, visible content outside the canvas, invalid hero/drone spatial relationships, duplicate runtime filenames, and packages over the tracked scene limit. Every screen coordinate comes from the scene manifest's single layout declaration. The unversioned scene-package contract also requires separate USB-power-absent, host-link-absent, synchronizing, uncertain, and fault prompts, producer-specific ready text, and disjoint reject/approve controls. Old fields, missing fields, and extra fields are rejected rather than adapted. Scene HUD text and control labels use only uppercase ASCII letters and spaces within their fixed byte limits, matching the device's finite pixel alphabet. QA images and LittleFS installation files are ignored. The native parser vector is tracked so a fresh checkout can prove Python-builder/C++-parser parity; it is generated, never edited by hand, and --check rejects drift. All --check paths prepare outputs in memory and compare without writing. Only the command without --check invokes the explicit output writers.

Art sources

Tracked <animation>_src.png strips are editable art sources. Image generation or manual cleanup may replace them, but spritekit never regenerates or overwrites them. Run the strict build after every art change.

Runtime boundary

Stack-chan firmware consumes and validates the generated raw package. Static contact sheets provide build-time visual QA; physical display behavior and cadence are established by the separate firmware and hardware acceptance checks.