这套 Starter Kit 用 Scene JSON、Block Contract、Theme Token、语义验证器和 Composition Builder,把 AI Agent 的输出限制为可验证数据,再生成引用 HyperFrames Block 的确定性视频工程。
使用说明
这套 Starter Kit 配合《HyperFrames Registry 实战》使用,目标是快速建立一个最小的数据驱动视频底座。
它不是完整 npm 包,而是一组可以复制进项目、再按实际 Registry 扩展的文件模板。
建议目录:
project/
data/
video.example.json
audio-map.example.json
schemas/
scene.schema.json
contracts/
terminal-command.json
themes/
theme.css
scripts/
validate-scenes.mjs
build-composition.mjs
registry/
blocks/
compositions/
assets/
snapshots/
output/
使用顺序:
复制模板
→ 修改 Block Contract
→ 让 Agent 输出 Scene JSON
→ 执行 Validator
→ 执行 Builder
→ HyperFrames check
→ Snapshot / Preview
→ 人工确认后 Render
文件一:video.example.json
{
"schema_version": "1.0",
"composition": {
"id": "main",
"width": 1920,
"height": 1080,
"duration": 15,
"fps": 30
},
"scenes": [
{
"scene_id": "01-install",
"block": "terminal-command",
"block_version": "1.0.0",
"start": 0,
"duration": 7,
"track": 1,
"theme": "code-editorial",
"motion": "type-and-confirm",
"props": {
"eyebrow": "INSTALL",
"command": "npm install hyperframes",
"output": "Installed successfully"
},
"audio": {
"cue": "install",
"sync": "word"
}
},
{
"scene_id": "02-render",
"block": "terminal-command",
"block_version": "1.0.0",
"start": 7,
"duration": 8,
"track": 1,
"theme": "terminal-green",
"motion": "type-and-confirm",
"props": {
"eyebrow": "RENDER",
"command": "npx hyperframes render --output out.mp4",
"output": "Video written to out.mp4"
},
"audio": {
"cue": "render",
"sync": "word"
}
}
]
}
修改规则
composition.id必须与主 Timeline key 一致scene_id全局唯一block必须存在于 Registry 或compositions/block_version必须匹配 Contractstart + duration不能超出 Composition- 同 Track 重叠必须是明确设计
- Theme 和 Motion 必须来自 Block 支持列表
文件二:scene.schema.json
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "https://example.local/schemas/scene.schema.json",
"title": "HyperFrames Scene",
"type": "object",
"required": [
"scene_id",
"block",
"block_version",
"start",
"duration",
"track",
"theme",
"motion",
"props"
],
"properties": {
"scene_id": {
"type": "string",
"pattern": "^[a-z0-9][a-z0-9-]*$"
},
"block": {
"type": "string",
"pattern": "^[a-z0-9][a-z0-9-]*$"
},
"block_version": {
"type": "string",
"pattern": "^[0-9]+\\.[0-9]+\\.[0-9]+$"
},
"start": {
"type": "number",
"minimum": 0
},
"duration": {
"type": "number",
"exclusiveMinimum": 0,
"maximum": 120
},
"track": {
"type": "integer",
"minimum": 0,
"maximum": 50
},
"theme": {
"type": "string",
"pattern": "^[a-z0-9][a-z0-9-]*$"
},
"motion": {
"type": "string",
"pattern": "^[a-z0-9][a-z0-9-]*$"
},
"props": {
"type": "object"
},
"audio": {
"type": "object",
"required": ["cue", "sync"],
"properties": {
"cue": {
"type": "string"
},
"sync": {
"enum": ["scene", "sentence", "word"]
}
},
"additionalProperties": false
},
"allow_overlap": {
"type": "boolean",
"default": false
}
},
"additionalProperties": false
}
这份是通用 Scene Schema。每个 Block 的具体 Props 应再用独立 Contract 或 Props Schema 验证。
文件三:Block Contract 模板
文件:
contracts/{{block-name}}.json
{
"name": "{{block-name}}",
"version": "1.0.0",
"type": "hyperframes:block",
"description": "{{一句话说明 Block 的用途}}",
"dimensions": {
"width": 1920,
"height": 1080
},
"duration": {
"min": 3,
"default": 6,
"max": 15
},
"themes": [
"code-editorial",
"terminal-green"
],
"motion_presets": [
"default"
],
"props": {
"title": {
"type": "string",
"required": true,
"maxLength": 60
},
"subtitle": {
"type": "string",
"required": false,
"maxLength": 120,
"default": ""
}
},
"media": {
"images": 0,
"videos": 0,
"audio": 0
},
"checkpoints": [
0.1,
0.35,
0.7,
0.95
]
}
Contract 应该回答的问题
- Block 叫什么
- 当前版本是什么
- 支持哪个画幅
- 最短和最长时长
- 支持哪些 Props
- 文字长度限制
- 支持哪些 Theme
- 支持哪些 Motion Preset
- 需要哪些媒体
- Snapshot 应检查哪些相对时间点
文件四:registry-item.json 模板
Block Registry 目录:
registry/blocks/{{block-name}}/
{{block-name}}.html
registry-item.json
registry-item.json:
{
"$schema": "https://hyperframes.heygen.com/schema/registry-item.json",
"name": "{{block-name}}",
"type": "hyperframes:block",
"title": "{{Human Readable Title}}",
"description": "{{One sentence description}}",
"dimensions": {
"width": 1920,
"height": 1080
},
"duration": 8,
"tags": [
"{{category}}",
"{{use-case}}"
],
"files": [
{
"path": "{{block-name}}.html",
"target": "compositions/{{block-name}}.html",
"type": "hyperframes:composition"
}
]
}
Component 模板没有固定尺寸和时长:
{
"$schema": "https://hyperframes.heygen.com/schema/registry-item.json",
"name": "{{component-name}}",
"type": "hyperframes:component",
"title": "{{Human Readable Title}}",
"description": "{{One sentence description}}",
"tags": [
"effect",
"overlay"
],
"files": [
{
"path": "{{component-name}}.html",
"target": "compositions/components/{{component-name}}.html",
"type": "hyperframes:snippet"
}
]
}
文件五:theme.css
:root {
--hf-bg: #12131c;
--hf-surface: #1a1c29;
--hf-surface-raised: #232635;
--hf-foreground: #f6f7fb;
--hf-muted: #9296a8;
--hf-accent: #ff6b4a;
--hf-success: #48f7b2;
--hf-danger: #ff5f57;
--hf-font-main: "Inter", system-ui, sans-serif;
--hf-font-display: "Inter Tight", "Inter", sans-serif;
--hf-font-code: "Fira Code", ui-monospace, monospace;
--hf-text-hero: 124px;
--hf-text-title: 88px;
--hf-text-body: 42px;
--hf-text-caption: 30px;
--hf-radius-sm: 12px;
--hf-radius-md: 20px;
--hf-radius-lg: 32px;
--hf-safe-margin: 96px;
--hf-gap-sm: 20px;
--hf-gap-md: 40px;
--hf-gap-lg: 72px;
--hf-motion-fast: 0.35s;
--hf-motion-normal: 0.65s;
--hf-motion-slow: 1.1s;
}
[data-theme="terminal-green"] {
--hf-bg: #07110f;
--hf-surface: #10221c;
--hf-surface-raised: #163128;
--hf-foreground: #f4fff9;
--hf-muted: #86a095;
--hf-accent: #48f7b2;
}
[data-theme="swiss-light"] {
--hf-bg: #f2f0e9;
--hf-surface: #ffffff;
--hf-surface-raised: #e8e5dc;
--hf-foreground: #111111;
--hf-muted: #656565;
--hf-accent: #173cff;
}
Theme 使用规则
- Block 内部优先使用
var(--hf-*) - Scene 只选择 Theme 名称
- 不让 Agent 直接传任意颜色值
- 新 Theme 必须经过对比度和 Snapshot 检查
- 字体文件应该保存到项目资产目录
- 如果 Block 不支持某 Theme,Validator 应该失败
文件六:audio-map.example.json
{
"version": "1.0",
"duration": 15,
"cues": {
"install": {
"start": 0.6,
"duration": 4.8,
"events": {
"command": {
"start": 1,
"duration": 1.8
},
"result": {
"start": 3.4,
"duration": 0.7
}
}
},
"render": {
"start": 7.4,
"duration": 5.2,
"events": {
"command": {
"start": 7.9,
"duration": 2.1
},
"result": {
"start": 11.2,
"duration": 0.8
}
}
}
}
}
Audio Map 规则
- 使用一个统一格式,不让每个 Block 直接适配不同 TTS 输出
- 明确绝对时间还是 Scene 相对时间
- Builder 负责时间换算
- Cue 必须位于 Scene 时间窗口内
- 不把毫秒时间直接等同于最终画面精度
- 最终视觉事件仍然要映射到视频帧
文件七:validate-scenes.mjs 骨架
import fs from "node:fs";
import path from "node:path";
import Ajv from "ajv";
const root = process.cwd();
function readJson(relativePath) {
return JSON.parse(
fs.readFileSync(path.join(root, relativePath), "utf8")
);
}
function fileExists(relativePath) {
return fs.existsSync(path.join(root, relativePath));
}
const video = readJson("data/video.json");
const sceneSchema = readJson("schemas/scene.schema.json");
const audioMap = fileExists("data/audio-map.json")
? readJson("data/audio-map.json")
: null;
const ajv = new Ajv({ allErrors: true, strict: true });
const validateScene = ajv.compile(sceneSchema);
const errors = [];
const sceneIds = new Set();
for (const scene of video.scenes) {
if (!validateScene(scene)) {
errors.push({
type: "schema",
scene: scene.scene_id,
details: validateScene.errors
});
continue;
}
const contractPath = `contracts/${scene.block}.json`;
if (!fileExists(contractPath)) {
errors.push({
type: "missing-contract",
scene: scene.scene_id,
block: scene.block
});
continue;
}
const contract = readJson(contractPath);
if (sceneIds.has(scene.scene_id)) {
errors.push({
type: "duplicate-scene-id",
scene: scene.scene_id
});
}
sceneIds.add(scene.scene_id);
if (scene.block_version !== contract.version) {
errors.push({
type: "block-version-mismatch",
scene: scene.scene_id,
expected: contract.version,
actual: scene.block_version
});
}
if (!contract.themes.includes(scene.theme)) {
errors.push({
type: "unsupported-theme",
scene: scene.scene_id,
theme: scene.theme
});
}
if (!contract.motion_presets.includes(scene.motion)) {
errors.push({
type: "unsupported-motion",
scene: scene.scene_id,
motion: scene.motion
});
}
if (
scene.duration < contract.duration.min ||
scene.duration > contract.duration.max
) {
errors.push({
type: "duration-out-of-range",
scene: scene.scene_id
});
}
if (scene.start + scene.duration > video.composition.duration) {
errors.push({
type: "scene-exceeds-composition",
scene: scene.scene_id
});
}
if (
scene.audio?.cue &&
(!audioMap || !audioMap.cues[scene.audio.cue])
) {
errors.push({
type: "missing-audio-cue",
scene: scene.scene_id,
cue: scene.audio.cue
});
}
}
for (let i = 0; i < video.scenes.length; i += 1) {
for (let j = i + 1; j < video.scenes.length; j += 1) {
const a = video.scenes[i];
const b = video.scenes[j];
if (a.track !== b.track) continue;
const overlaps =
a.start < b.start + b.duration &&
b.start < a.start + a.duration;
if (overlaps && !a.allow_overlap && !b.allow_overlap) {
errors.push({
type: "same-track-overlap",
scenes: [a.scene_id, b.scene_id]
});
}
}
}
if (errors.length > 0) {
console.error(JSON.stringify({ ok: false, errors }, null, 2));
process.exit(1);
}
console.log(JSON.stringify({
ok: true,
scenes: video.scenes.length,
duration: video.composition.duration
}, null, 2));
文件八:build-composition.mjs 骨架
import fs from "node:fs";
import path from "node:path";
const root = process.cwd();
const video = JSON.parse(
fs.readFileSync(path.join(root, "data/video.json"), "utf8")
);
function escapeAttribute(value) {
return String(value)
.replaceAll("&", "&")
.replaceAll("'", "'")
.replaceAll('"', """)
.replaceAll("<", "<")
.replaceAll(">", ">");
}
function renderScene(scene) {
const variables = {
...scene.props,
theme: scene.theme,
motion: scene.motion
};
return `
<div
data-composition-id="${escapeAttribute(scene.block)}"
data-composition-src="./${escapeAttribute(scene.block)}.html"
data-start="${scene.start}"
data-duration="${scene.duration}"
data-track-index="${scene.track}"
data-width="${video.composition.width}"
data-height="${video.composition.height}"
data-variable-values='${escapeAttribute(JSON.stringify(variables))}'
></div>`;
}
const html = `<!doctype html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8" />
<meta
name="viewport"
content="width=${video.composition.width}, height=${video.composition.height}"
/>
<title>Generated HyperFrames Composition</title>
<style>
html, body {
margin: 0;
width: ${video.composition.width}px;
height: ${video.composition.height}px;
overflow: hidden;
}
#root {
position: relative;
width: ${video.composition.width}px;
height: ${video.composition.height}px;
overflow: hidden;
}
</style>
</head>
<body>
<div
id="root"
data-composition-id="${escapeAttribute(video.composition.id)}"
data-start="0"
data-width="${video.composition.width}"
data-height="${video.composition.height}"
data-duration="${video.composition.duration}"
>
${video.scenes.map(renderScene).join("\n")}
</div>
<script src="./vendor/gsap.min.js"></script>
<script>
window.__timelines = window.__timelines || {};
window.__timelines["${escapeAttribute(video.composition.id)}"] =
gsap.timeline({ paused: true });
</script>
</body>
</html>`;
const output = path.join(root, "compositions/index.html");
fs.mkdirSync(path.dirname(output), { recursive: true });
fs.writeFileSync(output, html);
console.log(JSON.stringify({
ok: true,
output: "compositions/index.html",
scenes: video.scenes.length
}, null, 2));
文件九:package.json scripts
{
"scripts": {
"video:validate": "node scripts/validate-scenes.mjs",
"video:build": "node scripts/build-composition.mjs",
"video:check": "npm run video:validate && npm run video:build && hyperframes check --strict-variables",
"video:preview": "hyperframes preview",
"video:snapshot": "hyperframes snapshot --at 0.5,3.5,6.5,8,11,14.5",
"video:render": "hyperframes render --quality high --output output/video.mp4"
}
}
日常使用:
npm run video:check
npm run video:snapshot
npm run video:preview
# 最终确认后
npm run video:render
如果项目脚手架已经固定了 HyperFrames CLI 版本,应沿用项目现有命令,不要为了复制模板而取消版本固定。
文件十:AI Layout Driver Prompt
你是当前项目的 HyperFrames Layout Driver。
你的主要输出是符合 Schema 的 Scene JSON,不是任意 HTML、CSS 或 JavaScript。
开始前必须读取:
- BRIEF.md
- STORYBOARD.md
- frame.md
- data/video.json
- schemas/scene.schema.json
- contracts/*.json
- 当前 Registry Catalog
执行规则:
1. 为每个 Scene 选择已经注册且版本匹配的 Block。
2. Theme 和 Motion 只能使用 Block Contract 声明的枚举值。
3. Props 必须满足长度、类型和必填要求。
4. 不直接输出颜色值、任意 CSS 或远程媒体 URL。
5. 使用 Audio Map 中的 Cue 对齐场景和动作时间。
6. 如果 Registry 没有合适能力,先报告缺失 Block,不要重写整个项目。
7. 修改后运行 video:validate 和 video:build。
8. 然后执行 HyperFrames check 和关键帧 Snapshot。
9. 最终 Preview 未确认前,不执行高质量 Render。
输出格式:
- 修改后的 Scene JSON
- 使用的 Block、版本、Theme 和 Motion
- Validator 结果
- Check 结果
- Snapshot 时间点
- 仍需人工确认的问题
Block Authoring Checklist
Registry
- Block 名使用稳定 kebab-case
-
registry-item.json字段完整 - Registry 类型是
hyperframes:block - 目标路径正确
- 标签能表达用途
- 有清晰版本号
Composition
- Sub-composition 根位于
<template>内 - 样式和脚本也位于模板内
- 根有 Composition ID、宽、高、起点和时长
- Timeline key 与 Composition ID 完全一致
- 使用一个同步创建的 paused Timeline
- 可见片段具有正确的时间属性
- 背景由全画幅子元素承载
ID
- 所有 ID 使用 2~3 字母 Block 前缀
- 组装多个实例后没有重复 ID
- 媒体元素 ID 唯一
Variables
- 变量有类型、标签和默认值
- Enum 变量有 options
- 文本有 maxLength
- 直接文本和图片优先使用声明式绑定
- 复杂变量只在初始化时读取一次
- Preview 在没有覆盖变量时仍然正常
Determinism
- 没有
Math.random() - 没有
Date.now()或performance.now() - 没有无限
repeat: -1 - 没有关键运行时网络请求
- Timeline 不在异步回调中创建
- 媒体播放交给 HyperFrames
- 相同时间点重复 Snapshot 结果稳定
Visual QA
- Block 有明确安全边距
- 标题达到视频可读字号
- 长文本有明确长度上限
- Theme 对比度通过检查
- 高潮后有停留时间
- 最短、默认和最长时长都检查过
- 所有支持 Theme 都生成过 Snapshot
Registry 上线前检查
npx hyperframes lint
npx hyperframes check
npx hyperframes snapshot --at {{时间点}}
npx hyperframes preview
如果 Block 需要贡献到共享 Registry,还应该:
- 格式化 HTML
- 更新 Registry Manifest
- 生成目录预览图或视频
- 验证 Registry 文件
- 提交清晰的变更说明
推荐的第一批 Block
| Block | 主要 Props | 推荐 Motion |
|---|---|---|
title-card |
eyebrow、title、subtitle | title-rise-reveal |
terminal-command |
command、output | type-and-confirm |
process-flow |
nodes、result | diagram-build |
big-number |
value、label、source | number-count-up |
cta |
logo、message、action | logo-resolve |
不要一次建立几十个 Block。先让第一批 Block 经历真实视频项目,再根据使用频率和失败记录扩展。
推荐的成熟度路线
第 1 周
建立 Title、Terminal、CTA 三个 Block
第 2 周
加入 Scene Schema、Validator 和 Builder
第 3 周
加入 Theme 与 Motion Recipe
第 4 周
加入 Audio Map 和真实项目 Benchmark
后续
按真实需求扩展 Block,而不是按想象建立组件库
配套内容
- HyperFrames 原理详解
- HyperFrames Skills 第一条视频实战
- HyperFrames 画面质量与生产效率
- 从 AI Coder 到 AI Layout Driver
- HyperFrames 官方 Registry 使用指南
- HyperFrames Registry 完整实战
- HyperFrames Prompt、Brief 与渲染检查清单
RELATED / 相关推荐
接着读这些
按同一栏目、标签与技术栈为你挑选。
HyperFrames Registry 实战:Block + JSON Schema 视频流水线
从零创建可复用 HyperFrames Block、Scene JSON Schema、语义验证器和 Composition Builder,让 AI Agent 从现场写代码转向数据驱动的视频组装。
HyperFrames AI 视频 Prompt、Brief 与渲染检查清单
一套可复制的 HyperFrames AI 视频生产模板,包含主 Prompt、BRIEF、Storyboard、场景说明、修改指令和渲染前检查清单。
玩转 HyperFrames:从 AI Coder 到 AI Layout Driver
通过 Block Registry、Scene JSON、设计 token 和音频时间数据,把 HyperFrames 从每次现场写代码升级为可复用、可验证的视频生产系统。