Web3D 在线3D模型骨骼动画编辑器(开源 Reze Studio)

张开发
2026/4/28 6:02:51 15 分钟阅读

分享文章

Web3D 在线3D模型骨骼动画编辑器(开源 Reze Studio)
Web3D 在线3D模型骨骼动画编辑器 Reze Studio「32 Web3D 在线3D模型骨骼动画编辑器THreeJS」/~f4543YKLSZ~:/链接https://pan.quark.cn/s/c83b484c466b预览 https://reze-studio.vercel.app/一个现代化的、原生Web的MMD动画编辑器——专为手动关键帧编辑.vmd片段而设计的独立时间轴和曲线编辑器摆脱了仅限Windows的桌面安装限制。它并非一个完全的MMD替代品目前不支持MME风格的着色器或视频导出也无意成为Maya或Blender它是一个专注的、跨平台工具旨在出色地完成动画编辑工作。通过WebGPU和reze引擎集成Ammo.js物理引擎、IK解算器直接在GPU上运行渲染可在从iPad到游戏笔记本的任何设备上提供高帧率播放和流畅交互。功能特性PMX模型和VMD动画加载与渲染支持IK和物理效果时间轴包含摄影表和逐通道曲线编辑器贝塞尔插值曲线编辑在播放头位置插入/删除关键帧VMD导入/导出从本地文件夹加载用户的PMX模型骨骼列表支持分组层级结构表情Morph列表旋转/平移滑块支持直接数字输入表情权重关键帧设置针对片段编辑的撤销/重做轨道操作简化关键帧精简、清空键盘快捷键标签页关闭/刷新时的未保存更改警告视口骨骼拾取双击 3D变换控件Gizmo拖动在材质面板中拾取材质并显示高亮轮廓支持混合权重和骨骼蒙版的动画层支持静音/独奏切换的自定义骨骼组片段操作剪切、复制、粘贴、镜像粘贴左↔右、导入、时间拉伸动作捕捉导入视频 → VMDOverleaf风格的实时协作AI辅助动画生成式补间、动作重定向快速开始打开 reze.studio—— 会加载一个默认的Reze模型和示例片段因此您可以立即开始编辑。可选加载您自己的模型文件→加载PMX文件夹…选择包含.pmx文件的文件夹纹理文件必须与.pmx文件位于同一目录。可选加载现有片段或从头开始文件→加载VMD…导入现有的 .vmd 文件或选择文件→新建以清空时间轴在已加载的模型上自行设置关键帧动画。播放动画按空格键或点击播放按钮。保存您的编辑文件→导出VMD…。没有服务器参与——所有操作都在您的浏览器中完成因此请在关闭标签页前导出。动画编辑流程简介如果您从未手动设置过关键帧动画可以这样理解一个片段是每个骨骼和每个表情的关键帧 (keyframe) 列表——即“在第N帧骨骼处于此姿态”的快照。引擎会在关键帧之间进行插值使角色动作平滑流畅。编辑片段意味着移动、添加或调整这些关键帧。在 Reze Studio 中的典型工作流程选择一个骨骼。在左侧面板、摄影表dope sheet中点击它或在视口中双击模型。右侧的“属性检查器”Properties Inspector会显示其旋转/平移值以及该骨骼上的所有关键帧并且在3D视图中该骨骼位置会出现一个环形/轴控制器Gizmo。跳转到某一帧。在时间轴中拖动播放头或使用←/→键逐帧步进。视口会实时更新。调整骨骼姿态。在检查器中拖动旋转/平移滑块、直接输入数字或在视口中拖动Gizmo环形控制旋转轴控制平移。这两种方式都会写入当前帧的关键帧——如果该帧不存在关键帧则会自动插入一个。每次拖动操作将被记录为一个独立的可撤销编辑单元。调整关键帧间的运动曲线。在摄影表中选择一个关键帧然后打开曲线编辑器选项卡。每个通道rotX, rotY, rotZ, tX, tY, tZ都有其独立的贝塞尔曲线——拖动手柄可以改变缓动效果。这是将“僵硬”动画变得“生动”的关键。删除/微移/拖拽关键帧。在摄影表中您可以左右拖动菱形关键帧以调整时间或选择并删除。方向键可逐帧微调。清理轨道。在属性检查器中简化功能可移除选定骨骼上的冗余关键帧即被相邻关键帧间的贝塞尔曲线在指定的旋转/平移容差内精确复现的关键帧。清空则会完全清除该轨道。两者都可撤销。撤销错误操作。Ctrl/⌘Z撤销上一次片段编辑Ctrl/⌘ShiftZ或⌘Y重做。历史记录保留最近的100次编辑。加载新的VMD或PMX文件不会进入历史堆栈——否则会导致加载的模型与之不同步。检查材质。打开“材质”选项卡右侧面板点击材质名称可在视口中高亮显示——便于确认网格对应关系。点击同一名称或列表中的任意空白区域可清除高亮。材质选择与骨骼/表情选择互斥。对所有骨骼重复上述步骤直到姿态流畅。最后导出为VMD文件。键盘快捷键按键功能空格键播放 / 暂停←/→后退 / 前进一帧Home跳转到第一帧End跳转到最后一帧Ctrl/⌘Z撤销上一次片段编辑Ctrl/⌘ShiftZ,⌘Y重做在帧数输入框内使用←/→递减 / 递增播放头所在帧Shift 鼠标滚轮缩放数值 / Y轴Ctrl/⌘ 鼠标滚轮缩放时间 / X轴技术栈引擎: reze-engine —— WebGPU渲染器Ammo.js物理引擎IK解算器编辑器: Next.js 16, React 19, TypeScript, shadcn/ui, Tailwind架构除了作为MMD编辑器此仓库也是对“如何在React中实现响应迅速的时间轴编辑器”的一项研究。时间轴编辑器是对框架的极限压力测试它需要高帧率的播放头、多轴拖拽、数千个关键帧以及绝不能卡顿的WebGPU画布——所有这些都与常规的React UI共享同一棵树。本节记录了Reze Studio如何实现这一目标。简而言之 —— React工程要点分离外部状态存储。文档/选择状态存在于Studio中播放控制播放头、播放状态存在于Playback中。播放控制以rAFrequestAnimationFrame频率更新不会触发撤销/重做目标的无效更新。useSyncExternalStore 选择器模式。组件订阅单一数据片段useStudioSelector(s s.field)仅在数据片段变化时重新渲染。操作包useStudioActions()保持稳定不会导致重新渲染。热路径完全绕过React。播放、关键帧拖拽和姿态滑块拖拽都通过命令式操作直接修改引用/对象通过命令式句柄重绘画布并且仅在释放时与React交互一次。currentFrameRef逃生舱。播放控制存储持有一个引用EngineBridge的rAF循环直接向其写入。非订阅的消费者检查器采样器、PMX交换快照无需触发重新渲染即可读取实时播放头。具备快照桥接撤销功能的类Reducer核心结构。由于预览期间的编辑会直接修改当前片段存储还会维护一个不可变的clipSnapshot在最后一次提交/撤销/重做时进行的深拷贝。commit()将该快照推入历史记录past——而不是被修改的片段——因此历史记录永远不会捕获到拖拽中的中间状态。提供者树结构Studio // 外部存储 —— 片段 选择状态撤销/重做目标 └─ Playback // 外部存储 —— 当前帧、播放状态rAF循环更新不触发重渲染 └─ StudioStatusProvider // 外部存储 —— PMX名称、FPS、消息与页面重渲染隔离 └─ StudioPage // 布局外壳 文件处理器 ├─ EngineBridge // 无头组件 —— 所有与引擎相关的副作用返回 null ├─ StudioLeftPanel // 被记忆化 —— 骨骼列表、表情列表、文件菜单 ├─ StudioViewport // 被记忆化 —— WebGPU canvas ├─ Timeline // 切片订阅 —— 摄影表 曲线编辑器 │ └─ TimelineCanvas // 命令式播放头 拖拽重绘句柄 ├─ PropertiesInspector // 切片订阅 —— 姿态滑块、表情权重播放期间通过rAF自行采样 └─ StudioStatusFooter // 切片订阅 —— PMX名称、FPS、片段名称状态分层层级所在位置说明文档context/studio-context.ts外部存储切片订阅撤销/重做目标选择状态context/studio-context.ts骨骼、表情、关键帧播放控制context/playback-context.ts外部存储currentFrame,playing存储自身拥有的currentFrameRef供rAF消费者使用见下文注释状态栏components/studio-status.tsx外部存储PMX文件名、FPS、临时消息引擎引用StudioPageengineRef,modelRef,canvasRef视图Timeline中的本地 useState缩放、滚动、选项卡界面StudioPage中的本地 useState菜单栏、文件选择对话框播放控制注释currentFrameRef通过usePlaybackFrameRef()共享。EngineBridge 的 rAF 循环直接将实时播放头写入.current而不经过set()因此非订阅的消费者无需任何React工作即可读取实时帧。订阅模型Studio文档/选择状态、Playback播放控制和StudioStatus状态栏都是基于useSyncExternalStore的外部存储。组件通过useStudioSelector(s s.field)/usePlaybackSelector(...)/useStudioStatusSelector(...)读取因此每个组件仅在其依赖的数据片段变化时重新渲染并通过use*Actions()写入这些操作返回稳定的操作包不会导致重新渲染。包装存储内部的set()也是撤销/重做的挂载点——commit()将快照推入历史记录replaceClip()用于VMD/PMX加载和“新建”清除历史记录选择状态的变化从不触及撤销堆栈。热路径 —— 交互时零React更新三种高频交互播放、关键帧拖拽、姿态滑块拖拽都遵循相同的模式命令式地修改引用/对象通过命令式句柄重绘画布并在释放时仅与React交互一次。播放​ ——EngineBridge的 rAF 循环读取引擎时钟将实时帧写入播放控制存储的currentFrameRef通过usePlaybackFrameRef()共享的唯一引用并调用playheadDrawRef.current(frame)—— 这是TimelineCanvas暴露的一个句柄用于直接重绘播放头叠加层。没有每次tick的setCurrentFrame因此不会重新渲染但任何非订阅的消费者检查器姿态采样、PMX交换快照仍然可以通过该引用看到实时帧。自动滚动当播放头移出视口时翻页位于相同的命令式路径中仅在罕见的翻页边界处触及React。暂停时最终帧会通过setCurrentFrame刷新以便暂停视图与最后绘制的内容一致。实时姿态/表情读数​ ——PropertiesInspector在隔离的叶子子组件中采样所选骨骼的姿态和表情权重。暂停时它订阅currentFrame并在变化时重新采样播放时它运行自己的小型 rAF 循环直接读取modelRef.current的runtimeSkeleton/getMorphWeights()并通过相等性检查进行门控以防止未变化的帧触发协调。这将逐帧的工作保持在父检查器和StudioPage之外。关键帧拖拽​ ——Timeline的移动回调命令式地修改关键帧的frame/ 通道值 / 轨道顺序并触发dragRedrawRef.current()这会增加一个用于静态层缓存失效检查的内部拖拽版本号并重绘画布。selectedKeyframes条目被命令式地修改使高亮跟随拖拽。在鼠标弹起时一个单独的commit()克隆轨道 Maps 并创建撤销/重做快照同时通过EngineBridge执行一次model.loadClip。姿态滑块拖拽​ ——PropertiesInspector的apply*Axis/applyMorphWeight函数在每次拖拽tick中以“预览”模式运行原地修改匹配的关键帧或插入一个然后执行model.loadClip 跳转以更新3D视口。没有commit()因此时间轴保持静态检查器也不会协调。AxisSliderRow在拖拽期间保持本地的滑块值以防止Radix控件回弹到过期的受控属性值。在onValueCommit时触发一个单独的克隆 commit()操作 —— 只有这个commit()会进入撤销历史因此一次拖拽是一个可撤销的单元而不是数百个预览帧。Reze Studio一个现代化的、原生Web的MMD动画编辑器——专为手动关键帧编辑.vmd片段而设计的独立时间轴和曲线编辑器摆脱了仅限Windows的桌面安装限制。它并非一个完全的MMD替代品目前不支持MME风格的着色器或视频导出也无意成为Maya或Blender它是一个专注的、跨平台工具旨在出色地完成动画编辑工作。通过WebGPU和reze引擎集成Ammo.js物理引擎、IK解算器直接在GPU上运行渲染可在从iPad到游戏笔记本的任何设备上提供高帧率播放和流畅交互。功能特性PMX模型和VMD动画加载与渲染支持IK和物理效果时间轴包含摄影表和逐通道曲线编辑器贝塞尔插值曲线编辑在播放头位置插入/删除关键帧VMD导入/导出从本地文件夹加载用户的PMX模型骨骼列表支持分组层级结构表情Morph列表旋转/平移滑块支持直接数字输入表情权重关键帧设置针对片段编辑的撤销/重做轨道操作简化关键帧精简、清空键盘快捷键标签页关闭/刷新时的未保存更改警告视口骨骼拾取双击 3D变换控件Gizmo拖动在材质面板中拾取材质并显示高亮轮廓支持混合权重和骨骼蒙版的动画层支持静音/独奏切换的自定义骨骼组片段操作剪切、复制、粘贴、镜像粘贴左↔右、导入、时间拉伸动作捕捉导入视频 → VMDOverleaf风格的实时协作AI辅助动画生成式补间、动作重定向快速开始打开 reze.studio—— 会加载一个默认的Reze模型和示例片段因此您可以立即开始编辑。可选加载您自己的模型文件→加载PMX文件夹…选择包含.pmx文件的文件夹纹理文件必须与.pmx文件位于同一目录。可选加载现有片段或从头开始文件→加载VMD…导入现有的 .vmd 文件或选择文件→新建以清空时间轴在已加载的模型上自行设置关键帧动画。播放动画按空格键或点击播放按钮。保存您的编辑文件→导出VMD…。没有服务器参与——所有操作都在您的浏览器中完成因此请在关闭标签页前导出。动画编辑流程简介如果您从未手动设置过关键帧动画可以这样理解一个片段是每个骨骼和每个表情的关键帧 (keyframe) 列表——即“在第N帧骨骼处于此姿态”的快照。引擎会在关键帧之间进行插值使角色动作平滑流畅。编辑片段意味着移动、添加或调整这些关键帧。在 Reze Studio 中的典型工作流程选择一个骨骼。在左侧面板、摄影表dope sheet中点击它或在视口中双击模型。右侧的“属性检查器”Properties Inspector会显示其旋转/平移值以及该骨骼上的所有关键帧并且在3D视图中该骨骼位置会出现一个环形/轴控制器Gizmo。跳转到某一帧。在时间轴中拖动播放头或使用←/→键逐帧步进。视口会实时更新。调整骨骼姿态。在检查器中拖动旋转/平移滑块、直接输入数字或在视口中拖动Gizmo环形控制旋转轴控制平移。这两种方式都会写入当前帧的关键帧——如果该帧不存在关键帧则会自动插入一个。每次拖动操作将被记录为一个独立的可撤销编辑单元。调整关键帧间的运动曲线。在摄影表中选择一个关键帧然后打开曲线编辑器选项卡。每个通道rotX, rotY, rotZ, tX, tY, tZ都有其独立的贝塞尔曲线——拖动手柄可以改变缓动效果。这是将“僵硬”动画变得“生动”的关键。删除/微移/拖拽关键帧。在摄影表中您可以左右拖动菱形关键帧以调整时间或选择并删除。方向键可逐帧微调。清理轨道。在属性检查器中简化功能可移除选定骨骼上的冗余关键帧即被相邻关键帧间的贝塞尔曲线在指定的旋转/平移容差内精确复现的关键帧。清空则会完全清除该轨道。两者都可撤销。撤销错误操作。Ctrl/⌘Z撤销上一次片段编辑Ctrl/⌘ShiftZ或⌘Y重做。历史记录保留最近的100次编辑。加载新的VMD或PMX文件不会进入历史堆栈——否则会导致加载的模型与之不同步。检查材质。打开“材质”选项卡右侧面板点击材质名称可在视口中高亮显示——便于确认网格对应关系。点击同一名称或列表中的任意空白区域可清除高亮。材质选择与骨骼/表情选择互斥。对所有骨骼重复上述步骤直到姿态流畅。最后导出为VMD文件。键盘快捷键按键功能空格键播放 / 暂停←/→后退 / 前进一帧Home跳转到第一帧End跳转到最后一帧Ctrl/⌘Z撤销上一次片段编辑Ctrl/⌘ShiftZ,⌘Y重做在帧数输入框内使用←/→递减 / 递增播放头所在帧Shift 鼠标滚轮缩放数值 / Y轴Ctrl/⌘ 鼠标滚轮缩放时间 / X轴技术栈引擎: reze-engine —— WebGPU渲染器Ammo.js物理引擎IK解算器编辑器: Next.js 16, React 19, TypeScript, shadcn/ui, Tailwind架构除了作为MMD编辑器此仓库也是对“如何在React中实现响应迅速的时间轴编辑器”的一项研究。时间轴编辑器是对框架的极限压力测试它需要高帧率的播放头、多轴拖拽、数千个关键帧以及绝不能卡顿的WebGPU画布——所有这些都与常规的React UI共享同一棵树。本节记录了Reze Studio如何实现这一目标。简而言之 —— React工程要点分离外部状态存储。文档/选择状态存在于Studio中播放控制播放头、播放状态存在于Playback中。播放控制以rAFrequestAnimationFrame频率更新不会触发撤销/重做目标的无效更新。useSyncExternalStore 选择器模式。组件订阅单一数据片段useStudioSelector(s s.field)仅在数据片段变化时重新渲染。操作包useStudioActions()保持稳定不会导致重新渲染。热路径完全绕过React。播放、关键帧拖拽和姿态滑块拖拽都通过命令式操作直接修改引用/对象通过命令式句柄重绘画布并且仅在释放时与React交互一次。currentFrameRef逃生舱。播放控制存储持有一个引用EngineBridge的rAF循环直接向其写入。非订阅的消费者检查器采样器、PMX交换快照无需触发重新渲染即可读取实时播放头。具备快照桥接撤销功能的类Reducer核心结构。由于预览期间的编辑会直接修改当前片段存储还会维护一个不可变的clipSnapshot在最后一次提交/撤销/重做时进行的深拷贝。commit()将该快照推入历史记录past——而不是被修改的片段——因此历史记录永远不会捕获到拖拽中的中间状态。提供者树结构Studio // 外部存储 —— 片段 选择状态撤销/重做目标 └─ Playback // 外部存储 —— 当前帧、播放状态rAF循环更新不触发重渲染 └─ StudioStatusProvider // 外部存储 —— PMX名称、FPS、消息与页面重渲染隔离 └─ StudioPage // 布局外壳 文件处理器 ├─ EngineBridge // 无头组件 —— 所有与引擎相关的副作用返回 null ├─ StudioLeftPanel // 被记忆化 —— 骨骼列表、表情列表、文件菜单 ├─ StudioViewport // 被记忆化 —— WebGPU canvas ├─ Timeline // 切片订阅 —— 摄影表 曲线编辑器 │ └─ TimelineCanvas // 命令式播放头 拖拽重绘句柄 ├─ PropertiesInspector // 切片订阅 —— 姿态滑块、表情权重播放期间通过rAF自行采样 └─ StudioStatusFooter // 切片订阅 —— PMX名称、FPS、片段名称状态分层层级所在位置说明文档context/studio-context.ts外部存储切片订阅撤销/重做目标选择状态context/studio-context.ts骨骼、表情、关键帧播放控制context/playback-context.ts外部存储currentFrame,playing存储自身拥有的currentFrameRef供rAF消费者使用见下文注释状态栏components/studio-status.tsx外部存储PMX文件名、FPS、临时消息引擎引用StudioPageengineRef,modelRef,canvasRef视图Timeline中的本地 useState缩放、滚动、选项卡界面StudioPage中的本地 useState菜单栏、文件选择对话框播放控制注释currentFrameRef通过usePlaybackFrameRef()共享。EngineBridge 的 rAF 循环直接将实时播放头写入.current而不经过set()因此非订阅的消费者无需任何React工作即可读取实时帧。订阅模型Studio文档/选择状态、Playback播放控制和StudioStatus状态栏都是基于useSyncExternalStore的外部存储。组件通过useStudioSelector(s s.field)/usePlaybackSelector(...)/useStudioStatusSelector(...)读取因此每个组件仅在其依赖的数据片段变化时重新渲染并通过use*Actions()写入这些操作返回稳定的操作包不会导致重新渲染。包装存储内部的set()也是撤销/重做的挂载点——commit()将快照推入历史记录replaceClip()用于VMD/PMX加载和“新建”清除历史记录选择状态的变化从不触及撤销堆栈。热路径 —— 交互时零React更新三种高频交互播放、关键帧拖拽、姿态滑块拖拽都遵循相同的模式命令式地修改引用/对象通过命令式句柄重绘画布并在释放时仅与React交互一次。播放​ ——EngineBridge的 rAF 循环读取引擎时钟将实时帧写入播放控制存储的currentFrameRef通过usePlaybackFrameRef()共享的唯一引用并调用playheadDrawRef.current(frame)—— 这是TimelineCanvas暴露的一个句柄用于直接重绘播放头叠加层。没有每次tick的setCurrentFrame因此不会重新渲染但任何非订阅的消费者检查器姿态采样、PMX交换快照仍然可以通过该引用看到实时帧。自动滚动当播放头移出视口时翻页位于相同的命令式路径中仅在罕见的翻页边界处触及React。暂停时最终帧会通过setCurrentFrame刷新以便暂停视图与最后绘制的内容一致。实时姿态/表情读数​ ——PropertiesInspector在隔离的叶子子组件中采样所选骨骼的姿态和表情权重。暂停时它订阅currentFrame并在变化时重新采样播放时它运行自己的小型 rAF 循环直接读取modelRef.current的runtimeSkeleton/getMorphWeights()并通过相等性检查进行门控以防止未变化的帧触发协调。这将逐帧的工作保持在父检查器和StudioPage之外。关键帧拖拽​ ——Timeline的移动回调命令式地修改关键帧的frame/ 通道值 / 轨道顺序并触发dragRedrawRef.current()这会增加一个用于静态层缓存失效检查的内部拖拽版本号并重绘画布。selectedKeyframes条目被命令式地修改使高亮跟随拖拽。在鼠标弹起时一个单独的commit()克隆轨道 Maps 并创建撤销/重做快照同时通过EngineBridge执行一次model.loadClip。姿态滑块拖拽​ ——PropertiesInspector的apply*Axis/applyMorphWeight函数在每次拖拽tick中以“预览”模式运行原地修改匹配的关键帧或插入一个然后执行model.loadClip 跳转以更新3D视口。没有commit()因此时间轴保持静态检查器也不会协调。AxisSliderRow在拖拽期间保持本地的滑块值以防止Radix控件回弹到过期的受控属性值。在onValueCommit时触发一个单独的克隆 commit()操作 —— 只有这个commit()会进入撤销历史因此一次拖拽是一个可撤销的单元而不是数百个预览帧。简化轨道关键帧精简MMD的插值模型使得经典的Ramer–Douglas–Peucker算法不太适用每一帧存储一条完整的记录旋转是一个由单个贝塞尔曲线控制的slerp-t插值因此rotX/rotY/rotZ共享一个线段而非独立的曲线而平移具有三个独立的每轴贝塞尔曲线。Reze Studio 使用了一种专为此模型设计的、类似Schneider的自顶向下拟合方法而不是逐个丢弃关键帧在[第一帧, 最后一帧]范围内对原始轨道在每一整数帧进行密集采样。尝试用一条VMD段覆盖整个区间——包含四个独立的贝塞尔曲线旋转slerp-t tX/tY/tZ。对于每条曲线根据密集采样点匹配端点速度来初始化手柄然后通过在127参数空间的粗糙5^4网格搜索以及围绕最佳结果的局部5^4搜索进行优化。如果最大逐点误差 ≤ ε旋转为测地角平移为每轴距离则输出一个关键帧并折叠其间的所有中间关键帧。否则在最接近最大偏差帧的原始关键帧处分割并对两部分递归执行上述操作。相邻的原始关键帧会被原样保留包括其手动设置的插值。较早的贪心“如果可容忍则丢弃”算法存在一个细微缺陷丢弃一个关键帧会继承保留关键帧的贝塞尔手柄而这些手柄是为较短的线段设计的——将它们拉伸到更长的区间会扭曲速度曲线即使点对点误差 ε 很严格也会产生可见的抖动。为每个输出线段进行自定义拟合避免了这个问题。固定的容差为0.5° / 0.01单位不提供用户调节旋钮。整个操作作为一次commit()提交因此一次简化是一个撤销步骤。各部分职责所在文件文件职责app/page.tsxNext.js入口 —— 挂载所有提供者 StudioPage /context/studio-context.ts文档 选择状态存储useStudioSelector, 操作context/playback-context.ts播放控制存储选择器操作usePlaybackFrameRefcomponents/studio.tsxStudioPage—— 布局、文件处理、菜单栏、导出components/studio-status.tsx状态栏存储 StudioStatusFootercomponents/engine-bridge.tsx与引擎相关的副作用初始化、跳转、播放、rAF播放循环components/timeline.tsx摄影表 曲线编辑器命令式播放头 / 拖拽重绘components/properties-inspector.tsx姿态滑块、表情权重、插值编辑器components/axis-slider-row.tsx带有预览/提交分离 本地拖拽值的滑块行

更多文章