framevideo

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

FrameVideo

FrameVideo

HTML is the source of truth for video. A composition is an HTML file with
data-*
attributes for timing, a GSAP timeline for animation, and CSS for appearance. The framework handles clip visibility, media playback, and timeline sync.
HTML是视频的可信来源。一个合成作品是包含用于时间控制的
data-*
属性、用于动画的GSAP时间线以及用于外观的CSS的HTML文件。该框架负责处理片段可见性、媒体播放和时间线同步。

When To Use

使用场景

Use this skill for any FrameVideo composition task. This is the largest skill (1100+ lines) — use the navigation below to find what you need quickly.
本技能适用于任何FrameVideo合成任务。这是内容最丰富的技能(超过1100行)——使用下方导航快速找到你需要的内容。

🚀 New to FrameVideo?

🚀 刚接触FrameVideo?

  1. Read "Quick Start" (line 46) — minimal working example
  2. Read "Core Concepts" (line 95) — data attributes, timing, timeline contract
  3. Try the example, then come back for specific features
  1. 阅读「快速开始」(第46行)——最简可用示例
  2. 阅读「核心概念」(第95行)——数据属性、时间控制、时间线约定
  3. 尝试示例,然后返回查看特定功能

🎯 Looking for something specific?

🎯 寻找特定功能?

Layout & Structure:
  • Safe areas & margins → "Layout & Safe Areas" (line 180)
  • Multi-scene compositions → "Scene Transitions" (line 450) [MANDATORY for multi-scene]
  • Composition architecture → "Composition Structure" (line 120)
Animation & Motion:
  • Which animation library? → "Animation Adapter Routing" (line 28)
  • GSAP patterns → Load
    gsap
    skill (default choice)
  • Audio-reactive animation → "Audio Reactive Visuals" (line 620)
  • Custom effects → Animation adapter skills (gsap, animejs, waapi, etc.)
Media & Assets:
  • Video/audio playback → "Video & Audio" (line 140)
  • Captions & subtitles → "Captions" (line 580)
  • Parametrized compositions → "Variables" (line 160)
Workflow:
  • AI-driven production → "AI Production Route" (line 200)
  • Quality checks →
    framevideo-visual-qa
    skill
  • CLI commands →
    framevideo-cli
    skill
Do NOT use for:
  • CLI commands (init, lint, preview, render) →
    framevideo-cli
    skill
  • Asset preprocessing (TTS, transcribe, bg-removal) →
    framevideo-media
    skill
  • Quality checks and validation →
    framevideo-visual-qa
    skill
  • Chanjing digital humans →
    chanjing-digital-human
    skill

布局与结构:
  • 安全区域与边距 → 「布局与安全区域」(第180行)
  • 多场景合成 → 「场景转场」(第450行)[多场景必备]
  • 合成架构 → 「合成结构」(第120行)
动画与动效:
  • 选择哪个动画库? → 「动画适配器路由」(第28行)
  • GSAP模式 → 加载
    gsap
    技能(默认选择)
  • 音频响应式动画 → 「音频响应式视觉效果」(第620行)
  • 自定义效果 → 动画适配器技能(gsap、animejs、waapi等)
媒体与资产:
  • 视频/音频播放 → 「视频与音频」(第140行)
  • 字幕与副标题 → 「字幕」(第580行)
  • 参数化合成 → 「变量」(第160行)
工作流:
  • AI驱动制作 → 「AI制作流程」(第200行)
  • 质量检查 →
    framevideo-visual-qa
    技能
  • CLI命令 →
    framevideo-cli
    技能
请勿用于:
  • CLI命令(init、lint、preview、render)→
    framevideo-cli
    技能
  • 资产预处理(TTS、转录、背景移除)→
    framevideo-media
    技能
  • 质量检查与验证 →
    framevideo-visual-qa
    技能
  • Chanjing数字人 →
    chanjing-digital-human
    技能

Animation Adapter Routing

动画适配器路由

Default to
gsap
for most FrameVideo composition animation. Use a specific adapter skill only when the content or user request calls for it:
UseAdapter skill
Scene choreography, text/card motion, staggered timelines, most scripted animation
gsap
User requests Anime.js, or porting compact Anime.js DOM/SVG examples
animejs
Simple finite CSS keyframes, shimmer, glow, masks, and non-sequenced decoration
css-animations
Lightweight native
element.animate()
motion with no external library
waapi
Existing Lottie/dotLottie assets from design tools
lottie
Deterministic 3D scenes, GLTF, WebGL, camera moves, shader plates
three
WebGPU/TypeGPU shaders, particles, liquid glass, compute pipelines
typegpu
Shared rule for every adapter: render-critical animation must be deterministic and seekable. Do not use wall-clock time, infinite loops, or async registration for timelines/instances.

大多数FrameVideo合成动画默认使用
gsap
。仅当内容或用户需求明确要求时,才使用特定的适配器技能:
使用场景适配器技能
场景编排、文本/卡片动效、交错时间线、大多数脚本化动画
gsap
用户要求使用Anime.js,或移植紧凑的Anime.js DOM/SVG示例
animejs
简单的有限CSS关键帧、闪光、发光、遮罩和非序列装饰
css-animations
轻量级原生
element.animate()
动效,无需外部库
waapi
来自设计工具的现有Lottie/dotLottie资产
lottie
确定性3D场景、GLTF、WebGL、镜头移动、着色器模板
three
WebGPU/TypeGPU着色器、粒子、液态玻璃、计算管线
typegpu
所有适配器的通用规则:关键渲染动画必须是确定性且可定位的。不要使用挂钟时间、无限循环或异步注册来创建时间线/实例。

Quick Start

快速开始

Minimal working composition:
html
<!doctype html>
<html>
  <head>
    <meta charset="UTF-8" />
    <title>My Video</title>
  </head>
  <body>
    <div data-composition-id="main" data-width="1920" data-height="1080">
      <div id="scene-1" class="clip" data-start="0" data-duration="5" data-track-index="1">
        <div class="scene-content">
          <h1>Hello FrameVideo</h1>
        </div>
      </div>

      <style>
        [data-composition-id="main"] { background: #000; color: #fff; }
        .scene-content {
          display: flex;
          align-items: center;
          justify-content: center;
          width: 100%;
          height: 100%;
          padding: 120px 160px;
          box-sizing: border-box;
        }
        h1 { font-size: 120px; }
      </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 });
        tl.from("h1", { opacity: 0, y: 40, duration: 0.8, ease: "power3.out" }, 0.3);
        window.__timelines["main"] = tl;
      </script>
    </div>
  </body>
</html>
Next: Validate with
npx framevideo lint
, preview with
npx framevideo preview
.

最简可用合成示例:
html
<!doctype html>
<html>
  <head>
    <meta charset="UTF-8" />
    <title>My Video</title>
  </head>
  <body>
    <div data-composition-id="main" data-width="1920" data-height="1080">
      <div id="scene-1" class="clip" data-start="0" data-duration="5" data-track-index="1">
        <div class="scene-content">
          <h1>Hello FrameVideo</h1>
        </div>
      </div>

      <style>
        [data-composition-id="main"] { background: #000; color: #fff; }
        .scene-content {
          display: flex;
          align-items: center;
          justify-content: center;
          width: 100%;
          height: 100%;
          padding: 120px 160px;
          box-sizing: border-box;
        }
        h1 { font-size: 120px; }
      </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 });
        tl.from("h1", { opacity: 0, y: 40, duration: 0.8, ease: "power3.out" }, 0.3);
        window.__timelines["main"] = tl;
      </script>
    </div>
  </body>
</html>
下一步:使用
npx framevideo lint
验证,使用
npx framevideo preview
预览。

Section Index

章节索引

This skill has 1100+ lines organized into the following major sections. Jump to the section you need:
🎬 Core Concepts (lines 95-200) — Read first if new to FrameVideo
  • Data Attributes & Timing
  • Composition Structure
  • Timeline Contract
  • Video & Audio
  • Variables (Parametrized Compositions)
🎨 Layout & Design (lines 180-300)
  • Safe Areas & Margins
  • Typography & Readability
  • Color & Contrast
  • Responsive Layouts
✨ Animation & Motion (lines 300-450)
  • Animation Adapter Routing (see above)
  • GSAP Integration (or load
    gsap
    skill for details)
  • Timing & Easing
  • Stagger Patterns
🎞️ Scene Transitions (lines 450-580) — MANDATORY for multi-scene videos
  • Crossfades
  • Wipes & Reveals
  • Shader Transitions
  • Scene Architecture
📝 Captions & Subtitles (lines 580-650)
  • Caption Timing
  • Styling & Positioning
  • Transcript Integration
🎵 Audio-Reactive Visuals (lines 620-720)
  • Beat Detection
  • Amplitude-Based Animation
  • Music Synchronization
🔧 Advanced Patterns (lines 720-900)
  • HTML-in-Canvas Effects
  • Sub-Compositions
  • Dynamic Content
  • Performance Optimization
📚 References (lines 900-1100)
  • Examples Gallery
  • Troubleshooting
  • Best Practices
  • API Reference
Note: Line numbers are approximate guides. Use your Read tool's offset parameter to jump to sections, or read the full file if you need comprehensive context.

本技能包含超过1100行内容,分为以下主要章节。跳转到你需要的章节:
🎬 核心概念(第95-200行)——刚接触FrameVideo请先阅读
  • 数据属性与时间控制
  • 合成结构
  • 时间线约定
  • 视频与音频
  • 变量(参数化合成)
🎨 布局与设计(第180-300行)
  • 安全区域与边距
  • 排版与可读性
  • 颜色与对比度
  • 响应式布局
✨ 动画与动效(第300-450行)
  • 动画适配器路由(见上文)
  • GSAP集成(或加载
    gsap
    技能查看详情)
  • 时间控制与缓动
  • 交错模式
🎞️ 场景转场(第450-580行)——多场景视频必备
  • 淡入淡出
  • 擦除与揭示
  • 着色器转场
  • 场景架构
📝 字幕与副标题(第580-650行)
  • 字幕时间控制
  • 样式与定位
  • 转录集成
🎵 音频响应式视觉效果(第620-720行)
  • 节拍检测
  • 基于振幅的动画
  • 音乐同步
🔧 进阶模式(第720-900行)
  • Canvas内HTML效果
  • 子合成
  • 动态内容
  • 性能优化
📚 参考资料(第900-1100行)
  • 示例图库
  • 故障排除
  • 最佳实践
  • API参考
注意: 行号为大致指引。使用阅读工具的偏移参数跳转到对应章节,若需要全面上下文可阅读完整文件。

Core Concepts

核心概念

  • Video & Audio Elements
  • Variables (Parametrized Compositions)
Layout & Safe Areas (expand when positioning elements):
  • Layout Before Animation Principle
  • Container Patterns
  • Safe Area Rules
  • Text Handling
  • Common Layout Patterns
Animation & Motion (expand when adding motion):
  • Animation Guardrails
  • Entrance/Exit Patterns
  • Stagger & Sequencing
  • Scene Rhythm Templates
  • Animation Conflicts
Scene Transitions (mandatory for multi-scene videos):
  • 4 Non-Negotiable Rules
  • Transition Implementation
Advanced Features (as needed):
  • Captions & Subtitles
  • Audio-Reactive Animation
  • CSS Marker Highlighting
  • Shader Transitions
