Files
SpineParticlesWeb/Document/导出设计标准规范.md
2026-09-02 10:45:10 +08:00

22 KiB
Raw Permalink Blame History

SpineParticle · Spine JSON 导出设计标准规范

文档性质:导出功能开发、验收与后续维护的唯一对齐基线
规范状态:已完成产品规则对齐,导出设置面板已实现,JSON 导出逻辑尚未开始
目标格式:Spine JSON 4.2
主要用途:将导出 JSON 重新导入 Spine 编辑器继续编辑
最后更新:2026-08-31


一、规范目的

本规范用于固定 SpineParticle 的 Spine JSON 导出范围、骨架结构、动画烘焙、资源引用、拖尾蒙皮、关键帧压缩和导出设置语义,避免后续开发因上下文丢失或实现人员变化而偏离已确认规则。

后续实现若与本文冲突,应先重新确认并更新本文,不能仅在代码中改变既定语义。


二、导出目标与边界

2.1 导出目标

导出结果是一个能够由 Spine 4.2 识别,并能重新导入 Spine 编辑器继续编辑的 JSON 骨架动画文件。

导出数据必须满足:

  1. 粒子表现不依赖 SpineParticle 编辑器运行时;
  2. 粒子、序列帧、颜色、透明度、缩放、旋转、拖尾等表现被转换为 Spine 原生骨骼、插槽、附件与动画时间轴;
  3. 与其他场景模块发生关联的粒子表现必须烘焙为独立动画数据;
  4. 文件结构优先兼顾可编辑性、动画精度和合理体积;
  5. 导出后使用 Spine 4.2 Runtime 进行结构解析验证。

2.2 导出内容

只导出场景中的粒子系统相关内容:

  • 粒子系统骨骼;
  • 粒子图片插槽和 Region 附件;
  • 粒子位移、旋转、缩放动画;
  • 粒子颜色和透明度动画;
  • 粒子图片与序列帧附件切换;
  • 拖尾骨骼链;
  • 拖尾加权 Mesh、颜色、透明度和资源切换;
  • 项目中的“所属动画”及其粒子时间轴。

2.3 不导出的内容

以下场景对象本身不进入 JSON

  • 碰撞体;
  • 路径;
  • 已加载的 Spine 对象;
  • 原 Spine 对象中的骨骼、插槽、皮肤、图片和动画;
  • 编辑器辅助线、网格、背景图、骨骼预览点和调试显示。

这些模块若影响了粒子运动,必须只烘焙其最终结果,不能在导出 JSON 中保留对原对象的引用。

2.4 场景显隐规则

  • 场景对象小眼睛关闭的粒子系统不导出;
  • 显示状态正常的粒子系统参与导出;
  • 碰撞、路径和 Spine 对象无论是否显示都不作为对象导出;
  • 若可见粒子系统的模拟依赖有效的碰撞、路径或 Spine 跟随,其最终影响仍应被烘焙。

三、格式依据与版本规则

3.1 格式依据

实现时依次以以下内容作为格式依据:

  1. Spine 官方 GitHub 仓库中的 Spine 4.2 JSON 示例;
  2. 项目当前使用的 @esotericsoftware/spine-core 4.2.119 JSON 解析器;
  3. 项目已有的 Spine 4.2 官方导出样本;
  4. Spine 官方 JSON 格式说明。

官方中文说明中的部分示例仍使用 Spine 3.8,不能直接照搬旧版字段。实现必须重点核对 Spine 4.2 的:

  • skins 结构;
  • rgba 插槽时间轴;
  • attachments 动画结构;
  • 加权 Mesh 顶点编码;
  • 附件切换;
  • 多动画结构;
  • Draw Order 字段命名;
  • Sequence 附件及时间轴结构。

3.2 版本范围

第一版只支持:

Spine 4.2

设置面板保留下拉框,以便以后扩展版本,但第一版不得提供没有真实兼容实现的 4.0、4.1 或其他版本选项。


四、整体 JSON 结构

导出 JSON 的主要结构为:

skeleton
bones
slots
skins
animations

