8-bit fire sprites with rebuilt fire
Requires moves already rendered by the fire-sprites skill: this works from the separate body and fire
layers in moves/NAME/, not from flat video. $KIT is the kit root (two levels up from this file); py is
$KIT/.venv/bin/python; run from the project directory.
py $KIT/tools/retro.py # every rendered move
py $KIT/tools/retro.py "breath_*" # or just some (names or globs)
open retro.html
Why the fire is rebuilt, not shrunk
Shrinking a fire sprite and snapping it to a palette gives a flat white blob: on camera, flame is clipped to white, so there is no colour inside it to keep. Instead:
- Body: downscaled, hard alpha edge, mapped to a fixed 8-colour skin and leather palette (lightness weighted so shading survives), with a 1-pixel dark outline.
- Fire: the real flame shape is kept frame by frame, but its colour is redrawn. How deep a pixel sits inside the flame chooses a step on a 7-colour heat ramp, dark red at the edge through orange and yellow to a white core, with a 4x4 ordered dither between steps. Depth is measured relative to how thick that flame is, so a thin sword flame still gets a hot core and a huge breath cloud gets a wide gradient. A small opening pass removes thin lines of wall that leaked into the fire layer.
retro.html shows each move four ways: rebuilt fire and direct quantise, at 64 px and 40 px body height. The
direct version is there so the performer can see the difference; rebuilt fire is the one to ship.
Animation runs "on twos" (half the master frame rate), which reads as retro and halves the sheet size.
Outputs: retro/NAME_B64.png, NAME_B40.png (rebuilt), NAME_A64.png, NAME_A40.png (direct), and
retro/atlas.json with frame grid, fps and feet anchor. Draw them with nearest-neighbour scaling at integer
multiples only (image-rendering: pixelated in CSS).
What to tell the performer
Look at the result before describing it. Typical findings:
- Breath clouds read very well; the redraw gives them structure the footage lacks.
- Clouds that touched the frame edge, a window or blown-out wall come out boxy at this scale.
- The body flashes to near-white at a breath's peak and maps to dark navy in silhouette frames, because the palette follows the footage's light. Offer to hold skin tones steady if that bothers them (not built yet).
Changing the look
Edit the constants at the top of tools/retro.py: BODY_PAL (body palette, darkest first), FIRE_RAMP
(edge to core), the sizes in for B in (64, 40), and the depth curve on the heat = line. Keep the palette
fixed across all of one performer's moves so the animations match each other.