mcpField
F
framevideo

framevideo

github.com/chanjing-ai创意与媒体0181 次安装14 周前更新
代码仓库

关于 framevideo

framevideo 是用于创作 HTML 视频合成的技能,通过定时片段、CSS 和动画时间线组织内容,指导创作者与编码 Agent 进行设计、动画和制作。

主要功能

  1. 01基于 HTML 构建合成
  2. 02使用 data 属性编排片段
  3. 03通过受支持的适配器制作动画
  4. 04创建多场景转场
  5. 05添加字幕和音频响应视觉效果
  6. 06通过变量参数化合成

适用场景

  1. 01使用 HTML 制作动画视频
  2. 02编排视频、音频和叠加片段
  3. 03构建带转场的多场景视频
  4. 04制作字幕或音频响应动画

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/chanjing-ai/framevideo --skill framevideo

安装后在 Claude Code 中输入/framevideo确认已加载。

包含的文件

除 SKILL.md 外,安装时一起下载的参考资料和脚本。

data-in-motion.md
house-style.md
patterns.md
palettes/
bold-energetic.md
clean-corporate.md
dark-premium.md
jewel-rich.md
monochrome.md
nature-earth.md
neon-electric.md
pastel-soft.md
warm-editorial.md
references/
audio-reactive.md
beat-direction.md
captions.md
css-patterns.md
design-picker.md
dynamic-techniques.md
html-in-canvas-patterns.md
motion-principles.md
narration.md
prompt-expansion.md
techniques.md
text-effects.md
transcript-guide.md
transitions.md
references/transitions/
catalog.md
css-3d.md
css-blur.md
css-cover.md

详细介绍

FrameVideo

HTML 是视频的真实来源。一个合成内容是一个 HTML 文件,包含用于计时的 data-* 属性、用于动画的 GSAP 时间轴,以及用于呈现外观的 CSS。框架负责片段可见性、媒体播放和时间轴同步。

适用场景

任何 FrameVideo 合成任务 都使用此技能。这是内容最多的技能(1100 多行)——使用下面的导航,快速找到所需内容。

🚀 初次使用 FrameVideo?
  1. 阅读“快速开始”(第 46 行)——最简可运行示例
  2. 阅读“核心概念”(第 95 行)——数据属性、计时、时间轴约定
  3. 尝试示例,然后返回查找特定功能
🎯 查找特定内容?

布局与结构:

  • 安全区域与边距 → “布局与安全区域”(第 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、transcribe、bg-removal)→ framevideo-media 技能
  • 质量检查与验证 → framevideo-visual-qa 技能
  • 禅境数字人 → chanjing-digital-human 技能

动画适配器路由

大多数 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

所有适配器均遵循同一规则:对渲染至关重要的动画必须具有确定性且可跳转。请勿在时间轴/实例中使用墙上时钟时间、无限循环或异步注册。


快速开始

最简可运行的合成内容:

<!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/[email protected]/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 预览。


章节索引

此技能包含 1100 多行,按以下主要章节组织。可跳转到所需章节:

🎬 核心概念(第 95-200 行)— 如果你刚接触 FrameVideo,请先阅读

  • 数据属性与时间
  • 合成结构
  • 时间线约定
  • 视频与音频
  • 变量(参数化合成)

🎨 布局与设计(第 180-300 行)

  • 安全区域与边距
  • 排版与可读性
  • 色彩与对比度
  • 响应式布局

✨ 动画与运动(第 300-450 行)

  • 动画适配器路由(见上文)
  • GSAP 集成(或加载 gsap 技能了解详情)
  • 时间与缓动
  • 错开模式

🎞️ 场景转场(第 450-580 行)— 多场景视频必读

  • 交叉淡化
  • 擦除与显现
  • 着色器转场
  • 场景架构

📝 字幕(第 580-650 行)

  • 字幕时间
  • 样式与定位
  • 转录文本集成

🎵 音频响应式视觉效果(第 620-720 行)

  • 节拍检测
  • 基于振幅的动画
  • 音乐同步

🔧 高级模式(第 720-900 行)

  • Canvas 中的 HTML 效果
  • 子合成
  • 动态内容
  • 性能优化

📚 参考资料(第 900-1100 行)

  • 示例集
  • 故障排查
  • 最佳实践
  • API 参考

注意: 行号仅供参考。使用 Read 工具的 offset 参数跳转到相应章节;如果需要全面了解,也可以阅读整个文件。


