口播知识卡片视频
把口播视频做成"卡片 + 人像 + 图片/视频素材"的成品。四条不变的要求:
- 卡片跟着真实语音逐句走,不能靠脚本里手写的时间区间。
- 所有设计细节由用户决定——人像以什么形式出现、小窗尺寸位置、卡片版式、背景、动效、素材位置、音轨取哪一段,都是选项。
- 多视频是时间轴上的先后片段,不是同时播放的多个视口。 同时出现必须显式声明。
- 先内容、再结构、最后细节。 顺序是:素材类型 → 脚本与对齐 → 规格 → 剪辑方案 → 每部分呈现什么 → 视觉细节。
流程 0–11 步,每步末尾是硬确认门。做完一步把结果摊给用户看,拿到确认才往下走;用户说"你定""随便"时按本步推荐值决定并写明这是推荐值。
内容必须结构化
整条链路的中间产物都是机器可读的,任何一步都能单独重跑、核对、重建:
| 步骤 | 产物 | 谁消费 |
|---|---|---|
| 0 | 依赖矩阵与建议路径 | check_env.py |
| 0 | 项目骨架(index.html、hyperframes.json、assets/、work/) |
后面每一步 |
| 2 | script.txt(## 段名 / 句子 \| 重点词 \| 译文,后两列可空) |
align_sentences.py |
| 2 | sentences.json(逐句 t0/t1/until/kw/sub/exactRate) |
plan_table.py、validate_spec.py、build_composition.py |
| 4–8 | spec.json(结构决策 + 设计决策,逐步填满) |
plan_table.py、validate_spec.py、build_composition.py |
| 9 | index.html + proof/index.html |
HyperFrames |
| 9 | work/expected-clips.json(登记每个定时元素) |
check_timeline.py |
| 9 | work/confirm/keyframes.jpg、layout.jpg |
用户确认 |
字段与取值范围以 assets/spec.schema.json 为准,
含义与填写方式见 references/spec.md,
完整样板见 assets/spec.example.json。
不要手写 composition HTML——改 spec.json 再 build,手改会被覆盖。
开始前
- 读
/hyperframes,按它的状态表进入流程;本技能承担它的意图层与执行编排。 - 读
/hyperframes-core(composition 契约)——写 HTML 前必须读。 - 第 4–8 步问完后把确认结果写进
BRIEF.md,按/general-video执行。
续做已有项目
先跑这一个,不要直接开问:
python3 scripts/project_state.py --project .
它按产物判断做到哪一步、哪一步没跟上,并给出下一步。产物的存在与新旧就是"已确认过什么"的记录:
| 情况 | 怎么做 |
|---|---|
spec.json 存在且校验通过 |
读回来,只问用户这次要改哪一步(改视觉就只重跑 6 → 9) |
spec.json 还有 error |
先按它列出的 error 修,别往下走 |
index.html 比 spec.json 旧 |
改完没重建:重跑 build_composition.py + check_timeline.py |
| 确认包比构建旧 | 重出 keyframe_proof.py,再让用户看 |
不要因为"上次不是我做的"就把第 1–5 步重开一遍。 已经确认过的决定写在 spec.json 里,
重问既浪费时间,也会把定稿的东西改坏。真要改结构,明确说"这会回到第 4 步"。
流程
0 · 环境自检与项目骨架(自动 + 必要时用户决定)
先探测再干活,不要假设依赖都在:
python3 scripts/check_env.py [--project <项目目录>] [--fix] [--net]
它探测 python3 / ffmpeg / node / hyperframes / general-video 工作流 / 本地 ASR 引擎 /
uvx+fonttools / 额度登录,给出依赖矩阵与建议路径(用哪个 ASR、字体怎么处理、能不能云端渲染)。
缺失项分两类:能自动补的用 --fix 执行(执行前把命令列给用户看);不能自动补的(没有本地 ASR)
立刻告诉用户,并给替代方案(请用户提供逐字稿或带时间戳字幕)。
后面的调用逻辑按自检结果走:有 whisper-cli+ggml 就用它,否则用 openai-whisper 本地缓存模型,
都没有就走"用户提供逐字稿";字体能用 uvx 就子集化,不能就用系统字体 src: local()。
然后建骨架:
python3 scripts/scaffold_project.py --dir <项目目录>
跑 hyperframes init(自带 HYPERFRAMES_SKIP_SKILLS=1 与 --skip-transcribe),
建 assets/fonts/、work/,放一份 spec.skeleton.json 骨架。目标目录必须为空。
目录约定,后面所有脚本都按这个走:
| 路径 | 内容 |
|---|---|
spec.json |
全部决策,第 4–8 步逐步填满 |
script.txt |
逐句稿 + 重点词(+ 可选逐句译文),第 2 步 |
sentences.json |
逐句时间,第 2 步产出 |
assets/talk-voice.m4a |
口播原音轨(-c:a copy 抽出) |
assets/pip-face.mp4 |
人像代理(正方形、无音轨) |
assets/ 下的图片与视频 |
配图 / 录屏 / 快剪素材 |
assets/fonts/ |
本地 CJK 字体 + 许可文件 |
proof/ |
排版确认版(build 自动写) |
work/confirm/ |
给用户看的两张确认图 |
1 · 素材盘点与类型确认(确认)
python3 scripts/probe_media.py <用户给的素材...>
输出统一表:文件名、时长、分辨率、帧率、有无音轨、编码。逐项让用户确认素材类型:
| 这条素材是 | 归到哪里 |
|---|---|
| 口播(有说话人画面 + 语音) | pip.media(或 pip.takes)+ audio.src |
| 配图 / 截图 / 静图 | timeline.media,kind: "image" |
| 录屏 / 真机操作演示 | timeline.media,kind: "video" |
| 实拍 B-roll / 其他视频 | timeline.media,kind: "video" |
| 逐字稿 / 字幕文件 | script.txt 的来源 |
多段素材问清拼接顺序与取舍(片头保留否、重复段删哪条);图片问用途(配图 / 全屏 / 快剪)。
口播分几次录的不要手工拼长视频,走 pip.takes + scripts/prep_takes.py,
见 references/media-pipeline.md。
门 1:用户确认每条素材的类型与归属。
2 · 脚本与逐句对齐(确认或输入 + 自动)
内容层必须先定,后面的大纲才排得准。
- 有脚本就导入;没有就按 references/alignment.md 转写。
- 按语义分 6–8 段,每段给段名、重点词;要双语字幕就加第三列译文。
重点词每段 3–6 个,必须能在句子原文里原样命中;超过 6 个就请用户挑。 - 逐句对齐:
python3 scripts/align_sentences.py --media <口播文件> --script script.txt --out sentences.json
脚本里手写的估算时间区间不能用。 实测脚本写"段 1 约 40s"而成片实际 0–24s,差十几秒。
段落边界一律以真实语音为准,把实际边界表给用户看,只请他复核可疑句。
对齐会顺带算逐字命中率(exactRate):卡片文字只能删语气词、重排标点,改写会让命中率掉下来。
低于阈值会点名是哪几句——但 ASR 用字差异(繁简、同音字)也会拉低它,所以是复核提示不是结论。
门 2:用户确认逐句稿、分段与时间轴。
3 · 交付规格(确认或输入)
确认:画布比例与分辨率、帧率、成片时长基准、发布平台。比例和平台定了就套预设,不要手算几何:
python3 scripts/apply_preset.py --list
python3 scripts/apply_preset.py --layout portrait --platform douyin --spec spec.json
预设写入画布尺寸、卡片外框/槽位/字号、人像小窗的形状尺寸位置、字幕条位置,以及
canvas.safeArea(平台边距 + 右下操作栏这类局部禁入区)。只改几何,不动形态、配色、内容、时间表。
改完跑 validate_spec.py:进了平台遮挡区会明确告诉你哪个元素压到哪块 UI。
竖屏用 1080×1920 那套;竖屏宽度不够做左右并排,beside 要改成上下排布。
门 3:用户确认规格。
4 · 剪辑初步方案(确认或输入)
这一步不聊视觉,只聊结构。 把整条片子拆成若干段,给出结构表:每段大概讲什么、主画面是卡片还是素材、
有哪些素材要进来、人像这段以什么形式出现、大致多长时间。写进 spec.json 的骨架字段
(canvas / timeline.cardWindows / timeline.media 的 start/duration / pip.stages 的形式),然后:
python3 scripts/plan_table.py --spec spec.json --sentences sentences.json
它把 spec 展开成"剪辑方案表"(时间段、主画面、素材、人像形式、卡片段、内容摘要),并标出
"既没卡片也没素材"或"有素材但卡片没覆盖"的区间。这张表就是第 4 步要用户确认的东西。
给方案时把话说清楚:哪里用卡片讲、哪里切素材、同时有几块画面、节奏大概怎样。结构定不下来就先别做视觉。
门 4:用户确认整体走法。
5 · 每部分呈现什么内容(逐项确认)
逐段过一遍,把"这段呈现什么"定死:
| 问什么 | 落到哪里 |
|---|---|
| 这段卡片讲什么 | 段名 + 卡片文字来自哪几句(第 2 步已定) |
| 这段有没有素材、素材放哪、多大 | timeline.media[*] 的 box |
| 素材和卡片怎么共存 | media[*].withCard:no / overlay / beside |
| 人像这段以什么形式出现 | pip.stages[*].form:pip / full / left / right / top / bottom / box / hidden |
| 演示段要不要指出 UI 位置 | timeline.callouts |
两个必须用户回答的关键项:
withCard——这段素材和卡片什么关系:
| 值 | 画面 | 用在哪 |
|---|---|---|
no |
只有素材,这段不出卡片 | 全屏演示、纯 B-roll |
overlay |
素材铺底,卡片压在上面 | 素材全屏 + 卡片做下三分之一 |
beside |
卡片与素材并排 | 左卡片右配图 |
pip.stages[].form——这段人像怎么呈现。这条直接决定画面里同时有几个视口:
| 值 | 效果 | 用在哪 |
|---|---|---|
pip |
右上小窗(最上层,素材盖不住它) | 讲解段 |
full |
人像铺满画布(在卡片层下面) | 开场、结尾、强调 |
left/right/top/bottom |
占半屏 | 分屏讲 |
box |
用本段的 box |
特殊版式 |
hidden |
这段不出现人像,只留声音 | 全屏演示段 |
不写 stages = 整片都是 pip。写就必须首尾相接盖满整片(校验器会查空档与重叠)。
全屏素材会盖住非 pip 的人像层,校验器会提醒。详见 references/media-layout.md。
门 5:用户逐段确认"这段呈现什么、素材配不配卡片、人像什么形式、放哪"。
6 · 卡片视觉(逐项确认)
读 references/card-system.md 与 references/spec.md 的设计项清单,逐项问:
卡片形态(card.variant:panel / bubble / subtitle)、外框位置尺寸(card.box)、圆角、内边距、
槽位高度(card.slots)、正文字号区间与行高(card.type)、重点词高亮样式(card.highlight.style)、
chips、进度条、步骤流程图(segments[*].flow)、背景(background.*)、主副色(accent)。
答完先跑一次 validate_spec.py,把它打印的文字外框位置与尺寸表给用户过目。
门 6:用户确认视觉方案与几何表。
7 · 人像呈现细节(逐项确认)
形状(pip.shape)、宽度与宽高比(pip.size / aspect)、圆角(radius)、位置(anchor)、
描边(ring)、是否随段落切主题色(ring.followSegment)、窗口角标(label)、
各段之间的切换时长(motion.talentStage.duration)。
人脸必须锚定窗口中心。裁切框不要猜:按 references/media-pipeline.md
的多时间点试裁法生成对比图让用户挑,再定 pip.media.crop。
分条口播时同一个裁切框套用到所有 take(prep_takes.py --crop),挑框要看每一条的多个时间点。
门 7:用户确认人像的形状、尺寸、位置、描边与裁切。
8 · 素材呈现细节、转场与音轨(逐项确认)
读 references/media-layout.md,逐条素材问:
| 问什么 | spec 键 |
|---|---|
| 素材比例和框不匹配怎么办 | fit(cover / contain / fill)+ objectPosition |
| 要不要外框、圆角、投影 | frame / radius / borderWidth / borderColor / background / shadow |
| contain 的留边怎么补 | backdrop(none / color / blur) |
| 静图要不要镜头运动 | motion + motionAmount |
| 怎么进、怎么出 | transitionIn / transitionOut(cut / fade / slide-up / slide-left) |
| 要不要角标说明 | label |
| 录屏从第几秒开始取、几倍速 | mediaStart / rate |
| 素材自己的声音要不要 | audio.mode(默认 mute) |
多视频是先后片段。 两条素材时间重叠时必须在后一条写 overlapWithPrevious: true 才允许同时可见,
否则校验器报 error 并告诉你怎么改。默认的 cut 就是硬切,不要为了"顺一点"随手加叠化——
叠化意味着两块画面同时出现。
音轨:取哪一段、放哪、留多长由用户定(audio.sourceStart / duration / start);
默认建议跟随口播素材全片,但那是建议。抽出文件仍然 -c:a copy 不重编码。
配乐(可选,问一句要不要):audio.bed。volume 0.10–0.25,duck.to 0.3–0.5,
fadeIn/fadeOut 0.8–1.5s。压低是按人声整体区间算的固定窗口 duck,不是实时侧链;
要真侧链、EQ、压缩、总线走 /hyperframes-audio。配乐素材比窗口短时后半段会静音(本工具不循环)。
最后再跑一次 plan_table.py,把定稿后的方案表给用户做最后一次整体确认。
门 8:用户确认素材参数、转场与音轨范围。
9 · 构建、预检与确认包(自动 + 用户确认)
python3 scripts/validate_spec.py --spec spec.json --sentences sentences.json --check-files
python3 scripts/build_composition.py --spec spec.json --sentences sentences.json --out .
python3 scripts/check_timeline.py --project . --spec spec.json
python3 scripts/keyframe_proof.py --project . --spec spec.json --sentences sentences.json --out work/confirm
再按 references/verification.md 跑 lint → check → 音轨核对。
发现问题自己修掉再报,不要带着已知缺陷进确认。
check_timeline.py 是"结构化"的兑现环节:把 spec 的时间表和 npx hyperframes timeline --json
实际解析出来的时间轴逐行比对(图层、起点、时长、倍速),不一致就非零退出。
确认包是给用户看两张图,不是内部检查:
| 图 | 用户拿它确认什么 |
|---|---|
keyframes.jpg 每段至少一帧 + 每段素材进出边界帧 |
成片观感、同时有几块画面、素材切的时机 |
layout.jpg 每个外框描边并标 x,y 宽×高 |
字框与素材框的位置尺寸、有没有压小窗 |
门 9:用户确认画面与几何。
10 · 预览(用户)
npx hyperframes preview --background,把 Studio 地址给用户,说明时间轴上的文字、卡片、素材、人像都能直接点开改。
门 10:等用户看完。要改就回到对应步骤,改完重跑第 9 步。
11 · 渲染交付
用户确认后才渲染。先预检再渲染:
python3 scripts/preflight_render.py --project . --spec spec.json --frame-format png
它算帧数、估中间态磁盘、估耗时和成片体积。--video-frame-format png 画质更好但中间态大好几倍
(实测 4 分 44 秒的片子吃到 10GB 量级),磁盘不够会非零退出并给降档建议。
渲染完核对时长、分辨率、帧率、体积,并做音轨核对:默认不让素材声音混入(用户明确要的除外),
选定的人声区间必须完整、没有意外静音。文件放到用户可见的输出目录,输出里只留交付物。
渲完跑 npx hyperframes clean 清中间态。
顺带问一句是否需要发布用文案或标题;需要就按成片实际内容写,不要写片子里没说的能力。
门 11:交付。
全局红线
- 不替用户做设计决定。 素材位置、配不配卡片、人像什么形式、小窗尺寸位置、背景、动效、音轨范围——都在对应步骤问过、写进
spec.json。没答的项给推荐并说明是推荐值。 - 先内容再结构再细节。 第 2 步没定,不要跳到第 4 步;第 4、5 步没定,不要跳到第 6、7 步调视觉。
- 多视频是先后片段。 时间重叠必须显式写
overlapWithPrevious: true;默认是硬切,不是叠化。 - 画面里同时有几块,要说得出来。 全屏素材 +
pip人像 = 两块;想要一块就把人像设成hidden。 - 口播音轨不重编码(
-c:a copy),取用范围由用户定;只有用户选了全片才按全片写。 - 卡片面板右边界必须小于小窗左边界;素材
box也不能压小窗。编辑期就用validate_spec.py校验。 - 媒体元素自己就是裁切容器,不要给它套带
data-start的父元素(lint会判 error)。 - 命名
font-family必须配同文件内的@font-face,指向随项目交付的本地字体文件,并附许可文本。 - 段落交叉淡入淡出一定会触发 layout 的
content_overlap;用data-layout-allow-overlap标到被指到的具体元素。 - 逐句元素一律用 GSAP 在主时间轴上驱动,不要让每个句子各自带
data-start嵌套定时。 - 不要用
<br>强制换行;文字容器不要随手加display:flex(会把内联高亮拆成独立 flex item 而崩版)。 - 用字幕条形态时必须让最后一句自己淡出(没有卡片退场可依赖),否则相邻句子会长期叠在一起。
- 时间轴不能有空档:每一刻都得有卡片或全屏素材,否则只剩背景 + 人像。确实要留空镜就把
timeline.allowEmpty设为true。 - 用户要双语字幕就给
script.txt加第三列译文;props.subtitleBar.secondary只是开关,译文来自每句的sub。
索引
| 文件 | 何时读 |
|---|---|
| assets/spec.schema.json | 第 4–8 步;字段与取值范围的唯一依据 |
| references/spec.md | 第 6–8 步;设计项清单、字段含义 |
| references/card-system.md | 第 6 步;版式、配色、字号、动效 token、安全区与平台预设 |
| references/media-layout.md | 第 4、5、8 步;素材位置、呈现方式、混剪、人像呈现形式、演示标注 |
| references/media-pipeline.md | 第 1、2、7 步;素材探测、分条口播、人像裁切、音轨抽取、配乐 |
| references/alignment.md | 第 2 步;ASR 与逐句对齐 |
| references/verification.md | 第 9、11 步;预检、确认包、渲染参数、交付校验、交付前清单 |
scripts/check_env.py |
第 0 步,先跑这个 |
scripts/scaffold_project.py |
第 0 步 |
scripts/project_state.py |
续做/接手时先跑 |
scripts/probe_media.py |
第 1 步 |
scripts/prep_takes.py |
第 1、2 步,分条口播切代理与音轨 |
scripts/align_sentences.py |
第 2 步 |
scripts/apply_preset.py |
第 3 步,套版式与平台安全区 |
scripts/plan_table.py |
第 4、8 步,出剪辑方案表 |
scripts/validate_spec.py |
第 5–9 步,每次改完 spec 都跑 |
scripts/build_composition.py |
第 9 步 |
scripts/check_timeline.py |
第 9 步,spec ↔ 实际时间轴比对 |
scripts/keyframe_proof.py |
第 9 步,生成确认包 |
scripts/preflight_render.py |
第 11 步,渲染前算磁盘与耗时 |
scripts/subset_fonts.py |
第 6 步加完字体后 |