hyperframes

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

HyperFrames

HyperFrames

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文件。该框架负责处理剪辑可见性、媒体播放和时间线同步。

Approach

方法思路

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. Timing — which clips drive the duration, where do transitions land, what's the pacing.
  4. Layout — build the end-state first. See "Layout Before Animation" below.
  5. Animate — then add motion using the rules below.
For small edits (fix a color, adjust timing, add one element), skip straight to the rules.
When no
visual-style.md
or animation direction is provided, follow house-style.md for motion defaults, sizing, and color palettes.
在编写HTML之前,先从宏观层面思考:
  1. 内容体验 —— 观众应该获得怎样的体验?明确叙事脉络、关键节点和情感节奏。
  2. 结构规划 —— 需要多少个合成作品,哪些是子合成作品、哪些是内联合成,哪些轨道承载什么内容(视频、音频、叠加层、字幕)。
  3. 时间控制 —— 哪些剪辑决定整体时长,过渡效果安排在何时,整体节奏如何。
  4. 布局优先 —— 先构建最终状态。详见下方“动画前先做布局”部分。
  5. 添加动画 —— 然后按照以下规则添加动效。
对于小修改(调整颜色、修改时间、添加单个元素),可以直接跳过前面的步骤,直接遵循规则操作。
当未提供
visual-style.md
或动画指导时,请遵循house-style.md中的动效默认值、尺寸规范和调色板。

Layout Before Animation

动画前先做布局

Position every element where it should be at its most visible moment — the frame where it's fully entered, correctly placed, and not yet exiting. Write this as static HTML+CSS first. No GSAP yet.
Why this matters: 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 the final layout. Overlaps are invisible until the video renders. By building the end state first, you can see and fix layout problems before adding any motion.
将每个元素放置在其最清晰可见时刻的位置——也就是元素完全进入画面、位置正确且尚未退出的那一帧。先编写静态HTML+CSS,暂不使用GSAP。
为什么这很重要: 如果你将元素定位在动画的起始状态(屏幕外、缩放为0、透明度为0),然后将它们补间到你认为的最终位置,你其实是在猜测最终布局。重叠问题只有在视频渲染后才会显现。通过先构建最终状态,你可以在添加任何动效之前发现并修复布局问题。

The process

实施流程

  1. Identify the hero frame for each scene — the moment when the most elements are simultaneously visible. This is the layout you build.
  2. Write static CSS for that frame. The
    .scene-content
    container MUST fill the full scene using
    width: 100%; height: 100%; padding: Npx;
    with
    display: flex; flex-direction: column; gap: Npx; box-sizing: border-box
    . Use padding to push content inward — NEVER
    position: absolute; top: Npx
    on a content container. Absolute-positioned content containers overflow when content is taller than the remaining space. Reserve
    position: absolute
    for decoratives only.
  3. Add entrances with
    gsap.from()
    — animate FROM offscreen/invisible TO the CSS position. The CSS position is the ground truth; the tween describes the journey to get there.
  4. Add exits with
    gsap.to()
    — animate TO offscreen/invisible FROM the CSS position.
  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位置是基准,补间动画描述的是到达该位置的过程。
  4. 使用
    gsap.to()
    添加退场动画
    —— 从CSS定义的位置动画过渡到屏幕外/不可见状态。

Example

示例

css
/* scene-content fills the scene, padding positions 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;
}
/* 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 fills the scene, padding positions 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;
}
/* Container fills any scene size (1920x1080, 1080x1920, etc).
   Padding positions content. Flex + gap handles spacing. */