核心概念

  • 视频与音频元素
  • 变量(参数化合成)

布局与安全区域(定位元素时展开):

  • 先布局、后动画原则
  • 容器模式
  • 安全区域规则
  • 文本处理
  • 常见布局模式

动画与运动(添加动态效果时展开):

  • 动画防护规则
  • 进入/退出模式
  • 错开与排序
  • 场景节奏模板
  • 动画冲突

场景转场(多场景视频必读):

  • 4 条不可妥协的规则
  • 转场实现

高级功能(按需查看):

  • 字幕
  • 音频响应式动画
  • CSS 标记高亮
  • 着色器转场

参考资料(深入了解):

  • 参见末尾的“参考资料”章节,那里有 15 多篇详细指南

核心概念

数据属性与时间

每个剪辑都需要以下属性:

属性必需值
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。

合成结构

根元素必须包含以下属性:

<div data-composition-id="main" data-width="1920" data-height="1080">
  
</div>

独立合成(主 index.html):将根 <div> 直接放入 <body>。不要使用 <template>。

子合成(通过 data-composition-src 加载):必须使用 <template> 包装:

<template id="my-comp-template">
  <div data-composition-id="my-comp" data-width="1920" data-height="1080">
    
  </div>
</template>
时间线约定

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
  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>

使用相同的源文件。播放由框架控制——切勿调用 .play()。

变量(参数化组合)

三步模式:

  1. 声明于 <html> 根元素:
<html data-composition-variables='[
  {"id":"title","type":"string","label":"Title","default":"Hello"}
]'>
  1. 在脚本中读取:
const { title } = window.__framevideo.getVariables();
document.getElementById("hero").textContent = title;
  1. 在渲染时覆盖:
npx framevideo render --variables '{"title":"Q4 Report"}'

变量类型:string、number、color、boolean、enum。


📐 布局与安全区域(点击展开)

AI 制作流程

当用户要求将创意、脚本、情节、分镜、参考图片或粗略的视频构想转化为生成视频时,将 framevideo-ai-production 作为工作流的前半部分调用。该技能会将创意素材转化为 Clip、Shot 和 Chanjing AIGC 计划。

如需使用 Chanjing AI 生成真实图片/视频:

  1. 使用 framevideo-ai-production 生成 Shot 级别的 Chanjing AIGC 计划。
  2. 使用 chanjing-digital-human/references/ai-creation.md 了解 Chanjing AI Creation 模型发现、幂等提交、短时同步轮询、下载和本地素材路径。
  3. 仅使用 assets/ai-creation/images/ 或 assets/ai-creation/videos/ 下的本地素材进行合成。
  4. 返回此处构建 FrameVideo HTML 合成、音频、字幕、转场、QA、预览和渲染。

不要将 Chanjing 生成的远程输出 URL 直接插入合成 HTML。

方法

探索(仅适用于探索性请求)

对于开放式请求(“给我做一个产品发布视频”“为我们的品牌创作点内容”),如果用户还没有确定方向,请先了解其意图,再选择颜色:

  • 受众 — 谁会观看?开发者?高管?普通消费者?
  • 平台 — 视频在哪里播放?社交媒体(15 秒)、网站主视觉区、产品演示、内部使用?
  • 优先事项 — 哪一点最重要?动态效果质量?内容准确性?品牌一致性?速度?
  • 变体 — 用户想要多个选项,还是一个最佳镜头?

对于具体请求(“添加标题卡”“修正第 3 个场景的时间”),跳过探索环节。

对于探索性请求,可考虑提供 2–3 个差异显著的变体——不只是更换颜色,还可以采用不同的节奏、能量水平或结构方法。一个稳妥且符合预期,另一个大胆创新。无需强制提供——视情况使用即可。

第 1 步:设计系统

如果项目中已有设计规范,请先阅读。按优先级顺序查找:frame.md → design.md → DESIGN.md(在 Linux 上,design.md 和 DESIGN.md 是不同的文件——请检查这两种大小写;frame.md 始终使用小写,没有 FRAME.md 这个变体)。对于视频/framevideo 项目,frame.md 是首选规范;如果存在多个规范文件,则以它为准。它使用与 design.md 相同的格式。它是品牌颜色、字体和约束的唯一可信来源。请使用其中的确切值,不要臆造颜色或替换字体。任何格式都可以(YAML frontmatter、散文、表格——只需提取其中的值)。

