aseprite-mcp
Core integration with a local Aseprite installation: creates and edits sprites, draws with ASCII grids/shapes/gradients, reads pixels back, previews rendered frames, manages layers/frames/tags/palettes, applies art helpers (outline, shading, quantize/dither, mirroring, region copy, seamless tile shift), imports and reduces upscaled or hi-res art, and animates static art with presets, per-layer keyframe tracks and rigs. Also runs arbitrary Aseprite Lua as an escape hatch.
Exports animations as a Bevy-friendly atlas JSON alongside the sprite sheet, so sprite animations can be consumed directly by Bevy games.
Used to read video input when ingesting AI/video-generated frames, so video files can be cleaned into aligned, palette-locked, tagged pixel-art animations.
Runs any Replicate model (diffusion, pixel-art animation, video) using your sprite as input; can list a model's inputs, render the sprite upscaled on a solid background for the model's image input, and run one prediction per prompt, then pipes the raw outputs into the ingest pipeline to be cleaned into pixel art.
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@aseprite-mcpdraw a 16x16 slime sprite, animate it breathing, and export a sprite sheet"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
aseprite-mcp
A fast, token-efficient MCP server that lets AI assistants (Claude Code, Claude Desktop, Cursor, …) make pixel art, animate it, and export game-ready sprite sheets with your local Aseprite.
It also includes a CLI (aseprite-mcp build recipe.json), so the same animation recipes can run in your game's asset pipeline without an AI involved.
Highlights
Built for how a model draws.
drawtakes ASCII rows plus a color legend, shape tuples and dithered gradients.read_pixelsreturns the same grid format.previewreturns a zoomed image with a pixel grid that the model can actually look at.Fast. One persistent Aseprite worker process handles every call, so typical calls take 0.5–2 ms (a cold
aseprite -bstart is ~70 ms per call).batchruns many steps with one open and one save.Cheap on context. 16 tools totalling ~4k tokens of schema. Inputs and outputs are terse.
Art helpers. Selective auto-outline, light-direction shading with hue-shifted shadows and highlights, palette ramps, palette extraction, quantize-to-palette with Bayer or Floyd–Steinberg dithering, mirroring, region copy, seamless tile shifting.
Importing existing art. Upscaled pixel art is detected and reduced to its native resolution. Hi-res art can be pixelated to a target size by majority color per block.
separatesplits the background from the subject (and fills the hole behind it) so only the subject animates.Animation framework. 22 presets (
breathe,hop,hit,death,spin,sway,wave,cycle, …), composable per-layer tracks with keyframes, waves and easing, secondary motion via per-layer lag, and RotSprite-smoothed rotation.Game export. Sprite sheet + Aseprite JSON (frame tags), plus a Godot 4
SpriteFrames.tresand a Bevy-friendly atlas JSON.Safe with your assets. It refuses to overwrite existing non-
.asepriteimages. You import them, edit the import, then export.
Related MCP server: aseprite_mcp
Tools
Tool | What it does |
| New sprite, or import an image ( |
| Size, mode, layers, frame durations, tags (palette on request) |
|
|
|
|
| Extract dominant colors (from a sprite or any image), generate hue-shifted ramps, set the palette |
| Pixels → character grid + legend |
| Rendered PNG the model can see; frames, contact sheet, or one row per animation tag |
| add / update / delete / clear / merge_down |
| add (copy) / duration / delete / tag |
| Nearest-neighbor scale or canvas resize with anchor |
| PNG/GIF/sequence, or sprite sheet + JSON (+ Godot / Bevy files) |
| Static art → tagged animations → sprite sheet, from inline args or a recipe file |
| AI/video/hand-made frames → background removed, palette-locked, grid-snapped, aligned, tagged animation |
| Run any Replicate model (diffusion, pixel-art animation, video) with your sprite as input, then |
| Many steps in one call |
| Escape hatch: Aseprite Lua with |
Conventions: coordinates are 0-based from the top-left. Frames are 1-based (as in Aseprite). Colors are #rgb, #rrggbb, #rrggbbaa or transparent. Drawing replaces pixels.
Animation recipes
A recipe describes how static art becomes a set of animations and a sprite sheet. Keep it next to your art and rebuild whenever the art changes:
{
"source": "art/slime.aseprite",
"output": "build/slime_anim.aseprite",
"padding": [0, 6, 0, 0],
"animations": [
{ "name": "idle", "preset": { "name": "breathe", "lag": { "eyes": 0.1 } } },
{ "name": "jump", "preset": "hop" },
{ "name": "hit", "preset": { "name": "hit", "layers": "body" } },
{ "name": "die", "preset": "death" },
{ "name": "blink", "frames": 6, "durationMs": 120,
"tracks": [{ "layer": "eyes", "visible": { "seq": [1, 1, 1, 1, 1, 0] } }] }
],
"export": { "sheet": "game/sprites/slime.png", "engines": ["godot", "bevy"] }
}npx aseprite-mcp build art/slime.anim.json # once
npx aseprite-mcp build art/slime.anim.json --watch # rebuild on saveFrom the MCP side, animate with saveRecipe writes this file for you, with paths relative to the recipe.
Presets: bob, breathe, float, hop, walk, hit, flash, blink, shake, sway, wobble, pulse, spin, swing, spawn, death, fade_out, fade_in, wave, cycle. Each takes amount, layers (which layers move) and lag ({layer: delay} for secondary motion). Combine several by passing a list.
Tracks (per layer, composable): x, y, sx, sy, sxPx, syPx (scale by pixels), rot (degrees, RotSprite-smoothed), shear, waveAmp, alpha, flash + flashColor, dissolve (ordered dither), visible, cycle (palette cycling). Each value is a curve:
a number,
{ "seq": [...] }with one value per frame,{ "keys": [[t, v, ease?], ...] }withtfrom 0 to 1 and easesin,out,inout,steporback,{ "wave": "sine" | "triangle" | "square" | "saw", "amp", "base", "phase", "cycles" }.
Tip: draw parts (body, head, eyes, cape) on separate layers. Then lag and per-layer tracks give much livelier motion than moving the whole sprite.
Rigging existing art (idle and walk from one static image)
Existing single-layer art can be cut into parts and walked:
create_spritewithfromimports the art at native resolution.edit separatetakes off the background.edit splitcuts the parts onto layers namedhead,torso,arm_l,arm_r,leg_landleg_r. Put legsbelowthe torso.Animate with the rig presets:
[{ "op": "edit", "action": "split", "layer": "art", "toLayer": "leg_l", "below": true, "rects": [[0, 51, 30, 63]] },
{ "op": "edit", "action": "split", "layer": "art", "toLayer": "leg_r", "below": true, "rects": [[31, 51, 63, 63]] },
{ "op": "edit", "action": "split", "layer": "art", "toLayer": "arm_l", "rects": [[14, 36, 23, 43], [14, 44, 22, 49]] },
{ "op": "edit", "action": "split", "layer": "art", "toLayer": "head", "rects": [[0, 0, 63, 31]], "backfill": 0 }]Rig presets:
idle_rig(staggered breathing) andwalk_front(alternating leg lifts, body bob and weight shift, opposite arm swing).Remapping: use
partsfor other layer names, e.g.{"name": "walk_front", "parts": {"head": "skull"}}.Backfill:
splitgrows the remaining layer into the cut bybackfillpx (default 1), so a moving arm reveals torso, not a hole.
Redrawn poses (cutout-style animation)
Moving the same pixels only goes so far. For real poses, draw alternate versions of a part on extra source frames of the rig, and pick them per frame with a pose track:
Frame 1 holds the rest drawing. Frames 2, 3, … are a pose sheet that only needs the parts that change.
{"layer": "arm_r", "pose": {"seq": [1, 2, 2, 3, 3, 1, 1]}}shows rest → raised → strike. Layers without a drawing on that pose frame keep their rest drawing.Underpaint what a part hides. Painting the torso edge behind an arm, or a dark mouth interior behind a split-off
jaw, means raising the arm or dropping the jaw reveals something sensible.Effects such as slash streaks can live on their own layer, drawn only on a pose frame, so they appear exactly when the pose track selects them.
The rig presets also move an optional
jawpart together withhead.
AI-generated frames → clean pixel art (ingest)
Diffusion models, image editors and video models can produce new poses that procedural animation can't. Their output isn't pixel art yet: soft edges, noise, off-palette colors, backgrounds, drifting scale and position. ingest cleans it up:
Background removal. Uses existing alpha, a given color, or auto-detected border colors, flood-filled with a Lab tolerance that also follows smooth gradients.
Palette. Colors are pulled to the reference sprite's palette, a preset, or one extracted from the frames, at full resolution.
Pixel grid. The image is reduced by majority color per block, which keeps edges crisp and introduces no blended colors.
Specks. Orphan pixels are removed.
Alignment.
sequenceuses one shared transform and keeps the source's own motion; use it for video.feetputs each frame's feet on the ground line and its center of mass on the reference anchor; use it for separately generated poses.
Inputs: image files, a sprite sheet grid, or a video (ffmpeg required). Each call appends one tagged animation, so a character's idle, walk and attack all end up in one file:
{ "path": "build/hero.aseprite", "frames": ["gen/walk_1.png", "gen/walk_2.png", "..."],
"reference": "art/hero.aseprite", "align": "feet", "tag": "walk", "durationMs": 100 }Measured on synthetic diffusion-style frames (8× upscale, blurred edges, color noise and tint, gradient background), ingest recovers the original 64×64 frames at ~99% per-pixel accuracy in about 0.5 s per 512px frame.
Generating frames with Replicate (generate)
generate runs any Replicate model and pipes the output straight into ingest:
describe: truelists the model's inputs, since every model names them differently.imagerenders your sprite upscaled on a solid background and sends it to the model's image input (auto-detected).promptsruns one prediction per prompt, for example one per pose, 4 at a time.Raw outputs are kept in
<ingest path>.gen/, so you can re-run cleanup with other settings without paying again.Video outputs are split into frames with
ffmpeg(brew install ffmpeg).
{ "model": "black-forest-labs/flux-kontext-pro",
"image": { "path": "art/hero.aseprite", "hide": ["background"] },
"prompts": ["same character, left foot forward mid-stride, side view, plain white background",
"same character, legs passing, side view, plain white background", "..."],
"ingest": { "path": "build/hero.aseprite", "reference": "art/hero.aseprite", "tag": "walk", "align": "feet" } }Setup: create a token at replicate.com/account/api-tokens and put it in the MCP server's env as REPLICATE_API_TOKEN. In Claude Code's ~/.claude.json that's "mcpServers": { "aseprite": { ..., "env": { "REPLICATE_API_TOKEN": "r8_..." } } }. Restart the session afterwards.
Game engines
Each sheet export writes sheet.png + sheet.json (Aseprite json-array with frameTags). With engines:
Godot 4:
sheet.tres, aSpriteFramesresource with one animation per tag, correct per-frame timing, and loop off for one-shot animations (hit,death, …). Theres://path is detected from the nearestproject.godot. Drop it on anAnimatedSprite2D.Bevy:
sheet.atlas.json:{ "image": "slime.png", "size": [w, h], "frame_size": [fw, fh], "frames": [{ "rect": [x, y, w, h], "offset": [ox, oy], "duration_ms": 100 }], "animations": { "idle": { "frames": [0, 1, 2], "looping": true } } }Load it with
serde_jsonand build aTextureAtlasLayoutfromframes[].rect.
Install
Requires Node ≥ 20 and Aseprite (Steam or standalone).
git clone https://github.com/MJSchut/aseprite-mcp.git
cd aseprite-mcp
npm install # also builds dist/Claude Code
claude mcp add aseprite -s user -- node /absolute/path/to/aseprite-mcp/dist/index.jsClaude Desktop / Cursor / others
{ "mcpServers": { "aseprite": { "command": "node", "args": ["/absolute/path/to/aseprite-mcp/dist/index.js"] } } }Environment variables (all optional)
Variable | Purpose |
| Aseprite executable. Otherwise found on |
| Base directory for relative paths (default: the server's working directory). |
| Per-call timeout, default 60000. |
|
|
|
|
Notes
Edits operate on files. If a file is open in the Aseprite GUI, use File → Revert to see changes.
Tilemap layers are not supported by the drawing tools (use
run_lua).
Development
npm run build # tsc → dist/
npm test # end-to-end tests against your real Aseprite (skipped if not installed)Layout:
src/index.ts: tools and the CLI.src/aseprite.ts: binary discovery, the persistent worker, the runner.src/animate.ts: presets and recipes.src/export.ts: sheet export, Godot and Bevy writers.src/palettes.ts: palette presets.lua/ops.lua: every sprite operation, run inside Aseprite.
License
MIT
This server cannot be deployed
Maintenance
Related MCP Connectors
Create AI animations and export transparent sprite sheets, alpha video, frames, and game assets.
Generate, edit, style-match, turn, and animate game-ready pixel art at exact sizes.
Generate pixel art sprites, animations, 8-direction rotations and palettes for games.
Generate game sprite sheets and animations from an image, and clean up sprite backgrounds.
Related MCP Servers
- AlicenseCqualityDmaintenanceEnables AI assistants to automate Aseprite tasks such as sprite sheet export, frame extraction, and Lua scripting for sprite manipulation.2128 npm1MIT
- AlicenseAqualityDmaintenanceEnables AI sprite generation and semantic tools for Aseprite, allowing LLMs to create pixel art, add animations, and manage projects with visual feedback.61GPL 3.0
- AlicenseNot gradedqualityBmaintenanceEnables AI assistants to drive Aseprite for pixel-art creation, including sprite setup, grid-based drawing, layer/frame/tag management, reference image import, and export, with rendered previews after every mutation.MIT
- AlicenseBqualityCmaintenanceEnables AI assistants to create and edit pixel art and animated sprites in Aseprite through 104 tools covering drawing, layers, animation, palettes, tilemaps, exports, visual analysis, and raw Lua scripting.116MIT