错误示例——硬编码尺寸和绝对定位:
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);

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
图片/容器/合成作品必填秒数。视频/音频默认使用媒体本身的时长。
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-composition-id
唯一的合成作品ID
data-start
开始时间(根合成作品使用
"0"
data-duration
优先级高于GSAP时间线的总时长
data-width
/
data-height
像素尺寸(如1920x1080或1080x1920)
data-composition-src
外部HTML文件的路径

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">
    <!-- content -->
    <style>
      [data-composition-id="my-comp"] {
        /* scoped styles */
      }
    </style>
    <script src="https://cdn.jsdelivr.net/npm/gsap@3.14.2/dist/gsap.min.js"></script>
    <script>
      window.__timelines = window.__timelines || {};
      const tl = gsap.timeline({ paused: true });
      // tweens...
      window.__timelines["my-comp"] = tl;
    </script>
  </div>
</template>
在根合成作品中加载:
<div id="el-1" data-composition-id="my-comp" data-composition-src="compositions/my-comp.html" data-start="0" data-duration="10" data-track-index="1"></div>

Video and Audio

视频与音频

Video must be
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>
视频必须设置
muted playsinline
。音频始终使用单独的
<audio>
元素:
html
<video
  id="el-v"
  data-start="0"
  data-duration="30"
  data-track-index="0"
  src="video.mp4"
  muted
  playsinline
></video>
<audio
  id="el-a"
  data-start="0"
  data-duration="30"
  data-track-index="2"
  src="video.mp4"
  data-volume="1"
></audio>

Timeline Contract

时间线约定

  • All timelines start
    { 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或任何其他“退场”动画。过渡效果本身就是退场。在过渡开始的那一刻,退场场景的内容必须完全可见。
错误示例——过渡前使用退场动画:
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
正确示例——仅使用入场动画,过渡处理退场:
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);

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
When no
visual-style.md
or animation direction is provided, follow house-style.md for aesthetic defaults.
  • 第一个动画偏移0.1-0.3秒(不要从t=0开始)
  • 入场补间使用不同的缓动函数——每个场景至少使用3种不同的缓动函数
  • 同一场景内不要重复使用相同的入场模式
  • 避免在深色背景上使用全屏线性渐变(H.264会出现色带——使用径向渐变或纯色+局部发光效果)
  • 渲染后的视频中,标题字号≥60px,正文≥20px,数据标签≥16px
  • 数字列使用
    font-variant-numeric: tabular-nums
当未提供
visual-style.md
或动画指导时,请遵循house-style.md中的美学默认值。

Typography and Assets

排版与资源

  • Fonts: Just write the
    font-family
    you want in CSS — the compiler embeds supported fonts automatically. If a font isn't supported, the compiler warns.
  • Add
    crossorigin="anonymous"
    to external media
  • For dynamic text overflow, use
    window.__hyperframes.fitTextFontSize(text, { maxWidth, fontFamily, fontWeight })
  • All files live at the project root alongside
    index.html
    ; sub-compositions use
    ../
  • 字体: 直接在CSS中写入你需要的
    font-family
    ——编译器会自动嵌入支持的字体。如果字体不被支持,编译器会发出警告。
  • 外部媒体添加
    crossorigin="anonymous"
    属性
  • 对于动态文本溢出,使用
    window.__hyperframes.fitTextFontSize(text, { maxWidth, fontFamily, fontWeight })
  • 所有文件都与
    index.html
    一起放在项目根目录;子合成作品使用
    ../
    路径

Editing Existing Compositions

编辑现有合成作品

  • Read the full composition first — match existing fonts, colors, animation patterns
  • Only change what was requested
  • Preserve timing of unrelated clips
  • 先完整阅读现有合成作品——匹配现有的字体、颜色、动画模式
  • 只修改被要求修改的内容
  • 保留无关剪辑的时间设置

Output Checklist

输出检查清单

  • npx hyperframes lint
    and
    npx hyperframes validate
    both pass
  • Contrast warnings addressed (see Quality Checks below)
  • Animation choreography verified (see Quality Checks below)
  • npx hyperframes lint
    npx hyperframes validate
    均通过
  • 对比度警告已处理(见下方质量检查部分)
  • 动画编排已验证(见下方质量检查部分)

Quality Checks

质量检查

Contrast

对比度

hyperframes 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
    hyperframes validate
    until clean
Use
--no-contrast
to skip if iterating rapidly and you'll check later.
hyperframes 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+粗体)
  • 在浅色背景上:调暗颜色
  • 保持在调色板范围内——不要发明新颜色,调整现有颜色即可
  • 重新运行
    hyperframes validate
    直到无警告
如果需要快速迭代,之后再检查,可以使用
--no-contrast
参数跳过对比度检查。

Animation Map

动画映射