如果规范中指定了你无法在本地找到的字体(没有包含 .woff2 文件的 fonts/ 目录,也不是内置字体),请在编写 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.md 和 house-style.md。请以适合视频的尺度使用品牌颜色,不要使用网页 UI 的不透明度。

第 2 步:扩展提示词

每次创作都必须执行此步骤(单场景作品和简单编辑除外)。此步骤会结合设计规范(frame.md 或 design.md)和 house-style.md 梳理用户意图,并生成统一的中间内容,供所有下游 Agent 以相同方式读取。

阅读 references/prompt-expansion.md,了解完整流程和输出格式。

第 3 步:规划

编写 HTML 前,请先从高层次进行思考:

  1. 内容 — 观众应获得怎样的体验?确定叙事弧线、关键时刻和情绪节点。
  2. 结构 — 需要多少个构图,哪些是子构图,哪些是内联内容;哪些轨道承载什么内容(视频、音频、叠加层、字幕)。
  3. 节奏 — 实现前先确定场景节奏。哪些场景快速切入,哪些需要停留,着色器何时出现,能量何时达到峰值。为节奏模式命名:快-快-慢-快-着色器-停留。阅读 references/beat-direction.md,了解节奏模板。
  4. 时长 — 哪些片段决定时长,转场出现在哪里,节奏如何安排。
  5. 布局 — 先构建最终状态。参见下文“动画前先布局”。
  6. 动画 — 然后按照下方规则添加动态效果。

按要求构建。 用户要求“一个标题卡片”,并不意味着要求“一个标题卡片 + 3 个辅助场景 + 环境音乐 + 字幕”。每个场景、每个元素、每段补间动画都必须有存在的理由。如果增加场景或元素确实能改善作品,请提出建议,不要擅自添加。

对于小幅编辑(修复颜色、调整时间、添加一个元素),直接跳到规则部分。

编写任何构图 HTML 前,必须确认你已从第 1 步获得视觉识别方案。如果你打算使用 `#333`、`#3b82f6` 或 `Roboto`,说明你跳过了这一步。 ### 视觉 QA 技能

创建新构图、进行大幅布局/字幕/素材/图层调整、修复视觉问题,或在宣布构图已达到视觉要求之前,请使用 framevideo-visual-qa 技能。该技能负责通用的视频 QA 规则,包括安全区域、文字与背景的对比度、文字溢出、意外重叠和运动碰撞。请将项目专属的品牌形象保留在 frame.md、design.md 或 DESIGN.md 中;通用视觉 QA 方法则保留在该技能中。


📐 布局与安全区域(点击展开)

先布局,后动画原则

先构建最终状态。 将每个元素放在它最清晰可见的时刻应处的位置——完全进入画面、位置正确,尚未开始退出。先将其编写为静态 HTML+CSS,暂时不要使用 GSAP。

原因: 如果你根据元素的动画起始状态(画面外、缩放为 0、透明度为 0)来定位,再将其动画到你认为的目标位置,那就只能靠猜。渲染前看不到重叠。先构建最终状态,就能在添加动态效果前发现并修复布局问题。

流程:

  1. 确定主视觉帧——大多数元素同时可见的时刻
  2. 为该帧编写静态 CSS
  3. 使用 gsap.from() 添加入场动画——从画面外/不可见状态动画到 CSS 设定的位置
  4. 使用 gsap.to() 添加退场动画——从 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; }
// 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);
容器模式

✅ 全场景容器(推荐):

.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;
}

❌ 不要对内容使用绝对定位:

/* WRONG - breaks on long text */
.scene-content {
  position: absolute;
  top: 200px;
  left: 160px;
  width: 1920px;
  height: 1080px;
}

position: absolute 仅用于装饰元素(粒子、光晕、背景形状)。

安全区域规则

关键信息应保持在安全区域内:

  • 水平: 距离左右边缘约 5%(1920px 宽度时约为 96px)
  • 垂直: 距离顶部/底部边缘约 5%(1080px 高度时约为 54px)
  • 底部(字幕/CTA): 距离底部约 10%(约为 108px)

必须保持在安全区域内的内容:

  • 关键信息、标题、正文
  • Logo(除非有意锚定在边缘)
  • CTA 按钮和链接
  • 字幕
  • 出镜者的脸
  • 产品 UI 截图
  • 法律/价格文案