References (deep dives):
  • See "References" section at end for 15+ detailed guides

  • 视频与音频元素
  • 变量(参数化合成)
布局与安全区域(定位元素时展开):
  • 先布局后动画原则
  • 容器模式
  • 安全区域规则
  • 文本处理
  • 常见布局模式
动画与动效(添加动效时展开):
  • 动画约束规则
  • 入场/退场模式
  • 交错与序列
  • 场景节奏模板
  • 动画冲突
场景转场(多场景视频必备):
  • 4条不可协商规则
  • 转场实现
进阶功能(按需使用):
  • 字幕与副标题
  • 音频响应式动画
  • CSS标记高亮
  • 着色器转场
参考资料(深入学习):
  • 查看末尾的「参考资料」章节获取15+份详细指南

Core Concepts

核心概念

Data Attributes & Timing

数据属性与时间控制

Every clip requires these attributes:
AttributeRequiredValues
id
YesUnique identifier
data-start
YesSeconds or clip ID reference (
"el-1"
,
"intro + 2"
)
data-duration
Yes*Seconds. *Optional for video/audio (uses media length)
data-track-index
YesInteger. Same-track clips cannot overlap
Optional:
  • data-media-start
    - Trim offset into source (seconds)
  • data-volume
    - 0-1 (audio only, default 1)
Important:
data-track-index
does NOT control visual layering. Use CSS
z-index
.
每个片段都需要以下属性:
属性是否必填
id
唯一标识符
data-start
秒数或片段ID引用(
"el-1"
,
"intro + 2"
data-duration
是*秒数。*视频/音频可选(使用媒体时长)
data-track-index
整数。同轨道片段不能重叠
可选属性:
  • data-media-start
    - 源媒体的裁剪偏移量(秒)
  • data-volume
    - 0-1(仅音频,默认值1)
重要提示:
data-track-index
不控制视觉层级。请使用CSS
z-index

Composition Structure

合成结构

Root element with required attributes:
html
<div data-composition-id="main" data-width="1920" data-height="1080">
  <!-- content -->
</div>
Standalone compositions (main
index.html
): Put root
<div>
directly in
<body>
. Do NOT use
<template>
.
Sub-compositions (loaded via
data-composition-src
): MUST use
<template>
wrapper:
html
<template id="my-comp-template">
  <div data-composition-id="my-comp" data-width="1920" data-height="1080">
    <!-- content -->
  </div>
</template>
根元素需包含必填属性:
html
<div data-composition-id="main" data-width="1920" data-height="1080">
  <!-- 内容 -->
</div>
独立合成作品(主
index.html
):将根
<div>
直接放在
<body>
中。请勿使用
<template>
子合成作品(通过
data-composition-src
加载):必须使用
<template>
包裹:
html
<template id="my-comp-template">
  <div data-composition-id="my-comp" data-width="1920" data-height="1080">
    <!-- 内容 -->
  </div>
</template>

Timeline Contract

时间线约定

5 mandatory rules:
  1. Create paused:
    const tl = gsap.timeline({ paused: true });
  2. Register timeline:
    window.__timelines["main"] = tl;
    (key must match
    data-composition-id
    )
  3. Synchronous construction: Never build timelines inside
    async
    ,
    setTimeout
    , or Promises
  4. Duration from data attribute: Use
    data-duration
    , not GSAP timeline length
  5. Framework auto-nests: Don't manually add sub-composition timelines
5条强制规则:
  1. 创建时暂停:
    const tl = gsap.timeline({ paused: true });
  2. 注册时间线:
    window.__timelines["main"] = tl;
    (键必须与
    data-composition-id
    匹配)
  3. 同步构建: 切勿在
    async
    setTimeout
    或Promise内构建时间线
  4. 使用数据属性定义时长: 使用
    data-duration
    ,而非GSAP时间线长度
  5. 框架自动嵌套: 不要手动添加子合成时间线

Video & Audio

视频与音频

Video must be muted:
html
<video
  id="el-v"
  data-start="0"
  data-duration="30"
  data-track-index="0"
  src="video.mp4"
  muted
  playsinline
></video>
Audio track separate:
html
<audio
  id="el-a"
  data-start="0"
  data-duration="30"
  data-track-index="2"
  src="video.mp4"
  data-volume="1"
></audio>
Use same source file. Framework controls playback - never call
.play()
.
视频必须静音:
html
<video
  id="el-v"
  data-start="0"
  data-duration="30"
  data-track-index="0"
  src="video.mp4"
  muted
  playsinline
></video>
单独音频轨道:
html
<audio
  id="el-a"
  data-start="0"
  data-duration="30"
  data-track-index="2"
  src="video.mp4"
  data-volume="1"
></audio>
使用相同的源文件。框架控制播放——切勿调用
.play()

Variables (Parametrized Compositions)

变量(参数化合成)

Three-step pattern:
  1. Declare on
    <html>
    root:
html
<html data-composition-variables='[
  {"id":"title","type":"string","label":"Title","default":"Hello"}
]'>
  1. Read in script:
javascript
const { title } = window.__framevideo.getVariables();
document.getElementById("hero").textContent = title;
  1. Override at render:
bash
npx framevideo render --variables '{"title":"Q4 Report"}'
Variable types:
string
,
number
,
color
,
boolean
,
enum
.

<details> <summary><h2>📐 Layout & Safe Areas (Click to Expand)</h2></summary>
三步模式:
  1. 声明
    <html>
    根元素上:
html
<html data-composition-variables='[
  {"id":"title","type":"string","label":"Title","default":"Hello"}
]'>
  1. 读取在脚本中:
javascript
const { title } = window.__framevideo.getVariables();
document.getElementById("hero").textContent = title;
  1. 渲染时覆盖
bash
npx framevideo render --variables '{"title":"Q4 Report"}'
变量类型:
string
number
color
boolean
enum

<details> <summary><h2>📐 布局与安全区域(点击展开)</h2></summary>

AI Production Route

AI制作流程

When the user asks to go from an idea, script, plot, storyboard, reference image, or rough video concept to a generated video, invoke
framevideo-ai-production
as the front half of the workflow. That skill turns creative material into Clip, Shot, and Chanjing AIGC plans.
For real Chanjing AI image/video generation:
  1. Use
    framevideo-ai-production
    to produce Shot-level Chanjing AIGC plans.
  2. Use
    chanjing-digital-human/references/ai-creation.md
    for Chanjing AI Creation model discovery, idempotent submission, short sync polling, download, and local asset paths.
  3. Only compose with local assets under
    assets/ai-creation/images/
    or
    assets/ai-creation/videos/
    .
  4. Return here to build the FrameVideo HTML composition, audio, captions, transitions, QA, preview, and render.
Do not directly insert remote Chanjing output URLs into composition HTML.
当用户要求从创意想法、脚本、情节、分镜、参考图片或粗略视频概念生成视频时,调用
framevideo-ai-production
作为工作流的前半部分。该技能将创意素材转换为片段、镜头和Chanjing AIGC计划。
对于真实的Chanjing AI图像/视频生成:
  1. 使用
    framevideo-ai-production
    生成镜头级的Chanjing AIGC计划。
  2. 使用
    chanjing-digital-human/references/ai-creation.md
    进行Chanjing AI创作模型发现、幂等提交、短轮询同步、下载和本地资产路径处理。
  3. 仅使用
    assets/ai-creation/images/
    assets/ai-creation/videos/
    下的本地资产进行合成。
  4. 返回此处构建FrameVideo HTML合成作品、音频、字幕、转场、QA、预览和渲染。
请勿直接将Chanjing远程输出URL插入合成HTML中。

Approach

方法

Discovery (exploratory requests only)

需求探索(仅适用于开放式请求)

For open-ended requests ("make me a product launch video", "create something for our brand") where the user hasn't committed to a direction, understand intent before picking colors:
  • Audience — who watches this? Developers? Executives? General consumers?
  • Platform — where does it play? Social (15s), website hero, product demo, internal?
  • Priority — what matters most? Motion quality? Content accuracy? Brand fidelity? Speed?
  • Variations — does the user want options, or a single best shot?
For specific requests ("add a title card", "fix the timing on scene 3"), skip discovery.
For exploratory requests, consider offering 2-3 variations that differ meaningfully — not just color swaps, but different pacing, energy levels, or structural approaches. One safe/expected, one ambitious. Don't mandate this — it's a tool available when appropriate.
对于开放式请求(如“帮我制作一个产品发布视频”、“为我们的品牌创作内容”)且用户尚未确定方向的情况,在选择颜色前先明确意图:
  • 受众——谁会观看?开发者?高管?普通消费者?
  • 平台——在哪里播放?社交平台(15秒)、网站首页、产品演示、内部使用?
  • 优先级——最重要的是什么?动效质量?内容准确性?品牌一致性?速度?
  • 变体——用户想要多种选项,还是单一最优方案?
对于特定请求(如“添加标题卡”、“修复场景3的时间控制”),跳过需求探索。
对于探索性请求,可考虑提供2-3种差异显著的变体——不只是颜色切换,而是不同的节奏、能量水平或结构方式。一种安全/符合预期,一种更具野心。无需强制要求——仅在合适时提供此选项。

Step 1: Design system

步骤1:设计系统

If a design spec exists in the project, read it first. Look in precedence order:
frame.md
design.md
DESIGN.md
(
design.md
and
DESIGN.md
are different files on Linux — check both casings;
frame.md
is always lowercase, no
FRAME.md
variant).
frame.md
is the preferred spec for video/framevideo projects and wins if more than one exists; it uses the same format as
design.md
. It's the source of truth for brand colors, fonts, and constraints. Use its exact values — don't invent colors or substitute fonts. Any format works (YAML frontmatter, prose, tables — just extract the values).
If it names fonts you can't find locally (no
fonts/
directory with
.woff2
files, not a built-in font), warn the user before writing HTML: "the spec specifies [font name] but no font files found. Please add .woff2 files to
fonts/
or I'll fall back to [closest built-in alternative]."
If no
frame.md
or
design.md
exists, offer the user a choice:
  1. User named a style or mood? → Read visual-styles.md for the 8 named presets. Pick the closest match.
  2. Want to browse options visually? → Run the design picker: read references/design-picker.md for the full workflow. This serves a visual picker page. The user configures mood, palette, typography, and motion in the browser, then copies the generated design.md and pastes it back into the conversation.
  3. Want to skip and go fast? → Ask: mood, light or dark, any brand colors/fonts? Then pick a palette from house-style.md.
The design spec defines the brand. It does not define video composition rules. Those come from references/video-composition.md and house-style.md. Use brand colors at video-appropriate scale — not at web-UI opacity.
如果项目中存在设计规范,请先阅读。优先级顺序为:
frame.md
design.md
DESIGN.md
(在Linux系统中
design.md
DESIGN.md
是不同文件——请检查两种大小写;
frame.md
始终为小写,无
FRAME.md
变体)。
frame.md
是视频/framevideo项目的首选规范,若存在多个规范则以它为准;其格式与
design.md
相同。它是品牌颜色、字体和约束的可信来源。请使用其中的精确值——不要自行创建颜色或替换字体。任何格式均可(YAML前置元数据、散文、表格——只需提取值即可)。
如果规范中指定的字体在本地找不到(
fonts/
目录中没有
.woff2
文件,也不是内置字体),在编写HTML前警告用户:“规范指定了[字体名称]但未找到字体文件。请将.woff2文件添加到
fonts/
目录,否则我将使用[最接近的内置替代字体]。”
如果不存在
frame.md
design.md
,请为用户提供选择:
  1. 用户指定了风格或氛围? → 阅读visual-styles.md中的8种命名预设。选择最匹配的一种。
  2. 想要可视化浏览选项? → 运行设计选择器:阅读references/design-picker.md获取完整工作流。这会提供一个可视化选择页面。用户在浏览器中配置氛围、调色板、排版和动效,然后复制生成的design.md并粘贴回对话中。
  3. 想要跳过快速开始? → 询问:氛围、亮色或暗色、是否有品牌颜色/字体?然后从house-style.md中选择调色板。
