compose-video
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseCompose Video
视频合成
HTML is the source of truth for video. A composition is an HTML file with attributes for timing, a GSAP timeline for animation, and CSS for appearance. The framework handles clip visibility, media playback, and timeline sync.
data-*HTML是视频的核心依据。一个合成内容是包含用于时间控制的属性、用于动画的GSAP时间线以及用于外观的CSS的HTML文件。该框架负责处理剪辑可见性、媒体播放和时间线同步。
data-*Approach
方法步骤
Before writing HTML, think at a high level:
- What — what should the viewer experience? Identify the narrative arc, key moments, and emotional beats.
- Structure — how many compositions, which are sub-compositions vs inline, what tracks carry what (video, audio, overlays, captions).
- Timing — which clips drive the duration, where do transitions land, what's the pacing.
- Execute — then implement using the rules below.
For small edits (fix a color, adjust timing, add one element), skip straight to the rules.
When no or animation direction is provided, follow house-style.md for motion defaults, sizing, and color palettes.
visual-style.md在编写HTML之前,先从宏观层面规划:
- 内容定位 — 观众应该获得怎样的体验?明确叙事脉络、关键节点和情感节奏。
- 结构设计 — 需要多少个合成内容,哪些是子合成内容、哪些是内联内容,不同轨道分别承载什么(视频、音频、叠加层、字幕)。
- 时间规划 — 哪些剪辑决定时长,转场位置在哪里,整体节奏如何。
- 执行实现 — 然后按照以下规则进行开发。
对于小型修改(调整颜色、修改时间、添加单个元素),可以直接跳过规划步骤,直接遵循规则。
如果没有提供或动画指导,请遵循house-style.md中的动效默认设置、尺寸规范和调色板要求。
visual-style.mdData Attributes
数据属性
All Clips
所有剪辑
| Attribute | Required | Values |
|---|---|---|
| Yes | Unique identifier |
| Yes | Seconds or clip ID reference ( |
| Required for img/div/compositions | Seconds. Video/audio defaults to media duration. |
| Yes | Integer. Same-track clips cannot overlap. |
| No | Trim offset into source (seconds) |
| No | 0-1 (default 1) |
data-track-indexz-index| 属性 | 是否必填 | 取值 |
|---|---|---|
| 是 | 唯一标识符 |
| 是 | 秒数或剪辑ID引用(如 |
| 图片/ div/合成内容必填 | 秒数。视频/音频默认使用媒体自身时长。 |
| 是 | 整数。同一轨道的剪辑不能重叠。 |
| 否 | 源媒体的裁剪偏移量(秒) |
| 否 | 0-1(默认值为1) |
data-track-indexz-indexComposition Clips
合成内容剪辑
| Attribute | Required | Values |
|---|---|---|
| Yes | Unique composition ID |
| Yes | Takes precedence over GSAP timeline duration |
| Yes | Pixel dimensions (1920x1080 or 1080x1920) |
| No | Path to external HTML file |
| 属性 | 是否必填 | 取值 |
|---|---|---|
| 是 | 唯一的合成内容ID |
| 是 | 优先级高于GSAP时间线的时长 |
| 是 | 像素尺寸(1920x1080 或 1080x1920) |
| 否 | 外部HTML文件路径 |
Composition Structure
合成内容结构
Every composition is a wrapping a with . Each must include its own GSAP script and register its timeline:
<template><div>data-composition-idhtml
<template id="my-comp-template">
<div data-composition-id="my-comp" data-width="1920" data-height="1080">
<!-- content -->
<style>
[data-composition-id="my-comp"] {
/* scoped styles */
}
</style>
<script src="https://cdn.jsdelivr.net/npm/gsap@3.14.2/dist/gsap.min.js"></script>
<script>
window.__timelines = window.__timelines || {};
const tl = gsap.timeline({ paused: true });
// tweens...
window.__timelines["my-comp"] = tl;
</script>
</div>
</template>Load in root:
<div id="el-1" data-composition-id="my-comp" data-composition-src="compositions/my-comp.html" data-start="0" data-duration="10" data-track-index="1"></div>每个合成内容都是一个包裹着带有属性的的。每个合成内容必须包含自己的GSAP脚本并注册其时间线:
data-composition-id<div><template>html
<template id="my-comp-template">
<div data-composition-id="my-comp" data-width="1920" data-height="1080">
<!-- content -->
<style>
[data-composition-id="my-comp"] {
/* scoped styles */
}
</style>
<script src="https://cdn.jsdelivr.net/npm/gsap@3.14.2/dist/gsap.min.js"></script>
<script>
window.__timelines = window.__timelines || {};
const tl = gsap.timeline({ paused: true });
// tweens...
window.__timelines["my-comp"] = tl;
</script>
</div>
</template>在根页面中加载:
<div id="el-1" data-composition-id="my-comp" data-composition-src="compositions/my-comp.html" data-start="0" data-duration="10" data-track-index="1"></div>Video and Audio
视频与音频
Video must be . Audio is always a separate element:
muted playsinline<audio>html
<video
id="el-v"
data-start="0"
data-duration="30"
data-track-index="0"
src="video.mp4"
muted
playsinline
></video>
<audio
id="el-a"
data-start="0"
data-duration="30"
data-track-index="2"
src="video.mp4"
data-volume="1"
></audio>视频必须添加属性。音频始终作为独立的元素存在:
muted playsinline<audio>html
<video
id="el-v"
data-start="0"
data-duration="30"
data-track-index="0"
src="video.mp4"
muted
playsinline
></video>
<audio
id="el-a"
data-start="0"
data-duration="30"
data-track-index="2"
src="video.mp4"
data-volume="1"
></audio>Timeline Contract
时间线约定
- All timelines start — the player controls playback
{ paused: true } - Register every timeline:
window.__timelines["<composition-id>"] = tl - Framework auto-nests sub-timelines — do NOT manually add them
- Duration comes from , not from GSAP timeline length
data-duration - Never create empty tweens to set duration
- 所有时间线初始状态为— 由播放器控制播放
{ paused: true } - 必须注册每个时间线:
window.__timelines["<composition-id>"] = tl - 框架会自动嵌套子时间线 — 请勿手动添加
- 时长由决定,而非GSAP时间线的长度
data-duration - 不要创建空补间动画来设置时长
Rules (Non-Negotiable)
必须遵守的规则
Deterministic: No , , or time-based logic. The renderer must produce identical output every time.
Math.random()Date.now()GSAP: Only animate visual properties (, , , , , , , , transforms). Do NOT animate , , or call /.
opacityxyscalerotationcolorbackgroundColorborderRadiusvisibilitydisplayvideo.play()audio.play()Animation conflicts: Never animate the same property on the same element from multiple timelines simultaneously — causes flickering in headless renders.
Never do:
- Forget registration
window.__timelines - Use video for audio — always muted video + separate
<audio> - Nest video inside a timed div — use a non-timed wrapper
- Use (use
data-layer) ordata-track-index(usedata-end)data-duration - Animate video element dimensions — animate a wrapper div
- Call play/pause/seek on media — framework owns playback
- Create a top-level container without
data-composition-id
确定性: 禁止使用、或基于时间的逻辑。渲染器每次必须生成完全相同的输出。
Math.random()Date.now()GSAP: 仅允许动画视觉属性(、、、、、、、、变换属性)。禁止动画、属性,或调用/方法。
opacityxyscalerotationcolorbackgroundColorborderRadiusvisibilitydisplayvideo.play()audio.play()动画冲突: 禁止同时从多个时间线动画同一元素的同一属性 — 这会导致无头渲染时出现闪烁问题。
绝对禁止的操作:
- 忘记注册
window.__timelines - 使用视频承载音频 — 始终使用静音视频 + 独立的元素
<audio> - 将视频嵌套在带时间控制的div中 — 使用不带时间控制的包裹元素
- 使用(请使用
data-layer)或data-track-index(请使用data-end)data-duration - 动画视频元素的尺寸 — 请动画包裹视频的div元素
- 调用媒体的play/pause/seek方法 — 播放控制由框架负责
- 创建不带的顶级容器
data-composition-id
Editing Existing Compositions
编辑现有合成内容
- Read the full composition first — match existing fonts, colors, animation patterns
- Only change what was requested — don't rewrite untouched sections
- Don't rewrite entire files for small changes
- Preserve timing of unrelated clips
- 先完整阅读现有合成内容 — 匹配现有的字体、颜色、动画模式
- 仅修改被要求更改的部分 — 不要重写未涉及的内容
- 不要为了小修改而重写整个文件
- 保留无关剪辑的时间设置
Typography and Assets
排版与资源
- Every composition loads its own fonts (or
@importin@font-face)<style> - Use for local fonts — renderer needs fonts loaded before capturing
font-display: block - Add to media loaded from external URLs
crossorigin="anonymous" - Minimum readable text: 20px landscape, 18px portrait
- All files (video, audio, fonts, images) live at the project root alongside
index.html - From sub-compositions, use to reference root files
../
For PiP, title cards, and slide show patterns, see patterns.md.
For data, stats, and infographics, see data-in-motion.md.
- 每个合成内容都要加载自己的字体(在中使用
<style>或@import)@font-face - 本地字体使用— 渲染器需要在捕获画面前加载完成字体
font-display: block - 从外部URL加载的媒体需添加属性
crossorigin="anonymous" - 最小可读文本尺寸:横版20px,竖版18px
- 所有文件(视频、音频、字体、图片)都存放在项目根目录,与同级
index.html - 从子合成内容中引用根目录文件时使用路径
../
关于画中画、标题卡片和幻灯片模式,请参考patterns.md。
关于数据、统计信息和信息图,请参考data-in-motion.md。
Output Checklist
输出检查清单
- Every top-level container has
data-composition-id - Every composition has ,
data-width,data-heightdata-duration - Compositions in own HTML files, loaded via
data-composition-src - wrapper on sub-compositions
<template> - registered for every composition
window.__timelines - 100% deterministic — no randomness
- Each composition includes GSAP:
<script src="https://cdn.jsdelivr.net/npm/gsap@3.14.2/dist/gsap.min.js"></script>
- 每个顶级容器都带有属性
data-composition-id - 每个合成内容都带有、
data-width、data-height属性data-duration - 合成内容存放在独立的HTML文件中,通过加载
data-composition-src - 子合成内容使用包裹
<template> - 每个合成内容都已注册
window.__timelines - 100%确定性 — 无随机逻辑
- 每个合成内容都包含GSAP:
<script src="https://cdn.jsdelivr.net/npm/gsap@3.14.2/dist/gsap.min.js"></script>