/sprite-gen
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
$ npx -y skills add aldegad/sprite-gen --skill sprite-gen --agent claude-codeHow it fires
How this skill gets triggered: by you, by Claude, or both.
- Fires itselfAuto-invocation. Claude auto-loads it when your prompt matches the work.Auto-invocation is when the right skill fires by itself at the right moment, driven by a FLOW.md router and a hook, instead of you invoking it by name. It is the difference between a skill being installed and a skill actually getting used.Read the full definition →
- You can call itInvoke it directly when you want it.
- Slash command
/sprite-gen
Context preview
The summary Claude sees to decide when to auto-load this skill.
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
SKILL.md
sprite-gen.SKILL.mdname: sprite-gen
version: 1.58.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. Deterministic palette-swap bake (`sprite-gen recolor` / `recolor-palette`) turns one base sheet + a palette map into N colourway sheets in one command; 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-rowSprite Gen
`sprite-gen` builds generic game sprite atlases with a `component-row` pipeline:
sprite-request.json -> layout guides + prompts -> image-gen state rows
-> chroma alpha -> connected components -> transparent cells
-> sprite-sheet-alpha.png + manifest.json.frame_layout
Use 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.
필수 게이트 — AI raw 는 최종 에셋이 아니다 (BLOCKING)
이 스킬의 모든 산출물은 아래 체크리스트를 통과해야 한다. 하나라도 어기면 그 결과물은 실패로 보고한다:
- [ ] **AI 개입은 raw 생성 한 곳뿐이다.** `raw/<state>.png` 는 중간 산출물이며, 최종 에셋은 반드시 결정론 변환 — `extract_sprite_row_frames.py`(크로마 제거 → 컴포넌트 분리 → 피치 검출/그리드 스냅 → kCentroid → 공유 팔레트 → 셀 배치) — 를 거친다. 같은 입력이면 항상 같은 출력이 나오는 코드 경로만 픽셀 언페이크다.
- [ ] **단순 다운스케일 쇼트컷 금지.** raw 를 PIL `resize()` 한 줄로 줄여 최종 경로에 놓는 것은 픽셀 언페이크 변환이 아니다 — AA 가장자리 열화와 그리드 미정렬이 그대로 남는다. "이번 한 번만 빠르게" 도 금지. 파이프라인 없이 낱장만 변환할 때도 run dir 를 만들어 같은 추출 경로를 태운다.
- [ ] **베이스/앵커가 스타일 SSoT 다 — 도트 런이면 베이스부터 진짜 도트여야 한다.** 조립되는
프롬프트의 `Style contract:` 기본값은 "첨부한 베이스/앵커 레퍼런스를 그대로 따라라"이고, 이미지 모델은 첨부 레퍼런스를 프롬프트 텍스트보다 강하게 따른다. 그래서 `fit.pixel_unfake` 런에 AA/벡터풍 베이스를 붙이면 프롬프트에 "TRUE 32x32 pixel art" 를 적어도 raw 가 도트로 나오지 않는다 (실사고 2026-07-29 gptaku 아이콘: AA 블롭 베이스 → 비도트 raw → 추출 피치 x/y 불균일(10.5/9.7) → 실루엣 눌림 반려 3회). 잠금 전에 베이스에서 **픽셀 격자가 실측으로 검출되는지**(균일 블록 피치, AA 반투명 가장자리 없음) 확인하고, 아니면 베이스부터 다시 만든다. 프롬프트 문구로 베이스의 스타일을 이기려 하지 마라.
- [ ] **크로마 키는 소재색을 먼저 보고 고른다.** 핑크/보라/자주 소재 → 그린 `#00FF00`, 녹색/청록 식물 → 마젠타 `#FF00FF`. 분기표 SSoT 는 image-gen SKILL.md 최상단 게이트 (상세는 [`docs/chroma-alpha.md`](docs/chroma-alpha.md)).
- [ ] **변환 후 소재색 보존을 검증한다.** 꽃이 희게 탈색됐거나 주요 색이 빠졌으면 키 선택이 소재와 충돌한 것이다 — 로컬 보정이 아니라 키를 바꿔 재생성한다.
리네임 게이트 — 어휘/키를 바꿀 때 (BLOCKING)
스키마 키·식별자·라벨을 걸쳐 어휘를 바꾸는 작업(`pixel_perfect` → `pixel_unfake` 류)은 **일괄 치환으로 시작하지 않는다**. 치환은 이름을 바꾸지만 계약은 **층위**로 존재한다:
식별자 → 키 문자열 → 사용자 라벨(en+ko) → 문서 예제 → --help 문구 → 테스트 하니스
순서가 정해져 있다 (실사고 2026-07-25/26, plan `sprite-gen/pixel-unfake-rename` — 이 순서를 거꾸로 해서 검증자 리젝트 3라운드가 났다):
- [ ] **구조 단정을 스윕보다 먼저 쓴다.** 판독 SSoT(게이트) 밖에서 그 파일/키를 읽는 프로덕션
경로가 있으면 실패하는 테스트. **정규식이 아니라 AST** 로 — 실제 회귀 형태는 보통 두 줄(경로를 변수에 담고 다음 줄에서 읽기)이라 한 줄 정규식은 못 잡는다 (`tests/test_pixel_unfake_migration.py` 마지막 케이스가 그 형태).
- [ ] **그 단정을 mutant 로 검증한다.** 옛 형태를 일부러 되돌려 실제로 실패하는지 본다. 통과만
하는 단정은 장식이고, 그걸 근거로 "구조로 닫았다" 고 말하면 거짓 보고가 된다.
- [ ] **판독부는 키 이름만 바꾸지 않고 게이트 뒤로 옮긴다.** 이관 전 데이터에서 그 판독부만
조용히 틀린 답을 본다 (실측: 리롤이 "언페이크가 꺼져 있다" 며 거짓 거부).
- [ ] **구분자가 바뀌는 치환은 토큰 단위로.** `pixel-perfect` → `pixel unfake` 처럼 하이픈이
공백이 되는 치환은 argparse 옵션·경로·식별자를 깨뜨린다 (실측: `--fit-pixel unfake` 유령 옵션 등록 + 은퇴 안내문이 현행 플래그를 은퇴했다고 말하는 자기모순).
- [ ] **은퇴 이름은 조용한 별칭으로 남기지 않는다.** 새 이름을 안내하며 hard error. 그 안내
문구 자체는 치환 대상에서 제외한다.
- [ ] **순수 리네임 주장은 골든 회귀로 증명한다.** 리네임 전/후 산출물이 바이트 동일한지.
Base Lock Gate (Stage 0, BLOCKING)
Identity ownership in the row pipeline:
identity truth = accepted idle anchor
motion truth = layout guide + paired/basis row when needed
base truth = used only to create idle anchors, then removed from row inputs
The 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.
A 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`:
> Is there an image good enough to **lock** as the canonical base idle?
The base idle locks only when **all** of these hold:
- Full body, nothing cropped (head to feet inside frame).
- 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.
- For a pixel-art run (`fi
Read more
name: sprite-gen
version: 1.58.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. Deterministic palette-swap bake (`sprite-gen recolor` / `recolor-palette`) turns one base sheet + a palette map into N colourway sheets in one command; 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-rowSprite Gen
`sprite-gen` builds generic game sprite atlases with a `component-row` pipeline:
sprite-request.json -> layout guides + prompts -> image-gen state rows -> chroma alpha -> connected components -> transparent cells -> sprite-sheet-alpha.png + manifest.json.frame_layout
Use 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.
필수 게이트 — AI raw 는 최종 에셋이 아니다 (BLOCKING)
이 스킬의 모든 산출물은 아래 체크리스트를 통과해야 한다. 하나라도 어기면 그 결과물은 실패로 보고한다:
- [ ] **AI 개입은 raw 생성 한 곳뿐이다.** `raw/<state>.png` 는 중간 산출물이며, 최종 에셋은 반드시 결정론 변환 — `extract_sprite_row_frames.py`(크로마 제거 → 컴포넌트 분리 → 피치 검출/그리드 스냅 → kCentroid → 공유 팔레트 → 셀 배치) — 를 거친다. 같은 입력이면 항상 같은 출력이 나오는 코드 경로만 픽셀 언페이크다.
- [ ] **단순 다운스케일 쇼트컷 금지.** raw 를 PIL `resize()` 한 줄로 줄여 최종 경로에 놓는 것은 픽셀 언페이크 변환이 아니다 — AA 가장자리 열화와 그리드 미정렬이 그대로 남는다. "이번 한 번만 빠르게" 도 금지. 파이프라인 없이 낱장만 변환할 때도 run dir 를 만들어 같은 추출 경로를 태운다.
- [ ] **베이스/앵커가 스타일 SSoT 다 — 도트 런이면 베이스부터 진짜 도트여야 한다.** 조립되는
프롬프트의 `Style contract:` 기본값은 "첨부한 베이스/앵커 레퍼런스를 그대로 따라라"이고, 이미지 모델은 첨부 레퍼런스를 프롬프트 텍스트보다 강하게 따른다. 그래서 `fit.pixel_unfake` 런에 AA/벡터풍 베이스를 붙이면 프롬프트에 "TRUE 32x32 pixel art" 를 적어도 raw 가 도트로 나오지 않는다 (실사고 2026-07-29 gptaku 아이콘: AA 블롭 베이스 → 비도트 raw → 추출 피치 x/y 불균일(10.5/9.7) → 실루엣 눌림 반려 3회). 잠금 전에 베이스에서 **픽셀 격자가 실측으로 검출되는지**(균일 블록 피치, AA 반투명 가장자리 없음) 확인하고, 아니면 베이스부터 다시 만든다. 프롬프트 문구로 베이스의 스타일을 이기려 하지 마라.
- [ ] **크로마 키는 소재색을 먼저 보고 고른다.** 핑크/보라/자주 소재 → 그린 `#00FF00`, 녹색/청록 식물 → 마젠타 `#FF00FF`. 분기표 SSoT 는 image-gen SKILL.md 최상단 게이트 (상세는 [`docs/chroma-alpha.md`](docs/chroma-alpha.md)).
- [ ] **변환 후 소재색 보존을 검증한다.** 꽃이 희게 탈색됐거나 주요 색이 빠졌으면 키 선택이 소재와 충돌한 것이다 — 로컬 보정이 아니라 키를 바꿔 재생성한다.
리네임 게이트 — 어휘/키를 바꿀 때 (BLOCKING)
스키마 키·식별자·라벨을 걸쳐 어휘를 바꾸는 작업(`pixel_perfect` → `pixel_unfake` 류)은 **일괄 치환으로 시작하지 않는다**. 치환은 이름을 바꾸지만 계약은 **층위**로 존재한다:
식별자 → 키 문자열 → 사용자 라벨(en+ko) → 문서 예제 → --help 문구 → 테스트 하니스
순서가 정해져 있다 (실사고 2026-07-25/26, plan `sprite-gen/pixel-unfake-rename` — 이 순서를 거꾸로 해서 검증자 리젝트 3라운드가 났다):
- [ ] **구조 단정을 스윕보다 먼저 쓴다.** 판독 SSoT(게이트) 밖에서 그 파일/키를 읽는 프로덕션
경로가 있으면 실패하는 테스트. **정규식이 아니라 AST** 로 — 실제 회귀 형태는 보통 두 줄(경로를 변수에 담고 다음 줄에서 읽기)이라 한 줄 정규식은 못 잡는다 (`tests/test_pixel_unfake_migration.py` 마지막 케이스가 그 형태).
- [ ] **그 단정을 mutant 로 검증한다.** 옛 형태를 일부러 되돌려 실제로 실패하는지 본다. 통과만
하는 단정은 장식이고, 그걸 근거로 "구조로 닫았다" 고 말하면 거짓 보고가 된다.
- [ ] **판독부는 키 이름만 바꾸지 않고 게이트 뒤로 옮긴다.** 이관 전 데이터에서 그 판독부만
조용히 틀린 답을 본다 (실측: 리롤이 "언페이크가 꺼져 있다" 며 거짓 거부).
- [ ] **구분자가 바뀌는 치환은 토큰 단위로.** `pixel-perfect` → `pixel unfake` 처럼 하이픈이
공백이 되는 치환은 argparse 옵션·경로·식별자를 깨뜨린다 (실측: `--fit-pixel unfake` 유령 옵션 등록 + 은퇴 안내문이 현행 플래그를 은퇴했다고 말하는 자기모순).
- [ ] **은퇴 이름은 조용한 별칭으로 남기지 않는다.** 새 이름을 안내하며 hard error. 그 안내
문구 자체는 치환 대상에서 제외한다.
- [ ] **순수 리네임 주장은 골든 회귀로 증명한다.** 리네임 전/후 산출물이 바이트 동일한지.
Base Lock Gate (Stage 0, BLOCKING)
Identity ownership in the row pipeline:
identity truth = accepted idle anchor motion truth = layout guide + paired/basis row when needed base truth = used only to create idle anchors, then removed from row inputs
The 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.
A 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`:
> Is there an image good enough to **lock** as the canonical base idle?
The base idle locks only when **all** of these hold:
- Full body, nothing cropped (head to feet inside frame).
- 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.
- For a pixel-art run (`fi
Generate clean 2D game sprites & animation atlases — component-row pipeline: state rows, alpha cleanup, frame extraction, runtime atlases. Codex/Claude skill.