设计规范定义品牌。它不定义视频合成规则。 视频合成规则来自references/video-composition.mdhouse-style.md。以适合视频的比例使用品牌颜色——不要使用网页UI的透明度。

Step 2: Prompt expansion

步骤2:提示扩展

Always run on every composition (except single-scene pieces and trivial edits). This step grounds the user's intent against the design spec (
frame.md
or
design.md
) and
house-style.md
and produces a consistent intermediate that every downstream agent reads the same way.
Read references/prompt-expansion.md for the full process and output format.
每个合成作品都必须执行此步骤(单场景作品和微小编辑除外)。此步骤将用户意图与设计规范(
frame.md
design.md
)和
house-style.md
对齐,并生成一致的中间产物,供所有下游代理统一解读。
阅读references/prompt-expansion.md获取完整流程和输出格式。

Step 3: Plan

步骤3:规划

Before writing HTML, think at a high level:
  1. What — what should the viewer experience? Identify the narrative arc, key moments, and emotional beats.
  2. Structure — how many compositions, which are sub-compositions vs inline, what tracks carry what (video, audio, overlays, captions).
  3. Rhythm — declare your scene rhythm before implementing. Which scenes are quick hits, which are holds, where do shaders land, where does energy peak. Name the pattern: fast-fast-SLOW-fast-SHADER-hold. Read references/beat-direction.md for rhythm templates.
  4. Timing — which clips drive the duration, where do transitions land, what's the pacing.
  5. Layout — build the end-state first. See "Layout Before Animation" below.
  6. Animate — then add motion using the rules below.
Build what was asked. A request for "a title card" is not a request for "a title card + 3 supporting scenes + ambient music + captions." Every scene, every element, every tween should earn its place. If additional scenes or elements would genuinely improve the piece, propose them — don't add them.
For small edits (fix a color, adjust timing, add one element), skip straight to the rules.
<HARD-GATE> Before writing ANY composition HTML — verify you have a visual identity from Step 1. If you're reaching for `#333`, `#3b82f6`, or `Roboto`, you skipped it. </HARD-GATE>
编写HTML前,先进行高层次思考:
  1. 内容——观众应该体验到什么?确定叙事弧线、关键时刻和情感节拍。
  2. 结构——需要多少个合成作品,哪些是子合成哪些是内联,哪些轨道承载什么内容(视频、音频、叠加层、字幕)。
  3. 节奏——在实现前确定场景节奏。哪些场景是快速呈现,哪些是持续展示,着色器在哪里使用,能量峰值在哪里。命名模式:快-快-慢-快-着色器-持续。阅读references/beat-direction.md获取节奏模板。
  4. 时间控制——哪些片段决定时长,转场在哪里,节奏如何。
  5. 布局——先构建最终状态。见下文“先布局后动画”。
  6. 动画——然后使用以下规则添加动效。
构建用户要求的内容。 请求“制作一个标题卡”不等于请求“制作一个标题卡+3个辅助场景+背景音乐+字幕”。每个场景、每个元素、每个补间都应有其存在的理由。如果额外的场景或元素确实能提升作品质量,请提出建议——不要直接添加。
对于小修改(修复颜色、调整时间、添加一个元素),直接跳转到规则部分。
<HARD-GATE> 编写任何合成HTML前——确认你已从步骤1获得视觉标识。如果你使用`#333`、`#3b82f6`或`Roboto`,说明你跳过了该步骤。 </HARD-GATE>

Visual QA Skill

视觉QA技能

Use the
framevideo-visual-qa
skill when creating a new composition, making substantial layout/caption/asset/layering changes, fixing visual issues, or before declaring a composition visually ready. That skill owns reusable video QA rules for safe areas, text/background contrast, text overflow, unintentional overlap, and motion collisions. Keep project-specific brand identity in
frame.md
,
design.md
, or
DESIGN.md
; keep general visual QA method in the skill.

<details> <summary><h2>📐 Layout & Safe Areas (Click to Expand)</h2></summary>
在创建新合成作品、进行重大布局/字幕/资产/层级变更、修复视觉问题或宣布合成作品视觉完成前,使用
framevideo-visual-qa
技能。该技能拥有可复用的视频QA规则,涵盖安全区域、文本/背景对比度、文本溢出、意外重叠和动效冲突。将项目特定的品牌标识保存在
frame.md
design.md
DESIGN.md
中;将通用视觉QA方法保存在该技能中。

<details> <summary><h2>📐 布局与安全区域(点击展开)</h2></summary>

Layout Before Animation Principle

先布局后动画原则

Build the end state first. Position every element where it should be at its most visible moment - fully entered, correctly placed, not yet exiting. Write this as static HTML+CSS first. No GSAP yet.
Why: If you position elements at their animated start state (offscreen, scaled to 0, opacity 0) and tween them to where you think they should land, you're guessing. Overlaps are invisible until render. By building the end state first, you see and fix layout problems before adding motion.
The process:
  1. Identify the hero frame - the moment when most elements are simultaneously visible
  2. Write static CSS for that frame
  3. Add entrances with
    gsap.from()
    - animate FROM offscreen/invisible TO the CSS position
  4. Add exits with
    gsap.to()
    - animate TO offscreen/invisible FROM the CSS position
Example:
css
/* Step 1-2: Build the readable end state */
.scene-content {
  display: flex;
  flex-direction: column;
  justify-content: center;
  width: 100%;
  height: 100%;
  padding: 120px 160px;
  gap: 24px;
  box-sizing: border-box;
}
.title { font-size: 120px; }
.subtitle { font-size: 42px; }
javascript
// Step 3: Animate INTO those positions
tl.from(".title", { y: 60, opacity: 0, duration: 0.6, ease: "power3.out" }, 0);
tl.from(".subtitle", { y: 40, opacity: 0, duration: 0.5, ease: "power3.out" }, 0.2);

// Step 4: Animate OUT from those positions
tl.to(".title", { y: -40, opacity: 0, duration: 0.4, ease: "power2.in" }, 3);
先构建最终状态。 将每个元素定位在其最可见时刻的位置——完全入场、正确放置、尚未退场。先编写静态HTML+CSS。暂不使用GSAP。
原因: 如果你将元素定位在动画起始状态(屏幕外、缩放为0、透明度为0),然后补间到你认为应该到达的位置,这是在猜测。重叠问题在渲染前不可见。通过先构建最终状态,你可以在添加动效前发现并修复布局问题。
流程:
  1. 确定关键帧——大多数元素同时可见的时刻
  2. 为该帧编写静态CSS
  3. 使用
    gsap.from()
    添加入场动画
    ——从屏幕外/不可见状态动画到CSS定位的位置
  4. 使用
    gsap.to()
    添加退场动画
    ——从CSS定位的位置动画到屏幕外/不可见状态
示例:
css
/* 步骤1-2:构建可读的最终状态 */
.scene-content {
  display: flex;
  flex-direction: column;
  justify-content: center;
  width: 100%;
  height: 100%;
  padding: 120px 160px;
  gap: 24px;
  box-sizing: border-box;
}
.title { font-size: 120px; }
.subtitle { font-size: 42px; }
javascript
// 步骤3:动画进入这些位置
tl.from(".title", { y: 60, opacity: 0, duration: 0.6, ease: "power3.out" }, 0);
tl.from(".subtitle", { y: 40, opacity: 0, duration: 0.5, ease: "power3.out" }, 0.2);

// 步骤4:从这些位置动画退出
tl.to(".title", { y: -40, opacity: 0, duration: 0.4, ease: "power2.in" }, 3);

Container Patterns

容器模式

✅ Full-Scene Container (Recommended):
css
.scene-content {
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: center;
  width: 100%;
  height: 100%;
  padding: 120px 160px; /* Safe area */
  gap: 24px;
  box-sizing: border-box;
}
❌ Do NOT use absolute positioning for content:
css
/* WRONG - breaks on long text */
.scene-content {
  position: absolute;
  top: 200px;
  left: 160px;
  width: 1920px;
  height: 1080px;
}
Reserve
position: absolute
for decorative elements only (particles, glows, background shapes).
✅ 全场景容器(推荐):
css
.scene-content {
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: center;
  width: 100%;
  height: 100%;
  padding: 120px 160px; /* 安全区域 */
  gap: 24px;
  box-sizing: border-box;
}
❌ 请勿对内容使用绝对定位:
css
/* 错误——长文本会断裂 */
.scene-content {
  position: absolute;
  top: 200px;
  left: 160px;
  width: 1920px;
  height: 1080px;
}
仅将
position: absolute
用于装饰元素(粒子、发光效果、背景形状)。

Safe Area Rules

安全区域规则

Keep key information inside the safe area:
  • Horizontal: ~5% from left/right edges (~96px on 1920px width)
  • Vertical: ~5% from top/bottom edges (~54px on 1080px height)
  • Bottom (captions/CTA): ~10% from bottom (~108px)
What must stay safe:
  • Critical text, headlines, body copy
  • Logo (unless intentionally edge-anchored)
  • CTA buttons and links
  • Captions and subtitles
  • Presenter faces
  • Product UI screenshots
  • Legal/price copy
What can extend beyond:
  • Full-bleed backgrounds
  • Decorative glows and particles
  • Grain and texture overlays
  • Transition effects
Mark intentional overflow:
<div class="grain" data-layout-allow-overflow>
将关键信息保持在安全区域内:
  • 水平方向: 距左右边缘约5%(1920px宽度下约96px)
  • 垂直方向: 距上下边缘约5%(1080px高度下约54px)
  • 底部(字幕/CTA): 距底部约10%(约108px)
必须保持在安全区域内的内容:
  • 关键文本、标题、正文
  • Logo(除非故意锚定在边缘)
  • CTA按钮和链接
  • 字幕和副标题
  • 演示者面部
  • 产品UI截图
  • 法律/价格文本
可延伸到安全区域外的内容:
  • 全屏背景
  • 装饰性发光和粒子
  • 颗粒和纹理叠加层
  • 转场效果
标记有意溢出:
<div class="grain" data-layout-allow-overflow>

Text Handling

文本处理

