A Claude Code plugin for making pixel art with nothing installed beyond Python 3: sprites, animation cycles laid out for game engines, tilesets, UI skins, effect sheets, and animated scenes that open in any browser.
| Skill | What it does |
|---|---|
/pixel-art:sprite |
A static sprite (character, item, icon, portrait, face) as a PNG sheet |
/pixel-art:animate |
Idle, walk, attack and other cycles in 1, 4 or 8 directions, as an engine sprite sheet plus GIF previews |
/pixel-art:tileset |
Terrain, autotiles, and parallax layers as the target engine's tileset sheet |
/pixel-art:ui |
Window skins, icon sets, HUD elements, and bitmap fonts |
/pixel-art:vfx |
Hit sparks, spells, and explosions as a cell sheet (MV-style animations for RPG Maker) |
/pixel-art:scene |
A cutscene, title screen, ambient loop or short pixel film as one self-contained HTML file |
/pixel-art:sprite a 32x32 potion icon, PICO-8 palette
/pixel-art:animate a knight, walk and attack, 4 directions, RPG Maker MZ
/pixel-art:tileset an RPG Maker MZ A2 grass autotile
/pixel-art:ui an MZ window skin
/pixel-art:vfx a hit spark for MZ animations
/pixel-art:scene the knight walks to a campfire at dusk and says one line, 240x160- The model records a
brief.mdbeside the spec (subject, style references, proportions, palette, and the done criteria), then turns the request into a spec: a locked palette and frames, written by hand for small sprites or by a short procedural generator for larger ones. Tilesets, UI skins, and effect sheets use that same spec. A later round reads that brief instead of asking again. The palette may be an inline object, a bundled preset (pico-8,nes,game-boy, or a CC0 Lospec set inpalettes/), or a project palette file. The sheet shape comes fromreference/engine-layouts.md. scripts/backends.pyselects the backend andscripts/render.py(Python standard library only) writes the engine asset at 1x, an upscaled preview, a GIF per animation, and frame data.scripts/embed.pybuilds scenes into one HTML file.scripts/capture.pyserves that file and, when a browser is present, saves timeline shots and an optional WebM.- The model looks at what it rendered and revises, usually two to four rounds. Each round marks the brief's done criteria pass or fail. The loop stops when they all pass, or when the round budget is spent and the failures are named.
scripts/gallery.pywrites anindex.htmlshowing every output on one page.
| Setting | Default | Purpose |
|---|---|---|
output_dir |
unset (ask) | Where outputs go when the request and the project name no location |
backend |
native |
native or aseprite |
A project can name its own assets folder in its CLAUDE.md; that wins over output_dir.
- Python 3: required. The renderer uses the standard library only.
- A local browser (Chrome or Chromium on
PATH): optional.scripts/capture.pydrives it for the scene review loop. Without one, the command exits 3 and the skill says the scene was not reviewed visually. - Aseprite: optional.
scripts/backends.pyruns it whenaseprite --versionworks and otherwise falls back tonativewith one line. Details are inreference/backends.md. The adapter has run only against a local stand-in so far, not the real tool.
Native sheet.json follows the shape of Aseprite's json-hash export but is not identical: animation
tags list frame names and per-frame durations rather than from/to ranges. The Aseprite backend
writes Aseprite's own json-hash file instead (frames keyed by spec name, meta.image set to
sheet.png), and still writes the native GIFs and preview.
This plugin does not synthesize sound. embed.py inlines a WAV you place next to the template
(/*WAV:file.wav*/null), and the scene plays it on the first click. examples/campfire/campfire.wav
is that file for the example. It was rendered from the score in examples/campfire/AUDIO.txt.
The renderer that produced it lives in the retro-audio plugin and is not imported here. The
--record WebM for the example carries the WAV as its audio track when ffmpeg is present and is
video only otherwise.
scripts/kit.py is the procedural character kit: proportion presets (chibi, standard, tall),
head and hair shapes, clothing layers, material ramps, top-left shading, a selective outline, and
4-direction handling. Adapt it; do not treat it as a fixed generator. examples/walker/blacksmith.py
is a 4-direction walker built on it. examples/campfire/ holds an earlier hand-written RPG Maker MZ
walker and a cutscene that reuses it. examples/tileset/a2_ground.py, examples/ui/window_mz.py,
and examples/vfx/spark_mz.py each write a spec for an engine sheet. Copy a folder somewhere
writable, then run it there. For walker/, put scripts/kit.py beside blacksmith.py:
python3 blacksmith.py
python3 <plugin>/scripts/render.py blacksmith.json --out out --scale 4For campfire/:
python3 hero_mz.py
python3 <plugin>/scripts/render.py hero_mz.json --out out --scale 4
python3 <plugin>/scripts/embed.py scene.html out/campfire.html
python3 <plugin>/scripts/gallery.py out
python3 <plugin>/scripts/capture.py out/campfire.html --at 0,3,7 --record 4 --out out/capturereference/ holds the sourced rules the skills apply: craft-static.md, craft-animation.md,
craft-tiles.md, engine-layouts.md, scene-canvas.md, and backends.md. palettes/ holds
the bundled preset files and the notes for a project palette file.
Generated from this plugin's .claude-plugin/plugin.json. Every option Claude Code
will prompt for when the plugin is enabled, with the environment variable each hook
reads it from.
| Option | Type | Default | Environment variable | Description |
|---|---|---|---|---|
output_dir |
directory | (none) | CLAUDE_PLUGIN_OPTION_OUTPUT_DIR |
Where rendered sprites, sheets and scenes go when neither the request nor the project names a location. Leave unset to be asked. |
backend |
string | "native" |
CLAUDE_PLUGIN_OPTION_BACKEND |
native (default, no external tools) or aseprite. A named backend that is not present falls back to native with a notice. |
Three supported routes, in the order most people want them:
-
Interactively. Claude Code prompts for declared options when you enable the plugin. To change them later:
/plugin configure pixel-art@<marketplace>. -
Headless. Repeat
--configfor each option. Replace<marketplace>with the marketplace you installed this plugin from:claude plugin install pixel-art@<marketplace> -s <scope> --config output_dir=<value>
The same command reconfigures a plugin that is already installed: it prints
already installedand still writes the value. The short-circuit message is about the install, not the config write. Do notclaude plugin uninstallto reconfigure: uninstalling drops this plugin's whole storedpluginConfigsentry, resetting every option in the table above to its default.-sdefaults touser, so pass the scopeclaude plugin listreports for this plugin. The verified-version record lives in the plugin-reconfiguration convention.The value is stored immediately; the session you are in does not change. Hooks are handed their
CLAUDE_PLUGIN_OPTION_*when the session starts, so start a fresh Claude Code session before expecting new behavior. A check run in the old session still reports the old value, and that is not a failed write. -
By hand, in settings. Add the value under
pluginConfigsin your user settings (~/.claude/settings.json):{ "pluginConfigs": { "pixel-art@<marketplace>": { "options": { "output_dir": <value> } } } }Plugin option values are read from user,
--settings, and managed settings only, not from a project's.claude/settings.json. To vary behavior per repository, enable or disable the plugin in that project'senabledPluginsinstead of setting an option there.
Do not set the CLAUDE_PLUGIN_OPTION_* variables yourself. They are how Claude Code
hands a configured value to a hook process; the value comes from the routes above.
- User configuration: the
userConfigschema and theCLAUDE_PLUGIN_OPTION_<KEY>export - Plugin install options: the
--configflag's reference entry - Plugins and skills settings:
enabledPlugins,extraKnownMarketplaces,pluginConfigs - Settings files and who they affect: user vs project vs local precedence
- Manage installed plugins: enabling, disabling,
/plugin list