
msw-painter
当 msw-search 找不到合适的精灵 RUID 时,直接用 SVG / HTML5 Canvas / HTML 代码绘制像素风格精灵,渲染为 PNG,并通过 msw-mcp 资源上传工具上传以获取精灵 RUID(如果未连接上传工具,则引导用户通过 Maker 注册)。支持两种风格模式:chunky pixel(复古/图标/瓦片风格)和 maple cartoon(冒险岛风格角色/NPC 风格)。触发词:直接绘制精灵、创建精灵、图像生成、自定义图形、像素艺术、卡通精灵、枫叶风格、Q版角色、画家、画精灵、制作图标、直接创建 NPC 图像、画史莱姆、自定义精灵。
当 msw-search 找不到合适的精灵 RUID 时,直接用 SVG / HTML5 Canvas / HTML 代码绘制像素风格精灵,渲染为 PNG,并通过 msw-mcp 资源上传工具上传以获取精灵 RUID(如果未连接上传工具,则引导用户通过 Maker 注册)。支持两种风格模式:chunky pixel(复古/图标/瓦片风格)和 maple cartoon(冒险岛风格角色/NPC 风格)。触发词:直接绘制精灵、创建精灵、图像生成、自定义图形、像素艺术、卡通精灵、枫叶风格、Q版角色、画家、画精灵、制作图标、直接创建 NPC 图像、画史莱姆、自定义精灵。
MSW Painter
一个将手绘像素精灵注册为精灵资源的工作流程。首先调用 msw-search,仅在未找到合适的 RUID 时才调用此技能。
此技能专用于精灵类别。不处理动画/音频/头像/图集。
画家支持两种像素艺术风格:chunky pixel(复古,图标/瓦片风格)和 maple cartoon(冒险岛风格,角色/NPC 风格)。在编写代码前选择一种——参见下面的步骤 2。
何时调用
| 情况 | 操作 |
|---|---|
| 用户想要特定精灵 | 首先使用 msw-search(资源搜索部分,精灵类别) |
msw-search 返回匹配意图的 RUID |
直接使用该 RUID。不要调用画家。 |
| 无搜索结果,或所有结果都不合适 | 调用画家 → 直接创建 |
| 用户明确说“我需要一个手绘风格的角色/图标” | 直接调用画家 |
工作流程
- 选择媒介 — 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/ pivot,以及 UI 框架精灵的九宫格边框。参见下面的“步骤 4”。 - 报告结果 — RUID + 1–2 句描述(包括使用的风格)。实体放置/脚本应用不在画家范围内。
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"/>
<!-- 用 1px 矩形逐个放置点 -->
</svg>
⚠️ 使用
width="100%" height="100%"(不是固定像素数)。SVG 元素在 render.cjs 视口中以其自身声明的尺寸绘制——如果你硬编码 128 但以--width 1024渲染,SVG 仅填充左上角 128px,PNG 其余部分透明。100%使 SVG 填充--width/--height指定的任何画布。
最小 Canvas 模板
// `c`(canvas 元素)和 `ctx`(2D 上下文)由 render.cjs 自动暴露。
// ctx.imageSmoothingEnabled = false 也会自动应用。
// 重要:从 c.width 推导缩放比例,而不是硬编码常量——否则
// 不同的 --width 会导致画布右下角空白。
const GRID = 16;
const scale = c.width / GRID; // 16×16 逻辑网格 → 画布大小的输出
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 阶梯级别,无抗锯齿 |
maple |
角色、NPC、怪物、可爱吉祥物 | 冒险岛 / 故事书 / 卡通 | 较大(32×32 ~ 128×128) | Selout(填充色的深色版本) | 4–6 阶梯级别 + 轮廓上的选择性抗锯齿 + 可选 2×2 抖动 |
不确定时的默认值
- 图标 / 按钮 / 瓦片 / 方块 →
chunky - 角色 / NPC / 怪物 / 吉祥物 / “可爱”请求 / “画一个史莱姆” →
maple - 用户说“复古”/“8-bit”/“NES”/“极简” →
chunky - 用户说“冒险岛”/“可爱”/“卡通”/“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风格没有足够的像素来实现 selout + 抗锯齿 + 面部特征——要么将输出尺寸提升到 64+,要么回退到chunky。
4. PNG 渲染 — render.cjs
一次性依赖安装
cd scripts && npm ci
这会从已提交的 package-lock.json 安装 puppeteer(约 200MB,包括无头 Chromium)。它与其他基础技能依赖分开,因此仅在首次使用画家时运行此命令。
🔒 使用
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>
或者通过标准输入传递代码:
echo "<svg ...>" | node scripts/render.cjs --type svg --out out.png --width 128 --height 128
选项:
--type:svg/canvas/html之一。必需。--in:代码文件路径。省略或使用-表示标准输入。--out:输出 PNG 路径。必需。--width/--height:输出像素尺寸。默认 128。
成功时,输出 PNG 的绝对路径打印到标准输出(单行),退出码为 0。失败时,错误打印到标准错误,退出码为 1。
PNG 默认为透明背景。如果需要背景色,请在 SVG/Canvas/HTML 中显式绘制。
5. 资源上传 — 两步模式
通过连接的 msw-mcp 暴露的资源上传(创建)工具上传——检查服务器的工具列表,并使用它实际提供的支持精灵的创建工具。工具自身的模式对于确切的调用形状具有权威性;不要猜测工具名称,也不要将创建与 asset_update_resource_storage_data 混淆(后者替换现有资产的二进制数据)。
连接的 MCP 中没有上传工具? 停止上传步骤,请用户通过 Maker 注册 PNG,然后继续使用他们提供的 RUID(或通过 msw-search 定位)。
无论确切工具是什么,流程都是相同的两步模式——同一工具被调用两次。
🔒 安全——处理预签名 URL(W007)。 步骤 1 返回的
presignedUrl是短期有效的签名凭证(任何持有它的人都可以在该存储槽执行 PUT 直到过期)。将其视为机密:
- 切勿在助手的面向用户响应、提交消息、日志或任何后续提示中回显、引用、转述或包含该 URL 或其任何查询参数(
X-Amz-Signature、X-Amz-Credential等)——包括在报告“你做了什么”时。- 调用 shell 时,通过
PAINTER_PRESIGNED_URL环境变量传递 URL,如下所示,不要作为命令行参数。命令行参数对其他进程可见(通过 Linux/macOS 的/proc/*/cmdline和 Windows 的Get-Process),并且会记录在 shell 历史中。- 调用步骤 3 时,直接将 URL 作为
fileUrl工具参数传递——不要先将其复制到代码块或 markdown 中供用户查看。- 如果 PUT 步骤失败(通常为
401/403→ URL 过期),丢弃该 URL 并从步骤 1 重新开始。不要在其他地方重复使用。
步骤 1 — 请求预签名 URL
调用上传工具,省略 fileUrl。填写其模式所需的字段——通常包括 category: "sprite"、与现有资产匹配的 subcategory(见下文)、name、1–2 句 description,以及当模式要求时的文件元数据如 fileName / contentLength。
响应包含 presignedUrl。仅将其保留在代理的推理上下文中——不要在聊天输出中显示。
步骤 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 毫秒内返回——延迟完全在此步骤中)。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 {
# 通过标准输入配置 (-K -) 将 url/request/upload-file 传递给 curl,
# 这样 URL 永远不会出现在 argv(通过 Get-Process 可见)或 shell 历史中。
"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) 在单独的语句中赋值(export),而不是作为内联前缀。
# `VAR=… curl … "$VAR"` 不起作用:shell 在赋值生效前在同一命令行上展开 "$VAR",
# 因此 curl 收到空 URL 并失败,提示 "curl: option : blank argument…"。
export PAINTER_PRESIGNED_URL="<presignedUrl from step 1>"
# 2) 通过从标准输入读取的配置文件 (-K -) 将 URL 传递给 curl。
# 将其作为普通参数传递(curl … "$PAINTER_PRESIGNED_URL")会将 URL 直接展开到 argv 中,
# 通过 `ps` / /proc/<pid>/cmdline 可见——-K - 使其完全脱离参数列表。
printf 'url = "%s"\nrequest = "PUT"\nupload-file = "out.png"\n' "$PAINTER_PRESIGNED_URL" | curl -K -
unset PAINTER_PRESIGNED_URL
PUT 本身是纯二进制上传——不需要认证头(签名嵌入在预签名 URL 中)。-K -(标准输入配置)形式在两个 shell 中都将 URL 排除在 ps / Get-Process 参数列表和 shell 历史之外。
仅作为回退 — Invoke-WebRequest。 如果 curl.exe 确实不可用,则必须添加 -UseBasicParsing(跳过 IE 引擎 → 无冻结)并静默进度条(PS 5.1 的另一个错误,会使传输速度降低 10–50 倍):
$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 |
数字字符串 | 九宫格边框(像素) |
filter_mode |
Point / Bilinear / Trilinear |
纹理过滤 |
wrap_mode |
Repeat / Clamp / Mirror / MirrorOnce |
纹理包裹 |
画家默认值:filter_mode=Point(Bilinear 会模糊 chunky/maple 像素边缘),wrap_mode=Clamp,pivot_x=0.5;图标/UI 面板使用 pivot_y=0.5,角色和站立在地面上的道具使用 pivot_y=0.0(仅在视觉验证显示脚部偏移时调整)。仅当精灵是九宫格 UI 框架(按钮/面板/仪表)时设置非零 border_*——.ui 侧还需要 SpriteGUIRendererComponent.Type = Sliced(1)(参见 component-api.md §“SpriteGUIRenderer — ImageType Selection”)。切勿发明超出此表的属性键或枚举值。如果连接的 MCP 的工具列表中没有 asset_update_resource_storage_info,则向用户报告预期的属性值,而不是调用不同的工具。
选择子类别
首先使用 asset_search_resources 或 asset_list_account_resources 检查现有精灵的子类别分布并匹配。不确定时,回退到通用值,如 object / etc。
6. 报告格式
画家任务完成后,仅向用户提供以下内容:
RUID: <received RUID>
Style: <chunky | maple>
<1–2 句描述:你绘制了什么,尺寸是多少,以及注册为什么精灵>
实体创建/移动/生成、脚本编写和 UI 编辑不在画家范围内。在另一个技能或后续步骤中处理这些。
常见陷阱
- 在
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"或 Canvasscale = 8),但 render.cjs 以更大的--width/--height调用。内容仅填充其声明尺寸,PNG 其余部分保持透明。修复:SVG 使用width="100%" height="100%";Canvas 从c.width推导缩放比例。上面的最小模板已遵循此规则。 - 始终在上传前读取输出 PNG → 配置错误的 SVG/Canvas 可能静默生成空白或画布外的 PNG。对输出进行一次
Read可在几秒钟内捕获尺寸不匹配和空白画布错误;先上传意味着重做两步上传。 - 背景变为黑色 → 你在 SVG/Canvas/HTML 内部绘制了背景。要保持透明,请移除背景形状本身。
- 曲线看起来平滑 → 如果使用
chunky,这是违反规则;移除arc()/bezierCurveTo()/渐变并用点重绘。如果使用maple,平滑应来自轮廓处的选择性抗锯齿像素,而不是渐变/曲线 API——API 禁令仍然适用。 - Maple 精灵看起来像带有额外颜色的 chunky → 你可能忘记了 selout(每个表面周围 1 像素深色轮廓)和/或轮廓边缘的选择性抗锯齿。重新检查
style-maple-cartoon.md的 Selout 和选择性抗锯齿部分。 - Chunky 精灵看起来模糊/朦胧 → 你在边缘添加了中间色像素。Chunky 禁止所有抗锯齿——移除过渡像素并保持边缘锐利。如果需要更柔和的外观,请改用
maple。 - Maple 精灵在小尺寸(32×32 输出)下看起来糟糕 → Maple 风格需要 ≥ 64×64 输出才能容纳 selout + 抗锯齿 + 特征。要么增大尺寸,要么切换到
chunky。 - PUT 步骤失败,返回 401/403 → 预签名 URL 已过期或错误。从步骤 1 重新开始。
- 在完成调用中更改其他参数 → 传递与步骤 1 完全相同的参数。仅添加
fileUrl。