Natural wrapping:
css
.headline {
  max-width: 1200px; /* Wraps at this width */
  font-size: 96px;
  line-height: 1.1;
}
Dynamic fitting:
javascript
const { title } = window.__framevideo.getVariables();
const fontSize = window.__framevideo.fitTextFontSize(title, {
  maxWidth: 1200,
  fontFamily: 'Inter',
  fontWeight: 700
});
document.getElementById('title').style.fontSize = fontSize + 'px';
Avoid fixed-size text containers - use elastic containers with padding instead.
自然换行:
css
.headline {
  max-width: 1200px; /* 在此宽度换行 */
  font-size: 96px;
  line-height: 1.1;
}
动态适配:
javascript
const { title } = window.__framevideo.getVariables();
const fontSize = window.__framevideo.fitTextFontSize(title, {
  maxWidth: 1200,
  fontFamily: 'Inter',
  fontWeight: 700
});
document.getElementById('title').style.fontSize = fontSize + 'px';
避免固定尺寸的文本容器——改用带内边距的弹性容器。

Common Layout Patterns

常见布局模式

Centered Title Card:
html
<div class="scene-content">
  <h1>Main Message</h1>
  <p class="subtitle">Supporting detail</p>
</div>

<style>
  .scene-content {
    display: flex;
    flex-direction: column;
    justify-content: center;
    align-items: center;
    text-align: center;
    width: 100%;
    height: 100%;
    padding: 120px 160px;
    gap: 32px;
    box-sizing: border-box;
  }
</style>
Split Layout (Text + Visual):
html
<div class="scene-content">
  <div class="text-side">
    <h2>Product Feature</h2>
    <p>Explanation</p>
  </div>
  <div class="visual-side">
    <img src="assets/product.png" />
  </div>
</div>

<style>
  .scene-content {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 80px;
    align-items: center;
    width: 100%;
    height: 100%;
    padding: 120px 160px;
    box-sizing: border-box;
  }
</style>
</details>
<details> <summary><h2>🎬 Animation & Motion (Click to Expand)</h2></summary>
居中标题卡:
html
<div class="scene-content">
  <h1>Main Message</h1>
  <p class="subtitle">Supporting detail</p>
</div>

<style>
  .scene-content {
    display: flex;
    flex-direction: column;
    justify-content: center;
    align-items: center;
    text-align: center;
    width: 100%;
    height: 100%;
    padding: 120px 160px;
    gap: 32px;
    box-sizing: border-box;
  }
</style>
拆分布局(文本+视觉):
html
<div class="scene-content">
  <div class="text-side">
    <h2>Product Feature</h2>
    <p>Explanation</p>
  </div>
  <div class="visual-side">
    <img src="assets/product.png" />
  </div>
</div>

<style>
  .scene-content {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 80px;
    align-items: center;
    width: 100%;
    height: 100%;
    padding: 120px 160px;
    box-sizing: border-box;
  }
</style>
</details>
<details> <summary><h2>🎬 动画与动效(点击展开)</h2></summary>

Animation Guardrails

动画约束规则

Timing offsets - Never start first animation at t=0:
javascript
// ❌ Wrong
tl.from(".title", { opacity: 0 }, 0);

// ✅ Right
tl.from(".title", { opacity: 0 }, 0.2); // 0.1-0.3s offset
Vary easing curves - Use at least 3 different eases per scene:
javascript
tl.from("#el1", { opacity: 0, ease: "power3.out" }, 0.2);
tl.from("#el2", { opacity: 0, ease: "expo.out" }, 0.4);
tl.from("#el3", { opacity: 0, ease: "back.out(1.4)" }, 0.6);
Common eases:
power1.out
,
power2.out
,
power3.out
,
expo.out
,
back.out(1.7)
,
elastic.out(1, 0.3)
Don't repeat entrance patterns - Each element should have unique direction or style:
javascript
// ❌ Wrong - everything from top
tl.from("#title", { y: 60, opacity: 0 }, 0.2);
tl.from("#subtitle", { y: 60, opacity: 0 }, 0.5);

// ✅ Right - varied directions
tl.from("#title", { y: 60, opacity: 0 }, 0.2);
tl.from("#subtitle", { x: -30, opacity: 0 }, 0.5);
tl.from("#cta", { scale: 0.8, opacity: 0 }, 0.8);
Performance properties - Prefer GPU-accelerated:
  • ✅ Fast:
    opacity
    ,
    x
    ,
    y
    ,
    scale
    ,
    rotation
  • ❌ Slow:
    width
    ,
    height
    ,
    top
    ,
    left
    ,
    margin
    ,
    padding
    ,
    font-size
时间偏移——首个动画切勿在t=0开始:
javascript
// ❌ 错误
tl.from(".title", { opacity: 0 }, 0);

// ✅ 正确
tl.from(".title", { opacity: 0 }, 0.2); // 0.1-0.3秒偏移
多样化缓动曲线——每个场景至少使用3种不同的缓动效果:
javascript
tl.from("#el1", { opacity: 0, ease: "power3.out" }, 0.2);
tl.from("#el2", { opacity: 0, ease: "expo.out" }, 0.4);
tl.from("#el3", { opacity: 0, ease: "back.out(1.4)" }, 0.6);
常见缓动效果:
power1.out
power2.out
power3.out
expo.out
back.out(1.7)
elastic.out(1, 0.3)
不要重复入场模式——每个元素应有独特的方向或风格:
javascript
// ❌ 错误——所有元素都从上方入场
tl.from("#title", { y: 60, opacity: 0 }, 0.2);
tl.from("#subtitle", { y: 60, opacity: 0 }, 0.5);

// ✅ 正确——方向多样化
tl.from("#title", { y: 60, opacity: 0 }, 0.2);
tl.from("#subtitle", { x: -30, opacity: 0 }, 0.5);
tl.from("#cta", { scale: 0.8, opacity: 0 }, 0.8);
性能属性——优先使用GPU加速属性:
  • ✅ 快速:
    opacity
    x
    y
    scale
    rotation
  • ❌ 缓慢:
    width
    height
    top
    left
    margin
    padding
    font-size

Common Animation Patterns

常见动画模式

Stagger entrances:
javascript
// Stagger by time
tl.from(".item", { 
  y: 30, 
  opacity: 0, 
  duration: 0.5,
  stagger: 0.1,
  ease: "power2.out"
}, 0.5);

// Stagger from center
tl.from(".grid-item", {
  scale: 0.8,
  opacity: 0,
  duration: 0.4,
  stagger: { amount: 0.6, from: "center" },
  ease: "back.out(1.4)"
}, 1.0);
Sequence vs Overlap:
javascript
// Sequence - one after another
tl.from("#el1", { opacity: 0, duration: 0.5 }, 0);
tl.from("#el2", { opacity: 0, duration: 0.5 }, ">"); // After previous ends

// Overlap - start before previous ends
tl.from("#el1", { opacity: 0, duration: 0.8 }, 0);
tl.from("#el2", { opacity: 0, duration: 0.5 }, "<0.4"); // 0.4s after el1 starts
Label-based sequencing:
javascript
tl.addLabel("intro", 0);
tl.from("#title", { opacity: 0 }, "intro");
tl.from("#subtitle", { opacity: 0 }, "intro+=0.5");

tl.addLabel("content", 2.5);
tl.from("#feature1", { x: -40, opacity: 0 }, "content");
交错入场:
javascript
// 按时间交错
tl.from(".item", { 
  y: 30, 
  opacity: 0, 
  duration: 0.5,
  stagger: 0.1,
  ease: "power2.out"
}, 0.5);

// 从中心交错
tl.from(".grid-item", {
  scale: 0.8,
  opacity: 0,
  duration: 0.4,
  stagger: { amount: 0.6, from: "center" },
  ease: "back.out(1.4)"
}, 1.0);
序列与重叠:
javascript
// 序列——一个接一个
tl.from("#el1", { opacity: 0, duration: 0.5 }, 0);
tl.from("#el2", { opacity: 0, duration: 0.5 }, ">"); // 在上一个结束后开始

// 重叠——在上一个结束前开始
tl.from("#el1", { opacity: 0, duration: 0.8 }, 0);
tl.from("#el2", { opacity: 0, duration: 0.5 }, "<0.4"); // el1开始0.4秒后开始
基于标签的序列:
javascript
tl.addLabel("intro", 0);
tl.from("#title", { opacity: 0 }, "intro");
tl.from("#subtitle", { opacity: 0 }, "intro+=0.5");

tl.addLabel("content", 2.5);
tl.from("#feature1", { x: -40, opacity: 0 }, "content");

Scene Rhythm Templates

场景节奏模板

Declare rhythm before implementing:
  • Fast-Fast-SLOW: Quick intro beats → hold for message (2s, 3s, 5s)
  • Build-PEAK-Resolve: Escalating energy → climax → settle (3s, 2s, 4s)
  • Even Pulse: Consistent rhythm (all beats 3-4s, good for instructional)
See references/beat-direction.md for more templates.
实现前先声明节奏:
  • 快-快-慢: 快速开场节拍 → 持续展示信息(2秒、3秒、5秒)
  • 构建-峰值-收尾: 能量逐步提升 → 高潮 → 平稳(3秒、2秒、4秒)
  • 均匀脉动: 节奏一致(所有节拍3-4秒,适合教学内容)
查看references/beat-direction.md获取更多模板。

Animation Conflicts

动画冲突

Never animate the same property on the same element from multiple timelines:
javascript
// ❌ Wrong - both animate opacity
timeline1.to("#el", { opacity: 0.5 });
timeline2.to("#el", { opacity: 1 }); // Conflict!

// ✅ Right - separate properties
timeline1.to("#el", { opacity: 0.5 });
timeline2.to("#el", { x: 100 }); // No conflict
</details>
切勿从多个时间线同时为同一元素的同一属性设置动画:
javascript
// ❌ 错误——两者都动画opacity属性
timeline1.to("#el", { opacity: 0.5 });
timeline2.to("#el", { opacity: 1 }); // 冲突!

// ✅ 正确——属性分离
timeline1.to("#el", { opacity: 0.5 });
timeline2.to("#el", { x: 100 }); // 无冲突
</details>

Scene Transitions (Non-Negotiable)

场景转场(不可协商规则)

Every multi-scene composition MUST follow these 4 rules:
每个多场景合成作品必须遵循以下4条规则:

Rule 1: Always Use Transitions

规则1:始终使用转场

No jump cuts between scenes. Every scene change needs a transition.
场景间禁止跳切。每次场景切换都需要转场。

Rule 2: Always Use Entrance Animations

规则2:始终使用入场动画

Every element in every scene animates IN via
gsap.from()
. No element may appear fully-formed.
每个场景中的每个元素都必须通过
gsap.from()
动画入场。任何元素都不能直接完整显示。

Rule 3: Never Use Exit Animations (Except Final Scene)

规则3:切勿使用退场动画(最终场景除外)

Do NOT animate elements out before a transition. The transition IS the exit. The outgoing scene's content MUST be fully visible when the transition starts.
转场前请勿为元素设置退场动画。转场本身就是退场。转场开始时, outgoing场景的内容必须完全可见。

Rule 4: Final Scene Only

规则4:仅最终场景允许

The last scene is the ONLY scene where
gsap.to(..., { opacity: 0 })
or exit animations are allowed.
Example:
javascript
// Scene 1 (0-7s)
// ✅ Entrance animations only
tl.from("#s1-title", { y: 50, opacity: 0, duration: 0.7, ease: "power3.out" }, 0.3);
tl.from("#s1-subtitle", { y: 30, opacity: 0, duration: 0.5, ease: "power2.out" }, 0.6);
// ❌ NO exit animations - transition handles it

// Transition at 7s (see references/transitions.md)