不输出无关约束、碰撞体或路径附件。

推荐骨架层级:

root
├─ ParticleSystem1
│  ├─ _particle_000
│  ├─ _particle_001
│  ├─ _particle_000_trail_1_0
│  │  └─ _particle_000_trail_1_1
│  │     └─ ...
│  └─ ...
└─ ...

每个粒子系统必须作为 root 下的独立父骨骼,粒子骨骼统一使用简洁的 _particle_000 样式并归入对应系统。所有骨骼、插槽和附件名称仍须全局唯一;多系统发生重名时只为后续同名骨骼追加最短编号后缀。


五、Setup Pose 标准

5.1 普通骨骼

除拖尾子骨骼链外,所有导出骨骼的 Setup Pose 使用统一默认值:

x = 0
y = 0
rotation = 0
scaleX = 1
scaleY = 1

粒子系统在编辑器中的位置、旋转和缩放不写入普通骨骼 Setup Pose,必须进入对应动画时间轴。

5.2 拖尾骨骼链例外

拖尾是加权 Mesh 的绑定骨骼链。为了保证导入 Spine 后初始蒙皮结构正确:

  • 拖尾链保持正常父子层级;
  • 子骨骼保留合理的绑定位置和骨骼长度;
  • 子骨骼不能全部重叠在原点;
  • 动画帧中的拖尾世界状态转换为相对父骨骼的局部位移和局部旋转;
  • 拖尾链根独立于粒子图片骨骼的旋转和缩放,避免粒子图片变换意外污染拖尾蒙皮。

5.3 Setup Pose 可见性

所有蒙皮绑定完成后的粒子 Region 和拖尾 Mesh 在 Setup Pose 中默认透明度为 0,避免导入 Spine 后干扰已有图像显示。

动画开始后,由附件切换和 rgba 时间轴恢复正确图片、颜色与透明度。


六、粒子到 Spine 数据的映射

SpineParticle 数据 Spine 4.2 数据
粒子系统 系统根骨骼
粒子池槽位或独立出生粒子 粒子骨骼
粒子图片 Region 附件
粒子图片显示层 Slot
粒子位置 Bone Translate Timeline
粒子旋转 Bone Rotate Timeline
粒子缩放 Bone Scale Timeline
粒子颜色与透明度 Slot RGBA Timeline
粒子出生、死亡、假死 Attachment 与 RGBA Timeline
多图片资源 同一 Slot 下的多个 Region 附件
序列帧 Attachment Timeline 切换 Region
混合模式 Slot Blend
拖尾 加权 Mesh + 拖尾骨骼链
拖尾颜色与透明度 拖尾 Slot RGBA Timeline
所属动画 animations 下的动画名称

七、粒子骨骼与对象池

7.1 开启骨骼对象池

开启时:

  • 按粒子系统最大同时存活数量建立固定粒子骨骼池;
  • 粒子死亡后骨骼可供后续粒子复用;
  • 图片 Slot 和对应拖尾骨骼链随粒子骨骼一起复用;
  • 文件骨骼数量和时间轴体积应显著小于不复用模式;
  • 复用前后通过 Attachment 和 RGBA 关键帧明确隐藏、显示及切换资源。

7.2 关闭骨骼对象池

关闭时:

  • 每一次逻辑粒子出生建立独立骨骼;
  • 已死亡粒子的骨骼不再分配给后续粒子;
  • 动画较长或发射率较高时允许产生大量骨骼;
  • 界面无需阻止,但导出前可以提示预计骨骼数量和文件体积。

7.3 循环动画例外

纯循环持续动画必须保证循环衔接帧两端的粒子身份稳定。即使关闭对象池,也必须为跨越循环接缝的粒子维持稳定骨骼映射,避免循环首尾出现身份跳变。


八、图片与序列帧

8.1 图片文件

导出功能不复制、不下载、不嵌入 PNG,也不生成 Atlas。

JSON 只负责输出正确的图片资源路径。用户将在 Spine 中重新扫描并指定图片文件夹。