After authoring animations, run the animation map to verify choreography:
bash
node skills/hyperframes/scripts/animation-map.mjs <composition-dir> \
  --out <composition-dir>/.hyperframes/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/hyperframes/scripts/animation-map.mjs <composition-dir> \
  --out <composition-dir>/.hyperframes/anim-map
输出单个
animation-map.json
文件,包含:
  • 补间摘要:
    "#card1 animates opacity+y over 0.50s. moves 23px up. fades in. ends at (120, 200)"
  • ASCII时间线: 所有补间在合成作品时长内的甘特图
  • ** stagger检测:** 报告实际间隔(
    "3 elements stagger at 120ms"
  • 空白时段: 超过1秒无动画的时段——是有意停顿还是遗漏了入场动画?
  • 元素生命周期: 首次/末次动画时间、最终可见性
  • 场景快照: 5个关键时间点的可见元素状态
  • 标记:
    offscreen
    (屏幕外)、
    collision
    (碰撞)、
    invisible
    (不可见)、
    paced-fast
    (过快,小于0.2秒)、
    paced-slow
    (过慢,大于2秒)
阅读该JSON文件。扫描摘要,检查是否有意外情况。检查每个标记——修复或说明合理性。验证时间线是否符合预期的编排节奏。修复后重新运行。
小修改(调整颜色、修改单个时长)可以跳过此步骤。新合成作品和重大动画修改必须运行此工具。

References (loaded on demand)

按需加载的参考文档

  • 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/tts.md — Text-to-speech with Kokoro-82M. Voice selection, speed tuning, TTS+captions workflow. Read when generating narration or voiceover.
  • 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/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: easing as emotion, timing as weight, choreography as hierarchy, scene pacing, ambient motion, anti-patterns. Read when choreographing GSAP animations.
  • house-style.md — Default motion, sizing, and color palettes when no style is specified.
  • patterns.md — PiP, title cards, slide show patterns.
  • data-in-motion.md — Data, stats, and infographic patterns.
  • references/transcript-guide.md — Transcription commands, whisper models, external APIs, troubleshooting.
  • 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
      @hyperframes/shader-transitions
      (
      packages/shader-transitions/
      ) — read package source, not skill files.
GSAP patterns and effects are in the
/gsap
skill.
  • references/captions.md —— 与音频同步的字幕、副标题、歌词、卡拉OK效果。自适应语气的样式检测、逐词样式、文本溢出预防、字幕退场保证、词语分组。添加任何与音频时间同步的文本时请阅读。
  • references/tts.md —— 使用Kokoro-82M的文本转语音功能。语音选择、速度调整、TTS+字幕工作流。生成旁白或配音时请阅读。
  • references/audio-reactive.md —— 音频响应动画:将频段和振幅映射到GSAP属性。当视觉效果需要响应音乐、语音或声音时请阅读。
  • references/css-patterns.md —— CSS+GSAP标记高亮:高亮、圆圈、爆发、涂鸦、草图效果。确定性、完全可寻路。添加文本视觉强调效果时请阅读。
  • references/typography.md —— 排版:字体配对、OpenType特性、深色背景调整、字体发现脚本。必须阅读——每个合成作品都包含文本。
  • references/motion-principles.md —— 动效设计原则:缓动传递情感、时间控制体现重量、编排体现层级、场景节奏、环境动效、反模式。编排GSAP动画时请阅读。
  • house-style.md —— 未指定样式时的默认动效、尺寸和调色板。
  • patterns.md —— 画中画、标题卡、幻灯片模式。
  • data-in-motion.md —— 数据、统计信息和信息图模式。
  • references/transcript-guide.md —— 转录命令、whisper模型、外部API、故障排除。
  • references/dynamic-techniques.md —— 动态字幕动画技术(卡拉OK、裁剪路径、冲击、散射、弹性、3D效果)。
  • references/transitions.md —— 场景过渡:淡入淡出、擦除、揭示、着色器过渡。能量/情绪选择、CSS与WebGL使用指导。多场景合成作品必须阅读——无过渡的场景会产生跳切感。
    • transitions/catalog.md —— 严格规则、场景模板、各类型过渡实现代码指引。
    • 着色器过渡位于
      @hyperframes/shader-transitions
      packages/shader-transitions/
      )——请阅读包源码,而非技能文件。
GSAP模式和效果请查看
/gsap
技能。