// Scene 2 (8-15s)
// ✅ Entrance animations
tl.from("#s2-heading", { x: -40, opacity: 0, duration: 0.6, ease: "expo.out" }, 8.0);

// Final scene (15-20s)
// ✅ OK to fade out on final scene only
tl.from("#s3-cta", { scale: 0.9, opacity: 0, duration: 0.5 }, 15.2);
tl.to("#s3-cta", { opacity: 0, duration: 0.5, ease: "power2.in" }, 19.5);
See references/transitions.md for transition implementation.

最后一个场景是唯一允许使用
gsap.to(..., { opacity: 0 })
或退场动画的场景。
示例:
javascript
// 场景1(0-7秒)
// ✅ 仅入场动画
tl.from("#s1-title", { y: 50, opacity: 0, duration: 0.7, ease: "power3.out" }, 0.3);
tl.from("#s1-subtitle", { y: 30, opacity: 0, duration: 0.5, ease: "power2.out" }, 0.6);
// ❌ 禁止退场动画——转场会处理

// 转场在7秒处(查看references/transitions.md)

// 场景2(8-15秒)
// ✅ 入场动画
tl.from("#s2-heading", { x: -40, opacity: 0, duration: 0.6, ease: "expo.out" }, 8.0);

// 最终场景(15-20秒)
// ✅ 仅最终场景允许淡出
tl.from("#s3-cta", { scale: 0.9, opacity: 0, duration: 0.5 }, 15.2);
tl.to("#s3-cta", { opacity: 0, duration: 0.5, ease: "power2.in" }, 19.5);
查看references/transitions.md获取转场实现方法。

Layout Before Animation

先布局后动画

css
.scene-content {
  display: flex;
  flex-direction: column;
  justify-content: center;
  width: 100%;
  height: 100%;
  padding: 120px 160px;
  gap: 24px;
  box-sizing: border-box;
}
.title {
  font-size: 120px;
}
.subtitle {
  font-size: 42px;
}
/* Container fills any scene size (1920x1080, 1080x1920, etc).
   Padding positions content. Flex + gap handles spacing. */
WRONG — hardcoded dimensions and absolute positioning:
css
.scene-content {
  position: absolute;
  top: 200px;
  left: 160px;
  width: 1920px;
  height: 1080px;
  display: flex; /* ... */
}
js
// Step 3: Animate INTO those positions
tl.from(".title", { y: 60, opacity: 0, duration: 0.6, ease: "power3.out" }, 0);
tl.from(".subtitle", { y: 40, opacity: 0, duration: 0.5, ease: "power3.out" }, 0.2);
tl.from(".logo", { scale: 0.8, opacity: 0, duration: 0.4, ease: "power2.out" }, 0.3);

// Step 4: Animate OUT from those positions
tl.to(".title", { y: -40, opacity: 0, duration: 0.4, ease: "power2.in" }, 3);
tl.to(".subtitle", { y: -30, opacity: 0, duration: 0.3, ease: "power2.in" }, 3.1);
tl.to(".logo", { scale: 0.9, opacity: 0, duration: 0.3, ease: "power2.in" }, 3.2);
css
.scene-content {
  display: flex;
  flex-direction: column;
  justify-content: center;
  width: 100%;
  height: 100%;
  padding: 120px 160px;
  gap: 24px;
  box-sizing: border-box;
}
.title {
  font-size: 120px;
}
.subtitle {
  font-size: 42px;
}
/* 容器适配任何场景尺寸(1920x1080、1080x1920等)。
   内边距定位内容。Flex + gap处理间距。 */
错误——硬编码尺寸和绝对定位:
css
.scene-content {
  position: absolute;
  top: 200px;
  left: 160px;
  width: 1920px;
  height: 1080px;
  display: flex; /* ... */
}
js
// 步骤3:动画进入这些位置
tl.from(".title", { y: 60, opacity: 0, duration: 0.6, ease: "power3.out" }, 0);
tl.from(".subtitle", { y: 40, opacity: 0, duration: 0.5, ease: "power3.out" }, 0.2);
tl.from(".logo", { scale: 0.8, opacity: 0, duration: 0.4, ease: "power2.out" }, 0.3);

// 步骤4:从这些位置动画退出
tl.to(".title", { y: -40, opacity: 0, duration: 0.4, ease: "power2.in" }, 3);
tl.to(".subtitle", { y: -30, opacity: 0, duration: 0.3, ease: "power2.in" }, 3.1);
tl.to(".logo", { scale: 0.9, opacity: 0, duration: 0.3, ease: "power2.in" }, 3.2);

When elements share space across time

当元素在同一空间不同时间出现时

If element A exits before element B enters in the same area, both should have correct CSS positions for their respective hero frames. The timeline ordering guarantees they never visually coexist — but if you skip the layout step, you won't catch the case where they accidentally overlap due to a timing error.
如果元素A在元素B进入同一区域前退出,两者都应为各自的关键帧设置正确的CSS位置。时间线顺序保证它们不会同时在视觉上存在——但如果跳过布局步骤,你将无法发现因时间错误导致的意外重叠情况。

What counts as intentional overlap

什么是有意重叠

Layered effects (glow behind text, shadow elements, background patterns) and z-stacked designs (card stacks, depth layers) are intentional. The layout step is about catching unintentional overlap — two headlines landing on top of each other, a stat covering a label, content bleeding off-frame.
分层效果(文本后的发光、阴影元素、背景图案)和z轴堆叠设计(卡片堆叠、深度层)属于有意重叠。布局步骤是为了发现意外重叠——两个标题相互覆盖、统计数据覆盖标签、内容溢出屏幕。

Data Attributes

数据属性

All Clips

所有片段

AttributeRequiredValues
id
YesUnique identifier
data-start
YesSeconds or clip ID reference (
"el-1"
,
"intro + 2"
)
data-duration
Required for img/div/compositionsSeconds. Video/audio defaults to media duration.
data-track-index
YesInteger. Same-track clips cannot overlap.
data-media-start
NoTrim offset into source (seconds)
data-volume
No0-1 (default 1)
data-track-index
does not affect visual layering — use CSS
z-index
.
属性是否必填
id
唯一标识符
data-start
秒数或片段ID引用(
"el-1"
,
"intro + 2"
data-duration
img/div/compositions必填秒数。视频/音频默认使用媒体时长。
data-track-index
整数。同轨道片段不能重叠。
data-media-start
源媒体的裁剪偏移量(秒)
data-volume
0-1(默认值1)
data-track-index
影响视觉层级——请使用CSS
z-index

Composition Clips

合成片段

AttributeRequiredValues
data-composition-id
YesUnique composition ID
data-start
YesStart time (root composition: use
"0"
)
data-duration
YesTakes precedence over GSAP timeline duration
data-width
/
data-height
YesPixel dimensions (1920x1080 or 1080x1920)
data-composition-src
NoPath to external HTML file
data-variable-values
NoJSON object of per-instance variable overrides on a sub-comp host
On the root
<html>
element:
AttributeRequiredValues
data-composition-variables
NoJSON array of declared variables (id/type/label/default) — drives Studio editing UI and provides defaults for
getVariables()
属性是否必填
data-composition-id
唯一合成ID
data-start
开始时间(根合成:使用
"0"
data-duration
优先级高于GSAP时间线时长
data-width
/
data-height
像素尺寸(1920x1080或1080x1920)
data-composition-src
外部HTML文件路径
data-variable-values
子合成宿主的每个实例变量覆盖的JSON对象
在根
<html>
元素上:
属性是否必填
data-composition-variables
已声明变量的JSON数组(id/type/label/default)——驱动Studio编辑UI并为
getVariables()
提供默认值

Composition Structure

合成结构

Sub-compositions loaded via
data-composition-src
use a
<template>
wrapper. Standalone compositions (the main index.html) do NOT use
<template>
— they put the
data-composition-id
div directly in
<body>
. Using
<template>
on a standalone file hides all content from the browser and breaks rendering.
Sub-composition structure:
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>
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>
通过
data-composition-src
加载的子合成作品使用
<template>
包裹。独立合成作品(主index.html)请勿使用
<template>
——将
data-composition-id
div直接放在
<body>
中。在独立文件中使用
<template>
会隐藏所有内容,导致渲染失败。
子合成结构:
html
<template id="my-comp-template">
  <div data-composition-id="my-comp" data-width="1920" data-height="1080">
    <!-- 内容 -->
    <style>
      [data-composition-id="my-comp"] {
        /* 作用域样式 */
      }
    </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 });
      // 补间...
      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>

Variables (Parametrized Compositions)

变量(参数化合成)

Render the same composition with different content — title, theme color, prices, captions — without editing the source HTML.
Three-step pattern:
  1. Declare variables on the composition's
    <html>
    root with
    data-composition-variables
    . Each entry needs
    id
    ,
    type
    (one of
    string
    ,
    number
    ,
    color
    ,
    boolean
    ,
    enum
    ),
    label
    , and
    default
    . Enum entries also need
    options: [{value, label}, ...]
    .
  2. Read the resolved values inside the composition's script with
    window.__framevideo.getVariables()
    . Returns the merged result of declared defaults + per-instance overrides + CLI overrides.
  3. Override at render time with
    npx framevideo render --variables '{...}'
    (top-level) or with
    data-variable-values='{...}'
    on the host element (per-instance for sub-comps).
html
<!doctype html>
<html
  data-composition-variables='[
  {"id":"title","type":"string","label":"Title","default":"Hello"},
  {"id":"theme","type":"enum","label":"Theme","default":"light","options":[
    {"value":"light","label":"Light"},
    {"value":"dark","label":"Dark"}
  ]}
]'
>
  <body>
    <div data-composition-id="root" data-width="1920" data-height="1080">
      <h1 id="hero" class="clip" data-start="0" data-duration="3"></h1>
      <script>
        const { title, theme } = window.__framevideo.getVariables();
        document.getElementById("hero").textContent = title;
        document.body.dataset.theme = theme;
      </script>
    </div>
  </body>
</html>
bash
undefined
无需编辑源HTML,即可使用不同内容(标题、主题颜色、价格、字幕)渲染同一合成作品。
三步模式:
  1. 声明在合成作品的
    <html>
    根元素上,使用
    data-composition-variables
    。每个条目需要
    id
    type
    string
    number
    color
    boolean
    enum
    之一)、
    label
    default
    。Enum条目还需要
    options: [{value, label}, ...]
  2. 读取在合成作品的脚本中,使用
    window.__framevideo.getVariables()
    。返回已声明默认值 + 每个实例覆盖值 + CLI覆盖值的合并结果。
  3. 渲染时覆盖使用
    npx framevideo render --variables '{...}'
    (顶层)或在宿主元素上使用
    data-variable-values='{...}'
    (子合成的每个实例)。
html
<!doctype html>
<html
  data-composition-variables='[
  {"id":"title","type":"string","label":"Title","default":"Hello"},
  {"id":"theme","type":"enum","label":"Theme","default":"light","options":[
    {"value":"light","label":"Light"},
    {"value":"dark","label":"Dark"}
  ]}
]'
>
  <body>
    <div data-composition-id="root" data-width="1920" data-height="1080">
      <h1 id="hero" class="clip" data-start="0" data-duration="3"></h1>
      <script>
        const { title, theme } = window.__framevideo.getVariables();
        document.getElementById("hero").textContent = title;
        document.body.dataset.theme = theme;
      </script>
    </div>
  </body>
