修:draw-ui / oil-motion 原被当子模块指针收录 ⇒ 改为正常文件入库(两份内容原先对别人是空的)

一、问题(本轮实测)
`draw-ui` 与 `oil-motion` 目录里**各自带一个内嵌 `.git`** ⇒ 上一次提交把它们记成了 **gitlink(子模块指针)**
⇒ 仓库里只存了一个不属于任何远端的 commit id,**别人克隆下来这两份是空的** ✗(`git status` 显示 ` m draw-ui` / ` m oil-motion` = 子模块内容有改动)。

二、处置(可回退)
· 把两处的 `.git` **挪走**(⛔ 不是删除)⇒ `归档/内嵌git-20261008/{draw-ui,oil-motion}.git`;
· `git rm --cached` 掉那两个 gitlink,再 `git add` 两个目录 ⇒ **按正常文件入库**(内容才真的进仓库)。

三、副作用(如实记)
挪走 `.git` 后,这两个技能**不能再原地 `git pull` 取上游更新**(要更新得重新拉一份覆盖);
如需恢复其本地仓库,把 `归档/内嵌git-20261008/` 里的 `.git` 挪回原处即可。
This commit is contained in:
admin committed 2026-10-08 22:29:52 +08:00
1 parent e03465c398
commit 237a09a5b0
161 files changed
+19429 -2

No files matched your search

