Loading...
Loading...
Compare original and translation side by side
npx hyperframes render index.htmlcopy_starter_componentkind: "animations.jsx"<script type="text/babel">window.__timelines<hyperframes-player>preview.htmlindex.htmlpreview.htmlREADME.mdDESIGN.mdnpx hyperframes render index.htmlnpx hyperframes render index.htmlcopy_starter_componentkind: "animations.jsx"<script type="text/babel">window.__timelines<hyperframes-player>preview.htmlindex.htmlpreview.htmlREADME.mdDESIGN.mdnpx hyperframes render index.html.fig.docx.pptxweb_searchweb_fetch<brand>.com/blog.fig.docx.pptxweb_searchweb_fetch<brand>.com/blogTo make this look like yours — drop any of these (or describe in words):
- A screenshot or two of your product, site, or an ad you like.
- A brand PDF / style guide.
- A reference video for pacing / color / energy.
- A vibe in words — "clinical and cold", "loud and fast", "a particular director / movie".
- A must-have — a specific shader, transition, text effect, or element you already want.
Or say "just build" and I'll commit to <one concrete aesthetic you've chosen for this brief — named concretely, not "warm editorial" or "generic dark mode">.
为了让内容更贴合你的需求,请提供以下任意一项(或用文字描述):
- 产品、网站或你喜欢的广告的1-2张截图
- 品牌PDF/风格指南
- 参考视频(用于参考节奏/色彩/活力)
- 风格描述——比如「冷峻专业」、「动感强烈」、「特定导演/电影风格」
- 必备元素——特定着色器、转场效果、文字特效或你想要的元素
或者回复「直接制作」,我将为本次需求确定**<一个具体的美学风格名称,而非“温暖社论风”或“通用深色模式”>**。
DESIGN.mdDESIGN.mdDESIGN.mdindex.htmlDESIGN.md:rootindex.htmlindex.htmlDESIGN.mdDESIGN.mdindex.html:rootskills/hyperframes/references/typography.md#000#fffskills/hyperframes/house-style.mdskills/hyperframes/references/typography.md#000#fffskills/hyperframes/house-style.md| Displayed text (visible during the scene) | Minimum scene duration |
|---|---|
| No text (hero image, icon, decorative) | 1.5–2s |
| 1–3 words (kicker, label, number, short headline) | 2–3s |
| 4–10 words (short headline + tiny subhead) | 3–4s |
| 11–20 words (a full sentence or two short lines) | 4–6s |
| 21–35 words (multi-line paragraph, bullet list) | 6–8s |
| 35+ words (dense explainer text) | Split into two scenes. A single scene should not ask the viewer to read more than ~35 words. |
tl.from("#s5-sub", …)| Video length | Target scene count | Avg scene | Notes |
|---|---|---|---|
| 10–15s social ad | 5–8 | 2–3s | Relentless cuts, every scene is a punch |
| 20–30s teaser | 8–12 | 2–4s | Open / build / payoff / close, varied |
| 30–60s explainer | 12–20 | 3–5s | Each beat its own scene — don't combine two ideas |
| 60–120s narrative | 24–40 | 3–5s | Dense pacing. Think YouTube explainer, not slideshow |
| 120–240s long-form | 40–70 | 4–5s | Split into sub-compositions, each act ~8–14 scenes |
scene.data-durationtl.fromdata-durationshort-short-LONG-short-short-LONG-shortflat-flat-flat-flat| 场景内显示文本 | 最小场景时长 |
|---|---|
| 无文本(核心图片、图标、装饰元素) | 1.5–2秒 |
| 1–3字(副标题、标签、数字、短标题) | 2–3秒 |
| 4–10字(短标题+小标题) | 3–4秒 |
| 11–20字(完整句子或两行短文本) | 4–6秒 |
| 21–35字(多行段落、项目符号列表) | 6–8秒 |
| 35字以上(密集讲解文本) | 拆分为两个场景。单个场景不应要求观众阅读超过约35字。 |
tl.from("#s5-sub", …)| 视频时长 | 目标场景数 | 平均场景时长 | 说明 |
|---|---|---|---|
| 10–15秒社交广告 | 5–8 | 2–3秒 | 节奏紧凑,每个场景都有冲击力 |
| 20–30秒预告 | 8–12 | 2–4秒 | 开场/铺垫/高潮/收尾,节奏多变 |
| 30–60秒讲解视频 | 12–20 | 3–5秒 | 每个内容点单独成场景——不要合并两个想法 |
| 60–120秒叙事视频 | 24–40 | 3–5秒 | 节奏密集。参考YouTube讲解视频,而非幻灯片 |
| 120–240秒长视频 | 40–70 | 4–5秒 | 拆分为子合成内容,每个章节约8–14个场景 |
scene.data-durationtl.fromdata-duration短-短-长-短-短-长-短平-平-平-平| Phase | When | What |
|---|---|---|
| Build | 0 – 30% | Elements enter, staggered. Don't dump everything at once. Offset first tween 0.1–0.3s. |
| Breathe | 30% – 70% | Content visible, alive with at least ONE ambient motion. No element stands still here. |
| Resolve | 70% – 100% | A beat resolves — accent pulse, number lands, secondary element arrives, decisive end. |
skills/hyperframes/references/motion-principles.md| 阶段 | 时间范围 | 内容 |
|---|---|---|
| 构建 | 0 – 30% | 元素依次入场,错开时间。不要一次性全部入场。第一个动画偏移0.1–0.3秒。 |
| 维持 | 30% – 70% | 内容可见,至少有一个元素持续动效。此阶段无元素静止。 |
| 收尾 | 70% – 100% | 完成一个节拍——强调脉冲、数字到位、次要元素入场、明确收尾。 |
skills/hyperframes/references/motion-principles.md| Energy | Verbs | Example |
|---|---|---|
| High impact | SLAMS, CRASHES, PUNCHES, STAMPS, SHATTERS | "$1.9T" SLAMS in from left at -5° |
| Medium energy | CASCADE, SLIDES, DROPS, FILLS, DRAWS | Three cards CASCADE in staggered 0.3s |
| Low energy | types on, FLOATS, morphs, COUNTS UP, fades in | Counter COUNTS UP from 0 to 135K |
| 能量等级 | 动词 | 示例 |
|---|---|---|
| 高冲击力 | 猛击(SLAMS)、撞击(CRASHES)、冲击(PUNCHES)、踩踏(STAMPS)、碎裂(SHATTERS) | "$1.9T"从左侧以-5°角度猛击入场 |
| 中等能量 | 层叠(CASCADE)、滑动(SLIDES)、掉落(DROPS)、填充(FILLS)、绘制(DRAWS) | 三张卡片以0.3秒间隔层叠入场 |
| 低能量 | 打字式出现、漂浮(FLOATS)、变形(morphs)、计数上升(COUNTS UP)、淡入(fades in) | 计数器从0计数到135K |
| Element type | Mid-scene activity |
|---|---|
| Image / screenshot | Slow zoom ( |
| Stat / number | Counter animates from 0 to target |
| Chart / bars | Bars fill in sequence; line draws via |
| Logo / lockup | Subtle shimmer sweep, gentle scale pulse, or audio-reactive (if music present) |
| Background decoratives | Radial glow breathing, gradient shift, grain drift, hairline rule pulse |
| Any persistent element | Subtle float ( |
| 元素类型 | 场景内动态 |
|---|---|
| 图片/截图 | 缓慢缩放(场景时长内 |
| 统计数据/数字 | 计数器从0动画到目标值 |
| 图表/柱状图 | 柱状图依次填充;线条通过 |
| Logo/组合标志 | 微妙的闪光扫过、柔和的缩放脉冲或音频响应(若有音乐) |
| 背景装饰元素 | 径向呼吸光晕、渐变偏移、颗粒漂移、细线脉冲 |
| 任何持续显示元素 | 微妙漂浮( |
深蓝色背景。白色“$1.9T”,280px。Logo位于左上角。波浪图片位于右下角。镜头已在广阔的深色画布上空移动。渐变波浪像极光一样扫过画面——动态、变幻。“$1.9T”猛击出现,力量之大让波浪产生涟漪。这不是幻灯片——是一个瞬间。gsap.from().scene-content.scene-content.scene-contentgsap.from().scene-content.scene-content.scene-content<div class="scene-content">HyperShader.captureIncomingScene()html2canvas<!-- SCENE 1 — visible from t=0, no inline style -->
<div class="scene clip" id="s1" data-start="0" data-duration="5" data-track-index="0">
<!-- OUTSIDE .scene-content: backgrounds, decoratives. Captured into shader textures. -->
<div class="bg-grain"></div>
<div class="bg-vignette"></div>
<!-- INSIDE .scene-content: every animated element. REQUIRED on every scene. -->
<div class="scene-content">
<h1 id="s1-title">…</h1>
<p id="s1-sub">…</p>
</div>
</div>
<!-- SCENE 2+ — starts hidden; same wrapper structure.
Inline style is opacity:0 ONLY (no visibility:hidden). See "Scene initial visibility" below. -->
<div
class="scene clip"
id="s2"
data-start="5"
data-duration="5"
data-track-index="0"
style="opacity:0;"
>
<div class="bg-grain"></div>
<div class="scene-content">
<!-- ← MANDATORY, not just a scene-1 pattern -->
<h1 id="s2-title">…</h1>
<p id="s2-sub">…</p>
</div>
</div><div class="scene-content">HyperShader.captureIncomingScene()html2canvas<!-- 场景1 — 从t=0可见,无内联样式 -->
<div class="scene clip" id="s1" data-start="0" data-duration="5" data-track-index="0">
<!-- .scene-content外部:背景、装饰元素。捕获到着色器纹理中。 -->
<div class="bg-grain"></div>
<div class="bg-vignette"></div>
<!-- .scene-content内部:所有动画元素。每个场景都必须有。 -->
<div class="scene-content">
<h1 id="s1-title">…</h1>
<p id="s1-sub">…</p>
</div>
</div>
<!-- 场景2及以后 — 初始隐藏;结构相同。
内联样式仅设置opacity:0(不要visibility:hidden)。见下方“场景初始可见性”。 -->
<div
class="scene clip"
id="s2"
data-start="5"
data-duration="5"
data-track-index="0"
style="opacity:0;"
>
<div class="bg-grain"></div>
<div class="scene-content">
<!-- ← 必须存在,不仅是场景1的模式 -->
<h1 id="s2-title">…</h1>
<p id="s2-sub">…</p>
</div>
</div>| Attribute | Required | Values |
|---|---|---|
| yes | unique identifier |
| yes | literal string (scenes use |
| yes | seconds, or clip-id reference ( |
| required for img/div/compositions | seconds. video/audio default to media duration |
| yes | integer. same-track clips cannot overlap in time |
| no | trim offset into source (seconds) for video/audio |
| no | 0–1 (default 1) for audio |
data-track-indexz-indexindex.html<template>| Attribute | Required | Values |
|---|---|---|
| yes | unique ID. root uses |
| yes | root: |
| yes | seconds. takes precedence over GSAP timeline length |
| yes | pixel width (1920 for 16:9, 1080 for 9:16, 1080 for 1:1) |
| yes | pixel height (1080 for 16:9, 1920 for 9:16, 1080 for 1:1) |
| no | path to external HTML sub-composition ( |
| 属性 | 是否必填 | 值 |
|---|---|---|
| 是 | 唯一标识符 |
| 是 | 字面字符串(场景使用 |
| 是 | 秒数,或片段ID引用( |
| 图片/ div/合成内容必填 | 秒数。视频/音频默认使用媒体时长 |
| 是 | 整数。同轨道片段时间不可重叠 |
| 否 | 视频/音频源的裁剪偏移(秒) |
| 否 | 0–1(默认1),用于音频 |
data-track-indexz-indexindex.html<template>| 属性 | 是否必填 | 值 |
|---|---|---|
| 是 | 唯一ID。根元素惯例使用 |
| 是 | 根元素: |
| 是 | 秒数。优先级高于GSAP时间线长度 |
| 是 | 像素宽度(16:9为1920,9:16为1080,1:1为1080) |
| 是 | 像素高度(16:9为1080,9:16为1920,1:1为1080) |
| 否 | 外部HTML子合成内容路径( |
paused: truewindow.__timelines["<composition-id>"]data-composition-ididdata-composition-id<div id="main" data-composition-id="main" …>#main__timelinesid="root"data-composition-id="main"__timelines["main"].play().add()data-durationasyncawaitsetTimeoutpaused: truewindow.__timelines["<composition-id>"]data-composition-ididdata-composition-id<div id="main" data-composition-id="main" …>#main__timelinesid="root"data-composition-id="main"__timelines["main"].play().add()data-durationasyncawaitsetTimeoutmuted playsinline<video><audio>data-track-indexvideo.play()audio.play()<video
id="v-main"
class="clip"
data-start="0"
data-duration="30"
data-track-index="0"
src="footage.mp4"
muted
playsinline
></video>
<audio
id="v-main-audio"
class="clip"
data-start="0"
data-duration="30"
data-track-index="2"
src="footage.mp4"
data-volume="1"
></audio>data-media-startdata-durationmuted playsinline<video><audio>data-track-indexvideo.play()audio.play()<video
id="v-main"
class="clip"
data-start="0"
data-duration="30"
data-track-index="0"
src="footage.mp4"
muted
playsinline
></video>
<audio
id="v-main-audio"
class="clip"
data-start="0"
data-duration="30"
data-track-index="2"
src="footage.mp4"
data-volume="1"
></audio>data-media-startdata-durationstyle.visibility = "hidden"[data-start]style.opacitystyle="opacity:0;"visibility:hiddendata-startcaptureIncomingSceneopacity:1html2canvasstyle.opacity = "1"visibility:hiddencaptureIncomingScenehtml2canvasvisibility:hiddenstyle="visibility:hidden;"opacity:0opacity:0[data-start]style.visibility = "hidden"style.opacitystyle="opacity:0;"visibility:hiddendata-startcaptureIncomingScenehtml2canvasopacity:1style.opacity"1"visibility:hiddencaptureIncomingScenehtml2canvasvisibility:hiddenstyle="visibility:hidden;"opacity:0opacity:0@hyperframes/shader-transitions[HyperShader] Unknown shaderdomain-warpridged-burnwhip-pansdf-irisripple-wavesgravitational-lenscinematic-zoomchromatic-splitswirl-vortexthermal-distortionflash-through-whitecross-warp-morphlight-leakglitchpackages/shader-transitions/src/shaders/registry.tsskills/hyperframes/references/transitions.mdwindow.HyperShaderHyperframesShaderTransitions<script src="https://cdn.jsdelivr.net/npm/@hyperframes/shader-transitions/dist/index.global.js"></script>
<script>
const tl = gsap.timeline({ paused: true });
window.HyperShader.init({
bgColor: "#0a0a0d",
scenes: ["s1", "s2", "s3"],
timeline: tl,
transitions: [
{ time: 5.75, shader: "cinematic-zoom", duration: 0.5 },
{ time: 11.75, shader: "whip-pan", duration: 0.5 },
],
});
window.__timelines["main"] = tl;
</script>scenes.length === transitions.length + 1style="visibility:hidden;"style="opacity:0;"{ shader: "flash-through-white", duration: 0.01 }[start, start+duration)Bvisibility:hiddentransition.time === Bhtml2canvastransition.time < Btransition.time + duration > Btransition.time = B - duration/2time: 5.75opacitytl.set(#scene-N, {autoAlpha: …}, …)@hyperframes/shader-transitions[HyperShader] Unknown shaderdomain-warpridged-burnwhip-pansdf-irisripple-wavesgravitational-lenscinematic-zoomchromatic-splitswirl-vortexthermal-distortionflash-through-whitecross-warp-morphlight-leakglitchpackages/shader-transitions/src/shaders/registry.tsskills/hyperframes/references/transitions.mdwindow.HyperShaderHyperframesShaderTransitions<script src="https://cdn.jsdelivr.net/npm/@hyperframes/shader-transitions/dist/index.global.js"></script>
<script>
const tl = gsap.timeline({ paused: true });
window.HyperShader.init({
bgColor: "#0a0a0d",
scenes: ["s1", "s2", "s3"],
timeline: tl,
transitions: [
{ time: 5.75, shader: "cinematic-zoom", duration: 0.5 },
{ time: 11.75, shader: "whip-pan", duration: 0.5 },
],
});
window.__timelines["main"] = tl;
</script>scenes.length === transitions.length + 1style="visibility:hidden;"style="opacity:0;"{ shader: "flash-through-white", duration: 0.01 }[start, start+duration)Bvisibility:hiddentransition.time === Bhtml2canvastransition.time < Btransition.time + duration > Btransition.time = B - duration/2time: 5.75opacitytl.set(#scene-N, {autoAlpha: …}, …)index.htmlindex.html#gl-canvaspackages/shader-transitions/src/hyper-shader.tsdocument.querySelectorAll(".scene")index.htmlindex.html#gl-canvaspackages/shader-transitions/src/hyper-shader.tsdocument.querySelectorAll(".scene")compositions/<template>index.html<template><body><!-- compositions/act-1-intro.html -->
<template id="act-1-intro-template">
<div class="hf-sub" data-composition-id="act-1-intro" data-width="1920" data-height="1080">
<style>
.hf-sub {
position: relative;
width: 1920px;
height: 1080px;
}
/* scene styles scoped to this sub-comp */
</style>
<div class="scene clip" id="a1-s1" data-start="0" data-duration="5" data-track-index="0">
<div class="scene-content">…</div>
</div>
<div
class="scene clip"
id="a1-s2"
data-start="5"
data-duration="5"
data-track-index="0"
style="visibility:hidden;"
>
<div class="scene-content">…</div>
</div>
<script>
// Sub-comp does NOT re-load GSAP — parent loads it once.
window.__timelines = window.__timelines || {};
const tl = gsap.timeline({ paused: true });
// Tween positions are LOCAL (0 = sub-comp start). Parent auto-offsets at its data-start.
tl.from("#a1-s1 .title", { y: 40, autoAlpha: 0, duration: 0.8 }, 0.3);
tl.from("#a1-s2 .body", { y: 20, autoAlpha: 0, duration: 0.6 }, 5.3);
// DO NOT call window.HyperShader.init() here — HyperShader is root-only.
window.__timelines["act-1-intro"] = tl;
</script>
</div>
</template>compositions/<template>index.html<template><body><!-- compositions/act-1-intro.html -->
<template id="act-1-intro-template">
<div class="hf-sub" data-composition-id="act-1-intro" data-width="1920" data-height="1080">
<style>
.hf-sub {
position: relative;
width: 1920px;
height: 1080px;
}
/* 子合成内容的场景样式 */
</style>
<div class="scene clip" id="a1-s1" data-start="0" data-duration="5" data-track-index="0">
<div class="scene-content">…</div>
</div>
<div
class="scene clip"
id="a1-s2"
data-start="5"
data-duration="5"
data-track-index="0"
style="visibility:hidden;"
>
<div class="scene-content">…</div>
</div>
<script>
// 子合成内容无需重新加载GSAP——父元素已加载一次。
window.__timelines = window.__timelines || {};
const tl = gsap.timeline({ paused: true });
// 动画位置是本地的(0 = 子合成内容开始)。父元素会根据其data-start自动偏移。
tl.from("#a1-s1 .title", { y: 40, autoAlpha: 0, duration: 0.8 }, 0.3);
tl.from("#a1-s2 .body", { y: 20, autoAlpha: 0, duration: 0.6 }, 5.3);
// 请勿在此调用window.HyperShader.init()——HyperShader仅在根元素初始化。
window.__timelines["act-1-intro"] = tl;
</script>
</div>
</template>index.htmlindex.htmldata-composition-src<div
id="act-1"
class="scene clip"
data-composition-id="act-1-intro"
data-composition-src="compositions/act-1-intro.html"
data-start="0"
data-duration="30"
data-track-index="0"
></div><template id="<id>-template">data-composition-iddata-composition-idwindow.__timelines[...]data-startstyle="visibility:hidden;"data-composition-src<div
id="act-1"
class="scene clip"
data-composition-id="act-1-intro"
data-composition-src="compositions/act-1-intro.html"
data-start="0"
data-duration="30"
data-track-index="0"
></div><template id="<id>-template">data-composition-iddata-composition-idwindow.__timelines[...]data-startstyle="visibility:hidden;"| ❌ Never | ✅ Use instead |
|---|---|
| |
| seeded PRNG (e.g. mulberry32) with a known seed |
| timeline tweens + |
| |
Timelines built in | Construct synchronously at page load |
| Framework owns media playback |
Animating | |
| ❌ 禁止操作 | ✅ 替代方案 |
|---|---|
| |
未播种的 | 播种的PRNG(如mulberry32),使用已知种子 |
时间线中的 | 时间线动画 + |
任何动画或时间线设置 | |
| 页面加载时同步构建 |
代码中调用 | 框架控制媒体播放 |
动画 | |
skills/hyperframes/SKILL.md#Rules-Non-NegotiableopacityxyscalerotationcolortransformsvisibilitydisplayautoAlpha{ paused: true }window.__timelines["<composition-id>"].play()power2.outskills/hyperframes/SKILL.md#Rules-Non-NegotiableopacityxyscalerotationcolortransformsvisibilitydisplayautoAlpha{ paused: true }window.__timelines["<composition-id>"].play()power2.outcaptureScene(fromScene)html2canvasopacity: 0autoAlpha: 0html2canvas<TransitionSeries>references/transitions.md// ✖ WRONG — card fades to 0 before transition at t=17.80 fires.
// Shader captures an empty phone. User sees the card disappear
// 0.85s before the transition, then an empty-phone-to-next-scene morph.
tl.to("#s6-card", { x: 180, rotation: 14, duration: 0.55, ease: "power3.in" }, 16.5);
tl.to("#s6-card", { autoAlpha: 0, duration: 0.25 }, 16.95); // BANNED
// HyperShader transition at 17.80 captures #s6 with card invisible// ✓ RIGHT — mid-scene swipe gesture, then a different beat holds the final
// frame. Card moves but stays visible. Transition handles the actual exit.
tl.to("#s6-card", { x: 180, rotation: 14, duration: 0.55, ease: "power3.in" }, 15.3);
tl.from("#s6-check", { scale: 0, duration: 0.3, ease: "back.out(2)" }, 15.6);
tl.from("#s6-match-stamp", { scale: 1.5, autoAlpha: 0, duration: 0.4 }, 16.1);
// scene 6 ends at 18.0 with the matched-stamp + pulsing check button visible.
// HyperShader transition at 17.80 captures a FULL scene → clean morph.captureScene(fromScene)html2canvasopacity: 0autoAlpha: 0html2canvas<TransitionSeries>references/transitions.md// ✖ 错误——卡片在t=17.80转场前淡入0。
// 着色器捕获空白的手机。用户看到卡片在转场前0.85秒消失,然后是空白手机到下一场景的变形。
tl.to("#s6-card", { x: 180, rotation: 14, duration: 0.55, ease: "power3.in" }, 16.5);
tl.to("#s6-card", { autoAlpha: 0, duration: 0.25 }, 16.95); // 禁止
// HyperShader在17.80转场时捕获#s6,此时卡片不可见// ✓ 正确——场景内滑动手势,然后不同节拍保持最终帧。卡片移动但保持可见。转场处理实际退出。
tl.to("#s6-card", { x: 180, rotation: 14, duration: 0.55, ease: "power3.in" }, 15.3);
tl.from("#s6-check", { scale: 0, duration: 0.3, ease: "back.out(2)" }, 15.6);
tl.from("#s6-match-stamp", { scale: 1.5, autoAlpha: 0, duration: 0.4 }, 16.1);
// 场景6在18.0结束,此时匹配印章+脉冲检查按钮可见。
// HyperShader在17.80转场时捕获完整场景→干净变形。staggerstagger// ✖ WRONG — `from: "random"` picks a random origin at timeline-construction
// time using GSAP's internal unseeded random. Two renders of the same
// composition produce different stagger orderings. Fails PSNR regression
// tests and violates the deterministic-render rule.
tl.from(
"#s12 .card",
{
scale: 0.7,
autoAlpha: 0,
y: 40,
duration: 0.45,
stagger: { each: 0.04, from: "random" }, // BANNED
},
34.55,
);// ✓ RIGHT — deterministic stagger origins. All of these are safe.
tl.from(
"#s12 .card",
{ scale: 0.7, autoAlpha: 0, y: 40, duration: 0.45, stagger: { each: 0.04, from: "start" } },
34.55,
); // natural order
tl.from(
"#s12 .card",
{ scale: 0.7, autoAlpha: 0, y: 40, duration: 0.45, stagger: { each: 0.04, from: "center" } },
34.55,
); // ripple outward
tl.from(
"#s12 .card",
{
scale: 0.7,
autoAlpha: 0,
y: 40,
duration: 0.45,
stagger: { each: 0.04, grid: [3, 5], from: [0, 0] },
},
34.55,
); // grid-aware// ✖ 错误——`from: "random"`在时间线构建时使用GSAP内部未播种的随机数选择随机起点。
// 同一合成内容的两次渲染产生不同的 stagger顺序。无法通过PSNR回归测试,违反确定性渲染规则。
tl.from(
"#s12 .card",
{
scale: 0.7,
autoAlpha: 0,
y: 40,
duration: 0.45,
stagger: { each: 0.04, from: "random" }, // 禁止
},
34.55,
);// ✓ 正确——确定性 stagger起点。以下都是安全的。
tl.from(
"#s12 .card",
{ scale: 0.7, autoAlpha: 0, y: 40, duration: 0.45, stagger: { each: 0.04, from: "start" } },
34.55,
); // 自然顺序
tl.from(
"#s12 .card",
{ scale: 0.7, autoAlpha: 0, y: 40, duration: 0.45, stagger: { each: 0.04, from: "center" } },
34.55,
); // 向外扩散
tl.from(
"#s12 .card",
{
scale: 0.7,
autoAlpha: 0,
y: 40,
duration: 0.45,
stagger: { each: 0.04, grid: [3, 5], from: [0, 0] },
},
34.55,
); // 网格感知position: absolute; top; left.scene-contentposition: absolute; top; left.scene-content/* ✖ WRONG — absolute-positioned content container with hardcoded pixels.
Renders at 1920×1080 but overflows at any other aspect ratio. Also
pushes you toward absolute-positioning every child, which is fragile. */
.scene-content {
position: absolute;
top: 200px;
left: 160px;
width: 1920px;
height: 1080px;
}/* ✓ RIGHT — flex-filled container with padding for the positioning.
Works at any aspect ratio. Children flow naturally. */
.scene-content {
width: 100%;
height: 100%;
padding: 120px 160px;
display: flex;
flex-direction: column;
justify-content: center;
gap: 24px;
box-sizing: border-box;
}skills/hyperframes/SKILL.md#Layout-Before-Animationgsap.from()/* ✖ 错误——绝对定位的内容容器,使用硬编码像素。
在1920×1080渲染,但在其他宽高比下溢出。也会导致你倾向于绝对定位每个子元素,这很脆弱。 */
.scene-content {
position: absolute;
top: 200px;
left: 160px;
width: 1920px;
height: 1080px;
}/* ✓ 正确——弹性填充容器,用padding定位。
适用于任何宽高比。子元素自然排列。 */
.scene-content {
width: 100%;
height: 100%;
padding: 120px 160px;
display: flex;
flex-direction: column;
justify-content: center;
gap: 24px;
box-sizing: border-box;
}skills/hyperframes/SKILL.md#Layout-Before-Animationgsap.from()background-imagebackground-image<filter>background-image: url("data:image/svg+xml...")html2canvasSecurityError: The operation is insecuregl.texImage2D()/* ✖ WRONG — SVG filter as background-image.
Taints html2canvas's output canvas in Safari → breaks every shader
transition in Safari + cross-origin iframes. Also measurably slower in
WebKit than CSS gradients even when it does work. */
.grain {
position: absolute;
inset: 0;
pointer-events: none;
opacity: 0.08;
background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='200' height='200'><filter id='n'><feTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='2' stitchTiles='stitch'/></filter><rect width='100%25' height='100%25' filter='url(%23n)'/></svg>");
mix-blend-mode: overlay;
}/* ✓ RIGHT — layered CSS radial-gradient dots. Same grain effect visually,
pure CSS rendering, zero canvas taint, fast everywhere. */
.grain {
position: absolute;
inset: 0;
pointer-events: none;
opacity: 0.18;
background-image:
radial-gradient(rgba(255, 255, 255, 0.08) 1px, transparent 1.2px),
radial-gradient(rgba(0, 0, 0, 0.18) 1px, transparent 1.2px);
background-size:
3px 3px,
5px 5px;
background-position:
0 0,
1px 2px;
mix-blend-mode: overlay;
}feTurbulence + feDisplacementMapbackdrop-filterdata-no-capturecaptureScene()<!-- SVG decorative element skipped from shader capture only — still renders live -->
<div class="grain svg-filter-grain" data-no-capture></div><filter>background-image: url("data:image/svg+xml...")html2canvasgl.texImage2D()SecurityError: The operation is insecure/* ✖ 错误——SVG滤镜作为background-image。
在Safari中污染html2canvas的输出画布→破坏Safari + 跨源iframe中的每个着色器转场。即使正常工作,在WebKit中也比CSS渐变慢得多。 */
.grain {
position: absolute;
inset: 0;
pointer-events: none;
opacity: 0.08;
background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='200' height='200'><filter id='n'><feTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='2' stitchTiles='stitch'/></filter><rect width='100%25' height='100%25' filter='url(%23n)'/></svg>");
mix-blend-mode: overlay;
}/* ✓ 正确——分层CSS径向渐变点。视觉效果相同的颗粒,
纯CSS渲染,零画布污染,所有环境都快速。 */
.grain {
position: absolute;
inset: 0;
pointer-events: none;
opacity: 0.18;
background-image:
radial-gradient(rgba(255, 255, 255, 0.08) 1px, transparent 1.2px),
radial-gradient(rgba(0, 0, 0, 0.18) 1px, transparent 1.2px);
background-size:
3px 3px,
5px 5px;
background-position:
0 0,
1px 2px;
mix-blend-mode: overlay;
}feTurbulence + feDisplacementMapbackdrop-filterdata-no-capturecaptureScene()<!-- SVG装饰元素仅跳过着色器捕获——仍实时渲染 -->
<div class="grain svg-filter-grain" data-no-capture></div>class="scene clip"data-startdata-durationdata-track-indexstyle="opacity:0;"visibility:hiddencaptureIncomingScenestyle="visibility:hidden;"opacity:0data-durationdata-startdata-start<div class="scene-content">.scene-contenttransition.time < boundary < transition.time + durationtl.settl.totl.fromtl.fromToDate.now()Math.random()repeat: -1setIntervalstagger: { from: "random" }from: "start""center""end"tl.to(..., { opacity: 0 })tl.to(..., { autoAlpha: 0 })tl.to(..., { y: <offscreen> })background-imagedata:image/svg+xmlradial-gradientdata-no-capturefont-variant-numeric: tabular-numswindow.__timelines["<id>"] = tldata-composition-idclass="scene clip"data-startdata-durationdata-track-indexstyle="opacity:0;"visibility:hiddencaptureIncomingScenestyle="visibility:hidden;"opacity:0data-durationdata-startdata-start<div class="scene-content">.scene-contenttransition.time < boundary < transition.time + durationtl.settl.totl.fromtl.fromToDate.now()Math.random()repeat: -1setIntervalstagger: { from: "random" }from: "start""center""end"tl.to(..., { opacity: 0 })tl.to(..., { autoAlpha: 0 })tl.to(..., { y: <屏幕外> })background-imagedata:image/svg+xmlradial-gradientdata-no-capturefont-variant-numeric: tabular-numswindow.__timelines["<id>"] = tldata-composition-idindex.htmlpreview.htmlREADME.mdDESIGN.mdpreview.htmlindex.htmlpreview.htmlREADME.mdDESIGN.mdpreview.htmlpreview.htmlpreview.html?t=<token>"preview token required"<!doctype html>
<html>
<head>
<meta charset="utf-8" />
<title>HyperFrames Preview</title>
<style>
html,
body {
margin: 0;
padding: 0;
background: #111;
height: 100%;
overflow: hidden;
}
</style>
<script type="module" src="https://cdn.jsdelivr.net/npm/@hyperframes/player"></script>
</head>
<body>
<hyperframes-player
id="p"
controls
autoplay
muted
style="display:block;width:100vw;height:100vh"
></hyperframes-player>
<script>
document.getElementById("p").setAttribute("src", "./index.html" + location.search);
</script>
</body>
</html><hyperframes-player>?t=<token>"preview token required"<!doctype html>
<html>
<head>
<meta charset="utf-8" />
<title>HyperFrames Preview</title>
<style>
html,
body {
margin: 0;
padding: 0;
background: #111;
height: 100%;
overflow: hidden;
}
</style>
<script type="module" src="https://cdn.jsdelivr.net/npm/@hyperframes/player"></script>
</head>
<body>
<hyperframes-player
id="p"
controls
autoplay
muted
style="display:block;width:100vw;height:100vh"
></hyperframes-player>
<script>
document.getElementById("p").setAttribute("src", "./index.html" + location.search);
</script>
</body>
</html><hyperframes-player>README.mdREADME.md<project-name>undefined<project-name>undefinedhyperframeshyperframesbrew install ffmpegsudo apt install ffmpegnpx hyperframes doctornpxhyperframesbrew install ffmpegsudo apt install ffmpegnpx hyperframes doctornpxhyperframesnpx hyperframes previewhttp://localhost:3002npx hyperframes previewhttp://localhost:3002npx hyperframes render index.html -o output.mp4output.mp4--fps 60--resolution 3840x2160npx hyperframes render index.html -o output.mp4output.mp4--fps 60--resolution 3840x2160undefinedundefinedindex.html@hyperframes/core/dist/hyperframe.runtime.iife.jsreadycurrentTime<script src="https://cdn.jsdelivr.net/npm/gsap@3.14.2/dist/gsap.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/@hyperframes/core/dist/hyperframe.runtime.iife.js"></script>preview.htmlsrcdocument.getElementById("p").setAttribute("src", "./index.html" + location.search)src=data-composition-id__timelineswindow.__timelines["..."]"main"HyperShader.init()<div class="scene-content">captureIncomingScene()Date.now()Math.random()setIntervalsetTimeoutrepeat: -1index.html@hyperframes/core/dist/hyperframe.runtime.iife.jsreadycurrentTime<script src="https://cdn.jsdelivr.net/npm/gsap@3.14.2/dist/gsap.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/@hyperframes/core/dist/hyperframe.runtime.iife.js"></script>preview.htmldocument.getElementById("p").setAttribute("src", "./index.html" + location.search)srcsrc=data-composition-id__timelineswindow.__timelines["..."]"main"HyperShader.init()<div class="scene-content">captureIncomingScene()Date.now()Math.random()setIntervalsetTimeoutrepeat: -1| Type | Duration | Scenes | Avg scene | Format (default) |
|---|---|---|---|---|
| Social ad (IG/TikTok/Reels) | 10–15s | 5–8 | 2–3s | 1080×1920 (9:16) |
| Launch teaser | 10–20s | 6–10 | 2–3s | 1920×1080 or 1080×1920 |
| Product demo | 20–45s | 8–14 | 3–4s | 1920×1080 |
| Feature announcement | 15–30s | 6–12 | 2–4s | 1920×1080 |
| Brand reel | 20–45s | 8–14 | 3–4s | 1920×1080 |
| Explainer | 30–60s | 12–20 | 3–5s | 1920×1080 |
| Long-form narrative | 60–180s | 24–45 | 3–5s | 1920×1080 |
| 类型 | 时长 | 场景数 | 平均场景时长 | 默认格式 |
|---|---|---|---|---|
| 社交广告(IG/TikTok/Reels) | 10–15秒 | 5–8 | 2–3秒 | 1080×1920(9:16) |
| 发布预告 | 10–20秒 | 6–10 | 2–3秒 | 1920×1080或1080×1920 |
| 产品演示 | 20–45秒 | 8–14 | 3–4秒 | 1920×1080 |
| 功能发布 | 15–30秒 | 6–12 | 2–4秒 | 1920×1080 |
| 品牌短视频 | 20–45秒 | 8–14 | 3–4秒 | 1920×1080 |
| 讲解视频 | 30–60秒 | 12–20 | 3–5秒 | 1920×1080 |
| 长叙事视频 | 60–180秒 | 24–45 | 3–5秒 | 1920×1080 |
@hyperframes/playernpx hyperframeshyperframes add@hyperframes/playernpx hyperframeshyperframes addUse the attached skill. 30s product walkthrough matching these screenshots. Feature-led, 16:9, dark theme.Use the attached skill. 15s 9:16 teaser for the brand in this PDF. Honor palette and type exactly.Use the attached skill. 20s video in the same tonal register as this reference. Match pacing, color, shader character; my copy below.Use the attached skill. 30s hero reel with this copy for each scene: [pasted script]. Dark theme, technical, no warmth.Use the attached skill. 45s editorial explainer. Palette: #0a0a0d / #f5f5f7 / #7c6cff. Type: Space Grotesk + JetBrains Mono. Copy below.Use the HyperFrames Claude Design skill. Turn https://www.anthropic.com/news/claude-design-anthropic-labs into a 45-second editorial explainer.web_fetchUse the HyperFrames Claude Design skill. 30-second product video for linear.app.web_fetchUse the attached skill. Make me a 30-second launch video for Orbit. Make it cool.Cut it to 20 seconds and drop scene 3.使用附加技能。制作30秒产品导览,匹配这些截图。以功能为主,16:9,深色主题。使用附加技能。为PDF中的品牌制作15秒9:16预告。严格遵循调色板和字体。使用附加技能。制作20秒视频,与参考视频调性一致。匹配节奏、色彩、着色器风格;文案如下。使用附加技能。制作30秒核心短视频,每个场景使用以下文案:[粘贴脚本]。深色主题,科技感,无温暖风格。使用附加技能。制作45秒社论讲解视频。调色板:#0a0a0d / #f5f5f7 / #7c6cff。字体:Space Grotesk + JetBrains Mono。文案如下。使用HyperFrames Claude Design技能。将https://www.anthropic.com/news/claude-design-anthropic-labs转换为45秒社论讲解视频。web_fetch使用HyperFrames Claude Design技能。制作30秒linear.app产品视频。web_fetch使用附加技能。为Orbit制作30秒发布视频。要酷。缩短到20秒,删除场景3。