插件安装: 在执行设置或更新命令之前,当此技能位于HyperFrames插件内时,请遵循插件执行规则。独立安装则保留下方的更新说明。
首先,确保此技能是最新的——运行前请与用户确认:
npx hyperframes skills update talking-head-recut。如果一切已是最新,则快速无操作;否则,它会在您使用此技能及其依赖的核心领域技能之前,刷新它们。
说话人头像重新剪辑
说话人头像重新剪辑会获取一段完整播放的本地视频,并在其上叠加一系列定时、设计好的图形卡片——标题、下三分之一、数据标注、引用、侧面板、画中画——与视频的讲话内容同步。智能体会设计这些卡片(包括时间和内容),直接在对话中编写每个卡片的HTML,然后组装成一个合成HTML,并通过hyperframes将其渲染为MP4。没有固定的原型列表,也没有预设的卡片结构——叠加的图形完全由转录稿的实际内容决定。
入口是
/hyperframes。 此技能用于为现有的说话人头部剪辑打包设计好的图形卡片(标题、下三分之一、数据标注、引用、侧面板、画中画)——而不是纯字幕(将口头话语显示为文本)。原始视频不受影响地播放。 任何其他意图——纯字幕、独立图形、从头创建视频——或任何不确定性 → 请先阅读/hyperframes:意图层负责所有路由决策。
embedded-captions的图形包装姊妹技能。 字幕功能添加_口头话语_作为可读文本;本技能则在播放的视频上添加_设计好的图形_。纯字幕 →embedded-captions。从头构建视频 → 创建工作流 (product-launch-video/faceless-explainer/ ...)。
通过 /hyperframes 路由,意图层仅确认输入(哪个剪辑)并通知渲染策略问题为延迟提问——画幅比例、布局、样式组和卡片数量保留到第7步,在那里探测到的素材和转录稿将为推荐提供依据;该层的运行形状问题不适用。如果存在 BRIEF.md 文件,其中包含已确认的输入和用户的任何备注——请先读取它。
工作目录中可检查的中间文件:
metadata.json— 时长 / 宽度 / 高度 / 帧率audio.mp3— 提取的音频transcript.json— 一个扁平的单词数组[{ text, start, end }, …](Whisper 格式;没有segments,没有words包装器)storyboard.json— 轻量级卡片大纲(智能体的计划)public/cards/card-XX.html— 每个卡片一个HTML片段public/index.html— 最终组装的合成HTMLoutput.mp4— 渲染后的视频
CLI 解析
# hyperframes — 转录(本地Whisper)+ 将组装的HTML渲染为MP4
npx hyperframes --help
此技能完全运行在 hyperframes CLI 和系统 ffmpeg / ffprobe 之上。转录是本地的 Whisper 通过 hyperframes transcribe 实现——无需第三方服务、API密钥或速率限制代理。
工作流程
1. 检查环境
npx hyperframes doctor # ffmpeg, headless browser, render deps
# 确认捆绑的资产:
ls "<SKILL_DIR>/assets/fonts" "<SKILL_DIR>/assets/vendor/gsap.min.js"
必需条件:
ffmpeg/ffprobe(系统)<SKILL_DIR>/assets/fonts/*.woff2,<SKILL_DIR>/assets/vendor/gsap.min.js(捆绑在此技能内,第9步时会部署到工作目录)
转录无需密钥——hyperframes transcribe 在本地运行 Whisper(第4步)。
在 macOS 上强烈建议为 hyperframes render 设置以下环境变量:
export PRODUCER_BROWSER_GPU_MODE=hardware
2. 创建工作目录
所有工件都位于 videos/<project-name>/ 目录下——与其他视频工作流(product-launch-video / faceless-explainer / pr-to-video)的约定相同。保持当前工作目录在项目根目录;以下所有步骤都在此子目录下写入文件。
VIDEO_PATH="/absolute/path/input.mp4"
WORK_DIR="videos/$(basename "$VIDEO_PATH" | sed 's/\.[^.]*$//')"
mkdir -p "$WORK_DIR"
3. 提取音频和元数据
# 元数据 — 时长 / 宽度 / 高度 / 帧率
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"
# 音频
ffmpeg -y -i "$VIDEO_PATH" -vn -acodec libmp3lame -q:a 2 "$WORK_DIR/audio.mp3"
输出:metadata.json(读取 width/height/duration;fps 是 r_frame_rate 分数值,例如 30000/1001 → 29.97)+ audio.mp3。
4. 转录
npx hyperframes transcribe "$WORK_DIR/audio.mp3" -d "$WORK_DIR" --json --model small.en
本地 Whisper — 无需API密钥、无代理、无速率限制。将逐词级别的 transcript.json 写入工作目录(单词 text 及 start / end 时间戳)。读取它以获取第6步中驱动卡片定时的单词/句子时间信息;根据需要,在标点处或暂停处自行将单词分组为句子,以获得句子级别的块。
限制到媒体时长。 Whisper 可能返回最后一个单词的 end 时间略微超过实际剪辑长度——请将每个卡片的 endSec 和 composition.durationSeconds 限制为 metadata.json 中的时长,否则渲染将在视频结束后显示黑色尾部。
5. 修正转录稿
transcript.json 是一个扁平的单词对象数组——[{ "text": "...", "start": s, "end": s }, …](没有 segments 数组,没有 words 包装器;每个单词的键是 text)。读取它并修正明显的ASR错误:
- 同音字、产品名、技术术语、标点符号
- 原地编辑单词的
text;保留其start/end时间戳 - 没有预先分组的
segments数组——自行将单词分组为句子(在终端标点处或暂停处分隔),当您需要句子级别的块进行卡片定时时
6. 草拟轻量级故事板(在聊天中)
不涉及 CLI。 读取 transcript.json + metadata.json 并直接设计卡片。storyboard.json 是智能体内部的规划工件——没有 CLI 命令消费它;它的存在是为了让您在编写每个卡片的 HTML 之前,能清晰地思考时间和内容。保持下面示例的结构一致,以便相同的大纲可以驱动您在第9步中创作的合成HTML:
{
"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": "用演讲者午夜焦虑的问题吸引观众",
"startSec": 0.5,
"endSec": 13.0,
"accentIndex": 0,
"zone": "fullscreen",
"contentHints": {
"kicker": "一个诚实的问题",
"title": "深夜11点扪心自问的问题",
"detail": "客户60秒语音留言:‘如果人民币升值,是不是意味着我的美元保单大亏?’"
}
}
]
}
必需的卡片字段:
| 字段 | 类型 | 目的 |
|---|---|---|
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(可选) | enum: cut | fade | slide | wipe | 声明式的卡片到卡片过渡效果 |
五个 zone 值:
| zone | 解析后的边界 | 使用时机 |
|---|---|---|
fullscreen | 覆盖整个画布 | 英雄时刻、大数字、口号 |
whiteboard-area | 内边距40px(或竖屏高度的45%) | 密集数据/带注释的内容 |
lower-third | 底部30%的条带 | 在可见视频上进行标注 |
side-panel | 右侧42%(横屏)或底部40%(竖屏) | 数据在一侧,视频在另一侧 |
video-overlay | 全画布,期望卡片的大部分区域透明 | 在全出血视频上进行标注叠加 |
当您在第9步组装合成HTML时,根据上表将每个卡片的 zone 解析为卡片宿主包装器上的像素坐标。视频边界在合成级别(videoTrack.bounds)只设置一次;要让视频看起来在不同卡片之间“移动”,请在合成HTML的 <script> 中针对 #video-wrap 编写GSAP动画(参见第9步)。
没有预设的卡片角色,没有预设的叙事弧。 卡片完全来自视频实际所说的内容——可能全是引用或全是数据,可能以数字开头或以故事开头。让转录稿驱动节奏。
多少个要点?—— 根据时长和密度自动推断。 没有固定上限。根据视频时长选择一个基础节奏,然后根据信息密度进行调整。唯一的下限是固定的:最少5张卡片,这样即使短视频也有节奏感。
步骤 1 — 按时长确定基础节奏(中等密度下的自然秒数/卡片):
| 视频时长 | 基础节奏 (秒/卡) | 理由 |
|---|---|---|
| < 60s (短Reel) | 6–8秒 | 观众期望短格式下的快速切换 |
| 60秒 – 3分钟 | 8–12秒 | 正常的社交节奏 |
| 3 – 10分钟 | 12–20秒 | 给予呼吸空间;每张卡片承载更多内容 |
| 10 – 30分钟 | 20–35秒 | 长格式讲座/访谈的节奏 |
| > 30分钟 | 30–60秒 | 片段式的,接近章节的感觉 |
步骤 2 — 密度乘数(乘以基础节奏):
| 转录稿中的信号 | 乘数 | 效果 |
|---|---|---|
| 高密度 — 许多数字、明确的论断、快速的节奏、列表式的枚举、每1-2句话就是一个新想法 | × 0.7 | 切换更快,卡片更多 |
| 中等密度 — 数据与叙事混合的流程 | × 1.0 | 基础节奏 |
| 低密度 — 一个扩展的故事、重复的重构、缓慢的反思节奏、单一论点的展开 | × 1.5 | 切换更慢,卡片更少 |
步骤 3 — 计算:
secPerCard = basePace × densityMultiplier
cardCount = max(5, round(videoDurationSec / secPerCard))
示例(注意——没有上限;长视频自然会产生更多卡片):
- 30秒Reel,单一笑点(低密度) → 7 × 1.5 = 10.5秒/卡 → round(30/10.5)=3 → 下限为 5 张
- 60秒反思独白(低密度) → 10 × 1.5 = 15秒/卡 → 4 → 下限为 5 张
- 121秒说话人头像视频,丰富数据(高密度) → 10 × 0.7 = 7秒/卡 → 17 张
- 5分钟访谈,混合密度 → 16 × 1.0 = 16秒/卡 → 19 张
- 10分钟深度探讨,高密度 → 16 × 0.7 = 11秒/卡 → 55 张
- 30分钟讲座,中等密度 → 28 × 1.0 = 28秒/卡 → 64 张
- 1小时播客,低密度 → 45 × 1.5 = 67.5秒/卡 → 53 张
当一张卡片持续超过约15秒时,请计划一个更丰富的卡片(数据块、多步骤揭示、几个子点通过错开动画展开)——静态的一行文字在超过8秒后会变得无聊。对于长片段,如果许多卡片超过30秒,请考虑将时间线分块成子合成(每个章节一个.html,使用 data-composition-src 挂载),这样每个文件的GSAP时间线更易于管理——请参考 timeline_track_to_dense HyperFrames lint警告。
content 可以是一个纯字符串("标题:年化5.69%\n备注:...")或任何能够捕获数据的JSON形状。智能体决定每个卡片的形状。
可选结尾。 此技能没有固定的品牌结尾。如果用户想要一个结束卡片,请自行设计一个中性的卡片(标志字标+一句话标语,约1.5-2秒,淡入 -> 短暂停留 -> 淡出),将其追加到 cards[] 中,并延长 composition.durationSeconds...
[因翻译目的已截断]