禁止把以下编辑器内部地址写入附件路径:

  • Data URL
  • Blob URL
  • 浏览器临时对象地址;
  • 本机绝对文件路径。

8.2 图片路径

设置中的图片路径,例如:

./images/

写入 skeleton.images

附件 path 只写相对于图片文件夹的资源路径,不重复附加 ./images/。附件路径应:

  • 保留资源子文件夹结构;
  • 统一使用 /
  • 清理重复的 ./
  • 使用稳定文件名;
  • 默认使用不含图片扩展名的 Spine 资源路径;
  • 检测并提示重复路径。

8.3 图片缺失

图片缺失不阻止导出。

  • 仍然输出对应 Region 或 Mesh 附件;
  • 保留用户可识别的文件名和路径;
  • Spine 中允许显示缺失图片,用户可根据文件名补充文件;
  • 能取得图片原始尺寸时写入真实尺寸;
  • 完全无法取得尺寸时写入安全占位尺寸并给出提示;
  • 缺图、路径重复或占位尺寸属于警告,不直接取消 JSON 下载。

8.4 图片尺寸、缩放和锚点

  • Region width/height 使用图片原始像素尺寸;
  • 粒子资源缩放已经体现在粒子骨骼 Scale 动画中,不得重复乘到图片尺寸;
  • Pixi 锚点转换为 Region 相对骨骼中心的偏移;
  • 转换时必须处理 Spine 数学坐标 Y 向上与 Pixi 屏幕坐标 Y 向下的差异;
  • 实现后必须使用非中心锚点和旋转状态进行视觉对照。

8.5 序列帧

一组序列帧始终只使用一根粒子骨骼,不因图片数量增加骨骼。

第一版不依赖 Spine 原生 Sequence 命名约束,而采用:

  • 每张序列图片建立独立 Region 附件;
  • 使用 Attachment Timeline 切换当前 Region
  • 按烘焙后的最终图片索引输出,不在导出端重新推演播放模式。

需要完整支持:

  • 单次-尾帧消失;
  • 单次-尾帧固定;
  • 正向循环;
  • 反向循环。

九、拖尾加权 Mesh 标准

9.1 禁止项

拖尾不得使用逐帧 attachments → deform 时间轴作为正式导出方案。

9.2 正式结构

拖尾直接转换为:

拖尾骨骼链 + 加权 Mesh + 骨骼动画

复用项目现有拖尾数据:

  • trailGridRows / trailGridCols 生成网格拓扑;
  • 当前三角形索引写入 triangles
  • 当前 UV 与图片旋转写入 uvs
  • trailSkinWeights 中的 boneA / boneB / weight 转换为 Spine 加权 Mesh 顶点编码;
  • trailState.bones 转换为拖尾骨骼链动画;
  • 拖尾资源切换使用同一拖尾 Slot 下的多个 Mesh 附件和 Attachment Timeline
  • 拖尾颜色和透明度使用拖尾 Slot 的 RGBA Timeline。

9.3 拖尾动画映射

  • 拖尾长度由骨骼链各节点位置体现;
  • 拖尾方向由骨骼旋转体现;
  • 拖尾宽度由骨骼垂直缩放体现;
  • 拖尾形状曲线进入 Mesh 的绑定顶点分布;
  • 拖尾图片旋转进入 UV
  • 拖尾头部必须与粒子最终渲染位置一致;
  • 每帧世界状态转换为父子骨骼局部状态后再写入时间轴。

9.4 权重标准

  • 每个顶点使用项目已有的相邻骨骼影响关系;
  • 每个顶点权重和必须在允许误差内等于 1;
  • 骨骼索引必须对应最终 bones 数组顺序;
  • 不允许引用不存在或被排除的骨骼;
  • 导出后需要检查弯曲、宽度变化、资源旋转和粒子旋转情况下的拖尾形态。

十、外部关联烘焙

10.1 通用规则

所有导出动画先执行一次独立、确定性的离线烘焙:

  1. 使用当前粒子系统随机种子重置模拟;
  2. 按导出 FPS 逐帧推进;
  3. 计算路径跟随、Spine 骨骼跟随、碰撞和全部修改器;
  4. 记录粒子和拖尾最终渲染状态;
  5. 将外部对象影响转换为系统根或粒子骨骼动画;
  6. JSON 中不保留任何外部对象引用。

