Generate clean 2D game sprites & animation atlases — component-row pipeline: state rows, alpha cleanup, frame extraction, runtime atlases. Codex/Claude skill.
$ npx -y skills add aldegad/sprite-gen --agent claude-code
Run the curl in your terminal, the rest in Claude Code.
What's inside
English · 한국어 · 日本語 · 简体中文 · Español · Français
A still idle reads as frozen. Breathe turns a single pose into a living loop — deterministic squash & stretch baked on top of your curated frames. No regeneration, no re-extraction, no extra art. One sidecar field:
"breathe": { "depth": 0.05, "breaths": 3 }
Any silhouette works — humanoids, blobs, tentacles. Front, side, back:
Sprites generated and curated with this skill (claudecy, howl):
Ask an image model for a "sprite sheet" and you know what you get: a character whose face changes every frame, a background that won't key out, poses that overlap and drift off-grid, and a PNG your game engine can't actually consume. Cute demo, useless asset.
sprite-gen is a Codex/Claude skill that closes that gap. Give it one base image and a list of actions — it drives the generation row by row, locks the character's identity, strips the chroma background to real alpha, extracts each pose as a clean transparent frame, and bakes a runtime atlas with a machine-readable manifest.json.frame_layout.
And for the last 10% that generation never gets right, there's a curation webview: compare frames side by side, reject the broken ones, nudge rotation/scale/position non-destructively, watch the loop live — then bake. The pipeline does the labor; you keep the taste.
sprite-request.json → layout guides + prompts → sprite-gen gen state rows
→ chroma alpha → connected components → transparent frames
→ sprite-sheet-alpha.png + manifest.json.frame_layout
flowchart LR
REQ["sprite-request.json<br/>(numeric SSoT)"] --> GUIDES["layout guides<br/>+ prompts"]
GUIDES --> GEN["sprite-gen gen<br/>state row strips"]
GEN --> EXTRACT["chroma alpha →<br/>connected components"]
EXTRACT --> FRAMES["transparent frames"]
FRAMES --> ATLAS["sprite-sheet-alpha.png<br/>+ manifest.json.frame_layout"]
FRAMES -. "curation webview (optional)" .-> ATLAS
Full architecture:
docs/architecture.md
sprite-sheet-alpha.png) — real alpha, no leftover chroma fringe, verified against white backgrounds.manifest.json.frame_layout) — absolute frame rectangles, per-state fps and loop flags. Your engine samples rectangles; it never guesses a grid.sprite-gen recolor takes the base sheet plus a palette map and bakes N variant sheets in one command (exact RGB match by default; same input, same output bytes). The curation webview blink-compares them and records the adopted name. Detail: docs/recolor.md.The extractor keeps chroma cleanup deterministic: soft-alpha unmix preserves antialiased hair strands and thin outlines instead of peeling them away before coverage can be solved.
The close-up crops below show the edge detail behind the full-body comparisons.
![]()
![]()
AI-generated "pixel art" is not pixel art. The blocks wobble, the edges carry antialiasing, and the lattice drifts within a single row, so cutting on an even grid smears one block into the next. The community fix is to "unfake" the image — guess the block size from run lengths and re-quantize — but that measures each frame on its own, so a walk cycle's cell size breathes frame to frame.
Backbone Lattice measures one grid for the whole subject and holds every cut to it. Per-frame pitch detection feeds a row-wide, cross-frame consensus that outvotes harmonic misdetections; that consensus grid is the backbone every cut snaps to. Cuts land on actual colour boundaries, and a minimum cell width proportional to the measured pitch keeps two neighbouring cuts from ever collapsing onto the same band. One backbone, so the same block stays the same size across a whole animation instead of jumping between frames.
The result is verified against what shipped, not eyeballed on a hand-picked frame: every pixel-unfake run is re-derived from its own source strip and compared pixel by pixel. The shape you approved stays the shape you get; what changes is only where outlines and shading land, which is exactly what the backbone decides.
Generation gets you 90%. The webview is where a human takes it to shipped — standalone, no Studio or framework dependency, runs anywhere the skill is installed (Claude Code Desktop, the Codex app, a plain terminal).
![]()
curation.json sidecar — source PNGs are never rewritten, and the compose step bakes the result deterministically. Preview and bake share one affine matrix, so what you align is what you get.unpack_atlas_run.py --pngs-dir and use it as a general pick-the-winner view.For isometric sets, the webview overlays the floor grid (from meta.json tile/anchor) so you can snap furniture to the diamond axes with the shear handle.
![]()
The webview ships with English and Korean. Pass --lang en|ko when launching, or use the in-app toggle:
python3 scripts/serve_curation.py --run-dir <run-dir> --lang en # or ko
sprite-gen supports CPython 3.10+. CI runs the minimum supported version (3.10) and the latest covered version (3.14) on GitHub-hosted runners.
The quickstart requires a Python install with working venv/ensurepip. If python3 -m venv fails before package installation in a local distribution, use a standard CPython build for any supported version and rerun the same commands.
# 0. install dependencies (Pillow, NumPy) into a fresh virtualenv
python3 -m venv .venv && source .venv/bin/activate
pip install -e .
# 1. prepare a run from a base image
python3 scripts/prepare_sprite_run.py --out-dir <run-dir> --character-id <id> --base-image base.png
# 2. generate one row image per state with the engine-owned provider CLI
python3 scripts/generate_sprite_image.py --provider codex \
--prompt-file <run-dir>/prompts/<state>.txt \
--out <run-dir>/raw/<state>.png \
--ref <run-dir>/base-source.png \
--ref <run-dir>/references/layout-guides/<state>.png
# 3. extract frames
python3 scripts/extract_sprite_row_frames.py --run-dir <run-dir>
# 4. (optional) curate frames in the webview
python3 scripts/serve_curation.py --run-dir <run-dir>
# 5. bake the runtime atlas
python3 scripts/compose_sprite_atlas.py --run-dir <run-dir>
When only the combined sheet survives, rebuild a curator-ready run dir, then curate and export:
# rebuild frames: explicit --grid, --manifest rectangles, or alpha auto-detect (default)
python3 scripts/unpack_atlas_run.py --atlas sheet.png # auto-detect
python3 scripts/unpack_atlas_run.py --manifest manifest.json # exact rectangles
python3 scripts/unpack_atlas_run.py --pngs-dir furniture/ # import a loose PNG set
# after curating, bake corrections back to named PNGs
python3 scripts/export_curated_pngs.py --run-dir <run-dir>
Output defaults to a findable <source>-curator folder next to the input.
Once the atlas is composed, swap selected colours into N finished sheets without re-running generation. Dot art is exact-match by default; soft-edged art can opt into a tolerance. Geometry and alpha never move — the base manifest describes every variant.
# draft the opaque colours (edit into a recolor spec with kind "sprite-gen-recolor")
python3 -m sprite_gen.cli recolor-palette --base <run-dir>/sprite-sheet-alpha.png --out palette.draft.json
# bake every colourway into <run-dir>/variants/
python3 -m sprite_gen.cli recolor --run-dir <run-dir> --spec recolor.spec.json
# blink-compare and adopt in the curation view
python3 -m sprite_gen.cli curation --run-dir <run-dir>
Full spec/report contract and the adopt sidecar field: docs/recolor.md.
Generated sprites are keyed off their own magenta/green background inside the
pipeline, so they never need this. cutout is the import/post-edit utility: an
image that arrived with an opaque uniform background (a hand-drawn icon, a
downloaded sprite, a screenshot) is turned into a clean transparent PNG.
# routes on the corner colour: white/ivory -> matte, magenta/green -> extract engine
python3 -m sprite_gen.cli cutout icon.png --white-check
It reads the corner background colour and routes (--key auto|white|magenta|green):
--strength (bevel removal), --band (edge depth), --erode.extract chroma engine is
reused as-is. Key colours never appear in objects, so its colour-only cut is
safe there — exactly where a white matte's flood-fill guard is not needed.--white-check writes cyan/magenta/yellow composites so any leftover fringe
shows loudly. For uniform backgrounds; not for complex/non-uniform ones.
The full agent-facing workflow and contracts live in SKILL.md.
From Codex skill installer workflows, install this repository as a root skill:
python3 ~/.codex/skills/.system/skill-installer/scripts/install-skill-from-github.py \
--repo aldegad/sprite-gen --path .
Provider-backed generation is part of this engine (sprite_gen.gen), with
codex and grok as the supported providers. The general image-gen skill is
only a thin shuttle to the same command, so it does not need a second provider
implementation. See docs/gen.md for the CLI and verification
contract.
The component-row workflow is inspired by the Apache-2.0 licensed hatch-pet skill, but targets generic game sprite atlases and includes no pet packages or pet visual assets.
Apache-2.0
.githooks/
pre-commit
.github/
workflows/
ci.yml
.gitignore
.gitleaks.toml
CHANGELOG.md
docs/
architecture.md
assets/
breathe-editor.png
chroma-fullbody-illustration-green.png
chroma-fullbody-illustration-magenta.png
chroma-fullbody-pixelart-green.png
chroma-fullbody-pixelart-magenta.png
chroma-peel-illustration-before-after.png
chroma-peel-pixelart-before-after.png
claudecy-idle-crop.png
claudecy-idle.gif
claudecy-rest.gif
claudecy-running-crop.png
claudecy-running.gif
claudecy-sleep.gif
claudecy-success-crop.png
claudecy-success.gif
claudecy-talking.gif
claudecy-working.gif
curator-drag-update.gif
curator-iso.png
cutout-demo.png
demo-character.gif
demo-furniture.gif
founder-idle.gif
founder-side-idle.gif
founder-up-idle.gif
gptaku-flail.gif
gptaku-idle.gif
gptaku-jump.gif
howl-idle-crop.png
howl-idle.gif
howl-rest.gif
howl-running-crop.png
howl-running.gif
howl-sleep.gif
howl-success-crop.png
howl-success.gif
howl-talking.gif
howl-working.gif
social-preview-card.html
social-preview.png
chroma-alpha.md
curation.md
directional-anchor-workflow.md
frame-interpolation.md
gen.md
layer-tracks.md
locomotion-curation.md
pixel-unfake.md
qa-motion.md
recolor.md
run-contract.md
sheet-slicing.md
states-and-frames.md
static-pose-recipe.md
troubleshooting.md
LICENSE
NOTICE
pyproject.toml
README.es.md
README.fr.md
README.ja.md
README.ko.md
README.md
README.zh-Hans.md
scripts/
breathe_mutation_battery.py
check_visible_magenta.py
compose_layers.py
compose_selected_cycle.py
compose_sprite_atlas.py
compose_sprite_gif.py
curation.py
export_curated_pngs.py
extract_sprite_row_frames.py
extract.py
generate_sprite_image.py
gif_utils.py
inspect_sprite_run.py
interpolate_frames.py
measure_align_sigma.py
prepare_sprite_run.py
preview_animation.py
recolor.py
reroll_state_row.py
run_correction_loop.py
runio.py
score_sprite_run.py
serve_curation.py
slice_sheet_cells.py
unpack_atlas_run.py
SECURITY.md
SKILL.md
sprite_gen/
__init__.py
_deps.py
_modules.py
cli.py
compose/
__init__.py
compose_atlas.py
compose_cycle.py
compose_gif.py
compose_layers.py
export_pngs.py
layers.py
curate/
__init__.py
anchor.py
curation.py
effects/
__init__.py
anatomy.py
breathe.py
interpolate.py
recolor.py
reroll.py
frames/
__init__.py
check_visible_magenta.py
cutout.py
extract.py
segment.py
slice_sheet.py
unpack_atlas.py
gen/
__init__.py
base.py
chroma.py
codex_provider.py
generate_image.py
grok_provider.py
prepare.py
qa/
__init__.py
correction_loop.py
inspect.py
preview.py
score.py
serve/
__init__.py
composer/
composer.css
index.html
src/
api.js
boot.js
canvas.js
controls.js
i18n.js
library.js
session.js
ui.js
curator/
curator.css
index.html
src/
atlas.js
base-editor.js
boot.js
breathe.js
cards.js
chrome.js
compare.js
display.js
gen-trigger.js
i18n.js
lasso-select.js
persistence.js
pipeline-tree.js
progress.js
recolor.js
region-transform.js
row-controls.js
row-export.js
status.js
store.js
tooltip.js
transform-provider.js
transforms.js
tween.js
util.js
view-nav.js
zones.js
zoom-editor.js
serve_compose.py
serve_curation.py
spec/
__init__.py
layout.py
migrate_breathe.py
migrate_request.py
runio.py
util/
__init__.py
gif_utils.py
tests/
compose/
test_layer_compose.py
test_layer_contract.py
conftest.py
curate/
test_anchor_selection.py
test_curation_salvage_and_clones.py
test_directions.py
test_frame_variant.py
test_logical_height_contract.py
test_pixel_snap.py
test_pixel_unfake_migration.py
test_snap_phase_policy.py
effects/
test_breathe_anatomy_route.py
test_breathe_js_mirror.py
test_breathe_off_state.py
test_breathe_reference_key.py
test_breathe_sidecar_roundtrip.py
test_breathe.py
test_frame_interpolation.py
test_palette_post_only.py
test_recolor_bake.py
test_recolor_docs.py
fixtures/
expected-frames-manifest.json
expected-fused-frames-manifest.json
generate_fixtures.py
moe/
moe_green.png
moe_heart.png
moe_mirror.png
moe_red.png
run/
run-fused/
raw/
kick.png
pair.png
sprite-request.json
raw/
idle.png
walk.png
sprite-request.json
frames/
test_alpha_centroid_align.py
test_cutout.py
test_extract_perf_equivalence.py
test_extraction_golden.py
test_grid_record_exactness.py
test_heal_async.py
test_pitch_ground_truth.py
test_pitch_runlen_crosscheck.py
test_posix_manifest_paths.py
test_segment_projection.py
test_slice_sheet.py
test_sliver_guard.py
test_takes_heal.py
test_taxonomy_layout.py
gen/
test_chroma_extraction.py
test_chroma_key_auto.py
test_chroma_rcb_byte_identity.py
test_chroma_soft_alpha.py
test_chroma_ycbcr.py
test_codex_rollout_resolution.py
test_gen.py
packaging/
test_curation_asset_packaging.py
test_curation_cli_entrypoint.py
test_entrypoint_interpreter.py
test_layer_cli_entrypoint.py
test_numpy_dependency_gate.py
test_package_surface.py
test_pipeline_smoke.py
test_project_metadata.py
test_recolor_cli_entrypoint.py
test_version_ssot.py
qa/
test_inspect_score_loop.py
serve/
test_curation_view_contract.py
test_curator_pixel_scaling_ssot.py
test_curator_single_display_pipeline.py
test_pixel_grid_always_available.py
test_recolor_curation_view.py
spec/
test_migrate_breathe.py
test_request_read_no_mutation.py
test_request_write_isolation.py
test_runio_publish_set.pyFAQ
sprite-gen is a Claude Code plugin with 1 hand-picked skill for content work, indexed on Flowy. Install it with the command on its page. It includes sprite-gen. Its skills do not fire on their own yet. Request auto-invocation to have Flowy route them as you prompt. Free and open source.