把 test/full-test/out/<id>/output.json 串成可交互的虚拟人教学视频预览:
底视频播到节点 → 把引导语 / 等待态 / 反馈语 / 等待话术合成进视频的裁剪区域 bbox →
等待态可选不同选项触发对应反馈语。视频渲染走 canvas。
npm install
npm run dev # 打开输出的本地 URL(如 http://localhost:5173)在左栏上传或粘贴某个 output.json,点「播放」。
底视频 0→节点(冻结底帧) → 引导语(bbox) → 等待态乒乓循环 + 选项浮层
→ 用户点选项 → 反馈语[选中](bbox) → (可选)节点尾段 节点→末尾
- 节点位于底视频的 20s 处(clip = 节点前后各 20s)。
- 引导语 / 反馈语 / 等待话术是「裁剪区域大小」的生成视频,被合成进 bbox 矩形(百分比坐标)。
- 等待态是无音频的空闲视频,用乒乓引擎播放(参考 WaitingSimulatorV3):
- 入场:原速正放 0→t1;
- 循环:t1→t2 正放、t2→t1 倒放,往复乒乓;B 段每 0.5~1.5s 区间 80% 概率随机降速;
- 插话术:走满「等待轮次」轮(一轮 = 一次正放+倒放回 t1)且有话术片段时,插一次等待话术再回循环;
- 退场(点选项后):距 0s ≤ 退场阈值(默认 4s) → 按
max(1, 1+(t-1)/3)线性变速倒放回 0 再进反馈; > 阈值 → 直接跳出接反馈(用这段时间加载反馈视频)。
- 等待态帧在点「播放」时就开始预加载(避免进等待相位卡顿);若进相位时还没就绪, 舞台上会显示「等待态加载中 X%」的提示。
舞台下方的控制条:
- 播放/暂停:暂停/继续当前正在播的片段。
- 进度条:显示当前片段的播放进度;正向片段(节点/引导/反馈/尾段)可点击或拖拽 seek; 等待态乒乓不支持拖拽(会标注「等待态不可拖拽」)。
- 相位指示:节点 → 引导 → 等待 → 反馈 → 尾段,高亮当前相位。
左栏控制项:
- 反馈后继续播节点尾段:关掉则反馈结束停在末帧。
- 空闲插话术超时(s):等待态多久没操作就插一次等待话术(默认 8s)。
- 最小/最大降速:等待态乒乓的随机降速区间(默认 0.7~0.95)。
等待态反向播放需要把视频抽帧成 ImageBitmap,会读 canvas 像素;跨域视频会污染 canvas 致读取失败。
vite.config.js 配了 dev proxy 把 https://video.gaotu.cn/* 映射到同源 /gaotu/*,
proxyUrl 在加载时改写这些 URL。因此必须经 npm run dev 访问,直接用线上 URL 抽帧会失败。
非 video.gaotu.cn 域名的视频不会被代理(会提示风险)。
npm run test # vitest,覆盖纯逻辑:parseConfig / proxyUrl / waitingEngine / bboxToRectcanvas / 播放部分靠手动验收(见 docs/superpowers/plans/2026-06-25-fulltest-frontend-player.md Task 9)。
| 文件 | 职责 |
|---|---|
src/lib/proxyUrl.js |
video.gaotu.cn → /gaotu 同源改写 |
src/lib/parseConfig.js |
output.json → 播放模型(过滤缺失/失败阶段) |
src/lib/waitingEngine.js |
等待态乒乓纯状态机 |
src/lib/frameExtractor.js |
视频 URL → ImageBitmap[](30fps) |
src/player/compositor.js |
bboxToRect + canvas 画图 / 正向 video 驱动 / 帧段驱动(含 controller 控制 + 进度回报) |
src/player/ControlBar.jsx |
播放/暂停 + 进度条 seek + 相位指示 |
src/player/OptionOverlay.jsx |
等待相位题目 + 选项按钮 |
src/player/NodePlayer.jsx |
相位编排(canvas + 隐藏 video + 状态机 + 播放控制 + 预加载) |
src/App.jsx |
外壳:上传/粘贴 JSON + 控制 |