核心概念

合成

Hyperframes 视频的基本构建单元。

合成(Composition)是定义视频时间线的 HTML 文档。每个片段——视频、图片、音频——都存在于一个合成之中。

结构

每个合成都需要一个带有 data-composition-id 的根元素:

<div id="root" data-composition-id="root"
data-start="0" data-width="1920" data-height="1080">
<!-- 元素放在这里 -->
</div>

index.html 文件是顶层合成。它可以在内部包含嵌套合成。任何合成都可以被导入到另一个合成中——没有特殊的"根"类型。

片段类型

片段(Clip)是时间线上任意一个离散的块,用带有数据属性的 HTML 元素表示:

  • <video> -- 视频片段、B-roll、A-roll
  • <img> -- 静态图片、叠加层
  • <audio> -- 音乐、音效
  • <div data-composition-id="..."> -- 嵌套合成(动画、分组序列)

每种片段类型的完整属性列表请参阅 HTML Schema Reference

嵌套合成

你可以通过两种方式将一个合成嵌入另一个合成:从外部文件加载或在内联定义。外部文件是可复用合成的推荐方式。

外部文件

使用 data-composition-src 引用另一个 HTML 文件。框架会自动获取该文件、提取 <template> 内容、挂载它、执行脚本并注册时间线。

<div
id="el-5"
data-composition-id="intro-anim"
data-composition-src="compositions/intro-anim.html"
data-start="0"
data-track-index="3"
></div>

每个外部合成文件用 <template> 标签包裹其内容:

<template id="intro-anim-template">
<div data-composition-id="intro-anim" data-width="1920" data-height="1080">
<div class="title">Welcome!</div>

<style>
[data-composition-id="intro-anim"] .title {
font-size: 72px; color: white; text-align: center;
}
</style>

<script>
const tl = gsap.timeline({ paused: true });
l.from(".title", { opacity: 0, y: -50, duration: 1 });
window.__timelines["intro-anim"] = tl;
</script>
</div>
</template>

内联

直接在父合成内部定义嵌套合成。对于不需要复用的一次性合成,这种方式更简单。

<div id="root" data-composition-id="root"
data-start="0" data-width="1920" data-height="1080">

<!-- 内联嵌套合成 -->
<div id="el-5" data-composition-id="intro-anim"
data-start="0" data-track-index="3"
data-width="1920" data-height="1080">
<div class="title">Welcome!</div>
</div>

<script>
// 内联合成的时间线
const introTl = gsap.timeline({ paused: true });
introTl.from(".title", { opacity: 0, y: -50, duration: 1 });
window.__timelines["intro-anim"] = introTl;
</script>
</div>

内联合成不使用 <template> 标签或 data-composition-src

项目结构

project/ index.html compositions/ intro-anim.html caption-overlay.html outro-title.html assets/ video.mp4 music.mp3 logo.png

两个层次:原生元素和脚本

每个合成都有两个层次:

  • HTML -- 原生片段(videoimgaudio、嵌套合成)。声明式结构:播放什么、何时播放、在哪条轨道上。由数据属性控制。
  • Script -- 特效、过渡、动态 DOM、Canvas、SVG——通过 GSAP 实现创意动画。脚本不会控制媒体播放或片段的显示/隐藏。

⚠️ Warning

切勿使用脚本来播放/暂停/寻找媒体元素,或根据时间控制片段的显示/隐藏。框架会自动根据数据属性处理这些操作。重复这些行为的脚本会与框架产生冲突。示例请参阅常见错误

变量

HyperFrames 不会自动将 data-var-* 属性绑定到合成的 DOM 或 CSS 中。

支持的模式是:

  1. 在子合成的 <html> 根元素上使用 data-composition-variables 声明变量(id + type + default)。
  2. 在每个合成宿主元素上使用 data-variable-values 传递逐实例的值。
  3. 在合成内部使用 window.__hyperframes.getVariables() 读取解析后的值。运行时会按实例将宿主的 data-variable-values 覆盖在声明的默认值之上,因此相同的源文件可以使用不同的值嵌入多次。
<div
data-composition-id="card-pro"
data-composition-src="compositions/card.html"
data-start="0"
data-track-index="1"
data-variable-values='{"title":"Pro","color":"#ff4d4f"}'
></div>
<div
data-composition-id="card-enterprise"
data-composition-src="compositions/card.html"
data-start="card-pro"
data-track-index="1"
data-variable-values='{"title":"Enterprise","color":"#22c55e"}'
></div>
<html data-composition-variables='[
{"id":"title","type":"string","label":"Title","default":"Fallback"},
{"id":"color","type":"color","label":"Color","default":"#111827"}
]'>
<body>
<div data-composition-id="card" data-width="1920" data-height="1080">
<h1 class="title"></h1>

<style>
[data-composition-id="card"] {
--card-color: #111827;
}

[data-composition-id="card"] .title {
color: var(--card-color);
}
</style>

<script>
// 在子合成脚本中,getVariables() 返回逐实例的值:
// 声明的默认值 < 宿主 data-variable-values 覆盖值。
const { title, color } = __hyperframes.getVariables();
const root = document.querySelector('[data-composition-id="card"]');
root.querySelector(".title").textContent = title;
root.style.setProperty("--card-color", color);
</script>
</div>
</body>
</html>

如果你正在基于 @hyperframes/core 构建工具链,同一个 data-composition-variables 数组可以通过 extractCompositionMetadata() 读取,用于 Studio 编辑界面和分析流程。

列出合成

使用 CLI 查看项目中的所有合成:

npx hyperframes compositions

下一步