关于 msw-painter
msw-painter 是为 MSW 项目创建并注册手绘像素风精灵资源的工作流,涵盖风格选择、PNG 渲染和资源上传。
主要功能
- 01使用 SVG、Canvas 或 HTML 绘制
- 02提供 Chunky 和 Maple 风格
- 03按精灵类型参考尺寸
- 04将作品渲染为 PNG
- 05上传并注册精灵资源
- 06从种子图衍生一致变体
适用场景
- 01制作图标、地块或简单道具
- 02绘制角色、NPC 或怪物
- 03制作一组相关精灵变体
MCP 相关
它通过已连接的 msw-mcp 上传工具创建精灵资源并更新存储属性。若没有可用的上传工具,则引导用户通过 Maker 注册 PNG。
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ msw-git/ msw-ai-coding-plugins-official --skill msw-painter安装后在 Claude Code 中输入/msw-painter确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
references/size-guide.mdstyle-chunky-pixel.mdstyle-maple-cartoon.mdscripts/package.jsonrender.cjs详细介绍
MSW Painter
将手绘像素艺术精灵图注册为精灵图资源的工作流。请先调用 msw-search,只有在未找到合适的 RUID 时,才调用此技能。
此技能专用于精灵图类别,不处理动画/音频/头像/图集。
Painter 支持两种像素艺术风格:chunky pixel(复古、图标/图块风格)和 maple cartoon(受 MapleStory 启发,角色/NPC 风格)。编写代码前先选择一种,参见下方步骤 2。
何时调用
| 情况 | 操作 |
|---|---|
| 用户想要特定的精灵图 | 先使用 msw-search(资源搜索部分,精灵图类别) |
msw-search 返回符合需求的 RUID | 直接使用该 RUID。不要调用 Painter。 |
| 没有搜索结果,或所有结果都不合适 | 调用 Painter → 直接创建 |
| 用户明确表示“我需要一个看起来像手绘的角色/图标” | 直接调用 Painter |
工作流
- 选择媒介 — SVG / Canvas / HTML 任选其一。参见下方“选择媒介”。
- 选择风格 —
chunky或maple。参见下方“选择风格”。 - 确定尺寸 — 参见 references/size-guide.md。默认值为 128×128。
- 编写代码 — 遵循所选风格的规则:
chunky→ references/style-chunky-pixel.mdmaple→ references/style-maple-cartoon.md
- 渲染为 PNG — 运行
scripts/render.cjs。 - 上传资源 — 使用 msw-mcp 资源上传工具,采用两步预签名模式(§5)。如果已连接的 MCP 没有上传工具,请让用户通过 Maker 注册 PNG。
- 注册精灵图属性 — 上传后立即调用
asset_update_resource_storage_info:设置filter_mode/wrap_mode/枢轴点,并为 UI 边框精灵图设置 9-slice 边框。参见下方“步骤 4”。 - 报告结果 — RUID + 1–2 句描述(注明使用的风格)。实体放置/脚本应用不属于 Painter 的职责范围。
1. 选择媒介
| 媒介 | 推荐用途 | 优势 |
|---|---|---|
| SVG | 图标、徽标、简单角色、基于形状的像素艺术 | 代码直观,便于添加 1px 的 <rect> 点 |
| Canvas | 程序化图案、迭代逻辑(循环绘制纹理/噪声) | 可通过 JS 编程逻辑生成复杂图案 |
| HTML | 可通过 CSS 快速设置样式的复合布局 | 很少使用——SVG/Canvas 通常更适合像素艺术 |
最简 SVG 模板
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"
width="100%" height="100%" preserveAspectRatio="xMidYMid meet"
style="image-rendering: pixelated;">
<rect x="6" y="2" width="1" height="1" fill="#4A90D9"/>
</svg>
⚠️ 使用
width="100%" height="100%"(不要使用固定像素值)。SVG 元素会在 render.cjs 视口内按其自身声明的尺寸绘制——如果将尺寸硬编码为 128,但渲染时使用--width 1024,SVG 只会填充左上角的 128px,其余 PNG 区域将是透明的。使用100%可让 SVG 填充--width/--height指定的整个画布。
最简 Canvas 模板
// `c` (canvas element) and `ctx` (2D context) are auto-exposed by render.cjs.
// ctx.imageSmoothingEnabled = false is applied automatically as well.
// IMPORTANT: derive scale from c.width, not a hard-coded constant — otherwise
// a different --width leaves the bottom-right of the canvas blank.
const GRID = 16;
const scale = c.width / GRID; // 16×16 logical grid → canvas-sized output
ctx.fillStyle = '#4A90D9';
ctx.fillRect(6 * scale, 2 * scale, scale, scale);
最简 HTML 模板
<!doctype html>
<html><body style="margin:0; image-rendering: pixelated;">
</body></html>
2. 选择风格
| 风格 | 推荐用途 | 观感 | 逻辑网格 | 轮廓 | 阴影 |
|---|---|---|---|---|---|
chunky | 图标、按钮、图块、方块、简单道具 | 复古/8-bit/NES-SNES | 小(16×16、32×32) | 黑色或白色,1px | 2–4 级阶梯式明暗,禁止 AA |
maple | 角色、NPC、怪物、可爱吉祥物 | MapleStory/童话书/卡通 | 较大(32×32 ~ 128×128) | Selout(填充色的深色版本) | 4–6 级阶梯式明暗 + 在轮廓上选择性 AA + 可选 2×2 抖动 |
犹豫时的默认选择
- 图标/按钮/地砖/方块 →
chunky - 角色/NPC/怪物/吉祥物/“可爱”类请求/“画一只史莱姆” →
maple - 用户说“复古”/“8-bit”/“NES”/“极简” →
chunky - 用户说“MapleStory”/“可爱”/“卡通”/“Q 版”/“插画风” →
maple
各风格的完整规则:
两种风格使用相同的禁用 API(不使用曲线 API、渐变 API、小数坐标、filter: blur/drop-shadow)。它们在调色板丰富度、轮廓颜色、抗锯齿和工作网格方面有所不同。
3. 尺寸指南(摘要)
| 用途 | 推荐尺寸 |
|---|---|
| 图标/按钮 | 48×48 ~ 64×64 |
| 角色/物品/NPC/怪物 | 96×96 ~ 128×128 |
| 地砖/地板/方块 | 64×64 ~ 128×128 |
| 背景/大型物体 | 256×256 或更大(仅在明确要求时) |
默认尺寸为 128×128。有关各风格专用的工作网格表(chunky 使用类似 16×16 的小型逻辑网格;maple 使用类似 64×64 的大型逻辑网格)和 SD 角色比例,请参阅 references/size-guide.md。
如果请求的输出尺寸小于 64×64,
maple风格就没有足够的像素来呈现轮廓色、抗锯齿和面部特征——要么将输出尺寸提高到 64+,要么改用chunky。
3.5 多精灵图组——从同一个种子派生每个变体
当一个请求需要多个相关精灵图时——例如帧序列(行走 1/2/3、攻击姿势)、图标系列或同一角色的状态变体——切勿从头绘制每张精灵图。即使提示词重复使用相同描述,独立绘制的精灵图在尺寸、调色板和基线方面也会出现偏差。
- 先绘制一张种子精灵图,渲染并验证它(读取 PNG),然后再处理组内其余精灵图。
- 通过编辑种子代码的副本派生所有其他精灵图——保持逻辑网格、调色板常量、轮廓处理、剪影/比例和锚点一致;只更改姿势/内容。角色以底部中心为锚点,这样整组的脚就能保持在同一基线上。
- 渲染所有 PNG,并在上传任何文件之前并排读取它们。如果某个变体出现偏差(尺寸/调色板/基线),请从种子代码重新派生——不要修补已出现偏差的输出。
- 将每个 PNG 作为独立精灵图上传(§5),使用相同的名称前缀(
Slime_Walk_01、Slime_Walk_02,……),并一并报告所有 RUID(§6)。
对于帧序列,请事先告知用户限制:上传工具无法创建 animationclip,因此各帧会成为 N 个独立的精灵图 RUID;播放时需要脚本定时切换 SpriteRendererComponent.SpriteRUID。若要使用无需脚本即可播放的原生动画片段,用户必须自行通过 Maker 导入这些帧。
4. PNG 渲染——render.cjs
一次性安装依赖
cd scripts && npm ci
此操作会根据已提交的 package-lock.json 安装 puppeteer(包括无头 Chromium 在内约 200MB)。它与其他基础技能依赖分开,因此仅在首次使用 painter 时运行。
🔒 使用
npm ci,不要使用npm install。npm ci会严格安装package-lock.json中锁定的版本;如果锁文件与package.json不一致,则会失败——这是 W012 的供应链完整性保障。切勿手动编辑package-lock.json;如果需要升级 puppeteer,请在本地运行npm install puppeteer@<version>,并提交重新生成的锁文件。
沙箱与网络隔离
默认情况下,render.cjs 会在启用操作系统沙箱的状态下运行无头 Chromium,并阻止渲染页面发起所有网络请求。页面还会通过 data: URL 提供,并设置严格的 Content-Security-Policy(default-src 'none');SVG / HTML 输入也会经过清理,以移除 <script>、<foreignObject>、内联 on* 处理程序和非 data: URL。无需执行任何操作即可启用这些保护——它们始终处于开启状态。
如果你处于 Chromium 无法启动沙箱的受限环境中(某些 CI 容器、特定的 WSL 配置),请在调用 render.cjs 前设置 PAINTER_DISABLE_SANDBOX=1。请勿在开发者工作站上设置此项。
调用
node scripts/render.cjs --type <svg|canvas|html> --in <code-file> --out <out.png> --width <W> --height <H>
或者通过 stdin 传递代码:
echo "<svg ...>" | node scripts/render.cjs --type svg --out out.png --width 128 --height 128
选项:
--type:svg/canvas/html之一。必填。--in:代码文件的路径。省略此项或使用-表示 stdin。--out:输出 PNG 路径。必填。--width/--height:输出像素尺寸。默认值为 128。
成功时,输出 PNG 的绝对路径会以单行形式打印到 stdout,退出代码为 0。失败时,错误会打印到 stderr,退出代码为 1。
PNG 默认使用透明背景。如需背景色,请在 SVG / Canvas / HTML 内显式绘制。
5. 资源上传——两步模式
通过已连接的 msw-mcp 所提供的资源上传(创建)工具进行上传——检查服务的工具列表,并使用它实际提供的支持精灵图的创建工具。工具自身的 schema 是确切调用格式的权威依据;不要猜测工具名称,也不要将创建操作与 asset_update_resource_storage_data 混淆(该工具会替换现有资源的二进制数据)。
已连接的 MCP 中没有上传工具? 停止上传步骤,请用户改为通过 Maker 注册 PNG,然后使用用户提供的 RUID 继续(或通过 msw-search 查找 RUID)。
无论具体使用哪个工具,流程都是相同的两步模式——同一个工具会调用两次。
🔒 安全——处理预签名 URL(W007)。 第 1 步返回的
presignedUrl是短期有效的签名凭据(任何持有该 URL 的人都可以在它过期前向该存储位置执行 PUT)。请将其视为机密:
- 绝不在面向用户的助手回复、提交消息、日志或任何后续提示词中回显、引用、转述或包含该 URL 或其任何查询参数(
X-Amz-Signature、X-Amz-Credential等),包括报告“你做了什么”时。- 调用 shell 时,请按下方所示通过
PAINTER_PRESIGNED_URL环境变量传递 URL,不要将其作为命令行参数。其他进程可以通过/proc/*/cmdline(Linux/macOS)和Get-Process(Windows)查看命令行参数,而且这些参数会记录在 shell 历史中。- 调用第 3 步时,请直接将 URL 作为工具参数
fileUrl传递——不要先将它复制到代码块或 Markdown 中让用户看到。- 如果 PUT 步骤失败(通常是
401/403→ URL 已过期),请丢弃该 URL,并从第 1 步重新开始。不要在其他地方重用它。
第 1 步——请求预签名 URL
调用上传工具时省略 fileUrl。填写其 schema 要求的字段——通常包括 category: "sprite"、与现有资源匹配的 subcategory(见下文)、name、1–2 句话的 description,以及 schema 要求的文件元数据,例如 fileName / contentLength。
响应中会包含 presignedUrl。仅在 Agent 的推理上下文中保留该 URL——不要在聊天回复中透露。
步骤 2 — PUT PNG 二进制文件(通过环境变量传递 URL)
⚡ 使用
curl.exe,不要使用Invoke-WebRequest(P001 — “上传后冻结”问题)。 在 Windows PowerShell 5.1 中,除非传入-UseBasicParsing,否则Invoke-WebRequest会通过 Internet Explorer 引擎解析 HTTP 响应。IE 已在 Windows 11 上移除/禁用,因此调用会卡在 IE 的“首次启动配置”上;即使字节已经上传完毕,看起来仍会长时间冻结(MCP 工具本身约 45 ms 即返回——卡顿完全发生在此步骤)。curl.exe(随 Windows 10 1803 及更高版本和所有 Windows 11 一同提供,位于System32中)不依赖 IE,并且在 PowerShell 和 Git Bash 中的行为一致,因此这两种 Shell 中都优先使用它。
PowerShell(首选 — curl.exe):
$env:PAINTER_PRESIGNED_URL = "<presignedUrl from step 1>"
try {
# Feed url/request/upload-file to curl via a stdin config (-K -) so the URL
# never lands in argv (visible via Get-Process) or shell history.
"url = `"$env:PAINTER_PRESIGNED_URL`"`nrequest = `"PUT`"`nupload-file = `"out.png`"" | curl.exe -K -
} finally {
Remove-Item Env:\PAINTER_PRESIGNED_URL -ErrorAction SilentlyContinue
}
bash(适用于 Git for Windows / WSL — curl):
# 1) Assign on its OWN statement (export), NOT as an inline prefix.
# `VAR=… curl … "$VAR"` does NOT work: the shell expands "$VAR" on the
# same command line BEFORE the assignment takes effect, so curl receives
# an empty URL and fails with "curl: option : blank argument…".
export PAINTER_PRESIGNED_URL="<presignedUrl from step 1>"
# 2) Feed the URL to curl via a config file read from stdin (-K -). Passing it
# as a normal argument (curl … "$PAINTER_PRESIGNED_URL") would expand the URL
# straight into argv, where it is visible via `ps` / /proc/<pid>/cmdline —
# -K - keeps it out of the argument list entirely.
printf 'url = "%s"\nrequest = "PUT"\nupload-file = "out.png"\n' "$PAINTER_PRESIGNED_URL" | curl -K -
unset PAINTER_PRESIGNED_URL
PUT 本身是纯二进制上传——不需要身份验证标头(签名已嵌入预签名 URL 中)。两种 Shell 中的 -K -(stdin 配置)形式都会避免 URL 出现在 ps / Get-Process 参数列表和 Shell 历史记录中。
仅作备用方案 — Invoke-WebRequest。 如果确实无法使用 curl.exe,则必须添加 -UseBasicParsing(跳过 IE 引擎 → 不会冻结),并关闭进度条(另一个会使传输速度降低 10–50 倍的 PS 5.1 问题):
$env:PAINTER_PRESIGNED_URL = "<presignedUrl from step 1>"
$ProgressPreference = 'SilentlyContinue'
try {
Invoke-WebRequest -Method PUT -InFile out.png -Uri $env:PAINTER_PRESIGNED_URL `
-ContentType "image/png" -UseBasicParsing
} finally {
Remove-Item Env:\PAINTER_PRESIGNED_URL -ErrorAction SilentlyContinue
}
步骤 3 — 报告上传完成
使用相同参数再次调用同一工具,并添加 fileUrl,其值设为步骤 1 中的预签名 URL(直接将其作为工具参数传入——不要将其回显到聊天或代码块中)。
响应中包含精灵图的 RUID。这就是最终交付内容。此调用返回后,将该 URL 视为已完全使用——不要保留它。
步骤 4 — 注册精灵图属性
创建工具不接受 properties——步骤 3 返回 RUID 后,立即使用资源的 guid 调用 mcp__msw-mcp__asset_update_resource_storage_info。属性条目使用小写的 { "key": "...", "value": "..." },且值必须是字符串(资源响应会显示 Properties: [{ "Key", "Value" }]——输入时不要照搬这种大小写)。
| 键 | 值 | 含义 |
|---|---|---|
pivot_x / pivot_y | 数字字符串 | 精灵图轴心点 |
border_left / border_right / border_top / border_bottom | 数字字符串 | 9-slice 边框宽度,单位为 px |
filter_mode | Point / Bilinear / Trilinear | 纹理过滤 |
wrap_mode | Repeat / Clamp / Mirror / MirrorOnce | 纹理环绕 |
Painter 默认值:filter_mode=Point(Bilinear 会使块状 / 枫叶像素边缘变模糊),wrap_mode=Clamp,pivot_x=0.5;图标 / UI 面板的 pivot_y=0.5,站立在地面上的角色和道具的 pivot_y=0.0(只有目视验证发现脚部偏移时才调整)。仅当精灵图是 9-slice UI 框架(按钮 / 面板 / 仪表)时,才将 border_* 设为非零值——.ui 一侧还需要 SpriteGUIRendererComponent.Type = Sliced(1)(参见 component-api.md §“SpriteGUIRenderer — 图像类型选择”)。切勿使用此表之外的属性键或枚举值。如果已连接的 MCP 工具列表中没有 asset_update_resource_storage_info,请向用户报告计划使用的属性值,而不要改用其他工具。
选择子类别
首先使用 asset_search_resources 或 asset_list_account_resources 检查现有精灵图的子类别分布,并与之匹配。如有疑问,请使用 object / etc 等通用值。
6. 报告格式
Painter 任务完成后,只向用户提供以下内容:
RUID: <received RUID>
Style: <chunky | maple>
<1–2 sentence description: what you drew, at what size, and what sprite it was registered as>
对于 §3.5 集合,将 RUID: 行替换为集合中每个精灵图各占一行的 <sprite name>: <RUID>;Style 和描述保持为单项,涵盖整个集合。
实体创建 / 移动 / 生成、脚本编写和 UI 编辑不属于 Painter 的范围。请在其他技能或后续步骤中处理这些内容。
常见问题
- 运行
render.cjs前未运行npm ci→Cannot find module 'puppeteer'。仅首次需要。使用npm ci(而非npm install),以安装锁文件指定版本的 puppeteer。 - 省略
--width/--height→ 会回退到 128×128;如果用户想要其他尺寸,就必须重新绘制。务必指定尺寸。 - SVG/Canvas 内容只绘制在 PNG 的左上角 → 绘图代码声明了自身尺寸(例如 SVG 的
width="128" height="128"或 Canvas 的scale = 8),但调用 render.cjs 时指定的--width/--height更大。内容只会填满声明的尺寸,其余 PNG 区域保持透明。解决方法:SVG 使用width="100%" height="100%";Canvas 根据c.width推导缩放比例。上面的 Minimal 模板已采用这种做法。 - 上传前务必读取输出 PNG → 配置错误的 SVG/Canvas 可能会悄无声息地产生空白 PNG 或画布外 PNG。读取一次输出即可在几秒内发现尺寸不匹配和空白画布问题;先上传就意味着要重做两步上传流程。
- 背景显示为黑色 → 你在 SVG/Canvas/HTML 中绘制了背景。要保持透明,请移除背景图形本身。
- 曲线看起来很平滑 → 如果使用
chunky,这违反了规则;请移除arc()/bezierCurveTo()/渐变,并改用圆点绘制。如果使用maple,平滑效果应来自轮廓上的选择性 AA 像素,而非渐变/曲线 API——API 禁令仍然适用。 - Maple 精灵图看起来像加了更多颜色的 chunky → 你可能忘记了 selout(每个表面周围 1 像素的深色轮廓)和/或轮廓边缘的选择性 AA。请重新检查
style-maple-cartoon.md中的 Selout 和 Selective AA 部分。 - Chunky 精灵图看起来模糊不清 → 你在边缘添加了中间色像素。Chunky 禁止使用任何抗锯齿——请移除过渡像素,并保持边缘清晰。如果想要更柔和的效果,请改用
maple。 - 小尺寸(32×32 输出)的 Maple 精灵图效果不佳 → Maple 风格至少需要 64×64 的输出尺寸,才能容纳 selout、AA 和细节。请增大尺寸或改用
chunky。 - 一组精灵图出现偏差(不同变体间的尺寸 / 调色板 / 基线发生变化) → 它们是分别绘制的。请使用共享的网格/调色板/锚点常量(§3.5),从已批准的种子代码重新推导每个变体;上传前还要并排重新检查整组图。
- PUT 步骤失败,返回 401/403 → 预签名 URL 已过期或有误。请从步骤 1 重新开始。
- 更改完成调用中的其他参数 → 传入与步骤 1 完全相同的参数。只添加
fileUrl。