English | 中文
把一张 2D 立绘自动拆成部件、生成骨架、导出成 Spine 工程的本地工具。
上传一张图 → AI 判断有哪些部件、谁压着谁 → 像素级切图 → 生成骨骼层级 → 一键导出成
目标平台的 Spine 资源(Cocos / Unity / Spine 编辑器各版本),外加一个能直接进 Spine
编辑器二次编辑的 .spine 工程。
做 2D 游戏(尤其是带骨骼动画的角色)时,美术把一张立绘手工拆成头、身体、手臂、配饰……再 在 Spine 里建骨骼、绑权重、调绘制顺序,是个重复且耗时的活。这个工具把这段自动化:
| 步骤 | 手工做 | 这个工具 |
|---|---|---|
| 拆部件 | 抠图软件里一块块抠 | AI 判断部件清单 + 像素级分割 |
| 定层级 | 逐个想谁是谁的父级 | 按遮挡关系自动推断 |
| 建骨骼 | 手动摆放、对旋转中心 | 从部件 bbox 和姿态推出 pivot |
| 做网格 | 沿接缝手动连线刷权重 | 栅格剖分 + 环带缝合,接缝共享权重 |
| 补遮挡 | 手工仿制图章补被压住的部分 | 图像生成模型按上下文补图 |
| 导出 | 逐个骨架/图集配置 | 一键出多目标格式 |
它不是"一键出成品动画",它产出的是一个干净、可继续编辑的工程起点:部件分好了、 层级建好了、权重刷好了,美术拿到手是接着调网格和 K 帧,而不是从空白开始。
质量取决于源图。角色立绘(部件边界清晰、遮挡关系明确)效果最好; 部件互相穿插得很碎、或大量半透明的图,需要人工收尾。
每个阶段都有自己的质量门:过不了就在阶段内重试,不把烂结果往下游传。
原始图片
│
▼
阶段 0:场景理解 视觉模型
│ ├─ 有哪些部件、谁压着谁
│ ├─ BBox(粗定位)/ Pivot(关节)
│ ├─ Parent(层级)/ Depth(绘制顺序)
│ └─ 多边形轮廓(可选,SAM 的回退路径用)
│ │
│ JSON 被截断(stop_reason=max_tokens)→ 加大 token 重来一次
▼
阶段 1:切图 / 分层 MobileSAM(可选)
│ ├─ 把 BBox 当 prompt 喂给 SAM → 逐像素 Mask
│ │ 没装 SAM 就退回阶段 0 给的多边形,流程不中断
│ ├─ 掩码唯一归属:重叠像素归 depth 最大者
│ ├─ 掩码夹回自己的框内(防小配件擦掉大部件)
│ ├─ 无主像素按连通性认领,并撑开窗口
│ ├─ 导出 RGBA 图 + 边缘扩散
│ └─ 写 .erased.png:被本部件遮挡的真实像素(阶段 2 的真值)
│ │
│ 对齐诊断 → 写进生成日志,不自动重切
▼
阶段 2:遮挡补图 图像生成模型(可选)
│ ├─ 被压住的地方在切图上是透明的洞
│ ├─ 补全遮挡区域 / 修复边缘 / 保持画风一致
│ ├─ 被盖住的那片直接贴 .erased.png 真值,不让模型照着遮挡者再画
│ └─ 单轮接口失败 → 退避重试 3 次(只重试临时故障码)
│ │
│ 孔洞守卫按像素数补砸比例(近白/近黑/中暗色填充 = 补砸)
│ ┌────┴────┐
│ │ │
│ > 2% ≤ 2%,或已跑满 2 轮
│ │ │
│ ▼ ▼
│ 重补一轮 留最好的那一轮(不是最后一轮)
│(从原始切图重来,不在补砸结果上接着补)
▼
阶段 3:生成骨骼
│ ├─ Bone:拓扑序 + 一根合成 root(Spine 编辑器只认单根)
│ ├─ Mesh:栅格剖分 + 环带缝合
│ ├─ Weight:接缝两侧共享权重,每顶点 ≤ 4 根骨骼
│ ├─ Pivot → 骨骼原点,像素坐标 → Spine 坐标(居中、Y 翻转)
│ └─ Slot 按 depth 排序 = 绘制顺序
▼
阶段 4:动画 + 导出
│ ├─ 生成 idle(幅度压在 1.5° 内,转多了接缝会露)
│ ├─ 按目标平台转格式:Cocos / Unity / Spine 4.0–4.2
│ │ 版本差异:3.8 用 angle、4.0+ 用 value;skins 一个是对象一个是数组
│ ├─ 打图集、权重内联进 vertices 流
│ └─ 调 Spine 编辑器 CLI 生成 .spine
│ │
│ ┌────┴────┐
│ │ │
│ CLI 拒绝 成功
│ │ │
│ ▼ ▼
│ 错误写进 产物落盘
│ README.txt (见「导出产物结构」)
│ │ │
│ └────┬────┘
▼ ▼
在预览区看拼装与 idle → 导出 Spine 资源
| 阶段 | 解决的问题 | 不做会怎样 | 质量门 |
|---|---|---|---|
| 0 场景理解 | 图里有哪些部件、谁压着谁 | 不知道该切成几块 | JSON 截断就重来 |
| 1 切图 / 分层 | 每个部件的精确像素边界 | 切图互相重叠,转动时穿插 | 对齐诊断写日志 |
| 2 遮挡补图 | 被压住的区域是空的 | 部件一转就露洞 | 补砸比例 > 2% 重补 |
| 3 生成骨骼 | 层级、旋转中心、绘制顺序、接缝权重 | 动起来全乱、接缝裂开 | 纯计算,无门 |
| 4 动画 + 导出 | 变成目标平台能加载的格式 | 进不了项目 | Spine CLI 拒绝就报错 |
底板与孔洞兜底(_base_plate + 补图守卫)贯穿阶段 2:拼不上的缝由整图尺寸的底板遮住,
近白/近黑/中暗色的填充判定为补砸并换成邻域真值——不做就是底板黑块和切图白点。
核心流程只需要 Node + 一个 API Key,其余全是可选增强:
| 功能 | 需要什么 | 不要它会怎样 |
|---|---|---|
| AI 分析部件 | 必需:一个视觉模型 API Key | 工具无法工作 |
| 切图 / 拼装 / 骨架 / 导出 | 必需:Node 20+ | 工具无法工作 |
| 像素级分割 | 可选:MobileSAM(约 800MB)或 SAM 3(约 4GB) | 回退到多边形蒙版,边界略糙但能用 |
| 遮挡补图 | 可选:一个图像生成模型 | 被压住的区域留透明,部件单独看有洞 |
.spine 源工程 |
可选:本机装了 Spine 4.x 编辑器 | 目标平台资源照常产出,只是没有可二次编辑的工程 |
也就是说:npm install + 填 API Key 就能跑出目标平台能直接加载的资源。剩下三项按需再装,
任意一项缺失都只影响对应的那一个产出,不会让整条流程失败。
# 1. 依赖
npm install
# 2. 配置 API(二选一)
cp .env.example .env
# 然后编辑 .env,填 ANTHROPIC_API_KEY
# 用自建网关/中转服务的,再填 ANTHROPIC_BASE_URL
# 也可以不建 .env,直接在网页界面里填
# 3. 启动
npm run web
# → http://localhost:3000无需任何 Python 环境、无需 Spine 编辑器即可产出可用工程。
可选增强(按需):
# 像素级分割:自动建虚拟环境 + 拉模型权重(约 800MB,一次性)
npm run sam:setup && npm run sam:check
# 或者换成 SAM 3(约 4GB,需要 Python 3.10+):
# npm run sam3:setup && npm run sam3:check
# 然后在 .env 里设 SPINE_SEGMENTER=sam3
# .spine 源工程:装好 Spine 4.x 编辑器即可,会自动找常见安装位置
# 装在别处就设 SPINE_CLI_PATH两个分割器怎么选:
| MobileSAM(默认) | SAM 3 | |
|---|---|---|
| 提示方式 | 框(bbox) | 文本(部件名) |
| 速度 | 每部件 10~25ms | 每部件约 4.5s |
| 环境大小 | 585MB | 4GB(含 3.4GB 权重) |
| Python | 3.9 | 3.10+ |
| 擅长 | 大块部件 | 细碎部件(眼镜、眼睛、耳环) |
MobileSAM 只吃框,而框里几乎总装着好几件东西,它只挑最显眼的那件——实测
眼镜的框里它挑中整张脸。SAM 3 用文本提示绕开这个问题,给 glasses 就是眼镜。
所以换 sam3 是为了治具体的病,不是普遍升级:默认保持 mobilesam,只在 细碎部件被切错时切过去。两台环境互不影响,可以都装、随时切。
网页「5. 网格与补图」里有对应的单选控件,点了立刻生效(不用重启),并写回
.env 让下次启动还记得。没装的那个会自动置灰并显示安装命令。
SAM 3 权重是 SAM License(不是本项目的 Apache-2.0),官方仓库在 HuggingFace 上是需要审批的 gated 仓库。安装脚本只从 ModelScope 镜像拉到 你自己机器上、不随仓库分发,用之前请自行确认许可条款。
| # | 在界面上做什么 | 背后发生什么 |
|---|---|---|
| 1 | 上传立绘 PNG | 读出尺寸,建立像素坐标系 |
| 2 | 输入提示词,描述部件结构与旋转中心 | 提示词质量直接决定部件表质量,见下 |
| 3 | 选目标平台(Cocos 3.8 / Unity / Spine 4.0–4.2) | 决定骨架版本号、旋转字段名和 skins 形状 |
| 4 | 点「生成」 | 走阶段 0→3,日志面板实时输出 |
| 5 | 在预览区看拼装结果、切播放看 idle 动画 | 有缝/有异色就能立刻发现 |
| 6 | 点「导出」 | 走阶段 4,产出目标平台资源 + .spine |
工具自带四类提示词模板(角色 / 道具 / 特效 / 物品),在界面上点「2. 提示词」旁的
设置按钮可以改,模板存在 config/prompt-templates.json。
写提示词的关键是描述结构和旋转中心,而不是描述画面内容:
✅ 好的写法
一个女角色,左手叉腰、右手拿剪刀。
包含:头、发髻、眼镜、身体、围裙、左臂、右臂(含剪刀)、鞋。
头部绕脖子旋转;手臂绕肩膀旋转;围裙绕腰部旋转。
绘制顺序:身体 → 围裙 → 手臂 → 头 → 发髻 → 眼镜。
❌ 差的写法
一个生气的女人
(没说有哪些部件、没说层级、没说旋转中心)
四套模板都在 config/prompt-templates.json,界面上可改。它们管的不是「画什么」,
而是怎么拆、怎么定父子、pivot 放哪:
| 模板 | 拆解思路 | pivot 规则 | 部件数 |
|---|---|---|---|
| 角色类 | 躯干为根;服装按由内到外分层;手与手持道具必须合并(分开必定缺块) | 头在颈部底端、上臂在肩、前臂在肘、手在腕 | 6~15 |
| 道具类 | 主体为根;按真实运动拆(能转的轮子、能扣的扳机) | 放在真实旋转轴上 | 4~10 |
| 特效类 | 按距离核心的远近分层,最外层画在最上 | 基本都在几何中心,缩放/旋转时向外扩散才自然 | 3~8 |
| 物品类 | 只拆需要动的部分,纯装饰的整体一个部件 | 铰链/转轴位置 | 1~5 |
三套规则在四类模板里是共通的,写在模板正文里:
- 层级:口诀「盖人的当儿子,被盖的当父亲」——被遮住的当父级(先画),遮人的当子级(后画)
- bbox 外扩:边缘比可见内容再外扩 3~5 px 把轮廓线包进来,宁可多框 5 px 不少框 1 px
- pivot:写在真实的关节上,不是部件的几何中心
下面这组是仓库里 test_assets/12.png 跑完整条流程用的配置,界面上每个字段都对应得到:
| 项 | 值 |
|---|---|
| 分析模型 | claude-opus-5(视觉模型,出部件表) |
| 提示词模板 | 物品类——「好漂亮的水果拼盘」 |
| 补图模型 | gpt-image-2(同步接口,可带 mask 传本地图) |
| 像素级分割 | MobileSAM,权重约 40 MB |
| 网格粒度 | 8(每个部件的栅格剖分密度) |
| 输出目录 | ./output/generated |
| 导出目标 | cocos-3.8(骨架 3.8.75,旋转字段用 angle) |
| 产物 | 7 个部件 → 5 个加权网格 + 2 个 region;图集 1024×436 |
| 动画 | 只有 idle |
gpt-image-2是网关侧的模型码,不是我们要绑定的东西——换服务商时它和白名单 一起在界面上重选,config/api-defaults.json里只放接入点地址。
output/<工程名>/
│
├── <输入图名>_temp/ ← 中间产物,重跑补图要用,导出不会清掉
│ └── Image/
│ ├── <部件>.png 切图
│ ├── <部件>.erased.png 被遮挡区域的真实像素(补图真值)
│ ├── <部件>.front.png 该部件在别人前面的部分
│ └── verify-input.json 校验用输入快照
│
└── <输入图名>/
├── Spine工程/
│ └── <输入图名>.spine ← 可直接用 Spine 编辑器打开,二次编辑用
│
└── <目标格式>/ cocos-3.8 / unity / spine-4.2 ...
└── <输入图名>/
├── <输入图名>.json 骨架
├── <输入图名>.atlas 图集描述
├── <输入图名>.png 图集页
├── images/ 散图(回编辑器改网格时用)
└── README.txt 这次导出的参数与结果摘要
为什么中间产物单独放 _temp/:补图重跑、重新切图都要读它,导出时清掉就得重跑一遍
昂贵的 AI 流程。每个导出目标各占一层目录,是因为 3.8 和 4.x 的骨架/图集格式互不兼容,
平铺会互相覆盖——重导 Cocos 时 Unity 那份原封不动。
| 层 | 用了什么 | 为什么 |
|---|---|---|
| 运行时 | Node.js 20+(ESM) | 全程无构建步骤,改完直接跑 |
| Web 服务 | Express + SSE | SSE 推日志流,流水线进度实时可见 |
| 图像处理 | sharp | 原生 libvips,切图/拼装/合成都是毫秒级 |
| 视觉理解 | Claude 视觉模型 | 要它输出结构化 JSON(部件表),不只是描述画面 |
| 遮挡补图 | 图像生成模型(可选) | 补被压住的区域 |
| 像素级分割 | MobileSAM(可选,Python) | bbox 当 prompt 出精确掩码 |
| 编辑器交互 | Spine CLI(可选) | .spine 是私有二进制格式,只能由官方 CLI 生成 |
| 浏览器测试 | Playwright(dev) | 界面回归测试 |
| 前端 | 原生 JS,无框架 | 单页面工具,上框架是负担 |
为什么不用 SAM 硬撑着,而是留一条多边形回退路径:SAM 要装 800MB 的 Python 环境, 很多人只想先看看效果。回退路径用 AI 直接给的多边形,精度差一点但零依赖, 让人在决定要不要装之前就能跑通全流程。
为什么 .spine 不自己生成:它是 Spine 私有的二进制工程格式(raw-deflate 包裹标记流),
没有公开规范,各 4.x 小版本之间都会变。照着反推写一份,编辑器升级就静默读坏——
比不产出更糟。所以走官方支持的 CLI。
为什么用 SSE 而不是 WebSocket:日志是单向的,SSE 够用且自带重连,少一层握手。
所有配置项在 .env(参考 .env.example,已 gitignore)。
| 变量 | 默认 | 说明 |
|---|---|---|
ANTHROPIC_API_KEY |
空 | API Key,必填(也可在界面里填) |
ANTHROPIC_BASE_URL |
空 | 留空直连 Anthropic 官方;用自建网关/中转服务就填它的地址 |
PORT |
3000 |
监听端口 |
OUTPUT_DIR |
./output |
产物根目录 |
SPINE_CLI_PATH |
自动查找 | Spine 编辑器可执行文件 |
SPINE_SAM_HOME |
~/.spine-tool/mobilesam |
MobileSAM 环境位置 |
SPINE_SAM3_HOME |
~/.spine-tool/sam3 |
SAM 3 环境位置 |
SPINE_SEGMENTER |
mobilesam |
用哪个分割器:mobilesam / sam3 |
换 API 接入点:改 config/api-defaults.json 一处即可——界面表单的默认值从那里取,
不用在代码里翻找。.env 里的设置优先级更高,只影响本机。
Q: 需要联网吗? 分析、补图、分割都要调模型,需要联网。切图、拼装、骨架生成、导出全在本地。
Q: 不装 MobileSAM 能用吗? 能。会自动回退到多边形蒙版,边界精度低一些,但流程完整。想对比效果可以先不装跑一遍。
Q: 生成的部件被切坏了 / 有黑块白点怎么办? 先看日志面板里有没有补图失败的记录;「重跑补图」按钮可以只重跑失败的那些。 补图守卫会把近白、近黑、中暗色的填充判定为补砸并替换成邻域真值。
Q: 生成的骨架缺件 / 层级不对? 绝大多数是提示词的问题——回到第 2 步把部件清单、层级、旋转中心写清楚再生成。 也可以直接在界面上改提示词模板。
Q: 能在 Spine 里直接打开导出结果吗?
.json 是导入进 Spine(新建工程再导入),.spine 才是打开。
两者都在导出目录里,.spine 在 Spine工程/ 下。
Q: 支持哪些输入格式? PNG / JPG / WebP。要透明背景的话建议用 PNG。
Q: 为什么会生成 _base_plate 这个部件?
它是整图大小的兜底层,用来遮住部件之间拼不上的细缝。如果不需要,可以在提示词里
要求不要底板,或生成后手动删掉。
| 文档 | 内容 |
|---|---|
| Web 服务用法 | 界面各步骤详解、提示词技巧、环境变量 |
| 背景移除与补图 | 补图流程的完整技术细节与踩坑记录 |
| 基于深度的擦除 | 部件隔离为什么按 depth 决定归属 |
| MobileSAM 可行性验证 | 为什么选 MobileSAM、实测数据、提示策略对比 |
docs/notes/ 下是排查记录,记录某个问题当时是怎么查、怎么量的。想知道某个设计
决定为什么这么定,通常能在那里找到当时的实测数据。
npm install # 装依赖
npm run web # 启动服务
npm test # 单元测试
npm run test:e2e # 端到端(真跑 AI,慢)
npm run test:shot # 界面截图回归
npm run verify # 校验产物结构
npm run shot # 截预览图
npm run check # 环境自检
npm run sam:check # MobileSAM 环境状态
npm run sam3:setup # 装 SAM 3(约 4GB)
npm run sam3:check # SAM 3 环境状态server/
├── index.js HTTP 路由 + SSE 日志流
├── generate-cli.js 命令行入口
├── ai/
│ ├── claude.js 视觉理解:图 → 部件表
│ ├── models.js 模型清单
│ ├── image-models.js 图像生成模型清单
│ └── api-defaults.js 接入点默认值(读 config/api-defaults.json)
├── api/
│ ├── cutter.js 切图:掩码 → 独立 PNG
│ ├── isolate.js 部件隔离:重叠归属、无主像素认领
│ ├── mesh.js 栅格剖分 + 环带缝合
│ ├── generator.js 骨架与动画生成
│ ├── targets.js 目标格式适配(3.8 / 4.x 形状差异)
│ ├── atlas.js 图集打包
│ ├── spine-project.js Spine CLI 交互,生成 .spine
│ ├── inpaint.js 遮挡补图
│ ├── background.js 背景移除
│ ├── baseplate.js 底板兜底
│ ├── workspace.js 目录结构(唯一一份落点算法)
│ └── env-file.js .env 读写
└── sam/ MobileSAM 集成(可选)
├── client.mjs 常驻进程客户端
├── worker.py Python worker
└── setup.mjs 一键装环境
web/ 前端(原生 JS,无框架)
src/ 独立的 Spine 读写库(JSON/Binary 解析、往返、校验)
scripts/ 工具脚本
docs/ 文档与配图
config/ prompt-templates.json、api-defaults.json
temp/test/ 测试
npm test # 快,不碰网络
npm run test:e2e # 慢,真调 API,验证完整链路src/ 下的 Spine 读写库可以独立使用——它不依赖 server,做骨架格式转换很方便。
第三方组件(MobileSAM、sharp、Playwright 等)不随本仓库分发,装的时候各自从上游拉,
各自的协议见 NOTICE。.spine 是调本机已装的 Spine 编辑器 CLI 生成的,
本仓库不包含也不转发 Spine 编辑器的任何代码。
