本文由 莫潇羽@无忆研习社(www.wuyi.wiki)撰写,转载请注明出处。
版本提示:本文依据 2026 年 9 月中旬的 Hypit 官方文档整理,写稿当天 GitHub 上的最新发布版本为 v0.1.9。项目迭代很快,文中的 SVML 语法细节(如span-authority属性、@/id~这类边界吸附写法)和命令行用法可能随版本调整,动手前请先运行hypit version --check核对,一切以官方最新文档为准。
快速摘要
Hypit 是一个开源的 AI 视频制作系统,定位是给 Claude Code、Codex 这类“会用技能(Skill)的编程 Agent”提供一套写视频的语言和执行工具。它的核心是 SVML 标记语言:台词写在 Script 里,画面、字幕、特效不再绑定“第几秒”,而是绑定“哪个词、哪句话”。配音或口播录好之后,由 WhisperX 做词级对齐,把语义锚点换算成精确帧,最后交给 HyperFrames 渲染器输出 MP4。安装只需一行 npx skills add hypit-ai/hypit -g,需要 Node.js 22 及以上版本。生成模型是可选项,纯字幕加动态图形的视频可以不调用任何模型。对国内创作者来说,有三件事必须提前知道:语音对齐目前只支持英文和中文;境外模型服务的使用要遵守国内网络与内容管理规定;发布 AI 生成或合成的视频必须按《人工智能生成合成内容标识办法》做标识。
这篇文章不打算把 Hypit 吹成“一键出片神器”。它现在还处在 0.1.x 的早期版本,门槛也不低,更适合愿意和命令行、配置文件打交道的人。我会从“为什么改一句台词要返工半天”这个老问题讲起,一路拆到 SVML 的语法细节、从台词到成片的完整数据流、安装和出片的每一条命令、批量变体怎么复用已有素材、不用模型怎么出片,最后把国内平台发布必须补上的合规功课逐条讲清楚。
想看完整拆解,往下翻。
一、剪辑越做越累,问题其实出在“秒”上
一个几乎人人都经历过的返工场景
先说一个很普通的场景。你做了一条 45 秒左右的知识口播视频,结构是开场抛问题、中间讲三个要点、结尾给行动建议。视频发出去反馈不错,你打算照着同样的节奏再做一期,换个话题。
打开剪辑软件,你会发现能直接复用的东西少得可怜。工程文件可以另存一份,可里面的每一个元素都钉在时间轴上:第 3.2 秒弹出标题卡,第 7.8 秒切到产品特写,第 12 秒开始第二段字幕。新一期的口播只要比上一期多说半句,后面所有东西就会整体错位。字幕要重新对,贴纸要一个个挪,转场位置要重新卡点。
我自己折腾短视频这几年,最大的体会是:真正累人的往往不是“创意”,而是“对齐”。创意想好之后,大量时间耗在把画面、字幕、音效一帧一帧地挪回正确位置上。
时间轴剪辑的底层逻辑
主流的剪辑工具,无论是专业的非线性编辑软件,还是手机上的剪辑应用,底层逻辑都一样:以时间为坐标。所有素材都有“起点秒数”和“持续时长”两个属性,你拖动的每一个片段,本质上都是在修改这两个数字。
这种设计对“一次性作品”很友好,所见即所得,直观。可一旦你想把一条视频变成模板反复用,它的短板就暴露出来了:时间坐标记录的是“结果”,不是“意图”。软件只知道标题卡出现在第 3.2 秒,却不知道你之所以把它放在那里,是因为主播刚好说到了“三个误区”这几个字。
意图丢了,复用就只能靠人工重新理解一遍。下面这张图,是改动一句台词之后,时间轴工程里会发生的连锁反应:
flowchart TD
A[开场第二句台词多了 1.5 秒] --> B[后续口播整体后移]
B --> C[字幕块全部错位]
B --> D[B-roll 切入点对不上]
B --> E[音效和卡点失效]
C --> F[逐条手动重新对齐]
D --> F
E --> F
F --> G[重新导出检查]
换一种坐标系:绑定“词”而不是“秒”
如果把坐标系从“秒”换成“词”,情况就完全不同了。你在工程里记录的不再是“第 3.2 秒出标题卡”,而是“主播说到‘三个误区’时出标题卡”。至于“三个误区”这几个字最终落在第几秒,交给程序在配音生成之后自动算。
这样一来,台词改长了、改短了、换了一个主播重新录,只要那几个关键词还在,画面就会自动跟过去。这就是所谓的语义锚定。白话解释一下:锚定就是“拴住”,语义锚定就是把画面元素拴在一句话的意思上,而不是拴在一个时间点上。
我用一张表对比一下两种思路在常见改动下的工作量差异:
|
改动类型 |
时间轴思路要做的事 |
语义锚定思路要做的事 |
|
开场台词多加半句 |
后续字幕、贴纸、切镜全部手动后移 |
改台词文本,重新对齐后自动换算 |
|
换一位主播重录 |
所有卡点按新语速重新调整 |
替换口播素材,锚点重新测量 |
|
删掉中间一个要点 |
删除片段后填补空隙、修正后续位置 |
删掉对应段落,后面自动顺延 |
|
竖屏改横屏 |
所有元素位置和尺寸重新摆 |
切换画布和布局规则 |
|
同一结构换个产品 |
几乎等于重新剪一遍 |
替换产品相关文本和素材 |
这个思路本身并不新。字幕行业里的“强制对齐”技术早就存在,自动化剪辑工具里也有“按关键词触发”的零散功能。Hypit 做的事情,是把这个思路贯彻到整条视频的每一层:字幕、画面叠加、B-roll、配音、合成、渲染,全部围绕同一份台词来组织。
为什么偏偏是现在出现
语义锚定之所以现在才开始变得实用,我认为有两个外部条件成熟了。
第一个条件是词级语音对齐工具足够好用了。以 WhisperX 为代表的开源工具,能给出每个词在音频里的起止时间,而不只是整句的大概位置。没有这一步,“拴在词上”就只是一句空话。
第二个条件是编程 Agent 能读懂结构化文件了。一份包含几十个组件、上百行标记的视频描述文件,让人手写会很痛苦,但让 Agent 去写、去改、去检查,负担就小很多。人只需要用自然语言说“把开头换成更直接的提问”,剩下的交给 Agent 去改文件。
两个条件叠在一起,才让“用写文件的方式做视频”从极客玩具变成了普通创作者也能尝试的方案。
二、Hypit 的真实身份:一套给 Agent 用的视频编译工具
先把“它不是什么”说清楚
第一次听说 Hypit 的人,很容易把它想象成一个网页应用:上传视频,点个按钮,出来一堆新视频。实际并不是这样。
Hypit 没有那种傻瓜式的在线编辑界面作为主入口。它的主要使用方式,是在你本地的编程 Agent 里调用一个名为 hypit 的技能。你和 Agent 对话,Agent 读取 Hypit 提供的制作知识,调用 Hypit 的命令行工具,在你的项目文件夹里生成、修改一组文本文件,再把这些文件编译、渲染成视频。
所以,我更愿意把它理解成一套视频编译工具链。“编译”这个词借用自编程:程序员写的是人能读懂的源代码,编译器把它翻译成机器能执行的程序。Hypit 里,你(或者 Agent)写的是描述视频的源文件,Hypit 把它翻译成真正的 MP4。
拆开看,它由哪几块组成
根据官方文档的描述,Hypit 的结构可以分成下面几个角色。我按“谁负责什么”整理成表:
|
组成部分 |
负责的事情 |
白话理解 |
|
Hypit Skill |
给 Agent 提供视频制作的知识和工作方法 |
Agent 的“岗前培训手册” |
|
hypit 命令行包 |
提供检查、规划、构建、导出等可执行工具 |
真正干活的“工具箱” |
|
SVML / SVS / SVRUN 文件 |
分别描述视频内容、视觉样式、构建意图 |
剧本、化妆手册、开工单 |
|
本地 Runtime |
管理凭据、服务端点和后台执行进程 |
片场调度 |
|
WhisperX |
把口播音频里每个词的时间测出来 |
场记,记下每句话说在哪一帧 |
|
HyperFrames 渲染器 |
把合成结果逐帧渲染并编码成视频 |
冲印车间 |
|
生成模型(可选) |
生成图片、视频片段、配音 |
外请的摄影师和配音演员 |
这里有两个开源依赖值得多说一句。
HyperFrames 是 HeyGen 开源的视频渲染框架,采用 Apache 2.0 协议。它的做法是把视频的每一帧描述成网页,用无头浏览器逐帧截取,再用 FFmpeg 编码。“无头浏览器”就是没有界面、在后台运行的浏览器。这种做法的好处是确定性强,同样的输入每次渲染出来的结果一致,很适合自动化批量生产。它对环境的要求是 Node.js 22 及以上和 FFmpeg。
WhisperX 是一个开源语音识别项目,在 OpenAI 的 Whisper 模型基础上,用 wav2vec2 做强制对齐,得到词级时间戳,还能借助 pyannote 做说话人区分。“强制对齐”是指:已知文本内容,让程序去音频里找出每个字词的精确位置。Hypit 正是靠它把“台词”和“真实口播”对上号。
三个入口,对应三种起步方式
Hypit 官方给出了三种开始制作的方式,我按上手难度从低到高重新排一下:
flowchart LR
subgraph 起步方式
T[从现成模板开始]
D[用文字描述想要的视频]
R[提供一条参考视频]
end
T --> S[生成可编辑的 SVML 项目]
D --> S
R --> S
S --> C[检查与规划]
C --> B[构建与渲染]
B --> V[成片 + 可继续修改的源文件]
从模板开始:官方仓库里准备了播客、街头采访、双人对话、视频通话等常见格式的示例工程。新手我最推荐这个入口,因为模板本身就是一份“能跑通的标准答案”,照着改比从零写安全得多。
用文字描述:直接告诉 Agent 你想要什么样的视频,比如时长、风格、开头怎么抓人、结尾引导什么动作,Agent 会自己规划结构、写台词、决定画面方案,再落成 SVML 文件。
提供参考视频:给 Agent 一个本地视频文件或受支持平台的链接,再说明要替换什么,比如换主播、换产品、换语言、换画幅。Agent 会分析参考视频的镜头节奏、字幕落点、图形出现的时机,然后按你的目标改写。官方把这个入口放在最显眼的位置,但我要提前泼一盆冷水:参考视频的版权问题在国内非常敏感,第八章会专门讲。
不管从哪个入口进来,最终得到的都不是一个“只能看不能改”的成片,而是一整套普通文本文件。你随时可以打开来改,改完重新构建。这一点,是它和大多数在线 AI 视频工具最本质的区别。
模型从哪里来:自带密钥还是托管服务
Hypit 本身不绑定任何一家模型厂商。官方文档里提到两种接入方式。
一种是 HypiHub,也就是 Hypit 官方的托管服务,一个账号里集成了托管版 WhisperX,以及图片、视频、语音相关的模型。另一种是 BYOK,全称 Bring Your Own Key,意思是“自带密钥”:你用自己在各家模型平台申请的 API 密钥,通过 Hypit 的 Provider 机制接进来。Provider 可以理解成“适配器”,负责把 Hypit 的统一调用翻译成某家模型平台的接口格式。项目还允许你自己编写 Provider,本地能力和托管能力也可以混着用。
如果选用托管服务,建议先确认其服务端所在地区及数据处理条款。服务端位于境外时,上传含有人脸、人声等个人信息的素材,就涉及个人信息出境的合规判断,这一点在第八章“境外服务”一节会展开讲。
官方示例工程里出现的模型,包括用于生成视频片段的 Seedance、用于生成图片的 GPT Image 系列,以及用于对齐的 WhisperX。需要提醒的是,这些模型大多是境外服务,境外模型使用需遵守国内网络与内容管理相关规定。国内创作者如果想走合规路线,可以关注国内平台正式开放的同类模型接口,比如火山引擎在 2026 年 4 月正式开放的 Seedance 2.0 系列 API,再评估是否需要为它编写或适配 Provider。
还有一点我很认可:官方的 Agent 工作流程里明确要求,在发起任何付费调用之前,Agent 要先向你说明所用账号、计划做哪些工作、可查到的费率或预估成本,以及还不确定的部分,得到你的同意才开跑。账号、范围、预算任何一项变了,都要重新确认。这种“先报价后开工”的设计,对怕被 API 账单吓到的人非常友好。
它现在处在什么阶段
从 GitHub 的 Release 记录看,写稿时 Hypit 仍处在 0.1.x 区间,更新非常频繁。v0.1.8 发布于 2026 年 9 月 14 日,第二天就发布了 v0.1.9。最近几个版本主要在打磨命令行报错提示、长时间准备过程的进度展示、托管服务与自带密钥的连接说明,以及把正式发布流程和 npm 发包打通。
这里有个容易忽略的点:官方说明中,Hypit 的可执行程序和 Hypit Skill 是两份独立的安装,升级时要分别处理。以全局安装为例:
# 升级可执行程序(版本号以官方最新 Release 为准)
npm install --global @hypit/hypit@0.1.9
hypit version --check
# 升级全局安装的 Skill
npx skills update hypit -g
hypit version --check 只报告本机正在运行的版本和仓库里的最新版本,不会自动安装更新,也不会改动你的项目。官方还说明,升级之后已有的视频项目和生成好的素材不需要重新制作。
早期版本意味着两件事。好的一面是,功能在快速补齐,社区反馈能很快被响应。不好的一面是,语法和命令随时可能调整,今天能跑的写法,下个版本也许就要改。所以我的建议是:动手之前先用 hypit version --check 看一眼本地版本和最新版本的差距,遇到文档和实际行为对不上,优先以官方最新文档和 Release 说明为准。
说到这里,Hypit 的“身份”基本清楚了。接下来进入最核心的部分:SVML 到底长什么样,台词和画面是怎么拴在一起的。莫潇羽@无忆研习社 会尽量用中文例子来讲,毕竟官方示例几乎全是英文。
三、读懂 SVML:先写好台词,其他一切跟着台词走
SVML 是什么:先认识“标记语言”
没有编程背景的朋友,看到一堆尖括号可能会发怵。其实“标记语言”的思路非常朴素,我们平时就在用。
写作文时,给书名加上书名号《》,读者就知道这是一本书;编辑改稿时,在某句话下面画波浪线,排版的人就知道这里要加粗。标记语言就是用约定好的符号,给内容贴上“这是什么、该怎么处理”的标签。符号本身不是内容,而是关于内容的说明。
SVML 的全称是 Semantic Video Markup Language,官方文档里直接用“语义视频标记语言”来解释这个缩写。它的标签用尖括号包起来,写法和 XML 一脉相承。一个标签通常由下面几部分组成:
|
组成部分 |
例子 |
白话理解 |
|
开始与结束标签 |
|
一对“括号”,中间夹着的就是这部分内容 |
|
自闭合标签 |
|
不夹内容的标签,自己就是一个完整标记 |
|
属性 |
|
给标签补充的参数,名字等于值 |
|
引用 |
|
花括号里写路径,指向别处定义好的东西 |
|
导入 |
|
声明“这份文件要用到哪个功能包” |
如果你接触过网页制作,会觉得这套写法有点眼熟。网页的结构用 HTML 这种标记语言来写,外观用 CSS 样式表单独描述,SVML 借鉴了类似的分工:内容写在 .svml 里,外观写在 .svs 里。两者真正的区别在于要描述的对象不同。网页主要描述“某一刻页面上的东西怎么摆”,SVML 要描述的是“随着台词一句句展开,画面、字幕、声音之间的先后和对应关系”。也正因为这层区别,SVML 里最核心的组件不是画面,而是台词。
对新手来说,记住一点就够了:你不需要从零手写 SVML。日常工作里,文件主要由 Agent 生成和修改,你要做的是能看懂它大概在描述什么,发现不对时知道该让 Agent 改哪里。下面几节的语法讲解,也按“能看懂”的标准来读就行。
三类文件各管一摊
Hypit 项目里最常打交道的是三种文件,扩展名不同,职责也分得很开:
|
文件类型 |
扩展名 |
装的是什么 |
类比 |
|
Author Source |
|
视频内容:台词、素材、生成指令、轨道、合成 |
剧本加分镜 |
|
Stylesheet |
|
视觉规则:颜色、字号、位置、进出场动效 |
网页的样式表 |
|
Run Source |
|
这一次要产出什么、复用哪些旧结果 |
开工单 |
这种“内容、样式、执行”三分离的设计,好处在批量做变体时会非常明显:换产品只动 .svml 里的文本,换视觉风格只动 .svs,复用上一次生成好的镜头只动 .svrun,三者互不干扰。
SVML 文件内部由很多“组件”串起来,每个组件通过 import 引入一个功能包。整条视频里地位最特殊的,是 <script> 这个组件。
Script 的铁律:只写“说什么”
官方文档对 Script 的定位非常克制:它只装旁白或角色说出口的每一个字,不写时间码、不引用素材、不写样式、不写生成参数。管线里所有其他环节都读取 Script,而 Script 不读取任何其他东西。
我第一次读到这条规则时,觉得有点“洁癖”。后来想明白了,这正是整套系统能复用的前提。台词是一条视频最稳定的“语义骨架”,只要骨架干净,其他东西往上挂、往下拆都不会乱。
一个最小的 Script 长这样:
<import from="@hypit/script@1"/>
<script id="story">
<opening>
<HOST> 大家好,今天聊聊视频模板怎么复用。
</opening>
</script>
import 那一行激活了 Script 功能,id="story" 给这份台词起了个名字,方便其他组件引用。
段落:视频的“章节”
Script 里面由一个个段落(Segment)组成,段落就是按顺序排列的一块块口播内容。它有几个规定需要记住:
- 标签名本身就是段落的 id,在同一份 Script 里不能重名。
- 段落不能嵌套,每个段落都必须是
<script>的直接下级。 - 可以写成自闭合的空段落,比如
<pause/>,但空段落只代表“有这么个结构”,并不自动等于停顿,也不带默认时长。 - 命名遵循 XML 规则,可以用字母、数字、连字符和下划线。
我自己的习惯是按“功能”给段落命名,而不是按顺序编号。比如 hook、pain、demo、close,而不是 part1、part2。原因很简单:后面做变体时经常要调换顺序、插入新段落,用功能命名,引用关系一眼就能看懂。
其他组件引用段落时,写法类似 {story.segment.hook};如果要取这个段落的某种文本形式,就写 {story.segment.hook.speech} 这样的路径。
角色提示:谁在说话
多人对话的视频,需要标明每句话是谁说的,这就是角色提示(Role Cue):
<interview>
<HOST> 你平时做一条视频要多久?
<GUEST> 口播半小时,剪辑两个多小时。
</interview>
角色提示有几个容易踩的点。它没有闭合标签,一个角色的发言会一直延续到下一个角色提示或段落结束。一个段落里要么全部句子都标角色,要么全都不标,混着写会报错。角色标签长度限制在 1 到 32 个字符。
另外要特别注意,角色提示只是“标注谁在说”,它不会自动选择音色,也不会创建人物。音色和形象是在生成、配音环节另外指定的。
同一段带角色的台词,会被投影出三种文本形式,用在不同地方:
|
投影类型 |
内容 |
典型用途 |
|
dialogue |
带角色前缀,如“HOST: 你平时……” |
喂给视频生成模型,让它知道谁说哪句 |
|
speech |
去掉角色前缀的纯朗读文本 |
送去配音和对齐 |
|
caption |
去掉角色前缀的显示文本 |
生成字幕 |
双文本:屏幕上写的和嘴里说的不一样
做中文科普视频时,这个功能我觉得是最实用的。很多时候,字幕上想显示的和实际念出来的并不一致。英文缩写就是典型例子,屏幕上写“API”,嘴里要念“A P I”。
SVML 用双文本(Dual Text)解决,格式是 <显示内容|朗读内容>,竖线左边进字幕,右边进配音:
<explain>
<HOST> 我们用的是 <API|A P I> 接口,价格按 <1K|一千> 次调用计算。
</explain>
字幕会显示“我们用的是 API 接口,价格按 1K 次调用计算”,配音念的是“A P I”和“一千”。左边允许留空,比如 < |嗯> 表示“嗯”要念出来,但字幕里不显示,很适合保留口语语气又不让字幕显得啰嗦。
当显示和朗读完全一样时,可以省略竖线右边,写成 <组件化|>。这个写法看似多此一举,其实有用:它把几个字打包成一个完整的字幕单元,字幕样式可以整组高亮,而配音里每个字仍然单独计时。官方文档还特别提到,中文、日文的汉字会按“单字”切分成词元,避免一整句中文被当成一个超长单词处理。
还有一个符号 ||,叫字幕分句标记,用来人为指定字幕在哪里换条。它只能出现在完整的对齐单元之间,不能插进双文本内部。
选区和时刻:给画面留好“挂钩”
前面说的都是“台词本身”。真正让画面能拴在台词上的,是两种零宽度的标记:选区(Selection)和时刻(Moment)。零宽度的意思是,它们不会出现在字幕和配音里,只是在文本中间插了一个看不见的钉子。
选区表示“一段范围”,成对出现:
<script id="story">
<pain>
<HOST> @problem 改一句台词,后面的字幕全要重新对。 @/problem
</pain>
<answer>
<HOST> @fix 把画面拴在词上,这个问题就没了。 @/fix
</answer>
</script>
时刻表示“一个时间点”,写法是名字后面加感叹号:
<reveal>
<HOST> 一共有 @cards! 三个关键步骤。
</reveal>
@cards! 的意思是“在下一个词开始的那一刻”,后续你可以让一张卡片恰好在主播说出“三个”时弹出。
边界吸附方向的规则整理如下:
|
标记写法 |
含义 |
|
|
选区开始,吸附到下一个词的开头(默认) |
|
|
选区开始,吸附到上一个词的结尾 |
|
|
选区结束,吸附到上一个词的结尾(默认) |
|
|
选区结束,吸附到下一个词的开头 |
|
|
时刻,吸附到下一个词的开头 |
|
|
时刻,吸附到上一个词的结尾 |
有两点比 XML 标签更灵活。不同名字的选区可以交叉,不要求像标签那样严格嵌套,比如 @a 一 @b 二 @/a 三 @/b 是合法的。选区和时刻共用一套命名空间,同一个名字不能既当选区又当时刻。
引用方式分别是 {story.selection.problem} 和 {story.moment.cards}。
锚点是怎么数出来的
Script 编译之后,会形成一串有序的“语义锚点”,所有选区和时刻最终都落在这些锚点上。官方文档给了一个很清楚的计数规则,我换成纯文本写出来:
锚点总数 = 2 × 词元数 + 2 × 段落数 + 2
其中:
每个词元有“开始”和“结束”两个锚点
每个段落有“开始”和“结束”两个锚点
最后的 2 是整条节目的起点和终点
举个例子,一份 Script 有 3 个段落、一共 40 个词元(中文按单字计),锚点总数就是 2 × 40 + 2 × 3 + 2 = 88 个。
这个规则的意义在于:Script 里自始至终没有一个秒数,也没有一个帧号。锚点只是“位置身份”,真正的时间要等到配音生成、对齐完成之后才算出来。这就是第一章说的“意图”被完整保留下来的技术实现。
注释、转义和词属性
最后补几个写台词时会用到的细节。
注释用 <!-- 这里是注释 -->,不会进入任何文本投影,适合给自己或 Agent 留备忘。台词里如果真的需要显示 @、< 或反斜杠,要分别写成 \@、\<、\\,否则会被当成语法符号。
单个词后面还能挂一个平铺的属性块,比如 重要{emphasis,keyword},字幕组件可以据此给这个词单独上色或加粗。属性不带任何时间含义,也不能嵌套。
写到这里,SVML 里“说什么”这一层就讲完了。下一章接着看,这份台词是怎么一步步变成带画面、带字幕、带声音的成片的。
四、从台词到成片:一条视频在 Hypit 里走过的完整路径
先看全景
上一章的 Script 只是起点。一条带口播的视频,在 Hypit 里大致要经过六个环节。我把官方文档里的数据流重新画了一遍,方便对照:
flowchart TD
S[Script 台词] --> G[生成或导入口播素材]
G --> N[Normalize 统一帧率与时长]
N --> A[SemanticTake 词级对齐]
S --> A
A --> TL[Timeline 拼接成完整时间线]
TL --> P[Performance 口播画面轨]
TL --> SD[Sound 声音轨]
TL --> CP[Caption 字幕轨]
TL --> MT[Media Track 叠加素材与 B-roll]
TL --> TX[Text 文字标题轨]
P --> F[Film 合成]
SD --> F
CP --> F
MT --> F
TX --> F
F --> R[Render 渲染为 MP4]
这张图里最关键的节点是 Timeline。在它之前,一切都是“语义”,没有确定的时间;在它之后,所有轨道都从同一份时间线里读取帧位置。下面按顺序拆开讲。
统一素材:Normalize
口播素材可能来自模型生成,也可能是你自己拍的。不同来源的视频,帧率、时长、音轨情况五花八门,直接拼在一起一定出问题。所以第一步要做“标准化”。
<program:Clock id="clock" frame-rate="30"/>
<pipeline:Normalize id="hook-media" source={hook-video.video}
video="primary-moving" audio="default"
span-authority="video" clock={clock}/>
Clock 是整条视频共用的时钟,只声明一次,这里设为每秒 30 帧。每一段口播素材都经过 Normalize,被换算到同一个帧的坐标系里。span-authority="video" 表示以画面时长为准。
官方文档专门强调,标准化这一步不包含任何台词含义,也不做语音识别,它只负责把“素材事实”确定下来,给后面的对齐打地基。这种“一步只干一件事”的设计,排查问题时特别省心。
词级对齐:SemanticTake
素材标准化之后,就轮到 WhisperX 登场了。SemanticTake 这个组件拿着一段标准化后的素材,和 Script 里对应的某一个段落做对齐:
<whisperx:SemanticTake id="hook-semantic"
narrative={story}
segment={story.segment.hook}
media={hook-media.media}
language="zh"/>
它的输出里包含:标准化后的素材本身、段落身份、每个词在这段素材里的本地帧窗口,以及这个段落的全部锚点。
这里有一个对中文创作者非常关键的限制:language 参数在每次对齐时都必须填写,官方文档写明目前只接受 en 和 zh 两个值,Hypit 也不会根据文本或音频自动判断语言。换句话说,中英文口播可以做,粤语、日语、韩语等其他语言的口播,暂时没法走这条对齐路线。想做多语种版本的朋友,这一点要提前心里有数。
官方建议按“段落大小”一段段对齐,一个段落对应一段素材。我理解这样做有两个好处:单段出错只需要重做这一段,不会牵连整条;另外,段落边界本身就是天然的“换镜头点”,和拍摄、生成的习惯正好吻合。
拼接时间线:Timeline
对齐好的各段素材,由 Timeline 按节目顺序拼起来:
<time:Timeline id="speech" clock={clock}>
<time:Take source={hook-semantic.take}/>
<time:Take source={pain-semantic.take} at="previous.end+1s"/>
<time:Take source={demo-semantic.take} at="previous.end-10f"/>
</time:Timeline>
不写 at 时,每段默认紧跟在上一段后面。previous.end+1s 表示上一段结束后留 1 秒空隙,previous.end-10f 表示和上一段重叠 10 帧,适合做声音交叉过渡。时间线的结尾也可以用 end="content.end+2s" 多留 2 秒尾巴,或者用 end="30s" 定死总长。
有一条规则容易被忽略:时间线上没有素材覆盖的区域,系统不会自动填充占位画面。如果你留了空隙又没安排其他画面,那一段就是空的。
每一段素材在全局里的帧位置,等于它的放置起点加上它自己内部的本地帧号。这个换算完全是确定的,也就是说,同样的输入每次算出来的帧位置都一样。
各路轨道各自读取时间线
时间线建好之后,字幕、叠加素材、文字标题、声音、口播画面这些“轨道”就可以各干各的了。它们都接收同一个 timeline={speech.timeline},再用 during 属性说明自己在什么时候出现:
|
|
含义 |
|
|
整个 demo 段落期间 |
|
|
problem 选区覆盖的范围 |
|
|
cards 时刻那个时间点 |
|
|
整条节目全程 |
比如让一张示意卡片在 problem 选区期间出现:
<media-track:Track id="cards" timeline={speech.timeline} canvas={vertical}>
<media-track:Item image={pain-card.image}
during={story.selection.problem}
frame={card-frame}
appearance={recipes.media.card}
motion={recipes.motion.card}/>
</media-track:Track>
字幕轨则直接读取 Script 自动产出的字幕文档:
<caption-fine:Track id="captions"
document={story.caption}
timeline={speech.timeline}>
<caption-fine:Use style={primary-caption}/>
</caption-fine:Track>
注意看,这些代码里一个秒数都没有出现。卡片什么时候出、字幕每个字什么时候亮,全部由选区、时刻和对齐结果推导出来。台词一改,重新构建,位置自动更新。这就是语义锚定落到代码层面的样子。
样式表:把“长什么样”单独拎出来
轨道组件里的 appearance={recipes.media.card} 这类引用,指向的是 .svs 样式表。它的写法和网页 CSS 很像:
<?svml using="@hypit/svs@1"?>
<sheet version="1">
film.vertical { background: #0B0B10; }
media.card {
stack-order: 40; fit: cover;
clip: rounded; radius: 24;
}
motion.card {
enter: slide; enter-frames: 5; enter-direction: up;
exit: fade; exit-frames: 4;
}
caption.base {
stack-order: 70; x: 0.06; y: 0.74; width: 0.88;
size: 60; align: center;
fill: #FFFFFF; background: #0B0B10CC;
padding: 14 22; radius: 16;
}
</sheet>
stack-order 决定图层上下关系,数值小的在下面,数值大的盖在上面。官方文档给出的典型分层是这样的:
|
stack-order |
通常放什么 |
|
10 左右 |
口播画面 |
|
40 左右 |
叠加素材、B-roll |
|
70 左右 |
字幕 |
|
90 左右 |
文字标题 |
我的习惯是给每一层之间留足间隔,后面临时插一个“贴纸层”或“水印层”时,不用把所有数字都改一遍。
合成与渲染:Film 和 Render
所有轨道最终交给 Film 合成:
<film:Film id="main" canvas={vertical}
timeline={speech.timeline} appearance={recipes.film.vertical}>
<film:Track source={performance.visual}/>
<film:Track source={voice.audio}/>
<film:Track source={cards.visual}/>
<film:Track source={captions.track}/>
</film:Film>
<render:Video id="final"
composition={main.composition} timeline={speech.timeline}/>
Film 负责校验所有轨道,产出一份“合成描述”。render:Video 再调用 HyperFrames 渲染器,大致经过五步:把合成描述编译成逐帧的网页文档,用 Chrome 或 Chromium 逐帧渲染,把帧序列编码成视频,混合音轨,最后把画面和声音封装成 MP4。
这里有个细节,Film 里轨道的书写顺序不影响图层上下,上下关系只看样式表里的 stack-order。所以调整代码顺序不会意外把字幕压到画面底下,这点比很多剪辑软件“轨道位置即图层位置”的逻辑更不容易出错。
原理部分到此告一段落。莫潇羽@无忆研习社 建议新手不必一次记住所有组件名,理解“台词定锚点、对齐算时间、轨道读时间线、合成再渲染”这条主线就够了,具体语法遇到时再查文档。下一章开始动手。
五、动手:从装好环境到导出第一条成片
动手前的环境清单
先把需要准备的东西列清楚,免得装到一半卡住:
|
项目 |
要求 |
说明 |
|
Node.js |
22 及以上 |
版本过低会直接装不上,建议用 22 的较新小版本 |
|
编程 Agent |
支持 Skill 的即可 |
官方点名的是 Claude Code 和 Codex |
|
FFmpeg |
需要 |
渲染时负责视频编码与音频混合 |
|
Chrome 或 Chromium |
需要 |
渲染器靠它逐帧绘制画面 |
|
语音对齐能力 |
本地 WhisperX 或托管服务二选一 |
本地运行对显卡有一定要求 |
|
生成模型 |
可选 |
纯代码渲染的视频不需要 |
“Skill”这个词第一次出现,解释一下:它是一种给 Agent 使用的能力包,里面装着某一类任务的专业知识、操作规范和配套脚本。装上之后,Agent 遇到相关任务就会按照包里的方法去做,相当于给 Agent 请了个专项教练。
检查 Node.js 版本只需要一行命令:
node -v
# 输出 v22 开头或更高即可
版本不够的话,用 nvm 这类版本管理工具升级最省事。国内网络下载 npm 包偶尔会慢,可以把 npm 源切换到国内镜像:
npm config set registry https://registry.npmmirror.com
需要提醒一句,Hypit 的 Skill 和部分服务托管在境外代码平台上,访问受网络环境影响。遇到下载失败就稍后重试,不要去折腾任何突破网络管理的做法,合规永远排在效率前面。
安装 Skill
在终端执行官方给出的安装命令:
npx skills add hypit-ai/hypit -g
-g 表示全局安装,之后你打开任何项目文件夹,Agent 都能调用这个技能。
官方文档说得很清楚:Skill 负责提供制作知识,hypit 这个 npm 包负责提供可执行工具。你不需要把 Hypit 的代码仓库克隆到本地。第一次使用时,Agent 会自己检查可执行工具是否就绪,缺什么会告诉你并协助准备。
建一个干净的项目文件夹
我强烈建议每条视频或每个系列单独建一个文件夹。官方文档推荐过一种目录布局,我在它基础上加了几行中文注释:
my-video/
package.json 项目边界标记
authors/
main.svml 视频内容主文件
recipes/
visual.svs 视觉样式
runs/
final.svrun 成片构建意图
assets/ 自己提供的素材(需确认有使用授权)
output/ 导出给人看的成片
hypit.runtime.json 运行环境配置
.hypit/ 自动生成的运行数据与构建结果
官方特别说明,这只是给人看的推荐布局,Hypit 并不强制这些文件夹名,它只认你在源文件和命令里写明的路径。小项目把几个文件平铺在根目录也完全没问题。
有一点必须遵守:.hypit/ 目录、各种凭据、生成出来的媒体文件和日志,都不要提交到代码仓库。如果你用 Git 管理项目,记得把它们写进忽略清单。
和 Agent 说出你的第一个需求
在项目文件夹里打开 Agent,用 /hypit 调用技能。新手我建议从“文字描述”入口开始,不涉及任何参考视频,版权上最干净。比如:
/hypit 帮我做一条 25 秒左右的竖屏知识短视频,主题是“为什么
视频模板复用这么难”。开头用一个反问句抓注意力,中间用两张
示意卡片解释原因,结尾引导观众收藏。先不要调用任何付费模型,
用字幕和动态图形完成。
最后一句“先不要调用任何付费模型”很重要。第一次上手的目标是跑通流程、熟悉文件结构,而不是追求画面效果。等流程通了,再逐步加入配音和生成素材。
Agent 接到需求后,会先解释它对需求的理解和打算怎么做,然后在项目里生成 SVML、SVS、SVRUN 文件。这个过程中它会持续汇报进展,你随时可以打断它、调整方向。
配置运行环境
如果你想自己动手执行命令,或者想看懂 Agent 在做什么,下面这几条是运行环境相关的核心命令:
# 生成一份入门级运行配置并选中它(不会覆盖已有文件)
hypit runtime init
# 或者选中一份已有的运行配置
hypit runtime use hypit.runtime.json
# 查看当前凭据状态
hypit auth status
# 为某个服务端点登录凭据
hypit auth login hypihub.default
runtime init 只负责写一份起步配置并选中,不安装任何东西,不联系任何服务,也不启动后台进程。凭据通过 auth login 安全录入,绝对不要把 API 密钥直接写进 .svml、.svrun 或配置源文件里。
检查、规划、看报价,再开跑
这是我认为整个流程里最值得养成习惯的部分:先确认,再花钱。
# 体检运行环境(只读,不发起付费请求)
hypit doctor
# 编译检查视频源文件,校验导入、类型和组件连接
hypit check authors/main.svml
# 查看本次构建计划:会发起哪些外部请求、带什么参数
hypit plan runs/final.svrun
# 读取本次构建涉及服务的费率信息
hypit pricing runs/final.svrun
几条命令的分工我整理成表:
|
命令 |
做什么 |
会不会花钱 |
|
|
检查运行环境、端点配置、凭据是否齐全 |
不会 |
|
|
编译视频源文件,找语法和连接错误 |
不会 |
|
|
列出本次构建的全部操作和外部请求 |
不会 |
|
|
按所选服务读取费率,分组展示请求数量 |
不会 |
|
|
真正提交构建任务 |
可能会 |
pricing 读到的是费率信息,不是保证的总价。有些输入的时长在生成之前是未知的,报告里会把不确定的部分如实保留。AI 视频相关服务的价格变动非常快,任何时候都请以服务商官方定价页面的实时数据为准。
提交构建并导出成片
确认无误后,提交构建:
hypit build runs/final.svrun --title 第一版 --follow
加了 --follow,终端会持续显示进度。这里有个设计要理解:真正干活的是后台 Worker 进程,终端只是“观察者”。你中途关掉终端,构建并不会停,之后可以重新接上观察:
hypit status <构建编号> --watch
构建完成后,查看结果并导出:
hypit inspect <构建编号>
hypit get <构建编号> --output final.video --to output/final.mp4
构建成功时,终端会直接打印出每个文件目标对应的导出命令,照着复制就行。注意 --to 指向的目标文件不能已经存在,这是为了防止误覆盖。
用 Studio 做可视化微调
成片导出后,Agent 可以帮你打开 Hypit Studio。它提供一个可视化时间线界面,你能在上面查看各轨道的排布,并直接编辑部分支持的属性。
我的建议是把 Studio 当成“检查器”而不是“主编辑器”。字幕位置不舒服、卡片出现得太早,在 Studio 里看清楚问题,再回到对话里让 Agent 改源文件,这样修改会沉淀在文本里,下次做变体时依然有效。
六、复用与批量:变体为什么能越做越省
Hypit 没有“隐式缓存”
很多人第一次看到“批量变体”几个字,会以为系统会自动记住上次生成过的东西,下次跳过。Hypit 恰恰相反,官方文档明确写着:没有隐式缓存。
每次执行 build 都会拿到一个全新的构建编号和独立的结果目录,哪怕源文件一个字没改。原因在于生成模型本身是“不确定”的,同样