Install
$ agentstack add skill-ianlintner-ai-pixel-art-image-generation-ai-pixel-art-image-generation ✓ scanned · ✓ verified — works with Claude Code, Cursor, and more.
Security review
✓ PassedNo issues found. Passed automated security review. · v0.1.0 How review works →
- ✓ Prompt-injection patterns
- ✓ Secret / credential exfiltration
- ✓ Dangerous shell & filesystem operations
- ✓ Untrusted network calls
- ✓ Known-malicious package signatures
What it can access
- ✓ Network access No
- ✓ Filesystem access No
- ✓ Shell / process execution No
- ✓ Environment & secrets No
- ✓ Dynamic code execution No
From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.
About
AI Pixel Art & Tile Map Generator
Overview
Generate images via OpenAI/Azure AI Foundry and, via an integrated pixel-art pipeline, produce Tiled-compatible pixel-art sprites, tileset sheets, and short sprite-sheet animations for 2D games. The skill covers two user paths:
- General image generation — text-to-image via
gpt-image-2(OpenAI/Azure) or Flux/Stable Diffusion (fal.ai). - Pixel-art game-asset mode — generation + nearest-neighbor downscale + palette quantize + (for animations) Gemini 2.5 Flash Image reference-based frame consistency + TSX/TMJ export for Tiled.
Direct OpenAI uses OPENAI_API_KEY. Azure uses AZURE_OPENAI_ENDPOINT (or --endpoint) plus Azure CLI, DefaultAzureCredential, or AZURE_OPENAI_API_KEY. fal.ai uses FAL_KEY (or --fal-api-key). Provider selection is auto: Azure is used when AZURE_OPENAI_ENDPOINT is set, otherwise direct OpenAI is used. Pass --provider fal explicitly to use fal.ai.
When to Use Which Script
| Script | Use when user wants... | | ------------------------------- | ---------------------------------------------------------------------------- | | scripts/generate_image.py | A general-purpose image (any subject, fixed or flexible gpt-image-2 size). | | scripts/generate_sprite.py | A single pixel-art sprite (16/32/64 px) with a named palette. | | scripts/generate_tileset.py | N unique tiles packed into a sheet + TSX + TMJ for Tiled. | | scripts/generate_animation.py | 2–8 frame sprite-sheet animation (walk/idle) + TSX with `. | | scripts/pixelize.py | Post-process an existing image into pixel art (no generation). | | scripts/qa_report.py` | Standalone QA metrics on an existing pixel-art PNG. |
All scripts are invokable directly via python3 and print their output paths on completion.
Available Image Models
OpenAI / Azure
| Model | Provider | Use case | | ------------------ | ------------ | ------------------------------ | | gpt-image-2 | OpenAI/Azure | Default — highest quality | | gpt-image-1 | OpenAI/Azure | Older generation compatibility | | gpt-image-1-mini | OpenAI/Azure | Faster/cheaper drafts | | sora-2 | OpenAI/Azure | Video (not images) |
fal.ai — Text-to-Image
| Model | Best for | | ------------------------------------- | ----------------------------------------------------------------- | | fal-ai/recraft/v3/text-to-image | Pixel art tiles & sprites — SOTA vector art, consistent style | | fal-ai/flux/dev | General purpose, high quality (default) | | fal-ai/flux/schnell | Fast iteration, 4-step distilled, cheap batch tiles | | fal-ai/nano-banana-pro | Google's latest — excellent realism + editing combo | | fal-ai/qwen-image | Complex text rendering (UI/HUD elements) | | fal-ai/flux-pro/v1.1-ultra | Maximum quality, best composition | | fal-ai/recraft/v4/pro/text-to-image | Production-ready, refined lighting & materials | | fal-ai/seedream/v4.5/edit | ByteDance unified generation + editing |
fal.ai — Image-to-Image (Sprite Editing)
| Model | Best for | | ----------------------------- | --------------------------------------------------- | | fal-ai/nano-banana-pro/edit | Best editor — refine generated sprites, restyle | | fal-ai/flux-pro/kontext | Reference image + text → targeted local edits | | fal-ai/reve/edit | Simple image-to-image transform via text prompt | | fal-ai/bria/fibo-edit/edit | JSON + Mask + Image precise editing |
fal.ai — Utility Tools
| Model | Tool | Use case | | ------------------------------------------ | ----------------- | --------------------------------------------- | | fal-ai/bria/background/remove | bg-remove-bria | Best BG removal — commercially safe | | fal-ai/seedvr/upscale/image | upscale-seedvr | SeedVR2 upscale — $0.001/megapixel | | fal-ai/topaz/upscale/image | upscale-topaz | Professional-grade upscale (highest fidelity) | | fal-ai/ffmpeg-api/images-to-video | images-to-video | Animation export — stitch frames → MP4 | | fal-ai/kling-video/v3/pro/image-to-video | image-to-video | Animate a still sprite into video |
Gemini (separate provider): gemini-2.5-flash-image ("Nano Banana") — used for multi-frame animation consistency via reference images.
Auth
OpenAI
Use OPENAI_API_KEY or --openai-api-key.
Azure
- Azure CLI (
az login) — tried first; best for local/interactive. - DefaultAzureCredential — managed identity, env service principal, workload identity.
- API key (
AZURE_OPENAI_API_KEYor--api-key) — fallback for CI/headless.
Install to enable credential auth: pip install azure-identity
Endpoint gotcha. Azure AI Foundry resources expose two URLs. Use the Azure OpenAI legacy endpoint for gpt-image-*, not the AI Services endpoint:
- ✅
https://.openai.azure.com/— works withscripts/lib/azure_client.py. - ❌
https://.services.ai.azure.com/— Foundry-native API, not compatible with this skill.
Discover it with:
az cognitiveservices account show --name --resource-group \
--query 'properties.endpoints' -o json
Provider auto-select. Provider resolves to azure when AZURE_OPENAI_ENDPOINT is set in the environment. Some shells/tools (e.g. agent runners) don't source ~/.zshrc; if --provider auto falls back to OpenAI unexpectedly, either prefix the call (AZURE_OPENAI_ENDPOINT=... python scripts/…) or pass --provider azure --endpoint https://… explicitly.
Deploying a model on Azure
Before first use you need a deployment of the image model on your resource. The az cognitiveservices account deployment create extension has a bug where it pins an unsupported api-version. Use az rest directly:
SUB=$(az account show --query id -o tsv)
RG=$(az cognitiveservices account list \
--query "[?name==''].resourceGroup" -o tsv)
az rest --method put \
--url "https://management.azure.com/subscriptions/${SUB}/resourceGroups/${RG}/providers/Microsoft.CognitiveServices/accounts//deployments/gpt-image-2?api-version=2024-10-01" \
--body '{"sku":{"name":"GlobalStandard","capacity":1},"properties":{"model":{"format":"OpenAI","name":"gpt-image-2","version":"2026-04-21"}}}'
Check what's deployable in your region first:
az cognitiveservices model list --location \
--query "[?kind=='OpenAI' && starts_with(model.name,'gpt-image')].{name:model.name,version:model.version}" -o table
Regional availability (as of 2026-04). gpt-image-2 (version 2026-04-21) is only published in eastus2. gpt-image-1, gpt-image-1-mini, and gpt-image-1.5 are more broadly available. If your resource lives elsewhere, either deploy gpt-image-1.5 (newest broadly-available) or create a second resource in eastus2.
Gemini (only for generate_animation.py)
API key via GEMINI_API_KEY env var (or --gemini-api-key). Google has no usable Entra equivalent for this endpoint.
fal.ai
API key via FAL_KEY env var (or --fal-api-key). Get a key at https://fal.ai/dashboard/keys.
export FAL_KEY="your-key-here"
# or pass per-command:
python3 scripts/generate_image.py --provider fal --fal-api-key "..." --prompt "..." --output ~/img.png
Default model. fal-ai/flux/dev is the default. Override with --model or --deployment, or set FAL_MODEL in the environment.
Quality mapping. When using fal-ai/flux/dev (default):
--quality lowor--quality medium→ switches tofal-ai/flux/schnell(faster, 4-step distilled)--quality high→ stays onfal-ai/flux/dev(best quality)
Size mapping. fal.ai uses named presets. Standard sizes (1024x1024, 1024x768, etc.) are mapped automatically. Unrecognized sizes fall back to square_hd (1024×1024).
fal.ai Utility Tools
The scripts/lib/fal_tools.py module provides fal-hosted utilities as cloud alternatives to local libraries. Import and use directly:
from lib.fal_tools import remove_background_bria, upscale_seedvr, images_to_video
# Background removal (Bria RMBG 2.0 — commercially safe)
no_bg = remove_background_bria(sprite_bytes)
# Upscale before pixelize downscale (SeedVR2 — $0.001/megapixel)
hi_res = upscale_seedvr(sprite_bytes, scale=2)
# Stitch walk-cycle frames into MP4 animation
video = images_to_video([frame0, frame1, frame2, frame3], fps=8, hold_frames=15)
# Animate a still sprite into video (Kling 3.0 Pro)
animated = image_to_video(sprite_bytes, prompt="idle breathing animation")
Or use the dispatcher:
from lib.fal_tools import run_tool
result = run_tool("bg-remove-bria", image_bytes)
result = run_tool("upscale-seedvr", image_bytes, scale=2)
video = run_tool("images-to-video", [frame0, frame1, frame2, frame3])
Dependencies
pip install openai azure-identity google-genai fal-client pillow rembg onnxruntime
openai,azure-identity→ direct OpenAI, Azure auth, and image generation.google-genai→ Gemini reference-image generation (required forgenerate_animation.py).fal-client→ fal.ai image generation (Flux, Stable Diffusion, etc.) and utility tools (background removal, upscaling).pillow→ post-processing pipeline.rembg+onnxruntime→ optional local background removal (needed only when--transparent-bgis passed; pulls ~100 MB of ONNX runtime).
Workflows
1. General image generation
# OpenAI (default)
python3 scripts/generate_image.py \
--prompt "a cat on mars, photorealistic" \
--size 1024x1024 --quality medium \
--output ~/cat.png
# fal.ai with Flux
python3 scripts/generate_image.py \
--provider fal --model fal-ai/flux/dev \
--prompt "a cat on mars, photorealistic" \
--size 1024x1024 --quality high \
--output ~/cat_fal.png
Common sizes: 1024x1024, 1536x1024, 1024x1536, 2048x2048, 2048x1152, 3840x2160, 2160x3840, auto. Custom gpt-image-2 sizes are accepted when they satisfy the model constraints. Qualities: low, medium, high.
2. Single pixel-art sprite
python3 ~/.claude/skills/ai-pixel-art-image-generation/scripts/generate_sprite.py \
--prompt "orange tabby cat, front view, idle stance" \
--size 64 --palette db32 --transparent-bg \
--output ~/cat_64.png
--sizeis the final pixel dimension (square).--paletteis one of:gameboy,pico8,db16,db32,nes,aap64, orauto.--palette autopicks a palette from subject keywords — see the Palette Auto-Pick table.--outline {none,palette-darkest}— defaultpalette-darkest. Adds a 1-px dark ring via alpha dilation → XOR → darkest-luminance neighbour colour before palette quantize.--transparent-bgrunsrembgbefore downscale.--qaruns QA metrics after save, writes.qa.json, and exits non-zero on hard-gate failure.
Output: square RGBA PNG at --size × --size, limited to palette colors, hard edges.
3. Tileset for Tiled
python3 ~/.claude/skills/ai-pixel-art-image-generation/scripts/generate_tileset.py \
--prompt "grass, dirt, stone, water, sand, path, wood plank, stone brick" \
--tile-size 32 --count 16 --columns 4 --palette pico8 \
--name overworld --output-dir ~/tilesets/overworld/
Comma-separated tile concepts in --prompt; repeats if fewer than --count. Emits:
overworld.png— packed sheet atcolumns*K × rows*K.overworld.tsx— Tiled tileset XML with per-tilenameproperties.overworld.tmj— minimal example map filled with tile 1, openable in Tiled.
Tileset flags:
--palette {gameboy,pico8,db16,db32,nes,aap64,auto}—autopicks from keywords (e.g.,"stone"→db32).--seamless {none,crop,torus,auto}— defaultauto. Pixelizes source at 3× tile size, centre-crops for edge consistency, then if seam_diff ≥ 12.0 runs a torus-wrap feather blend. Seereferences/seamless.md(if present) orlib/seamless.py.--qaruns QA metrics (per-tile seam_diff mean, palette fidelity, alpha crispness) and writes a.qa.jsonsidecar.
4. Sprite-sheet animation
python3 ~/.claude/skills/ai-pixel-art-image-generation/scripts/generate_animation.py \
--prompt "knight with blue cape, side view, walking right" \
--frames 4 --tile-size 32 --palette db16 \
--duration-ms 120 --action walk \
--name knight_walk --output-dir ~/sprites/knight/
- Frame 0 is generated via OpenAI/Azure (
gpt-image-2). - Frames 1..N use Gemini 2.5 Flash Image with frame 0 as a reference image to maintain character consistency.
- TSX emits an `
block on tile id 0 that cycles all frames at--duration-ms`. - Frame prompts come from
POSE_LIBRARYingenerate_animation.py, keyed by(action, frame_idx, total). Supported actions today:walk(4 frames, contact/passing/contact-mirror/passing-mirror),idle(2 frames),attack(4 frames: wind-up/strike/recoil/recovery). Unknown keys fall back to generic"frame N of M"phrasing. --qaruns animation QA (palette fidelity, alpha crispness,silhouette_ioubetween frame 0 and frame 2,bbox_drift_x,bbox_drift_y) and writes a.qa.jsonsidecar.--transparent-bgenables rembg on every frame, then applies a shared bbox crop across all frames so the character stays aligned frame-to-frame. Per-frame tight-crop would drift position and break the walk-cycle feel.
Consistency caveat: walk cycles may need rerolls. Rerun for different frames if one drifts.
5. Post-process an existing image
python3 ~/.claude/skills/ai-pixel-art-image-generation/scripts/pixelize.py \
--input raw.png --output sprite.png \
--size 32 --palette pico8 --transparent-bg
Prompt Engineering
See references/pixel_art_prompting.md for detailed guidance. Key rules:
- Include "pixel art sprite, clean hard edges, limited palette, plain flat background, no text, no watermark".
- Specify view angle explicitly ("side view profile", "top-down").
- For tilesets, add "top-down game tile, seamless, centered".
- Avoid "photorealistic", "smooth shading", "gradients".
Tiled Format Notes
See references/tiled_format.md. Quick facts:
- TSX `` is relative to the TSX file — keep PNG + TSX in the same directory.
- TMJ
dataarray uses global ids (firstgid + local_id). Tile 0 in TSX → gid 1 in TMJ. - Tile animations declared inline; game engines must re-implement playback at runtime (the `` tag is metadata).
Palettes
See references/palettes.md. Available: gameboy (4), pico8 (16), db16 (16), db32 (32), nes (54), aap64 (64).
Palette auto-pick
When --palette auto is passed, lib/palettes.suggest_palette scans the prompt against a keyword table and picks a palette whose colour range matches the subject. Explicit --palette always wins. The chosen palette and matched keyword are logged to stderr.
| Keyword pattern | Palette | Why | | ---------------------------------------------------------------------------- | --------- | ----------------------------------------------- | | `metal\|steel\|armor\|stone\|grey\|gray\|silver\|iron\|dungeon\
…
Source & license
This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.
- Author: ianlintner
- Source: ianlintner/ai-pixel-art-image-generation
- License: MIT
- Homepage: https://ianlintner.github.io/ai-pixel-art-image-generation/
Install and usage instructions live in the source repository linked above.
Reviews
No reviews yet — be the first.
Write a review
Versions
- v0.1.0 Imported from the upstream source.