可以超出安全区域的内容:

  • 全出血背景
  • 装饰性光晕和粒子
  • 颗粒和纹理叠加层
  • 转场效果

标记有意溢出的内容:<div class="grain" data-layout-allow-overflow>

文字处理

自然换行:

.headline {
  max-width: 1200px; /* Wraps at this width */
  font-size: 96px;
  line-height: 1.1;
}

动态适配:

const { title } = window.__framevideo.getVariables();
const fontSize = window.__framevideo.fitTextFontSize(title, {
  maxWidth: 1200,
  fontFamily: 'Inter',
  fontWeight: 700
});
document.getElementById('title').style.fontSize = fontSize + 'px';

避免使用固定尺寸的文字容器——改用带内边距的弹性容器。

常见布局模式

居中标题卡片:

<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>

分栏布局(文字 + 视觉元素):

<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>

🎬 动画与动态效果(点击展开)

动画规范

时间偏移——首次动画绝不能从 t=0 开始:

// ❌ Wrong
tl.from(".title", { opacity: 0 }, 0);

// ✅ Right
tl.from(".title", { opacity: 0 }, 0.2); // 0.1-0.3s offset

改变缓动曲线——每个场景至少使用 3 种不同的缓动效果:

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)

不要重复使用入场模式——每个元素都应采用独特的方向或样式:

// ❌ 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);

性能属性——优先使用 GPU 加速的属性:

  • ✅ 快:opacity、x、y、scale、rotation
  • ❌ 慢:width、height、top、left、margin、padding、font-size
常见动画模式

错开入场:

// 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 - 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

基于标签的序列编排:

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");
场景节奏模板

实现之前先确定节奏:

  • 快-快-慢: 快速开场节拍 → 留出时间传达信息(2s、3s、5s)
  • 铺垫-高潮-收尾: 能量逐渐提升 → 达到高潮 → 平稳收尾(3s、2s、4s)
  • 均匀脉冲: 节奏一致(每个节拍均为 3–4s,适用于教学内容)

更多模板请参阅 references/beat-direction.md。

### 动画冲突

切勿在多个时间线上对同一元素的同一属性制作动画:

// ❌ 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

场景过渡(不可妥协)

每个多场景合成都必须遵循以下 4 条规则:

规则 1:始终使用过渡

场景之间不得硬切。每次场景切换都必须使用过渡。

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

每个场景中的每个元素都必须通过 gsap.from() 动画入场。不得让任何元素以完整形态直接出现。

规则 3:绝不使用退场动画(最后一个场景除外)

过渡开始前不要让元素动画退场。过渡本身就是退场。过渡开始时,离场场景的内容必须完全可见。

规则 4:仅限最后一个场景

只有最后一个场景允许使用 gsap.to(..., { opacity: 0 }) 或退场动画。

示例:

// 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);

过渡实现请参阅 references/transitions.md。


动画前先布局

.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. */

错误 — 尺寸硬编码并使用绝对定位:

.scene-content {
  position: absolute;
  top: 200px;
  left: 160px;
  width: 1920px;
  height: 1080px;
  display: flex; /* ... */
}
// 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);
当元素在不同时间共享空间时

如果元素 A 在元素 B 进入同一区域前退场,两者在各自的主视觉帧中都应有正确的 CSS 位置。时间线的顺序可确保它们不会在视觉上同时出现,但如果跳过布局步骤,就无法发现因计时错误而意外重叠的情况。

哪些情况属于有意重叠

分层效果(文字后的光晕、阴影元素、背景图案)以及按 z 轴堆叠的设计(卡片堆叠、景深层)都属于有意重叠。布局步骤旨在发现无意的重叠——例如两个标题相互覆盖、统计数据遮住标签,或内容溢出画面。

数据属性

所有片段
属性必需值
id是唯一标识符
data-start是秒数或片段 ID 引用("el-1"、"intro + 2")
data-durationimg/div/合成必需秒数。视频/音频默认使用媒体时长。
data-track-index是整数。同一轨道上的片段不能重叠。
data-media-start否源媒体中的剪辑偏移(秒)
data-volume否0-1(默认值为 1)

data-track-index 不会影响视觉分层——请使用 CSS z-index。

合成片段
属性必填值
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() 提供默认值

合成结构

通过 data-composition-src 加载的子合成使用 <template> 包装。独立合成(主 index.html)不使用 <template>——它们会将 data-composition-id div 直接放在 <body> 中。在独立文件中使用 <template> 会使所有内容对浏览器隐藏,并导致渲染失败。