10.2 碰撞

  • 不导出碰撞体;
  • 碰撞造成的位置、速度方向、暂停、销毁和反弹结果进入最终粒子动画;
  • 碰撞突变前后必须保留关键帧,不能跨越突变进行平滑压缩。

10.3 路径跟随

  • 不导出路径对象或 Path Constraint
  • 本地空间跟随烘焙为系统根运动与粒子局部运动;
  • 世界空间跟随烘焙为粒子最终世界运动,已出生粒子不能错误继承后续路径移动;
  • 路径方向和旋转表现按画布最终结果写入。

10.4 Spine 骨骼跟随

  • 不导出原 Spine 对象或原目标骨骼;
  • 跟随位置和用户设置的偏移进入最终动画;
  • 不额外继承原 Spine 骨骼的缩放和旋转,保持编辑器现有语义;
  • 目标失效时按编辑器当前默认回退逻辑处理。

10.5 坐标空间

不能只读取粒子局部快照直接输出。每帧必须组合:

粒子局部状态
+ 系统根变换
+ 当前帧跟随目标产生的有效变换
= 最终可导出状态

同时统一处理 Pixi Y 向下与 Spine Y 向上的坐标转换、旋转方向和父子局部变换。


十一、动画归属与时长

11.1 多动画

一个 JSON 包含项目中的多个“所属动画”:

"animations": {
  "animation": {},
  "animation2": {},
  "start": {},
  "loop": {},
  "end": {}
}
  • 每个粒子系统只写入它所属的动画;
  • 多个粒子系统可以属于同一动画;
  • 同一动画时长取参与导出的粒子系统中最长者;
  • 较短系统到达末帧后保持符合自身模式的末帧状态;
  • Spine、碰撞体和路径自身时长不参与导出动画时长计算。

11.2 空动画

空动画是否保留遵循“排除无内容动画”设置:

  • 设置关闭:所属动画列表中的空动画仍输出为 {}
  • 设置开启:没有任何可见粒子动画内容的动画不写入 JSON。

11.3 循环持续三段动画

  • 启动段、纯循环段和结束段按用户当前保存的状态导出;
  • 循环衔接帧的粒子身份和视觉状态必须稳定;
  • 纯循环段保留假死粒子的骨骼身份,并通过附件隐藏或透明度 0 表现死亡;
  • 循环首尾接缝不得因关键帧精简产生卡顿或突变;
  • 延迟时间保持现有循环持续语义;
  • 所属动画命名继续沿用编辑器已有逻辑,不由导出器自动改名。

11.4 时间端点

  • 时间为 frameIndex / exportFps
  • 时间轴包含可选择的最后端点帧;
  • 循环动画允许保留首尾相同的末端点;
  • 时长不足完整导出帧时按规则向上取整,不能截断最长寿命粒子或拖尾。

十二、关键帧烘焙与压缩

12.1 总体策略

采用:

完整逐帧烘焙 → 分类 → 安全精简 → 误差验证

不能先减少采样再模拟,也不能简单每隔固定帧保留一帧。

12.2 离散数据

以下数据不能进行数值插值,只保留变化点并使用阶跃语义:

  • 粒子出生和死亡;
  • 图片显示和隐藏;
  • 粒子图片资源切换;
  • 序列帧附件切换;
  • 拖尾资源切换;
  • 混合模式变化;
  • 假死状态切换。

连续多帧相同附件或相同状态只输出第一次变化关键帧。

12.3 连续数据

以下数据先逐帧烘焙,再进行误差受控精简:

  • 粒子位置;
  • 粒子旋转;
  • 粒子缩放;
  • 粒子颜色和透明度;
  • 拖尾骨骼位置;
  • 拖尾骨骼旋转;
  • 拖尾宽度缩放。

精简器检查删除中间关键帧后,Spine 插值结果是否仍在误差范围内。采用以下视觉容差:

