hyperframes 竖屏谈话类视频字幕模板 portrait-header:9:16 顶部条带 + 底部 Crown 的完整实现指南
【免费下载链接】hyperframesWrite HTML. Render video. Built for agents.项目地址: https://gitcode.com/GitHub_Trending/hy/hyperframes
本篇技术指南讲解 hyperframes 内置字幕技能(embedded-captions)中面向9:16 竖屏谈话类(talking-head)视频的portrait-header模板:如何在主体头顶的横向条带中呈现逐词浮现的字幕,并可选在画面底部渲染一行"王冠"(crown)高潮字。读完本文,你将掌握该模板的锁定视觉身份、布局字段取值方法、五档字阶(typography slot)分配规则、完整 plan.json 编写方式,以及模板底层 HTML/GSAP 的实现原理。
模板定位:竖屏场景的字幕嵌入方案
portrait-header是 hyperframes 仓库中 embedded-captions 技能 的一个旧版模板,规格文档位于 skills/embedded-captions/modes/cinematic/_archive/portrait-header/spec.md,同目录下保留了对应的 template.html。
其设计目标非常明确:为竖屏说话人视频提供一种"不遮挡面部、又能最大化字幕存在感"的排版方式——字幕不落在常见的底部,而是整体放在画面顶部、位于人物头顶上方的一条水平条带(header strip)中。当画面能够拍到人物腰部以下时,还可以在画面底部叠加一条 crown(高潮字),形成"顶部字幕带 + 底部高潮句"的上下呼应结构。
该模板与横屏的champion(规格文档)同属旧版 cinematic 模板体系:两者共享intro / phrase / emph / dream / crown 五档字阶与 "single-caption swap"(同一时刻只显示一条字幕)的排版模型,区别只在于布局方向——champion面向 16:9 横向侧栏 + 中央 Crown,而portrait-header面向 9:16 竖屏顶部条带。规格文档中明确写到,如果素材是 16:9 横屏,应改用champion或memory-wall模板。
需要说明的是,从 modes/cinematic/README.md 可以看到,该技能现已演进为DNA 视觉语言体系(10 种场景参数化的视觉语言),旧的 per-template HTML 外壳已退役,
_archive/目录下的 portrait-header / champion / memory-wall 均作为"设计参考(design references only)"保留。本文基于归档模板的规格与源码展开,其布局思路(顶部条带 + 底部 Crown)与五档字阶模型在理解当前 DNA 体系时仍有直接的参考价值。
锁定视觉身份(Visual identity):哪些不可改动
规格文档用LOCKED(锁定)标注了模板的视觉身份,即模板的灵魂,任何使用都必须保持这四条,否则会破坏模板的视觉一致性:
- 五档字阶(typography slots):
intro/phrase/emph/dream/crown,全部居中显示; - 混合模式:
mix-blend-mode: screen,叠加在暖骨色(warm bone color,#fff5df)之上——screen 混合让浅色文字在暗色/中等亮度背景上自然"融"进画面,同时保持可读; - 单字幕轮换(single-caption swap):同一时刻所有字幕都堆叠在顶部条带的同一位置,后一条替换前一条,绝不同屏出现多条(底部 crown 除外);
- 逐词动画:每行按单词逐个浮现,分两种"语气"——
soft(柔和)为轻微的 Y 轴漂移淡入,present(呈现)为缩放弹出(pop+scale)。
从 template.html 的源码可以确认这套锁定样式如何落地:.cap基类统一设置mix-blend-mode: {{BLEND_MODE}}、color: {{CAP_COLOR}}、text-shadow与filter,五个字阶类各自通过calc(字号 * var(--font-scale))计算实际字号:
| 字阶 | 基础字号(× font_scale) | 字重 | 样式 | 字距 |
|---|---|---|---|---|
.cap-intro | 72px | 500 | 斜体 | -0.005em |
.cap-phrase | 88px | 600 | 常规 | -0.015em |
.cap-emph | 104px | 800 | 常规 | -0.025em |
.cap-dream | 92px | 700 | 斜体 | -0.015em |
.cap-crown | 130px | 900 | 全大写(uppercase) | -0.035em |
可以看到叙事弧线的字阶递进:intro 最小最轻(斜体 500),phrase 加粗,emph 最大最重(800 字重、-0.025em 收紧字距),dream 回到斜体但保持较重,crown 用最重的 900 字重 + 全大写 + 最紧字距,制造"一句话高潮"的视觉冲击。
适用场景判断:什么素材适合,什么必须拒绝
规格文档给出了一套清晰的决策标准,这与技能整体"先探片、后决策"的流程一致(见 SKILL.md 的 Decision gate):
✅ 适合(Good fit):
- 9:16 竖屏视频(典型 1080×1920);
- 单一主体居中填满画面;
- 头顶上方有干净的留白区域(clean band)——这是顶部条带的落点;
- 语速相对密集(大量短句)——此时 crown 只用于唯一的高潮句。
❌ 不适合(Wrong fit):
- 主体的头部已经顶到画面上缘(没有可容纳顶部条带的空间);
- 16:9 横屏素材——改用
champion(播客/访谈风)或memory-wall(内省独白风); - 多个说话人或多次切换镜头——单条带 + 单 Crown 的模型无法承载多视角叙事。
这条"头部上方必须有干净条带"的硬性前提,与技能参考文档 layout-heuristics.md 中"字幕平面必须永远落在背景像素上、绝不能压住人体"的原则一脉相承。规格文档在 "When to apply" 中把竖屏布局的规则总结为第 5 条 invariant:竖屏 9:16 时,墙面平面变成顶部条带(全宽,高度约 20%),crown(如使用)位于其下方。
布局决策:agent 需要决定的五个字段
模板遵循"STYLE LOCKED. LAYOUT OPEN."(样式锁定、布局开放)的设计哲学——视觉身份不可动,但布局完全开放给使用者按场景调整。规格文档给出了布局决策表(以 1080×1920 为例):
| 字段 | 含义 | 示例值(1080×1920) |
|---|---|---|
header.top | 顶部条带在画面中的 Y 坐标。应位于主体头顶上方,并留约 30px 呼吸空间 | 若发顶在 y≈200,则取30 |
header.height | 条带高度。长字幕/两行折行时需要更大值 | 280 |
crown_top | 底部 crown 线的 Y 坐标。画面看不到腰部时跳过 | 近全身镜头取1620 |
crown_enabled | 是否渲染底部 crown。主体下半身完全填满画面时跳过(遮罩本身就会挡住 crown) | 紧凑半身景别取false |
font_scale | 对锁定字号的整体缩放倍率 | 1080×1920 取1.0 |
在 template.html 中,这三个布局输入被直接注入 CSS:.header-plane使用top: {{HEADER_TOP}}px; height: {{HEADER_HEIGHT}}px定位,.crown-plane使用top: {{CROWN_TOP}}px,而:root { --font-scale: {{FONT_SCALE}} }驱动全部五个字阶的字号计算。条带内部还预置了padding: 24px 40px的安全边距,字幕.cap以绝对定位居中(left: 40px; right: 40px; text-align: center),max-width: calc(100% - 80px)保证长句不会溢出条带。
决策经验:crown 何时该开、何时该关
规格文档特别强调:竖屏条带本身很窄,多数字幕组(group)只占 1–2 行,因此 crown 的使用必须克制——如果 crown 会被主体身体的遮罩(matte)挡住,就不要用。典型场景是 Pausch 式(普式演讲)半身肖像:由于躯干占满下半画面,crown 往往必须整体跳过,把高潮词提升为顶部条带中的emph字阶即可。
这一判断与 layout-heuristics.md 中 crown 放置的经验表完全对应:当主体占据画面 >70% 或近景脸部 >80% 时,crown 应降级为列内emph,所有字幕放进 header/footer 条带——这正是 portrait-header 的默认工作模式。
Slot 分配:五档字阶的叙事弧线
规格文档规定 slot 分配沿用与champion相同的弧线模型(见 champion/spec.md 的 Slot assignment 表格):
| Slot | 用途 |
|---|---|
intro | 填充词/话语标记("you know," "for me," "so…") |
phrase | 主要陈述从句 |
emph | 关键成就/最高级表达 |
dream | 展望性语句、过去式回忆 |
crown | 全片唯一高潮句——中心舞台的 payoff |
对 portrait-header 而言,因为条带只有一条且较窄,还有两条额外纪律:
- 多数字幕组控制在 1–2 行内(结合
header.height的取值来容纳两行折行); - crown 不应在会被主体遮罩挡住时使用;此时把高潮直接提升为条带中的
emph即可。
关于"一句话应该被拆成多少个组",可以参考 caption-grouping.md 的规则:停顿 ≥500ms、句号/问号/感叹号、强逗号(≥250ms 停顿)、话语重置词("but" "so" "you know")都会触发切组;单组上限为 6 个词或 2.5 秒。组级时间则取in = 首词.start - 0.08、out = min(下一组.in - 0.05, 末词.end + 0.6),保证组窗口完整包裹内部单词(这也是技能"group windows must envelop their words"的硬性校验,见 SKILL.md)。
Plan.json 结构逐字段解析
规格文档给出了完整的 plan.json 示例,这里逐字段拆解:
{ "mode": "template", "template": "portrait-header", "duration": 25.3, "fps": 24, "width": 1080, "height": 1920, "header": { "top": 30, "height": 280 }, "crown_top": 1620, "font_scale": 1.0, "groups": [ { "id": "cg-0", "slot": "intro", "tone": "soft", "in": 0.10, "out": 3.20, "words": [...] }, { "id": "cg-1", "slot": "phrase", "tone": "soft", "in": 3.55, "out": 5.80, "words": [...] }, { "id": "cg-2", "slot": "emph", "tone": "present", "in": 17.85, "out": 22.10, "words": [ {"text": "Time", "start": 17.94, "end": 18.26}, {"text": "is", "start": 18.38, "end": 18.54}, {"text": "all", "start": 18.66, "end": 18.80}, {"text": "we", "start": 18.92, "end": 19.02}, {"text": "have", "start": 19.12, "end": 19.38} ]} ], "crown_group": null }各字段含义与取值要点:
mode/template:固定为"template"与"portrait-header",用于编译器的模板路由;duration/fps/width/height:成片参数,与源视频保持一致(竖屏典型 1080×1920、24fps);header.top/header.height:顶部条带的 Y 坐标与高度,见上文布局决策表;crown_top:底部 crown 的 Y 坐标,仅当启用 crown 时有效;font_scale:五个字阶的整体缩放倍率,用于适配不同画幅高度;groups[]:字幕组数组。每个组包含:id:唯一标识(如cg-0),模板用它生成 DOM 选择器;slot:五档字阶之一,决定使用哪个.cap-*类;tone:"soft"或"present",决定逐词动画曲线;in/out:组在时间轴上的显示窗口(秒);words[]:单词级时间戳,每个词带text/start/end,用于逐词卡拉 OK 式浮现,时间必须源自转录结果(Whisper 词级时间戳)。
crown_group:底部 crown 组。规格文档明确要求:如果你已确认 crown 会被主体身体或镜头构图挡住,必须显式设为null。
从 template.html 的实现看,GROUPS与CROWN两个 JSON 会被注入脚本:所有groups[]渲染进.header-plane,crown_group(若非空)渲染进.crown-plane,两者的动画由同一个animateGroup()函数驱动。
底层实现:模板 HTML 与 GSAP 逐词动画
模板是一个自包含的 HTML 合成外壳,通过占位符({{WIDTH}}、{{HEADER_TOP}}、{{GROUPS_HTML}}等)由编译器填充后交给渲染管线。其结构如下:
#a-roll:底层<video>,播放source.mp4,object-fit: cover铺满画幅,负责真实视频层;#stage:叠加层(z-index: 2,pointer-events: none),内含.header-plane(顶部条带,承载{{GROUPS_HTML}})与.crown-plane(底部 crown,承载{{CROWN_HTML}});#a-roll-audio:音轨引用(track-index: 3),与画面分离以便后续合成时对齐音频;- 根元素
#root:携带data-composition-id="main"、data-duration、data-width/height等元数据,供 hyperframes 渲染/合成脚本识别合成图层。
逐词动画由 GSAP(3.14.2,通过 CDN 引入)时间线实现,核心逻辑在animateGroup(g)函数中:
var isSoft = g.tone === "soft"; tl.set(sel, { opacity: 1, y: 0 }, Math.max(0, g.in - 0.01)); g.words.forEach(function (w, i) { var wsel = sel + " .w[data-i='" + i + "']"; if (isSoft) { tl.fromTo(wsel, { opacity: 0, y: 8 }, { opacity: 1, y: 0, duration: 0.42, ease: "power2.out", overwrite: "auto" }, w.start); } else { tl.fromTo(wsel, { opacity: 0, y: 6, scale: 1.04 }, { opacity: 1, y: 0, scale: 1.0, duration: 0.22, ease: "power3.out", overwrite: "auto", transformOrigin: "50% 50%" }, w.start); } });动画语义与锁定视觉身份的第四条完全对应:
soft(柔和):单词从opacity: 0, y: 8淡入并轻微上移归位,时长 0.42s、power2.out缓动——柔和、安静,适合 intro / phrase / dream;present(呈现):单词从opacity: 0, y: 6, scale: 1.04以 0.22s、power3.out弹出并缩回 1.0——干脆、有力,适合 emph 与 crown;- 退出:整组在
g.out - 0.45处开始 0.45s 淡出(power2.in),并在g.out时刻置为visibility: hidden,保证组与组之间无缝交接、绝不重叠(single-caption swap)。
时间线最终注册为window.__timelines["main"],由渲染引擎 seek 到指定帧截屏合成。这种"每个词精确对齐w.start时间戳"的逐词 karaoke 机制,与技能"词级时间戳必须与转录一致(容差 80ms)"的非协商约束(见 SKILL.md)严格对应。
实战工作流:从素材到成片
把 portrait-header 放进技能的整体流水线(详见 SKILL.md 的 5 步管线),使用方式如下:
# 1. 初始化项目(把竖屏源视频交给技能) hyperframes init <project> --non-interactive --video <video.mp4> --skill=embedded-captions # 2. 一键准备:并行生成主体遮罩 + 转录 + 音频包络 → 安全区 bash scripts/prepare.sh <project> # 输出:frames_fg/ transcript.json safe-zones.json # 3. 编写创作决策文件(本模板:plan.json,按上文 schema 编写) # Cinematic 旧模板流程:补时间 → 适配字号 → 编译合成 node scripts/fill-timings.cjs <project> node scripts/fit-fonts.cjs <project> node scripts/make-composition.cjs <project> # 4. 视觉 QA:先看合成预览帧,别急着渲染 node scripts/preview-frames.cjs <project> # 5. 渲染合成 → 通过门禁 → final.mp4 bash scripts/render-and-composite.sh <project>其中第 3 步值得一提:fill-timings.cjs 会直接按讲话顺序从transcript.json中按位置匹配并回填每组每个词的start/end与组级in/out,从而消除"文字匹配错词"导致的时序漂移——编写 plan.json 时只需给出组内单词与组级显示窗口(in/out只会被钳制、不会被收窄,以保留作者有意设置的高潮停顿)。这意味着你在 plan.json 中只需关注分组与字阶,时间细节由脚本保证确定性。
第 5 步的渲染门禁会自动执行时序校验(check-timing.cjs --strict)、遮挡/溢出检查与手递手(hand-off)检查,与 template.html 的确定性 GSAP 时间线(无Math.random()、无Date.now())共同保证每一帧的合成结果可复现。
从 portrait-header 看模板体系演进
作为归档模板,portrait-header 的顶部条带 + 底部 Crown + 五档字阶设计在今天仍有方法论价值:它解决了竖屏谈话类视频的核心矛盾——字幕要醒目,但不能遮脸。当前技能用 DNA 体系(dna/README.md)将这一思路参数化:10 种视觉语言各自锁定字体、调色、混合模式与运动语法,并通过safe-zones.json按场景采样强调色、接触阴影与景深模糊;而"竖屏顶部留白"的布局判断则沉淀在 layout-heuristics.md 的 invariants 中("9:16 时墙面平面变为顶部条带,高度约 20%")。
因此,阅读 portrait-header 规格的正确姿势是:把它当作竖屏字幕编排的设计语言参考——理解五档字阶的弧线逻辑、single-caption swap 的稀缺原则、crown 的取舍标准;在实际生产中,则遵循技能当前推荐的身份选择流程,从 CATALOG.md 的 35 个身份中挑选,或直接使用cream/ink等 DNA,而不再直接使用这份归档模板。需要横向对比时,可同时翻阅 champion 规格(横屏侧栏 + 中央 Crown)与 memory-wall 规格(墙面诗行堆叠),三者共同构成了这套模板库对"单说话人 + 嵌入型字幕"不同画幅、不同语气的完整覆盖。
【免费下载链接】hyperframesWrite HTML. Render video. Built for agents.项目地址: https://gitcode.com/GitHub_Trending/hy/hyperframes
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考