A pixel-art glow and spark sprite generator. Give it a shape and a palette, get back a clean transparent PNG — no blur, no anti-aliasing bleed, grid-aligned for actual sprite work.
Built for game VFX where "glow" needs to stay pixel art: item auras, weapon hit-sparks, bite/slash impact marks, magic effects. Real gaussian bloom looks great in a 3D scene and terrible zoomed into a 32x32 sprite — this generates the stepped, dithered look on purpose instead of faking it with blur.
shape(x, y) → (distance, angle) → quantize into steps → palette ramp → alpha → PNG
- Shapes are signed distance functions, not sprites —
point(radial burst),slash(tapered arc),crescent(bite mark), or import your own black/white mask. - Every shape returns both distance and angle. Distance drives brightness;
angle drives spike direction, blade taper, and — for the
prismaticpalette — a hue sweep around the shape instead of concentric rainbow rings. - Palettes are ramps interpolated in OKLab, not RGB, so a blend from blue to yellow doesn't pass through muddy grey. Ramps are checked for monotonic luminance on load — a ramp that dips reads as a ring, not a light source.
- Step count and alpha both scale with sprite size — a 16px sprite can't hold 6 bands the way a 96px one can.
- Bayer dithering between steps, so bands blend without needing more colors than the target platform wants.
python3 -m venv .venv
source .venv/bin/activate # Windows: .venv\Scripts\Activate.ps1
pip install pillow numpy scipy # scipy only needed for mask import# single sprite
python glowgen.py --shape point --palette ember --size 64 -o glow.png
# sprite sheet across all built-in palettes
python glowgen.py --shape slash --sheet palette --size 48 --pad 4 -o sheet.png
# sprite sheet across all shapes
python glowgen.py --palette prismatic --sheet shape -o shapes.png
# sprite sheet across sizes (checks the effect still reads small)
python glowgen.py --shape point --palette holy --sheet size -o sizes.png
# sprite sheet rotated 8 ways (useful for slash/crescent)
python glowgen.py --shape slash --palette void --sheet rotate -o rotations.png
# override shape parameters directly
python glowgen.py --shape point --set spike=0.8 spike_arms=3 --palette toxic -o custom.png
# import a black/white mask as a custom shape
python glowgen.py --shape my_mask.png --palette frost -o from_mask.png
# solid background for preview/contact sheets (not for shipping — see note below)
python glowgen.py --shape point --palette prismatic --bg "#141020" -o preview.pngRun python glowgen.py --help for the full flag list (alpha mode, dithering
on/off, gamma, upscaling, etc).
Defined in palettes.json — plain data, no code changes needed to add one:
"myTone": ["#hex1", "#hex2", "#hex3", "#hex4", "#hex5"]Darkest first, brightest last. "prismatic" is a reserved name — it triggers
the procedural angle-driven rainbow rather than a fixed ramp.
Ships with: ember, frost, holy, toxic, void, blood, abyss,
prismatic.
See CLAUDE.md for the full list of rules the codebase follows
(why shapes must return an angle, why ramps interpolate in OKLab, the
Image.alpha_composite vs paste(mask=) gotcha that corrupts stepped alpha,
etc). Worth reading before extending the shape registry.
- Animation. The pipeline is designed for it (every shape parameter is a dict value, nothing hardcoded) but frame-by-frame animation isn't wired up.
- Snapping output to a fixed in-game palette. Planned as an opt-in toggle,
since
prismaticwould just die if force-snapped to a small palette.