Communitygithub.com

alecramos-sudo/hyperframes-skill

使用HyperFrames HTML创建视频合成、动画、标题卡片、叠加层、字幕、画外音、音频响应式视觉效果和场景过渡。

hyperframes-skill 是什么?

HyperFrames是一个基于HTML的视频创作框架,将HTML作为视频的“事实来源”(source of truth)。该技能专为开发者和AI代理设计,支持在HyperFrames环境中构建完整的视频制作工作流,包括合成创作、动画、字幕同步、文本转语音、音频响应式动画(如节拍同步、发光、脉冲效果)以及场景过渡(如交叉淡入淡出、擦除、圆形显示、着色器过渡)。其核心方法强调“先布局后动画”,通过静态CSS定位元素的最终可见状态,再使用GSAP时间线添加入场和退场动画,从而避免布局重叠问题。技能还强制执行视觉标识检查、确定性动画(禁用Math.random和无限循环)以及严格的时间线构建规则,确保视频输出的一致性和可靠性。它支持Claude Code、Cursor、Codex等AI代理平台,是进行程序化视频内容生产的强大工具。

兼容平台~Claude Code~Codex CLI~Cursor
npx skills add alecramos-sudo/hyperframes-skill

在你喜欢的 AI 中提问

打开一个已预加载此 Agent Skill 的新对话。

预览

来自技能 README

文档

HyperFrames

HTML是视频的“事实来源”。一个合成是一个带有data-*属性用于时序、一个GSAP时间线用于动画以及CSS用于外观的HTML文件。该框架处理剪辑可见性、媒体播放和时间线同步。

原则

在编写HTML之前,从高层思考:

  1. 什么——观众应该体验到什么?确定叙事弧线、关键时刻和情感节拍。
  2. 结构——有多少个合成?哪些是子合成,哪些是内联的?哪些轨道承载什么内容(视频、音频、叠加层、字幕)。
  3. 时序——哪些剪辑控制时长?过渡发生在哪里?节奏如何?
  4. 布局——先构建最终状态。请参阅下面的“先布局后动画”。
  5. 动画——然后使用下面的规则添加动画。

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

视觉标识门禁

按此顺序检查:

  1. 项目中是否存在DESIGN.md?→读取它。使用其确切的颜色、字体、动画规则和“勿做”约束。
  2. 是否存在visual-style.md?→读取它。应用其style_prompt_full和结构化字段。(注意:visual-style.md是项目特定的文件。visual-styles.md是包含8个命名预设的风格库——不同的文件。)
  3. 用户是否命名了一种风格(例如,“Swiss Pulse”、“dark and techy”、“luxury brand”)?→读取visual-styles.md以获取8个命名预设。生成一个最小的DESIGN.md,包含:## Style Prompt(一段)、## Colors(3-5个十六进制值及其角色)、## Typography(1-2个字体系列)、## What NOT to Do(3-5个反模式)。
  4. 以上都不满足?→在编写任何HTML之前,先问3个问题:
    • 情绪是什么?(爆炸性/电影感/流畅/技术性/混乱/温暖)
    • 使用亮色还是暗色画布?
    • 有没有特定的品牌颜色、字体或视觉参考? 然后根据答案生成一个最小的DESIGN.md。

每个合成必须将其调色板和排版追溯到DESIGN.md、visual-style.md或明确的用户指示。如果您使用#333、#3b82f6或Roboto——您跳过了这一步。

关于动画默认值、尺寸、入场模式和缓动——请遵循house-style.md。house style处理对象如何移动,而DESIGN.md处理对象看起来什么样。

先布局后动画

将每个元素定位在其最可见的时刻——即它完全进入、正确放置、并且尚未退出的帧。首先将其作为静态的HTML+CSS编写。不要使用GSAP。

为什么这很重要: 如果您将元素定位在其动画起始状态(屏幕外、缩放为0、透明度为0),然后通过tween将它们移动到您认为应该落地的位置,您是在猜测最终布局。在视频渲染之前,重叠是不可见的。通过首先构建最终状态,您可以在添加任何动画之前看到并修复布局问题。