数据 建议容差
粒子位置 0.05–0.1 像素(当前实现取 0.1)
拖尾骨骼位置 0.05–0.1 像素(当前实现取 0.1)
旋转 0.01°
缩放 0.01
透明度 0.01
RGB 单通道 1/255

出生、死亡、附件切换、碰撞突变和循环接缝仍强制保留,不允许跨边界压缩。

12.4 强制保留点

以下位置不得跨越压缩:

  • 粒子出生帧;
  • 粒子死亡帧;
  • 附件显示、隐藏和切换帧;
  • 碰撞、反弹、暂停和销毁前后;
  • 运动方向突然变化处;
  • 拖尾出现和消失处;
  • 循环首尾衔接区域;
  • 延迟段和正式运动段边界;
  • 旋转角度展开产生的边界。

12.5 旋转处理

压缩前先进行角度展开。例如:

358° → 1° → 4°

应转换为:

358° → 361° → 364°

避免 Spine 插值时反向旋转一整圈。

12.6 插值曲线设置

  • 线性 (Linear):连续数据使用线性插值和线性误差精简;
  • 平滑贝塞尔 (Smooth Bézier):对连续段拟合贝塞尔,并逐帧检查误差;
  • 贝塞尔拟合不满足容差时必须增加关键帧,不能牺牲精度;
  • 离散数据、突变点、碰撞边界和循环接缝不受平滑贝塞尔设置影响。

十三、导出设置标准

导出设置是全局编辑器设置,不属于单个粒子系统。必须参与:

  • 保存配置;
  • 加载配置;
  • 预设加载;
  • 撤回;
  • 旧配置默认值补齐。

13.1 设置项与默认值

设置 默认值 规则
图片路径 ./images/ 写入 skeleton.images
Spine 版本 Spine 4.2 第一版唯一选项
关键帧插值曲线 线性 (Linear) 可切换平滑贝塞尔
导出 FPS 30 支持 1240 的正整数
不写 fps 关闭 只省略 skeleton.fps 元数据
整数帧对齐 开启 关键帧位于导出 FPS 的整数帧网格
骨骼对象池 开启 复用粒子骨骼和拖尾链
排除无内容动画 关闭 关闭时保留空动画 {}
默认文件名 SpineParticle.json 浏览器处理重复下载名称

13.2 导出 FPS 语义

修改导出 FPS 时保持动画实际秒数不变。

例如:

30f / 30 FPS = 1 秒
60f / 60 FPS = 1 秒

不能在导出 60 FPS 时仍只输出 30 帧并把动画缩短为 0.5 秒。

“不写 fps”仅省略 Spine JSON 中的 FPS 元数据,内部烘焙、采样和时间换算仍使用导出 FPS。

13.3 整数帧对齐

开启时:

time = integerFrame / exportFps

不能产生小数帧位置。无法整除的尾端时长向上取整,同时保持需要完成的粒子生命周期和拖尾状态。


十四、命名与文件规则

14.1 默认文件名

SpineParticle.json

14.2 名称安全

导出器必须:

  • 为系统、粒子、拖尾、Slot 和 Attachment 生成稳定名称;
  • 处理空名称、重复名称和非法路径分隔符;
  • 保留用户所属动画名称;
  • 不在没有必要时修改用户可见的图片文件名;
  • 保证同一配置、同一种子和同一导出设置产生稳定命名。

十五、代码结构标准

导出功能必须使用独立文件,不能把大量逻辑继续堆入 ParticlePanel.vueStage.vue 或 Store。

推荐结构:

src/export/
├─ spineExportSettings.ts
├─ spineJsonTypes.ts
├─ particleExportBaker.ts
├─ spineMeshBuilder.ts
├─ spineKeyframeReducer.ts
├─ spineJsonExporter.ts
└─ spineJsonValidator.ts

