OpenMontage avatar-video 技能详解:HeyGen AI 数字人视频的文字叠加层(Text Overlays)精准控制
本文基于 OpenMontage 仓库中 avatar-video 技能的参考文档 展开,讲解如何在 HeyGen v2 API 生成的 AI 数字人视频中叠加标题、下三分之一(lower third)、行动号召(CTA)等屏幕文字元素。读完本文,你可以完整掌握文字叠加层的数据结构、坐标定位规则、字体样式配置、模板化封装与时间轴对齐方法,并了解它在 OpenMontage 的 Remotion 合成链路中的实际落位方式。
一、文字叠加层在 avatar-video 技能中的定位
OpenMontage 仓库中,.agents/skills/avatar-video/ 是一个面向 AI 编码助手的"数字人视频制作"技能包,其 SKILL.md 定义了标准工作流:
- 列出数字人 —
GET /v2/avatars,选定avatar_id与default_voice_id; - 列出声音 —
GET /v2/voices,为数字人匹配合适音色; - 撰写脚本 — 每个场景承载一个概念;
- 生成视频 —
POST /v2/video/generate,逐场景配置数字人、声音、背景; - 轮询状态 —
GET /v2/videos/{video_id}直至completed。
文字叠加层属于其中的**视频自定义(Video Customization)**环节。技能文档的 Quick Reference 表中明确将其归类为定制能力之一,与背景(backgrounds.md)、字幕(captions.md)并列,所有请求需携带 X-Api-Key 请求头,并从环境变量 HEYGEN_API_KEY 读取密钥。
需要先区分两个易混淆的概念:
| 能力 | 内容来源 | 适用场景 |
|---|---|---|
| 文字叠加层(Text Overlays) | 你手动指定文本、位置、样式、出现时间 | 标题卡、人名条、CTA 等设计性文字 |
| 自动字幕(Captions) | 由语音自动转录生成 | 口播内容的听障可访问性、无声播放场景 |
两者可叠加使用:数字人口播时挂自动字幕,同时用文字叠加层强调章节标题与关键信息。
二、基础用法与 TextOverlay 数据结构
在视频配置中,基础用法是先构建 video_inputs(数字人 + 声音 + 背景),再叠加文字配置。原文档给出的示例骨架如下(文字叠加能力随订阅档位不同而开放):
const videoConfig = {
video_inputs: [
{
character: {
type: "avatar",
avatar_id: "josh_lite3_20230714",
avatar_style: "normal",
},
voice: {
type: "text",
input_text: "Welcome to our presentation!",
voice_id: "1bd001e7e50f421d891986aad5158bc8",
},
background: {
type: "color",
value: "#1a1a2e",
},
},
],
// Text overlay configuration (if supported in your API tier)
// Note: Availability varies by plan
};
单个文字叠加层由 TextOverlay 接口描述,这是整个能力的数据核心:
interface TextOverlay {
text: string;
x: number; // X 坐标(像素或百分比)
y: number; // Y 坐标(像素或百分比)
width?: number; // 文本框宽度
height?: number; // 文本框高度
font_family?: string;
font_size?: number;
font_color?: string;
background_color?: string;
text_align?: "left" | "center" | "right";
duration?: {
start: number; // 出现时间(秒)
end: number; // 消失时间(秒)
};
}
关键属性说明:
x/y:定位锚点,单位为像素或视频尺寸的百分比,坐标系见下一节;width/height:文本框尺寸,用于控制换行与包裹范围;font_family/font_size/font_color/font_weight/background_color:字体族、字号、字色、字重与文字背景色(半透明背景可显著提升复杂画面上的可读性);text_align:left/center/right三档对齐;duration:以秒为单位的出现/消失时间窗,是文字叠加层与脚本节奏对齐的关键。
三、坐标系与常用定位
坐标系规则
- 原点:左上角
(0, 0); - X 轴:向右增大;
- Y 轴:向下增大;
- 单位:像素,或相对视频宽高的百分比。
常用位置速查表(以 1920×1080 为例)
| 位置 | X | Y | 说明 |
|---|---|---|---|
| 左上角 | 50 | 50 | 上左侧 |
| 顶部居中 | 960 | 50 | 顶部中央 |
| 右上角 | 1870 | 50 | 上右侧 |
| 正中央 | 960 | 540 | 画面正中 |
| 左下 | 50 | 1030 | 下三分之一区域左侧 |
| 底部居中 | 960 | 1030 | 下三分之一区域中央 |
注意该表的取值依赖分辨率:1920×1080 来自 dimensions.md 中 16:9 横屏 1080p 的标准规格。若改用竖屏 1080×1920 或方形 1080×1080,"居中"与"下三分之一"的坐标必须按实际宽高重新计算,不能照抄上表。
位置辅助函数
原文档给出了一个把语义化位置名映射到坐标的辅助函数,可直接复用:
interface Position {
x: number;
y: number;
}
function getTextPosition(
location: "top-left" | "top-center" | "top-right" | "center" | "bottom-left" | "bottom-center" | "bottom-right",
videoWidth: number,
videoHeight: number,
padding: number = 50
): Position {
const positions: Record<string, Position> = {
"top-left": { x: padding, y: padding },
"top-center": { x: videoWidth / 2, y: padding },
"top-right": { x: videoWidth - padding, y: padding },
"center": { x: videoWidth / 2, y: videoHeight / 2 },
"bottom-left": { x: padding, y: videoHeight - padding },
"bottom-center": { x: videoWidth / 2, y: videoHeight - padding },
"bottom-right": { x: videoWidth - padding, y: videoHeight - padding },
};
return positions[location];
}
这个设计的好处是把"位置语义"与"像素坐标"解耦:换分辨率时只需换 videoWidth / videoHeight 两个入参,padding 默认 50px 用于留出安全边距,避免文字贴边。
四、字体样式配置
样式属性示例
const textStyle = {
font_family: "Arial",
font_size: 48,
font_color: "#FFFFFF",
font_weight: "bold",
background_color: "rgba(0, 0, 0, 0.5)",
text_align: "center",
};
其中 background_color 使用 rgba 半透明黑色是常见手法——文字压在任意背景上都保持对比度,而不需要预判背景明暗。
常用字体族选择
| 字体 | 风格 | 适用场景 |
|---|---|---|
| Arial | 无衬线 | 干净、通用 |
| Helvetica | 无衬线 | 现代、专业 |
| Times New Roman | 衬线 | 传统、正式 |
| Georgia | 衬线 | 优雅、易读 |
| Roboto | 无衬线 | 现代、数字感 |
| Open Sans | 无衬线 | 亲和、易读性好 |
五、三种典型叠加模式
原文档给出三类高频模式的完整配置,均可直接复制改造:
1. 标题卡(Title Card)
画面正中、开场 0~3 秒展示的大标题:
const titleOverlay = {
text: "Product Demo",
x: 960,
y: 540,
font_family: "Arial",
font_size: 72,
font_color: "#FFFFFF",
text_align: "center",
duration: {
start: 0,
end: 3,
},
};
2. 下三分之一条(Lower Third,人名/头衔)
左下角带半透明蓝底的两行文字,第 2 秒出现、第 8 秒消失:
const lowerThirdOverlay = {
text: "John Smith\nCEO, Company Inc.",
x: 100,
y: 900,
font_family: "Arial",
font_size: 36,
font_color: "#FFFFFF",
background_color: "rgba(0, 102, 204, 0.9)",
text_align: "left",
duration: {
start: 2,
end: 8,
},
};
注意 text 中用 \n 分隔姓名与头衔两行,配合左对齐形成经典的"人名条"版式。
3. 行动号召(Call to Action)
收尾段落的引导文字,用金色(#FFD700)突出:
const ctaOverlay = {
text: "Visit example.com",
x: 960,
y: 1000,
font_family: "Arial",
font_size: 42,
font_color: "#FFD700",
text_align: "center",
duration: {
start: 25,
end: 30,
},
};
六、模板化封装:TextOverlayTemplate
为避免每个视频重复调参,原文档定义了一套"模板 + 工厂函数"的封装方式:模板只存样式,位置与时长由调用方注入。
interface TextOverlayTemplate {
name: string;
style: Partial<TextOverlay>;
}
const templates: TextOverlayTemplate[] = [
{
name: "title",
style: {
font_family: "Arial",
font_size: 72,
font_color: "#FFFFFF",
text_align: "center",
},
},
{
name: "subtitle",
style: {
font_family: "Arial",
font_size: 42,
font_color: "#CCCCCC",
text_align: "center",
},
},
{
name: "lower-third",
style: {
font_family: "Arial",
font_size: 36,
font_color: "#FFFFFF",
background_color: "rgba(0, 0, 0, 0.7)",
text_align: "left",
},
},
{
name: "caption",
style: {
font_family: "Arial",
font_size: 32,
font_color: "#FFFFFF",
background_color: "rgba(0, 0, 0, 0.5)",
text_align: "center",
},
},
];
function createTextOverlay(
text: string,
templateName: string,
position: Position,
duration?: { start: number; end: number }
): TextOverlay {
const template = templates.find((t) => t.name === templateName);
if (!template) {
throw new Error(`Template "${templateName}" not found`);
}
return {
text,
x: position.x,
y: position.y,
...template.style,
duration,
};
}
四个内建模板覆盖了绝大多数版式需求:
| 模板名 | 字号 | 颜色 | 背景 | 对齐 | 典型用途 |
|---|---|---|---|---|---|
title |
72 | 白 | 无 | 居中 | 开场标题卡 |
subtitle |
42 | #CCCCCC 浅灰 |
无 | 居中 | 章节副标题 |
lower-third |
36 | 白 | 黑 70% | 左对齐 | 人名/头衔条 |
caption |
32 | 白 | 黑 50% | 居中 | 强调性说明文字 |
工厂函数在模板名缺失时抛出显式错误,便于在批量生成场景中快速定位配置笔误——这一点与技能 SKILL.md 的"生成前先校验输入"的最佳实践一致。
七、时间轴对齐:让文字跟着脚本走
文字叠加层最容易踩的坑是与口播节奏脱节。原文档的做法是在脚本中先标注时间区间,再为每个区间生成对应叠加层:
// 带时间标记的脚本
const script = `
Hello and welcome. [0:00 - 0:03]
Let me show you our features. [0:03 - 0:08]
First, we have analytics. [0:08 - 0:15]
Get started today! [0:15 - 0:20]
`;
// 与之匹配的文字叠加层
const overlays = [
{
text: "Welcome",
duration: { start: 0, end: 3 },
...titleStyle,
},
{
text: "Feature Overview",
duration: { start: 3, end: 8 },
...subtitleStyle,
},
{
text: "Analytics Dashboard",
duration: { start: 8, end: 15 },
...lowerThirdStyle,
},
{
text: "www.example.com",
duration: { start: 15, end: 20 },
...ctaStyle,
},
];
这里有两点实践细节值得注意:
- 时间区间首尾相接(0→3→8→15→20),避免同一区域两个叠加层交叉重叠导致文字打架;
- 口播时长可预估:remotion-integration.md 给出了经验公式——按约 150 词/分钟的语速估算视频时长,
wordCount / 150 * 60 * fps可得大致帧数。因此标注脚本时间戳时,可以先按该速率粗排,待视频生成后再微调。
八、最佳实践与能力边界
原文档总结了六条最佳实践:
- 可读性 — 文字与背景之间保持足够对比度;
- 字号 — 保证在移动设备上依然可读;
- 时长 — 给观众留足阅读时间(经验值:至少 3 秒);
- 定位 — 不要遮挡数字人的脸部区域;
- 一致性 — 全片使用统一的字体与样式;
- 无障碍 — 考虑色盲友好的配色方案。
同时明确列出了能力边界(Limitations):
- 文字叠加支持情况随订阅档位不同而变化;
- 部分高级样式选项可能不开放给 API;
- 复杂动画可能需要后期工具完成;
- 自动生成的字幕请参见技能内的 captions.md(仓库路径 .agents/skills/avatar-video/references/captions.md)。
也就是说:把"确定性文字"交给叠加层、把"口播字幕"交给自动字幕、把"复杂动效文字"留给后期/程序化合成,是这套能力划分背后的设计逻辑。
九、仓库纵深:文字叠加层在 OpenMontage 合成链路中的落位
上述内容主要覆盖 HeyGen 侧的"生成时叠加"。从仓库源码结构看,OpenMontage 还有一条合成时叠加的路线,理解两者配合能更完整地把握该技能的用法。
1. 技能包内的交叉引用
avatar-video 技能把文字叠加层定位为"Video Customization"三大件之一(背景 / 文字叠加 / 字幕),见 SKILL.md 的 Reference Files 一节;Quick Reference 表中"Add text overlays → text-overlays.md"一行给出了直达索引。这说明在 Agent 执行视频任务时,文字需求会先路由到本文所讲的参考文档。
2. Remotion 合成路线:叠加层是"第三层"
对于需要复杂动效的文字(打字机效果、弹性入场、逐词高亮等),仓库的推荐做法是:HeyGen 只产出"干净的数字人视频",文字在 Remotion 中作为独立图层合成。remotion-integration.md 中的分层示例把这一思路具体化(约 L277-L307):
<AbsoluteFill>
{/* Layer 1: 背景/内容 */}
<AbsoluteFill style={{ backgroundColor: "#1a1a2e" }}>
<YourMotionGraphics />
</AbsoluteFill>
{/* Layer 2: 透明背景数字人(OffthreadVideo 保证逐帧精确) */}
<OffthreadVideo src={avatarWebmUrl} transparent style={{...}} />
{/* Layer 3: 数字人之上的文字叠加层,用 Sequence 控制出现帧 */}
<Sequence from={30}>
<AnimatedTitle text="Welcome!" />
</Sequence>
</AbsoluteFill>
对比两种路线,可以得出选型结论:
| 维度 | 生成时叠加(本文主体) | 合成时叠加(Remotion) |
|---|---|---|
| 实现位置 | HeyGen API 配置 | Remotion 组件图层 |
| 时间单位 | 秒(duration.start/end) |
帧(Sequence from) |
| 动效能力 | 受 API 档位限制 | 完整(GSAP/CSS/任意 React 动效) |
| 适用场景 | 静态标题、人名条、CTA | 弹性入场、逐词高亮、复杂排版 |
两个时间系统的换算关系很直接:帧号 = 秒 × fps,例如 from={30} 在 30fps 下即第 1 秒出现,与生成时路线 duration: { start: 1 } 等价。该文档同时强调必须使用 OffthreadVideo 而非 Video(浏览器解码器不逐帧精确,渲染会抖动),这与文字叠加层的帧对齐质量直接相关。
3. 仓库内的字幕叠加组件
从源码结构看,OpenMontage 的 Remotion 工程 remotion-composer/ 已内置文字叠加类组件,如 CaptionOverlay、HeroTitle、EndTag 等,并在 组件出口文件 中统一导出。可以推断:走合成路线时,"下三分之一条""片尾 CTA"等版式可以直接复用这些组件,而本文第二至七节的坐标、字号、时长规则依然适用——只是坐标从 HeyGen 的像素坐标系转换为 Remotion 的 CSS 定位(position: absolute + top/left),两者共享同一套"原点左上、Y 轴向下"的坐标系心智模型。
十、小结
OpenMontage 的 avatar-video 技能把"数字人视频上的文字"拆成了三层可控能力:数据层(TextOverlay 接口的坐标、字体、时长三要素)、版式层(title / subtitle / lower-third / caption 四个模板 + 位置辅助函数)、时间层(与脚本时间戳逐区间对齐)。生成时叠加适合确定性文字,Remotion 合成路线(OffthreadVideo + Sequence + 仓库内置覆盖组件)承接复杂动效,二者按"动效复杂度"分工。掌握本文的数据结构、定位速查表、模板工厂与时间轴对齐方法,即可在 OpenMontage 的 avatar-video 工作流中独立完成标题卡、人名条、CTA 等全部常规文字叠加需求。
atomcodeClaude Code 的开源替代方案。连接任意大模型,编辑代码,运行命令,自动验证 — 全自动执行。用 Rust 构建,极致性能。 | An open-source alternative to Claude Code. Connect any LLM, edit code, run commands, and verify changes — autonomously. Built in Rust for speed. Get StartedRust0623
Hy4-previewHy4 preview 是由腾讯混元团队研发的新一代混合专家(MoE)旗舰模型。模型总参数量 770B,每个 token 激活 49B,主干共包含78层,第一层采用标准 FFN,其余 77 层均为 MoE 结构,每层包含 256 个路由专家与 1 个共享专家,每个 token 激活 top-8 路由专家及共享专家。主干之外原生内置 1 层 MTP(总参数量 10B,激活 0.7B)以支持投机解码。Python00
GLM-5.3GLM-5.3 与 GLM-5.2 使用相同的基座模型——所有提升均来自后训练。与 GLM-5.2 相比,它在复杂编程和长程任务上的表现显著提升。Jinja00
GLM-5.3-FlashGLM-5.3-Flash (320B-A18B),是GLM-5系列的首个原生多模态模型。320B总参数,能力超过GLM-5.2Jinja00
Spark-X2.5-4BSpark-X2.5-4B 旨在让强大的 AI 更实用、更高效、更易获得。在广泛日常任务中表现强劲,涵盖对话、写作、翻译、推理、编码、工具调用以及智能体工作流,并在同等规模的开源模型中取得领先成绩。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00
Spark-X2.5-1.7BSpark-X2.5-1.7B 旨在让强大的 AI 更加实用、高效且易于获取。这些模型在广泛的日常任务中表现出色,涵盖对话、写作、翻译、推理、编程、工具调用和智能体工作流,并在同等规模的开源模型中取得领先结果。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00