过程

  1. 为每个场景确定主帧——即最多元素同时可见的时刻。这是您要构建的布局。
  2. 为该帧编写静态CSS。.scene-content容器必须使用width: 100%; height: 100%; padding: Npx;并配合display: flex; flex-direction: column; gap: Npx; box-sizing: border-box来填充整个场景。使用内边距将内容向内推——绝不要在内容容器上使用position: absolute; top: Npx。绝对定位的内容容器在内容高于剩余空间时会溢出。只有在装饰性元素上使用position: absolute。
  3. 使用gsap.from()添加入场——从屏幕外/不可见动画到CSS位置。CSS是地面真相;tween描述了到达那里的旅程。
  4. 使用gsap.to()添加退场——从CSS位置动画到屏幕外/不可见。

示例

/* scene-content填充场景,内边距定位内容 */
.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处理间距。 */

错误——硬编码尺寸和绝对定位:

.scene-content {
  position: absolute;
  top: 200px;
  left: 160px;
  width: 1920px;
  height: 1080px;
  display: flex;
}
// 第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);

当元素随时间共享空间时

如果元素A在元素B进入同一区域之前退出,两者都应该为其各自的主帧拥有正确的CSS位置。时间线顺序保证它们永远不会在视觉上共存——但是如果您跳过了布局步骤,您将无法捕获由于时序错误导致它们意外重叠的情况。

什么算有意重叠

分层效果(文本后的发光、阴影元素、背景图案)和z轴堆叠设计(卡片堆叠、深度层)是有意的。布局步骤旨在捕获无意的重叠——两个标题互相叠在一起、一个统计数字覆盖了标签、内容溢出帧外。

数据属性

所有剪辑

属性必需值
id是唯一标识符
data-start是秒数或剪辑ID引用("el-1"、"intro + 2")
data-durationimg/div/composition需要秒数。视频/音频默认为媒体时长。
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-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"] {
        /* 作用域样式 */
      }
    </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>

视频和音频

视频必须是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>

时间线契约

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

规则(不可协商)

确定性: 没有Math.random()、Date.now()或基于时间的逻辑。如果需要伪随机值(例如mulberry32),请使用种子PRNG。

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. 在任何时间线或tween上使用repeat: -1——始终是有限重复
  9. 异步构建时间线(在async、setTimeout、Promise内部)
  10. 在后期场景的剪辑元素上使用gsap.set()——它们在页面加载时不存在于DOM中。应使用tl.set(selector, vars, timePosition)在其data-start时间或之后的时间点上的时间线内部代替。
  11. 在内容文本中使用<br>——强制换行不考虑实际渲染的字体宽度。自然换行的文本加上<br>会产生一个额外的不想要的换行,导致重叠。请让文本通过max-width自然换行。例外情况:短显式标题,其中每个单词刻意在其自己的行上(例如,130px的“THE\nIMMORTAL\nGAME”)。

场景过渡(不可协商)

每个多场景合成必须遵循所有以下规则。违反任何一条都会导致合成损坏。

  1. 始终在场景之间使用过渡。 没有跳切。没有例外。
  2. 始终在每个场景上使用入场动画。 每个元素通过gsap.from()动画进入。没有元素可以完全成形地出现。如果一个场景有5个元素,则需要5个入场tween。
  3. 永远不要使用退场动画,除非在最后一个场景中。这意味着:在过渡触发之前,没有gsap.to()将透明度动画化为0、将y移出屏幕、将缩放动画化为0或任何其他“退出”动画。过渡本身就是退场。离开场景的内容在过渡开始时必须完全可见。
  4. 仅限最后一个场景: 最后一个场景可以将元素淡出(例如,淡出到黑色)。这是唯一允许使用gsap.to(..., { opacity: 0 })的场景。

错误——在过渡之前使用退场动画:

// 禁止——这会清空场景,使得过渡无法使用它
tl.to("#s1-title", { opacity: 0, y: -40, duration: 0.4 }, 6.5);
tl.to("#s1-subtitle", { opacity: 0, duration: 0.3 }, 6.7);
// 过渡在空帧上触发

正确——仅入场,过渡处理退场:

// 场景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);
// 没有退场tween——7.2秒处的过渡处理场景切换
// 场景2入场动画
tl.from("#s2-heading", { x: -40, opacity: 0, duration: 0.6, ease: "expo.out" }, 8.0);

动画护栏

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

当没有提供visual-style.md或动画方向时,请遵循house-style.md以获得美学默认值。

排版和资源

  • 字体: 只需在CSS中编写您想要的font-family——编译器会自动嵌入支持的字体。如果某个字体不受支持,编译器会发出警告。
  • 在外部媒体上添加crossorigin="anonymous"

相关技能