Workflow·Gaming & Entertainment·v1.59.0

Sprite Gen

Generate clean 2D game sprites and animation atlases with a component-row pipeline: layout guides, chroma-key alpha cleanup, frame…

You say
Buy it · $19 Read it before you buy $19 Written by aldegad · unverified publisher
Context cost
530.6k tokensestimated from the bundle, loaded when it triggers
Bundle
179 files · 2122.5 kB145 scripts among them — read before you run
Licence
Apache-2.0paid listing
Last change
v1.59.0
Servers it uses
Noneruns standalone

What it does

Generate clean 2D game sprites and animation atlases with a component-row pipeline: base identity, numeric sprite-request SSoT, per-state layout guides, image-gen row strips, chroma-key alpha cleanup, connected-component frame extraction, cell-based atlas composition, QA reports, and runtime manifest frame_layout. Its curation webview also serves ANY image-candidate set (icons, logos, generated drafts) — agent chat can't render images, this can: unpack_atlas_run --pngs-dir import, then serve_curation side-by-side compare/pick.

Installed, it changes the agent in these ways.

What this skill changes about the agent is not written down here yet. The listing was collected from its source, and the description is in its own SKILL.md.

Workflow

Runs a procedure end to end.

spritesatlasgame-assetsanimation

The skill itself

This is the whole product. A skill is instructions the model reads, so there is nothing behind the listing you cannot see first — the front matter loads with every session, and the body below it loads when the skill triggers.

