Files
ttstd-infinite-canvas/PREVIS_REFACTOR_PLAN.md

289 lines
17 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 预演台统一重构:分析、设计与执行方案
## 0. 结论先行
当前问题不是“高频工作流样式还不够精致”,而是产品结构上同时维护了两套入口:
- 高频工作流:真实高频工作流,布局清晰,用户已经反复调试到可用。
- 旧分裂工作台:功能覆盖更广,但布局、样式和交互边界长期没有同步,已经出现样式 bug、功能 bug、滚动问题和空白问题。
继续在两套页面上各自修复,会让同一份场景数据拥有两套操作语义,之后每次新增能力都要重复接线、重复测试、重复修复。
本轮方向确定为:
> 删除“高频工作流”和“旧分裂工作台”这两个产品层级,把所有能力合并到一个统一的“预演台”工作区。布局、视觉和交互以已经验证过的高频工作流方案为主;从 DirectorDesk 只吸收真正有价值的场景编排能力,尤其是轨迹绘制与轨迹播放,不复制它的表面结构。
“预演台”是产品名称。内部可以继续保留 `layout / pose / animate / camera` 作为能力状态,但它们只能是同一工作区中的上下文,不再是两套工作台。
## 1. 反复犯错的问题
### 1.1 把参考产品的表面结构当成了产品答案
错误表现:
- 看到 DirectorDesk 的左侧布景、右侧摄影机、底部时间轴,就把“多面板旧分裂工作台”整体搬过来。
- 只复制了组件形状、标题和分栏,没有先确认我们的用户真正高频的任务顺序。
- 参考产品里真正有价值的能力(轨迹、路径、基于距离的步行动画、镜头连续性)反而没有成为主线。
修复思路:
- 参考产品只提取“能力和原则”,不提取它的页面壳。
- 先问用户在当前产品里最常做什么,再决定入口、密度和默认视图。
- 对 DirectorDesk 的吸收清单只保留:自由手绘轨迹、轨迹简化、按距离分配时间、路径朝向、演员/摄影机路径可视化、同一场景多视图观察。
- 明确不复制:独立桌面应用的菜单层级、复杂资源管理、与本项目无关的深度导出和外部工程概念。
### 1.2 把“功能完整”误解成“再造一个页面
错误表现:
- 为了补齐布景、姿态、动画、摄影机,新增旧分裂工作台。
- 结果是高频工作流和旧分裂工作台分别拥有一部分能力,任何一边都不是完整事实来源。
- 同一个操作在两套页面上可能使用不同的保存、选择、视口和检查器路径。
修复思路:
- 功能完整不等于页面分裂。
- 所有场景修改都必须进入同一套 `commit / history / save coordinator` 链路。
- 所有对象、灯光、摄影机、资产、姿态、关键帧和输出都在同一个预演台布局中可达。
- 复杂功能通过同一页面里的分区、抽屉、工具栏、检查器和时间轴渐进展开,而不是增加第二个工作台。
### 1.3 先修局部样式,后补产品信息架构
错误表现:
- 不断调整圆角、颜色、间距、按钮样式。
- 但页面仍然有两套入口,用户不知道该进入哪一个。
- 旧分裂工作台中的功能不在高频工作流出现,导致“看起来有功能,实际上找不到”。
修复思路:
- 顺序固定为:信息架构 -> 任务路径 -> 状态模型 -> 组件布局 -> 视觉细节。
- 页面只有一个产品入口,先解决“在哪里做”再解决“看起来怎样”。
- 视觉规范以高频工作流当前已验证的密度、面板、颜色、对象列表和视口胶囊切换为基线。
### 1.4 通过重新实现,破坏已经修好的行为
错误表现:
- 修复 UI 时把保存、撤销、模型加载、上下文恢复、对象摆位等已稳定链路一起改动。
- 为了“统一”,把刻意放宽的产品规则重新收紧。
- 用逐个报错、逐个补洞的方式开发,最后无法确认完整流程是否可靠。
修复思路:
- 统一页面只替换产品壳,不重写已稳定的场景数据和保存底座。
- 保留 `touchPrevisScene`、`commit`、`stagedTransaction`、保存协调器、模型加载诊断和 WebGL 恢复机制。
- 每轮修改后跑完整流程:打开、加对象、选中、摆位、画轨迹、播放、保存、回写、关闭、重开。
- 不以“某一个错误消失”为完成标准,而以端到端流程通过为标准。
### 1.5 把轨迹当成动画的附属细节,而不是核心能力
错误表现:
- 目前主要依靠零散 transform 关键帧和简单折线显示。
- 用户无法像导演在场地上画走位一样直接表达动作。
- 轨迹时间可能受鼠标事件数量、停顿和绘制速度影响,导致播放速度不稳定。
修复思路:
- 轨迹是预演台的核心编辑对象,必须有明显的“画轨迹”入口。
- 轨迹采样后先做三维简化,再按路径距离分配时间,不能按 pointer event 间隔直接写时间。
- 演员沿轨迹移动时默认按路径方向转向;摄影机轨迹至少保证位置连续,并保留原镜头朝向。
- 轨迹必须能在导演视角、机位视角和时间轴播放中被验证。
## 2. 用户调教出来的产品设计原则
这些不是装饰偏好,而是预演台的产品约束:
1. 高频工作流是 99% 用户使用的真实入口,所有功能必须进入主工作流。
2. 不允许用“高级模式”作为缺功能的借口;高级能力必须在同一个预演台中自然出现。
3. UI 需要高端、专业、有质感,但不能靠装饰遮盖信息架构问题。
4. 画布节点必须有真实场景缩略图或可靠的实时预览,不用空白文字占位冒充完成。
5. 新演员必须默认拥有可区分的颜色,颜色可直接编辑。
6. 对象、摄影机、灯光、资产、环境、姿态、运镜、动画和输出必须在同一场景事实源中工作。
7. 操作必须可逆、可保存、可重开,不能出现“界面看起来成功但数据没有保存”。
8. 功能入口应该面向任务:添加角色、搭景、画轨迹、设计镜头、调整动作、输出,而不是面向内部代码模块。
9. 不用重复造同一套 UI。一个布局、一个状态模型、一个保存链路、一个测试入口。
10. 重构不得把已经明确放宽的产品规则重新收紧,例如素材删除不因为引用关系被拦截。
## 3. DirectorDesk 真正值得吸收的东西
### 吸收
- **自由手绘路径**:在地面或物体表面直接拖出演员/摄影机路线。
- **路径点清理和简化**:去掉高频采样噪声,同时保留拐角和闭环形状。
- **基于距离的时间分配**:相同路径不因鼠标快慢、帧率或事件密度而改变播放速度。
- **连续路径与途经点停留**:后续可支持停留点、分段速度和连续曲线。
- **路径方向**:演员沿路径方向朝向;摄影机可选择沿路径、看向目标或保持镜头方向。
- **路径可视化**:轨迹线、起点、终点、当前播放位置、选中状态要一眼可见。
- **位置和动作分离**:路线控制空间移动,动作片段控制走路/跑步/姿势,二者可以独立调整。
- **多视图验证**:导演视角调整空间关系,机位视角检查最终画面,时间轴检查连续性。
### 不吸收
- 不复制 DirectorDesk 的独立应用信息架构。
- 不复制与本项目无关的资源目录、导出协议和菜单层级。
- 不为了“看起来像”而保留第二个高级页面。
- 不把桌面端复杂能力一次性全部塞进首屏;复杂选项放入检查器和可展开工具。
## 4. 统一预演台设计
### 4.1 统一产品结构
名称:**预演台**。
单一全屏工作区:
- 顶部:关闭、场景标题、撤销/重做、保存状态、渲染模式、生成白膜、回写构图。
- 左侧:场景对象、摄影机、灯光、道具库、画布资产、轨迹目标入口。
- 中间:主 3D 视口;导演视角/机位视角/正交视图切换;对象和轨迹直接可见。
- 右侧:当前镜头与选中对象检查器;景别、运镜、时长、帧率、姿态、体型、颜色、变换、灯光、镜头参数和生成提示词。
- 底部:时间轴按需展开;镜头条、对象轨道、摄影机轨道、关键帧、播放和 Auto Key 都在这里。
没有“高频工作流 / 旧分裂工作台”切换按钮,也没有“进入旧分裂工作台”的隐藏入口。
### 4.2 统一页面中的上下文
内部仍可以使用 `layout / pose / animate / camera` 作为能力上下文,但它们只影响:
- 当前检查器优先展示什么。
- 是否显示时间轴和 Auto Key。
- 渲染模式有哪些。
- 当前工具栏的默认工具。
它们不能切换到另一套页面,也不能改变对象数据的来源。
### 4.3 主任务顺序
1. 选镜头或创建镜头。
2. 从左侧添加演员、道具、资产、灯光和摄影机。
3. 在中间视口拖动对象,或点击“画轨迹”直接绘制走位。
4. 在右侧调整姿态、体型、颜色和镜头参数。
5. 在底部时间轴播放、补关键帧、查看轨迹连续性。
6. 在机位视角确认画面。
7. 生成白膜或回写构图。
每一步都应在同一个页面完成,不需要跳转或换工作台。
### 4.4 轨迹交互
- 选中演员或摄影机后,工具栏出现“画轨迹”。
- 点击后进入绘制态:视口进入路径采样,OrbitControls 暂停,鼠标/触摸拖动生成地面路径。
- 绘制中显示临时路径和起点/终点。
- 松开后按当前镜头时长生成路径关键帧。
- 演员:按路径方向生成水平朝向,保留当前高度、缩放和姿态/动作。
- 摄影机:写入连续位置关键帧,默认保留当前旋转;后续再提供“沿路朝向 / 看向主体”的切换。
- 再次绘制覆盖该对象当前轨迹,撤销可以恢复旧轨迹。
- 没有选中可移动对象时,按钮给出明确提示,不进入半成品状态。
## 5. 数据与实现边界
### 保留
- `PrevisScene`、`PrevisObject`、`PrevisCamera`、`PrevisLight`。
- 现有 transform keyframe 结构,轨迹首版直接编译为关键帧,避免引入第二套持久化格式。
- `previs-animation-semantics.ts` 的动画编辑语义。
- 保存协调器、草稿恢复、页面卸载保护、诊断事件和视口 capture/record。
- 既有对象颜色、actor archetype、actorProfile、motionClips 和 boneTracks。
### 新增
- `previs-path.ts`:
- 三维点清理与 Ramer-Douglas-Peucker 简化。
- 按路径距离计算 waypoint 时间。
- 轨迹关键帧生成。
- 路径方向和 yaw 计算。
- 视口绘制态:仅在显式绘制轨迹时接管 pointer 事件。
- 轨迹预览:临时线、已保存路径、当前播放点。
- 单元测试覆盖:简化、距离计时、退化路径、方向角连续性、关键帧生成。
### 不新增
- 不再增加 第二套模式状态。
- 不再保留一套只为“旧分裂工作台”服务的 JSX 和 CSS。
- 不建立第二个场景编辑器 store。
- 不把路径采样事件直接持久化为大量 pointer 记录。
## 6. 重构阶段与验收门
### Phase 1:先写统一事实源
- 删除顶部快速/高级切换。
- 统一预演台默认显示场景对象、摄影机、灯光、资产、镜头检查器。
- 将原旧分裂工作台中仍有价值的工具接入现有 `pv-*` 布局。
- 删除重复 JSX 和对应的高级 CSS。
成功标志:项目中只剩一个预演台 UI 分支,搜索不到“高频工作流/旧分裂工作台”产品入口。
### Phase 2:轨迹基础能力
- 增加纯函数路径库和单元测试。
- 视口增加显式画轨迹态。
- 演员和摄影机轨迹编译为已有关键帧。
- 播放头和轨迹预览同步。
成功标志:能在同一页面画演员路线、播放并撤销;摄影机路线能在导演视角看到。
### Phase 3:布局与体验收敛
- 左侧补齐旧分裂工作台里的对象、灯光、模型资产和道具入口。
- 右侧补齐对象/灯光/镜头检查器和提示词输出。
- 底部时间轴按动画上下文展开,不再用页面切换表达“高级”。
- 统一按钮、焦点、触控尺寸、滚动容器和空状态。
成功标志:用户不需要记住功能属于哪一种工作台;所有高频能力在一个页面可发现。
### Phase 4:测试和清理
- 更新 Chrome E2E:不再点击旧分裂工作台;默认打开即验证统一界面。
- 保留对象添加、撤销、模型加载、上下文丢失恢复、保存失败重试等 P0 场景。
- 增加轨迹的纯函数测试和至少一条浏览器轨迹 smoke。
- 删除无引用的高级组件、样式、旧命名和测试描述。
成功标志:TypeScript、ESLint、单元测试、Vite build、Chrome E2E 全部通过;完整流程可从打开走到保存、关闭和重开。
## 7. 明确的完成标准
- 用户只看到一个产品:预演台。
- 高频工作流中已验证的布局和视觉成为全局基线。
- 布景、演员、姿态、动画、摄影机、灯光、资产、环境、提示词和输出全部可达。
- 轨迹绘制成为一等交互,不是隐藏在高级模式里的补充按钮。
- 轨迹播放速度由路径距离和镜头时长决定,不由鼠标事件或绘制速度决定。
- 新演员颜色自动区分且可编辑。
- 画布卡片、模型加载、保存恢复和输出链路没有回归。
- 没有“进入旧分裂工作台”或“切换高频工作流”的产品级文案、按钮和双份页面。
## 8. 本轮 IA 实施记录(2026-10-05)
### 已落地的左右面板职责
- 左侧只负责场景层级、对象、摄影机、灯光、道具和资源浏览;移除重复的摄影机、灯光、道具库添加入口,避免同一动作在多个面板出现。
- 中央只负责真实 WebGL 视口、对象操作、视角工具和轨迹绘制;移除旧的视图胶囊,视图状态统一由视口工具层管理。
- 右侧只负责当前选择上下文:选中对象显示对象检查器,选中灯光显示灯光检查器,选中摄影机显示摄影机检查器,无选择时才显示镜头设计上下文。
- 底部只负责时间、播放、Auto Key、镜头条、对象轨道和关键帧;不在左右面板复制时间控制。
- 移动端将右侧检查器变成滑入抽屉,通过显式打开/关闭按钮进入,不牺牲检查器能力,也不压缩主视口到不可用尺寸。
### 覆盖层与响应式纠错记录
- 下拉菜单、工具提示和检查器抽屉使用明确的层级、边界和碰撞策略;打开菜单时不遮盖错误面板,Escape 可关闭,焦点回到触发控件。
- 本轮曾将移动工具声明放在 media block 外并多写一个 `}`,导致 Vite 在 `canvas-previs-workbench.css:1415` 失败。修正方式是把移动端工具栏、轨迹按钮和时间轴声明收回同一个 `@media (max-width: 860px)`,再以生产构建验证 CSS 结构。
- 移动端保留 176-200px 左侧层级栏、单列视口和 280px 时间轴下限;右侧检查器使用不超过 92vw 的抽屉,避免面板相互覆盖。
### 当前验收状态(截至 2026-10-05)
- 已通过:TypeScript、目标 ESLint、`git diff --check`、Vite production build、轨迹纯函数测试(`npx --yes bun test test/previs-path.test.ts`,5 tests / 12 assertions)。
- 已通过:完整 Chrome P0 E2E,A-F 共 62/62 断言通过;覆盖统一工作台启动、真实 WebGL、添加/撤销、动画时间轴、模型成功加载、模型失败重试、加载中删除、WebGL context loss/restore、保存失败提示、重试入口和关闭保护。
- 已通过:桌面结构探针(1680×932):左/右面板各 272px,中央 canvas 约 1132×879;DOM 中 `.pv-viewport-toolbar`、取景模式组和 canvas 各 1 个,旧 Dock 与视图胶囊均为 0。
- 已通过:窄屏结构探针(390×844):左层级栏 176px,主视口约 299px,右检查器以约 359px 抽屉停在屏幕外,工具栏位于主视口内;未发现面板几何重叠。开发环境仅出现已知 Ant Design/Three 弃用提示,无运行时异常。
- 已通过:精确旧双工作台/旧产品入口扫描为 0 命中;保留的历史文档术语不构成运行时入口。
- 尚未覆盖:浏览器内真实轨迹拖拽、轨迹取消/预览/播放、轨迹撤销和演员/摄影机轨迹持久化重载;保存成功后的重开闭环;保存失败后实际点击“重试保存”并确认恢复;移动端截图级视觉验收;完整下拉碰撞与焦点回归。
- 不能宣称完成的门禁:上述浏览器轨迹与持久化闭环仍需专门 smoke;本轮已证明轨迹算法和基础 pointer 取消逻辑,但没有把它们扩大解释为完整端到端通过。
### 下一轮验收顺序
1. 在稳定的本地预演台页面完成浏览器轨迹绘制、取消、距离计时、预览、播放、撤销、镜头切换、模式切换和保存重载闭环。
2. 补保存成功重开、保存失败后重试成功,以及导出动作的浏览器断言。
3. 补移动端实际截图和打开检查器抽屉后的边界/焦点/Escape 断言。
4. 扫描源代码、测试和文档,确认不存在旧的双页面入口、路由、分支或产品级名称。
5. 最后再次运行 TypeScript、ESLint、轨迹测试、Vite build、E2E 和 `git diff --check`。