子合成结构:

<template id="my-comp-template">
  <div data-composition-id="my-comp" data-width="1920" data-height="1080">
    
    <style>
      [data-composition-id="my-comp"] {
        /* scoped styles */
      }
    </style>
    <script src="https://cdn.jsdelivr.net/npm/[email protected]/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>

变量(参数化合成)

无需编辑源 HTML,即可使用不同内容渲染同一合成,例如标题、主题颜色、价格和字幕。

三步模式:

  1. 声明:在合成的 <html> 根元素上使用 data-composition-variables 声明变量。每个条目都需要 id、type(取值为 string、number、color、boolean、enum 之一)、label 和 default。枚举条目还需要 options: [{value, label}, ...]。
  2. 读取:在合成脚本中使用 window.__framevideo.getVariables() 读取解析后的值。返回已声明的默认值、每个实例的覆盖值和 CLI 覆盖值合并后的结果。
  3. 覆盖:在渲染时使用 npx framevideo render --variables '{...}'(顶层覆盖),或在宿主元素上使用 data-variable-values='{...}'(为子合成的每个实例分别覆盖)。
<!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>
# Dev preview uses declared defaults
npx framevideo preview

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

# Or from a JSON file
npx framevideo render --variables-file ./vars.json

**子合成的每实例值:**通过 data-composition-src 加载的子合成中也可以使用相同的 getVariables()。每个宿主元素都会传递自己的值:

<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 中。

视频和音频

视频必须设置为 muted playsinline。音频始终使用单独的 <audio> 元素:

<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 下载本地资源:

npx framevideo chanjing music list --compact
npx framevideo chanjing music download --id <music-id> --chorus --duration 10 --json

使用返回的 htmlSnippet,或手动编写相同结构。BGM 应保存在本地的 assets/music/ 下;不要在合成 HTML 中直接引用 Chanjing/OSS 远程 URL。建议将 BGM 音量设为 0.10-0.22;存在语音或数字人旁白时,使用 data-volume="0.12"。

对于 Chanjing 平台的音效,请先下载 SFX 资源,并将其放置在事件发生的时间点:

npx framevideo chanjing sound-effect list --compact
npx framevideo chanjing sfx download --id <effect-id> --volume 0.8 --json

SFX 应保存在本地的 assets/sfx/ 下。使用简短且与事件对应的 <audio> 片段,将 data-start 设为准确的提示时间,将 data-track-index="30" 或更高,并根据混音将 data-volume="0.6-1" 设为适当值。

时间线约定

  • 所有时间线均以 { paused: true } 开始——播放由播放器控制
  • 注册每条时间线:window.__timelines["<composition-id>"] = tl
  • 框架会自动嵌套子时间线——不要手动添加
  • 时长取自 data-duration,而非 GSAP 时间线长度
  • 不要创建空补间来设置时长

规则(不可协商)

确定性: 不要使用 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. 对媒体调用播放/暂停/定位操作——播放由框架控制
  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”)。

场景转场(不可妥协)

每个多场景合成都 MUST 遵循以下所有规则。违反其中任何一条,合成都不合格。

  1. 始终在场景之间使用转场。 不得跳切。没有例外。
  2. 始终为每个场景使用入场动画。 每个元素都必须通过 gsap.from() 动画入场。不得让任何元素以完整形态直接出现。如果一个场景有 5 个元素,就需要 5 个入场补间动画。
  3. 绝不使用退场动画,最后一个场景除外。这意味着:在转场触发之前,不得使用任何让透明度变为 0、让元素沿 y 轴移出屏幕、让缩放变为 0,或执行其他“退场”动画的 gsap.to()。转场本身就是退场。转场开始时,离场场景的内容 MUST 完全可见。
  4. 仅限最后一个场景: 最后一个场景可以淡出元素(例如,淡变为黑屏)。这是唯一允许使用 gsap.to(..., { opacity: 0 }) 的场景。

错误 — 转场前使用退场动画:

// 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

正确 — 仅使用入场动画,由转场处理退场:

// 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);

动画规范

  • 将第一个动画偏移 0.1-0.3 秒(而不是 t=0)
  • 在入场补间动画中使用不同的缓动效果 — 每个场景至少使用 3 种不同的缓动效果
  • 不要在一个场景中重复入场模式
  • 避免在深色背景上使用全屏线性渐变(H.264 会出现色带 — 使用径向渐变,或使用纯色并添加局部辉光)
  • 渲染视频时,标题至少为 60px,正文至少为 20px,数据标签至少为 16px
  • 在数字列上使用 font-variant-numeric: tabular-nums