</html>
bash
undefined

Dev preview uses declared defaults

开发预览使用已声明的默认值

npx framevideo preview
npx framevideo preview

Render with overrides

使用覆盖值渲染

npx framevideo render --variables '{"title":"Q4 Report","theme":"dark"}' --output q4.mp4
npx framevideo render --variables '{"title":"Q4 Report","theme":"dark"}' --output q4.mp4

Or from a JSON file

或从JSON文件读取

npx framevideo render --variables-file ./vars.json

**Sub-composition per-instance values:** the same `getVariables()` works inside sub-comps loaded via `data-composition-src`. Each host element passes its own values:

```html
<div
  data-composition-id="card-pro"
  data-composition-src="compositions/card.html"
  data-variable-values='{"title":"Pro","price":"$29"}'
></div>
<div
  data-composition-id="card-enterprise"
  data-composition-src="compositions/card.html"
  data-variable-values='{"title":"Enterprise","price":"Custom"}'
></div>
The runtime layers each host's
data-variable-values
over the sub-comp's declared defaults on a per-instance basis, so the same source can be embedded multiple times with different content.
Rules of thumb:
  • Always provide a sensible
    default
    for every declared variable. Dev preview uses defaults — without them, the composition won't render correctly until
    --variables
    is provided.
  • Read variables once at the top of the script (
    const { title } = ...
    ), not inside frame loops or event handlers —
    getVariables()
    allocates a fresh object per call.
  • Use
    --strict-variables
    in CI to fail fast on undeclared keys or type mismatches.
  • Variable types are validated at render time.
    string
    ,
    number
    ,
    boolean
    , and
    color
    (hex string) check
    typeof
    ;
    enum
    checks the value is in the declared
    options
    .
npx framevideo render --variables-file ./vars.json

**子合成的每个实例值:** 相同的`getVariables()`在通过`data-composition-src`加载的子合成中也能工作。每个宿主元素传递自己的值:

```html
<div
  data-composition-id="card-pro"
  data-composition-src="compositions/card.html"
  data-variable-values='{"title":"Pro","price":"$29"}'
></div>
<div
  data-composition-id="card-enterprise"
  data-composition-src="compositions/card.html"
  data-variable-values='{"title":"Enterprise","price":"Custom"}'
></div>
运行时将每个宿主的
data-variable-values
覆盖到子合成的已声明默认值上,每个实例独立处理,因此同一源可以多次嵌入并使用不同内容。
经验法则:
  • 始终为每个已声明变量提供合理的
    default
    值。开发预览使用默认值——如果没有默认值,在提供
    --variables
    前合成作品无法正确渲染。
  • 在脚本顶部读取变量一次(
    const { title } = ...
    ),不要在帧循环或事件处理程序中读取——
    getVariables()
    每次调用都会分配一个新对象。
  • 在CI中使用
    --strict-variables
    快速检测未声明的键或类型不匹配。
  • 变量类型在渲染时验证。
    string
    number
    boolean
    color
    (十六进制字符串)检查
    typeof
    enum
    检查值是否在已声明的
    options
    中。

Video and Audio

视频和音频

Video must be
muted playsinline
. Audio is always a separate
<audio>
element:
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>
For background music from the Chanjing platform, use the CLI to download a local asset first:
bash
npx framevideo chanjing music list --compact
npx framevideo chanjing music download --id <music-id> --chorus --duration 10 --json
Use the returned
htmlSnippet
or author the same shape manually. Keep BGM local under
assets/music/
; do not reference remote Chanjing/OSS URLs directly in composition HTML. Suggested BGM volume is
0.10-0.22
; use
data-volume="0.12"
when speech or digital-human narration is present.
For sound effects from the Chanjing platform, download the SFX asset first and place it at the event time:
bash
npx framevideo chanjing sound-effect list --compact
npx framevideo chanjing sfx download --id <effect-id> --volume 0.8 --json
Keep SFX local under
assets/sfx/
. Use short, event-specific
<audio>
clips with
data-start
set to the exact cue time,
data-track-index="30"
or higher, and
data-volume="0.6-1"
depending on the mix.
视频必须设置
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>
对于来自Chanjing平台的背景音乐,先使用CLI下载本地资产:
bash
npx framevideo chanjing music list --compact
npx framevideo chanjing music download --id <music-id> --chorus --duration 10 --json
使用返回的
htmlSnippet
或手动编写相同结构。将背景音乐保存在本地
assets/music/
下;请勿在合成HTML中直接引用Chanjing/OSS远程URL。建议背景音乐音量为
0.10-0.22
;当有语音或数字人旁白时,使用
data-volume="0.12"
对于来自Chanjing平台的音效,先下载音效资产并放置在事件时间点:
bash
npx framevideo chanjing sound-effect list --compact
npx framevideo chanjing sfx download --id <effect-id> --volume 0.8 --json
将音效保存在本地
assets/sfx/
下。使用短的、事件特定的
<audio>
片段,
data-start
设置为精确的提示时间,
data-track-index="30"
或更高,
data-volume="0.6-1"
(根据混音调整)。

Timeline Contract

时间线约定

  • All timelines start
    { paused: true }
    — the player controls playback
  • Register every timeline:
    window.__timelines["<composition-id>"] = tl
  • Framework auto-nests sub-timelines — do NOT manually add them
  • Duration comes from
    data-duration
    , not from GSAP timeline length
  • Never create empty tweens to set duration
  • 所有时间线启动时设置
    { paused: true }
    ——播放器控制播放
  • 注册每个时间线:
    window.__timelines["<composition-id>"] = tl
  • 框架自动嵌套子时间线——请勿手动添加
  • 时长来自
    data-duration
    ,而非GSAP时间线长度
  • 切勿创建空补间来设置时长

Rules (Non-Negotiable)

规则(不可协商)

Deterministic: No
Math.random()
,
Date.now()
, or time-based logic. Use a seeded PRNG if you need pseudo-random values (e.g. mulberry32).
GSAP: Only animate visual properties (
opacity
,
x
,
y
,
scale
,
rotation
,
color
,
backgroundColor
,
borderRadius
, transforms). Do NOT animate
visibility
,
display
, or call
video.play()
/
audio.play()
.
Animation conflicts: Never animate the same property on the same element from multiple timelines simultaneously.
No
repeat: -1
:
Infinite-repeat timelines break the capture engine. Calculate the exact repeat count from composition duration:
repeat: Math.ceil(duration / cycleDuration) - 1
.
Synchronous timeline construction: Never build timelines inside
async
/
await
,
setTimeout
, or Promises. The capture engine reads
window.__timelines
synchronously after page load. Fonts are embedded by the compiler, so they're available immediately — no need to wait for font loading.
Never do:
  1. Forget
    window.__timelines
    registration
  2. Use video for audio — always muted video + separate
    <audio>
  3. Nest video inside a timed div — use a non-timed wrapper
  4. Use
    data-layer
    (use
    data-track-index
    ) or
    data-end
    (use
    data-duration
    )
  5. Animate video element dimensions — animate a wrapper div
  6. Call play/pause/seek on media — framework owns playback
  7. Create a top-level container without
    data-composition-id
  8. Use
    repeat: -1
    on any timeline or tween — always finite repeats
  9. Build timelines asynchronously (inside
    async
    ,
    setTimeout
    ,
    Promise
    )
  10. Use
    gsap.set()
    on clip elements from later scenes — they don't exist in the DOM at page load. Use
    tl.set(selector, vars, timePosition)
    inside the timeline at or after the clip's
    data-start
    time instead.
  11. Use
    <br>
    in content text — forced line breaks don't account for actual rendered font width. Text that wraps naturally + a
    <br>
    produces an extra unwanted break, causing overlap. Let text wrap via
    max-width
    instead. Exception: short display titles where each word is deliberately on its own line (e.g., "THE\nIMMORTAL\nGAME" at 130px).
