HyperFrames Talking Head Recut:为访谈与播客素材批量生成与转录同步的图形覆盖卡片
【免费下载链接】hyperframesWrite HTML. Render video. Built for agents.项目地址: https://gitcode.com/GitHub_Trending/hy/hyperframes
导读:Talking Head Recut 是 HyperFrames 中面向“已有讲话类视频素材”的图形包装工作流——原始素材完整播放、不被裁剪,Agent 依据本地 Whisper 转录逐句设计定时出现的图形卡片(动效标题、lower-thirds、数据标注、引用、侧边栏、画中画),并把每张卡片写成独立 HTML 片段后组装成单个合成页面,最终由hyperframes渲染为 MP4。读完本文,你将掌握从ffprobe提取元数据、本地转录、故事板节奏算法、渲染策略决策、卡片 HTML 契约到 GSAP 主时间线组装与渲染的完整链路。
一、路由契约:这个工作流解决什么问题
Talking Head Recut 的入口契约记录在 skills/hyperframes/references/routes/talking-head-recut.md:
- 输入(Input):一段已有的 talking-head、采访或播客素材,用于“包装”。底层视频片段保持原样播放。
- 输出(Output):同一段素材叠加与转录同步的图形覆盖卡片——动效标题、lower-thirds、数据标注、pull-quotes、侧面板或画中画。任意时长。
- 触发器(Triggers):用户说“package this video”“add graphic overlays to my talk”“add lower-thirds or data callouts to this interview”等话术时路由到本工作流。
在 HyperFrames 的路由表中,本工作流排在“纯字幕”之后、“音乐驱动视频”之前:embedded-captions负责把口语做成可读字幕,而talking-head-recut负责在播放中的视频上叠加设计的图形。如果用户想要的是纯字幕、独立图形或从零创作视频,应走其他路由(skills/hyperframes/SKILL.md §2 路由表)。
访谈(Interview)形态决定了意图层的提问方式(详见 skills/hyperframes/references/intent-interview.md 的八步流程):
- Must-haves(必须现在问):只有一个——哪一段素材(输入文件)。
- Deferred(需提前告知):渲染策略问题——宽高比、布局、风格组、卡片数量——推迟到工作流第 7 步,届时建议将来自探测后的素材与转录文本。访谈时只需告知用户这些提问稍后会出现。
- Run-shape(运行形态):均不适用(该路由跳过故事板/自动化两个运行形态问题)。
BRIEF.md若存在,则承载已确认的输入与用户备注,应先读取。意图层只确认输入并宣布延迟提问,其余交给工作流执行。
二、工作流总览与目录约定
核心实现位于 skills/talking-head-recut/SKILL.md,共 11 步:检查环境 → 创建工作目录 → 提取音频与元数据 → 转录 → 修正转录 → 起草故事板 → 决定渲染策略 → 编写每张卡片 HTML → 组装合成 HTML → 渲染 MP4 → 汇报结果。
所有中间产物遵循与其他视频工作流一致的videos/<project-name>/约定,可检查的中间文件包括:
| 文件 | 内容 |
|---|---|
metadata.json | 时长 / 宽 / 高 / fps |
audio.mp3 | 提取出的音频 |
transcript.json | 扁平词级数组[{ text, start, end }, …](Whisper 输出,无segments也无words包裹层) |
storyboard.json | 轻量卡片大纲(Agent 的规划产物) |
public/cards/card-XX.html | 每张卡片一个 HTML 片段 |
public/index.html | 最终组装的合成页面 |
output.mp4 | 渲染产物 |
三、环境检查与工作目录
先运行环境自检,确认 ffmpeg、无头浏览器与渲染依赖齐备,并确认技能内置字体与 GSAP 存在:
npx hyperframes doctor # ffmpeg, headless browser, render deps ls "skills/talking-head-recut/assets/fonts" "skills/talking-head-recut/assets/vendor/gsap.min.js"必需依赖:系统ffmpeg/ffprobe;技能内置的assets/fonts/*.woff2与assets/vendor/gsap.min.js(第 9 步会 stage 到工作目录)。转录无需任何 API key——hyperframes transcribe在本地运行 Whisper。macOS 上渲染强烈建议开启硬件 GPU:
export PRODUCER_BROWSER_GPU_MODE=hardware创建工作目录(cwd 保持在仓库根,所有输出写入单一子目录):
VIDEO_PATH="/absolute/path/input.mp4" WORK_DIR="videos/$(basename "$VIDEO_PATH" | sed 's/\.[^.]*$//')" mkdir -p "$WORK_DIR"四、提取元数据与音频,然后本地转录
# metadata — duration / width / height / fps ffprobe -v error -select_streams v:0 \ -show_entries stream=width,height,r_frame_rate \ -show_entries format=duration -of json "$VIDEO_PATH" > "$WORK_DIR/metadata.json" # audio ffmpeg -y -i "$VIDEO_PATH" -vn -acodec libmp3lame -q:a 2 "$WORK_DIR/audio.mp3"注意 fps 需要把r_frame_rate分数求值,例如30000/1001 → 29.97。随后本地转录:
npx hyperframes transcribe "$WORK_DIR/audio.mp3" -d "$WORK_DIR" --json --model small.en从 packages/cli/src/commands/transcribe.ts 的命令定义可以看到,transcribe子命令支持--engine(auto/parakeet/whisper)、--model(tiny.en到large-v3)、--language过滤、--json输出、--to srt|vtt旁白导出与--preserve-cues等参数;它还能直接导入已有 SRT 或 OpenAI Whisper JSON 响应。转录产物是词级transcript.json——没有segments数组,需要分组到句子时按标点/停顿自行切分。
钳制到媒体时长:Whisper 可能把最后一个词的end略微超出素材实际长度。必须把所有卡片的endSec以及composition.durationSeconds钳制到metadata.json的时长,否则渲染会出现视频结束后的黑尾。
五、修正转录文本
transcript.json是扁平词对象数组(键名为text)。逐词修正明显的 ASR 错误:同音词、产品名、技术术语、标点。编辑某个词的text时保留其start/end时间戳。
六、起草轻量故事板(纯聊天,无 CLI)
没有 CLI 消费storyboard.json——它是 Agent 内部的规划产物,用于在写每张卡片的 HTML 之前把时间与内容想清楚。保持 v3 结构,使同一份大纲能驱动第 9 步的合成:
{ "schemaVersion": 3, "composition": { "fps": 30, "width": 1080, "height": 1920, "durationSeconds": 121.2, "layout": "portrait", "themeId": "noir", "seed": 42 }, "videoTrack": { "sourcePath": "input-video.mp4", "startSec": 0, "endSec": 121.2, "bounds": { "x": 0, "y": 0, "width": 1080, "height": 1920 } }, "subtitles": { "enabled": false }, "cards": [ { "id": "card-01", "intent": "Hook with the speaker's anxious midnight question", "startSec": 0.5, "endSec": 13.0, "accentIndex": 0, "zone": "fullscreen", "contentHints": { "kicker": "AN HONEST QUESTION", "title": "The soul-searching question at 11 PM", "detail": "Client's 60-second voice message: 'If the RMB appreciates, does that mean my USD policy is a terrible loss?'" } } ] }卡片必填字段:
| 字段 | 类型 | 用途 |
|---|---|---|
id | string | 卡片 HTML 与 GSAP 选择器中的稳定 id |
intent | string | 自然语言描述,供卡片合成参考 |
startSec/endSec | number | 秒级时间(endSec > startSec) |
accentIndex | 0\|1\|2\|3\|4 | 该卡片使用 5 个主题强调色中的哪一个 |
zone | enum(见下) | 卡片在画布上的位置 |
contentHints | object | 自由格式;kicker/title/detail/data/quote 放这里 |
archetype(可选) | string | 记录卡片模式的自由标签;缺省 = 自由形式 |
transition(可选) | cut\|fade\|slide\|wipe | 声明式卡间转场 |
五个zone值:
| zone | 解析后的边界 | 适用场景 |
|---|---|---|
fullscreen | 覆盖整个画布 | 高光时刻、大数字、口号 |
whiteboard-area | 内缩 40px(或竖屏高度的 45%) | 密集数据 / 注释内容 |
lower-third | 底部 30% 条带 | 在可见视频上做标注 |
side-panel | 横屏右侧 42% / 竖屏底部 40% | 数据一侧、视频另一侧 |
video-overlay | 全画布,期望卡片基本透明 | 全幅视频上的注释覆盖 |
注意:schema没有card.layout字段,视频边界只在合成层设置一次(videoTrack.bounds);要让视频看起来在卡片间“移动”,是在合成<script>里用 GSAP 对#video-wrap做 tween(见第九节)。
卡片节奏:先按时长定基础节奏,再按信息密度修正
没有固定卡片数量上限,但有下限:至少 5 张,保证短视频也有节奏。
第 1 步——按视频时长取基础节奏(中等密度的自然秒/卡):
| 视频时长 | 基础节奏(每卡秒数) | 理由 |
|---|---|---|
| < 60s(短 Reel) | 6–8s | 短视频观众期待快速切镜 |
| 60s – 3 min | 8–12s | 常规社交节奏 |
| 3 – 10 min | 12–20s | 留呼吸感,每卡承载更多 |
| 10 – 30 min | 20–35s | 长讲座 / 访谈节奏 |
| > 30 min | 30–60s | 章节感、近似剧集 |
第 2 步——密度乘数:高密度(大量数字、独立论点、列举式、每 1–2 句一个新想法)× 0.7(切得更快、卡片更多);中密度(数据与叙事混合)× 1.0;低密度(单一长故事、反复重述、缓慢反思)× 1.5(切得更慢、卡片更少)。
第 3 步——计算:
secPerCard = basePace × densityMultiplier cardCount = max(5, round(videoDurationSec / secPerCard))示例:121s 高密度讲话视频 → 10 × 0.7 = 7s/卡 →17 张;1 小时低密度播客 → 45 × 1.5 = 67.5s/卡 →53 张。无上限钳制——长视频自然产生更多卡片。
当单卡超过约 15s,应规划更丰富的卡片(数据块、多步揭示、错落动画的子要点);超过 30s 的长篇可考虑把时间线切成子合成(每章节一个 .html,用data-composition-src挂载),以规避timeline_track_too_dense的 lint 警告。技能不附带固定品牌 outro;如需结尾卡,自行设计一个中性结尾(字标 + 一句话,约 1.5–2s,淡入→短暂停留→淡出),追加进cards[]并同步延长composition.durationSeconds。
七、决定渲染策略:先与用户确认视觉方向
在设计卡片或决定边界之前,先请用户选择输出比例、布局、风格与卡片密度预设。提问前预计算两件事:
recommendedRatio(依据metadata.json的宽高比):sourceAspect = width / height;≥ 1.5(约 3:2 以上宽幅)→ 推荐16:9;≤ 0.7(约 9:13 以上竖幅)→ 推荐9:16;介于之间(近方形)→ 推荐4:5。推荐项标签标注“(recommended · matches source video X:Y)”。autoCount:max(5, round(videoSec / (basePace × densityMultiplier)))。
提问通道与环境兼容
按可用性依次选择:原生结构化提问工具(一次 4 问)→ 其他原生澄清工具 → 无原生工具(Codex CLI 等纯文本运行时)时直接在对话中发一条消息、4 个编号问题。每轮最多 2–5 问;即使用户信息缺失不阻塞渲染,只要参数实质影响最终输出(比例/布局/风格/卡片数)就问一次。若用户已批准默认值、明确不用问、或运行带自主信号(“surprise me”“decide for me”),则跳过提问,直接采用:recommendedRatio+layout="stack"(最稳妥的跨比例默认)+ 依据转录语气在 editorial/data 最中性组里选风格 +autoCount,并用一句话告知用户你的选择。
四个问题的选项(原生AskUserQuestion或纯文本模板):
- 输出宽高比:A. 16:9 横屏(1920×1080,TV/YouTube/桌面);B. 9:16 竖屏(1080×1920,TikTok/Reels);C. 4:5(1080×1350,Instagram 信息流 / 朋友圈,近方形源最佳)。
- 整体布局:A. split 左右分屏(各半画布);B. stack 上下堆叠(视频在上约 52%、卡片在下);C. pip 画中画(卡片铺满画布、视频缩为圆角角窗);D. overlay 全屏玻璃覆盖(视频全幅、卡片浮层)。
- 卡片风格组(与帧自动挑选矩阵的行严格对应):A. warm-paper(academic / editorial / whiteboard / xhs);B. clinical(audit / swiss / terminal / minimal);C. experimental(geom / spotlight)。
- 卡片数量:A. Auto(推荐,约 N 张);B. Fewer(约
round(N × 0.6)张);C. More(约round(N × 1.5)张);D. 直接给具体数字。回答格式如"1A 2C 3B 4A"或自然语言均可;回复default/auto表示全部采用推荐值。
答案的落地规则
输出画布按比例解析为精确的composition.width × height:16:9 →1920×1080(layout: "landscape");9:16 →1080×1920("portrait");4:5 →1080×1350(schema 把 4:5 视为 portrait,因高 > 宽)。references/layouts/*.html只记录了横竖两种比例,4:5 的边界需从竖屏等比缩放:水平值不变,垂直值乘以1350/1920 ≈ 0.703。
风格组 → 具体风格:在用户所选组内依据转录语气挑最贴合者;不确定时可用第二次提问在组内 2–4 个具体风格中二选一。
卡片数最终解析:Auto →autoCount;Fewer →max(5, round(autoCount × 0.6));More →round(autoCount × 1.5)(无上限);Other 为整数 →max(5, parseInt(n));Other 无法解析 → 回退autoCount。
自动挑选视频帧(帧不提问,由布局 × 风格决定):
| 布局 | warm-paper 风格 | clinical 风格 | experimental 风格 |
|---|---|---|---|
split | polaroid | hairline | clean |
stack | polaroid | hairline | clean |
pip | clean(pip 胶囊自带边框) | clean | clean |
overlay | clean(全幅禁装饰帧) | clean | clean |
随后用一句话告知用户你选定的比例(+画布尺寸)、布局、具体风格、帧与最终卡片数,并把五个值记入工作记忆。
渲染策略输入
- 源视频在 GSAP 目标内的适配:
<video>元素使用object-fit: cover并被裁剪到#video-wrap的 tween 边界。若不想裁剪(如竖屏源放到横屏画布),让 tween 指向与源同宽高比的矩形,让周围画布透出(或用卡片/背景填充)。 card.zone按卡设置:从合成布局推导(split → side-panel,stack → lower-third,pip → fullscreen,overlay → video-overlay),也可为一卡一例使用其他 zone(fullscreen 用于 hero/引用,whiteboard-area 用于密集数据)。accentIndex按卡设置:每卡取 5 个主题强调色之一;跨卡变化制造节奏,同一叙事节拍内复用同一下标。- 动效词汇:从
data-anim种类中选 2–3 个可重复模式并坚持使用,保证合成观感一致。
主题调色板(作为--accent-N/--bg/--textCSS 变量用在合成<style>中):
| themeId | 强调色(5 色) | 画板背景 | 文字 |
|---|---|---|---|
| classic | #1971c2 #e03131 #2f9e44 #e8590c #9c36b5 | #FFF9E3 | #1e1e1e |
| noir | #4cc9f0 #f72585 #4ade80 #fb923c #a78bfa | #1a1a1a | #f1f1f1 |
| mint | #0077b6 #d62828 #2d6a4f #e76f51 #7209b7 | #e8faf0 | #1b4332 |
| craft | #bf5700 #d62728 #6c757d #e9b54a #3d5a80 | #f6efe1 | #2d2d2d |
| slate | #0ea5e9 #ef4444 #22c55e #f97316 #a855f7 | #1e293b | #f1f5f9 |
| mono | #000 #555 #888 #aaa #ccc | #fff | #000 |
内置字体(assets/fonts/下的 woff2,第 9 步 stage 到工作目录):Caveat(手写体)、LXGW WenKai TC(中文手写)、Inter(现代无衬线)、Virgil(几何手写)。
视觉设计库:Style × Layout × VideoFrame
skills/talking-head-recut/references/DESIGN_INDEX.md 把视觉拆成三个正交维度,可自由混搭:
| 维度 | 键 | 决定什么 |
|---|---|---|
| style | academiceditorialminimalspotlightgeomwhiteboardauditterminalswissxhs | 卡片视觉语言——字体、配色、装饰、卡内布局 |
| layout | splitstackpipoverlay | 源视频与卡片如何共享画布 |
| frame | cleanhairlinepolaroid | 视频元素周围的装饰性边框 |
10 个样式各有鲜明性格:academic(暖纸·网格·衬线·蓝高亮)、editorial(奶油底·珊瑚块·大斜体引用)、minimal(纯黑白·大字号·留白)、spotlight(暗紫渐变·发光·戏剧感)、geom(黄绿+亮粉+黑碰撞)、whiteboard(纸张·Caveat 手写·涂鸦边框)、audit(牛皮纸·两端对齐衬线·APPROVED 印章)、terminal(深色·等宽·ASCII 边框·提示符光标)、swiss(白底·Helvetica·双细线·红强调)、xhs(奶油+亮粉·chip·#话题·❤️💬 行)。选择依据是内容语气而非内容类型。
决定使用某个维度时,读取对应文件:layouts/(横竖两种比例的精确videoBounds+cardBounds与可复制的 storyboard JSON)、styles/(自带 CSS token 与占位要点的自包含卡片片段)、frames/(#video-wrap兄弟元素的装饰 HTML 与放置说明)。style × layout × frame按卡自由切换,只要转场顺滑即可——常见节奏是editorial × overlay × clean开场,数据卡切audit × split × hairline,whiteboard × pip × polaroid收尾。
四种合成布局的坐标配方
布局是两部分配方:在storyboard.json写card.zone+ 在合成<script>中为#video-wrap编写 GSAP tween:
| 合成布局 | 推荐card.zone | #video-wrapGSAP 目标(横屏 1920×1080) | #video-wrapGSAP 目标(竖屏 1080×1920) | 适用场景 |
|---|---|---|---|---|
split | side-panel | { left: 960, top: 0, width: 960, height: 1080 } | { left: 0, top: 960, width: 1080, height: 960 }(下半) | 讲话人 + 数据左右对半 |
stack | lower-third | { left: 14, top: 14, width: 1892, height: 548 }(顶部 52%) | { left: 0, top: 0, width: 1080, height: 844 }(顶部 44%) | 讲话人在上 + 摘要卡在下 |
pip | fullscreen | { left: 1480, top: 760, width: 400, height: 300 }+.framed类 | { left: 690, top: 28, width: 360, height: 203 }+.framed | 内容密集型卡片 + 角落画中画 |
overlay | video-overlay | { left: 0, top: 0, width: 1920, height: 1080 }(全幅) | { left: 0, top: 0, width: 1080, height: 1920 } | 电影感 / 玻璃卡盖全幅视频 |
4:5(1080×1350)时把竖屏的 y/h 值乘以0.703。layouts/split.html 的头部注释展示了这套配方的标准写法(横屏视频右半、竖屏视频下半、4:5 按比例推导),并建议用深色页面背景让 14–18px 的分隔间隙呈现为干净的隔条。
与视频共享画布的卡片必须透明底:overlay、pip 配方以及任何card.zone = 'lower-third' | 'video-overlay'的时刻,卡片的.root绝不能绘制不透明背景,否则会遮挡视频。两种模式:A)透明根 + 页面 body 提供奶油色背景;B)仅对全屏卡显式设置背景,overlay 卡保持透明。side-panelzone(split 配方)的卡片宿主只占半幅画布,不透明背景是安全的。
八、编写每张卡片的 HTML
为每张卡创建$WORK_DIR/public/cards/{card-id}.html,每个文件是满足以下契约的单一根 HTML 片段:
<div class="card">SKILL_DIR="skills/talking-head-recut" mkdir -p "$WORK_DIR/public/fonts" "$WORK_DIR/public/vendor" "$WORK_DIR/public/cards" cp -n "$SKILL_DIR/assets/fonts/"* "$WORK_DIR/public/fonts/" cp -n "$SKILL_DIR/assets/vendor/gsap.min.js" "$WORK_DIR/public/vendor/" # RE-ENCODE with dense keyframes (-g / -keyint_min = composition fps, e.g. 30) ffmpeg -y -i "$VIDEO_PATH" -c:v libx264 -crf 18 -g 30 -keyint_min 30 \ -pix_fmt yuv420p -movflags +faststart -c:a aac "$WORK_DIR/public/input-video.mp4"合成模板(skills/talking-head-recut/SKILL.md 第 9 步的完整版本)的骨架:<head>里先为 4 款内置字体写@font-face(font-display: block),再在:root定义--bg/--text/--accent-0..4/--font-family;#stage通过data-composition-id/data-start/data-duration/data-fps/data-width/data-height声明合成参数;#video-wrap内的<video>保持muted,同时挂一个#source-audio音频轨复用同一源文件(data-track-index="10"、data-volume="1"),这样渲染出的 MP4 自带原始人声而无需手动 remux,且音量/闪避可在时间线上独立控制。
每个card-host必须同时带card-host与clip两个类,并用data-start/data-duration/data-track-index声明其时间窗与层级,style内联写resolveZoneBounds(card.zone)得到的像素边界。主时间线脚本的要点:注册一个paused: true的 GSAP timeline,每卡一组进入(tl.set可见性 +fromTo不透明度)+ 卡内动效编译(如kinetic-chars编译为对.char的tl.from(..., { stagger: 0.04 }))+ 退出;卡间若布局变化,在下一卡进入前对#video-wrap补一段tl.to(..., { left/top/width/height, duration: 0.6, ease: 'power2.inOut' })(并可用tl.set("#video-wrap", { className: "video-wrapper framed" })切换装饰类);最后注册window.__timelines["talking-head-recut"] = tl。
两个易踩的坑(lint 会警告):body / 全局font-family必须列出具体字体名(如'Inter', 'Caveat', ...),不能用var(--font-family)——HyperFrames 的字体解析器在静态分析时不展开 CSS 变量(lint:font_family_without_font_face);卡片内仍可使用变量。时间轴必须同步构建,禁止async/setTimeout/ Promise / 媒体play(),渲染路径禁用Math.random()与Date.now(),禁用repeat: -1(用有限重复)。
GSAP 语句速查表(时间 =card.startSec +>cd "$WORK_DIR" PRODUCER_BROWSER_GPU_MODE=hardware npx hyperframes render public \ --skill=talking-head-recut \ -o output.mp4 \ --fps 30
hyperframes render <dir>读取<dir>/index.html产出 MP4。PRODUCER_BROWSER_GPU_MODE=hardware(或--browser-gpu)在 macOS 上强烈推荐——纯软件 Chrome 渲染在多数笔记本上会超时。全量渲染前可用单帧快照做 sanity check:
npx hyperframes snapshot public --at 5 # → public/snapshots/frame-00-at-5s.png汇报时向用户交代:工作目录路径、storyboard.json(你设计的卡片大纲)、public/cards/*.html(每卡一个 HTML)、public/index.html(组装后的合成)、output.mp4(成片)、ASR 提供方、卡片数量及选择理由(一句话)、缺失的素材或质量注意点。若用户要求实时预览(仅在请求时,运行中不要打开),在渲染完成后启动长驻服务并给出 URL:
(cd "$WORK_DIR/public" && npx hyperframes preview --background) # 或 npx hyperframes play 获取可分享链接合成页面本身忠实呈现“原素材 + 覆盖层”,因为视频在index.html内原样播放。未获用户许可不要删除工作目录。
小结
Talking Head Recut 的价值在于把“给讲话类视频做图形包装”变成一条可审计、可复现、全部本地运行的流水线:输入一段已有素材,输出一张与逐词转录严格同步的图形卡片时间线,最终落成一个 HTML 合成与一段 MP4。它的关键工程决策包括:transcript.json的词级时间戳直接驱动卡片 timing;storyboard.json作为纯规划产物分离“设计与实现”;卡片 HTML 以data-anim-*声明动画、由单一 GSAP 主时间线统一编译;视频边界只在合成层设置一次,卡间“移动”完全由#video-wrap的 tween 完成;以及无<script>、无外部 URL、作用域样式等保证可渲染性与确定性的硬性契约。无论输出 16:9 横屏、9:16 竖屏还是 4:5 社交比例,这条链路都能让访谈、播客与演讲素材在几分钟内变成节奏清晰、信息密度可调的包装成片。
【免费下载链接】hyperframesWrite HTML. Render video. Built for agents.项目地址: https://gitcode.com/GitHub_Trending/hy/hyperframes
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考