如果不存在 frame.md 或 design.md,请遵循 house-style.md 中的美学默认规范。

字体排版与资源

  • 内置字体: 在 CSS 中填写所需的 font-family — 编译器会自动嵌入受支持的字体。
  • 自定义字体: 如果规范(frame.md 或 design.md)指定了非内置字体,用户必须在 fonts/ 目录中提供 .woff2 文件。如果缺少文件,请在编写 HTML 前发出警告。文件存在时,添加指向本地文件的 @font-face 声明。
  • 为外部媒体添加 crossorigin="anonymous"
  • 对于动态文本溢出,请使用 window.__framevideo.fitTextFontSize(text, { maxWidth, fontFamily, fontWeight })
  • 所有文件都放在项目根目录,与 index.html 同级;子合成使用 ../

编辑现有合成

  • 读取实际文件,不要猜测。 编辑、扩展或创建配套合成时,请读取现有源文件。不要凭记忆还原十六进制颜色代码。不要猜测 GSAP 缓动模式。合成本身就是规范 — 从中提取精确值。
  • 根据读取到的内容匹配现有字体、颜色和动画模式
  • 只修改用户要求的内容
  • 保留无关片段的时间安排

输出检查清单

创作期间的 Chanjing OAuth

当请求的视频需要 Chanjing 支持的功能(公共语音、平台语音、数字人,或任何 Studio 面板提示缺少 Chanjing 身份验证时),请调用 chanjing-digital-human 技能 — 尤其是 Auth Contract 和 Missing Credentials UX。如果可以通过预览或 Studio 登录,不要只提供终端环境变量的指导就停止。

切勿打印、回显或提交令牌或凭据存储内容。缺少身份验证时,不要伪造生成的资源;只有用户接受临时方案时,才可使用占位内容继续。

输出检查清单

快速检查(立即运行,并等待结果):

  • npx framevideo lint 和 npx framevideo validate 均通过
  • 如果存在设计规范(frame.md 或 design.md),则确认设计规范已遵循

较慢的检查(向用户展示预览时并行运行):

  • npx framevideo inspect 通过,或每个报告的溢出都已明确标记为有意保留
  • 已处理对比度警告(见下方的质量检查)
  • 已验证动画编排(见下方的质量检查)
  • 已对新建合成和重大视觉更改应用 framevideo-visual-qa

质量检查

视觉检查

framevideo inspect 会在无头 Chrome 中运行合成,逐帧检查时间线,并通过时间戳、选择器、边界框和修复提示来定位视觉布局问题。请在运行 lint 和 validate 后使用:

npx framevideo inspect
npx framevideo inspect --json

失败通常意味着文本溢出了气泡或卡片、固定尺寸的标签裁切了动态文案,或文本移出了画布。可通过增大容器尺寸或内边距、减小字号或字间距、设置实际的 max-width 让文本在容器内换行,或对动态文案使用 window.__framevideo.fitTextFontSize(...) 来修复。

对于内容密集的视频,可使用 --samples 15;对于指定的关键帧,可使用 --at 1.5,4,7.25。默认会折叠重复出现的静态问题,以免 Agent 上下文被大量内容淹没。如果溢出是入场或退场动画的预期效果,请为元素或其祖先添加 data-layout-allow-overflow。如果某个装饰元素不应参与审查,请为其添加 data-layout-ignore。

framevideo layout 是同一项检查的兼容别名。

对比度

framevideo validate 默认会运行 WCAG 对比度审计。它会跳转到 5 个时间戳,为页面截图,采样每个文本元素背后的背景像素,并计算对比度。未通过的项目会显示为警告:

⚠ WCAG AA contrast warnings (3):
  · .subtitle "secondary text" — 2.67:1 (need 4.5:1, t=5.3s)

如果出现警告:

  • 深色背景:调亮未通过检查的颜色,直到达到 4.5:1(普通文本)或 3:1(大号文本,24px 及以上,或 19px 及以上的粗体文本)
  • 浅色背景:调暗颜色
  • 保持在同一调色板范围内——不要引入新颜色,而应调整现有颜色
  • 反复运行 framevideo validate,直到没有警告

