Skip to main content
Glama

sprite-canon

一个 MCP 服务器,让 AI 生成的游戏精灵看起来像同一个游戏。

原始版与确定性重绘对比——着色保留,轮廓永不改变

一个角色,三套服装——蓝色和红色行是 sprite_repaint 调用,而不是重新生成。相同的着色顺序,相同的轮廓,每次结果一致。

AI 生成器擅长制作漂亮的精灵,却不擅长让它与上一个匹配。要求同一个角色两次,调色板就会漂移,服装会变异,新帽子会漂浮在头顶上方 3 像素处——每个资源单独看都很好,但组装起来游戏看起来就不对劲。反复“直到匹配”的重新生成不会收敛;它烧钱,而且你无法对结果进行差异比较。

sprite-canon 采取了相反的方法,该方法源自一个真实游戏项目,该项目生成了约 4,000 帧,并艰难地吸取了所有教训:

  1. 你的一致性规则变成数据——一个 sprite-canon.json(“canon”)保存调色板、命名颜色区域(皮肤、服装、轮廓等)、相对比例和检查阈值。与你的资源一起提交。

  2. 验证是数字化的,而非视觉化的。 你无法用肉眼检查 96 种服装变体 × 8 个方向 × 4 帧。sprite_verify 返回针对实际发布缺陷的硬性通过/失败数字:偏离调色板的像素、帧间抖动的配饰、从背面亮而从正面暗的区域、触及脸部的重绘。

  3. 修复是确定性的像素操作,而非重新生成。 将区域重绘到新的颜色渐变上会保留着色和轮廓,绝不触及受保护区域,并且每次产生相同输出。服装变体是一次工具调用,而不是提示词彩票。

安装

Claude Desktop — 一个文件,无需配置

  1. 从最新版本下载 sprite-canon.mcpb。

  2. 在 Claude Desktop 中,打开 设置 → 扩展(Windows 上为 ☰ 菜单 → 文件 → 设置)。

  3. 将 .mcpb 文件拖入扩展页面,查看并点击安装。

(如果您的操作系统已注册 .mcpb 关联,双击文件也可以——拖放始终有效。替代方法:扩展 → 高级设置 → 安装扩展 → 选择文件。)

这就是全部安装过程:该捆绑包自带依赖项,Claude Desktop 提供 Node 运行时。需要 Claude Desktop 应用——Claude Code 请参见下文。

Claude Code / 其他 MCP 客户端

git clone https://github.com/useka12-eng/sprite-canon
cd sprite-canon && npm install

然后在项目的 .mcp.json(或任何 MCP 客户端配置)中注册:

{
  "mcpServers": {
    "sprite-canon": {
      "command": "node",
      "args": ["/path/to/sprite-canon/src/mcp/server.mjs"]
    }
  }
}

需要 Node 18+。无原生依赖——PNG/GIF 编解码器是自包含的。

自行构建捆绑包

npx @anthropic-ai/mcpb pack . dist/sprite-canon.mcpb

Related MCP server: Spiritmarch Aseprite MCP

工具

工具

功能

canon_init

创建 canon;从示例图像中学习调色板(使用次数 ≥ N 的颜色——较稀有的通常是抗锯齿噪声)

canon_learn

通过采样几个像素、列出颜色或 HSL 规则来定义区域。记录区域的亮度范围。将面部/轮廓标记为 protected

canon_info

显示解析后的 canon + 对照它统计文件(未匹配的像素 = 区域定义中的缺口)

colors_inspect

按频率和亮度列出实际使用的颜色——canon 决策的原始材料

sprite_measure

每帧解剖(边界框、帽/头宽度、腰部行、每个区域的第一行)+ 跨帧抖动

sprite_verify

数字检查:palette、jitter、spread、protected、leftover、scale

sprite_repaint

确定性地将区域重新着色到暗→亮渐变上;受保护区域不可触碰

sprite_sheet

缩放后的联系表以图像形式内联返回——在表上判断一致性,而不是在游戏中

gif_patch

无损 GIF 操作:跨所有颜色表进行调色板替换(零生成损失)、重新定时

输入可以是 PNG、动画 GIF 或 PNG 精灵表(cellW/cellH)。

工作流程

canon_init      → learn the palette from your existing good assets
canon_learn     → sample skin / outfit / outline once; mark face + outline protected
sprite_measure  → read the numbers before placing anything ("where do the eyes start?")
sprite_repaint  → make variants deterministically (outfits, teams, seasons)
sprite_verify   → prove it: face untouched, nothing left over, no jitter, on palette
sprite_sheet    → look at the result as a sheet, zoomed, before it enters the game

