Procedural generation of pixel-art sprites: characters, creatures, items, props, icons, tiles

Notes compiled 2026-11-02. Target: plain JavaScript, phone browser, small internal resolutions (64x64 to 640x360), deterministic seeds. Where a claim comes from my own engineering knowledge rather than a fetched source, it sits under Inferences, not Cited Findings. Research budget was about 18 tool calls, so some games named in the brief (Moonring, Enter the Gungeon, Noita, Shapez, No Man’s Sky, Spore, Dwarf Fortress) have no fetched primary sources here. They are listed under Gaps.

1. Mask/template generators (Bollinger, zfedoran, mirrored masks, cellular automata): how they keep silhouettes readable

Takeaway

The whole family comes down to this: a hand-authored mask (per-cell rules: always empty, always solid, random solid/empty, random body/outline), randomized per seed, mirrored on one axis, then given an outline pass (any empty 4-neighbor of a body cell becomes outline). Readability comes from the mask, which acts as the body plan, plus symmetry and the outline, not from the noise. Bollinger also curated the output: he patched known-bad sub-patterns and rejected weak results. Cellular-automata variants (Sprator) swap the mask for a few Life-like smoothing steps on a tiny noise grid, then mirror and outline it the same way.

Cited Findings

Dave Bollinger, Pixel Spaceships (c. 2006, original page archived 2008; newer write-up at davebollinger.us)

zfedoran/pixel-sprite-generator (JavaScript, credits Bollinger): the exact algorithm, from the source file

Sprator (yurkth): cellular-automata sprites

Inferences

Gaps

2. Part/kit-based (paper-doll) generation, palette swapping, and how specific games vary characters and items

Takeaway

Kit-based generation (layer pre-drawn parts in a fixed z-order, then recolor each layer through a palette ramp) is the most reliable route to hand-made quality procedural characters and items, and it is cheap at runtime. The LPC generator stores its layer metadata (groups, z-index) in JSON, and its recolors break wherever assets don’t share a common ramp. Caves of Qud shows the extreme low-cost form: each tile is authored in 2 or 3 index colors (foreground, detail, background), and the game assigns real colors from a fixed 18-color palette at runtime. Item generators (swords, spellbooks, Starbound-style guns) stack slot parts (blade/guard/handle; butt/middle/barrel) with palette swaps.

Cited Findings

Inferences

Gaps

3. Rendering-based pipelines: 3D/voxel to pixel art, sprite stacking, SDF/vector rasterization, L-systems, metaballs

Takeaway

Dead Cells is the canonical production case: simple low-poly 3D models in 3ds Max, rendered by an in-house tool at tiny size with no anti-aliasing, exported per frame as PNG plus a normal map, then shaded by a toon shader. Flicker was never fully solved. Sprite stacking (NIUM) gives a pseudo-3D look at runtime from horizontal slices drawn with 1-px vertical offsets and rotated together. For a phone JS engine, the realistic runtime options are sprite stacking, SDF/shape rasterization into palette indexes, and L-system or metaball generators drawn straight into an index buffer. Full 3D-to-pixel rendering is better done offline.

Cited Findings

Inferences

Gaps

4. Post-passes that make generated sprites look hand-made

Takeaway

The passes that matter most, in order: (1) quantize to a fixed palette of hue-shifted ramps (shift hue, not just value, between shades; Slynyrd caps shifts around 20 degrees); (2) outline, either 1-px outer, or “selective” outline colored by the adjacent fill’s darkest ramp step; (3) light-direction shading (top-left light: darken bottom-right edges, highlight top-left); (4) cleanup: remove orphan pixels, single-pixel holes and L-shaped corner pixels (“pixel-perfect”), and keep cluster sizes reasonable; (5) optional ordered (Bayer) dithering for gradients only. Pixel Composer ships a “De-Corner” filter, and Krita has worked on a pixel-perfect stroke mode.

Cited Findings

Inferences

Implementable passes, all on an Int8Array/Uint8Array index buffer b[w*h] (0 = transparent):

Gaps

5. ML/AI approaches (as of late 2026)

Takeaway

Diffusion-based pixel-art services (PixelLab, Retro Diffusion) are the practical state of the art for offline asset generation: text or image to sprite, directional rotations, skeleton-driven animation frames, and palette and size controls, priced per image or one-time. Academic work focuses on generating missing directions and poses (Pix2Pix and imputation GANs) and on pose-conditioned sprite-sheet diffusion, using small datasets (hundreds of sequences). None of these is a sensible on-device runtime generator for a small phone game. The usual pattern is to generate offline, then clean up, re-quantize to the game palette and snap to the grid by hand or with scripts.

Cited Findings

Inferences

Gaps

6. Programmatic authoring tools: Aseprite Lua, PICO-8 idioms, icon generators, pixel DSLs (“pixel recipes”)

Takeaway

For a plain-JS engine, the most useful idea is “sprites as code”: tiny strings or arrays of palette indexes (PICO-8 style hex strings, ASCII art maps) plus procedural modifiers, held in the source and painted at load time. Aseprite’s Lua API and tools such as Retro Diffusion and PalettePainter fit an offline authoring step. Few authoritative sources were fetched on this topic in the budget.

Cited Findings

Inferences

Gaps

7. Determinism: same seed gives the same sprite

Takeaway

None of the classic JS generators are seedable out of the box (zfedoran calls Math.random() throughout), but they are easy to make so: replace every random call with a seeded PRNG stream derived from (world seed, sprite kind, id), and keep everything in integer palette-index buffers. Bollinger’s design, where a ship is six 32-bit numbers, is the ideal: the sprite is a pure function of its seed bits.

Cited Findings

Inferences

Gaps