确定性: 禁止使用
Math.random()
Date.now()
或基于时间的逻辑。如果需要伪随机值,请使用种子PRNG(如mulberry32)。
GSAP: 仅动画视觉属性(
opacity
x
y
scale
rotation
color
backgroundColor
borderRadius
、变换)。请勿动画
visibility
display
或调用
video.play()
/
audio.play()
动画冲突: 切勿从多个时间线同时为同一元素的同一属性设置动画。
禁止
repeat: -1
无限重复的时间线会破坏捕获引擎。根据合成时长计算精确的重复次数:
repeat: Math.ceil(duration / cycleDuration) - 1
同步时间线构建: 切勿在
async
/
await
setTimeout
或Promise内构建时间线。捕获引擎在页面加载后同步读取
window.__timelines
。字体由编译器嵌入,因此立即可用——无需等待字体加载。
切勿执行以下操作:
  1. 忘记注册
    window.__timelines
  2. 使用视频承载音频——始终使用静音视频 + 单独的
    <audio>
  3. 将视频嵌套在定时div中——使用非定时包装器
  4. 使用
    data-layer
    (请使用
    data-track-index
    )或
    data-end
    (请使用
    data-duration
  5. 动画视频元素尺寸——动画包装div
  6. 调用媒体的play/pause/seek——框架负责播放
  7. 创建没有
    data-composition-id
    的顶层容器
  8. 在任何时间线或补间上使用
    repeat: -1
    ——始终使用有限重复
  9. 异步构建时间线(在
    async
    setTimeout
    、Promise内)
  10. 在脚本中对后续场景的片段元素使用
    gsap.set()
    ——页面加载时它们不存在于DOM中。请在时间线中片段的
    data-start
    时间或之后使用
    tl.set(selector, vars, timePosition)
  11. 在内容文本中使用
    <br>
    ——强制换行不考虑实际渲染的字体宽度。自然换行的文本 +
    <br>
    会产生额外的不必要换行,导致重叠。请通过
    max-width
    让文本自然换行。例外:短展示标题,每个单词故意单独一行(如130px字体的"THE\nIMMORTAL\nGAME")。

Scene Transitions (Non-Negotiable)

场景转场(不可协商规则)

Every multi-scene composition MUST follow ALL of these rules. Violating any one of them is a broken composition.
  1. ALWAYS use transitions between scenes. No jump cuts. No exceptions.
  2. ALWAYS use entrance animations on every scene. Every element animates IN via
    gsap.from()
    . No element may appear fully-formed. If a scene has 5 elements, it needs 5 entrance tweens.
  3. NEVER use exit animations except on the final scene. This means: NO
    gsap.to()
    that animates opacity to 0, y offscreen, scale to 0, or any other "out" animation before a transition fires. The transition IS the exit. The outgoing scene's content MUST be fully visible at the moment the transition starts.
  4. Final scene only: The last scene may fade elements out (e.g., fade to black). This is the ONLY scene where
    gsap.to(..., { opacity: 0 })
    is allowed.
WRONG — exit animation before transition:
js
// BANNED — this empties the scene before the transition can use it
tl.to("#s1-title", { opacity: 0, y: -40, duration: 0.4 }, 6.5);
tl.to("#s1-subtitle", { opacity: 0, duration: 0.3 }, 6.7);
// transition fires on empty frame
RIGHT — entrance only, transition handles exit:
js
// Scene 1 entrance animations
tl.from("#s1-title", { y: 50, opacity: 0, duration: 0.7, ease: "power3.out" }, 0.3);
tl.from("#s1-subtitle", { y: 30, opacity: 0, duration: 0.5, ease: "power2.out" }, 0.6);
// NO exit tweens — transition at 7.2s handles the scene change
// Scene 2 entrance animations
tl.from("#s2-heading", { x: -40, opacity: 0, duration: 0.6, ease: "expo.out" }, 8.0);
每个多场景合成作品必须遵循所有这些规则。违反任何一条都会导致合成作品损坏。
  1. 场景间始终使用转场。 禁止跳切。无例外。
  2. 每个场景始终使用入场动画。 每个元素都必须通过
    gsap.from()
    动画入场。任何元素都不能直接完整显示。如果一个场景有5个元素,就需要5个入场补间。
  3. 除最终场景外,切勿使用退场动画。 这意味着:转场触发前,禁止使用
    gsap.to()
    将透明度动画为0、y轴移出屏幕、缩放为0或任何其他“退场”动画。转场本身就是退场。转场开始时, outgoing场景的内容必须完全可见。
  4. 仅最终场景允许: 最后一个场景可以淡出元素(如淡入黑场)。这是唯一允许使用
    gsap.to(..., { opacity: 0 })
    的场景。
错误——转场前使用退场动画:
js
// 禁止——这会在转场可用前清空场景
tl.to("#s1-title", { opacity: 0, y: -40, duration: 0.4 }, 6.5);
tl.to("#s1-subtitle", { opacity: 0, duration: 0.3 }, 6.7);
// 转场在空帧上触发
正确——仅入场动画,转场处理退场:
js
// 场景1入场动画
tl.from("#s1-title", { y: 50, opacity: 0, duration: 0.7, ease: "power3.out" }, 0.3);
tl.from("#s1-subtitle", { y: 30, opacity: 0, duration: 0.5, ease: "power2.out" }, 0.6);
// 无退场补间——7.2秒处的转场处理场景切换
// 场景2入场动画
tl.from("#s2-heading", { x: -40, opacity: 0, duration: 0.6, ease: "expo.out" }, 8.0);

Animation Guardrails

动画约束规则

  • Offset first animation 0.1-0.3s (not t=0)
  • Vary eases across entrance tweens — use at least 3 different eases per scene
  • Don't repeat an entrance pattern within a scene
  • Avoid full-screen linear gradients on dark backgrounds (H.264 banding — use radial or solid + localized glow)
  • 60px+ headlines, 20px+ body, 16px+ data labels for rendered video
  • font-variant-numeric: tabular-nums
    on number columns
If no
frame.md
or
design.md
exists, follow house-style.md for aesthetic defaults.
  • 首个动画偏移0.1-0.3秒(不要在t=0开始)
  • 入场补间使用多样化的缓动效果——每个场景至少使用3种不同的缓动效果
  • 场景内不要重复入场模式
  • 深色背景上避免全屏线性渐变(H.264色带——使用径向渐变或纯色 + 局部发光)
  • 渲染视频的标题至少60px,正文至少20px,数据标签至少16px
  • 数字列使用
    font-variant-numeric: tabular-nums
如果不存在
frame.md
design.md
,请遵循house-style.md的美学默认值。

Typography and Assets

排版和资产

  • Built-in fonts: Write the
    font-family
    you want in CSS — the compiler embeds supported fonts automatically.
  • Custom fonts: If the spec (
    frame.md
    or
    design.md
    ) names a font that isn't built-in, the user must provide
    .woff2
    files in a
    fonts/
    directory. If missing, warn before writing HTML. When files exist, add
    @font-face
    declarations pointing to the local files.
  • Add
    crossorigin="anonymous"
    to external media
  • For dynamic text overflow, use
    window.__framevideo.fitTextFontSize(text, { maxWidth, fontFamily, fontWeight })
  • All files live at the project root alongside
    index.html
    ; sub-compositions use
    ../
  • 内置字体: 在CSS中写入你想要的
    font-family
    ——编译器会自动嵌入支持的字体。
  • 自定义字体: 如果规范(
    frame.md
    design.md
    )指定了非内置字体,用户必须在
    fonts/
    目录中提供
    .woff2
    文件。如果缺失,编写HTML前警告用户。当文件存在时,添加指向本地文件的
    @font-face
    声明。
  • 为外部媒体添加
    crossorigin="anonymous"
  • 对于动态文本溢出,使用
    window.__framevideo.fitTextFontSize(text, { maxWidth, fontFamily, fontWeight })
  • 所有文件与
    index.html
    一起放在项目根目录;子合成使用
    ../

Editing Existing Compositions

编辑现有合成作品

  • Read actual files, don't guess. When editing, extending, or creating companion compositions, read the existing source. Don't reconstruct hex codes from memory. Don't guess GSAP easing patterns. The composition IS the spec — extract exact values from it.
  • Match existing fonts, colors, animation patterns from what you read
  • Only change what was requested
  • Preserve timing of unrelated clips
  • 读取实际文件,不要猜测。 编辑、扩展或创建配套合成作品时,读取现有源代码。不要凭记忆重构十六进制代码。不要猜测GSAP缓动模式。合成作品本身就是规范——从中提取精确值。
  • 匹配现有字体、颜色、动画模式
  • 仅修改用户要求的内容
  • 保留无关片段的时间控制

Output Checklist

输出检查清单

Chanjing OAuth During Authoring

创作期间的Chanjing OAuth

When a requested video needs Chanjing-backed features (public voices, platform speech, digital humans, or any Studio panel reporting missing Chanjing auth), invoke the
chanjing-digital-human
skill — especially Auth Contract and Missing Credentials UX. Do not stop at terminal env-var guidance when preview/Studio login is available.
Never print, echo, or commit tokens or credential-store contents. Do not fake generated assets when auth is missing; continue with placeholders only if the user accepts that as an interim state.
当请求的视频需要Chanjing支持的功能(公共语音、平台语音、数字人或任何Studio面板报告缺少Chanjing授权)时,调用
chanjing-digital-human
技能——尤其是授权约定缺少凭证UX。当预览/Studio登录可用时,不要仅停留在终端环境变量指导。
切勿打印、回显或提交令牌或凭证存储内容。当缺少授权时,不要伪造生成的资产;仅当用户接受作为临时状态时,才使用占位符继续。

Output Checklist

输出检查清单

Fast (run immediately, block on results):
  • npx framevideo lint
    and
    npx framevideo validate
    both pass
  • Design adherence verified if a design spec (
    frame.md
    or
    design.md
    ) exists
Slow (run in parallel while presenting the preview to the user):
  • npx framevideo inspect
    passes, or every reported overflow is intentionally marked
  • Contrast warnings addressed (see Quality Checks below)
  • Animation choreography verified (see Quality Checks below)
  • framevideo-visual-qa
    applied for new compositions and significant visual changes
快速检查(立即运行,等待结果):
  • npx framevideo lint
    npx framevideo validate
    都通过
  • 如果存在设计规范(
    frame.md
    design.md
    ),验证是否符合设计要求
慢速检查(向用户展示预览时并行运行):
  • npx framevideo inspect
    通过,或每个报告的溢出都已标记为有意
  • 对比度警告已处理(见下文质量检查)
  • 动画编排已验证(见下文质量检查)
  • 新合成作品和重大视觉变更已应用
    framevideo-visual-qa

Quality Checks

质量检查

Visual Inspect

视觉检查

framevideo inspect
runs the composition in headless Chrome, seeks through the timeline, and maps visual layout issues with timestamps, selectors, bounding boxes, and fix hints. Run it after
lint
and
validate
:
bash
npx framevideo inspect
npx framevideo inspect --json
Failures usually mean text is spilling out of a bubble/card, a fixed-size label is clipping dynamic copy, or text has moved off the canvas. Fix by increasing container size or padding, reducing font size or letter spacing, adding a real
max-width
so text wraps inside the container, or using
window.__framevideo.fitTextFontSize(...)
for dynamic copy.
Use
--samples 15
for dense videos and
--at 1.5,4,7.25
for specific hero frames. Repeated static issues are collapsed by default to avoid flooding agent context. If overflow is intentional for an entrance/exit animation, mark the element or ancestor with
data-layout-allow-overflow
. If a decorative element should never be audited, mark it with
data-layout-ignore
.
framevideo layout
is the compatibility alias for the same check.
framevideo inspect
在无头Chrome中运行合成作品,遍历时间线,映射带有时间戳、选择器、边界框和修复提示的视觉布局问题。在
lint
validate
后运行:
bash
npx framevideo inspect
npx framevideo inspect --json
失败通常意味着文本溢出气泡/卡片、固定尺寸标签裁剪动态内容或文本移出画布。修复方法包括增加容器尺寸或内边距、减小字体大小或字间距、添加真实的
max-width
让文本在容器内换行,或对动态内容使用
window.__framevideo.fitTextFontSize(...)
对于密集视频使用
--samples 15
,对于特定关键帧使用
--at 1.5,4,7.25
。默认情况下,重复的静态问题会被折叠,避免淹没代理上下文。如果溢出是入场/退场动画的有意效果,标记元素或祖先为
data-layout-allow-overflow
。如果装饰元素不应被审核,标记为
data-layout-ignore
framevideo layout
是同一检查的兼容性别名。

Contrast

对比度

framevideo validate
runs a WCAG contrast audit by default. It seeks to 5 timestamps, screenshots the page, samples background pixels behind every text element, and computes contrast ratios. Failures appear as warnings:
⚠ WCAG AA contrast warnings (3):
  · .subtitle "secondary text" — 2.67:1 (need 4.5:1, t=5.3s)
If warnings appear:
  • On dark backgrounds: brighten the failing color until it clears 4.5:1 (normal text) or 3:1 (large text, 24px+ or 19px+ bold)
  • On light backgrounds: darken it
  • Stay within the palette family — don't invent a new color, adjust the existing one
  • Re-run
    framevideo validate
    until clean
Use
--no-contrast
to skip if iterating rapidly and you'll check later.
framevideo validate
默认运行WCAG对比度审核。它会定位到5个时间戳,截图页面,采样每个文本元素后的背景像素,计算对比度比率。失败会显示为警告:
⚠ WCAG AA对比度警告(3):
  · .subtitle "secondary text" — 2.67:1(需要4.5:1,t=5.3秒)
如果出现警告:
  • 深色背景:调亮失败的颜色直到对比度超过4.5:1(普通文本)或3:1(大文本,24px+或19px+粗体)
  • 浅色背景:调暗颜色
  • 保持在调色板范围内——不要创建新颜色,调整现有颜色
  • 重新运行
    framevideo validate
    直到无警告
如果快速迭代并稍后检查,可使用
--no-contrast
跳过。

Design Adherence

设计合规性

If a design spec (
frame.md
or
design.md
) exists, verify the composition follows it after authoring. Read the HTML and check:
  1. Colors — every hex value in the composition appears in the spec's palette section (however the user labeled it: Colors, Palette, Theme, etc.). Flag any invented colors.
  2. Typography — font families and weights match the spec's type spec. No substitutions.
  3. Corners — border-radius values match the declared corner style, if specified.
  4. Spacing — padding and gap values fall within the declared density range, if specified.
  5. Depth — shadow usage matches the declared depth level, if specified (flat = none, subtle = light, layered = glows).
  6. Avoidance rules — if the spec has a section listing things to avoid (commonly "What NOT to Do", "Don'ts", "Anti-patterns", or "Do's and Don'ts"), verify none are present.
Report violations as a checklist. Fix each one before serving.
If no design spec exists (house-style-only path), verify:
  1. Palette consistency — the same bg, fg, and accent colors are used across all scenes. No per-scene color invention.
  2. No lazy defaults — check the composition against house-style.md's "Lazy Defaults to Question" list. If any appear, they must be a deliberate choice for the content, not a default.
如果存在设计规范(
frame.md
design.md
),创作后验证合成作品是否符合规范。读取HTML并检查:
  1. 颜色——合成作品中的每个十六进制值都出现在规范的调色板部分(无论用户如何标记:Colors、Palette、Theme等)。标记任何自行创建的颜色。
  2. 排版——字体族和字重与规范的排版要求匹配。不要替换。
  3. 圆角——border-radius值与声明的圆角样式匹配(如果指定)。
  4. 间距——padding和gap值在声明的密度范围内(如果指定)。
  5. 深度——阴影使用与声明的深度级别匹配(如果指定:flat=无,subtle=浅色,layered=发光)。
  6. 避免规则——如果规范有列出避免事项的章节(通常为“What NOT to Do”、“Don'ts”、“Anti-patterns”或“Do's and Don'ts”),验证是否存在违反情况。
将违规情况作为检查清单报告。修复后再交付。
如果不存在设计规范(仅使用house-style),验证:
  1. 调色板一致性——所有场景使用相同的背景、前景和强调色。不要为每个场景创建新颜色。
  2. 无惰性默认值——对照house-style.md的“Lazy Defaults to Question”列表检查合成作品。如果存在任何惰性默认值,必须是针对内容的 deliberate选择,而非默认值。

Animation Map

动画映射

After authoring animations, run the animation map to verify choreography:
bash
node skills/framevideo/scripts/animation-map.mjs <composition-dir> \
  --out <composition-dir>/.framevideo/anim-map
Outputs a single
animation-map.json
with:
  • Per-tween summaries:
    "#card1 animates opacity+y over 0.50s. moves 23px up. fades in. ends at (120, 200)"
  • ASCII timeline: Gantt chart of all tweens across the composition duration
  • Stagger detection: reports actual intervals (
    "3 elements stagger at 120ms"
    )
  • Dead zones: periods over 1s with no animation — intentional hold or missing entrance?
  • Element lifecycles: first/last animation time, final visibility
  • Scene snapshots: visible element state at 5 key timestamps
  • Flags:
    offscreen
    ,
    collision
    ,
    invisible
    ,
    paced-fast
    (under 0.2s),
    paced-slow
    (over 2s)
Read the JSON. Scan summaries for anything unexpected. Check every flag — fix or justify. Verify the timeline shows the intended choreography rhythm. Re-run after fixes.
Skip on small edits (fixing a color, adjusting one duration). Run on new compositions and significant animation changes.

创作动画后,运行动画映射验证编排:
bash
node skills/framevideo/scripts/animation-map.mjs <composition-dir> \
  --out <composition-dir>/.framevideo/anim-map
输出单个
animation-map.json
,包含:
  • 每个补间摘要
    "#card1 animates opacity+y over 0.50s. moves 23px up. fades in. ends at (120, 200)"
  • ASCII时间线:合成作品时长内所有补间的甘特图
  • 交错检测:报告实际间隔(
    "3 elements stagger at 120ms"
  • 死区:超过1秒无动画的时间段——是有意持续展示还是缺少入场动画?
  • 元素生命周期:首次/末次动画时间、最终可见性
  • 场景快照:5个关键时间点的可见元素状态
  • 标记
    offscreen
    collision
    invisible
    paced-fast
    (少于0.2秒)、
    paced-slow
    (超过2秒)
读取JSON。扫描摘要查找意外内容。检查每个标记——修复或说明理由。验证时间线是否显示预期的编排节奏。修复后重新运行。
小修改(修复颜色、调整一个时长)可跳过。新合成作品和重大动画变更需运行。

References (loaded on demand)

参考资料(按需加载)

  • framevideo-visual-qa
    skill
    — Visual QA for safe areas, overlap, overflow, contrast, dynamic text fitting, and motion collisions. Use after new compositions or major layout/caption/asset changes.
  • references/captions.md — Captions, subtitles, lyrics, karaoke synced to audio. Tone-adaptive style detection, per-word styling, text overflow prevention, caption exit guarantees, word grouping. Read when adding any text synced to audio timing.
  • references/audio-reactive.md — Audio-reactive animation: map frequency bands and amplitude to GSAP properties. Read when visuals should respond to music, voice, or sound.
  • references/css-patterns.md — CSS+GSAP marker highlighting: highlight, circle, burst, scribble, sketchout. Deterministic, fully seekable. Read when adding visual emphasis to text.
  • references/video-composition.md — Video-medium rules: density, color presence, scale, frame composition, the design spec as brand not layout. Always read — these override web instincts.
  • references/beat-direction.md — Beat planning: concept, mood, choreography verbs, rhythm templates, transition decisions, depth layers. Always read for multi-scene compositions.
  • references/typography.md — Typography: font pairing, OpenType features, dark-background adjustments, font discovery script. Always read — every composition has text.
  • references/motion-principles.md — Motion design principles, image motion treatment, load-bearing GSAP rules. Always read — every composition has motion.
  • references/techniques.md — 13 primitive animation techniques with code patterns: SVG drawing, Canvas 2D, CSS 3D, kinetic type, Lottie, video compositing, typing, variable fonts, MotionPath, velocity transitions, audio-reactive, clip-path reveals, WebGL shaders. Adapt the patterns — don't copy-paste. (For pre-built UI templates — terminal chrome, device mockups, moodboard layouts — see
    registry/blocks/
    .)
  • references/html-in-canvas-patterns.md — HTML-in-Canvas patterns: live DOM as GPU texture via
    drawElementImage
    +
    layoutsubtree
    . Shared boilerplate + ~6 effect recipes (iPhone/MacBook mockups, liquid glass, magnetic, portal, shatter, text cursor). Use for 1–3 hero beats per video.
  • references/narration.md — Pacing, tone, script structure, number pronunciation, opening line patterns. Read when the composition includes voiceover or TTS.
  • references/design-picker.md — Create a design.md via visual picker. Read when no
    frame.md
    or
    design.md
    exists and the user wants to create one.
  • visual-styles.md — 8 named visual styles with hex palettes, GSAP easing signatures, and shader pairings. Read when user names a style or when generating a design spec.
  • house-style.md — Default motion, sizing, and color palettes when no
    frame.md
    or
    design.md
    is specified.
  • patterns.md — PiP, title cards, slide show patterns.
  • data-in-motion.md — Data, stats, and infographic patterns.
  • references/transcript-guide.md — Caption-side transcript handling: input formats, mandatory quality check, cleaning JS, OpenAI/Groq API fallback, "if no transcript exists" flow. (For the
    transcribe
    CLI invocation, model selection rules, and the
    .en
    gotcha, see the
    framevideo-media
    skill.)
  • references/dynamic-techniques.md — Dynamic caption animation techniques (karaoke, clip-path, slam, scatter, elastic, 3D).
  • references/transitions.md — Scene transitions: crossfades, wipes, reveals, shader transitions. Energy/mood selection, CSS vs WebGL guidance. Always read for multi-scene compositions — scenes without transitions feel like jump cuts.
    • transitions/catalog.md — Hard rules, scene template, and routing to per-type implementation code.
    • Shader transitions are in
      @framevideo/shader-transitions
      (
      packages/shader-transitions/
      ) — read package source, not skill files.
GSAP patterns and effects are in the
/gsap
skill.
  • framevideo-visual-qa
    技能
    ——视觉QA,涵盖安全区域、重叠、溢出、对比度、动态文本适配和动效冲突。新合成作品或重大布局/字幕/资产变更后使用。
  • references/captions.md——字幕、副标题、歌词、与音频同步的卡拉OK。自适应风格检测、逐词样式、文本溢出预防、字幕退场保证、单词分组。添加任何与音频时间同步的文本时阅读。
  • references/audio-reactive.md——音频响应式动画:将频段和振幅映射到GSAP属性。视觉效果需要响应音乐、语音或声音时阅读。
  • references/css-patterns.md——CSS+GSAP标记高亮:高亮、圆圈、爆发、涂鸦、草图效果。确定性、完全可定位。为文本添加视觉强调时阅读。
  • references/video-composition.md——视频媒体规则:密度、颜色呈现、比例、帧合成、作为品牌而非布局的设计规范。务必阅读——这些规则覆盖网页设计直觉。
  • references/beat-direction.md——节拍规划:概念、氛围、编排动词、节奏模板、转场决策、深度层。多场景合成作品务必阅读。
  • references/typography.md——排版:字体配对、OpenType特性、深色背景调整、字体发现脚本。务必阅读——每个合成作品都有文本。
  • references/motion-principles.md——动效设计原则、图像动效处理、核心GSAP规则。务必阅读——每个合成作品都有动效。
  • references/techniques.md——13种原始动画技术及代码模式:SVG绘制、Canvas 2D、CSS 3D、动态文字、Lottie、视频合成、打字效果、可变字体、MotionPath、速度转场、音频响应、clip-path揭示、WebGL着色器。适配模式——不要复制粘贴。(预构建UI模板——终端界面、设备模型、情绪板布局——请查看
    registry/blocks/
    。)
  • references/html-in-canvas-patterns.md——Canvas内HTML模式:通过
    drawElementImage
    +
    layoutsubtree
    将实时DOM作为GPU纹理。共享模板 + ~6种效果方案(iPhone/MacBook模型、液态玻璃、磁性、门户、破碎、文本光标)。每个视频使用1–3个关键节拍。
  • references/narration.md——节奏、语气、脚本结构、数字发音、开场模式。合成作品包含旁白或TTS时阅读。
  • references/design-picker.md——通过可视化选择器创建design.md。不存在
    frame.md
    design.md
    且用户想要创建时阅读。
  • visual-styles.md——8种命名视觉样式,包含十六进制调色板、GSAP缓动特征和着色器配对。用户指定风格或生成设计规范时阅读。
  • house-style.md——不存在
    frame.md
    design.md
    时的默认动效、尺寸和颜色调色板。
  • patterns.md——画中画、标题卡、幻灯片模式。
  • data-in-motion.md——数据、统计和信息图模式。
  • references/transcript-guide.md——字幕侧转录处理:输入格式、强制质量检查、清理JS、OpenAI/Groq API fallback、“无转录时”流程。(
    transcribe
    CLI调用、模型选择规则和
    .en
    注意事项,请查看
    framevideo-media
    技能。)
  • references/dynamic-techniques.md——动态字幕动画技术(卡拉OK、clip-path、 slam、 scatter、 elastic、3D)。
  • references/transitions.md——场景转场:淡入淡出、擦除、揭示、着色器转场。能量/氛围选择、CSS vs WebGL指南。多场景合成作品务必阅读——无转场的场景会感觉像跳切。
    • transitions/catalog.md——硬规则、场景模板和按类型路由到实现代码。
    • 着色器转场在
      @framevideo/shader-transitions
      packages/shader-transitions/
      )中——阅读包源代码,而非技能文件。
GSAP模式和效果在
/gsap
技能中。