creating-sprites
Creating Sprites
Generate pixel-art game sprites via OpenAI's gpt-image-1.5 model with native transparent background support, then process them into game-ready assets with correct dimensions and proper anchoring.
Reference Files
| File | Read When |
|---|---|
references/sprite-sizes.md |
Choosing target size, generation size, crop mode, or fake pixel math for a sprite type |
references/prompt-guide.md |
Constructing or refining a generation prompt, choosing style keywords, or writing per-type prompts |
references/troubleshooting.md |
A generation fails, transparency check fails, style doesn't match, or API returns errors |
Prerequisites
OPENAI_API_KEY— an OpenAI API key- The generate script auto-loads from:
--api-keyflag →OPENAI_API_KEYenv var →.envfile in current directory
- The generate script auto-loads from:
- Python dependencies:
openaiandPillow(installed viarequirements.txtin the skill'sscripts/directory)
Script Paths
All scripts/ paths in this skill are relative to the skill directory, not the project directory. Resolve them to absolute paths before running. For example, if the skill is installed at ~/.claude/skills/creating-sprites/, then scripts/generate_sprite.py means ~/.claude/skills/creating-sprites/scripts/generate_sprite.py.
Workflow Checklist
- [ ] Phase 0: Verify prerequisites
- [ ] Phase 1: Determine sprite requirements
- [ ] Phase 2: Prepare reference images
- [ ] Phase 3: Construct prompt
- [ ] Phase 4: Generate candidates
- [ ] Phase 5: Validate candidates
- [ ] Phase 6: Process chosen sprite
- [ ] Phase 7: Save and update plan
Phase 0: Verify Prerequisites
Before doing any work, verify the environment is ready. Handle what you can; only ask the user for things you can't resolve yourself.
-
Check API key — check all three sources:
python -c " import os from pathlib import Path key = os.environ.get('OPENAI_API_KEY', '') if not key: env = Path('.env') if env.exists(): for line in env.read_text().splitlines(): if line.strip().startswith('OPENAI_API_KEY'): key = line.partition('=')[2].strip().strip('\"').strip(\"'\") print('OK' if key else 'MISSING') "- If
MISSING: ask the user to addOPENAI_API_KEY=their-keyto a.envfile in the project root, or export it as an environment variable - Do NOT proceed past this phase without a valid key
- If
-
Install Python dependencies (do this yourself, don't ask the user):
pip install -r <skill-dir>/scripts/requirements.txt
Only the API key requires user action. Everything else you should handle yourself.
Phase 1: Determine Sprite Requirements
Identify what to create and look up its parameters.
- Determine the entity type: item, enemy, decoration, structure, UI icon, player, pet, animal, boss, terrain tile
- Read
references/sprite-sizes.mdfor common size examples, generation size, and crop mode — use these as a starting point and adjust based on the specific entity - Record these values:
target_widthandtarget_height(e.g., 32x32)generation_size(1024x1024 default)crop_mode(bottom-anchor, center, or none)
- Identify the destination path in the project for the final sprite
- Identify 1-3 existing sprites that could serve as style references
Phase 2: Prepare Reference Images
Existing sprites are tiny and must be upscaled for the AI model to interpret them. Reference images are passed directly to the API via --reference flags for style matching.
For each reference sprite, run:
python scripts/upscale_reference.py --input path/to/sprite.png --output temp/sprite_upscaled.png
The script auto-calculates the best integer multiplier to reach 500-1024px using nearest-neighbor interpolation (preserves pixel crispness).
If no reference sprites exist (first sprite in the project), skip this phase. The prompt alone will define the style.
Phase 3: Construct Prompt
Read references/prompt-guide.md for the base template, style keywords, and per-type examples.
Every prompt must specify:
- Pixel-art style with era/palette keywords (derived from reference analysis in Phase 2)
- Target fake-pixel dimensions ("a 32x32 pixel art sprite")
- Transparent background (gpt-image-1.5 supports this natively)
- ONE sprite only, centered in frame
- No border, no shadow, no text, no grid
- Subject description
- Anchoring: "touching the bottom of the image" for entities, "centered" for items
- "Match the style of the provided reference images" when references are included
Phase 4: Generate and Validate (Max 3 Attempts)
You get at most 3 generation attempts per sprite. Each attempt produces 4 candidates. Never delete candidates from previous attempts — you will pick the best sprite across ALL attempts at the end.
The --name flag sets the base filename. Use a short, descriptive slug for the sprite (e.g. slime, health_potion, oak_tree). Use a versioned suffix to prevent overwrites across attempts: slime_v1, slime_v2, slime_v3.
Attempt 1 — Initial Generation
Generate with the prompt from Phase 3. The script always requests a transparent background natively, whether or not reference images are provided.
python scripts/generate_sprite.py \
--prompt "A 32x32 pixel art ..." \
--output-dir ./sprites-wip \
--reference temp/ref1_upscaled.png \
--reference temp/ref2_upscaled.png \
--count 4 \
--name slime_v1
Outputs: slime_v1_001.png through slime_v1_004.png.
Validate (run on every attempt):
-
Programmatic check — run on each candidate:
python scripts/check_transparency.py --input ./sprites-wip/slime_v1_001.pngOutput format:
FILE: slime_v1_001.png FORMAT: PNG ALPHA_CHANNEL: yes TRANSPARENT_PIXELS: 45.2% CHECKERBOARD_DETECTED: no RESULT: PASS- PASS: At least 10% transparent pixels, no checkerboard pattern
- FAIL: No alpha channel, 0% transparency, checkerboard detected, or not PNG
-
Visual inspection — use the Read tool to view each passing candidate alongside the reference images from Phase 3. Compare against the references — don't judge in isolation. A sprite can look fine on its own but still miss the intended style, proportions, or details from the references. Check: matches references? Single sprite? Correct orientation? Right proportions? Matches game style?
If any candidate passes both checks → skip to Pick the Best below.
Attempts 2 and 3 — Diagnose Then Fix
Before each retry, diagnose the failure type from previous attempts. The fix depends on the problem:
Background problems (use prompt refinement, then chromakey)
Symptoms: colored background instead of transparency, checkerboard pattern, unwanted scenery (grass, forest, inventory frame, etc.)
- Attempt 2: Strengthen transparency language in prompt: "isolated sprite on transparent background, no checkerboard pattern, actual PNG transparency, no scenery, no environment"
- Attempt 3 (if background problems persist): Switch to chromakey fallback:
- Pick a safe background color not present in the subject (see
references/troubleshooting.md) - Add to prompt: "solid flat [COLOR] background, no gradients, no patterns, no shadows"
- After generation, process with:
process_sprite.py remove-bg --chroma-color HEXCODE
- Pick a safe background color not present in the subject (see
Subject problems (use prompt refinement only — NOT chromakey)
Symptoms: wrong proportions, wrong style, multiple sprites, missing details, wrong pose/orientation — but transparency is fine.
- Attempts 2 and 3: Refine the prompt and/or adjust style keywords. See
references/troubleshooting.md. Chromakey does not help here — the problem is the subject, not the background. Keep iterating on prompt wording and style descriptions.
Mixed problems (both background and subject issues)
- Prioritize fixing the subject first (prompt refinement), since chromakey can always fix the background later
- If subject looks good by Attempt 2 but background is still wrong, use chromakey for Attempt 3
python scripts/generate_sprite.py \
--prompt "Refined prompt ..." \
--output-dir ./sprites-wip \
--count 4 \
--name slime_v2 # then slime_v3 for attempt 3
Validate the same way after each attempt.
Pick the Best (across ALL attempts)
After completing your attempts, review all candidates from every attempt — not just the latest batch. A sprite from Attempt 1 may be better than one from Attempt 3.
Use the Read tool to compare the top candidates side-by-side and against the original reference images — select the one that best matches the intended style and details from the references.
If All 3 Attempts Fail
Create a manual creation task in the implementation plan and move on. Don't block progress on one asset. Save the best attempt as a reference for future manual work.
Phase 6: Process Chosen Sprite
Run the full pipeline on the selected candidate:
python scripts/process_sprite.py pipeline \
--input ./sprites-wip/slime_002.png \
--output ./sprites/slime.png \
--target-width 32 --target-height 32 \
--crop-mode bottom-anchor
If chromakey was used, add --chroma-color HEXCODE --tolerance 45.
Pipeline steps (can also run individually):
- Remove background (if chromakey):
remove-bg --chroma-color HEXCODE - Downscale: nearest-neighbor from generation size to target dimensions
- Crop per crop mode: bottom-anchor trims sides/top; center and none leave canvas as-is
Post-chromakey re-check: The pipeline automatically detects leftover chroma fringe pixels after background removal. If fringe is detected (>5% of edge pixels match the chroma color), it re-runs removal with tolerance +15 and checks again. Watch the pipeline output for DETECTED/CLEAN/WARNING messages.
After the pipeline completes, run check_transparency.py on the output with --chroma-color HEXCODE to verify:
python scripts/check_transparency.py --input OUTPUT.png --chroma-color HEXCODE
If it fails or the visual check shows artifacts, still use the sprite but add a task to the implementation plan noting the sprite needs manual background cleanup by the user.
Read the final sprite alongside the reference images to verify: matches references, correct dimensions, clean transparency, pixel-art preserved, appropriate crop.
Phase 7: Save and Update Plan
- Move the final sprite to the correct project folder
- Clean up temporary upscaled references (temp/)
- Keep all candidates in
sprites-wip/— do NOT delete any, from ANY attempt. The versioned filenames (slime_v1_001.png,slime_v2_003.png, etc.) make it easy to revisit rejected candidates later - Update the implementation plan with integration tasks (add to asset registry, create entity config, etc.)
Anti-Patterns
| Avoid | Do Instead |
|---|---|
| Generating without reference images | Always use 1-3 style references when available |
| Passing tiny 32px sprites as references | Upscale references to 500-1024px with nearest neighbor first |
| Bilinear/bicubic downscaling | Always nearest-neighbor to preserve pixel crispness |
| Multiple sprites in one image | ONE sprite per image, 4 separate API calls |
| Only visual transparency check | Always run check_transparency.py script first |
| Green chromakey for plant sprites | Pick a chromakey color not present in the subject |
| Skipping visual validation | Always Read the image to inspect after programmatic checks |
| Judging sprites without references | Always compare candidates against the original reference images — never evaluate in isolation |
| Cropping items | Items stay centered in canvas; only crop entities |
| Giving up after 1 failed generation | Up to 3 attempts; diagnose failure type and apply the right fix each time |
| Using chromakey for subject problems | Chromakey fixes backgrounds only; for wrong style/proportions, refine the prompt |
| Deleting candidates from earlier attempts | Keep ALL candidates; pick the best across all attempts at the end |
Reusing the same --name across attempts |
Use versioned names (slime_v1, slime_v2, slime_v3) to prevent overwrites |
| Using generic style keywords | Derive style keywords from studying the project's existing sprites |
Dependency Note
This skill requires openai and Pillow. Phase 0 handles installation automatically.
This is an approved exception to the standard-library-only rule for scripts.
More from riccardogrin/skills
creating-skills
Guides creation of agent skills following best practices and the open format specification. Covers pattern selection, frontmatter, directory structure, reference files, validation, and iteration. Use when creating a new skill, updating SKILL.md, or asking "how to write a skill
16looping-tasks
Generates an autonomous implementation loop that executes tasks from a plan across Claude sessions, with periodic audit passes that inject follow-up tasks. Covers loop script, prompt design, and audit cadence. Use when setting up autonomous task execution or Ralph-style iterative workflows
16planning
Creates implementation-ready plans through discovery interviews, external research, and codebase analysis. Covers requirements, competitor research, architecture decisions, and change sequencing. Use when planning features, roadmaps, specs, or any work that needs discovery before coding
14listing-docs
Scans docs/ folder for markdown files with YAML front-matter and lists their summaries and read_when hints. Helps identify relevant documentation before coding. Use when starting a task, checking available docs, or asking "what docs exist
14enforcing-architecture
Sets up automated architecture enforcement via check scripts and hooks that catch layer violations on every file edit. Run after `/initializing-projects` for complex projects with 3+ distinct layers, or when no ARCHITECTURE.md exists and the codebase has clear architectural boundaries worth enforcing mechanically
14initializing-projects
Generates a minimal, self-maintaining CLAUDE.md for projects through auto-detection and developer interview. Covers project identity, do/don't rules, hooks, and self-maintenance. Use when starting a new project or adding Claude Code support to an existing one
13