+118
View File
@@ -0,0 +1,118 @@
# 透明图集路线
仅当 Concept Contract 锁定 `background_owner: page`(主体确有透明复用需求),且
`motion_budget.py` 返回 `delivery.selected=alpha-atlas` 时执行本流程。结果不是
`alpha-atlas` 时停止阅读,改走 [chroma-video.md](chroma-video.md) 或
[baked-video.md](baked-video.md)。
本文档只覆盖图集路线专属的帧提取、清理、检测与打包。公共步骤各有唯一事实源:
- 预算与路线选择:[delivery-selection.md](delivery-selection.md)
- 关键帧、提示词与提交命令:[prompting.md](prompting.md)
- 帧策略与图集压缩:[optimization.md](optimization.md)
- 母版验收、抠图验收、Pilot 与帧链硬门:[qa.md](qa.md)
- 运行时映射:[runtime.md](runtime.md)
## 交付物
```text
motion-name/
├── source/
│ ├── first-frame.png
│ ├── last-frame.png # 单向转场需要
│ ├── prompt.txt
│ ├── master.mp4
│ └── master.job.json
├── frames/
│ ├── raw/
│ ├── clean/ # 闭环或尾部清理后
│ └── final/
├── qa/
│ ├── raw-analysis.json
│ ├── raw-contact.jpg
│ ├── final-analysis.json
│ └── final-contact.jpg
└── final/
├── motion.webp
├── motion.json
└── implementation.*
```
## 1. 帧准备与离线抠色
母版通过 [qa.md](qa.md) 的母版验收后再提取帧。色键在这一步离线去除,网页只加载已经透明的图集。
`frame_policy=native` 时按源帧提取,`--key auto` 从画面边缘采样实际背景色:
```bash
python3 "$OIL_MOTION/scripts/motion_pipeline.py" extract \
source/master.mp4 frames/raw \
--key auto
python3 "$OIL_MOTION/scripts/motion_pipeline.py" analyze frames/raw \
--output qa/raw-analysis.json
python3 "$OIL_MOTION/scripts/motion_pipeline.py" contact frames/raw \
--output qa/raw-contact.jpg \
--columns 8
```
`frame_policy=interpolate` 时改用 [optimization.md](optimization.md) 的插帧命令,它同时输出原始与插帧的接触表和对比报告。
在白、黑和真实页面背景上查看接触表:残留色键、主体内部被误删或边缘溢色时,回到母版或关键帧返工,不靠调阈值掩盖。
## 2. 闭环清理与可选稳定
闭环动画:
```bash
python3 "$OIL_MOTION/scripts/loop_cleanup.py" \
frames/raw frames/clean \
--seam-window "$SEAM_WINDOW" \
--duplicate-threshold "$DUPLICATE_THRESHOLD" \
--report qa/loop-cleanup.json
```
该工具只做确定性选帧,不生成动作,也不对相邻帧做透明叠加。接缝选错时调整
`--seam-window`,不要为了减少帧数盲目提高重复阈值。首尾不同的单向转场传入
`--end-reference last-frame.png`,裁掉模型在尾帧上的多余停顿。
固定主体存在轻微漂移时才稳定:
```bash
python3 "$OIL_MOTION/scripts/motion_pipeline.py" normalize \
frames/clean frames/final \
--anchor bottom \
--max-scale-change 0.08
```
不需要清理或稳定的步骤直接跳过,把上一步合格的帧作为 `frames/final`。自由运动、镜头运动和真实透视变化禁止稳定。
## 3. 最终门槛与图集打包
```bash
python3 "$OIL_MOTION/scripts/motion_pipeline.py" analyze frames/final \
--output qa/final-analysis.json
python3 "$OIL_MOTION/scripts/motion_pipeline.py" contact frames/final \
--output qa/final-contact.jpg \
--columns 8
python3 "$OIL_MOTION/scripts/motion_pipeline.py" atlas frames/final \
--output final/motion.webp \
--manifest final/motion.json \
--cell-width 360 \
--cell-height 360 \
--quality 88
```
打包前用最终帧数和单元格尺寸重新运行 [delivery-selection.md](delivery-selection.md)
的预算。只有仍返回 `alpha-atlas` 且通过时才打包;结果变成 `chroma-video` 时停止打包,
改走视频路线。需要压到目标体积时按 [optimization.md](optimization.md) 执行,不要手动
反复猜 WebP 质量。
## 4. 网页实现
从 [assets/interactive-motion.ts](../assets/interactive-motion.ts) 的对应控制器开始,
映射、阻尼、预加载和降级按 [runtime.md](runtime.md) 执行,验收和故障定位按
[qa.md](qa.md) 执行。出现闪帧时按“母版 → 帧 → 图集 → 映射 → 解码”的顺序定位。
+51
View File
@@ -0,0 +1,51 @@
# API Key 配置与业务读取
生成关键帧和视频需要 ZenMux 的 API Key;处理已有素材不需要。运行环境已经可信地注入了 `ZENMUX_API_KEY`(例如 CI 或宿主的密钥配置)时直接复用。本机第一次填写或更换 Key 时,使用随附的本机配置页,不让用户把 Key 贴进聊天,也不改用终端输入。
## 首次配置
页面需要 Node.js 22.18+。第一次使用时在组件目录安装锁定依赖,然后查状态:
```bash
npm --prefix "$OIL_MOTION/scripts/credential-ui" ci --ignore-scripts
node "$OIL_MOTION/scripts/credential-ui/src/profile.ts" status default
node "$OIL_MOTION/scripts/credential-ui/src/profile.ts" setup default
```
`status` 的退出码:0 表示可以读取,2 表示还没配置,1 表示配置或系统凭据服务出错。只有缺失或用户要求更换时才运行 `setup`,把返回的本机链接交给用户亲自填写。不要自动操作真实的 Key 页面,也不截图。
页面不会回填已保存的值:已有项留空表示保留,替换前需要用户确认。只有返回 `saved` 才算全部保存成功;遇到 `partial`、超时或中断,先重新查状态,再补填未完成的项。保存成功只说明 Key 已存好、能读到,Key 是否有效以第一次生成调用的结果为准。
## 服务与用途绑定
| 配置名 | 业务环境变量 | 系统凭据引用 |
| --- | --- | --- |
| default | `ZENMUX_API_KEY` | `oil-motion/zenmux/default` |
图片和视频共用这一个 Key。配置好 Key 不代表可以随意调用收费接口:每次生成仍按主流程先做 Pilot,批量生成前让用户确认。
以后接入其他服务时,每个服务各写一份独立声明;需要在同一页填写时,用组件的 `configure-page` 组合,见[组件说明](../scripts/credential-ui/README.md)。不要求用户填写用不到的服务。
## 运行业务
`image_job.py` 与 `video_job.py` 都通过 `profile.ts run default --` 运行,`--` 后面照原样写业务参数。完整命令只维护在[提示词与提交](prompting.md),不要在别处复制,也不要省略 Pilot、production 等必要参数。
环境变量优先;没有时,run 入口只从系统凭据库读取这个配置需要的 Key,并只注入给它启动的业务进程。命令参数、普通文件和状态输出里都不会出现 Key。页面保存的 Key 只能经 run 入口读到:直接运行生成脚本会报“读取不到 ZenMux API Key”,这时改用 run 入口,不要让用户重新填写。
## 平台与安全边界
系统凭据库分别是 macOS 钥匙串、Windows 凭据管理器和 Linux Secret Service。Linux 还需要 `secret-tool`、用户 D-Bus 和已解锁的桌面凭据服务。缺少后端时直接停止,不自动安装、解锁,也不改存明文。目前只在 macOS 上做过原生验证,Windows 和 Linux 还需要实机验收。CI、容器和远程服务器使用已有的密钥注入,不要把本机配置页开放到网络上。
旧版 `~/.config/oil-motion/config.json` 里的明文 Key 仍能被脚本读到,但不会被自动迁移或删除;用户在页面重新保存后,可以自己删掉旧文件。Key 属于当前系统用户,正常流程不会让它进入对话,但这不等于能防住同一用户下运行的任意程序。
## 验证
修改凭据组件后运行:
```bash
npm --prefix "$OIL_MOTION/scripts/credential-ui" run check
npm --prefix "$OIL_MOTION/scripts/credential-ui" run build
npm --prefix "$OIL_MOTION/scripts/credential-ui" test
```
测试用假后端覆盖页面、同页保存、业务变量读取、部分失败恢复和脱敏,不操作用户真实的 Key。原生测试 `npm run test:native` 只创建随机的测试条目并在结束后清理,不验证服务额度或生成效果。
+83
View File
@@ -0,0 +1,83 @@
# 烘焙视频路线
仅当 `background_owner: video` 且预算返回 `delivery.selected=baked-video` 时读取。视频包含完整画面;不做抠色、色键或页面背景合成。
## 编译
先完成内容验收和预算,再运行:
```bash
python3 "$OIL_MOTION/scripts/compile_scroll_video.py" \
"$SOURCE_VIDEO" "$OUTPUT_DIRECTORY" \
--background-owner video \
--budget-report build/motion-budget.json \
--frame-policy "$FRAME_POLICY" \
--fps "$TARGET_FPS" \
--timeline-output build/timeline.json \
--desktop-width "$DESKTOP_WIDTH" \
--mobile-width "$MOBILE_WIDTH"
```
`FRAME_POLICY` 与 `TARGET_FPS` 来自 Motion Brief。使用 `native` 时目标帧率等于源帧率;使用 `interpolate` 时目标帧率必须更高。
编译器会:
1. 按帧策略保留原始帧或插帧,并输出对应接触表和报告。
2. 按需清理闭环接缝或尾部重复帧。
3. 编码桌面端和移动端全关键帧 MP4,移除音轨。
4. 生成普通 `poster.png` 与 `compile.json`。
多段时间轴用 `--initial-state-id` 指定初始状态,并用重复的 `--segment DESTINATION_STATE_ID=START:HOLD:END_EXCLUSIVE` 传入后续状态与帧边界;需要统一播放曲线时使用 `--playback-curve` 及对应速率参数。编译器负责生成状态映射并把最终保留帧换算成时间。
成功后默认删除可重新生成的中间 PNG;只有诊断帧准备、裁剪或编码问题时才使用 `--keep-frames`。
## 多段连续
`clip_continuity=chain` 时,按 [qa.md](qa.md) 同时执行:
- 上一段实际尾帧作为下一段生成输入;
- 相邻成片解码后的尾帧与首帧接缝验收;
- 身份、构图、光线和背景偏差累积检查。
合并后从最终成片生成 `timeline.json`,不手工抄写段落时间。
“分段”只属于生产过程。交付前必须把连续链编译为每个设备版本各自的一条主视频;运行时不得把生产片段逐段设为 `src`。
## 网页接入
页面只保留一个持续存在的视频元素:
```html
<section class="motion-stage">
<video class="motion-video" muted playsinline preload="auto"></video>
</section>
```
```css
.motion-stage { overflow: hidden; }
.motion-video { width: 100%; height: 100%; object-fit: cover; display: block; }
```
根据预算中的 `runtime.controller` 接入 [runtime.md](runtime.md):
- `frame-scrub`:整数帧映射到 `currentTime`。
- `segment-playback`:读取 `timeline.json` 分段播放、反向和精确停帧。
- `autonomous-playback`:按时间播放,仅在素材通过闭环验收时循环。
控制器变化不改变视频背景归属,也不需要重新选择媒体格式。
桌面与移动资源只在会话初始化时选择。分页、反向和普通 resize 期间不换 `src`;确需切换设备版本时,执行一次受控重载并恢复到当前状态的 `hold`,不能把换源当作页面转场。
## 加载与降级
- 预加载 `poster.png` 和首个需要的视频资源。
- 视频解码或资源加载失败时显示 `poster.png`。
- `prefers-reduced-motion` 显示合同指定的静态状态。
## 验收
- 完整观看桌面与移动输出,确认主体、背景、光线、接触关系和镜头连续。
- 多段输出接缝通过 [qa.md](qa.md) 的成片连续性硬门。
- `compile.json` 中桌面与移动输出的 `allFramesAreKeyframes` 为 `true`。
- 实际页面没有抠色、色键 Shader 或阈值配置。
- 按选中的控制器验收 seek、分段播放或自动播放,不混用验收标准。
+94
View File
@@ -0,0 +1,94 @@
# 色键视频路线
仅当 `background_owner: page` 且预算返回 `delivery.selected=chroma-video` 时读取。主体通过 WebGL 实时生成 Alpha,页面拥有最终背景。
如果镜头、环境光、接触阴影、景深或背景连续性属于画面主体的一部分,停止本路线并回到合同改用 [baked-video.md](baked-video.md)。
## 编译
输入必须是从已验收透明关键帧确定性合成、并由视频模型保持均匀的色键母版:
```bash
python3 "$OIL_MOTION/scripts/compile_scroll_video.py" \
"$SOURCE_VIDEO" "$OUTPUT_DIRECTORY" \
--background-owner page \
--budget-report build/motion-budget.json \
--frame-policy "$FRAME_POLICY" \
--fps "$TARGET_FPS" \
--timeline-output build/timeline.json \
--desktop-width "$DESKTOP_WIDTH" \
--mobile-width "$MOBILE_WIDTH"
```
需要记录语义锚点时追加 `--anchor NAME=SOURCE_FRAME`;静态降级状态使用 `--poster-source-frame`。索引都基于帧准备后的序列,编译器会在清理后重新映射。
编译器会:
1. 按 `frame_policy` 保留原始帧或插帧,并输出接触表与报告。
2. 按需清理接缝或重复尾帧。
3. 检查整段代表帧的色键颜色与边缘均匀度。
4. 编码桌面与移动全关键帧 MP4。
5. 逐帧模拟运行时抠色,使用与 WebGL 相同的 `dominance-v2` 参数检查残留、误删和溢色。
6. 生成编码后 Alpha 接触表、`background-matrix`、静态 Alpha 降级图和 `compile.json`。
多段时间轴用 `--initial-state-id` 指定初始状态,并用重复的 `--segment DESTINATION_STATE_ID=START:HOLD:END_EXCLUSIVE` 传入后续状态与帧边界。编译器从最终保留帧生成状态映射与 `timeline.json`,页面不得手工换算秒数。
默认删除可重新生成的中间 PNG;诊断帧准备、抠色或编码问题时才使用 `--keep-frames`。
## 抠色硬门
- 编译后的实际 MP4 解码帧仍有可见色键块、边缘溢色、主体内部误删或半透明脏边时,拒收母版。
- 禁止靠扩大抠色阈值、腐蚀轮廓或模糊边缘掩盖素材缺陷。
- 阈值只能复现已验收母版的已知色键,不能修复不均匀背景或错误主体颜色。
- 半透明、发丝和大范围运动模糊属于高风险输入;无法稳定通过时重新生成,或重新评估背景归属。
- 自动报告通过后仍要查看白、黑、高饱和色和真实页面背景上的合成结果。
## 网页接入
使用两个共享实现:
- [assets/interactive-motion.ts](../assets/interactive-motion.ts):按 `runtime.controller` 控制帧或视频时间。
- [assets/chroma-video-renderer.ts](../assets/chroma-video-renderer.ts):读取 `compile.json.runtime.keying` 并绘制透明 Canvas。
`frame-scrub` 调用 renderer 的 `render(frame)`。`segment-playback` 或 `autonomous-playback` 在视频按时间播放期间调用 `startLive()`,停止或销毁时调用 `stopLive()`。不要在页面复制 Shader 参数或另写抠色算法。
```ts
const runtime = manifest.runtime;
const renderer = createChromaVideoRenderer({
video,
canvas,
frameCount: runtime.frameCount,
fps: runtime.fps,
keying: runtime.keying,
});
```
页面不能直接显示色键视频:
```html
<section class="motion-stage">
<video class="motion-source" muted playsinline preload="auto"></video>
<canvas class="motion-canvas"></canvas>
</section>
```
```css
.motion-stage { background: var(--page-background); }
.motion-source { display: none; }
.motion-canvas { width: 100%; height: 100%; display: block; }
```
## 加载与降级
- 预加载静态 Alpha 状态、视频元数据和首个需要的媒体。
- WebGL、视频解码或资源加载失败时显示静态 Alpha 图,不能露出色键母版。
- `prefers-reduced-motion` 显示合同指定的静态 Alpha 状态。
## 验收
- `qa/post-encode-keying.json` 的桌面与移动结果均为 `passed: true`。
- `compile.postEncodeKeyingPassed` 为 `true`,实际检查帧数与报告一致。
- 查看 Alpha 接触表和 `background-matrix`;自动报告不能替代视觉检查。
- `allFramesAreKeyframes` 为 `true`。
- 按实际 `runtime.controller` 检查快速反向、停帧、连续播放或循环。
- 页面更换背景只改变页面层,不重新生成主体。
+163
View File
@@ -0,0 +1,163 @@
# 交互动画创意方法
当用户询问“可以做什么效果”、只有目标没有动作方案,或现有动画缺少表达目的时读取本文件。
## 从作用开始
先确定动画承担的主要作用,只选一个主作用:
- 引导注意:让用户发现可以交互的对象。
- 解释关系:展示输入、过程、因果、层级或空间关系。
- 表达进度:让连续位置、阶段或完成度可感知。
- 提供反馈:确认悬停、拖拽、提交、成功、失败或等待。
- 奖励探索:让用户主动操作后获得有意义的变化。
- 营造情绪:建立轻快、克制、紧张、柔和或机械的节奏。
没有作用的动作只是装饰。装饰可以存在,但必须低成本、可暂停且不干扰内容。
需要案例时,按作用查阅 [网页动效参考模式](motion-patterns.md)。借用输入与反馈的关系、视觉锚点和信息节奏,再替换成用户自己的对象;不要把参考站的皮肤、题材或实现猜测当作默认方案。
## 先审计对象的运动潜力
不要从“场景视频、绿幕、雪碧图、视差、跟随鼠标”开始。先检查对象本身:
| 维度 | 要问的问题 | 常见变化 |
|---|---|---|
| 结构 | 由哪些层、壳体、部件和连接组成? | 组装、拆解、爆炸图、剖切、折叠、展开 |
| 功能 | 输入、处理和输出是什么? | 启动、传递、计算、充能、响应、完成 |
| 材质 | 表面和内部能否改变可见性? | 透明、X 光、线框、液态、熔化、结晶 |
| 空间 | 用户应该从哪里看到哪里? | 环绕、推进、拉远、穿越、进入内部、越过尺度 |
| 状态 | 前后状态有什么意义? | 开关、空满、快慢、新旧、普通与专业模式 |
| 信息 | 哪些关系需要被理解? | 分流、汇聚、映射、因果、比较、层级、反馈 |
一个手机可以从完整外观变成爆炸图、进入芯片内部、沿信号路径点亮,再重新组装。
一个软件产品可以从界面进入数据管线,展示处理过程后回到结果。例子只说明方法,不是
Skill 的默认题材。
## 动作语法
从下面选择能表达内容的动词,不要把所有变化塞进一条动画:
- 结构:assemble、disassemble、explode、separate、stack、fold、unfold、peel、cutaway。
- 形态:morph、inflate、compress、grow、dissolve、crystallize、flow。
- 材质:reveal、x-ray、wireframe、scan、heatmap、translucent。
- 空间:orbit、dolly、macro、fly-through、tunnel、parallax、scale-jump。
- 信息:trace、route、pulse、branch、converge、compare、highlight。
- 状态:activate、charge、complete、unlock、switch、transform。
## 把输入映射到变化
| 输入 | 连续参数 | 适合的视觉回应 | 参数结构 |
|---|---|---|---|
| scroll | 全页或局部进度、速度 | 拆解、组装、穿越、材质和章节转场 | linear |
| pointer | 方向、距离、速度 | 环绕视角、聚焦部件、剖切深度、光照扫描 | circular / 2d |
| drag | 位移、角度、拉伸量 | 直接拆分、撕开、旋转、比较前后 | linear / 2d |
| touch / orientation | 倾斜、方向、力度 | 重力、内部层差、液体、空间视差 | 2d |
| audio | 音量、频谱、节拍 | 频谱结构、脉冲、形变、排列 | linear |
| data / state | 数值、阶段、成功失败 | 流量、热力、完成度、模式切换 | linear / discrete |
### 转动与视向:先分清转的是什么
“转动 360°”至少对应四种完全不同的素材。合同里只写“转一圈”,模型就会自己挑一个旋转轴,所以先按下表分型:
| 类型 | 画面上发生什么 | 参数空间 | 输入映射 | 典型用途 |
|---|---|---|---|---|
| 圆周注视 | 脸始终朝向镜头,视线沿屏幕前方的一圈移动:12 点抬头、3 点看右、6 点低头、9 点看左,再回到 12 点;不露后脑勺 | circular | 指针相对主体中心的角度 | 吉祥物、头像、数字人跟随光标 |
| 二维注视 | 同样面向镜头,但上下与左右幅度分别变化,指针靠近中心时接近正视 | 2d | 指针的 x、y 分量 | 需要区分“看得多远”的角色 |
| 水平摆头 | 只绕竖直轴左右转,例如 -60° 到 +60°,两端是极限,中间是正视 | linear | 指针 x 或横向进度 | 横向巡视、侧向视差 |
| 展台自转 | 主体绕自身竖直中轴转满一圈,依次露出正面、侧面和背面 | circular | 拖动距离或滚动进度 | 手机、腕表、球鞋等硬件展示 |
圆周注视只用到方向角,指针远近不改变姿态。如果角色在指针靠近时应该接近正视、离远了才明显转头,就要用二维注视,不能拿一条环形视频代替。展台自转会露出侧面和背面:真实产品先用参考图生成 0°、90°、180°、270° 四张关键帧,再分四段生成;只给一张正面图让模型一次转完,背面就是模型猜出来的。
## 一镜到底:先想好接缝藏在哪里
滚动驱动的一镜到底,本质上是多段首尾相接的短视频(`K0 → K1 → K2…`):上一段的尾帧就是下一段的首帧,每段只完成一级变化。场景切换发生在段内,靠某个一直在画面里的东西把前后两个世界接起来。所以先选“接缝藏在哪里”,再设计关键帧:
| 范式 | 接缝藏在哪里 | 交接关键帧怎么定 | 主要风险 |
|---|---|---|---|
| 尺度穿透 | 画面正中心的锚点物体 | 上一段的尾帧就是下一段的首帧,画面中心的小物体是下一段要推近的目标 | 每段只放大一级;跨度太大时模型会在途中换掉物体 |
| 遮挡转场 | 前景实体完全挡住镜头的那一帧 | 遮挡物占满画幅的同一张图,同时作为上一段尾帧和下一段首帧 | 遮挡不完全时,背景置换会露出来 |
| 形状匹配 | 两个场景里轮廓相同的物体 | 一段以圆形表盘为首帧、以同位置同大小的星球为尾帧,轮廓不动,只换表面内容 | 轮廓在段内移动或变形,就会像硬切 |
| 时间流转 | 锁死的机位和轮廓 | 用同一构图和姿态,生成不同年代或季节的状态图 | 模型容易顺带改几何;关键帧之间逐项对照结构 |
| 倒影穿越 | 眼睛、镜面或水滴里的倒影 | 一段以倒影特写为首帧、以倒影里的场景全景为尾帧,推进中倒影逐渐充满画面 | 特写帧里的倒影要足够清楚,提前生成锁定 |
| 剖切穿墙 | 外墙溶解成剖面或线框 | 完整外墙为首帧,剖开后的内部结构为尾帧 | 推进速度要匀,突然减速会让溶解看起来像卡住 |
整座城市折叠、重力翻转这类大范围形变,当前视频模型很难保持几何连续。只在用户明确要求时尝试,并先用 Pilot 验证。
选定范式后再检查三件事:
- **倒放是否成立。** scrub 模式下用户会往回滚:推进变成拉远,溶解变成复原,这些都自然;爆炸、泼洒这类倒放违反直觉的动作,要单独生成反向片段;分段播放的反向默认也是倒放同一段,同样要检查。
- **停在任意位置是否好看。** scrub 的每一帧都可能成为静止画面,不要靠运动模糊掩盖形变。
- **文字放在哪里。** 需要阅读的说明放在交接关键帧附近的稳定状态上,由页面层叠加,不写进视频。
## 判断语义与几何
- 部件连接、壳体开启、材质形变、关节、抓握、毛发、布料和遮挡属于语义运动,由关键帧约束下的 AI 视频生成。
- 位移、缩放、旋转、裁切、路径、惯性和参数映射属于几何运动,由程序完成。
- 只要移动整张图片会破坏接触或遮挡关系,就生成完整语义动作。
## 按显示尺度选择复杂度
- 小型控件:动作短、轮廓清晰、状态明确,只生成必要的短片段和少量帧。
- 内容插画:允许一个主要语义动作,控制持续时间和资源体积。
- Hero 或全屏叙事:先锁 Concept Contract 的背景归属,再做资源预算;路线选择按
[delivery-selection.md](delivery-selection.md) 的决策顺序执行。
- 长页面连续滚动:区分全页进度和局部章节进度,不默认把整页映射到一条视频。
## 让三个方向真正不同
方向必须来自对象本身,而不是沿用上一个项目。同一个对象先从结构、空间或镜头、材质或状态三类变化里各想一个方向,再挑出最多三个。用户已经明确动作时,不为凑数量增加无关方向。
三个方向至少在两项上不同:
- 不同驱动方式。
- 不同参数空间。
- 不同表达作用。
- 不同运动主体或结构。
- 不同关键状态或镜头路径。
避免给出三个只是速度、幅度或颜色不同的同类方案。
## 方向卡
每个方向写一张简短的方向卡,方便用户比较和挑选:
1. **表达目的**:用户通过这次交互新理解了什么,或完成了什么。
2. **起止状态与锚点**:起始和最终画面是什么,哪些身份、结构或阅读位置始终不变。
3. **真正变化的部分**:哪些结构、材质或镜头发生变化;镜头移动时写清轨迹。
4. **输入与回应**:输入怎样映射到进度或状态;停手、反向和再次触发时画面怎样回应。
5. **制作分工**:哪些画面由关键帧锁定,哪些变化交给视频模型,哪些文字、布局和状态由程序实现。
6. **成本与替代**:目标尺寸下的清晰度、帧数和加载成本,触屏怎么操作,静态替代是什么,以及最需要先验证的风险。
借用了外部案例时,再写明案例链接、实际看到的现象,以及哪些只是推测,见 [motion-patterns.md](motion-patterns.md)。
## 把方向变成关键帧
需要生成素材时,生产顺序固定为“先生图,再生视频”。每个方向先回答:
1. 起始图是什么。
2. 结束图是什么。
3. 是否需要中间关键帧才能让变化稳定。
4. 哪两张相邻关键帧组成一段视频。
- 真实产品的 Logo、孔位、部件数量和比例不能漂移时,用原始产品图作为参考生成并验收每张关键帧,不让视频模型凭文字猜终点。
- 单段视频只完成一个主要语义变化,例如“整机拆开”或“镜头进入芯片”。
- 多阶段叙事使用 `K0 → K1 → K2…`:先验收全部计划关键帧,再从 Pilot 开始逐段生成视频。
- 文字、数字、进度和高亮由程序在运行时叠加;主要画面与转场仍来自关键帧约束的 AI 视频。
例如“手机完整态 → 爆炸图 → 芯片特写 → 重新组装”需要四张关键帧和三段视频,
不是一条长提示词。这样每段更稳定,也便于滚动正反播放和单独重做。
## 创意质量门槛
拒绝以下方向:
- 用户输入与画面变化没有可理解的关系。
- 动画只有自动播放,没有交互带来的新信息或反馈。
- 静止状态不成立,必须一直运动才能看懂。
- 用高成本栅格视频实现简单几何运动。
- 为了使用已有视频而强行选择不匹配的参数模型。
- 只能在演示尺寸成立,缩小或触屏后失去意义。
- 用赛博霓虹、机械电路、发光细线这类套路装饰填满画面,掩盖结构和镜头上的问题。
选定方向后,把它转换为 Motion Brief,再进入资源预算、生成和实现。
+122
View File
@@ -0,0 +1,122 @@
# 自动选择交付与运行时
本文件是媒体格式选择的唯一事实源。选择分为三个正交问题,必须依次处理:
1. `background_owner` 决定背景是否烧入媒体。
2. 参数空间、访问方式和资源预算决定媒体格式。
3. `time_control` 决定运行时控制器。
不要用媒体格式推断播放方式,也不要用滚动或分页布局推断 scrub。
## 1. 背景归属
- `video`:背景与主体在同一视频中生成,选择 `baked-video`,不抠色。
- `page`:主体必须透明复用。关键帧直接生成真实 Alpha;需要视频模型时才从透明源合成色键输入,再在 `alpha-atlas` 与 `chroma-video` 中预算。
`--background-owner` 没有默认值。合同未锁定时停止,不得因为参数缺失静默选择透明或色键路线。
## 2. 执行预算
生成素材前用 Brief 的计划帧数(目标帧率 × 时长)运行一次,帧准备完成后再用实际帧数复核:
```bash
python3 "$OIL_MOTION/scripts/motion_budget.py" \
--frames "$FRAME_COUNT" \
--display "$DISPLAY_SIZE" \
--dpr "$TARGET_DPR" \
--driver "$DRIVER" \
--time-control "$TIME_CONTROL" \
--parameter-space "$PARAMETER_SPACE" \
--background-owner "$BACKGROUND_OWNER" \
--report build/motion-budget.json \
--strict \
--json
```
只有 `driver=scroll` 且 `time_control=scrub` 时才额外传 `--scroll-pages`,用于检查滚动采样密度。分段播放按成片帧率验收,不把页面数量换算成 scrub 帧数。
读取以下结果:
- `delivery.selected`:唯一主媒体格式。
- `delivery.reasonCodes`:选择依据。
- `runtime.renderer`:对应渲染器。
- `runtime.controller`:对应时间控制器。
- `failures` 与 `passes`:阻断项。
## 3. 固定决策顺序:媒体格式
1. `background_owner=video`:选择 `baked-video`。
2. `parameter_space=2d`:选择 `alpha-atlas`;超预算时降低采样或拆分轴后重新预算。
3. `parameter_space=discrete`:每个独立状态或转场分别预算,不把无序状态拼成线性视频。
4. 随机访问且单图集与解码内存均在预算内:选择 `alpha-atlas`。
5. 一维顺序访问且达到视频帧数门槛:选择 `chroma-video`。
6. 一维图集超过纹理或解码内存预算:选择 `chroma-video`。
7. 其余小型透明资源:选择 `alpha-atlas`。
`background_owner=video` 遇到二维或无序离散参数时,拆成多条独立烘焙片段分别预算;不能压成一条时间轴。
## 纹理上限怎么计算
`--max-texture=4096` 限制的是单张纹理的宽和高,不直接限制帧数。预算必须使用
“最大 CSS 显示尺寸 × 目标 DPR”得到最低单格尺寸,再计算单张图集容量:
```text
columns = floor(max_texture / cell_width)
rows = floor(max_texture / cell_height)
capacity = columns * rows
```
例如 48 帧、最低单格 640×640 px 时,4096 纹理只能容纳 6×6=36 帧,不能做成
一张图集。改成 7×7 时单格最多约 585×585 px;使用 576 px 只有在实际显示尺寸
乘 DPR 不超过 576 时才成立,不能为了塞进一张图而牺牲已确认的清晰度。
同理,16×14 排列能否放进一张图只取决于单格尺寸:宽最多 256 px,高最多约
292 px。帧数很多的图集能放进一张图,靠的是更小的单格,不是绕过了浏览器纹理上限。
当前运行时只接受一张主图集。圆环或一维时间轴超出单图集预算时自动选择
`chroma-video`;真正的二维参数仍需要 `alpha-atlas`,超预算时降低参数采样密度、
拆分独立状态或拆分参数轴后重新预算。不要自行实现未经过预算和预加载验收的多图集切换。
## 4. 控制器选择
控制器只由合同中的 `time_control` 决定:
| `time_control` | `runtime.controller` |
|---|---|
| `scrub` | `frame-scrub` |
| `segment-play` | `segment-playback` |
| `autonomous` | `autonomous-playback` |
`delivery.selected` 可以与任一合理控制器组合。例如视频既可以逐帧 scrub,也可以按片段正常播放;图集也可以按时间自动播放。
## 超预算处理
- `alpha-atlas` 超预算:降低采样密度、拆分独立状态,或在用户已确认的显示范围内重新预算;不得偷降清晰度。
- `chroma-video` 被选中:只保留 QA 帧和静态 Alpha 降级,不再生成大型 Alpha 图集。
- `baked-video` 被选中:不得加入抠色、色键 Shader 或页面背景合成。
- 源素材低于最大 CSS 尺寸乘 DPR:重新生成或调整已确认的显示目标,不从低清网页资产反向放大。
任何调整后都重新运行预算,旧报告失效。
### 母版像素不足时的显示预算
视频的可用分辨率见 [prompting.md](prompting.md#分辨率和时长)。预算使用探测到的实际
像素尺寸,通过 `--source WIDTHxHEIGHT` 传入;不能把分辨率标签或放大后的尺寸当作源尺寸。
同时核对宽高与最终裁切,目标 DPR 不得超过
`min(源宽 / CSS 宽, 源高 / CSS 高)`。
例如只有 `1344×768` 母版、最大显示为 `1280×720` CSS px 时,把原先的高 DPR 目标下调为
`--display 1280x720 --dpr 1.05 --source 1344x768`,所需像素为 `1344×756`,
再按上面的预算命令运行 `--strict` 并重写 `build/motion-budget.json`。若保留 DPR `2`,
则把 16:9 显示目标缩小到最多 `672×378` CSS px。编译资源宽度不得超过母版可用宽度。
降低目标 DPR 是素材清晰度取舍,不改变设备的真实 DPR,也不代表在高 DPR 屏幕上达到
原来的清晰度。将调整同步到合同的 `destination` 与 Brief 的 `quality_target`、
`pixel_dimensions`,按新目标重新验收;不得只改预算数值而仍在更大的容器中显示。
## 后续路由
- `alpha-atlas`:读 [alpha-atlas.md](alpha-atlas.md)。
- `chroma-video`:读 [chroma-video.md](chroma-video.md)。
- `baked-video`:读 [baked-video.md](baked-video.md)。
- 控制器实现:读 [runtime.md](runtime.md)。
+84
View File
@@ -0,0 +1,84 @@
# 动画原理展示页
需要把“母版视频如何变成可交互动画”讲清楚时,使用
`scripts/create_explainer.py` 生成独立 HTML。不要复制某个项目的角色、文案或布局;
页面只读取图集结构和驱动配置。
## 页面包含
- 左侧完整雪碧图,可缩放、拖拽,并高亮右侧真正渲染的帧。
- 可选“母版视频”Tab,用于对照 AI 视频和编译后的网页资产。
- 右侧实时动画、帧号、行列位置和输入映射公式。
- 桌面端 2:1 布局,移动端自动上下排列。
- 图集解码完成后才显示,避免首帧闪烁。
## 驱动方式
| `--driver` | 输入 | 适用素材 |
|---|---|---|
| `pointer-angle` | 指针相对主体的方向 | 环形方向、朝向、旋钮 |
| `pointer-x` | 指针在预览区的横向位置 | 线性姿态、前后对比 |
| `drag` | 横向拖拽距离 | 可抓取产品、逐帧检查 |
| `scroll` | 页面滚动进度 | 章节转场、产品拆解、一镜到底 |
| `autoplay` | 时间 | 待机、循环动作、无需操作的展示 |
`pointer-angle` 使用首尾相连和最短环形距离。其余交互默认是有起止点的线性序列。
自动播放支持 `loop`、`pingpong` 和 `once`。
滚动模式生成前先按 [delivery-selection.md](delivery-selection.md) 运行预算,并传
`--scroll-pages`。预算默认要求每屏至少 24 帧;帧数不够时,长滚动会出现明显的换帧
阶梯,不能只靠调小 `smooth-time` 掩盖。
## 生成
图集 URL 和视频 URL 最终写入 HTML,均以输出 HTML 的目录为基准。manifest 是生成
时读取的本地 JSON,不会在浏览器运行时请求。
```bash
python3 "$OIL_MOTION/scripts/create_explainer.py" \
--title "一张图,240 个方向。" \
--manifest final/motion.json \
--atlas-url ../final/motion.webp \
--video-url ../source/master.mp4 \
--driver pointer-angle \
--output motion-explainer.html
```
没有 manifest 时直接给出网格参数:
```bash
python3 "$OIL_MOTION/scripts/create_explainer.py" \
--atlas-url ./motion.webp \
--frames 96 \
--columns 12 \
--rows 8 \
--cell-width 320 \
--cell-height 320 \
--driver scroll \
--scroll-pages 4 \
--output scroll-explainer.html
```
自动播放:
```bash
python3 "$OIL_MOTION/scripts/create_explainer.py" \
--atlas-url ./idle.webp \
--frames 48 --columns 8 --rows 6 \
--driver autoplay \
--autoplay-fps 18 \
--autoplay-mode pingpong \
--output autoplay-explainer.html
```
输出已存在时脚本默认停止;确认目标后再传 `--force`。
## 验收
1. 通过本地 HTTP 服务打开页面,不只用 `file://`。
2. 检查右侧当前帧与左侧高亮格严格一致。
3. 检查首帧、尾帧、快速反向和环形接缝。
4. 切换视频 Tab 后能播放,切回图集时视频暂停。
5. 滚动模式页面确实有滚动距离,进度能完整覆盖 0 到 1。
6. 在 0%、50%、100% 三个位置检查右侧帧号与左侧高亮严格一致,并快速反向滚动确认没有漏帧或明显阶梯。
7. 在移动端检查布局、触摸拖拽和 reduced-motion 静态降级。
+168
View File
@@ -0,0 +1,168 @@
# 网页动效参考模式
## 目录
- [使用方法](#使用方法)
- [按表达目的选方向](#按表达目的选方向)
- [模式卡](#模式卡)
- [把模式编成可验收的方向](#把模式编成可验收的方向)
- [参考采纳门槛](#参考采纳门槛)
## 使用方法
这些模式提供创意参照,不是必须使用的风格或已经交付的运行时能力。只读与当前表达目的相关的两三张卡。
参考资料分为三类证据:**交互实测**指操作过公开页面;**预览观察**指观看过展示录像;**页面说明**指作者或策展页面的描述。录像里的指针、滚动条和按钮不等于能操作的真实页面。案例会更新,复用前重新核对链接与版本;实现建议是模式转译,不代表原站源码。
先分清动作发生在哪一层:
| 层 | 回答的问题 | 生产方式 |
| --- | --- | --- |
| 素材语义 | 身体、结构、材质、遮挡或场景实际发生什么变化? | 需要生成时,沿现有关键帧、Pilot、媒体预算与时间轴流程执行 |
| 容器编排 | 哪张图成为焦点,窗口怎样放大,文字何时让位? | 程序控制位移、比例、透视、遮罩和层级;不为这些动作额外生成视频 |
| UI 状态 | 选中了什么,操作处在哪一步,用户能否取消? | 程序维护真实状态、文本、焦点与事件;动画表现状态,不替代状态 |
只涉及后两层的方向交给普通前端实现,不进入本 Skill 的生图、生视频或 `motion_budget.py`。混合方案只让语义素材进入媒体流水线;没有新增 `delivery.selected` 或控制器枚举。二维模拟、实时三维和语音处理也不能因为有参考案例就宣称现有素材控制器已支持。
## 按表达目的选方向
| 主要目的 | 优先模式 | 主要驱动 | 成本来源 |
| --- | --- | --- | --- |
| 解释同一产品的不同能力 | 01 材质章节、02 表面进入内部 | scroll / state | 关键帧连续性与产品保真 |
| 把注意力交给一个对象 | 03 小窗扩展、04 多图汇聚、06 透视归正 | scroll | DOM 编排、媒体加载 |
| 把零散内容组织成关系 | 05 散点成序、09 关系星图 | scroll / state | 稳定对象标识与阅读顺序 |
| 鼓励主动探索 | 07 贴纸舞台、08 就地预览、12 内容空间 | pointer / drag | 命中、遮挡与移动端替代 |
| 展示多个可比较的选择 | 10 压缩展开 | state / touch | 可读布局与键盘焦点 |
| 让过程和累计变化可感知 | 11 语音状态体、13 使用痕迹 | audio / data / state | 真实数据和状态反馈 |
| 让模式切换具有连续性 | 14 图标共享形态 | state | 语义清晰与精确几何 |
## 模式卡
### 01 同一产品,材质与场景按章节变化
- **参考**:[MotionSites / Cordex](https://motionsites.ai/?prompt=cordex),预览观察:同一条管状产品以大比例展示,编织材质、应用场景和参数卡发生切换。
- **转译**:把“多个卖点”变成同一对象的多种可见状态,例如外壳保护、内部结构、不同环境适配。机位、主轴和产品轮廓是视觉锚点。
- **输入与状态**:有因果顺序的章节可用 `scroll + scrub + linear`;独立型号选择属于 `state + discrete`,不能假设任意两个型号都有连续视频过渡。
- **制作分工**:AI 素材承担材质、结构和环境变化;型号、参数和选项用 DOM。纯换色能准确计算时直接用程序或真实三维。
- **验收重点**:停在中间也看得懂;参数只随已确认状态切换;反向滚动不把 A 型号说明留在 B 型号画面上。触屏提供章节入口,静态替代展示产品与相应参数。
### 02 从表面进入内部,再回到可解释的整体
- **参考**:[MotionSites / Alethia](https://motionsites.ai/?prompt=alethia),预览观察:岩石状主体及蓝色表面结构在近景、整体与不同构图间变化。
- **转译**:借鉴“整体—细节”的尺度关系,不复制岩石皮肤。可用于材料孔隙、产品内部或概念系统;真实结构需要原始资料约束。
- **输入与状态**:有起止的推进用 `scroll + scrub + linear`。自由观察或任意绕行则需要二维/三维表示,不能伪装成一条视频。
- **制作分工**:先选始终可辨认的纹理或部件作锚点;生成整体、过渡入口、内部三个关键状态;精确标签由程序跟随已标定位置。
- **验收重点**:微观细节与原对象有可解释的关系,回退能找回原位置;新内容出现前给出阅读空间。移动端可以缩短路径并直接展示局部放大图。
### 03 小窗口扩展成主舞台
- **参考**:[21st / Scroll media expansion hero](https://21st.dev/@arunachalam/components/scroll-expansion-hero)、[Hero Scroll Video Pin Reveal](https://21st.dev/@ajith66310/components/hero-scroll-video-pin-reveal),公开预览与页面说明。
- **转译**:先让人认出对象,再让媒体窗口扩展,正文随后出现。适合产品演示、案例影片和局部特写进入全景。
- **输入与状态**:窗口尺寸跟随局部滚动;窗口里的视频可以独立按时间播放,也可以另有随动时间轴,两者分别定义。
- **制作分工**:窗口、圆角、文字位移与遮罩由程序处理;已有图像或视频通常足够。镜头真正穿越物体时才进入语义素材生成。
- **验收重点**:扩展前后主体裁切可接受;文字让出焦点;结束后自然接回正文;反向操作恢复原窗口。减少动态效果时直接给最终窗口与正文。
### 04 多图换位,汇聚成一个焦点
- **参考**:[21st / Scroll Choreography](https://21st.dev/@componentry/components/scroll-choreography),交互实测:四图随滚动改变位置,最后一图覆盖视口,回滚恢复多图布局。
- **转译**:用多个输入汇聚为一个结果,或从候选案例中突出一个主案例。图像的身份连续比路径炫技更重要。
- **输入与状态**:局部 `scroll` 控制“展开—换位—汇聚—突出”;版式有二维坐标,不意味着需要二维视频采样。
- **制作分工**:使用独立图片与 DOM 变换,保留稳定对象标识;最终焦点可接入一段生成的语义动作。
- **验收重点**:突出的是哪张图始终明确;回滚回到各自原位;源图足够清晰;小屏减少同时出现的图数。不要把所有图与文字烘焙进一段视频。
### 05 散点成序:散开、围合、展开为可读路径
- **参考**:[21st / Scroll Morph Hero](https://21st.dev/@prashantsom75/components/scroll-morph-hero),页面说明:散乱布局变成圆形,再形成滚动驱动的弧形排列。
- **转译**:表现收集、归纳与组织,把原本零散的信息排成有意义的顺序。圆形只是中间构图,不是目的。
- **输入与状态**:可用进入时的一次聚合,加滚动控制的排列变化;先交代自动段何时交还控制权,避免一开始滚动却等动画播完。
- **制作分工**:坐标、角度、缩放、透明度由程序生成;保持每个对象的身份与最终读序。无需为规则排列调用视频模型。
- **验收重点**:聚合后的组织关系比起点更清楚;对象不突然替换;自动引入可跳过;小屏直接呈现有序列表。
### 06 透视陈列归正为可阅读界面
- **参考**:[21st / Container Scroll Animation](https://21st.dev/@manuarora700/components/container-scroll-animation),页面说明与使用代码:滚动改变容器的三维朝向,内容可是一张界面截图。
- **转译**:开场展示产品的形象,继续浏览时把界面转正,交给用户阅读。适合桌面软件、控制台或设计工具介绍。
- **输入与状态**:局部滚动控制有限角度的透视与比例;这不是产品全周自转,也不是头部注视。
- **制作分工**:CSS 透视和 DOM 变换;界面截图或真实 UI 保持准确。只有设备开合、连接或接触关系真的变化时才增加语义素材。
- **验收重点**:最终正视状态足够长且足够清晰;文字不能永远倾斜;触屏直接展示正视界面,保证后续操作区域的命中正确。
### 07 贴纸舞台与可探索的边缘区域
- **参考**:[MotionSites / Orbit Stickers](https://motionsites.ai/?prompt=orbit-stickers),预览观察:太空主题贴纸从页脚边缘进入、层叠并改变位置,链接区保持留白。
- **转译**:把品牌资产做成可挑选、可拖动的小物件,用于页脚、空状态或轻量入门。借鉴层次与探索感,不默认继承太空主题。
- **输入与状态**:整片贴纸拖动适合 `drag` 的二维坐标;点击让某个角色发生短语义动作时,角色内部可单独用 `segment-play`。
- **制作分工**:透明静态贴纸配程序变换;只有角色肢体或真实材质发生变化时才生成对应动作。需要碰撞时另外实现物理模拟。
- **验收重点**:装饰不遮挡链接和焦点;拖动能取消、复位;触屏不会把正常页面滚动误当拖拽;静态贴纸组合仍成立。录像没有证明原站物理引擎的存在。
### 08 在探索位置给出预览或光照反馈
- **参考**:[21st / Hover Preview](https://21st.dev/@minhxthanh/components/hover-preview) 的页面说明为文字链接悬停预览;[Spotlight Card](https://21st.dev/@jahed/components/spotlight-card) 提供指针相关视觉反馈的公开演示。
- **转译**:列表保持紧凑,用户关注某项时才显示局部图像;高光用于指出可操作区域或当前观察位置。
- **输入与状态**:指针位置是二维数据,选中的条目是离散状态。不要把二者强行塞进同一个视频进度。
- **制作分工**:预览图、遮罩、高光和避让由程序控制;可搭配已生成的短素材,但不能让浮层接管链接本身的输入。
- **验收重点**:靠近屏幕边缘时不越界;键盘聚焦与触屏点击也能看到同等信息;纯装饰高光关闭后功能完整。
### 09 关系星图:用选择揭示关联
- **参考**:[21st / Radial Orbital Timeline](https://21st.dev/@jatin-yadav05/components/radial-orbital-timeline),交互实测:选中节点显示状态、说明和关联节点入口,点击关联项能切换详情。
- **转译**:将系统能力、流程阶段或生态连接显性化。轨道布置承担空间组织,选择状态承担信息揭示。
- **输入与状态**:选择节点属于 `state + discrete`;即使节点沿圆周排布,也不能据此设置素材 `parameter_space: circular`。
- **制作分工**:数据节点、连线、标签和焦点由程序维护;中心的品牌物体可独立使用生成素材。真实流程状态来自业务数据。
- **验收重点**:选择后对象易追踪,详情不会随自动公转逃走;关系可被文字或列表表达;小屏有顺序明确的节点列表。不要照搬演示中的随机能量数值。
### 10 压缩邻项,展开当前选择
- **参考**:[21st / Squeeze Carousel](https://21st.dev/@yura/components/carousel-squeeze),页面说明与使用代码:一项宽幅展示,其他项收为细条;演示配置关闭自动轮播。
- **转译**:在有限空间里保留“还有哪些选项”的空间线索,同时集中展示当前产品或案例。
- **输入与状态**:点击、触屏或键盘选择离散项;布局动画跟随所选项,不让自动轮播擅自改变正在阅读的内容。
- **制作分工**:DOM 布局与裁切;只有当前项需要动态展示时才加载素材。主体定位按每张图片单独设定。
- **验收重点**:压缩后仍可识别和选择;焦点不因宽度变化丢失;小屏用可读标签或列表替代极细点击条;减少动态效果时直接换布局。
### 11 语音状态体:把真实输入转成反馈
- **参考**:[21st / Voice Powered Orb](https://21st.dev/@isaiahbjork/components/voice-powered-orb),作者说明与使用代码:WebGL 球体按音频强度改变视觉表现;真实麦克风链路需另行验证。
- **转译**:为语音助手区分空闲、聆听、处理中、输出和错误。音量只能表达输入活动,不能冒充任务完成进度。
- **输入与状态**:业务状态决定模式,音频包络影响有限的强度参数。拒绝授权、静音和断流都必须有明确状态。
- **制作分工**:信号处理、颜色、强度或 shader 由程序执行;生成素材仅用于有意义的形体状态,不尝试预烘焙任意频谱。
- **验收重点**:无声音时不假装收到输入;用户启动后才请求麦克风;停止后结束采集;文本状态在无动画时依然可读。参考组件存在不等于已支持整条语音链路。
### 12 把内容集合变成空间,再回到具体任务
- **参考**:[Cosmos 官网](https://www.cosmos.so/),当前页面观察:图片围绕首屏文案分布,后续章节介绍集合、颜色搜索、相似图与来源信息;[Godly 历史收录](https://godly.website/website/cosmos-978) 仅作出处线索。
- **转译**:用内容对象本身建立空间感,然后让它们服务于搜索、归类或溯源。适合素材库、知识库和研究工具。
- **输入与状态**:首屏可有轻量自动运动;关键交互使用真实搜索或明确标为演示的输入。滚动负责章节揭示,不能伪造真实搜索结果。
- **制作分工**:图片卡与 UI 用程序;可把一张选中的图接入语义动画,但不需要把整个内容库做成视频。
- **验收重点**:标题、搜索与 CTA 保持稳定;背景卡片不抢焦点;产品能力在静态页面中也说得清。历史收录和现行官网不是同一版本证据。
### 13 使用痕迹:累计行为变成可见材质
- **参考**:[Recent / Aging Button](https://recent.design/i/a06z03e-aging-button-microinteraction),策展说明与预览:按钮随着点击次数增加出现磨损和脏污。
- **转译**:把次数、使用历程或里程碑变成对象状态,例如徽章抛光、工具磨损或植物成长;只用于变化具有产品意义的地方。
- **输入与状态**:输入是累计数据,状态映射必须可复现;不是“等待越久随机变脏”。跨次访问是否保留由业务需求决定。
- **制作分工**:简单纹理混合用程序;复杂生长或老化可生成少量明确关键状态与相邻转场。数值、历史与重置由程序管理。
- **验收重点**:磨损不影响按钮文字和可用性,不使人误以为损坏或禁用;清楚区分“保存成功”与“累计变化”。普通高频操作不必每次演出。
### 14 共享几何形态,让状态切换有来有去
- **参考**:[Recent / 3-in-1 Icon Morph](https://recent.design/i/t36wysw-3-in-1-icon-morph),预览观察:多个状态图形的线、点和轮廓重组成一个符号;策展账号标签不视为原作者证明。
- **转译**:为展开/收起、组合/拆开或模式切换保留共同几何锚点,让用户看出新状态从何而来。
- **输入与状态**:业务事件选择目标状态;快速反向应从当前几何状态继续,不先跳回起点重播。
- **制作分工**:SVG 或 DOM 精确控制线段、点和遮罩;功能图标与文字不交给视频模型绘制。语义完全不同的状态可以直接替换,不强求变形。
- **验收重点**:最终符号没有丢失必要状态信息;读屏名称同步更新;缩小后仍清晰;减少动态效果时直接切换到最终符号。
## 把模式编成可验收的方向
方向卡的格式以 [concepts.md](concepts.md) 的“方向卡”为准,最多提出三个方向。借用本库的模式时,在卡上补一项“参考与证据”:案例链接、实际看到的现象,以及哪些只是建议或推测。
把节奏写进 Brief 现有的 `storyboard` 与 `rest_state`;运行时规则仍以 [runtime.md](runtime.md) 为准。不要从参考卡增加一套重复的合同、时间轴或预算字段。
## 参考采纳门槛
- 先认出对象,再发生变化;一次转场只突出一个主要结果。文案需要阅读时,为主动作安排可读状态,不机械套用某个网站的固定秒数。
- 至少比较静态初始态、变化中、静态结束态。连续输入还要检查停手与反向;只看开场录像不足以证明交互成立。
- 参考提炼为“输入—视觉回应—信息作用”,再替换题材;不把霓虹、玻璃、粒子或巨大文字当成创意本身。
- 原站源码、访问权限或性能数据不可见时,不推断其生成模型、框架、内存占用或移动端质量。安装组件前另查当前依赖与具体许可。
- 不照搬参考提示词中的整页滚动映射、固定帧数、固定 DPR 或强制滚动锁定;这些选择回到用户的内容、宿主容器与现有预算流程。
- 素材首次就绪前保留可读页面;加载交接保持同一视觉状态;装饰失败不能阻断导航。
素材质量与连续性验收仍使用 [qa.md](qa.md)。本参考库的作用是帮助选对方向,不替代 Pilot 或目标设备验证。
+70
View File
@@ -0,0 +1,70 @@
# 帧策略与图集压缩
本文件是 `frame_policy` 和图集清晰度预算的唯一事实源。先验收动作母版,再决定是否插帧;插帧不是默认正确答案。
## 选择帧策略
使用 `native`:
- 源帧率已经满足最终正常播放;
- 原始节奏、停顿或逐帧绘制感属于视觉设计;
- 插帧会产生重影、双轮廓、线稿扭曲或结构错误。
使用 `interpolate`:
- scrub 的参数采样明显不足;
- 目标播放速度下原始帧率可见跳步;
- 插帧结果通过自动比较和人工接触表验收。
把决定写入 Motion Brief:
```yaml
frame_policy: native | interpolate
target_fps: <native 使用源帧率;interpolate 必须高于源帧率>
```
## 插帧流程
只有 `frame_policy=interpolate` 时执行:
```bash
python3 "$OIL_MOTION/scripts/optimize_motion.py" interpolate \
"$SOURCE_VIDEO" "$OUTPUT_DIRECTORY" \
--fps "$TARGET_FPS" \
--key "$KEY_MODE"
```
同时检查原始与插帧接触表。新增重影、双轮廓、边缘撕裂、部件穿插、结构扭曲、亮度闪帧或中心突变时,插帧失败;改用合格的原始帧,或重新生成母版,不得把插帧伪影带入编译。
`frame_policy=native` 仍需输出原始帧接触表和分析报告,只是不生成虚构中间帧。视频路线由 `compile_scroll_video.py --frame-policy` 统一执行对应分支;图集路线的原始帧提取见 [alpha-atlas.md](alpha-atlas.md)。
## 裁剪与拼接
- 裁剪只删除确实无变化的重复区,不改变已验收动作的终点。
- 每次裁剪或拼接后,重新检查所有新产生的相邻帧。
- 不能删除一段缓慢变化,再把远处最终帧直接接回;需要保留到终点的连续采样。
- 时间轴锚点和 `hold` 必须从最终保留帧重新生成。
## 图集压缩
只有预算选择 `alpha-atlas` 时执行:
```bash
python3 "$OIL_MOTION/scripts/optimize_motion.py" atlas "$FINAL_FRAMES" \
--output "$OUTPUT_ATLAS" \
--target-mb "$TARGET_MIB" \
--display "$DISPLAY_SIZE" \
--dpr "$TARGET_DPR" \
--cell-width "$CELL_WIDTH" \
--cell-height "$CELL_HEIGHT" \
--columns "$COLUMNS"
```
工具先按“最大 CSS 尺寸 × DPR”计算最低单帧像素,再在不低于该尺寸的前提下搜索压缩质量。`clarityMet` 必须为 `true`;`targetMet=false` 时回到 [delivery-selection.md](delivery-selection.md) 重新预算,不继续降低清晰度。
## 验收
- `native`:接触表、相邻帧分析和最终播放均通过。
- `interpolate`:原始与插帧接触表均通过,且插帧没有新增结构或边缘缺陷。
- 最大显示尺寸和目标 DPR 未确认前,不执行最终压缩。
- 文件体积、解码内存和纹理尺寸同时满足目标设备预算。
+482
View File
@@ -0,0 +1,482 @@
# 关键帧、视频提示词与任务提交
本文档是关键帧与视频提示词写法,以及 `image_job.py`、`video_job.py` 提交命令的唯一事实源。
路线选择见 [delivery-selection.md](delivery-selection.md),Pilot 与帧链硬门命令见
[qa.md](qa.md)。
## 目录
- [生成关键帧](#生成关键帧)
- [画幅与尺寸](#画幅与尺寸)
- [写提示词前先决定](#写提示词前先决定)
- [提交视频任务(video_job.py)](#提交视频任务video_jobpy)
- 提示词段落:[身份锁定](#通用身份锁定段)、[固定镜头](#固定镜头段)、[场景背景](#场景背景段baked-路线)、[视频色键](#视频色键段page-路线)
- 按动作类型:[转动与视向](#转动与视向提示词)、[一镜到底](#一镜到底连续镜头提示词)、[产品拆解](#产品拆解与爆炸图)、[镜头穿越](#镜头穿越)、[多段串联](#多段关键帧串联)、[指针二维](#指针二维动画)、[逐帧 scrub](#逐帧-scrub-时间轴)、[分段播放](#分段播放转场)、[离散状态](#离散状态动画)
- [失败修复提示词](#失败修复提示词)、[负面约束](#负面约束)、[分辨率和时长](#分辨率和时长)
## 生成关键帧
生产主流程(先生图、再生视频、逐段串联)见 SKILL.md 主流程。视频提示词只描述两张已验收
关键帧之间如何连续变化,不再承担终点设计;主体身份、产品结构、Logo、构图和风格必须先在
关键帧图片中解决。
关键帧通过凭据入口运行 `image_job.py`:
```bash
node "$OIL_MOTION/scripts/credential-ui/src/profile.ts" run default -- python3 "$OIL_MOTION/scripts/image_job.py" \
--prompt-file source/K0.txt \
--image source/product-reference.png \
--background transparent \
--size 2048x1152 \
--output source/K0-alpha.png
```
- `--background` 必填。`background_owner=page` 传 `transparent`,直接生成真实透明背景 PNG;
脚本检查 Alpha 通道、四角透明和可见主体,不合格的结果另存为 `*.rejected.png` 并以非零状态退出。
`background_owner=video` 传 `opaque`,提示词写明完整场景、光线和地面接触。
- `--image` 可重复。真实产品图、身份参考或上一张已验收关键帧都作为输入;提示词按顺序
写明“图 1 是……”以及哪些部分必须保持不变。没有参考图时才走文生图。
- 不确定参数时先加 `--dry-run`:只校验并打印请求摘要,不计费,也不需要 Key。
- 输出已存在时默认停止;确认要替换后才加 `--force`。
`background_owner=page` 时不要让生图模型画绿色、品红、灰色、白色或棋盘格背景。提交视频前,
再从透明源确定性合成视频模型需要的均匀色键副本:
```bash
python3 "$OIL_MOTION/scripts/composite_alpha_keyframe.py" \
source/K0-alpha.png source/K0-video.png \
--key-color '#00FF00'
```
透明源与视频输入副本必须分开保存。主体含大量绿色时,合成副本改用 `#FF00FF`。
需要同一主体从轨道一端精确移动到另一端时,可以先准备透明主体层,用程序生成身份和尺寸
完全一致的首尾帧,再交给视频模型补全中间形变:
```bash
python3 "$OIL_MOTION/scripts/compose_travel_frames.py" subject.png \
--first-output first-green.png \
--last-output last-green.png \
--size 864x1536 \
--subject-height 0.36 \
--subject-anchor-x 0.535
```
该工具只负责扁平轨道、缩放和精确位移。中间的结构形变、接触关系和前后遮挡仍由首尾帧
约束下的视频模型完成。
## 画幅与尺寸
Concept Contract 锁定 `aspect_ratio` 后,关键帧、视频和编译输出沿用同一比例:
| `aspect_ratio` | 关键帧 `--size` | 视频画幅 | 常见容器 |
| --- | --- | --- | --- |
| `16:9` | `2048x1152` 或 `1536x864` | 从首帧推断为 `16:9` | 横向全屏、Hero、宽幅转场 |
| `9:16` | `1152x2048` 或 `864x1536` | `9:16` | 竖屏全屏、移动端故事 |
| `1:1` | `1024x1024` 或 `2048x2048` | `1:1` | 卡片、头像、方形视窗 |
| `21:9` | `2016x864` | `21:9` | 宽银幕叙事 |
默认图片模型(gpt-image-2 系列)要求宽高都是 16 的倍数、最长边不超过 3840、长短边之比
不超过 3:1、总像素在 655,360 到 8,294,400 之间,脚本会在联网前校验。换用其他模型时以
该模型支持的尺寸为准,并核对脚本报告的实际宽高比。
容器是 16:10、4:3 或其他比例时,选最接近的生成比例,在合同中写明裁切或补边策略,再按
最终视口验收。编译输出宽度由最大 CSS 尺寸乘目标 DPR 决定,见各媒体路线的编译命令。
## 写提示词前先决定
提示词从 Concept Contract 和 Identity Bible 出发,不得加入用户未确认的主体、人数、
风格、情绪或叙事形式;合同中的限制必须原样成为提示词约束。
先写清楚:
1. `time_control` 是逐帧 scrub、分段播放还是自主播放。
2. 时间轴或状态转场的起点、终点和方向。
3. 主体哪些部分允许变化,哪些必须固定(角色照抄 Identity Bible 的身份锚点)。
4. 是否闭环。
5. 背景归属:`background_owner=video` 时写明场景、环境光、地面接触和景深如何保持
连续;`background_owner=page` 时写明关键帧生图使用真实 Alpha、视频输入副本使用
绿色还是洋红色键,以及如何保证视频四角与时间维度均匀。
6. 最终会按时间、角度、二维位置还是状态取帧。
图片模型负责关键帧,`page` 路线直接输出透明通道;视频模型负责动作语义和画面连续性,不负责精确
切帧、Alpha 视频、帧编号、压缩或图集。不要让视频提示词承担透明通道或图集输出。
## 提交视频任务(video_job.py)
`video_job.py` 用于提交、轮询和下载 ZenMux / MiniMax 原生视频任务,把重复的接口
调用、图片编码、状态轮询和结果保存程序化。提交前按 SKILL.md 的“首次配置”检查一次
凭据,命令始终经 `profile.ts run default --` 运行。
模式与参数约束:
- `reference_image` 与 `first_frame` / `last_frame` / `loop_frame` 互斥。混用会触发
MiniMax 接口错误 `2013`,脚本会在联网前阻止提交。
- 首尾帧转场需要锁定身份时,先把身份和风格生成进验收后的首尾关键帧,不能再附加
`reference_image`。
- 闭环动作把同一张已验收构图同时传为首帧和尾帧(`--loop-frame`)。这能加强接缝
约束,但仍需检查首尾差异和运动方向。
- 默认不传 `--model`(固定 `minimax/minimax-h3-max`)和 `--ratio`(按首帧推断画幅)。
- 默认传 5 秒 `duration`。使用 `--frames` 时不传 `duration`,二者不能同时出现;
只有当前接口明确支持帧数控制时才使用 `--frames`。
- 模型支持时用 `--seed` 复现,并保存任务元数据和尾帧;seed 不能替代参考图和首尾帧。
- `generate_audio=false` 不能保证成片没有音轨;编译脚本会统一移除音轨。
- 模型实际输出的时长和帧数可能略多于请求,尾部还可能停顿。先用
`motion_pipeline.py probe` 查看实际值,再按目标尾帧清理,不要把请求值当成成片值。
- 模型或接口拒绝参数时停止并报告具体响应;只有用户同意降级后,才能移除约束或更换
模型,不要静默删掉首尾帧。
- 一条视频只承担一条连续时间轴或一个状态转场,时长和分辨率见[分辨率和时长](#分辨率和时长)。
- `--stage` 必填:第一段为 `pilot`,后续生产段为 `production` 并传
`--pilot-approval`;连续叙事的生产段同时传 `--continuity-mode chain`、
`--previous-tail` 和 `--frame-chain-manifest`。Pilot 批准与帧链校验的规则、
阻断条件和命令见 [qa.md](qa.md)。
第一段 Pilot(单向转场 `K0 → K1`):
```bash
node "$OIL_MOTION/scripts/credential-ui/src/profile.ts" run default -- python3 "$OIL_MOTION/scripts/video_job.py" \
--stage pilot \
--segment-index 1 \
--prompt-file source/segment-01.txt \
--first-frame source/K0.png \
--last-frame source/K1.png \
--resolution 768P \
--duration 5 \
--seed 42 \
--output source/segment-01.mp4 \
--metadata source/segment-01.job.json
```
闭环动作把 `--last-frame source/K1.png` 换成 `--loop-frame`。`background_owner=page`
时,首尾帧传 `composite_alpha_keyframe.py` 合成的色键副本,不传透明源。脚本把实际尾帧
保存为 `<输出名>-last-frame.jpg`,这里是 `source/segment-01-last-frame.jpg`。
第 2 段及之后的连续生产:
```bash
node "$OIL_MOTION/scripts/credential-ui/src/profile.ts" run default -- python3 "$OIL_MOTION/scripts/video_job.py" \
--stage production \
--segment-index 2 \
--pilot-approval pilot/approval.json \
--continuity-mode chain \
--previous-tail source/segment-01-last-frame.jpg \
--first-frame source/segment-01-last-frame.jpg \
--last-frame source/K2.png \
--frame-chain-manifest qa/frame-chain.json \
--prompt-file source/segment-02.txt \
--output source/segment-02.mp4
```
`--first-frame` 与 `--previous-tail` 传同一个文件:续段从上一段真实结束的画面接着走,
尾帧仍是计划关键帧。帧链的校验规则见 [qa.md](qa.md)。
## 通用身份锁定段
有角色时,先把 Identity Bible 的身份锚点(脸型五官、发型发色、服装配色、标志物、
体型比例、风格线条)写进这段,再放在动作描述前,并替换尖括号:
```text
Use the supplied first and last frames as the exact identity and design
references for <SUBJECT>. Preserve the same silhouette, anatomy, face, clothing or product
geometry, colors, line work, texture, and proportions in every frame. The
subject remains the same size and at the same anchored position throughout the
shot. Do not add, remove, duplicate, or redesign any body part, accessory,
feature, logo, control, or prop.
```
如果主体是插画,补充:
```text
Preserve the original illustration style exactly. Keep line thickness,
halftone texture, flat color regions, and edge sharpness consistent. Do not
turn the subject into volumetric CGI, photorealistic, painterly, or glossy imagery.
```
## 固定镜头段
```text
Locked camera and locked framing. No camera pan, tilt, zoom, orbit, shake,
reframing, perspective change, lens change, depth of field, or lighting change.
The body and contact point remain fixed. Only <ALLOWED_PARTS> may move.
```
只有镜头运动本身需要被滚动控制时才删除这段,并明确描述镜头轨迹。
## 场景背景段(baked 路线)
仅当 Concept Contract 锁定 `background_owner: video` 时使用。场景、环境光、地面
接触和景深就是要烧进视频的内容,必须明确锁定,保证多段之间连续:
```text
The scene is <SCENE_ANCHOR> with <LIGHTING> and <GROUND_CONTACT>. Keep the
environment, light direction, color temperature, ground contact, shadows, and
depth of field identical and continuous across the entire shot. The background
is part of the final picture: no chroma key, no flat color backdrop, no
background replacement, and no transparency.
```
多段叙事时,这一段在每条提示词中原样复用,并把上一段验收后的实际尾帧作为下一段
首帧输入。
## 视频色键段(page 路线)
仅当 Concept Contract 锁定 `background_owner: page` 时追加到视频提示词,图集和色键视频两条路线都用它。
首尾关键帧先由 `image_job.py --background transparent` 生成透明 PNG,再由
`composite_alpha_keyframe.py` 合成为视频输入;不要把这段用于图片提示词。默认 `#00FF00`,主体含绿色时改用 `#FF00FF`。
```text
The entire background is one perfectly uniform flat chroma-key <KEY_COLOR>
rectangle in every frame. No gradient, texture, noise, floor plane, horizon,
shadow, reflection, glow, particles, color variation, or lighting falloff on
the background. Keep the subject fully separated from all image borders with
generous padding. No cast shadow. No green/magenta object or reflected spill on
the subject. No text, subtitle, watermark, border, or UI.
```
模型未必严格生成指定色值,所以最重要的是四周和时间维度保持均匀。后续脚本会从边缘采样真实背景色。
## 转动与视向提示词
先按 [concepts.md](concepts.md) 的四种类型确认要转的是什么,再选下面的写法。
### 圆周注视
脸始终朝向镜头,视线沿屏幕前方的一圈顺时针移动,不能转出后脑勺:
```text
Create one continuous clockwise head and gaze rotation cycle. The face and eyes
of <SUBJECT> remain oriented toward the camera at all times; do not rotate around
to show the back of the head. An invisible target moves smoothly clockwise in a
circle on the front screen plane (12 o'clock looking up, 3 o'clock looking
right, 6 o'clock looking down, 9 o'clock looking left, returning cleanly to 12
o'clock). <SUBJECT> follows the target smoothly within a natural cone of vision,
tilting and rolling its head without leaving the front-facing half-sphere. Pass
through every intermediate angle at a constant rate without pausing or snapping.
End exactly at the first frame pose for a seamless loop. Keep torso and position
completely stationary. No blinking, idle sway, or deformation.
```
运行时用 `atan2(y, x)` 把指针方向映射到角度。
### 二维注视
见下文[指针二维动画](#指针二维动画)的二维采样。
### 水平摆头
只绕竖直轴转,不闭环:
```text
Move once continuously from looking left (-60 degrees) through center to
looking right (+60 degrees). Do not loop, do not return to start, and do not
pause at intermediate angles. Head turns only on the horizontal yaw axis; locked
vertical pitch, locked camera, locked scale, locked center anchor.
```
### 展台自转
真实产品的侧面和背面不能交给模型猜。先用产品参考图生成 0°、90°、180°、270° 四张关键帧,
再按 `K0 → K1 → K2 → K3 → K0` 分四段生成,每段转 90°:
```text
Use the supplied first and last frames as the exact geometry, material, color,
logo, control, and proportion references. Rotate the product clockwise around
its vertical center from the angle of the first frame to the angle of the last
frame at a constant angular speed. Locked orthographic-like camera, fixed scale,
fixed center, fixed lighting, no perspective breathing, no added details, no
deformation, no text changes, no logo changes.
```
只有背面不重要的小型物件,才用一张正面图配 `--loop-frame` 一次转完。
## 一镜到底连续镜头提示词
范式和交接关键帧的定法见 [concepts.md](concepts.md)。每段只负责一级变化,首尾帧就是交接关键帧。
所有范式共用一个骨架,只替换镜头句和范式句:
```text
Use the supplied first and last frames as exact composition anchors.
<CAMERA_CLAUSE> <PARADIGM_CLAUSE> No cuts, dissolves, jump pans, rotational
drift, or sudden speed changes. Arrive exactly at the framing, scale, and
alignment of the last frame. Every intermediate frame must read clearly when
playback stops.
```
镜头句:推进用 `The camera moves forward in one uninterrupted dolly at a steady speed toward <TARGET>.`;
机位不动用 `The camera stays completely locked.`
| 范式 | `<PARADIGM_CLAUSE>` |
|---|---|
| 尺度穿透 | `The center subject <TARGET> stays exactly at the center while the surroundings expand past the frame edges, passing through <INTERMEDIATE_LAYERS>.` |
| 遮挡转场 | `A large foreground <OCCLUDER> crosses the lens and fills the entire frame by the last frame. Exposure stays constant.` |
| 形状匹配 | `The <SHAPE> outline keeps exactly the same screen position and size while its surface transforms from <SUBJECT_A> into <SUBJECT_B>.` |
| 时间流转 | `Only materials and lighting change, continuously from <STATE_A> to <STATE_B>; silhouette, geometry, and perspective never change.` |
| 倒影穿越 | `The camera pushes into the reflection on <REFLECTIVE_SURFACE>; the reflected scene grows sharper until it fills the frame as the real scene of the last frame.` |
| 剖切穿墙 | `As the camera reaches the wall of <STRUCTURE>, the surface dissolves into a clean cutaway that reveals <INTERIOR>, without slowing down.` |
## 产品拆解与爆炸图
先根据真实产品参考图分别生成完整态和爆炸态图片。两张图都通过人工验收后,再作为精确首尾帧;
不要让视频模型凭文字发明最终结构。
```text
Use the supplied first and last frames as exact geometry, identity, material,
logo, component-count, alignment, camera, lighting, and composition references.
Create one continuous transformation from the fully assembled <PRODUCT> to the
approved exploded view. Separate the existing shell, display, battery, boards,
connectors, cameras, and fasteners only along their physically plausible axes.
Preserve every component's exact shape, scale, orientation, color, and relative
order. Keep all parts readable and non-overlapping at the final state. No new,
missing, duplicated, melted, or redesigned components. No cuts, camera changes,
scale breathing, motion blur, labels, or unrelated motion. Every intermediate
frame must be a stable reversible assembly state suitable for scroll scrubbing.
```
爆炸方向、间距、部件数量和最终构图必须先在尾帧图片中确定。视频负责从完整态连续过渡到
该尾帧;文字标注、数字和部件高亮在生成后由程序覆盖,避免 AI 视频生成不稳定文字。
## 镜头穿越
镜头运动本身是交互内容时,不使用固定镜头段,改为明确一条可逆轨迹:
```text
Create one continuous forward camera move from <START_VIEW> to <END_VIEW>.
Follow the supplied path through <ORDERED_LANDMARKS> without cuts, orbiting,
sideways drift, speed jumps, focus pumping, or lens changes. Keep product
geometry, lighting, scale relationships, and landmark positions consistent.
Every frame must remain sharp and readable when scroll playback stops. The
reverse frame order must also form a natural backward move.
```
长距离穿越不要只给起点和终点。先生成路径上的中间关键帧,保证主体、空间地标、比例和风格
一致,再把相邻关键帧分别生成短视频。
## 多段关键帧串联
先建立 `K0 → K1 → K2…Kn`:
- 第 `i` 段以 `Ki` 为首帧、`Ki+1` 为尾帧;`chain` 模式下第 2 段起的首帧换成上一段的实际尾帧。
- 所有关键帧复用同一组参考图、画幅、风格约束、主体比例和场景设定。
- 每段只写一个主要变化。
- 拼接后逐帧检查接缝;若接缝不稳,重做对应短片,不重做整条时间轴。
实际尾帧接力、SHA-256 校验和误差累积处理按 [qa.md](qa.md) 的“连续帧链”执行。
## 指针二维动画
二维输入不能只靠一条左右转头视频准确表达。优先选择以下方案:
### 方案 A:角度足够
指针远近不影响姿态时,用[圆周注视](#圆周注视)生成完整方向环。距离只影响平滑速度或回正强度。
### 方案 B:二维采样
生成固定网格中的多个短片或关键姿态,例如:
```text
Generate the same subject and framing for target position <X_POSITION>,
<Y_POSITION>. Keep the exact body anchor, subject scale, lighting, style, and
background used in every other grid sample. Move only <ALLOWED_PARTS> toward
that target and settle naturally. No entrance or exit motion.
```
二维网格至少覆盖左上、上、右上、左、中、右、左下、下、右下。用程序统一锚点和尺寸,再做双线性邻域选择或插值。不要要求模型在一条视频中遍历网格后直接随机访问。
## 逐帧 scrub 时间轴
适合产品拆解、页面叙事、图表展开和场景变换:
```text
Create a single continuous transformation designed for frame-by-frame scroll
scrubbing. At frame 0, <START_STATE>. Over the shot, <ORDERED_CHANGES>. At the
last frame, <END_STATE>. Every intermediate frame must be a meaningful stable
progress state. Use constant visual continuity with no cuts, dissolves, sudden
jumps, duplicated holds, camera shake, motion blur, or unrelated motion. Keep
the composition readable when playback is stopped on any frame.
```
把多个变化写成相对进度阶段,例如 `0–35%` 完成第一阶段、`35–80%` 推进主要关系、
`80–100%` 到达最终状态。要求每个阶段持续变化,并明确禁止模型在前段快速完成主要
动作、后段只保留近重复帧。百分比用于约束节奏,不要求模型输出精确帧编号;实际节奏
仍需通过接触表检查,必要时裁剪或重定时。
scrub 序列的目标帧率由帧密度和画质验收决定。优先生成清晰的语义关键阶段,再按
[optimization.md](optimization.md) 选择保留原帧或插帧。
## 分段播放转场
适合输入触发后按时间完成、并在状态锚点停住的片段:
```text
Create one uninterrupted transition from the exact provided first frame to the
exact provided last frame. Begin the intended motion immediately, preserve all
identity, structure, framing, background, and lighting constraints throughout,
and reach the final state only at the end. No cut, dissolve, unrelated idle
motion, early completion, long final hold, or return motion.
```
每段只描述一个方向的主要变化。运行时反向通常复用同一段;只有倒放违反物理或叙事规律时,才另外生成反向片段。
## 离散状态动画
每个状态单独生成,不让一个长视频同时包含 hover、点击、成功和失败:
```text
Create a short transition from the exact neutral pose to the exact <STATE>
pose. The first frame must match the shared neutral reference exactly. Hold the
final pose only briefly. No camera movement, no unrelated idle motion, and no
return transition.
```
反向状态优先用程序倒放;只有倒放不符合物理规律时再单独生成。
## 失败修复提示词
一次只修一个问题,同时重申所有不变量:
```text
Keep the subject identity, design, style, camera, framing, scale, anchor,
background, lighting, and correct motion unchanged. Fix only this issue:
<ONE_PRECISE_ISSUE>. Do not add any new motion or detail.
```
常见修复:
- `Keep every approved component unchanged; remove the duplicated connector.`
- `Keep the body fixed; eliminate scale pulsing and center drift.`
- `Remove the one-frame brightness flash; lighting is identical in every frame.`
- `Continue through the angle without pausing or snapping.`
- `Make the last frame match the first frame exactly for a seamless loop.`
## 负面约束
按需要加入,不必机械复制全部:
```text
No cuts, morphing, identity drift, scale breathing, position drift, duplicated
limbs, missing limbs, extra objects, blinking, idle sway, motion blur, ghosting,
frame blending, lighting flicker, shadows on the background, camera movement,
text, watermark, border, style change, unnecessary sci-fi circuitry, or plastic AI clutter.
```
用户没有要求科幻题材时,不写 `cyberpunk`、`neon glow`、`intricate circuitry`、
`hyperdetailed 8k` 这类套路词,也不要用满画面的细碎发光线条充当细节。画面冲击力来自镜头、
形态对比和干净的轮廓;细节只服务于叙事焦点,非焦点区域保持干净。需要时追加:
```text
No unnecessary sci-fi circuitry, generic cyberpunk neon clutter, plastic AI
noise, over-detailed artificial lines, or visual noise.
```
## 分辨率和时长
- 单段 3–6 秒,只完成一个主要变化;更长的动作拆成多段,否则容易漂移。
- 默认模型 `minimax/minimax-h3-max` 仅支持 `480P`、`768P`,不支持 `1080P` 或 `2K`,
见 [ZenMux 模型信息](https://zenmux.ai/minimax/minimax-h3-max)。Pilot 与最终母版均用
`768P`;`480P` 可用于动作草案,不能当作更高清的母版。脚本接受大小写并在提交前校验。
- 母版像素至少覆盖最大 CSS 尺寸乘目标 DPR。模型最高分辨率仍不够时,先调整显示目标或
说明取舍,不从低清母版放大。只有 `768P` 母版时,按实际宽高下调预算中的显示尺寸或
目标 DPR;例如 `1344×768` 可覆盖 `1280×720` CSS px、目标 DPR `1.05`,
具体参数与复核方法见 [显示预算取舍](delivery-selection.md#母版像素不足时的显示预算)。
- 是否插帧由 Motion Brief 的 `frame_policy` 决定,提示词不要求模型自行提高帧率。
+160
View File
@@ -0,0 +1,160 @@
# 质量检查与生产硬门
本文档是 Pilot、连续帧链和最终验收的唯一事实源。检查顺序固定为:用户意图 → 关键帧 → 母版 → 帧准备 → 媒体编译 → 时间轴 → 真实页面运行时。上游失败时停止,不在下游掩盖。
## Concept Contract 回归
每次验收先逐项对照合同:
- 主体数量、身份和关系一致。
- 风格、情绪、动作和叙事形式保持用户原意。
- `background_owner=video` 的成品没有抠色;`page` 的成品没有烧入页面背景。
- `driver`、`time_control` 和 `navigation` 分别符合要求。
- `clip_continuity` 与 Pilot 批准一致。
任一项偏离都属于需求级错误,必须返工;不接受“差不多”。
## Identity Bible
有角色或稳定身份对象时,逐张关键帧和逐段母版检查:
- 同脸或同一识别特征;
- 发型、服装、材质和配色一致;
- 配饰、标记、零件和道具不增不减不错位;
- 比例、锚点和主要轮廓没有无意漂移。
## 透明关键帧
`background_owner=page` 时,原始关键帧必须是直接生成的真实 Alpha PNG:四角透明,没有实体底色或棋盘格,主体边缘在浅色和深色测试底上均干净。`image_job.py` 会自动检查 Alpha 通道、四角和可见主体;边缘质量仍要放在测试底上看。
视频模型需要色键时,只能从已验收透明源确定性合成副本,并保留源文件对应关系。不得生成色底图片再反向抠图。
## Pilot 硬门
批量生成前必须具备:第一组关键帧、第一段短视频、真实页面最终位置挂载、明确的视觉验收结论。通过后生成 `pilot/approval.json`:
```bash
python3 "$OIL_MOTION/scripts/production_gate.py" approve-pilot \
--contract source/concept-contract.yaml \
--identity-bible source/identity-bible.md \
--first-frame "$FIRST_FRAME" \
--last-frame "$LAST_FRAME" \
--video "$PILOT_VIDEO" \
--page-evidence "$PAGE_EVIDENCE" \
--reviewer "$REVIEWER" \
--decision pass \
--output pilot/approval.json
```
批准文件记录工件 SHA-256 和合同中的连续模式。生产阶段必须验证批准文件与工件未变化;任何变更都会使批准失效。
## 连续帧链
`clip_continuity=chain` 必须通过两道不同硬门。
### 1. 生成输入接力
上一段验收后的实际尾帧必须作为下一段首帧的原文件:
```bash
python3 "$OIL_MOTION/scripts/production_gate.py" verify-chain \
--previous-tail "$PREVIOUS_TAIL" \
--next-first "$NEXT_FIRST_INPUT" \
--segment-index "$SEGMENT_INDEX" \
--manifest qa/frame-chain.json
```
这一步验证生成请求没有换图,但不能证明模型输出首帧没有重绘。
### 2. 成片输出接缝
下一段生成完成后,再比较上一段成片解码尾帧与下一段成片解码首帧:
```bash
python3 "$OIL_MOTION/scripts/production_gate.py" verify-output-chain \
--previous-video "$PREVIOUS_VIDEO" \
--next-video "$NEXT_VIDEO" \
--segment-index "$SEGMENT_INDEX" \
--manifest qa/frame-chain.json \
--evidence-dir qa/frame-chain-evidence
```
自动相似度通过后仍要查看证据帧,确认身份、构图、光线和背景没有可见跳变。再把实际尾帧与计划关键帧比较;偏差超限时重做当前段或更新后续约束,不允许误差逐段累积。
## 母版
- 完整观看,不只看首尾截图。
- 主体身份、结构、颜色和数量稳定。
- 动作没有硬切、无意反向、长时间待机或错误终点。
- 镜头、透视、光线和接触关系符合合同。
- 闭环素材首尾真实连续。
- `page` 路线的色键背景均匀;烘焙路线的背景与主体一起连续。
## 帧准备
`frame_policy=native`:
- 查看原始接触表和相邻帧分析。
- 在目标播放速度下确认节奏和清晰度。
`frame_policy=interpolate`:
- 同时查看原始与插帧接触表。
- 插帧不得新增重影、双轮廓、边缘撕裂、结构扭曲、穿插或闪帧。
- 失败时回到合格原始帧或重新生成,不把插帧当成强制交付条件。
任何裁剪和拼接都必须检查新产生的相邻帧;不能用远距离末帧替代被删除的缓慢变化。
## 媒体编译
- 输出像素至少覆盖最大 CSS 尺寸乘目标 DPR,不超过母版可用分辨率。
- 图集帧数、行列和实际文件一致。
- 视频帧率、帧数、全关键帧状态和 `compile.json` 一致。
- 色键路线按 [chroma-video.md](chroma-video.md) 验收编码后抠色和多底色矩阵。
- 烘焙路线按 [baked-video.md](baked-video.md) 验收完整画面,不得出现色键处理。
## 时间轴
`timeline.json` 必须由最终编译结果生成,并验证:
- [runtime.md](runtime.md) 定义的时间轴硬性语义全部通过。
- 页面状态 ID、顺序和 `timeline.json.states` 完全一致;缺失、重复或错序时初始化失败。
- 重新裁剪、拼接或编码后旧时间轴失效。
- 播放曲线参数来自清单,页面没有第二份常量。
## 运行时验收
所有模式都检查:
- 冷缓存、慢网、资源失败和 `prefers-reduced-motion`。
- 目标 CSS 尺寸、DPR、浏览器 100% 缩放和移动端。
- 窗口变化、页面切后台再恢复、快速连续输入。
- 媒体节点不重复创建,降级时不露出色键或半成品。
`frame-scrub`:
- 慢速、快速、跳转和连续反向都能到达正确帧。
- 输入停止时画面停在对应位置,不粘滞、不越界。
`segment-playback`:
- 输入发生后立即开始,不等待页面导航结束。
- 连续链使用同一媒体实例,不在状态间换源。
- 反向输入从当前画面撤回。
- 每段停在 `hold`,没有越过目标后回跳。
- 快速重复输入只执行最新目标,旧播放已取消。
- 同一次惯性手势不会连续跳过多个状态;程序化页面滚动不会反向触发媒体控制器。
- 首尾边界按 `gesture_policy.boundary` 停止或闭环,不产生空状态。
`autonomous-playback`:
- 浏览器阻止自动播放时有明确降级或启动手势。
- 只有通过闭环验收的素材才循环。
## 故障定位
- **闪帧或切帧**:依次检查母版、裁剪接缝、成片输出接缝、`hold/endExclusive`、旧媒体层和资源解码。
- **动作粘滞**:检查是否重复平滑、目标是否及时更新、seek 是否串行堆积。
- **停下后回跳**:检查是否用 `timeupdate` 判断、是否停在 `endExclusive`、是否先越界再回设。
- **新版本变糊**:检查母版分辨率、插帧伪影、重复缩放、图集单元格和有损压缩。
- **色键残留**:检查母版和编码后实际帧;不得先扩大运行时阈值。
+152
View File
@@ -0,0 +1,152 @@
# 运行时控制
本文档是时间控制、输入映射、预加载和运行时性能的唯一事实源。媒体格式由
[delivery-selection.md](delivery-selection.md) 决定;两者独立。
## 先读预算结果
`build/motion-budget.json` 必须分别给出:
- `delivery.selected`:使用哪种媒体和渲染器。
- `runtime.controller`:输入如何控制媒体时间。
| `time_control` | `runtime.controller` | 行为 |
|---|---|---|
| `scrub` | `frame-scrub` | 输入值持续映射到帧或时间 |
| `segment-play` | `segment-playback` | 输入选择相邻状态,片段按时间播放 |
| `autonomous` | `autonomous-playback` | 媒体时间自行推进 |
不要根据 `scroll`、分页布局或视频格式猜控制器。滚动既可以 scrub,也可以触发片段播放。
## 时间轴清单
所有控制器只读取编译生成的 `build/timeline.json`,页面中不得维护第二份时间常量。
```yaml
schemaVersion: 1
fps: <实际编码帧率>
frameDuration: <1 / fps>
initialState: <稳定状态 ID>
states:
- id: <页面与运行时共同使用的状态 ID>
hold: <该状态的停帧时间>
segments:
- id: <稳定标识>
from: <起点状态 ID>
to: <终点状态 ID>
start: <本段第一张可见帧的时间,包含>
hold: <本段结束后应停留的最后可见帧时间>
endExclusive: <本段编码边界,不包含>
curve:
type: constant | edge-mid-edge
rate: <constant 使用>
edgeRate: <edge-mid-edge 使用>
midRate: <edge-mid-edge 使用>
```
硬性语义:
- `start <= hold < endExclusive`。
- 停止播放时只能落在 `hold`,不能落在 `endExclusive`。
- `states` 顺序必须与片段的 `from → to` 一致;页面状态直接使用这些 ID,不另建索引映射表。
- 所有时间都来自最终编码后的实际帧,不从生成时长或原始素材手工推算。
- 裁剪、拼接或重新编码后必须重新生成清单。
## frame-scrub
适用于“输入停在哪里,画面就停在哪里”的交互。使用
[assets/interactive-motion.ts](../assets/interactive-motion.ts) 的
`createFrameAnimator` 管理目标帧、阻尼和反向。
一维映射:
```text
progress = clamp((value - start) / (end - start), 0, 1)
targetFrame = progress * (frameCount - 1)
```
环形输入使用最短环形距离;二维输入使用二维采样网格,不能压成一维进度。输入事件只更新目标值,实际渲染集中在 `requestAnimationFrame`。
视频 scrub 每次只提交最新整数目标帧,丢弃过时 seek。需要随机访问或快速反向时使用全关键帧视频,并验收 seek 延迟。
## segment-playback
适用于“输入选择下一状态,动作随后自行完成”的交互。使用
[assets/interactive-motion.ts](../assets/interactive-motion.ts) 的
`createSegmentPlayer`,不要在页面重新实现播放状态机。
必须满足:
1. 生产时可以分段生成,但连续链交付前必须合并;运行时使用一个持续存在的媒体实例,切换状态不替换 `src`、视频节点或图片层。
2. 输入一发生就启动媒体;页面导航或其他几何动画可以并行,不等待动作结束。
3. 反向输入先取消当前播放,再从当前 `currentTime` 向上一状态撤回。
4. 前进可以使用用户输入触发的 `video.play()`。反向不能依赖浏览器支持负 `playbackRate`,由共享控制器按时间轴回放。
5. 使用 `requestVideoFrameCallback`,无支持时回退 `requestAnimationFrame`;不得用低频 `timeupdate` 判断停帧。
6. 接近目标时先暂停,再精确设到 `hold`,避免越过目标后回跳。
7. 播放速率曲线属于时间轴清单。需要两端快、中间慢时使用 `edge-mid-edge`;正放与倒放读取同一曲线。
8. 快速连续输入只保留最新目标,旧任务必须可取消。
桌面与移动媒体版本在初始化时选择。普通 resize 不换源;确需重载另一版本时,恢复到当前状态的 `hold` 后再继续。
分页导航只负责选择目标状态 ID。它不能把分段时间轴改成多个互不相关的视频,也不能用页面切换遮盖媒体接缝。
### 分步手势策略
`segment-playback` 与分页导航组合时,必须从 Motion Brief 读取 `gesture_policy`:
- `one-gesture-one-step`:把同一次滚轮或触控板惯性序列合并成一个方向意图,不能按每个原始事件连续跳状态。
- `while_active`:明确新输入是重定向、排队还是忽略;默认需要可反向的交互使用 `retarget`。
- `boundary`:首尾状态执行 `clamp` 或合同明确的 `loop`,不能越界创建空状态。
- `programmatic_navigation=ignore`:页面自身的平滑滚动和位置校正不得再次触发媒体状态变化。
- 页面元素的状态 ID 必须直接匹配 `timeline.json.states[].id`;找不到、重复或顺序不一致时在初始化阶段失败。
从 [assets/step-gesture.ts](../assets/step-gesture.ts) 的 `createStepGestureAdapter` 开始实现。滚轮、触控板或触摸层只把方向增量送入该适配器;手势阈值、惯性结束判定和程序化导航锁不得在页面监听、媒体控制器和分页组件中各写一份。
## autonomous-playback
适用于待机、循环或进入可见区域后自行播放的动画。浏览器允许时使用 `muted playsinline`;需要声音或浏览器阻止自动播放时,等待明确用户手势。循环只在素材本身通过首尾接缝验收时启用。
## 渲染器
### Alpha 图集
- 单元格尺寸统一,并至少覆盖最大 CSS 尺寸乘目标 DPR。
- 清单保存帧数、行列、单元格尺寸和参数映射。
- 切帧只更新 `background-position`,不创建多张透明图片交叉淡化。
- 默认单张纹理不超过 4096;超预算回到自动路线选择。
### Chroma 视频
- 视频保留均匀色键,由 `chroma-video-renderer.ts` 绘制透明 Canvas。
- 页面背景、文字和其他视觉层位于 Canvas 外部。
- 运行时从 `compile.json.runtime.keying` 读取全部参数,不在页面另写阈值。
- WebGL 或视频失败时显示静态 Alpha 降级图,不能露出色键母版。
### Baked 视频
- 视频本身包含完整画面,不做抠色、色键或背景合成。
- 可由视频元素直接显示,也可绘制到 Canvas。
- 失败时显示普通 `poster.png`。
## 输入、布局与生命周期
- `pointermove`、`scroll` 和触摸事件只记录输入,不在事件回调中反复写 DOM。
- 布局变化后重新读取主体位置;不要永久缓存 `getBoundingClientRect()`。
- 使用 `IntersectionObserver` 暂停离屏计算,使用 `ResizeObserver` 更新布局。
- 手机方向权限必须由用户手势请求;拒绝或不可用时回退触摸或静态状态。
- 页面切后台时暂停;恢复后以最新目标和当前媒体时间继续。
## 预加载与降级
- 图集预加载清单、静态帧和图集,并等待 `Image.decode()`。
- 视频预加载静态降级、元数据和首个需要的媒体;`loadedmetadata` 前不得 seek 或播放。
- 加载完成前只显示一张静态降级图或简洁加载层。
- 资源失败时解除页面锁定并回退静态画面,不让次要动画阻塞页面。
- `prefers-reduced-motion` 使用合同指定的静态状态,不自动播放或连续 scrub。
## 性能验收
- 每个动画帧最多一次 DOM 写入;目标未变化时不重复渲染。
- 离屏或状态稳定时停止 `requestAnimationFrame`。
- 不同时渲染两张大图做“平滑”。
- 在冷缓存、弱网、低端移动设备、快速反向和连续输入下检查。