重构资源画本独立转场与中断处理
Project CI / Repository checks (pull_request) Failing after 15s
Project CI / Backend tests (pull_request) Failing after 15s
Project CI / Frontend tests (pull_request) Has been cancelled
Project CI / Native shell tests (pull_request) Has been cancelled

使用独立FLIP快照层和Web Animations统一动画收尾
统一分类导航并保留滚轮节流和各画布视口
修复快照缩放与悬停导致的终点偏移
补充动画回归测试并更新资源画本技术文档
This commit is contained in:
2026-09-05 11:21:17 +08:00
parent 65ffd4cc69
commit ba718e3d4b
10 changed files with 685 additions and 549 deletions
@@ -2,6 +2,13 @@
> 当前口径:本文件保留可复用的排障经验;历史条目的旧路由、旧版本和已删除文档仅作根因背景,不得据此恢复退役入口。当前命令、路由和 schema 以代码与 `docs/README.md` 为准。
## 2026-09-05 资源画本转场与视口分离
- `resourceBookController` 使用独立 FLIP 快照层和 Web Animations 完成信号;逻辑栏目立即提交,不用定时器猜 CSS 动画终点。再次导航从当前快照位置开始,旧完成回调由 token 失效。
- 屏幕 DOMRect 与逻辑布局坐标不能混用。主画布缩略入口测量先逆 viewport;快照复制必须保留祖先缩放对内部图片、文字的影响,单纯把克隆外框改成屏幕宽高会产生内部留白。
- 点击和滚轮共用导航入口,但滚轮提交不得重置已有的冷却和队列;监听器使用最新导航回调引用,避免视觉 phase 更新重装监听器并清空待处理手势。
- jsdom 不执行真实转场;定向模型测试之外,仍需浏览器核验中断连续性、图片/文字尺寸、viewport 保留和窄屏布局。完整契约见资源自由画板技术方案。
## 2026-09-02 Tauri 事件桥在浏览器预览中必须 fail-safe
- **现象**Vitest/jsdom 挂载 AGC 客户端时,错误报告通知调用 `@tauri-apps/api/event.listen`,因缺少 `window.__TAURI_INTERNALS__` 产生未处理拒绝;测试断言虽通过,CI 仍以 unhandled errors 失败。
@@ -1,38 +1,26 @@
# Game Agent 资源自由画板与快速编辑
## 2026-09-04 动画回归排查与重构收敛方案
## 2026-09-05 资源画本独立转场
最近一组资源画本提交(`f339b383f``019b1761f``f883d4bf2``069248b29``820fbfd98`)把主画布、子画布、真实资源卡、分页画布和滚轮转发逐步叠加在同一个页面组件中,造成状态、坐标和副作用互相耦合。本阶段先完成低风险收敛:
- `resourceBookModel` 立即提交目标 `main / child + category``entering / returning-main` 只表示尚未收尾的视觉过程,不承载待提交的栏目。缩略入口、大纲、下一页、滚轮与资源定位共用分类导航入口;子画布互切直接到达目标,不经过主画布。
- 真实 `ResourceCard` 仍由唯一的 `ResourceBookScene` 挂载,保持预览请求、播放器和交互的单一所有者。转场前 `resourceBookController.begin` 捕获当前可见标题与资源卡的屏幕矩形和表现;目标 DOM 提交后的 layout effect 调用 `play`
- `ResourceBookTransitionLayer` 是 manager 内未变换的独立层。快照仅复制表现,不挂载 React 业务组件,移除重复 ID、业务 data 属性及可访问控件身份,整层 `inert / aria-hidden / pointer-events:none`。播放中的视频优先捕获当前帧;跨源禁止读取时保留已有 poster,不启动第二个播放器。
- FLIP 只动画快照的 transform/opacity,统一时长 420ms,所有 `Animation.finished` 完成后删除快照并恢复目标真实节点;动画创建失败、零尺寸或不支持 Web Animations 时直接完成。`prefers-reduced-motion` 不创建动画,不等待定时器。
- 再次导航先读取当前动画快照的实际位置,再取消旧动画并重新建立目标;token 隔离旧 promise,过期完成和取消均不能提交新状态。窗口尺寸变化、排序或异步布局更新时直接收尾到当前目标,避免使用过期几何。
- 缩放、适应内容和空白拖动先结束视觉转场再执行用户输入;转场中的资源卡 pointer-down 不启动持久化拖拽。普通滚轮保留分页 controller 的原有阈值、冷却与队列,导航提交不能重置该冷却;Ctrl/Meta 滚轮取消待切页队列。
- viewport 只属于用户交互状态,按主画布以及 `sortMode/category` 隔离保存。转场不插值也不持久化 viewport;测量主画布缩略入口时先逆变换回布局坐标,避免缩放后的 DOMRect 被二次缩放。只有真实非零测量才能标记首次 fit 完成。
- 真实 `ResourceCard` 只保留一棵由 `ResourceBookScene` 管理的节点树;主画布缩略卡只负责入口展示,不再复制真实卡片或预览
- 修复主画布稳定 `main/idle` 状态误把标题和共享预览卡隐藏的问题;主画布与返回中的 overview 统一保持可见,只有进入子画布后才切换为活动栏目。
- 转场 timer、`requestAnimationFrame` 和项目切换绑定同一个 token;新目标、切项目或卸载时统一失效旧回调,避免旧动画写入新栏目。
- 从大纲或“下一页”进入时使用已测量的缩略卡布局作为过渡起点;子画布互切先同步逻辑目标栏目,再按既有 320ms/520ms 节奏完成返回与进入动画。
- 主画布 viewport 与子画布 viewport 分离;普通滚轮直接复用分页画布 handler,Ctrl/Meta 滚轮只更新当前 viewport,不再向隐藏 DOM 重新派发 `WheelEvent`
- 转场阶段由 `ResourceBookScene` 统一承载当前 viewport:主画布缩放后的背景、标题、预览卡,以及进入/返回子画布时的目标缩放,都在同一条 `transform` 动画链路中完成,避免缩放后卡片和背景使用不同坐标系。
- 依赖图尚未完成读取时不挂载真实资源卡;失败时允许使用明确的 fallback 快照,避免预览和布局在未确定的图上提前启动。
重构按三个边界推进,不改变当前动画视觉参数:
1. 已抽离 `resourceBookModel``resourceBookLayout``resourceBookViewport` 纯模块,以 reducer 管理 `main / child / entering / returning`,组件只订阅投影并渲染。
2. 已抽离 `resourceBookController``resourceCanvasController`,由 tokenized transition controller 管理 timer/RAF,由分页 controller 管理滚轮阈值、方向、节流和重置;主画布、子画布和分页画布不再通过隐藏 DOM 转发推进状态。
3. 已删除历史资源画本动画规则和重复 hover 选择器,并为快速切换、项目切换、origin 解析、viewport 隔离、唯一预览观察和滚轮状态补充回归测试。
### 当前验证与未收敛项(2026-09-04)
`npm --prefix apps/ai-game-creator-shell run typecheck``npm run check:encoding``git diff --check` 和相关 ESLint 检查已通过。`apps/ai-game-creator-shell/tests/appSurface.test.ts` 已恢复为 `384 passed / 0 failed`,资源画本模型与 controller 测试合计 `9 passed / 0 failed`;另补充主画布稳定态标题与共享预览卡回归场景。
测试仍会输出既有的 React `act(...)` 提示,以及 jsdom 未实现 `HTMLMediaElement.prototype.pause` 的 stderr;这些是测试环境警告,不影响断言结果,也未新增生产兼容层。
验收使用 `resourceBookController.test.ts``resourceBookModel.test.ts``resourceBookViewport.test.ts``appSurface.test.ts`;页面 `.suite.ts``appSurface.test.ts` 注册,不能作为独立 Vitest 文件运行。真实浏览器需覆盖主/子往返、连续改选、滚轮切换、取消后缩放、尺寸变化、减少动画偏好,以及快照图片和字体的正确比例。jsdom 不模拟真实插值,不能代替浏览器验收
### 2026-09-05 子画布无限平移与初始可读比例
子画布改为固定视口加可无限平移的 world 层:视口本身保持 `overflow: hidden`,平移和缩放只作用于 `.game-resource-book-scene-world`,不再让内容容器的边界限制拖动范围。首次 fit(包括隐藏分页画布提前完成的 fit)统一保证比例不低于 `1:1`,避免子画布展开后卡片缩成不可读的小块;用户后续主动缩放或平移的视口仍按每个分类独立保留。新增 viewport 回归测试覆盖初始可读比例和超出内容边界双向平移。
返回主画布时使用独立的 `returning-main` 阶段:卡片先完成子画布到主画布预览位的缩回,随后主画布直接进入稳定布局,不再重复播放 world/main viewport 的平移动画;子画布之间切换仍使用原有的返回后进入动画。
返回主画布时立即提交主画布布局,由独立快照层完成缩回;world/main viewport 不播放附加动画。
## 2026-09-04 资源画本 UI 阶段补充
资源工作台当前产品方向调整为“主画布 + 子画布”的统一画本模型。主画布展示各子画布的缩略卡片,不直接展开真实资源内容;缩略卡片内部按资源类型显示有限层叠卡片,最多展示三层,更多资源以虚化卡片提示。进入子画布时使用共享元素转场:标题栏和资源卡片沿用同一组 DOM 元素,从缩略卡片的原始位置移动、展开到子画布中的目标位置,不允许先播放独立放大动画再硬切另一套内容;主画布预览和子画布展开态必须复用同一套卡片视觉与标题栏结构。进入子画布时在标题栏提供缩回主画布的缩放按钮;从一个子画布切换到另一个子画布时必须先完成缩回主画布,再进入目标子画布。
资源工作台采用“主画布 + 子画布”的统一画本模型。主画布展示各子画布的缩略入口,内部按资源类型显示有限层叠卡片,最多三层,更多资源以虚化卡片提示。主画布预览和子画布展开态复用同一套卡片视觉与标题栏结构,共享元素快照从当前屏幕位置过渡到目标位置。子画布标题栏提供缩回主画布的按钮;子画布互切直接到达目标,不强制经过主画布。
本阶段先实现前端 UI、导航状态和转场表现,资源真实跨画布移动、主画布正式资源登记、上传/生成任务、版本绑定以及 UI 编辑器导入与 UI 包工作流继续沿用现有权威链路,待 UI 编辑器完善后再接入。临时画本视图状态不得替代 manifest、草稿或其它后端业务真相。