此工具编码的教训

这些不是假设——每一个都首先作为真实缺陷出现:

  • 测量,不要假设比例。 将帽檐放置在“头部高度的 52%”恰好落在眼睛上:在 20 像素高的头上,眼睛距顶部 7–9 像素,因此每个固定比例都会碰到它们。sprite_measure 报告每帧面部实际开始的位置。

  • 使用固定亮度范围进行重绘。 按图像归一化会将相同的源颜色映射到不同的输出,具体取决于区域可见多少——我们的帽子从背面亮,从正面暗。canon 记录每个区域的范围一次;重绘始终使用它。

  • 结构性保护区域。 “在面部周围小心”在规模上会失败。protected: true 意味着重绘不能触及它,验证证明它没有触及。

  • 修补 GIF 调色板,不要重新编码。 索引 GIF 的颜色存在于其颜色表中——全局和每帧局部(仅修补全局表是经典的半修复)。替换表条目会完美同步地重新装扮每一帧,零损失。

  • 区域定义有缺口;统计它们。 重绘后残留的 12 个旧颜色像素对眼睛不可见,但对 leftover 显而易见。当它触发时,canon_info 的统计显示你的区域未覆盖哪些颜色。

比例表

sprite_verify 的 scale 检查读取 canon.scale.heights——相对于参考资源(等于 1 的条目)的相对大小。目前没有工具写入此部分;手动添加到 sprite-canon.json:

"scale": { "heights": { "hero": 1, "house": 3.4, "chicken": 0.45 } }

然后使用 scaleNames 将文件基名映射到这些键进行验证。这会在玩家发现之前一周捕捉到经典的“房子比英雄小”问题。

实用说明

  • 始终传递 canonPath(或 canon 所在目录之上的文件)。stdio MCP 服务器的工作目录属于客户端,而不是你的项目,因此工具拒绝从 cwd 猜测。

  • 编解码器限制:PNG 必须是 8 位、非隔行、RGB/RGBA/调色板(常见的像素艺术情况;16 位或隔行文件会被拒绝并显示明确错误)。GIF 编码器在每文件最多 255 种不透明颜色时精确——超出后,最近调色板吸附。

  • sprite_sheet 内联返回图像,最大约 800 KB;更大的表仅返回文件路径。

  • 精灵表逐格往返:空单元格保持为空,不会压缩。

这不是什么

  • 不是生成器。将其与任何制作艺术品的工具配对(PixelLab、Aseprite、Gemini、手绘像素);sprite-canon 是保持结果连贯的层。

  • 不是图集打包器/碰撞工具——sprite-tools 很好地覆盖了这一点。

  • 不是魔法:你每个项目花约 10 分钟教它你的 canon。正是这种投入使每个后续检查和修复都值得信赖。

开发

npm test          # unit + end-to-end MCP tests (22)

测试套件包括针对 v0.1 中对抗性多代理审查发现的每个错误的回归测试——表单元格压缩、GIF 处置语义、假成功响应、静默零检查通过。如果其中一个失败,说明曾经存在的错误又回来了。

MIT

Available Tools

9 tools
canon_infoA