SKILL.md48.2 kB · 555 lines
--- name: sprite-gen version: 1.59.0 description: "Generate clean 2D game sprites and animation atlases with a component-row pipeline: base identity, numeric sprite-request SSoT, per-state layout guides, image-gen row strips, chroma-key alpha cleanup, connected-component frame extraction, cell-based atlas composition, QA reports, and runtime manifest frame_layout. Its curation webview also serves ANY image-candidate set (icons, logos, generated drafts) — agent chat can't render images, this can: unpack_atlas_run --pngs-dir import, then serve_curation side-by-side compare/pick. Palette-swap bake (`sprite-gen recolor`) turns a base sheet + palette map into N colourway sheets; the curation view blink-compares and adopts a pick into curation.json.recolor.picked. Curation triggers (KR/EN): 큐레이션, 큐레이션뷰, 큐레이션 해줘, 이미지 후보 보여줘/안 보임, 나란히 비교, 골라볼게 띄워줘, curation view, show image candidates side by side, let me pick. Recolor triggers (KR/EN): 팔레트 스왑, 팔레트 베이크, 리컬러, 색깔 바꾸기, 컬러웨이, 색 변형, 팔레트 맵, 색갈이, palette swap, recolor, colourway, colorway, bake variants, palette map." license: Apache-2.0 depends_on: required_bins: - name: codex why: "gen --provider codex (image_gen via ChatGPT OAuth)" - name: grok why: "gen --provider grok (Imagine via xAI OAuth)" required_scripts: - scripts/prepare_sprite_run.py - scripts/generate_sprite_image.py - scripts/extract_sprite_row_frames.py - scripts/interpolate_frames.py - scripts/compose_sprite_atlas.py - scripts/preview_animation.py - scripts/compose_selected_cycle.py - scripts/compose_sprite_gif.py - scripts/inspect_sprite_run.py - scripts/score_sprite_run.py - scripts/run_correction_loop.py - scripts/gif_utils.py - scripts/curation.py - scripts/runio.py - scripts/serve_curation.py - scripts/slice_sheet_cells.py - scripts/unpack_atlas_run.py - scripts/export_curated_pngs.py - scripts/recolor.py - scripts/compose_layers.py modes: default: component-row ---
37# Sprite Gen
38
39sprite-gen builds generic game sprite atlases with a component-row pipeline:
40
41```text
42sprite-request.json -> layout guides + prompts -> image-gen state rows
43-> chroma alpha -> connected components -> transparent cells
44-> sprite-sheet-alpha.png + manifest.json.frame_layout
45```
46
47Use only the component-row pipeline. Do not treat one-shot master sheets, fixed-grid atlas cutting, local drawing, or static fallback as a successful sprite result.
48
49## 필수 게이트 — AI raw 는 최종 에셋이 아니다 (BLOCKING)
50
51이 스킬의 모든 산출물은 아래 체크리스트를 통과해야 한다. 하나라도 어기면 그 결과물은 실패로 보고한다:
52
53- [ ] **AI 개입은 raw 생성 한 곳뿐이다.** raw/<state>.png 는 중간 산출물이며, 최종 에셋은 반드시 결정론 변환 — extract_sprite_row_frames.py(크로마 제거 → 컴포넌트 분리 → 피치 검출/그리드 스냅 → kCentroid → 공유 팔레트 → 셀 배치) — 를 거친다. 같은 입력이면 항상 같은 출력이 나오는 코드 경로만 픽셀 언페이크다.
54- [ ] **단순 다운스케일 쇼트컷 금지.** raw 를 PIL resize() 한 줄로 줄여 최종 경로에 놓는 것은 픽셀 언페이크 변환이 아니다 — AA 가장자리 열화와 그리드 미정렬이 그대로 남는다. "이번 한 번만 빠르게" 도 금지. 파이프라인 없이 낱장만 변환할 때도 run dir 를 만들어 같은 추출 경로를 태운다.
55- [ ] **베이스/앵커가 스타일 SSoT 다 — 도트 런이면 베이스부터 진짜 도트여야 한다.** 조립되는
56 프롬프트의 Style contract: 기본값은 "첨부한 베이스/앵커 레퍼런스를 그대로 따라라"이고,
57 이미지 모델은 첨부 레퍼런스를 프롬프트 텍스트보다 강하게 따른다. 그래서 fit.pixel_unfake
58 런에 AA/벡터풍 베이스를 붙이면 프롬프트에 "TRUE 32x32 pixel art" 를 적어도 raw 가 도트로
59 나오지 않는다. 잠금 전에 베이스에서 **픽셀 격자가 실측으로 검출되는지**(균일 블록 피치,
60 AA 반투명 가장자리 없음) 확인하고, 아니면 베이스부터 다시
61 만든다. 프롬프트 문구로 베이스의 스타일을 이기려 하지 마라.
62- [ ] **크로마 키는 소재색을 먼저 보고 고른다.** 핑크/보라/자주 소재 → 그린 #00FF00, 녹색/청록 식물 → 마젠타 #FF00FF. 분기표 SSoT 는 image-gen SKILL.md 최상단 게이트 (상세는 [docs/chroma-alpha.md](docs/chroma-alpha.md)).
63- [ ] **변환 후 소재색 보존을 검증한다.** 꽃이 희게 탈색됐거나 주요 색이 빠졌으면 키 선택이 소재와 충돌한 것이다 — 로컬 보정이 아니라 키를 바꿔 재생성한다.
64
65## 리네임 게이트 — 어휘/키를 바꿀 때 (BLOCKING)
66
67스키마 키·식별자·라벨을 걸쳐 어휘를 바꾸는 작업(pixel_perfectpixel_unfake 류)은
68**일괄 치환으로 시작하지 않는다**. 치환은 이름을 바꾸지만 계약은 **층위**로 존재한다:
69
70```text
71식별자 → 키 문자열 → 사용자 라벨(en+ko) → 문서 예제 → --help 문구 → 테스트 하니스
72```
73
74순서가 정해져 있다 (회귀 2026-07-25/26, plan sprite-gen/pixel-unfake-rename — 이 순서를
75거꾸로 해서 검증자 리젝트 3라운드가 났다):
76
77- [ ] **구조 단정을 스윕보다 먼저 쓴다.** 판독 SSoT(게이트) 밖에서 그 파일/키를 읽는 프로덕션
78 경로가 있으면 실패하는 테스트. **정규식이 아니라 AST** 로 — 실제 회귀 형태는 보통 두
79 줄(경로를 변수에 담고 다음 줄에서 읽기)이라 한 줄 정규식은 못 잡는다
80 (tests/test_pixel_unfake_migration.py 마지막 케이스가 그 형태).
81- [ ] **그 단정을 mutant 로 검증한다.** 옛 형태를 일부러 되돌려 실제로 실패하는지 본다. 통과만
82 하는 단정은 장식이고, 그걸 근거로 "구조로 닫았다" 고 말하면 거짓 보고가 된다.
83- [ ] **판독부는 키 이름만 바꾸지 않고 게이트 뒤로 옮긴다.** 이관 전 데이터에서 그 판독부만
84 조용히 틀린 답을 본다 (실측: 리롤이 "언페이크가 꺼져 있다" 며 거짓 거부).
85- [ ] **구분자가 바뀌는 치환은 토큰 단위로.** pixel-perfectpixel unfake 처럼 하이픈이
86 공백이 되는 치환은 argparse 옵션·경로·식별자를 깨뜨린다 (실측: --fit-pixel unfake 유령
87 옵션 등록 + 은퇴 안내문이 현행 플래그를 은퇴했다고 말하는 자기모순).
88- [ ] **은퇴 이름은 조용한 별칭으로 남기지 않는다.** 새 이름을 안내하며 hard error. 그 안내
89 문구 자체는 치환 대상에서 제외한다.
90- [ ] **순수 리네임 주장은 골든 회귀로 증명한다.** 리네임 전/후 산출물이 바이트 동일한지.
91
92
93## Base Lock Gate (Stage 0, BLOCKING)
94
95Identity ownership in the row pipeline:
96
97```text
98identity truth = accepted idle anchor
99motion truth = layout guide + paired/basis row when needed
100base truth = used only to create idle anchors, then removed from row inputs
101```
102
103The full reference-ownership flow (base → idle anchors → base 폐기 → basis/paired rows) and the base re-attach ban live in [docs/architecture.md](docs/architecture.md) §5.
104
105A weak idle anchor poisons every state — proportions, style, and identity drift compound across all rows. Before any row generation, answer the gate question y/n:
106
107> Is there an image good enough to **lock** as the canonical base idle?
108
109The base idle locks only when **all** of these hold:
110
111- Full body, nothing cropped (head to feet inside frame).
112- The final proportions and style the user asked for are already correct in this image (for example SD / chibi head-to-body ratio, pixel look, outline weight). The base defines the target — do not plan to "fix it later" in the rows.
113- For a pixel-art run (fit.pixel_unfake): the base itself is true pixel art — a uniform pixel-block grid is measurably present and edges are hard (no anti-aliased fringe). The style contract delegates style authority to this image, so a non-pixel base structurally produces a non-pixel row.
114- Identity matches the character sheet / reference (face, hair, markings, palette, props).
115- One clear single idle pose, facing the intended camera, readable silhouette at small size.
116- Background is a flat clean chroma-ready fill (or trivially keyable).
117
118If the answer is n: generate/iterate base candidates, review each against the criteria above, and re-gate. **Do not run prepare_sprite_run.py until a base is locked.** "Good enough for now" is not a pass — drift only grows once the rows start. When the answer is y, that exact file becomes the accepted idle anchor for its direction; keep the original generation so the lock decision is auditable, but do not attach it again after the idle anchors have replaced it as row identity truth.
119
120## 실행 인터프리터 — 전역 python3 는 이 스킬의 인터프리터가 아니다 (BLOCKING)
121
122이 스킬의 모든 명령은 **레포 루트의 venv 인터프리터**로 실행한다:
123
124```bash
125export SPRITE_GEN_ROOT=/path/to/sprite-gen
126$SPRITE_GEN_ROOT/.venv/bin/python <script.py> ...
127```
128
129- **부트스트랩은 README quickstart·CI 와 같은 한 줄이다** — python3 -m venv .venv && .venv/bin/pip install -e ..
130 .venv 가 없으면 만든 뒤 실행한다. 다른 경로에 만들었다면 그 인터프리터의 절대경로로 바꿔 쓴다 —
131 바뀌면 안 되는 것은 경로가 아니라 **"전역 python3 를 쓰지 않는다"** 는 규칙이다.
132- **이유**: 의존(Pillow, NumPy)의 SSoT 는 pyproject.toml 이고, 그것을 실물로 만드는 곳은 이 venv 하나다.
133 전역 python3$PATH 가 그날 가리키는 아무 인터프리터이고(macOS 에서는 보통 homebrew CPython,
134 PEP 668 EXTERNALLY-MANAGED), 거기 든 패키지는 손으로 넣은 것이라 선언과 실물이 갈린다. 실제로
135 그렇게 갈렸다: homebrew python3 에는 Pillow 만 있고 NumPy 가 없어서, **한 개가 깔려 있다는 이유로
136 다 깔린 것처럼 보이는** 상태였다.
137- **폴백 금지**: ".venv 있으면 그거, 없으면 python3" 같은 해석은 두지 않는다 (원칙 6).
138 없으면 만들거나 요란하게 실패한다 — 조용히 다른 인터프리터로 도는 경로는 없다.
139- **NumPy 가 없는 인터프리터에서는 아무것도 시작하지 않는다**: 진입점은 패키지 import 시점에
140 멈추고, 실행한 인터프리터 경로와 위 부트스트랩 명령을 그대로 찍는다. 추출 경로는 바이트 동일
141 계약을 지고 있어서 **순수 파이썬 폴백은 없다** — 느리게라도 도는 두 번째 구현을 두면 같은 질문에
142 답이 둘이 된다. (게이트 sprite_gen/_deps.py, 잠금 tests/test_numpy_dependency_gate.py)
143- **자식 프로세스는 상속한다**: heal_run 과 큐레이션 서버는 자식을 sys.executable 로 띄운다.
144 즉 부모를 옳은 인터프리터로 띄우면 그 아래는 자동으로 옳고, 반대로 큐레이션 서버를 전역 python3
145 띄우면 그 서버가 부르는 재추출·compose 가 전부 같이 틀린다. 고칠 곳은 **띄우는 순간 한 곳**이다.
146- **sprite-gen <tool> 은 실재하는 콘솔 스크립트다** (anchor, cutout, curation,
147 recolor, recolor-palette, migrate-breathe, migrate-request …). pip install 이 venv 의 bin/ 에 써 넣고 그 shebang 이 **바로 그 venv 의
148 인터프리터**를 가리키므로, 이 형식은 인터프리터를 고르는 문제 자체가 없다:
149
150 ```bash
151 $SPRITE_GEN_ROOT/.venv/bin/sprite-gen <tool> ...
152 ```
153
154 - **여기서도 절대경로다** — 맨 sprite-gen 이 PATH 에 있는 건 venv 를 활성화했거나 그 환경에
155 설치한 셸 안에서뿐이다. SKILL.md·docs/*.md 는 활성화 없는 셸에서 읽히므로 맨 python3
156 같은 이유로 맨 sprite-gen 도 쓰지 않는다 (README quickstart 는 활성화가 앞에 있어 예외).
157 - **이 변경 이전에 만든 .venv 에는 없다** — [project.scripts] 가 없던 시절 설치본이라
158 bin/sprite-gen 이 안 만들어졌다. pip install -e . 를 한 번 다시 돌리면 생긴다.
159 - $SPRITE_GEN_ROOT/.venv/bin/python -m sprite_gen.cli <tool> ... 는 같은
160 cli:main 을 부르는 동치 형식이다 — 콘솔 스크립트가 아직 없는 venv 에서 쓴다.
161- **레지스터는 파일로 갈린다**: 상대경로 python3 scripts/... 형식이 같은 인터프리터를 가리키는 건
162 source .venv/bin/activate 가 **바로 앞에 적혀 있는** README quickstart 안에서만이다. SKILL.md
163 docs/*.md 는 활성화 단계가 없는 셸에서 읽히므로, 절대경로든 상대경로든 **여기서는 상대형을 쓰지
164 않는다** — 위 venv 절대경로 형식 하나만 쓴다. (tests/test_entrypoint_interpreter.py 가 이 두 파일군에
165 대해 잠근다.)
166
167## Script Map
168
169Scripts are explicit pipeline commands, not hidden imports. One job each (stage detail: [docs/architecture.md](docs/architecture.md) §2):
170
171- prepare_sprite_run.py — write sprite-request.json, per-state layout guides, prompts, and empty raw/ + frames/ from request truth.
172- extract_sprite_row_frames.py — read raw/<state>.png strips: chroma removal → connected components → transparent frame cells + frames/frames-manifest.json.
173- **에이전트 주도 호흡** (사용자가 "숨쉬기 적용해서 뽑아줘" 라고만 해도 됨): 호흡은 사이드카 필드라 뷰 없이도 켤 수 있다 — (1) states.<state>.breathe = {"depth": 0.06, "breaths": 1, "lag": 0.1} 만 쓰면 된다. **경계는 선언하지 않는다** — sprite_gen/anatomy.py 가 검출한다. 큐레이터를 거치면 그 결과가 사이드카 anatomy 에 얼려지고(GET /api/breathe-anatomy), 뷰 없이 에이전트가 breathe 만 쓴 런은 anatomy 가 비어 있어 **굽기가 매번 다시 잰다** — 굽기는 사이드카에 쓰지 않는다. 어느 쪽이든 동작한다. **굽기는 얼린 값을 신뢰하지 않는다 — 언제나 자기 기준 프레임에서 다시 잰다** (얼린 값은 큐레이터 프리뷰용 캐시다). 사이드카와 어긋나면 manifest 의 sidecar_drift 로 값을 실어 보고한다. 그 캐시가 아직 유효한지는 기준 프레임의 **입력** 지문(원본 파일 스탬프·픽셀편집·변형·변종)으로 판정하고, 어긋나면 큐레이터가 프리뷰·영상 내보내기를 **거부하며 갱신하라고 알린다** — 조용히 낡은 숫자로 그리지 않는다. 사람이 특정 행에 고정하고 싶을 때만 rigid_row 를 준다. (에이전트 직접 쓰기는 load_curationstamp_curation 도장 경로 필수, 열린 탭은 새로고침 안내 — 함정 상세: [docs/troubleshooting.md](docs/troubleshooting.md)), (2) compose_sprite_gif.py/compose_sprite_atlas.py 가 자동으로 굽는다. 검증: gif-manifest 의 breathe.phases. **구 splits/amplitude/subpixel 은 요란하게 거부된다** — 옮기려면 sprite-gen migrate-breathe <run-dir> --apply.
174- **정지 자세(sit/lie/carry_idle 등) 행 레시피** — 정지 1컷 + 링크 복제 @ 4fps + 허리선 호흡(breaths 3) + 눈 보이는 방향만 깜빡임. **복제 수 = recommended_breathe_frames(breathe) − 1** (호흡당 SMOOTH_CYCLE_FRAMES=6 프레임 확보; breaths 3 → 총 18컷) — 짧은 루프(옛 11컷)에 다수 호흡을 우겨넣으면 1px 위상이 매 프레임 토글해 진동으로 읽히던 걸 막는다 (maintainer 2026-07-24). 깜빡임은 **시퀀스 끝 근처**(맨 끝 아님, 뒤에 눈뜬 rest ≥2)에 배치해 루프 이음새 전에 다시 떠 스냅을 없앤다. 실측 도출 근거·자동 적용 절차·프레임 게이트: [docs/static-pose-recipe.md](docs/static-pose-recipe.md) (maintainer 확정 2026-07-19, 이징 게이트 2026-07-24).
175- 호흡(idle breathing)은 **후처리 레이어**다 (maintainer 확정 2026-07-18) — 스크립트가 아니라 curation.json 사이드카 states.<state>.breathe = {depth, depth_x?, breaths, lag, rigid_row?, anatomy} 로 선언하고, compose/GIF 가 재생 시퀀스 위에 결정론(봉투 워프, sprite_gen/breathe.py)으로 굽는다. 깜빡임 프레임도 그대로 숨쉰다 (프레임 선택과 직교).
176 - **변형은 자르지 않고 강도를 떨군다** (2026-07-25 교체): 스프라이트 전체에 연속 변형장을 걸고 그 강도를 강체 경계에서 0 으로 테이퍼한다. env=0 인 행은 가로 사상이 항등이고 세로 누적이 정확히 1씩 늘어 **그 구간이 프레임 간 비트 동일**하다 — 눈·입이 몇 도트뿐이라 근사로는 표정이 뭉갠다. 가로는 행 안에서 밀도를 적분하므로 사상이 단조라 접힘이 없고, 날개 같은 부속은 밀리기만 하고 안 늘어난다.
177 - **강체 경계는 가슴이 아니라 목이다.** 가슴은 해부학 개념이라 몬스터마다 다르지만 목은 기하학적 병목이라 안정적으로 잡힌다. 얼굴이 몸통에 있으면(버섯·슬라임) 대칭 눈쌍을 찾아 얼굴 아래로 내린다. 병목도 얼굴도 없으면 어깨-기울기로 떨어지고 그 사실이 anatomy.warnings 에 남는다.
178 - 큐레이션 뷰: 줄 헤더 호흡 체크박스(즉시 on/off) + 라벨 클릭 편집기(실재생 위 **강체 경계 1개 드래그** · 세로 진폭 depth · 가로 진폭 depth_x(기본 "=세로", 0 = 가로 끄기 — maintainer 요청 2026-07-30 가로/세로 분리) · 루프당 호흡 횟수 · auto 되돌리기 — 즉시 반영, Esc 복원, 최종 굽기 필름스트립). 루프 길이는 시퀀스 그대로 불변이고 위상이 연속값이라 breaths 는 요청 그대로 적용된다 (범위 1~8이고 **정수여야 한다**; 밖이거나 비정수면 조용히 깎지 않고 요란하게 거부한다 — depth 0.005~0.20, depth_x null|0~0.20, lag 0~0.45 도 같다). 재추출/굽기 대기 없음.
179 - 세로선(몸통 밴드)을 **사람이 조정하면** 보호 램프가 밴드 자체에 앵커된다 — 밴드 밖 열은 늘어나지 않고 밀리기만 한다. 자동 검출 밴드는 부속(날개·긴 팔)이 실재할 때만 켜지는 기존 계약 그대로다 (블롭에서 밴드 조정이 무력했던 버그 수리, 2026-07-30).
180- interpolate_frames.py — AI in-between: 두 프레임을 ref 로 물려 **생성형**(codex 기본/grok)으로 중간 프레임을 그려 **테이크**로 기록 (raw 단계 AI — 최종 프레임은 여전히 결정론 추출이 굽는다). 서버 머신의 provider CLI OAuth 를 쓰므로 GUI 버튼도 동작 — 인증 전제와 실측 근거(RIFE 파기): [docs/frame-interpolation.md](docs/frame-interpolation.md).
181- compose_sprite_atlas.py — compose sprite-sheet-alpha.png + runtime manifest.json.frame_layout.
182- export_aseprite.py (sprite-gen export-aseprite) — describe the composed atlas as Aseprite-compatible JSON for Phaser or Flame; usage, mapping, and limitations: [docs/engine-export.md](docs/engine-export.md).
183- preview_animation.py — QA previews from extracted frames: contact sheets + state GIFs under qa/.
184- compose_selected_cycle.py — record a human-selected frame subset as a selected-cycle manifest + QA GIF/contact sheet (reads curation.json by default; --frames overrides).
185- compose_sprite_gif.py — clean transparent GIF export: single frame set, or --run-dir batch (one GIF per state from request fps + curation.json) into <run-dir>/exports/; called by the webview's Export-GIFs button and the v2 desktop app.
186- inspect_sprite_run.py — deterministic row inspection for the automatic correction loop: expected vs found frame count, 64-bin RGB histogram similarity, dHash silhouette similarity, motion presence, centroid jitter, and extraction warnings.
187- score_sprite_run.py — score an inspect report (0-100), preserve the best-candidate rank signal, and turn measured defects into provider-ready correction hints.
188- run_correction_loop.py — bounded inspect → score → correction-hint loop (max 3 passes by default). It can run as a dry-run verifier without a provider, or call an explicit provider command; missing provider without --dry-run fails loudly.
189- gif_utils.py — shared transparent-GIF writer.
190- curation.py — curation sidecar SSoT (schema + transform math + the stamping atomic writer) shared by the compose scripts, the anchor CLI, and the webview server so they never drift.
191- sprite_gen/curate/anchor.py (sprite-gen anchor) — direction-anchor SSoT: which curated instance is a direction's identity (human pin > the anchor row's sequence head), the post-processing bake of that one frame, and the references/anchors/<dir>-anchor-x8.png derived cache that row generation attaches. Reroll, the generation plan, and the curation view's anchor chip all resolve through it.
192- sprite_gen/spec/runio.py — safe run-dir IO: single-writer lock (.sprite-gen.lock) + atomic writes for the extract/compose/export/unpack writers, so parallel agents cannot interleave writes into one character folder.
193- sprite_gen/serve/serve_curation.py (sprite-gen curation) — standalone curation webview for one run dir (works from Claude Code Desktop, the Codex app, or any host with the skill). The -m sprite_gen.serve.serve_curation module form and the scripts/serve_curation.py wrapper reach the same declaration and the same implementation — three live entry forms, one program (launch forms: [docs/curation.md](docs/curation.md)). When <run-dir>/variants/recolor.report.json is present, the view also blink-compares baked colourways and records the adopted name in curation.json.recolor.picked (detail: [docs/recolor.md](docs/recolor.md)).
194- sprite_gen/effects/recolor.py (sprite-gen recolor / sprite-gen recolor-palette) — deterministic palette-swap bake. recolor-palette drafts a frequency-ordered palette map from a base sheet; recolor takes base sheet + recolor spec and bakes N variant sheets + a per-variant substitution report into <run-dir>/variants/ (or an explicit --out-dir). Exact RGB match by default (dot-art safe); opt-in Chebyshev tolerance for soft edges. Alpha preserved, geometry untouched — a base manifest describes every variant. No Silent Fallback: unused map sources and unmapped passthrough colours are named and counted in recolor.report.json. Detail: [docs/recolor.md](docs/recolor.md).
195- sprite_gen/compose/compose_layers.py (sprite-gen compose-layers) — deterministic composite bake for a run that declares a **rig**. Stacks curated rows onto each other by integer pivot translation + arbitrary alpha masks (no resampling, rotation or scale of its own) into <run-dir>/layers/<name>.png + <name>.manifest.json + layers.report.json. Optional and opt-in: a request with no rig / track / layers is not a layer run and is refused by name rather than composed. All-or-nothing — declaration, composition **and** publish: one violation reports every violation and writes nothing. Declaration schema, CLI usage, and what prepare carries: [docs/layer-tracks.md](docs/layer-tracks.md).
196- unpack_atlas_run.py — inverse of compose: rebuild a curator-ready run dir from a finished sheet (--grid > --manifest > auto-detect) or import a PNG folder (--pngs-dir, with sibling meta.json labels/iso grid).
197- export_curated_pngs.py — export curated frames back to named PNGs with the transform baked in, into <run-dir>/curated/; the deliverable for imported still sets.
198- cutout.py (sprite-gen cutout) — background remover for **imported** images (not pipeline output, which is already keyed). Routes on the corner background colour (--key auto|white|magenta|green): **white/ivory** → position matte (corner flood-fill keeps interior highlights unholed → decontaminated soft-alpha border + soft erode); **magenta/green key** → reuse the verified extract.remove_chroma_background engine as-is (no drift — key colours are absent from objects so its colour-only cut is safe there). --white-check writes cyan/magenta/yellow verification composites. No Silent Fallback (leftover non-zero RGB under transparency raises).
199- slice_sheet_cells.py — slice a multi-figure grid sheet (same character, N expressions/variants in one image) into per-cell standing cuts: v1.13 chroma alpha + centroid cell assignment + merged-figure split/in-cell re-label + neighbour-debris drop + per-cell height normalization + shared feet baseline. For dialogue cut-in portraits (立ち絵), not animation rows. Detail: [docs/sheet-slicing.md](docs/sheet-slicing.md).
200- check_visible_magenta.py — optional screenshot QA guard for visible chroma-key leakage.
201
202## Workflow
203
2040. Pass the **Base Lock Gate** above. Do not start step 1 until a base idle is locked (y).
205
2061. Prepare the run:
207
208```bash
209$SPRITE_GEN_ROOT/.venv/bin/python $SPRITE_GEN_ROOT/scripts/prepare_sprite_run.py \
210 --out-dir <target>/assets/generated/sprites/<character-id> \
211 --character-id <character-id> \
212 --base-image /absolute/path/to/base.png \
213 --description "<short identity note>" \
214 --force
215```
216
217For hatch-pet-style locomotion, add the cell gate explicitly: --cell-width 192 --cell-height 208.
218
219방향 있는 캐릭터(휴머노이드 4/8방향)는 방향 계약을 함께 선언한다: --directions down,side,up --mirror left=side.
220방향 계약 런의 파일은 **택소노미**(raw/<dir>/<pose>.png, frames/<dir>/<pose>/, 가이드/프롬프트 동일)로
221나뉜다 — 자세가 늘어도 flat 폴더가 비대해지지 않는다. 경로 리졸버 SSoT 는 sprite_gen/layout.py,
222추출된 프레임의 경로는 frames-manifest row.files 가 SSoT 다 (run-contract §2).
223base = down 정면 기본자세 하나이고, prepare 가 방향 앵커(<dir>_idle) 슬롯을 합성하고 생성 체인 SSoT
224(references/generation-plan.json — 1단계 앵커는 base 기반, 2단계 행은 자기 방향 앵커 기반, 미러 방향은
225생성 생략 계약)를 기록한다. 상세와 좌우 재생성 규칙: [docs/directional-anchor-workflow.md](docs/directional-anchor-workflow.md) "Prepare 스캐폴딩".
226
227This writes:
228
229```text
230sprite-request.json
231base-source.<ext>
232references/layout-guides/<state>.png
233prompts/<state>.txt
234raw/
235frames/
236```
237
2382. Generate one image per state with the engine's own gen command (generation is engine-owned; the image-gen skill is now a thin shuttle over this — [docs/gen.md](docs/gen.md)):
239
240```bash
241$SPRITE_GEN_ROOT/.venv/bin/python $SPRITE_GEN_ROOT/scripts/generate_sprite_image.py \
242 --provider codex \
243 --prompt-file <run>/prompts/<state>.txt \
244 --out <run>/raw/<state>.png \
245 --ref <run>/base-source.<ext> --ref <run>/references/layout-guides/<state>.png
246```
247
248Use prompts/<state>.txt as the prompt; save the selected image as raw/<state>.png. --provider is optional — the default is **codex** (SPRITE_GEN_DEFAULT_PROVIDER env overrides it; an observable grok fallback kicks in only if codex is unavailable). Pass --provider grok explicitly for the faster backend; codex adheres tighter to negative constraints. Default policy: [docs/gen.md](docs/gen.md#default-provider-selection). Keep the request chroma key on the background (extraction removes it). Reference attachment rules:
249
250**생성 동시성 (maintainer 확정 2026-07-19)**: 여러 행을 뽑는 배치는 **4동시**로 돌린다 —
251sprite-gen gen 호출을 최대 4개 병렬 (codex 실측 4병렬까지 스로틀 없음; grok 도 4,
252사용자 관측상 6까지 가능하나 기본은 4). 1개씩 직렬은 멀티-행 배치에서 안티패턴.
253run-dir 쓰기는 runio.py 락이 지키므로 생성(각자 다른 raw/<state>.png 출력)은
254안전하게 병렬화된다. 이 규칙은 지침이다 — 오케스트레이션 스크립트를 짤 때
255ThreadPoolExecutor(max_workers=4) 급으로 반영하라.
256
257Generation providers are **engine backends**, not user-facing agents. Selecting
258grok launches a headless grok -p process owned by GrokProvider; it does not
259require or route through a separate user-facing skill/task. Spawning a visible
260worker/agent is the caller's orchestrator concern — out of this engine's scope.
261Command chain: [docs/gen.md](docs/gen.md#provider-topology).
262
263- Simple/default states (before direction-anchor mode exists): attach exactly two references — base-source.<ext> (canonical identity) + references/layout-guides/<state>.png (layout only).
264- Direction-anchor mode: do **not** attach base-source.<ext> to action rows. Attach the accepted target-direction anchor (**a single-pose single image — never a multi-frame idle row**) + the state layout guide; for a paired row also attach the basis row as timing/scale/motion reference only. **Never choose the anchor crop by hand** — ask the pipeline, right before each generation:
265
266```bash
267$SPRITE_GEN_ROOT/.venv/bin/python -m sprite_gen.cli anchor \
268 --run-dir <run> --for-state <state> # prints the identity ref path (bakes it)
269```
270
271 It returns references/anchors/<dir>-anchor-x8.png for an action row (the curated anchor frame — pixel edits, transforms, deletions and reordering all baked, upscaled ×8 NEAREST) and base-source.<ext> for an anchor row or a non-direction run. The file is a derived cache, so re-run it every time; which frame is the anchor is the human's call (--pick <state>#<index>, or the pin button in the curation view) and defaults to the anchor row's curated sequence head. Chain details: [docs/directional-anchor-workflow.md](docs/directional-anchor-workflow.md).
272- Hatch-pet-style locomotion may attach additional references only when they are part of the row plan, recorded in qa-notes.md: original sheet / canonical base (identity support only), a previous gait row such as raw/running-right.png (motion rhythm only), or an accepted motion-QA artifact (gait readability support only).
273
2743. Extract frames:
275
276```bash
277$SPRITE_GEN_ROOT/.venv/bin/python $SPRITE_GEN_ROOT/scripts/extract_sprite_row_frames.py \
278 --run-dir <target>/assets/generated/sprites/<character-id>
279```
280
281This removes the request chroma key, finds connected sprite components, fits each pose into a fresh transparent request-sized cell, and writes frames/<state>/frame-N.png plus frames/frames-manifest.json.
282
2833.5. (Optional) Curate frames in the webview:
284
285```bash
286$SPRITE_GEN_ROOT/.venv/bin/sprite-gen curation \
287 --run-dir <target>/assets/generated/sprites/<character-id>
288```
289
290Standalone local webview: side-by-side frame compare, select/reject, drag-to-reorder play sequence, non-destructive per-frame transform saved to curation.json (originals never rewritten; no sidecar = all frames in order, an explicit default). Usage detail, finished-sheet editing via unpack_atlas_run.py, and the standalone image-candidate curation path: [docs/curation.md](docs/curation.md).
291
2924. Compose the runtime atlas:
293
294```bash
295$SPRITE_GEN_ROOT/.venv/bin/python $SPRITE_GEN_ROOT/scripts/compose_sprite_atlas.py \
296 --run-dir <target>/assets/generated/sprites/<character-id>
297```
298
299This writes:
300
301```text
302sprite-sheet-alpha.png
303sprite-sheet-alpha.report.json
304manifest.json
305```
306
307manifest.json.frame_layout is the runtime SSoT. Game code must consume rectangles from the manifest and must not recover frame rectangles from alpha content at runtime.
308
3094.5. (Optional) Bake palette-swap colourways of the finished atlas:
310
311```bash
312# draft the opaque colours of the base sheet (edit into a recolor spec)
313$SPRITE_GEN_ROOT/.venv/bin/sprite-gen recolor-palette \
314 --base <run>/sprite-sheet-alpha.png --out <run>/palette.draft.json
315
316# bake N variants from a recolor spec (kind "sprite-gen-recolor") into <run>/variants/
317$SPRITE_GEN_ROOT/.venv/bin/sprite-gen recolor \
318 --run-dir <run> --spec <run>/recolor.spec.json
319```
320
321Exact RGB match by default (dot art); opt-in match: "tolerance" for soft edges. Same input → same output bytes. The report names every unused map source and every unmapped passthrough colour — nothing outside the map vanishes quietly. Spec schema, report fields, and curation-view adopt flow: [docs/recolor.md](docs/recolor.md).
322
3234.6. (Optional, rig runs only) Bake the declared composite stacks:
324
325```bash
326$SPRITE_GEN_ROOT/.venv/bin/sprite-gen compose-layers \
327 --run-dir <target>/assets/generated/sprites/<character-id>
328```
329
330Only for a run whose sprite-request.json declares rig / states.<state>.track / layers — every other run is untouched by this feature and this step is skipped. It stacks the **curated** rows (integer pivot translation + alpha masks, no resampling) into <run>/layers/<name>.png + <name>.manifest.json + layers.report.json, so the same run bakes the same bytes every time. --names a,b bakes a subset and leaves the rest of layers/ alone. Declaration schema, landmark rules, track kinds, and what prepare carries: [docs/layer-tracks.md](docs/layer-tracks.md).
331
3325. Launch the curation webview automatically (default closing step):
333
334```bash
335$SPRITE_GEN_ROOT/.venv/bin/sprite-gen curation \
336 --run-dir <target>/assets/generated/sprites/<character-id> &
337```
338
339After the atlas composes (and QA previews exist), launch the webview in the background and report the printed URL — finishing a run means handing the human the open webview, not just file paths. Multi-agent launch rules (per-launch free port, one webview per run dir, .sprite-gen.lock, --no-open for headless): [docs/curation.md](docs/curation.md). Skip the auto-launch only for an explicitly unattended batch run.
340
341## SSoT
342
343Every run starts with sprite-request.json. It owns the numeric recipe used by prompts and scripts:
344
345```json
346{
347 "version": 1,
348 "kind": "sprite-gen-request",
349 "engine": "component-row",
350 "character": { "id": "demo-hero", "description": "same character as the base image" },
351 "cell": { "shape": "square", "size": 256, "safe_margin": 24 },
352 "chroma_key": { "name": "magenta", "hex": "#FF00FF", "rgb": [255, 0, 255] },
353 "states": {
354 "idle": { "frames": 4, "fps": 4, "loop": true, "action": "subtle breathing and blinking" },
355 "attack": { "frames": 4, "fps": 8, "loop": false, "action": "simple windup, strike, recovery attack pose sequence with no detached effects" },
356 "jump": { "frames": 4, "fps": 8, "loop": false, "action": "jump arc through body position only" },
357 "wave": { "frames": 4, "fps": 6, "loop": false, "action": "friendly hand wave gesture; arm changes clearly while feet stay planted" }
358 }
359}
360```
361
362256 is a default variable, not a hidden constant. Change it through the request, then regenerate guides, prompts, extraction, and atlas from the same request.
363
364When safe_margin is omitted, the default is **proportional**: 9.4% of the cell dimension per axis, floored (256 → 24px, 128 → 12px, rect 192×208 → 18/19px). An explicit request/CLI value is absolute and wins as-is.
365
366**테이크(takes)** — 같은 상태의 후보/보강 스트립은 수동 병합이 아니라 request 로 선언한다:
367"states": { "down_idle": { "frames": 4, ..., "takes": [{ "label": "blink", "frames": 4 }] } }
368+ raw/<...>.takes/<label>.png. 추출이 primary 뒤에 이어붙여 한 행의 프레임 풀을 만들고
369manifest labels("blink#0"…)로 큐레이션 뷰에 표시된다. 계약 상세: docs/run-contract.md §2.
370
371**실시간 계약** — frames/ 는 (raw + request + 엔진)의 파생 캐시다. 큐레이션 뷰·compose·
372다운로드가 진입 시 heal_run 으로 stale 행을 자동 재유도하므로 "재추출" 을 별도 스텝으로
373지시할 필요가 없다 (raw 없는 행은 보존 + 관측 노트). 캐시 키 = 행별 engine_revision.
374
375Optional fit object (opt-in; absent means legacy behavior), exposed by prepare_sprite_run.py as --fit-* flags:
376
377- "fit": { "resample": "kcentroid", "align_x": "foot-centroid", "align_y": "bottom" } — pixel-art-aware downscale and jitter-free frame alignment. align_x: "alpha-centroid" (opt-in, perfectpixel-studio port) aligns the fringe-insensitive alpha-weighted centroid per frame — the strongest anti-jitter anchor for walk/run rows.
378- "fit": { "pixel_unfake": true, "logical_height": 64, ... } — true pixel-unfake extraction with no non-integer resampling (per-frame pitch detection → grid snap → kCentroid → run-wide shared palette → integer NEAREST). Fully deterministic code, applied at the row-extraction stage only; the style SSoT is the attached base/anchor reference, never prompt text.
379- Parameter reference, stage ownership, the pixel-density reference rule, and the before/after plain-twin + curator toggle: [docs/pixel-unfake.md](docs/pixel-unfake.md).
380
381Rectangular generation cells are allowed when the target motion benefits from hatch-pet-style row proportions:
382
383```json
384"cell": { "shape": "rect", "width": 192, "height": 208, "safe_margin_x": 18, "safe_margin_y": 16 }
385```
386
387The generated row uses the request cell shape. The final atlas is still consumed through manifest.json.frame_layout; runtime code must not assume square cells.
388
389## Prompt Contract
390
391The generated row prompt must come from prompts/<state>.txt. Do not hand-write frame counts into a separate prompt. The prompt requires:
392
393- exact state frame count from sprite-request.json
394- one complete full-body pose per invisible request-sized slot
395- safe margin from sprite-request.json
396- same locked anchor identity across every frame
397- motion-only row responsibility: the row should solve limb/body timing, not rediscover character details
398- flat chroma-key background from sprite-request.json
399- no shadows, glows, smears, speed lines, dust, scenery, text, UI, frame numbers, guide boxes, or detached effects
400
401If image generation produces guide boxes, visible labels, overlapping poses, backgrounds, cropped bodies, or identity drift, regenerate the row. Do not repair bad visual generation by drawing or tiling sprites locally.
402
403## Output Contract
404
405**Install from curated/, never from frames/.** frames/ is pre-curation — the human's
406picks, pixel edits and transforms live in curation.json and are applied downstream. Copying
407frames/ into an app silently ships the un-edited image and nothing fails. Stills →
408export_curated_pngs.py then curated/. Animation → the composed atlas + manifest.
409Contract: [docs/run-contract.md](docs/run-contract.md) §2-c.
410
411One worker owns exactly one character folder. The canonical run-dir folder tree — every input/output file and which ones drive the curation view — is owned by [docs/run-contract.md](docs/run-contract.md) §2. Do not let multiple workers write the same character folder. The curation.json sidecar schema (selected/order/transforms/pixel_unfake) and its folder-collision rule: [docs/curation.md](docs/curation.md).
412
413## Runtime Contract
414
415manifest.json must contain:
416
417- game_input: "sprite-sheet-alpha.png"
418- degraded_static_fallback: false
419- animation.rows.<state> with frames, fps, durations_ms, and loop
420- frame_layout.rows.<state>[i] absolute atlas rectangles
421
422Runtime must sample only the active rectangle. Rendering the whole atlas on one plane, guessing a grid, or showing a raw chroma row is a failed integration.
423
424Frame timing and cell reuse (2026-07-16, Aseprite-JSON 과 동형 패턴):
425
426- frame_layout.rows.<state> 는 재생(인스턴스) 순서 그대로이며, 같은 그림으로
427 구워지는 복제 인스턴스는 **같은 rect 가 반복**된다 — 텍스처 칸은 고유 굽기당
428 하나만 쓴다. 소비자는 지금처럼 프레임 인덱스 → rect 샘플링만 하면 된다.
429- animation.rows.<state>.durations_ms[i] 가 프레임별 표시 시간의 SSoT 다
430 (현재는 fps 등간격으로 채워짐). 배열이 있으면 fps 대신 이것을 따른다 —
431 루프딜레이/홀드 프레임은 마지막 프레임 복제(rect 재사용, 텍스처 비용 0)나
432 duration 연장으로 표현한다.
433
434Static fallback is allowed only as explicit survival output when generation is blocked. It is not a sprite-gen pass and must not create sprite-sheet-alpha.png.
435
436## QA
437
438Automated checks (must all pass before reporting done):
439
440- frames/frames-manifest.json.ok is true
441- sprite-sheet-alpha.report.json.ok is true
442- every state has the declared frame count
443- no frame is empty or near-opaque background
444- no frame has excessive edge pixels or chroma-adjacent pixels
445- browser screenshots pass scripts/check_visible_magenta.py when used in a game
446
447Automatic correction-loop dry run:
448
449```bash
450$SPRITE_GEN_ROOT/.venv/bin/python $SPRITE_GEN_ROOT/scripts/run_correction_loop.py \
451 --run-dir <target>/assets/generated/sprites/<character-id> \
452 --states <state> \
453 --dry-run
454```
455
456This writes correction-loop.report.json, per-attempt inspect.json, score.json,
457and correction-hints.txt. A real regeneration loop must pass an explicit
458provider command; there is no silent fallback generator.
459Use --min-attempts 2 for a live E2E that must exercise at least one provider
460regeneration even when the seed candidate already clears the score gate.
461
462### Motion Continuity (BLOCKING)
463
464Static identity QA is not enough — a row can have the right frame count, clean alpha, and consistent identity and still animate as garbage. Build the previews and review motion **as motion**:
465
466```bash
467$SPRITE_GEN_ROOT/.venv/bin/python $SPRITE_GEN_ROOT/scripts/preview_animation.py \
468 --run-dir <target>/assets/generated/sprites/<character-id>
469```
470
471The full verdict criteria (cyclic locomotion, loop seam, non-loop gestures, humanoid per-frame anatomy review, independent second opinion) live in [docs/qa-motion.md](docs/qa-motion.md). If a row fails motion continuity, **regenerate that row** — do not repair motion by drawing or re-timing frames locally. Record the per-state motion verdict in qa-notes.md.
472
473Report:
474
475```text
476sprite_gen_done=<character-id>
477folder=<absolute folder path>
478engine=component-row
479files=sprite-request,raw,frames,atlas,manifest
480qa_note=<one sentence>
481```
482
483## Docs Topology
484
485Leaf docs are one link deep from this hub. The tree groups them by the concern
486you are in — walk down the branch that matches your task, don't scan the flat
487list. Each doc owns its tables; SKILL.md and the others point rather than restate.
488
489```text
490sprite-gen (this SKILL.md = behavior contract + hub)
491
492├─ CONTRACT & STRUCTURE ── "what files exist and what each stage promises"
493│ ├─ docs/run-contract.md # pipeline stage I/O table · canonical run-dir folder tree ·
494│ │ # curation-view display contract · run_revision/HTTP-409 ·
495│ │ # per-state salvage + stale backup · --pngs-dir import rule
496│ └─ docs/architecture.md # how scripts realize the contract: stages · cell geometry ·
497│ # idle-anchor ownership flow · extraction internals (SKILL wins on conflict)
498
499├─ REQUEST AUTHORING ── "fill sprite-request.json before generating"
500│ ├─ docs/states-and-frames.md # which states · frame counts (4/5/6/8/9/12) · Quick Path JSON
501│ ├─ docs/subject-profiles.md # "subject": character|effect · sparse-floor 프로필 ·
502│ │ # 이펙트 베스트/워스트 프랙티스 (실측 배터리 근거)
503│ ├─ docs/pixel-unfake.md # fit / pixel_unfake params · plain-twin curator toggle · density refs
504│ └─ docs/chroma-alpha.md # chroma key branch table · --chroma-key auto · alpha cleanup
505
506├─ GENERATION ── "raw/<state>.png from prompts (the one AI step)"
507│ ├─ docs/gen.md # sprite-gen gen provider CLI · verified PNG/report · image-gen shuttle
508│ ├─ docs/frame-interpolation.md # generative in-between (codex/grok) → take raw · auth prereqs · RIFE retire rationale
509│ └─ docs/seamless-video-loop.md # non-looping AI video clip → seamless loop: flow-matched cut + RIFE seam bridge
510
511├─ CURATION ── "human/agent picks, edits, and downloads via the webview"
512│ └─ docs/curation.md # webview · curation.json schema (selected/order/transforms/
513│ # deleted/clones/revision/recolor.picked) · per-state salvage ·
514│ # frame CLONES · standalone image-candidate path · finished-sheet
515│ # re-edit (unpack)
516
517├─ COLOURWAYS ── "bake N palette-swapped sheets from one base atlas"
518│ └─ docs/recolor.md # recolor / recolor-palette CLI · spec + report schema · exact vs
519│ # tolerance match · variants/ layout · curation blink-compare + adopt
520
521├─ LAYER TRACKS ── "compose rows onto each other instead of generating every combination"
522│ └─ docs/layer-tracks.md # rig profiles + integer landmarks · track kinds (base /
523│ # action_overlay / prop_effect / full_body_override) ·
524│ # composite stack · manifest rig block · layers/ artifact tree ·
525│ # compose-layers CLI + prepare 의 레이어 키 반입/드롭 고지
526
527├─ ENGINE EXPORT ── "adapt one composed atlas to existing game-engine loaders"
528│ └─ docs/engine-export.md # Aseprite JSON mapping · Phaser tags · Flame per-state hash
529
530├─ SPECIALIZED INPUTS ── "not the plain animation-row path"
531│ ├─ docs/directional-anchor-workflow.md # directional / 45° anchor chains · hatch-pet locomotion
532│ └─ docs/sheet-slicing.md # multi-figure variant sheet → per-cell standing cuts (立ち絵, not rows)
533
534├─ QA ── "verify motion as motion before reporting done"
535│ ├─ docs/qa-motion.md # Motion Continuity verdict criteria (BLOCKING)
536│ └─ docs/locomotion-curation.md # motion-phase guides · manual selected cycles · clean GIF export
537
538└─ TROUBLESHOOTING ── "조용히 이상할 때 먼저 볼 표"
539 └─ docs/troubleshooting.md # 사이드카 스테일 가드/도장 경로 · 두-작성자 충돌 ·
540 # provider 무출력 행(env 위생) · 세로 스트립 전멸 · ffmpeg 500
541```
542
543Concept taxonomy (which doc owns each term, so agents don't guess):
544
545- sprite-request.json, cell, states, takes → run-contract.md §2 · states-and-frames.md
546- run_revision, state_revision, per-state salvage, curation.stale-*.json → curation.py + curation.md
547- curation.json fields (selected/order/deleted/transforms/pixels/clones/pixel_unfake/revision/recolor.picked) → curation.md
548- frame **clones** (duplicate instances, source_frame_index) → curation.md + compose consumers
549- frame_layout, manifest.json runtime contract → run-contract.md + this SKILL.md "Runtime Contract"
550- Aseprite-compatible Phaser / Flame JSON export → [docs/engine-export.md](docs/engine-export.md)
551- pixel-unfake fit, .plain.png/orig/ twins → pixel-unfake.md
552- recolor spec / report / variants/ bake + colourway adopt → recolor.md
553- rig profiles / landmarks, row track kinds, composite layers stack + layers/ bake (sprite-gen compose-layers) → [docs/layer-tracks.md](docs/layer-tracks.md) (sprite_gen/compose/layers.py validates the declaration, sprite_gen/compose/compose_layers.py bakes it)
554- webview interactions (title-drag reorder, 넣기/빼기 toggle, 2-tier card, custom data-tip tooltip, recolor blink-compare) → sprite_gen/curator/ (도메인 분할 src/*.js — 로드 순서 SSoT 는 / — + curator.css), described in curation.md + recolor.md
555
In the file
SKILL.md5,616 words
Files179
LicenceApache-2.0
Why you can read it

Nothing in a skill executes. The client loads the text and the model follows it, so a skill can be audited the way a runbook is — by reading it.

What it costs in context

Skills are not billed by the call. They are paid for in context: every token the instructions occupy is a token your code, your diff and your conversation cannot use. Here is what this one takes and when it takes it.

≈500
always loaded
The name and description, so the model knows the skill exists and when to reach for it.
530,125
on trigger
The instruction body and 178 supporting files, read only when the skill fires.
265.3%
of a 200k window
Ten skills this size would take about 2653% of the window before you open a file.
050k100k150k200k context window

530.6k tokens, estimated from the bundle at four bytes to the token, held for the rest of the session once it triggers. Heavy. Teams tend to install this one per project rather than globally, and load it only when the job comes up.

Servers bill, skills cost

A server charges by the month. A skill charges once per session, in context, and then keeps charging it for as long as the session lives.

Before and after

The same question, put to the same model twice: once as it comes, and once with these instructions loaded.

No worked example has been published for this skill yet.

Adoption
Installsnone yet
Ratingno reviews yet

The procedure it runs

The procedure has not been published here. It is in the skill’s own SKILL.md, which its author has not sent to the marketplace yet.

Prose, not code

These steps are written for a model to follow, not executed by a runtime. It can still be told to skip one, and it will say so when it does.

Servers it uses

None. This skill calls no MCP servers at all.

Everything it needs is in the instructions, so it works in a project with nothing connected — the model reads the file and changes how it works with what it can already reach.

It writes no files and reaches no network. All it changes is how the model reasons and writes.

What it asks for
Writes filesno
Network accessno

Read from the allowed-tools line of this skill’s own SKILL.md. A skill grants no permissions of its own — it can only ask for tools your client already has.

What it will not do

Every skill is narrow, and the useful ones say where they stop. These are the jobs this one is the wrong tool for.

What this skill is not for has not been published here. Nothing is implied by that: it is a section the author has not filled in.

What is in the bundle

179 files, 2122.5 kB on disk. Mostly text — the instructions the model reads — with 145 scripts in it that your client would run only if the instructions tell it to.

  • .gitleaks.toml1.7 kB
  • CHANGELOG.md2.4 kB
  • CONTRIBUTORS.md2.1 kB
  • README.es.md17.6 kB
  • README.fr.md18.7 kB
  • README.ja.md19.6 kB
  • README.ko.md17.9 kB
  • README.md14.4 kB
  • README.zh-Hans.md14.9 kB
  • SECURITY.md3.1 kB
  • SKILL.md48.2 kB
  • pyproject.toml5.4 kB
  • .github/workflows/ci.yml1.3 kB
  • docs/architecture.md23.8 kB
  • docs/chroma-alpha.md6.8 kB
  • docs/curation.md23.3 kB
  • docs/directional-anchor-workflow.md22.7 kB
  • docs/engine-export.md3.5 kB
  • docs/frame-interpolation.md5.0 kB
  • docs/gen.md8.1 kB
  • docs/layer-tracks.md27.3 kB
  • docs/locomotion-curation.md4.3 kB
  • docs/pixel-unfake.md20.3 kB
  • docs/qa-motion.md3.1 kB
  • docs/recolor.md10.1 kB
  • docs/run-contract.md44.0 kB
  • docs/seamless-video-loop.md5.4 kB
  • docs/sheet-slicing.md4.7 kB
  • docs/states-and-frames.md4.0 kB
  • docs/static-pose-recipe.md4.0 kB
  • docs/subject-profiles.md3.2 kB
  • docs/troubleshooting.md3.7 kB
  • scripts/breathe_mutation_battery.py15.6 kB
  • scripts/check_visible_magenta.py0.5 kB
  • scripts/compose_layers.py0.5 kB
  • scripts/compose_selected_cycle.py0.5 kB
  • scripts/compose_sprite_atlas.py0.5 kB
  • scripts/compose_sprite_gif.py0.5 kB
  • scripts/curation.py0.4 kB
  • scripts/export_aseprite.py0.5 kB
  • scripts/export_curated_pngs.py0.5 kB
  • scripts/extract.py0.4 kB
  • scripts/extract_sprite_row_frames.py0.5 kB
  • scripts/generate_sprite_image.py0.4 kB
  • scripts/gif_utils.py0.4 kB
  • scripts/inspect_sprite_run.py0.5 kB
  • scripts/interpolate_frames.py0.5 kB
  • scripts/measure_align_sigma.py4.8 kB
  • scripts/prepare_sprite_run.py0.5 kB
  • scripts/preview_animation.py0.5 kB
  • scripts/recolor.py0.5 kB
  • scripts/reroll_state_row.py0.5 kB
  • scripts/run_correction_loop.py0.5 kB
  • scripts/runio.py0.4 kB
  • scripts/score_sprite_run.py0.5 kB
  • scripts/serve_curation.py0.5 kB
  • scripts/slice_sheet_cells.py0.5 kB
  • scripts/unpack_atlas_run.py0.5 kB
  • scripts/validate_pr6_subject_profile.py8.4 kB
  • sprite_gen/__init__.py1.1 kB
  • sprite_gen/_deps.py2.8 kB
  • sprite_gen/_modules.py1.4 kB
  • sprite_gen/cli.py16.3 kB
  • sprite_gen/compose/__init__.py0.1 kB
  • sprite_gen/compose/compose_atlas.py17.7 kB
  • sprite_gen/compose/compose_cycle.py9.2 kB
  • sprite_gen/compose/compose_gif.py14.0 kB
  • sprite_gen/compose/compose_layers.py29.1 kB
  • sprite_gen/compose/export_aseprite.py9.7 kB
  • sprite_gen/compose/export_pngs.py6.7 kB
  • sprite_gen/compose/layers.py22.4 kB
  • sprite_gen/curate/__init__.py0.1 kB
  • sprite_gen/curate/anchor.py29.2 kB
  • sprite_gen/curate/curation.py64.5 kB
  • sprite_gen/effects/__init__.py0.1 kB
  • sprite_gen/effects/anatomy.py15.5 kB
  • sprite_gen/effects/breathe.py34.9 kB
  • sprite_gen/effects/interpolate.py14.7 kB
  • sprite_gen/effects/recolor.py19.7 kB
  • sprite_gen/effects/reroll.py7.2 kB
  • sprite_gen/frames/__init__.py0.1 kB
  • sprite_gen/frames/check_visible_magenta.py3.5 kB
  • sprite_gen/frames/cutout.py15.9 kB
  • sprite_gen/frames/extract.py174.3 kB
  • sprite_gen/frames/segment.py16.4 kB
  • sprite_gen/frames/slice_sheet.py12.7 kB
  • sprite_gen/frames/unpack_atlas.py30.0 kB
  • sprite_gen/gen/__init__.py12.4 kB
  • sprite_gen/gen/base.py5.2 kB
  • sprite_gen/gen/chroma.py5.0 kB
  • sprite_gen/gen/codex_provider.py13.5 kB
  • sprite_gen/gen/generate_image.py0.7 kB
  • sprite_gen/gen/grok_provider.py4.4 kB
  • sprite_gen/gen/prepare.py62.9 kB
  • sprite_gen/qa/__init__.py0.1 kB
  • sprite_gen/qa/correction_loop.py7.2 kB
  • sprite_gen/qa/inspect.py17.4 kB
  • sprite_gen/qa/preview.py6.4 kB
  • sprite_gen/qa/score.py7.2 kB
  • sprite_gen/serve/__init__.py0.1 kB
  • sprite_gen/serve/serve_compose.py20.0 kB
  • sprite_gen/serve/serve_curation.py88.8 kB
  • sprite_gen/spec/__init__.py0.1 kB
  • sprite_gen/spec/layout.py4.8 kB
  • sprite_gen/spec/migrate_breathe.py8.1 kB
  • sprite_gen/spec/migrate_request.py4.2 kB
  • sprite_gen/spec/runio.py25.3 kB
  • sprite_gen/spec/subject.py3.5 kB
  • sprite_gen/util/__init__.py0.1 kB
  • sprite_gen/util/gif_utils.py3.1 kB
  • tests/conftest.py1.5 kB
  • tests/test_subject_profile.py9.1 kB
  • tests/compose/test_export_aseprite.py5.0 kB
  • tests/compose/test_layer_compose.py29.4 kB
  • tests/compose/test_layer_contract.py25.8 kB
  • tests/curate/test_anchor_selection.py36.9 kB
  • tests/curate/test_curation_salvage_and_clones.py9.8 kB
  • tests/curate/test_directions.py4.7 kB
  • tests/curate/test_frame_variant.py4.2 kB
  • tests/curate/test_logical_height_contract.py8.7 kB
  • tests/curate/test_pixel_snap.py16.9 kB
  • tests/curate/test_pixel_unfake_migration.py16.7 kB
  • tests/curate/test_snap_phase_policy.py4.8 kB
  • tests/effects/test_breathe.py46.1 kB
  • tests/effects/test_breathe_anatomy_route.py18.1 kB
  • tests/effects/test_breathe_js_mirror.py25.3 kB
  • tests/effects/test_breathe_off_state.py47.8 kB
  • tests/effects/test_breathe_reference_key.py33.6 kB
  • tests/effects/test_breathe_sidecar_roundtrip.py17.4 kB
  • tests/effects/test_frame_interpolation.py6.6 kB
  • tests/effects/test_palette_post_only.py4.5 kB
  • tests/effects/test_recolor_bake.py7.2 kB
  • tests/effects/test_recolor_docs.py4.9 kB
  • tests/fixtures/expected-frames-manifest.json2.7 kB
  • tests/fixtures/expected-fused-frames-manifest.json2.1 kB
  • tests/fixtures/generate_fixtures.py4.0 kB
  • tests/frames/test_alpha_centroid_align.py4.0 kB
  • tests/frames/test_cutout.py5.9 kB
  • tests/frames/test_extract_perf_equivalence.py16.2 kB
  • tests/frames/test_extraction_golden.py2.6 kB
  • tests/frames/test_grid_record_exactness.py9.1 kB
  • tests/frames/test_heal_async.py6.9 kB
  • tests/frames/test_pitch_ground_truth.py13.5 kB
  • tests/frames/test_pitch_runlen_crosscheck.py9.1 kB
  • tests/frames/test_posix_manifest_paths.py0.9 kB
  • tests/frames/test_row_placement_align_y.py2.2 kB
  • tests/frames/test_segment_projection.py8.3 kB
  • tests/frames/test_slice_sheet.py4.4 kB
  • tests/frames/test_sliver_guard.py3.9 kB
  • tests/frames/test_takes_heal.py13.2 kB
  • tests/frames/test_taxonomy_layout.py4.0 kB
  • tests/gen/test_chroma_extraction.py16.2 kB
  • tests/gen/test_chroma_key_auto.py9.5 kB
  • tests/gen/test_chroma_rcb_byte_identity.py75.5 kB
  • tests/gen/test_chroma_soft_alpha.py9.4 kB
  • tests/gen/test_chroma_ycbcr.py9.1 kB
  • tests/gen/test_codex_rollout_resolution.py6.7 kB
  • tests/gen/test_gen.py22.0 kB
  • tests/packaging/test_curation_asset_packaging.py10.2 kB
  • tests/packaging/test_curation_cli_entrypoint.py3.2 kB
  • tests/packaging/test_entrypoint_interpreter.py3.8 kB
  • tests/packaging/test_layer_cli_entrypoint.py2.0 kB
  • tests/packaging/test_numpy_dependency_gate.py8.6 kB
  • tests/packaging/test_package_surface.py5.1 kB
  • tests/packaging/test_pipeline_smoke.py28.3 kB
  • tests/packaging/test_project_metadata.py1.6 kB
  • tests/packaging/test_recolor_cli_entrypoint.py1.7 kB
  • tests/packaging/test_version_ssot.py0.8 kB
  • tests/qa/test_inspect_score_loop.py5.3 kB
  • tests/serve/test_curation_view_contract.py30.2 kB
  • tests/serve/test_curator_pixel_scaling_ssot.py14.2 kB
  • tests/serve/test_curator_single_display_pipeline.py7.2 kB
  • tests/serve/test_pixel_grid_always_available.py5.4 kB
  • tests/serve/test_recolor_curation_view.py11.5 kB
  • tests/spec/test_migrate_breathe.py5.6 kB
  • tests/spec/test_publish_rwlock_cross_process.py3.6 kB
  • tests/spec/test_request_read_no_mutation.py8.9 kB
  • tests/spec/test_request_write_isolation.py11.9 kB
  • tests/spec/test_runio_publish_set.py2.3 kB
What is not in it

A skill installs nothing and depends on nothing: it is a folder your client reads. This one carries 145 scripts beside the text, so the bundle is 179 files you can review in full before installing. The Apache-2.0 licence covers the templates and examples as well as the instructions.

Install

Installing copies the bundle into your project. Nothing runs at install time — the files sit on disk until the model reads them.

$19 once
Sprite Gen · Apache-2.0 · aldegad
one-time
Price$19 once
LicenceApache-2.0 — the author’s, unchanged by this purchase
Paid throughStripe, once, on the card you add at the checkout
Keeps workingfor good — the files are yours once they are on disk
Updatesevery release of 1.x through this account

You can read the whole bundle before paying — the SKILL.md above is the product, not a preview of it. What the money buys is the delivery: the folder packaged and handed to your machine by key, every update its author ships, and our support if it does not do what this listing says. The terms of use are Apache-2.0, set by the author and unchanged by buying it here.

Payment runs through Stripe, on a page like this one rather than a redirect. Once there is an account it joins the same mcprush invoice as everything else you run, so there is never a second card to enter.

Which clients pick it up on their own

A skill is a folder of text. A client with a skills folder reads it without being told; everywhere else the same text works, it is just handed to the model rather than found.

Claude Code.claude/skills/
Claude Desktop
ChatGPT
Cursor.cursor/skills/
VS Code.github/skills/
Codex CLI.agents/skills/
Gemini CLI.gemini/skills/
Grok.grok/skills/
Zed.agents/skills/
Windsurf.windsurf/skills/
Agent SDK.claude/skills/
HTTP / API
This release
Version1.59.0
Publishedno release date on file
Price$19
Referencealdegad/sprite-gen

Versions

v1.59.0 is what is on the shelf; no release here carries a date. Instructions change more often than APIs do — a skill can be rewritten entirely without anything it depends on moving.

v1.59.0
  • No earlier releases have been published to the marketplace.
Pinning

Put aldegad/sprite-gen@1.59.0 in the install command to hold this exact version. Without the suffix you get whatever is current the day you install, and nothing moves under you afterwards.

Reviews

no reviews yet · no installs yet

Nobody has reviewed this skill yet. The rating is the mean of the reviews written here, so there is none until somebody writes the first.

Who can post

Only accounts that have had the skill installed for fourteen days, so a review is written after living with it rather than after reading it. Publishers may reply once.

Who wrote it

AL
aldegad

Publishes on mcprush.

0 servers listed1 skill listednot claimed
Profile
Publisher
Servers0