如果需要快速迭代,之后再检查,可使用 --no-contrast 跳过检查。

设计规范遵循情况

如果存在设计规范(frame.md 或 design.md),完成创作后请确认合成内容符合规范。阅读 HTML 并检查:

  1. 颜色——合成内容中的每个十六进制颜色值都应出现在规范的调色板部分(无论用户将其标为“颜色”“调色板”“主题”等)。标记任何自行引入的颜色。
  2. 字体排印——字体系列和字重应与规范中的字体要求一致,不得替换。
  3. 圆角——如果规范指定了圆角样式,边框圆角值应与之匹配。
  4. 间距——如果规范指定了密度范围,内边距和间隙值应在该范围内。
  5. 层次——阴影的使用应符合规范中声明的层次级别(扁平 = 无阴影,微妙 = 浅阴影,分层 = 光晕)。
  6. 规避规则——如果规范列出了应避免的事项(通常称为“绝对不要做”“禁忌”“反模式”或“应该做与不应该做”),请确认这些事项都未出现。

将违规项整理成检查清单。开始提供服务前,请逐一修复。

如果没有设计规范(仅遵循品牌风格指南的路径),请检查:

  1. 调色板一致性——所有场景使用相同的背景色、前景色和强调色,不得为单个场景自行引入颜色。
  2. 避免偷懒套用默认值——对照 house-style.md 中的“需要审慎考虑的偷懒默认值”列表检查合成内容。如有任何默认值,都必须是基于内容有意选择的,而不是直接套用。
动画映射

编写动画后,运行动画映射以验证动画编排:

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")
  • 空白区间:超过 1s 且没有动画的时段——是有意停顿,还是缺少入场动画?
  • 元素生命周期:首次/最后动画时间、最终可见性
  • 场景快照:5 个关键时间戳处可见元素的状态
  • 标记:offscreen、collision、invisible、paced-fast(短于 0.2s)、paced-slow(长于 2s)

阅读 JSON。检查摘要中是否有异常。检查每个标记,并修正或说明原因。确认时间线体现了预期的动画编排节奏。修正后重新运行。

小幅编辑时跳过(例如修正颜色、调整一个持续时间)。在新建合成和进行重大动画更改时运行。


参考资料(按需加载)

  • framevideo-visual-qa skill — 针对安全区域、重叠、溢出、对比度、动态文本适配和运动碰撞进行视觉 QA。用于新构图或重大布局、字幕、素材变更后。
  • references/captions.md — 与音频同步的字幕、歌词和卡拉 OK。根据语气自适应检测样式、逐词设置样式、防止文本溢出、确保字幕退出、分组单词。添加任何与音频时间同步的文本时阅读。
  • references/audio-reactive.md — 音频响应动画:将频段和振幅映射到 GSAP 属性。需要视觉效果响应音乐、语音或声音时阅读。
  • references/css-patterns.md — CSS+GSAP 标记高亮:高亮、画圈、爆发、涂鸦、描摹。确定性强且完全可寻址。为文本添加视觉强调时阅读。
  • references/video-composition.md — 视频媒介规则:密度、色彩呈现、缩放、画面构图,以及将设计规范视为品牌而非布局。始终阅读——这些规则优先于 Web 设计直觉。
  • 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 — HTML-in-Canvas 模式:通过 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 — PiP、标题卡、幻灯片模式。
  • data-in-motion.md — 数据、统计和信息图模式。
  • references/transcript-guide.md — 字幕侧的转录处理:输入格式、强制质量检查、JS 清理、OpenAI/Groq API 回退方案、“不存在转录文本时”的处理流程。(关于 transcribe CLI 调用、模型选择规则和 .en 陷阱,请参见 framevideo-media skill。)
  • references/dynamic-techniques.md — 动态字幕动画技术(卡拉 OK、clip-path、猛击、散射、弹性、3D)。
  • references/transitions.md — 场景转场:交叉淡化、擦除、显现、着色器转场。能量感/氛围选择、CSS 与 WebGL 指南。多场景合成时务必阅读——没有转场的场景会显得像跳切。
    • transitions/catalog.md — 硬性规则、场景模板,以及各类型实现代码的索引。
    • 着色器转场位于 @framevideo/shader-transitions(packages/shader-transitions/)中——请阅读软件包源代码,而非技能文件。

GSAP 模式和效果位于 /gsap 技能中。

评论

支持 Markdown