14 KiB
网页粒子系统 · 阶段九
阶段定位:撤回与快捷键、编辑器配置持久化、可复用预设体系定版
完成日期:2026-08-30
工程目录:/Users/tianmokeji/Desktop/SpineParticle
技术栈:Vue 3 + TypeScript + Pinia + PixiJS 7 + Spine Runtime 4.2 + Vite
一、阶段结论
阶段九在阶段八场景编辑、Spine 骨骼跟随和对象复制能力的基础上,补齐了编辑器日常使用所需的撤回、快捷键、工程保存、工程加载和预设加载流程。
编辑器现在可以把粒子系统、碰撞体、路径、Spine、系统设置、画布视图和动画归属等数据保存为可移植 JSON,并能把 Spine 骨架、Atlas 与多张纹理一并内嵌。配置重新加载后不需要再次选择 Spine 原始文件,画布、动画列表和骨骼树可以直接恢复。
本阶段主要完成:
- 实现默认 20 步、最大 200 步的撤回历史;
- 在系统设置中增加最大撤回次数设置;
- 支持
Ctrl/Cmd + Z撤回; - 增加画布工具、时间轴和保存配置快捷键;
- 实现完整编辑器配置 JSON 下载保存;
- 实现本地 JSON 配置加载和数据恢复;
- 将 Spine 原始资源以内嵌 Data URL 形式纳入配置;
- 修复 Spine 配置恢复后的运行时资源注册和渲染;
- 实现
public/Preset/预设目录与自动索引; - 实现预设列表、空状态和一键加载;
- 建立纯粒子、路径、碰撞体、Spine 和空场景测试预设;
- 修复包含
+的预设文件名无法通过开发服务器读取的问题; - 为预设加载错误增加文件命名检查提示;
- 修复同一配置第二次加载后停在第 0 帧的问题;
- 完成普通配置和含 Spine 配置的保存—加载往返验证。
二、撤回功能
2.1 历史模型
编辑器通过快照记录可撤回数据。默认保留 20 步,用户可以在系统设置中修改,允许范围为 1~200 步。
快照覆盖:
- 全部粒子系统及其面板参数;
- 全部碰撞体;
- 全部路径与路径点;
- 全部 Spine 场景对象;
- 所属动画列表;
- 除撤回上限自身以外的系统设置;
- 对象显隐、背景图数据及背景偏移和透明度。
以下内容不作为普通撤回快照保存:
- 粒子逐帧录制缓存;
- PixiJS
Texture实例; - 拖尾运行时纹理实例;
- 当前时间轴帧和正在播放状态;
- 撤回上限本身。
这些数据属于运行时缓存或撤回系统自身配置,恢复快照后由编辑器重新计算或重建。
2.2 操作合并
参数连续拖动或连续输入不会为每个微小变化创建独立历史。编辑器在最后一次变化后等待约 250ms,再把连续变化合并为一步操作。
该设计适用于:
- 滑块拖动;
- 数值连续输入;
- 曲线调整;
- 场景对象变换;
- 背景图偏移和透明度调整。
2.3 Spine 资源安全
Spine 场景对象的可序列化属性保存在快照中,已解析的 SkeletonData 和纹理通过资源注册表引用计数保留。
撤回删除、复制或资源替换操作时:
- 快照仍引用的 Spine 资源不会被提前销毁;
- 恢复快照时重新注册对应 Spine ID 的运行时资源;
- 超出撤回上限的旧快照会释放自己持有的资源引用;
- 粒子录制缓存清空并重新生成。
2.4 撤回后的状态修复
执行撤回后会:
- 恢复场景对象和设置;
- 修复当前选择,避免选择已不存在的对象;
- 恢复粒子系统所属动画;
- 清空旧录制帧;
- 重新计算时间轴总长度;
- 更新撤回按钮的剩余步数和可用状态。
当前阶段只实现“撤回”,尚未实现“重做”。
三、快捷键
3.1 快捷键表
| 快捷键 | 作用 | 生效范围 |
|---|---|---|
Ctrl/Cmd + Z |
撤回上一步 | 全局 |
Ctrl/Cmd + S |
下载保存当前编辑器配置 | 全局 |
Q |
切换为画布拖动模式 | 画布已选中 |
W |
切换位移工具 | 画布已选中 |
E |
切换旋转工具 | 画布已选中 |
R |
切换缩放工具 | 画布已选中 |
D |
播放/暂停时间轴 | 全局非输入状态 |
S |
回到时间轴第 0 帧 | 全局非输入状态 |
3.2 浏览器快捷键覆盖
Ctrl/Cmd + S 和 Ctrl/Cmd + Z 会阻止浏览器默认行为,分别交给编辑器保存和撤回,不再弹出浏览器网页保存或执行浏览器输入历史撤销。
3.3 输入控件保护
当焦点位于以下控件时,普通字母快捷键不会触发:
input;textarea;select;contenteditable内容。
因此输入名称、搜索骨骼或编辑参数时,可以正常键入 q/w/e/r/d/s。带 Ctrl/Cmd 的保存与撤回仍按编辑器全局快捷键处理。
四、编辑器配置保存
4.1 保存入口
场景对象面板上方增加:
保存配置;加载配置;选择预设。
点击“保存配置”或按 Ctrl/Cmd + S,浏览器会下载:
SpineParticle-YYYYMMDD-HHMMSS.json
4.2 文件格式
当前格式标识与版本:
format: SpineParticle.EditorConfig
version: 1
顶层数据结构:
editor 画布缩放与平移
settings 系统设置、背景图及撤回上限
timeline FPS、循环状态和所属动画列表
selection 当前场景对象类型与 ID
scene 粒子、碰撞体、路径和 Spine 数组
savedAt 保存时间
4.3 粒子与图片资源
粒子系统保存全部可编辑参数,包括:
- 发射模式、持续时间和延迟;
- 发射器形状和根变换;
- 生命周期、速度、缩放、旋转与曲线;
- 颜色、透明度、混合模式;
- 修改器;
- 碰撞、路径和骨骼跟随;
- 图片资源与拖尾资源;
- 对象显隐和所属动画。
PixiJS 纹理实例和粒子逐帧缓存不会写入 JSON。图片资源通过自身的预览 URL 或 Data URL 保存,配置加载时重新创建纹理。
4.4 Spine 原始资源内嵌
Spine 对象除属性、动画选择和骨骼元数据外,还保存原始资源副本:
sourceBundle.skeleton
sourceBundle.atlas
sourceBundle.textures[]
每个资源同时保存原文件名和 Data URL。恢复时重新创建同名 File:
- JSON 使用原 JSON 文件名;
- SKEL 使用原二进制文件名;
- Atlas 保留原 Atlas 文件名和内容;
- 纹理保留 Atlas 中引用的准确文件名。
保持文件名一致是 Atlas 再次匹配多张纹理的关键。Data URL 只是文件内容载体,不会替代资源之间的文件名引用关系。
Spine 面板在首次加载成功后异步生成 sourceBundle,避免内嵌资源转换干扰当前画布中的实时 Spine 解析结果。
五、编辑器配置加载
5.1 校验
加载本地文件时只接受 .json,并依次检查:
- 是否为有效 JSON;
format是否为SpineParticle.EditorConfig;- 配置版本是否为 1;
- 场景是否包含粒子、碰撞体、路径和 Spine 数组。
失败时保持当前编辑器状态,并显示具体错误。
5.2 原子恢复流程
配置加载先在临时数据中完成资源准备:
- 深度复制配置数据;
- 补齐旧粒子参数默认值;
- 重建粒子和拖尾纹理;
- 还原 Spine 原始文件;
- 解析骨架、Atlas 和多纹理;
- 全部解析成功后再替换当前场景;
- 注册新的 Spine 运行时资源;
- 修复对象选择和所属动画;
- 重新计算时间轴长度。
如果内嵌 Spine 资源解析失败,已临时创建的纹理会释放,不会把半完成场景覆盖到编辑器中。
5.3 Spine 运行时刷新
重复加载配置时,Spine 对象 ID 可能相同。加载流程会提升 assetVersion,确保运行时层识别为新资源并重新创建 Spine 显示对象,而不是继续使用旧实例。
资源加载完成后会恢复:
- Spine 画布渲染;
- 动画列表和动画时长;
- 当前选择的 Spine 动画;
- 骨骼层级树;
- 当前选中骨骼;
- 粒子系统保存的 Spine ID 与骨骼名称绑定。
5.4 加载后自动播放
配置和预设加载完成后统一执行:
frame = 0
recorded = false
playing = true
因此首次加载和连续加载同一份配置都会从头自动播放,不再依赖场景深度监听是否检测到数据变化。
六、预设体系
6.1 预设目录
预设文件放置于:
public/Preset/
每个预设都是与“保存配置”完全相同的 SpineParticle.EditorConfig JSON,因此预设和本地工程配置共用一套解析、校验和资源恢复流程。
6.2 自动索引
Vite 插件会扫描预设目录中的全部 .json 文件并自动生成:
public/Preset/index.json
索引生成时:
- 排除
index.json自身; - 按中文文件名排序;
- 使用文件名去掉
.json作为界面名称; - 开发服务器监听文件新增和删除并刷新列表;
- 生产构建开始前重新生成索引。
目录中没有配置文件时,下拉框显示“无预设文件”并置灰。
6.3 当前预设
当前项目包含:
纯粒子.json;纯粒子-路径.json;纯粒子-碰撞.json;纯粒子-spine.json;空场景.json;默认粒子.json。
带 Spine 的预设内嵌 bingo.json、bingo.atlas、bingo.png 和 bingo_2.png,加载后可直接显示 Spine、动画列表和骨骼树。
6.4 文件命名规则
阶段测试发现,文件名包含 + 时,经 URL 编码后开发服务器会返回应用 HTML,而不是目标 JSON,最终表现为“配置文件不是有效的 JSON”。
为确保开发环境和静态托管环境行为一致,组合预设统一使用连字符:
推荐:纯粒子-路径.json
避免:纯粒子+路径.json
预设加载失败时,界面在原始错误后追加:
请检查预设文件命名
七、代码结构
本阶段新增或重点调整:
| 文件 | 职责 |
|---|---|
src/editor/editorClone.ts |
安全深度复制编辑器可序列化数据 |
src/editor/editorHistory.ts |
撤回快照、合并、上限和 Spine 资源引用 |
src/editor/useEditorShortcuts.ts |
全局快捷键、画布焦点和输入保护 |
src/editor/editorConfig.ts |
配置创建、下载、校验、加载和资源恢复 |
src/spine/spineSourceBundle.ts |
Spine 原始文件 Data URL 内嵌与还原 |
src/spine/spineAssetRegistry.ts |
Spine 配置恢复和撤回所需的资源生命周期 |
src/views/ParticlePanel.vue |
保存、加载、预设列表和结果提示 |
src/views/Stage.vue |
快捷键接入、撤回按钮和加载后的运行时刷新 |
vite.config.ts |
预设索引自动生成和 Spine 依赖去重 |
配置、历史与快捷键逻辑已从主画布和主属性面板中拆分,避免继续扩大单文件职责。
八、验证结果
已完成以下实际验证:
Ctrl/Cmd + S可以下载编辑器配置;- 配置文件名按时间生成且 JSON 格式有效;
- 修改粒子名称后保存,再次修改并加载,名称恢复为保存值;
- 系统设置、背景图数据、画布视图和场景对象写入配置;
- 含 Spine 的配置保存后文件约 11MB,资源数据完整内嵌;
- 含 Spine 配置重新加载后,Spine 名称恢复;
- Spine 画布图像正常显示;
- 14 个 Spine 动画及“无”选项正常恢复;
- 骨骼层级树正常恢复;
- 页面未出现资源解析或渲染错误;
纯粒子.json加载成功;纯粒子-路径.json加载成功,场景包含粒子与路径;纯粒子-碰撞.json加载成功,场景包含粒子与碰撞体;纯粒子-spine.json加载成功,场景包含粒子与 Spine;空场景.json可以加载为零对象场景;默认粒子.json加载成功;- 同一 Spine 预设连续加载两次,两次都从第 0 帧自动播放;
- 第二次加载后帧数从 40 推进到 59,播放按钮保持“暂停”状态;
- 浏览器控制台无错误和警告;
npm run build生产构建通过。
构建仍存在 Vite 主产物超过 500kB 的提示,不影响功能和构建结果。
九、当前限制
- 当前只支持单向撤回,尚未实现重做;
- 撤回历史只存在于当前页面内存中,刷新页面后清空;
- 撤回不保存当前播放帧、播放状态、画布选择和粒子录制缓存;
- 配置格式当前为版本 1,尚未建立跨版本迁移器;
- Spine 和本地图片使用 Data URL 内嵌,资源较大时配置文件体积明显增加;
- 保存配置始终下载新文件,尚未提供覆盖保存、最近文件和自动保存;
- 浏览器安全限制下无法记住原本地文件路径;
- 预设依赖构建时生成的索引,纯静态部署后新增文件需要重新构建;
- 预设命名目前通过规避
+保证兼容,尚未建立完整的文件名字符校验; - 配置导入目前只接受 JSON,尚未支持 YAML;
- 配置文件没有压缩,包含 Spine 多纹理时下载和解析成本较高;
- 主包仍包含 Spine 运行时和主要编辑器模块,尚未动态拆包。
十、阶段十建议
- 增加重做功能和
Ctrl/Cmd + Shift + Z快捷键; - 增加配置格式迁移器,支持未来版本平滑升级;
- 为预设文件名建立创建、校验和错误定位工具;
- 提供自动保存、最近配置和页面异常恢复;
- 支持压缩工程包,把 JSON 与 Spine、粒子图片资源拆分存储;
- 增加配置导入前预览、差异对比和合并模式;
- 为配置与预设建立自动化往返测试;
- 对无效 ID、丢失骨骼、缺失纹理和旧字段提供迁移报告;
- 增加工程名称、作者、备注和自定义元数据;
- 开始设计正式导出结构,把所属动画、粒子系统和 Spine 骨骼绑定映射到导出数据;
- 对 Spine 和编辑器主模块进行动态加载,降低初始包体积;
- 增加配置资源大小统计和大文件保存提示。