laohan-donghua · diff
v10.0.0 to v11.1.0-candidate
58 added, 634 removed. Audit F to A.
---
name: laohan-donghua
- version: "10.0.0"
- description: "从口播稿+真人视频生成带B-roll overlay的最终视频。一个index.html+一次render出成片。Use when 用户说生成B-roll、做视频片段、配图动画、Hyperframes动画、教程配图、给视频加特效、做overlay、加动效。"
- ---
-
- # Hyperframes B-roll Overlay 视频
-
- 从口播稿+真人视频,生成带 B-roll overlay 动画的最终成片。一个 index.html,一次 render。
-
- ## 核心理念
-
- 1. **一个 index.html,一个 render。** 禁止分开渲染再 ffmpeg overlay
- 2. **从零构建,不复制模板。** 按 DESIGN.md 从零写每个场景 HTML
- 3. **时间戳驱动。** 官方 `npx hyperframes transcribe` 拿真实时间戳
- 4. **每个场景不同视觉风格。** 在 DESIGN.md 框架内做变体
- 5. **B-Roll 覆盖率按内容密度决定。** AI/教程密集型通常 30-45%,策略评论 25-35%,个人叙事 15-25%,UI 证据型可到 40-55%
-
- ## B-roll 目的与 source mode 硬规则
-
- B-roll 第一目标是提升观感、可读性、代入感、节奏感和理解速度,不是给每一句口播取证。对标账号里的数字卡、仪表盘、数据墙不默认等于真实数据;学习的是界面表现、动画华丽程度、转场、字体、特效、节奏和信息层级。
-
- 每个 B-roll 场景必须先选一个 source mode:
-
- | source mode | 默认场景 | 处理方式 |
- |-------------|----------|----------|
- | `illustrative` | 观点、教学步骤、个人经验、类比、用于强调的数字/数据 | 默认模式。做成更强的原创动画、数字墙、流程图、概念面板;不要要求用户证明。 |
- | `public-source` | GitHub stars、官方文档、公开 benchmark、release、论文、公开趋势/新闻 | 需要时联网查公开来源,保存 URL/标题/访问日期/提取事实,再做原创卡片或图表。 |
- | `user-provided proof` | 用户自己的后台、花费、私有截图、评论、聊天、账号状态、真实发布数据 | 只有确实需要证明用户私有结果时才向用户要素材。 |
-
- 没有真实 proof 素材不是默认卡点。比如“研究了 3 天”“一个月烧了 50 亿 token”这类表达,如果用户没有截图,默认做成示意动画;只有用户明确要证明真实花费/用量时才要截图或数据。超越参考账号的主战场是表现层,不是证明层。
-
- ## 不适用场景
-
- - **从零做视频(无口播稿+无视频)** → `/make-a-video`
- - **纯动画/PPT(无真人出镜)** → `/hyperframes`
- - **竖屏短视频(9:16)** → 先明确目标画布和 face-wrapper 架构,再继续;不要默认按 16:9 裁切
-
- `make-a-video` 是完整视频创作流程(8-gate,从选题到渲染),laohan-donghua 是 B-roll overlay 专项流程(18-step,口播稿+真人视频→overlay 成片)。两者并行,不嵌套。
-
- ## 委托关系
-
- | 职责 | 委托给 | 何时调用 |
- |------|--------|----------|
- | Composition 编写规则 | `/hyperframes` | 写 HTML 前 |
- | CLI 命令 | `/hyperframes-cli` | lint/render |
- | 媒体处理 | `/hyperframes-media` | 转录 |
- | GSAP 动画 | `/gsap` | 复杂动画 |
- | Catalog blocks 安装 | `/hyperframes-registry` | 需要官方预制组件时 |
- | 规则约束 | `rules/hyperframes.md` | 自动加载 |
- | Render Contract + workspace | `CLAUDE.md` | 自动加载(11 条硬规则 + 项目结构) |
- | 架构/设计参数 | `references/` | 构建时查阅 |
-
- **写 composition 前,先调用 `/hyperframes` 获取框架规则。**
-
- ## HyperFrames student-kit 项目内优先级
-
- 如果当前工作目录是 `/Users/hanzhmacbookair/Documents/hyperframes/hyperframes-student-kit` 或其 `video-projects/*` 子项目,本 skill 必须让位给项目内权威流程:
-
- 1. `docs/AI_TALKING_HEAD_OVERLAY_SYSTEM.md`
- 2. 生成项目的 `PROJECT_BRIEF.md`
- 3. 生成项目的 `SCRIPT_ANALYSIS.md`
- 4. 生成项目的 `ASSET_PLAN.md`
- 5. 生成项目的 `AI_SCENE_INDEX.md` / `STYLE_PROFILE.md` / `style-profile.json`
- 6. 生成项目的 `OVERLAY_PLAN.md`
-
- 在该项目内,禁止继续引用不存在的 `scene-index.md`;禁止写死 30% 覆盖率;禁止把参考账号下载帧、封面、logo 或精确布局作为项目素材。
-
+ version: "11.1.0-candidate"
+ description: 真人口播动画生产编排器。读取⑨导演 EDL、⑩已核验素材、剪后视频和实际字幕,分别用 Remotion 或 HyperFrames 生成并 QA 最终成片。Use when 用户说生成动画成片、渲染口播动画、进入⑪动画生产、Remotion 成片、HyperFrames 成片、合成最终视频。
---
- ## 执行流程
-
- ### 🚧 流程门控(每步必须通过才能继续)
-
- | Gate | 位置 | 必须产出 | 未通过则 |
- |------|------|---------|---------|
- | G1 | 步骤 4 后 | 场景规划表(编号+口播段落+提取文字+布局+情绪+语义类型)| 禁止进入步骤 6 |
- | G2 | 步骤 8 后 | 时间戳校准表(帧对齐 data-start/duration,场景间 ≥0.3s 间隔)| 禁止构建 compositions |
- | G3 | 步骤 10 后 | 全场景构建检查清单全部 ✅ | 禁止 lint |
- | G4 | 步骤 12 后 | lint 0 error + validate 通过 + inspect 无溢出 | 禁止 preview |
- | G5 | 步骤 15 后 | 用户在 Studio 明确说"可以" | 禁止 draft render |
- | G6 | 步骤 16 后 | 每个 hero 帧 Read 确认无黑帧/裁切/溢出 | 禁止 standard render |
- | G7 | 步骤 17 后 | 用户在 MP4 明确说"可以" | 禁止 final render |
-
- **强制规则**:
- 1. 跳过任何 Gate → 停止执行,回到未完成的步骤。没有例外。
- 2. 默认由 agent 自主推进,不要每步都让用户记命令或确认。只有源视频内容问题、素材缺失会改变真实性、Studio/MP4 预览放行、最终渲染放行时才问用户。
- 3. "我觉得大概是这样" ≠ 通过。必须有具体的表格/文件/命令输出。
-
- ### 用户侧(模型不参与)
-
- 1. 口播稿定稿
- 2. 录制真人出镜视频
- 3. 剪掉错误片段,得到干净口播视频
-
- ### 实际输入验收(必须先做)
-
- 真实拍摄素材经常不是干净成片。开始 overlay 前,先判断输入属于哪类:
-
- | 问题类型 | 例子 | 处理 |
- |----------|------|------|
- | 媒体格式问题 | 非 H.264、无音轨、奇数尺寸、异常 fps、竖屏/方屏 | 先转码或选对应 face-wrapper 架构,再继续 |
- | 口播内容问题 | 口误、重说、咳嗽、长停顿、重复 take、废话段 | 不要用动画遮盖;先让用户剪映导出干净版,或输出粗剪时间戳清单让用户确认 |
- | 文稿不匹配 | 口播稿和实际说法不一致 | 以 transcript 时间戳为准,先修正 SCRIPT.md,再规划 overlay |
- | 素材缺失 | 提到网页/数据/聊天/产品但没有截图或录屏 | 先判定 source mode:普通观点/教学/强调数字用原创示意动画;公开事实可联网查源;只有私有结果必须证明时才让用户补素材 |
-
- 如果项目提供输入检查脚本,先运行它。例如 HyperFrames student-kit:
-
- ```bash
- npm run input:inspect -- <video.mp4>
- ```
-
- **硬规则**:内容问题没有处理前,不进入步骤 4 的 overlay 场景规划。动画不能拯救坏口播。
-
- ### 阶段一:只要口播稿
-
- #### 步骤 4:读口播稿 → 插入点设计 + 内容规划 + 场景规划
-
- 📖 **读取**:口播稿全文
- 📖 **查阅**:项目内 `AI_SCENE_INDEX.md` / `style-profile.json`;非 student-kit 项目则使用本 skill 的 `references/` 作为备用技法库
-
- 这是最关键的步骤。三层规划决定视频质量。
-
- **4a. 语义分类 + 默认技法映射**:给口播稿每段标记内容类型,并匹配默认技法(模型可覆盖,但默认选择已覆盖 80% 场景):
-
- | 类型 | Overlay? | 默认技法 | 来源 |
- |------|-----------|---------|------|
- | 数据/数字 | ✅ | Counter count-up + 数字 glow | may-shorts-6 scene1 |
- | 列举/枚举 | ✅ | Stagger list + strike-through(否定项) | may-shorts-6 scene3 |
- | 概念解释 | ✅ | Chrome gradient sweep + text-shadow glow | may-shorts-6 scene6 |
- | 对比/VS | ✅ | 分栏卡片 + mask-image feather | — |
- | 重点强调 | ✅ | Slam + micro-tremor + scan-line sweep | may-shorts-18 scene1 |
- | 冲击/反转 | ✅ | Hero slam + spark burst + glow pulse | may-shorts-18 scene5 |
- | 标签/功能名 | ✅ | Chip/pill badge pop + glow pulse | may-shorts-18 scene2 |
- | 紧张/倒计时 | ✅ | Letter-spacing breath + vignette breathing | may-shorts-18 scene5 |
- | 工具介绍 | ✅ | 命令行/步骤列表 + accent 色 glow | — |
- | 总结/CTA | ✅ | 全屏 endcard + shimmer sweep | may-shorts-6 scene8 |
- | 纯叙述/过渡 | ❌ | 保持真人全屏(HERO 模式) | — |
- | 情感/故事 | ❌ | 保持真人全屏 | — |
-
- **4b. B-Roll 覆盖率计算**:
-
- ```
- 先按内容类型选择覆盖率:
- - AI/教程密集型:30-45%
- - 策略评论:25-35%
- - 个人叙事:15-25%
- - UI 证据型:40-55%
-
- 总视频时长 × 选定覆盖率 = overlay 总时长范围
- overlay 总时长 ÷ 场景数 = 平均场景时长(普通 2-4.5s,证据场景 4-8s)
- ```
-
- 场景数由内容密度决定,不是均分。密集段落可以连续多个场景,稀疏段落保持全屏。
-
- **4c. 内容提取**:为每个 overlay 场景提炼显示文字。
-
- 不是整句口播稿搬上去,是**提炼后的关键词/短语**。文字量决定布局:
-
- | 提取文字量 | 适合布局 | 典型字号 |
- |-----------|---------|---------|
- | 1 个关键词 | hero 大字居中 | 80-120px |
- | 1 标题 + 2-3 标签 | 上标题下列表 | 标题 64px, 标签 36px |
- | 1 标题 + 1 数字 | 左文右数据 | 标题 56px, 数字 96px |
- | 3-5 个并列项 | 横向卡片/竖向列表 | 32-40px |
-
- 输出格式:
-
- ```
- 场景 | 口播段落 | 提取的 overlay 文字 | 文字量 | 建议布局 | 情绪
- s1 | "终端输一行..." | "opencli" + "一行命令搞定" + "标题·播放量·时间" | 3 标签 | 列表式 | 震撼
- s2 | "想抓知乎热榜..." | "知乎热榜" + "50条" + "链接+摘要" | 标题+数据 | 数据展示 | 专业
- ```
-
- **4d. 视觉结构匹配**:根据内容类型 + 文字量,从项目内 `AI_SCENE_INDEX.md` / `style-profile.json` 找视觉结构模式;没有这些文件时才用本 skill 的 `references/` 技法库。
-
- 这不是复制模板——是参考空间分配和布局方式。用实际文字长度重新设计具体位置和字号。
-
- **完成条件:**
- - 场景清单(编号 + 口播段落 + 提取文字 + 建议布局 + 情绪)
- - overlay 总占比符合选定内容密度目标
- - 每个场景有明确的文字内容和布局方向
-
- **🚧 GATE 1**:场景规划表未输出 → 禁止进入步骤 6。必须包含所有列。产出物是一个完整的 markdown 表格。
-
- #### 步骤 5:创建 DESIGN.md
-
- 📖 **读取**:项目本地 `.agents/skills/hyperframes/` 或 `.claude/skills/hyperframes/`;如果当前是 student-kit 项目,优先使用 `STYLE_PROFILE.md` / `style-profile.json`
- 📖 **参考**:`DESIGN.ais-example.md`(完整结构模板)
-
- 从 visual-styles.md 选择最匹配口播内容的风格。教程类 AI 工具测评通常适合 Swiss Pulse(数据驱动)或 Data Drift(AI/未来感)。
-
- DESIGN.md 必须包含:
- - Style Prompt(一句话风格描述)
- - Colors(token + hex + role)
- - Typography(标题/正文/标签 各用哪个字体)
- - Motion Rules(energy / easing entry/exit/ambient / duration entrance/hold/transition)
- - What NOT to Do
-
- **完成条件:** DESIGN.md 包含上述全部段落
-
- ### 阶段二:需要口播视频
-
- #### 步骤 6:环境检查
-
- 📖 **读取**:项目本地 `.agents/skills/hyperframes-cli/SKILL.md` 或 `.claude/skills/hyperframes-cli/SKILL.md`(doctor 命令详情)
-
- ```bash
- cd video-projects/<project-slug>
- npx hyperframes doctor
- npx hyperframes benchmark # 找到系统最优 workers/quality 设置
- ```
-
- CLI 必须从项目目录运行。检查 assets/ 中视频是否为 H.264 MP4,非 H.264 需先 re-encode:
-
- ```bash
- ffmpeg -i raw.mov -c:v libx264 -preset medium -crf 20 -c:a aac -b:a 192k -movflags +faststart assets/clip.mp4
- ```
-
- #### 步骤 7:转录
-
- 📖 **读取**:项目本地 `.agents/skills/hyperframes-media/SKILL.md` 或 `.claude/skills/hyperframes-media/SKILL.md`(transcribe 命令详情)
-
- **字幕系统选择(固定优先级)**:
-
- | 优先级 | 方案 | 条件 | 说明 |
- |--------|------|------|------|
- | ★ 首选 | word-level 逐词字幕 | 官方转录输出含 word timestamps | 三态颜色(未读→accent→白色)+ 逐词 scale 弹跳 + 8 方向 text-shadow 描边。参考 may-shorts-6 captions.html |
- | ↓ 降级 | sentence-level 整句字幕 | word 数据缺失 | 28px 毛玻璃条底板 |
-
- 用官方转录拿时间戳:
-
- ```bash
- npx hyperframes transcribe assets/<video>.mp4 --model small --language zh --json
- ```
-
- **字幕文本来源**:用 Whisper 转录原文,手动修正识别错误(如"翻热节"→"翻热点")。不用口播稿精简版。字幕是屏幕底部的口播内容,不是场景动画里的文字。
-
- **中文识别准确率校验**(可选):如官方识别质量不满意,用硅基流动做对照参考:
-
- ```bash
- curl -s -X POST https://api.siliconflow.cn/v1/audio/transcriptions \
- -H "Authorization: Bearer $SILICONFLOW_API_KEY" \
- -F "model=FunAudioLLM/SenseVoiceSmall" -F "file=@assets/<video>.mp4"
- ```
-
- 注意:硅基流动返回纯文本(无时间戳),只能用于校验中文识别准确率,不能替代官方 `--json` 输出。
-
- #### 步骤 8:精确校准时间戳
-
- 读 transcript.json,将步骤 4 的场景清单中每个 overlay 匹配到精确的口播段落:
- - 起始时间 = 对应口播句子的开始
- - 结束时间 = 对应口播句子的结束
- - 帧边界对齐:时间 snap 到 0.0333s 倍数(30fps)
- - 场景间留 0.3-0.5s 间隔(避免连续 overlay 太密)
-
- **完成条件:** 每个场景有精确的帧对齐 data-start/data-duration,overlay 总占比符合步骤 4b 的内容密度目标
-
- **🚧 GATE 2**:时间戳校准表未输出 → 禁止构建 compositions。产出物是一个完整的时间戳表,每行有 data-start、data-duration、帧对齐确认。
-
- #### 步骤 9:构建 compositions
-
- 📖 **必读**:`references/broll-architecture.md`(架构约束 + 常见错误速查)
- 📖 **查阅**:`references/broll-techniques.md`(24 种常用动画技法 + 3 大基础设施系统,按场景需要选用)
- 📖 **查阅**:`references/broll-design-reference.md`(face-wrapper 4 种架构、8 种视觉风格、face 美化)
- 📖 **参考**:项目内 `AI_SCENE_INDEX.md` / `style-profile.json`(按内容类型 + 文字量匹配视觉结构模式)
- 📖 **必读**:项目本地 `.agents/skills/hyperframes/references/typography.md` 或 `.claude/skills/hyperframes/references/typography.md`(字体排版规则,每个场景都有文字)
- 📖 **参考**:项目本地 `.agents/skills/hyperframes/references/css-patterns.md` 或 `.claude/skills/hyperframes/references/css-patterns.md`(文字强调效果)
- 📖 **规则**:`rules/hyperframes.md`(自动加载,承重 GSAP 规则)
-
- 对每个场景创建 `compositions/<scene-name>.html`。从零按 DESIGN.md 构建。
-
- **推荐 Layout Before Animation 方法论**(官方):先写最终状态的静态 CSS(hero frame),再用 `gsap.from()` 添加入场动画。
-
- **场景视觉设计**:
- - 每个场景在 DESIGN.md 框架内做变体(同色系不同布局)
- - 按 `AI_SCENE_INDEX.md` / `style-profile.json` 匹配内容类型的视觉结构
- - 变体方式:布局方向(左对齐/居中/卡片)、强调元素(数字/标签/图标)、动画节奏
-
- **文字尺寸验证**(用官方工具,不靠猜):
-
- 在 Studio preview 中运行以下工具验证文字不溢出:
-
- ```js
- // 方法 1:自动计算最佳字号
- var result = window.__hyperframes.fitTextFontSize("显示的文字", {
- maxWidth: 800, // 容器宽度(overlay bg 通常 960px,内容区 600-800px)
- fontFamily: "Noto Sans SC",
- fontWeight: 900
- });
- // result.fontSize → 设到 CSS 中
-
- // 方法 2:精确文字测量(无 DOM reflow)
- var prepared = window.__hyperframes.pretext.prepare("显示的文字", "900 64px 'Noto Sans SC'");
- var layout = window.__hyperframes.pretext.layout(prepared, 800, 1.3);
- // layout.width, layout.height → 检查是否超出容器
- ```
-
- 原则:先确定容器宽度 → 用 fitTextFontSize 算字号 → 写入 CSS。不要反过来先猜字号再发现溢出。
-
- **完整场景示例**(改文字/颜色即用,不需要从片段组装):
-
- | 示例文件 | 覆盖内容类型 | 包含技法 |
- |---------|------------|---------|
- | `references/example-a-data.html` | 数据/数字 | panel + counter count-up + underline + vignette breathing + anchor |
- | `references/example-b-list.html` | 列举/枚举 | panel + stagger list + strike-through + mask-image + vignette breathing + anchor |
- | `references/example-c-concept.html` | 概念解释 | panel + chrome gradient sweep + clip-path reveal + text-shadow glow + vignette breathing + anchor |
- | `references/example-d-negate.html` | 否定/反转 | X-mark pop + global strike + mask-image feather + vignette breathing |
- | `references/example-e-affirm.html` | 肯定列表 | check-list stagger + dual-accent + mask-image feather + vignette breathing |
- | `references/example-f-punch.html` | 短冲击强调 | burst flash + punch card + text-stroke outline(<1s,带退场) |
- | `references/example-g-cta.html` | CTA/Outro | logo crystallize + shimmer sweep + underline scale + wordmark fade |
- | `references/example-h-stamp.html` | 价格/印章强调 | stamp badge(旋转弹入)+ banner bar(横向展开)+ backdrop blur |
-
- **用法**:复制最匹配的示例 → 改 `data-composition-id`、文字内容、颜色、DURATION → 按需增减元素。
-
- **最小模板**(极简骨架,仅用于无法匹配上述 8 种示例时):
-
- ```html
- <template id="<scene-name>-template">
- <div data-composition-id="<scene-name>" data-start="0"
- data-duration="<时长>" data-width="1920" data-height="1080"> <!-- data-duration 可选,框架不使用,仅作文档参考。实际时长由 anchor tween 的 tl.duration() 决定 -->
- <div class="bg"></div>
- <div class="vignette"></div>
- <div class="title">标题</div>
- </div>
-
- <style>
- [data-composition-id="<scene-name>"] .bg {
- position: absolute; top: 0; left: 0; width: 960px; height: 1080px; /* 宽度按需设计,右侧留空给 face-wrapper */
- background: linear-gradient(160deg, #0a0e1a, #0d1225);
- mask-image: linear-gradient(to right, #000 0%, #000 calc(100% - 80px), transparent 100%);
- }
- [data-composition-id="<scene-name>"] .vignette {
- position: absolute; top: 0; left: 0; width: 960px; height: 1080px;
- pointer-events: none;
- background: radial-gradient(ellipse at 50% 50%, transparent 30%, rgba(0,0,0,0.5) 100%);
- opacity: 0.2;
- }
- [data-composition-id="<scene-name>"] .title {
- position: absolute; top: 120px; left: 80px;
- font: 900 96px/1 "Noto Sans SC", sans-serif; color: #f5f5f5;
- }
- </style>
-
- <script src="https://cdn.jsdelivr.net/npm/gsap@3.14.2/dist/gsap.min.js"></script>
- <script>
- (() => {
- const DURATION = <时长>;
- const tl = gsap.timeline({ paused: true });
-
- // BUILD(入场)
- tl.fromTo('.title', { autoAlpha: 0, y: 30 },
- { autoAlpha: 1, y: 0, duration: 0.5, ease: 'power2.out' }, 0.1);
-
- // BREATHE(ambient)
- const cycles = Math.ceil(DURATION / 4) - 1;
- tl.to('.vignette', { opacity: '+=0.08', duration: 2,
- repeat: cycles, yoyo: true, ease: 'sine.inOut' }, 1.5);
-
- // Anchor tween(必须)
- tl.to({}, { duration: DURATION }, 0);
- window.__timelines['<scene-name>'] = tl;
- })();
- </script>
- </template>
- ```
-
- **构建检查清单:**
-
- ```
- □ 根 div 有 data-start="0" + data-duration + data-width + data-height
- □ 内部元素没有 class="clip" / data-start / data-duration / data-track-index
- □ CSS 全部用 [data-composition-id="xxx"] scope
- □ 文件有 <template> 包装 + <script src="gsap.min.js">
- □ 背景最低 3 层:渐变底 + vignette + 至少一个漂移/呼吸元素
- □ 所有彩色文字有匹配色 text-shadow glow
- □ 按 DESIGN.md motion token 选 easing/duration
- □ 两阶段:build(入场)+ breathe(ambient)
- □ overlay 模式不写退场/resolve 动画(outro 除外)
- □ 禁止 Math.random() / Date.now() / repeat: -1
- □ 文字尺寸已用 fitTextFontSize 或 pretext 验证,不溢出容器
- □ 每个场景的文字内容来自步骤 4c 的内容提取表
- □ INSET 场景 bg 用全宽(1920px 或 inset:0),SIDE 场景用 960px + mask-image
- ```
-
- #### 步骤 10:构建 index.html
-
- 📖 **必读**:`references/broll-architecture.md`(mount div 属性要求)
- 📖 **查阅**:`references/broll-design-reference.md`(face-wrapper 4 种架构和过渡时序)
-
- **完整模板**:
-
- ```html
- <!doctype html>
- <html lang="zh-CN">
- <head>
- <meta charset="UTF-8" />
- <meta name="viewport" content="width=1920, height=1080" />
- <title><项目名></title>
- <script src="https://cdn.jsdelivr.net/npm/gsap@3.14.2/dist/gsap.min.js"></script>
- <link href="https://fonts.googleapis.com/css2?family=Noto+Sans+SC:wght@400;500;700;900&family=Space+Grotesk:wght@700;900&display=block"
- rel="stylesheet" />
- <style>
- * { margin: 0; padding: 0; box-sizing: border-box; }
- html, body { width: 1920px; height: 1080px; overflow: hidden;
- background: #050b13; font-family: "Noto Sans SC", sans-serif; color: #fff; }
- #root { position: relative; width: 1920px; height: 1080px; overflow: hidden; }
-
- /* Face-wrapper — 三种模式(固定,不改) */
- #face-wrapper {
- position: absolute; top: 0; left: 0; width: 1920px; height: 1080px;
- transform-origin: 0 0; transform: translate(0px, 0px) scale(1);
- z-index: 0;
- }
- #face-video {
- display: block; width: 100%; height: 100%; object-fit: cover;
- filter: contrast(1.04) saturate(1.02) brightness(0.99);
- }
- #face-wrapper::after {
- content: ""; position: absolute; inset: 0; pointer-events: none;
- background: radial-gradient(ellipse at center, transparent 60%,
- rgba(5,11,19,0.3) 88%, rgba(5,11,19,0.7) 100%);
- }
-
- .scene-layer {
- position: absolute; top: 0; left: 0; width: 1920px; height: 1080px;
- }
- </style>
- </head>
- <body>
- <div id="root" data-composition-id="<project-id>" data-start="0"
- data-width="1920" data-height="1080">
-
- <!-- Poster frame(GSAP-managed, not a clip) -->
- <img id="poster" src="assets/clip-poster.jpg"
- style="position:absolute;top:0;left:0;width:1920px;height:1080px;object-fit:cover;">
-
- <!-- Face video (muted, audio from sibling <audio>) -->
- <div id="face-wrapper">
- <video id="face-video" src="assets/talking_head.mp4"
- muted data-start="0" data-duration="TOTAL" data-track-index="1"
- playsinline></video>
- </div>
-
- <!-- Last frame(GSAP-managed, not a clip) -->
- <img id="lastframe" src="assets/clip-lastframe.jpg"
- style="position:absolute;top:0;left:0;width:1920px;height:1080px;object-fit:cover;opacity:0;">
-
- <!-- Audio track -->
- <audio src="assets/audio.wav" data-start="0" data-duration="TOTAL"
- data-volume="1" data-track-index="2"></audio>
-
- <!-- Ambient background(全时长舞台层:grid 漂移 + 粒子 + vignette) -->
- <div class="scene-layer" data-composition-id="ambient-bg"
- data-composition-src="compositions/ambient-bg.html"
- data-start="0" data-duration="TOTAL" data-track-index="0"
- data-width="1920" data-height="1080"></div>
-
- <!-- Scene overlays(每个 mount div 必须有 data-track-index + data-width + data-height) -->
- <div class="scene-layer" data-composition-id="s1-hook"
- data-composition-src="compositions/s1-hook.html"
- data-start="17.0" data-duration="4.8" data-track-index="3"
- data-width="1920" data-height="1080"></div>
- <!-- ...更多场景... -->
-
- <!-- Captions(word-level 逐词字幕,独立 sub-composition) -->
- <div class="scene-layer" data-composition-id="captions"
- data-composition-src="compositions/captions.html"
- data-start="0" data-duration="TOTAL" data-track-index="4"
- data-width="1920" data-height="1080"></div>
- </div>
-
- <script>
- window.__timelines = window.__timelines || {};
- const mainTl = gsap.timeline({ paused: true });
- const TOTAL = <总时长>;
-
- // ── Face-wrapper 三种模式(固定参数,不改) ──
- const HERO = { x: 0, y: 0, scale: 1, opacity: 1 }; // 全屏人脸
- const SIDE = { x: 480, y: 0, scale: 1, opacity: 1 }; // 左右分屏(默认)
- const INSET = { x: 1340, y: 760, scale: 0.27, opacity: 1 }; // 小窗右下角
- const MODE_DUR = 0.32;
-
- // 初始状态:HERO(开场全屏人脸)
- mainTl.set("#face-wrapper", HERO, 0);
-
- // ── Face 过渡时间表 ──
- const transitions = [
- { t: 17.0, mode: SIDE }, // s1 开始
- { t: 21.8, mode: HERO }, // s1 结束
- // ...按场景填充...
- { t: 174.3, mode: INSET }, // outro 开始(INSET 替代 fade out)
- ];
- transitions.forEach(({ t, mode }) => {
- mainTl.to("#face-wrapper",
- { ...mode, duration: MODE_DUR, ease: "expo.inOut" }, t - 0.15);
- });
-
- // ── Poster → video handoff ──
- mainTl.to("#poster", { opacity: 0, duration: 0.15, ease: "power2.out" }, 0.1);
- // ── Lastframe hold after video ends ──
- mainTl.set("#lastframe", { opacity: 1 }, TOTAL - 0.5);
-
- // ── Ken Burns 缓慢缩放 ──
- mainTl.to("#face-video", { scale: 1.03, duration: TOTAL, ease: "none" }, 0);
-
- // ── Pad to TOTAL ──
- mainTl.set({}, {}, TOTAL);
- window.__timelines["<project-id>"] = mainTl;
- </script>
- </body>
- </html>
- ```
-
- 关键规则:
- - `<video>` 不加 `class="clip"`
- - poster/lastframe 由 GSAP 管理 opacity(不是 class="clip" + data 属性)
- - mount div 缺 `data-track-index` / `data-width` / `data-height` 任一 = 黑帧
- - **index.html 不用 `<template>` 包装**(只有 sub-composition 文件才用)
- - Face-wrapper 过渡时间表与场景 data-start 对齐,`t - 0.15` 提前
- - Google Fonts CDN 保留(Studio preview 需要,渲染时编译器自动嵌入)
- - **字幕用独立 captions.html sub-composition**(track-index 4),不用 inline .cap div
- - **outro 用 INSET 模式**(结尾最后 ~0.6s 可 fade out face 让锁屏画面独占)
- - **ambient-bg 常开**(track-index 0,全时长舞台层)
-
- **🚧 GATE 3**:步骤 9 的构建检查清单全部 ✅ 后才能进入 lint。逐场景检查,任何一项未通过 → 返回修改对应 composition。
-
- #### 步骤 11-18:验证管线
-
- 📖 **读取**:项目本地 `.agents/skills/hyperframes-cli/SKILL.md` 或 `.claude/skills/hyperframes-cli/SKILL.md`(命令参数详解)
-
- ```bash
- # 11. 静态检查
- npx hyperframes lint # 修 error,triage warning(含对比度检查)
+ # 真人口播动画生产
- # 12. 运行时检查(lint 看不到 JS 异常、音频同步等运行时问题)
- npx hyperframes validate # headless Chrome 运行时验证
+ 本 skill 执行已经做出的导演决策,不重新决定哪些话要动画。动画不是固定 B-roll 覆盖率,也不是一个 HTML 模板。
- # 13. 布局检查
- npx hyperframes inspect # headless Chrome 视觉布局
+ ## 必要输入
- # 14. 动画编排分析(新场景或重大改动时运行)
- node .claude/skills/hyperframes/scripts/animation-map.mjs compositions/ --out compositions/.hyperframes/anim-map
- # 输出:per-tween 摘要、ASCII 时间线、stagger 检测、dead zone 标记、元素生命周期、场景快照
+ 读取当前 episode:
- # 15. Gate 1: Studio preview(强制)
- npx hyperframes preview # localhost:3002
- # → 用户确认布局后才进下一步
+ 1. 07-剪辑/clean.mp4 与 subtitles.srt;
+ 2. 09-导演/edl.json、source-manifest.json、renderer-brief.md;
+ 3. 10-素材/素材清单.json(仅当 EDL 有 BROLL_STOCK);
+ 4. episode-config.json。
- # 16. Draft 渲染 + 抽帧验证
- npx hyperframes render --quality draft --output renders/draft.mp4
- # 抽帧验证(snapshot 优先,ffmpeg fallback):
- npx hyperframes snapshot --at <scene1-t>,<scene2-t>,<scene3-t> --timeout 10000
- # fallback(snapshot 不可用时):
- # mkdir -p renders/frames
- # for t in <scene1-t> <scene2-t> ...; do
- # ffmpeg -y -ss $t -i renders/draft.mp4 -frames:v 1 -q:v 2 "renders/frames/t${t}.png"
- # done
- # 每个 PNG 必须 Read 确认无黑帧/裁切/溢出
+ 缺输入时报告文件名并停止。只有 素材清单.json 标为 visually_verified 的资产可以使用。
- # 17. Gate 2: MP4 preview(强制)
- # npx serve renders -p 8080 -n → 用户确认节奏+音频同步
+ 🛑 STOP:EDL、source manifest、renderer brief 或 required 素材缺失时,不创建 renderer 项目。
- # 18. Standard 渲染
- npx hyperframes render --quality standard --output renders/final.mp4
- # 性能选项(按需):
- # --workers <n> 并行 worker(默认 CPU/2 上限4,短视频用 1)
- # --gpu 硬件编码(Mac: VideoToolbox)
- # --docker 确定性渲染(跨平台一致,AI agent 推荐)
- ```
+ ## 工作流
- **渲染策略**:优先整体渲染(官方方法)。如黑帧严重,降级为逐场景渲染 + ffmpeg overlay 合成。黑帧预防见 `rules/hyperframes.md` 的结构性预防清单。
+ ### 1. 建立 renderer 任务
- **两个 preview gate 强制**:Gate 1 确认布局,Gate 2 确认节奏+音频。lint 通过 ≠ 渲染正确。
+ 先在 workflow 根运行 `node scripts/prepare-renderer-handoff.mjs episodes/<slug> <remotion|hyperframes>`。两个 renderer 只能消费各自 `11-动画/renderer-handoffs/<renderer>/input-manifest.json`,先验证全部 SHA-256;禁止从 `视频动画` 的旧 pilot 或历史 project 猜输入。
- ---
+ 渲染前运行 `node scripts/verify-renderer-handoff.mjs episodes/<slug>/11-动画/renderer-handoffs/<renderer>/input-manifest.json`。任何 hash 变化都回⑨或⑩重新生成 handoff,不能沿用旧 candidate。
- ## Overlay 专属规则
+ 随后运行 `node scripts/create-renderer-workspace.mjs episodes/<slug> <renderer>`,只在本期 `11-动画/renderer-projects/<renderer>/` 实现;生成器拒绝覆盖已有 workspace,旧 pilot 不参与。
- 以下规则仅适用于 B-roll overlay 模式,通用规则见 `rules/hyperframes.md`。
+ workspace 必须通过 `node scripts/verify-renderer-workspace.mjs episodes/<slug> <renderer>`;它绑定当前 handoff SHA 和全部生成文件 SHA。handoff 变化后旧 workspace 与 candidate 必须拒绝,不能继续渲染。
- ### Face-wrapper 模式选择(固定优先级)
+ 完成检查后用 `node scripts/render-episode-remotion.mjs episodes/<slug>` 或 `node scripts/render-episode-hyperframes.mjs episodes/<slug>` 写入各自 candidate;渲染后必须继续走本期 QA 与审片 gate。
- | 模式 | 参数 | 何时用 | 说明 |
- |------|------|--------|------|
- | **SIDE** | `x:480, y:0, scale:1` | 日常讲解场景(默认) | 左右分屏,960px 内容区 + 右侧全尺寸人脸 |
- | **INSET** | `x:1340, y:760, scale:0.27` | outro/CTA、多栏对比、需要全屏宽度的内容 | 小窗人脸,释放完整画面空间 |
- | **HERO** | `x:0, y:0, scale:1` | 无场景 overlay 时、冲击/强调时刻 | 全屏人脸 |
+ 每个 candidate 先由独立审阅写入 `11-动画/qa-reviews/<renderer>.json`(绑定 candidate SHA、审阅者、时间、字幕安全区和有声审片结论及说明),再运行 `node scripts/create-qa-evidence.mjs episodes/<slug> <renderer> --review-file 11-动画/qa-reviews/<renderer>.json`,最后运行 `node scripts/create-render-manifest.mjs episodes/<slug>`。它生成真实 contact sheet、每个 selected beat 的入场/中段/退场帧、完整解码和结构化 `qa-evidence.json`。不能靠命令行或 Markdown 写 PASS 放行。
- **禁止**:中途直接 fade out face(用 INSET 替代,保留人格存在感)。结尾最后 0.6s 可以 fade out(may-shorts-6 在 CTA 锁定后 fade face 让锁屏画面独占结尾)。
+ - CROSS_RENDER_VALIDATION_PAIR:Remotion 和 HyperFrames 各建独立 candidate 项目,使用同一 source hash、EDL、字幕和事实文字。
+ - PRIMARY_RENDERER:primary_renderer 必须是 remotion 或 hyperframes,且已有接受记录;否则停止并要求回到 CROSS_RENDER_VALIDATION_PAIR。专项 beat 只有在 EDL 明确指定后才交给另一 renderer。
+ - 两个 candidate 不共享组件、HTML、CSS、GSAP、布局常量、转场或旧项目 scene。
- **使用逻辑**:
- - SIDE → INSET 转换用于 outro(人脸缩小但一直在)
- - INSET 场景的 bg 必须用全宽(1920px 或 `inset: 0`),因为人脸只占右下角
- - 多栏/多内容需要全屏宽度时选 INSET,不是 SIDE
+ ### 2. 实现 base video
- ### 场景视觉规则
+ - 每个 ILLUSTRATIVE beat 只实现 EDL 指定的理解问题。
+ - HERO/NONE beat 保持真人,不新增主动画。
+ - PROOF beat 只能使用 source-manifest 记录的来源。
+ - BROLL_STOCK beat 只能使用 visually_verified 素材。
+ - Remotion 使用 frame-driven composition;HyperFrames 使用 deterministic paused timeline。
+ - BROLL/PROOF 只使用 handoff 锁定的本期真实资产;ILLUSTRATIVE 只显示 EDL 的 `visual.on_screen_text`,禁止显示 `acceptance_question`。
- 📖 **详细规则见 `rules/hyperframes.md`** overlay 美学规范章节。核心要点:
+ ### 3. 统一字幕与合成
- - bg 深色渐变(非纯黑 `#000`),vignette opacity 0.15-0.3,不需要 grain overlay
- - SIDE 场景 bg 960px + mask-image feather(60-100px 右边缘),INSET 场景全宽(1920px 或 inset:0)
- - 所有彩色文字加匹配色 text-shadow glow(如 `0 0 30px rgba(accent,0.5)`)
- - overlay 不写退场/resolve 动画(outro 除外)— face-wrapper 缩回 scale 1.0 自然掩盖
- - outro 可以有退场 fade(0.8-1.2s)
+ - workspace 以⑧的校对字幕作为唯一字幕文本,并在 candidate 中统一合成。
+ - Remotion 使用 component motion diagram;HyperFrames 使用 timeline full-bleed scene,两者不得共享固定卡片布局。
+ - 不把口播稿精简版、场景标题或旧项目字幕混入字幕轨。
- ### 字幕系统规则
+ ### 4. QA 与交付
- 📖 **详细规则见 `rules/hyperframes.md`** Captions 章节。核心要点:
+ 在 11-动画/ 写 candidates、contact sheets、render-manifest.json、qa-report.md。CROSS_RENDER_VALIDATION_PAIR 只写两个 candidate;viewer_verdict 为 ACCEPTED 且 selected_candidate 明确后,才把选中 candidate 写为 07-剪辑/final.mp4。PRIMARY_RENDERER 也遵守同一 final 条件。
- - 首选 word-level 逐词字幕(独立 captions.html sub-composition),降级用整句字幕
- - 字幕文本用 Whisper 转录原文 + 手动修正(不是口播稿精简版)
- - 逐词三态颜色:未读(dim) → 当前(accent) → 已读(white) + scale 1.06 微弹跳 back.out(3)
- - 8 方向 text-shadow 描边(非毛玻璃底板)
- - 特殊关键词可标 accent 色切换(如"warn"切橙色)
+ QA 必须记录:画布、fps、时长、音视频 stream、完整解码、source hash、EDL 版本、字幕安全区、每个 selected beat 的 hero frame 与边界帧、有声审片结论。
- ### 场景密度策略
+ ## 执行模式
- | 原则 | 说明 |
- |------|------|
- | B-Roll 占比符合内容密度目标 | 总 overlay 时长 / 总视频时长;AI/教程密集型通常 30-45%,策略评论 25-35%,个人叙事 15-25%,UI 证据型可到 40-55% |
- | 每 10-15s 至少一个场景 | 避免长时间无动画 |
- | 场景时长跟口播段落匹配 | 不能太短(看不完)也不能太长(想关掉) |
- | 长口播段落拆分多个场景 | 不在一个场景里塞 15s+ 内容 |
+ - REVIEW_GATED:静态构图和最终 MP4 等 Jeffrey 结论。
+ - AUTONOMOUS_RUN:在锁定 EDL 内自主渲染并最多三轮自检;发布始终等 Jeffrey。
- ---
+ 技术 PASS 不等于 viewer PASS,不得因渲染成功把 candidate 写成 accepted 方法。
- ## 项目目录
+ 🔴 CHECKPOINT:只有 viewer_verdict=ACCEPTED 且 selected_candidate 是 technical_qa=PASS 的候选,才创建 final.mp4。
- ```
- video-projects/<project-slug>/
- DESIGN.md ← 视觉设计(含 motion token)
- index.html ← 主编排(video + audio + scenes)
- compositions/ ← 场景 HTML
- assets/ ← 视频/音频/转录
- renders/ ← 渲染产物(gitignore)
- ```
+ Jeffrey 明确选片后运行 `node scripts/accept-render-candidate.mjs episodes/<slug> candidates/<renderer>.mp4 --viewer-accepted`;脚本绑定 manifest、candidate、QA evidence,并创建同字节 final 与 review-record。
- ## 知识参考
+ 双 renderer 比较成立后运行 `node scripts/record-renderer-validation.mjs episodes/<slug> <renderer> --viewer-accepted "<选择理由>"`。它绑定两份 candidate/QA/review 并生成结构化 comparison;只有该记录通过后,下期才允许切 PRIMARY_RENDERER。
- **本 skill 自带:**
- - `references/broll-architecture.md` — sub-composition 结构、CSS scope、常见错误
- - `references/broll-design-reference.md` — face-wrapper 4 种架构、8 种视觉风格、face 美化、边缘 feather
- - `references/broll-techniques.md` — 24 种常用动画技法 + 3 大基础设施系统(ambient-bg/captions/face-wrapper)
+ ## 失败处理
- **项目级(自动加载):**
- - `docs/AI_TALKING_HEAD_OVERLAY_SYSTEM.md` — student-kit 内 AI/tech 口播增强权威流程
- - `CLAUDE.md` — **Render Contract(11 条硬规则)+ workspace layout + 全部 CLI 命令**。构建前必读
- - `rules/hyperframes.md` — B-roll overlay 完整规则 + 渲染器踩坑 + 性能优化
- - `MOTION_PHILOSOPHY.md` — 官方美学体系(10 Laws + pre-flight checklist)
- - `DESIGN.ais-example.md` — 完整 DESIGN.md 结构模板
- - `video-projects/may-shorts-6/` — 官方 overlay 参考项目
- - `AI_SCENE_INDEX.md` / `style-profile.json` — student-kit 项目内 AI/tech 场景模式库(按语义触发、素材需求、face mode 速查)
+ | 情况 | 动作 |
+ |---|---|
+ | renderer 无法读 source | 生成兼容 production source,记录新 hash,并让两边使用同一字节文件 |
+ | 画面遮挡字幕 | 修 overlay 或字幕安全区后重渲染,不能删字幕掩盖 |
+ | 视觉像旧模板或两个 renderer 太像 | 回读 renderer-brief;保留同一语义,分别重做视觉语言 |
+ | EDL 缺 source 或事实来源 | 返回⑨,不由本 skill 猜补 |
+ | QA 不通过 | 最多三轮针对性修复;仍失败则保留 candidate 并报告失败证据 |
- **委托 skill:**
- - `/hyperframes` — Composition 编写规则,写 HTML 前调用
- - `/hyperframes-cli` — init / lint / inspect / preview / render / doctor
- - `/hyperframes-media` — 转录 / TTS / 背景移除
- - `/hyperframes-registry` — 安装 catalog blocks(`npx hyperframes add <name>`)
- - `/gsap` — GSAP 动画参考
+ ## 禁止事项
- **官方源码仓库(本地权威文档):**
- - `/Users/hanzhmacbookair/Documents/hyperframes/hyperframes-repo/docs/` — 超越 skill 文件的官方文档
- - `guides/rendering.mdx` — workers/GPU/Docker/质量设置
- - `guides/gsap-animation.mdx` — GSAP 官方规则
- - `guides/performance.mdx` — 性能优化
- - `guides/common-mistakes.mdx` — 7 个常见错误
- - `concepts/determinism.mdx` — 确定性渲染原理
- - `concepts/data-attributes.mdx` — data 属性完整参考
- - `reference/html-schema.mdx` — HTML Schema 权威定义
+ - 不按固定 coverage、每 N 秒场景、固定 face-wrapper、固定卡片或固定文字生成;
+ - 不把 clean.mp4 复制命名为 final.mp4;
+ - 不为展示素材而插无关 B-roll;
+ - 不使用旧 v10 的 index.html、示例、视觉常量或人工 gate 规则;
+ - 不自动发布。