职责:

  • spineExportSettings.ts:导出设置类型、默认值和旧配置补齐;
  • spineJsonTypes.tsSpine 4.2 JSON 类型;
  • particleExportBaker.ts:确定性逐帧模拟和外部关联解除;
  • spineMeshBuilder.ts:拖尾骨骼链、权重、UV 和三角形生成;
  • spineKeyframeReducer.ts:离散合并和连续时间轴误差精简;
  • spineJsonExporter.ts:组装 Skeleton、Bones、Slots、Skins 和 Animations
  • spineJsonValidator.ts:导出前后结构验证和警告。

界面中的“导出Spine Json”按钮只负责调用导出入口、显示结果和下载文件。


十六、验证与验收标准

16.1 结构验证

导出前检查:

  • 骨骼名称唯一;
  • 父骨骼先于子骨骼;
  • Slot 引用的骨骼存在;
  • Skin 引用的 Slot 存在;
  • Attachment Timeline 引用的附件存在;
  • Mesh 骨骼索引有效;
  • Mesh 权重和正确;
  • UV、顶点和三角形索引数量匹配;
  • 动画时间递增;
  • 颜色为有效 RGBA
  • 所有数字有限,不出现 NaNInfinity

16.2 Runtime 验证

生成 JSON 后,使用项目内 Spine 4.2 Runtime 进行一次解析验证。解析失败时不应下载伪成功文件,应显示明确错误位置。

图片缺失不属于 JSON 结构失败,只显示警告。

16.3 视觉验证

至少对以下帧进行编辑器画布与导出结果对照:

  • 第一帧;
  • 粒子第一次出生帧;
  • 最大粒子数量附近;
  • 图片或序列帧切换帧;
  • 碰撞发生前后;
  • 路径或 Spine 跟随运动中间帧;
  • 拖尾明显弯曲帧;
  • 最后一帧;
  • 纯循环首帧和末帧。

对照内容包括:

  • 粒子数量;
  • 粒子位置;
  • 旋转与缩放;
  • 图片资源;
  • 颜色与透明度;
  • 绘制顺序;
  • 拖尾位置、方向、宽度和弯曲;
  • 循环接缝。

16.4 文件体积验收

  • 优先通过对象池、重复状态合并和误差受控关键帧精简减小文件;
  • 拖尾必须使用加权 Mesh,不能用逐帧 Deform 换取实现简单;
  • 不能为了缩小文件破坏碰撞、噪声、序列帧或循环精度;
  • 对象池关闭时允许文件显著增大,但应给出预计规模提示。

十七、当前实施状态

截至本文落盘:

  1. 导出范围、格式目标和关键规则已对齐;
  2. 导出设置面板已实现;
  3. 导出设置已接入保存、加载、预设、撤回和旧配置补齐;
  4. 默认文件名已定义为 SpineParticle.json
  5. “导出Spine Json”按钮尚未接入 JSON 生成;
  6. 正式导出代码必须等待用户明确的“开始”指令后实施;
  7. 开始实现前应下载并核对 Spine 官方 GitHub 仓库中的 Spine 4.2 加权 Mesh 和多动画 JSON 示例。

十八、禁止偏离项摘要

以下规则未经重新确认不得改变:

  1. 只导出可见粒子系统;
  2. 不导出碰撞体、路径和原 Spine 对象;
  3. 外部关联必须烘焙为独立动画;
  4. 第一版只支持 Spine 4.2
  5. 图片文件不导出,只写正确路径;
  6. 缺图不阻止导出;
  7. 序列帧只使用一根粒子骨骼;
  8. 拖尾必须使用加权 Mesh 和拖尾骨骼链;
  9. 拖尾不得正式导出为逐帧 Deform
  10. 先逐帧烘焙,再安全精简关键帧;
  11. Setup Pose 普通骨骼位移和旋转为 0、缩放为 1;
  12. 拖尾子骨骼保留正确绑定链位置;
  13. Setup Pose 图片和 Mesh 默认透明度为 0;
  14. 修改 FPS 时保持实际秒数不变;
  15. 空动画是否保留遵循“排除无内容动画”;
  16. 默认文件名为 SpineParticle.json
  17. 导出功能必须拆分为独立代码模块;
  18. 导出主要用途是重新导入 Spine 编辑器继续编辑。