Show the resolved canon (palette size, regions with their rules and protection flags, scale table, thresholds) and optionally census a file against it — how many pixels each region matches, and how many match nothing (unmatched pixels mean your region definitions have gaps). Pass canonPath or censusFile — without either there is nowhere to search from (the server's working directory is the client's, not your project's).

NameRequiredDescriptionDefault
cellHNospritesheet cell height (PNG sheets only)
cellWNospritesheet cell width (PNG sheets only)
canonPathNopath to sprite-canon.json (default: search upward from the target file)
censusFileNocount region membership of this file's first frame (also used as the search origin for the canon)
listColorsNoinclude the full palette hex list
canon_initA

Create sprite-canon.json for a project: the single source of truth for palette, regions, scale and check thresholds. Learns the palette from sample images (colours used at least minCount times; rarer colours are usually anti-aliasing noise). Run once per project, then commit the file.

NameRequiredDescriptionDefault
dirYesproject directory to create sprite-canon.json in
nameNoproject name
cellHNospritesheet cell height (PNG sheets only)
cellWNospritesheet cell width (PNG sheets only)
minCountNomin occurrences for a colour to enter the palette (default 4)
sampleFilesNoPNG/GIF files or directories to learn the palette from
updatePaletteNorelearn just the palette of an EXISTING canon from sampleFiles (regions/scale/checks untouched)
canon_learnA

Define or update a named region in the canon (e.g. skin, hair, outfit, outline). Give a few [x,y] points on sample images; the sampled colours (optionally expanded by absorb) become the region. The region's luminance range is recorded — repaint uses that FIXED range so the same source colour always maps to the same output colour in every frame and direction. Mark regions like face/eyes/outline as protected: repaint will never touch them and verify will fail if anything else does. Instead of points you may pass explicit colors, or an HSL rule (hue/sat/light ranges) for anti-aliased art — an HSL-only region additionally needs lumRange if you ever want to repaint it. Updates MERGE additively into an existing region; pass replace=true to redefine it from scratch (the only way to remove a mis-sampled colour).

NameRequiredDescriptionDefault
hueNoHSL rule: hue range in degrees
satNoHSL rule: saturation range 0..1
cellHNospritesheet cell height (PNG sheets only)
cellWNospritesheet cell width (PNG sheets only)
lightNoHSL rule: lightness range 0..1
absorbNoalso absorb colours within this per-channel distance of sampled ones (default 0)
colorsNoexplicit hex colours instead of samples
regionYesregion name, e.g. 'skin' / 'outline' / 'cloak'
replaceNoredefine the region from scratch instead of merging (default false)
samplesNo
lumRangeNofixed luminance range (0-255) for repainting — required for HSL-only regions, auto-computed for colour lists
canonPathNopath to sprite-canon.json (default: search upward from the target file)
protectedNomark as protected (never repainted, verified untouched)
colors_inspectA

List the colours actually used in files, sorted by frequency, with luminance — the raw material for canon_init/canon_learn decisions. Use it to spot near-duplicate colours, anti-aliasing noise, and which hexes belong to which visual part before defining regions.

NameRequiredDescriptionDefault
topNohow many colours to list (default 40)
cellHNospritesheet cell height (PNG sheets only)
cellWNospritesheet cell width (PNG sheets only)
filesYes
gif_patchA

Operations on animated GIFs. 'palette' swaps colours in every colour table (global AND per-frame local — patching only the global table is a classic half-fix) without touching frame data: zero generation loss, every frame changes in perfect sync — the correct way to re-dress an indexed sprite. The response reports how many table entries each source colour actually matched; 0 means that hex isn't in the file (use colors_inspect to find the exact hexes). 'retime' re-times all frames to msPerFrame. GIF delays are quantised to 10ms steps with a 20ms minimum; pixels survive a decode/re-encode that is exact up to 255 opaque colours (beyond that, nearest-palette snapping). Real bug this fixes: an animation authored at 1.8s being cut off by game code that frees the sprite after 0.62s — retime the GIF instead of dropping frames.

NameRequiredDescriptionDefault
fileYes
actionYes
outFileYes
colorMapNofor 'palette': { fromHex: toHex, ... }
msPerFrameNofor 'retime': delay per frame in ms (quantised to 10ms steps, min 20ms)
sprite_measureA

Measure a sprite's anatomy per frame and its cross-frame jitter: bounding box, top row, widest row, cap (head) width, waist (neck) row, and — with canon regions — the first row of each region (e.g. where the face starts). Use before placing anything relative to a sprite: measured rows beat guessed proportions. Real bug this catches: a hat brim placed at '52% of head height' landed exactly on the eyes, because eye rows vary per frame — measure, don't assume.

NameRequiredDescriptionDefault
fileYesPNG / GIF / spritesheet
cellHNospritesheet cell height (PNG sheets only)
cellWNospritesheet cell width (PNG sheets only)
canonPathNopath to sprite-canon.json (default: search upward from the target file)
sprite_repaintA

Deterministically recolour a canon region onto a colour ramp (dark→light hex list) — the alternative to regenerating with AI and losing consistency. Shading survives (luminance maps onto the ramp using the region's FIXED recorded range), silhouettes never change, protected regions are never touched, and the same input always gives the same output. Use maskFromFile when repainting an already-recoloured variant: regions are matched on the original (identical pixel layout), paint is applied to the variant. Writes to outFile (never overwrites the input unless outFile equals it).

NameRequiredDescriptionDefault
fileYes
rampYeshex colours dark→light, e.g. ['4a3418','7a5628','a8813c','cfae6b']
rowsNorestrict painting to this row range [from,to]
cellHNospritesheet cell height (PNG sheets only)
cellWNospritesheet cell width (PNG sheets only)
regionYescanon region to repaint
outFileYes
canonPathNopath to sprite-canon.json (default: search upward from the target file)
maskFromFileNomatch the region on this file instead (same pixel layout)
sprite_sheetA

Compose a zoomed contact sheet (PNG on a checkerboard) from sprites — one row per file, one column per frame — and return it as an image so you can LOOK at what you just made. Judge consistency on sheets, not in-game: every visual defect we ever caught was caught on a sheet. Use crop to zoom into the area under suspicion (e.g. just the head).

NameRequiredDescriptionDefault
cropNocrop every cell to this rect before zooming
zoomNopixel zoom (default 4)
cellHNospritesheet cell height (PNG sheets only)
cellWNospritesheet cell width (PNG sheets only)
filesYesfiles or directories; each file becomes a row
outFileYeswhere to write the sheet PNG
maxFramesNomax frames per row (default 8)
returnImageNoalso return the sheet inline as an image (default true; sheets over ~800KB are returned as path only)
sprite_verifyA

Run numeric consistency checks and get hard pass/fail numbers — the replacement for eyeballing hundreds of frames. Checks: 'palette' (every pixel on the canon palette), 'jitter' (landmarks stay put across frames), 'spread' (a region's mean luminance agrees across a file group — catches 'bright from behind, dark from the front'), 'protected' (vs baseFile: face/outline pixels untouched), 'leftover' (vs baseFile: no source-region pixel survived inside a repainted area), 'scale' (relative sizes match the canon table). Files may be directories (all PNG/GIF inside).

NameRequiredDescriptionDefault
cellHNospritesheet cell height (PNG sheets only)
cellWNospritesheet cell width (PNG sheets only)
filesYesfiles or directories to verify
checksNowhich checks to run (default: palette + jitter)
regionNoregion name for 'spread'/'leftover'
baseFilesNooriginals for 'protected'/'leftover'. Paired to files by identical filename (case-insensitive) when names line up, otherwise by list position (equal lengths required). Each result echoes which base it was compared against.
canonPathNopath to sprite-canon.json (default: search upward from the target file)
scaleNamesNofor 'scale': map of filename -> name in canon.scale.heights

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections.

  1. 9 tool updatesv0.1.0
    • First observedcanon_info
    • First observedcanon_init
    • First observedcanon_learn
    • First observedcolors_inspect
    • First observedgif_patch
    • First observedsprite_measure
    • First observedsprite_repaint
    • First observedsprite_sheet
    • First observedsprite_verify

TDQS

A4.2/5.0

Scored across 9 tools

Disambiguation4/5

Each tool has a clearly different job: inspecting colors, defining canon, measuring sprites, verifying, repainting, compositing sheets, and patching GIFs. The only mild overlap is between sprite_repaint and gif_patch palette swapping, but their contexts (canon region remapping vs. indexed GIF color tables) are distinct enough to avoid real confusion.

Naming Consistency4/5

Names follow a clear snake_case pattern of a domain prefix (colors, canon, sprite, gif) plus an action or noun. Minor grammatical inconsistency exists (colors_inspect, canon_info, sprite_sheet are noun-heavy while canon_learn and sprite_repaint are verb-focused), but the overall convention is predictable and readable.

Tool Count5/5

Nine tools is a well-scoped set for a sprite canon workflow: each tool covers a distinct step from inspection and canon creation to measurement, verification, repainting, contact sheets, and GIF operations. Nothing feels redundant or missing at the count level.

Completeness4/5

The suite covers the full workflow: inspect, initialize canon, define regions, measure, verify, repaint, and generate contact sheets. Minor gaps exist, such as no explicit tool for deleting or renaming a region, and global canon settings like scale/thresholds can only be managed through init or by editing the file directly.

Maintenance

ActivityStale
ResponsivenessNo recent community issues

Related MCP Connectors

Related MCP Servers

  • A
    license
    Not graded
    quality
    C
    maintenance
    Enables AI coding agents to create, draw, and refine Aseprite documents through deterministic canvas, layer, frame, tag, and palette tools, with pixel analyzers, style validation, and preview/diff visual feedback. It also supports spritesheet and animated GIF export, producing multi-layer game-ready assets.
    1
    MIT
  • A
    license
    A
    quality
    B
    maintenance
    Enables agents to author, validate, inspect, patch, and render editable JSON pixel-art and animation recipes through local tools, producing PNG contact sheets, APNGs, sprite atlases, and related export bundles.
    2
    8
    1,388 npm
    47
    MIT
  • A
    license
    Not graded
    quality
    B
    maintenance
    Enables AI agents to create layered pixel-art sprites and animations, inspect pixels, and export images, spritesheets, GIFs, APNGs, and TrueType pixel fonts. Documents and edits stay local, accessible over stdio MCP or callable directly from a shell.
    26
    MIT