Codex-native skills for generating Codogotchi pets from a seed image, text description, or existing Codex sheet.
Analogous to the openai/skills/.curated/hatch-pet skill, adapted for Codogotchi's three-tier spritesheet system and Codogotchi-specific state vocabulary.
Publish your pet: once you have a Codex + Lite-Basic pet (the gallery's minimum bar), share it on the Codogotchi pet gallery — sign in at
/upload, and others install it withnpx codogotchi add <id>. Uploads are server-validated and re-packed, so the package you generate here is the package the gallery distributes.
This plugin is run by Codex in two explicit stages, and it stops before keying:
- Built-in image generation stage: Codex uses its built-in
image_gentool to generate one full animation row per call as 8 invisible equal-size slots, 4 across and 2 down (8 filled slots, no empty slot), on the single flat chroma key chosen for this pet (see Chroma below). The prompt says "slots," never "grid/cells," so the model paints one continuous flat field instead of 8 separate cards with per-cell backdrops.prepare_pet_run.pyalso emits a reference-onlylayout-guide.png(a 4×2 placeholder with slot boundaries, blue safe-margins, and centering crosshairs) that is attached to every call — it carries placement/centering/safe-margins as a picture, which is what keeps the character from clipping the edge.image_gencannot hit an exact canvas size, so the overall size is nominal. The output is ephemeral — there is no save path to hunt for; it is piped straight into the next stage. - Local assembly stage:
slice_grid.pyslices the 4×2 grid (dimension-tolerant — any input size), shares one scale across all 8 frames, and emits the exact canonical1536×208row strip;compose_atlas.pystacks the strips into a magenta-background atlas; then slim QA runs.
The plugin does not mean "ask image generation for the whole atlas at once." The default workflow is grid-first:
image_gen 4×2 grid (any size, flat #FF00FF) → slice_grid.py (→ exact 1536×208 strip) → compose_atlas.py → validate_atlas.py → make_contact_sheet.py → render_animation_previews.py → pre_install_qa_gate.py → hand off to the user for keying
Why grid-first. image_gen cannot be made to honor an 8:1 aspect ratio — strips came back at wildly varying sizes and some rows (git-ops, web-search) clipped. A 4×2 grid sits near a friendly ratio, so it generates clean every time, and slice_grid.py makes the exact strip deterministically. The skill also prescribes no save path: image_gen cannot reliably store or re-find what it generates, so the skill names no directories — scripts own their I/O and the model just chains ephemeral output forward. And the model must not screenshot or eyeball its own output (it can't reliably see its own framing, and it wastes tokens); geometry is enforced by slice_grid.py and visual review is the human's on the contact sheet.
Keying is intentionally not done here. After three days of trying to get an agent to chroma-key reliably (greenish eyes, a green checkmark prop, edge spill), the pipeline leaves the background flat-keyed end-to-end and hands the finished atlas to the user to key in Codogotchi Studio — a purpose-built tool whose tolerance / edge / spill / hue controls separate green props from the magenta key far better than an agent can. The pipeline's deliverable is a magenta-background (pre-key) atlas; the user keys it and installs the transparent result.
Non-negotiable row gate: one row at a time — generate grid → slice_grid.py — before starting the next. If a grid comes back clipped, cramped, or off-model, regenerate the whole grid instead of patching forward. Do not compose an atlas until every row strip exists. Style, prop clarity, face/eye integrity, scale, and stable motion are reviewed by the human on the script-produced contact sheet after composing — the model does not eyeball its own output.
Recommended production pattern: ask image_gen for the minimum number of distinct keyframes needed for a readable, non-static loop within the 4×2 grid, reusing/mirroring earlier stable frames to close the loop when that still looks good in motion. This is a speed optimization, not a hard rule.
Caveats:
- Use it only when the row still reads clearly at a glance and the prop remains obvious in every frame.
- Do not use mirrored/reused closures if they create visible popping, robotic timing, or "cheap" looking loops.
- Some rows need more unique motion than others; ask for extra distinct frames whenever the row's action or emotion demands it.
- Validation does not judge motion quality; eyeball the contact sheet and previews.
Stability over expressiveness — the paramount rule for standing/status rows. A calm pet with small, smooth motion always beats an expressive one that jitters. When the two conflict, choose stability. Any large or whole-body motion you describe comes back inconsistent between frames — legs swing, props teleport, the pet hops. A mild, stable loop is the goal for standing/status rows; expressiveness is a distant second.
- Anchor the body. Torso, head position, hips, and both feet stay in nearly the same place across all 8 frames. In standing rows the legs do not walk, swing, or restage — feet stay planted in the same stance on the baseline.
- Move one thing at a time. Confine motion to a single element — the named prop, one arm/hand, or the eyes/expression — plus at most a gentle ≤few-px bob. Avoid simultaneous whole-body motion; that is what reads as erratic once the frames are rendered separately.
- Low amplitude, short smooth arcs. Gestures are gentle and small; a prop travels a little and consistently, never roaming around the cell between frames. Big described motions (punch, leap, big swing) become popping when each frame is independent — keep arcs short and the change between adjacent frames small.
- "No static rows" is a floor, not a target. The floor is subtle, smooth life — a breath, a small sway, blinking eyes, one quiet prop beat — just enough that the 8 frames differ. It is not a push toward big motion. A barely-moving-but-stable row passes; a busy-but-jittery row is a reject.
Locomotion carve-out. Mouse interaction rows such as Codex running-right and running-left are not standing/status loops. They use a fluid run-in-place stride cycle: preserve identity, scale, baseline, and facing, keep the character horizontally centered (no marching across the cell — lateral travel risks clipping the edge), and make all 8 frames distinct, evenly-spaced phases of one stride that flow smoothly — no clusters of near-identical frames and no teleport jump. Motion is mostly the legs cycling plus light arm swing. Frame 8 returns cleanly to frame 1.
Alignment specifics (these serve the rule above):
- Stable horizontal axis: for standing/status rows, horizontally center the character/content in every cell so the pet does not hop left/right during playback. For locomotion rows, keep the character centered and judge the in-place stride cycle: scale, baseline, and facing stay stable while all 8 frames flow as distinct, even phases.
- Stable bottom baseline: vertically align frames to a shared foot/ground baseline near the bottom of the cell, normally
y = cell_h - 8 - scaled_h. Do not vertically center ordinary standing rows; that makes the pet float too far above the badge/panel. - Validation guard:
validate_atlas.pygates dimensions, grid integrity, and static-row detection (RGB-based). On a pre-key sheet the background is an opaque key, not transparency, so there is no per-frame alpha to measure geometry from — scale and horizontal-alignment are eyeball checks on the contact sheet and previews. - Jump exception: explicit jump/leap rows (Codex
jumping, SoAticket-completed) are one full jump cycle across all 8 distinct frames (crouch → push-off → rise → airborne peak → descend → land → settle) — no standing/idle filler frames. Give real vertical clearance (feet clearly airborne at the peak, ~24–40 px off baseline — a genuine single bounce, not a ≤ 12 px shin-high hover that reads as floating), stay horizontally centered, raise the arms into a gesture that stays below full overhead extension (so hands don't clip the top), and take off and land cleanly on a stable horizontal axis — controlled, not flailing.
One flat key for the whole pet, auto-selected per pet. prepare_pet_run.py picks ONE chroma for the entire pet (every row of every tier shares it — Studio keys each sheet uniformly): with a seed it auto-selects the canonical key (magenta #FF00FF, blue #0047BB, or green #00B140) farthest from the pet's own palette; with no seed (or --chroma magenta) it falls back to magenta. There is no per-row key selection. Because the props are now fed programmatically, the reserved accent colors recolor to avoid whatever key wins: the success ✓/stamp/banner (default green) flips to blue under a green key, and the dead-state ghost (default ethereal blue) flips to warm rose under a blue key — so a pink/magenta pet can take a clean green or blue key without ever keying out an intentional detail. Magenta remains the safe default and tiebreak.
The plugin does not key the sheet. Keying is delegated to the user via Codogotchi Studio. This is deliberate: an agent cannot reliably tune a matte. Because the key is now chosen per pet and the reserved accents recolor around it, no intentional detail ever shares the background hue — the user's tool, with real tolerance/edge/spill/hue controls, exports the transparent sheet cleanly regardless of which key was selected.
What this means per surface:
- Prompts demand one perfectly flat
#FF00FFbackground (hex stated literally), with no falloff, shadow, texture, halo, or antialias spill into the key. - Green details on the character/props are fine — do not avoid green and do not switch rows like
verifying,web-search,green-tdd, orreview-cleanto another key. slice_grid.pyslices the 4×2 grid and emits the exact1536×208strip on the flat magenta key, preserving foreground colours (intentional green props included). It does not alter foreground colours.compose_atlas.pystacks the strips onto a flat magenta canvas and outputs an opaque, magenta-background atlas.
The pipeline's deliverable is a magenta-background atlas, so QA is what's honestly checkable before keying. The keying handoff is blocked until these artifacts are present and newer than the final atlas:
validate-<tier>.jsonfromvalidate_atlas.py --out-json(dimensions, grid, static-row)contact-<tier>.pngfrommake_contact_sheet.pypreviews-<tier>/*.giffromrender_animation_previews.py
python scripts/validate_atlas.py --atlas <work>/<sheet>.webp --tier <tier> --out-json <validation-json>
python scripts/make_contact_sheet.py --atlas <work>/<sheet>.webp --tier <tier>
python scripts/render_animation_previews.py --atlas <work>/<sheet>.webp --tier <tier>
python scripts/pre_install_qa_gate.py --atlas <work>/<sheet>.webp --tier <tier>Scale, alignment, prop clarity, and identity are eyeball checks on the contact sheet and previews — validate_atlas.py cannot measure them on a magenta background. After the gate passes, hand the magenta atlas to the user to key at https://codogotchi.app/studio, then install the transparent result.
Generation time varies, but full-tier delivery should look like full-tier delivery: row-by-row generation, per-row inspection, final validation, contact sheet, previews, crop QA, and pre-install gate. If a tier is completed unusually quickly, explicitly report what was compressed, reused, skipped, or waived. Script validation alone is not QA.
The lite sheet is split in two: codogotchi-lite-basic-spritesheet.webp (9 rows, incl. ghost) is the minimal "alive/ghost" tier every pet ships; codogotchi-lite-enhanced-spritesheet.webp (8 rows) is a polish extension. Dependencies: Codex is always required · Lite-Basic is required before Lite-Enhanced · SoA needs only Codex.
| Skill | Starting point | Produces |
|---|---|---|
hatch-codogotchi-codex-and-lite-basic |
nothing (seed image / description) | Codex + Lite-Basic |
hatch-codogotchi-codex-and-lite-full |
nothing (seed image / description) | Codex + Lite-Basic + Lite-Enhanced |
hatch-codogotchi-lite-basic |
existing Codex spritesheet.webp |
Lite-Basic |
hatch-codogotchi-lite-enhanced |
existing Codex + Lite-Basic | Lite-Enhanced |
hatch-codogotchi-soa |
existing Codex spritesheet.webp |
SoA |
Each skill lives at skills/<short-name>/SKILL.md (e.g. skills/codex-and-lite-basic/SKILL.md).
Do you have a Codex spritesheet.webp already?
No → want full lite? yes → hatch-codogotchi-codex-and-lite-full (Codex + Basic + Enhanced)
no → hatch-codogotchi-codex-and-lite-basic (Codex + Basic)
Yes → add Lite-Basic? → hatch-codogotchi-lite-basic
add Lite-Enhanced? → hatch-codogotchi-lite-enhanced (requires Lite-Basic first)
add SoA gates? → hatch-codogotchi-soa (needs only Codex)
Name the skill explicitly on the first line, then say what to hatch:
Use the hatch-codogotchi-codex-and-lite-basic skill.
Hatch a new Codogotchi named "Mochi" from this description: a chibi orange tabby in a tiny yellow hoodie, round head, warm pastel palette. Plush style.
Use the hatch-codogotchi-lite-basic skill.
Hatch a Codogotchi from my existing Codex pet in ~/.codex/pets/<pet-name>.
Use the hatch-codogotchi-codex-and-lite-basic skill.
Hatch a new Codogotchi named "Mochi" from this seed image.
| Tier | File | Grid | Dimensions | States |
|---|---|---|---|---|
| 1 — Codex | spritesheet.webp |
8×9 | 1536×1872 | idle, interactions, errored, fallbacks. Required. |
| 2 — Lite-Basic | codogotchi-lite-basic-spritesheet.webp |
8×9 | 1536×1872 | minimal "alive/ghost": revive, standby, thinking, reading, implementing, testing, errored, waiting, ghost |
| 3 — Lite-Enhanced | codogotchi-lite-enhanced-spritesheet.webp |
8×8 | 1536×1664 | polish: idle-impatient/-frustrated, cramming, editing, git-ops, verifying, searching, web-search. Requires Tier 2. |
| 4 — SoA | codogotchi-soa-spritesheet.webp |
8×10 | 1536×2080 | delivery gate moments (Son-of-Anton) |
All tiers: 192×208 px cell, 8 frames/row, 187.5 ms/frame, continuous loop.
Tier 1 is required. Resolution order per render moment: SoA → Enhanced → Basic → Codex. Enhanced cannot be installed without Basic.
# 0. Choose artifact paths.
# The plugin does not prescribe where image generation stores files.
# Use any local working paths and substitute them for <work>.
# 1. Prepare run with seed image (or --description "...")
python scripts/prepare_pet_run.py \
--seed <seed> --pet-name "Beemo" --style plush
# 2. Use Codex's built-in image_gen tool to generate one 4x2 grid per row.
# Use sheet-prompts/<tier>/<row>.txt. Grid = 4 cols x 2 rows of 192x208 cells,
# 8 populated, no empty cell, flat #FF00FF. image_gen need not hit an exact size;
# its output is ephemeral (no required save path).
# 3. Slice each grid into the canonical 1536x208 row strip (paths caller-chosen/ephemeral)
python scripts/slice_grid.py --input <grid> --out <row-strip>
# 4. Compose + encode (after ALL rows) → magenta-background atlas
python scripts/compose_atlas.py --rows-dir <codex-strips> --tier codex --out <work>/spritesheet.png
python scripts/compose_atlas.py --rows-dir <lite-basic-strips> --tier lite-basic --out <atlas-png>
cwebp -lossless -exact <work>/spritesheet.png -o <work>/spritesheet.webp
cwebp -lossless -exact <atlas-png> -o <atlas-webp>
# 5. Slim QA gate for each atlas (runs on the magenta-background sheet)
python scripts/validate_atlas.py --atlas <work>/spritesheet.webp --tier codex --out-json <validation-json>
python scripts/make_contact_sheet.py --atlas <work>/spritesheet.webp --tier codex
python scripts/render_animation_previews.py --atlas <work>/spritesheet.webp --tier codex
python scripts/pre_install_qa_gate.py --atlas <work>/spritesheet.webp --tier codex
python scripts/validate_atlas.py --atlas <atlas-webp> --tier lite-basic --out-json <validation-json>
python scripts/make_contact_sheet.py --atlas <atlas-webp> --tier lite-basic
python scripts/render_animation_previews.py --atlas <atlas-webp> --tier lite-basic
python scripts/pre_install_qa_gate.py --atlas <atlas-webp> --tier lite-basic
# (Optional) add the Lite-Enhanced sheet afterward — requires the Basic sheet above:
# python scripts/prepare_pet_run.py --seed <seed> --pet-id beemo --tier lite-enhanced
# …generate 4x2 grids / slice_grid / compose --tier lite-enhanced → magenta-background atlas
# 6. Write pet.json (metadata only; description defaults from pet name/style if --description was omitted)
python scripts/prepare_pet_run.py --write-pet-json --run-dir <work>/
# 7. KEY THE MAGENTA ATLASES — do NOT install them as-is.
# Direct the user to https://codogotchi.app/studio: load each magenta *.webp,
# tune the knobs, export the transparent sheet, then install the keyed result.# 1. Extract character reference from existing Codex sheet
python scripts/extract_seed_from_codex.py \
--spritesheet <existing-codex-spritesheet> \
--out <seed>
# 2. Prepare run (lite-basic, lite-enhanced, or soa)
python scripts/prepare_pet_run.py \
--seed <seed> --pet-id maew --pet-name "Maew" --tier lite-basic
# 3-5. Use built-in image_gen to generate one 4x2 grid per row, slice each with
# slice_grid.py, compose the magenta-background atlas, pass the slim QA gate (same pipeline).
# lite-enhanced is a separate run and REQUIRES the lite-basic sheet to exist first.
# 6. Key the magenta atlas at https://codogotchi.app/studio, then install the transparent
# result; don't overwrite spritesheet.webp or pet.json.hatch-codogotchi/
README.md ← this file
skills/
codex-and-lite-basic/SKILL.md ← new pet: Codex + Lite-Basic from scratch
codex-and-lite-full/SKILL.md ← new pet: Codex + Lite-Basic + Lite-Enhanced
lite-basic/SKILL.md ← existing Codex pet: add Lite-Basic
lite-enhanced/SKILL.md ← existing Codex + Basic pet: add Lite-Enhanced
soa/SKILL.md ← existing Codex pet: add SoA
references/
animation-rows-codex.md ← Codex row specs and motion descriptions
animation-rows-lite.md ← Lite-Basic + Lite-Enhanced row specs, props
animation-rows-soa.md ← SoA row specs and motion descriptions
codogotchi-pet-contract.md ← Pet package contract (files, schema, loading)
qa-rubric.md ← QA checklist (automated + eyeball)
scripts/
extract_seed_from_codex.py ← Extract reference cell from existing spritesheet
prepare_pet_run.py ← Bootstrap run folder + 4x2 grid prompts + manifest
slice_grid.py ← Slice a generated 4x2 grid (any size) → exact 1536x208 row strip
compose_atlas.py ← Stack magenta-background row strips → atlas PNG
validate_atlas.py ← Slim validation (dimensions, grid, static-row)
make_contact_sheet.py ← Generate labelled QA contact sheet
render_animation_previews.py ← Generate animated GIF previews per row
pre_install_qa_gate.py ← Block keying handoff unless QA artifacts are fresh
chroma_palette.py ← Shared chroma helpers (extract_seed_from_codex)
Keying is not in this list — it is done by the user in Codogotchi Studio after the pipeline delivers the magenta-background atlas.
-
Faking frames by transforming the seed — Do not crop/warp/rotate/scale/re-composite a seed. Every frame in the strip must be a genuine render in that pose.
-
Rushing the whole atlas in one pass — One row at a time, grid-first: generate a single 4×2 grid →
slice_grid.py→ exact1536×208strip → repeat for the next row → only then compose the atlas. -
Clipped frames — The format is one 4×2 grid of 8 cells at 192×208 each, no empty cell, on flat
#FF00FF, at any overall size. Requesting a single wide 8×1 strip is what caused clipping — never do it; the 4×2 grid is the fix.slice_grid.pytolerates any input size and snaps to the exact strip, so do not distort the character to hit a dimension. If any foreground crosses a cell boundary, regenerate the grid. Generate one grid per row; never the whole atlas at once. -
Style drift from the Codex sheet (Lite and SoA only) — Compare every row against the existing Codex cells. Same character, same palette, same linework.
-
Jerky / over-animated motion (the stability killer) — The single worst outcome, and invisible to the scripts. For standing/status rows, stability beats expressiveness every time — anchor the body and both feet, move one element at low amplitude, keep frame-to-frame change small. For locomotion rows, require a fluid in-place stride cycle: centered (no lateral travel), stable scale/baseline/direction, all 8 frames distinct and evenly spaced, no static-then-jump. "No static rows" is a floor, not a target. Eyeball the contact sheet and previews. See Motion & alignment doctrine above.
-
Mime / charades (the readability killer) — Codogotchi animations must be readable at a glance. States that don't map to a plain human emotion must be carried by one clearly-visible prop, never subtle hand gestures or an invisible prop ("invisible keyboard", "unseen screen"). Use exactly the prop named — never an A/B choice. Same prop, all 8 frames. See
references/animation-rows-lite.md→ prop doctrine. -
Per-frame scale drift — A cell whose character is noticeably larger/smaller than its rowmates. Ask
image_genfor one shared head height / body scale across the grid;slice_grid.pyalso shares one scale across the row when it builds the strip. On a pre-key sheet this can't be measured automatically (the opaque key background leaves no alpha to measure), so the human reviews the contact sheet; if a cell is off, regenerate the whole grid. -
Horizontal alignment drift — The pet must not hop left/right inside the frame. Eyeball the contact sheet / previews and confirm the character body stays on a stable x-axis.
-
Vertical float from center alignment — Ordinary standing rows should use a shared bottom baseline near
cell_h - 8, not vertical centering. Centering the full bbox vertically can make the pet hover too far above theAnimationBadgePanel. Jump/leap rows are the exception, and they must visibly take off (real clearance — ~24–40 px airborne at the peak, not a shin-high hover) and land cleanly, with all 8 frames a distinct phase of one bounce (no standing filler frames). -
Character identity drift — After every grid, compare against the seed artifact and verify the same age/proportions, hair silhouette, dress/outfit, sandals/accessories, palette, and linework. This is a human review on the contact sheet — there is no automated identity gate.
If any cell in a row fails QA (off pose, scale drift, weak prop, identity drift, jitter), regenerate the whole 4×2 grid for that row using its prompt, re-run slice_grid.py, and re-run the QA scripts. Fix by regenerating the grid, never by editing individual cells.
validate_atlas.pyonly catches dimensions, grid, and pixel-identical static rows. Everything perceptual — motion quality (#5), props (#6), scale (#7), alignment (#8), baseline (#9), identity (#10) — is an eyeball pass on the contact sheet and previews. Keying quality (edges, green-prop separation) is the user's job in Codogotchi Studio.
notes/private/byo-lite-and-soa-spritesheet-spec.md— canonical artist BYO specnotes/private/codogotchi-8frame-lite-soa-sheet-prompts.md— ready-to-paste image-gen prompts (PROMPT 1 = Lite, PROMPT 2 = SoA)notes/private/spritesheet-animation-swap-canonical-prompt.md— Modes A/B deep-dive
openai/skills/.curated/hatch-pet— the original skill this adapts from