资讯动态

OpenMontage HyperFrames Sine Wave Loop:用 GSAP 相位驱动实现「微抖动与有界呼吸」的 Idle 动画配方

发布时间:2026/9/8 22:03:14 来源:尧图企业网站定制
OpenMontage HyperFrames Sine Wave Loop用 GSAP 相位驱动实现「微抖动与有界呼吸」的 Idle 动画配方【免费下载链接】OpenMontageWorlds first open-source, agentic video production system. 12 production pipelines, 100 tools, 700 agent skill and production-knowledge files. Turn your AI coding assistant into a full video production studio.项目地址: https://gitcode.com/GitHub_Trending/op/OpenMontage本文围绕 sine-wave-loop.md 这条 HyperFrames 原子动效规则展开它规定了如何用一个有限时长的 GSAP tween 驱动Math.sin相位为「已定格」的镜头元素叠加低振幅微抖动subtle jitter或单次有界呼吸bounded ambient breath。读完本文你可以掌握完整可运行的 HTML/CSS/GSAP 代码骨架、全部调参取值范围布局、入场、空闲三阶段、四种进阶变体以及为什么这套实现必须交给 GSAP 时间轴而不能交给 CSSkeyframes的底层原因。运动教义Reveal Jitter Breath最后才用本规则文档开篇给出了一条明确的选型优先级Reach for this last这是理解整条规则的前提圆形呼吸——让文字/卡片上下缩放来显得有生命感——被认为是廉价动作它是 Agent 的本能作弊项观感上显得软弱。文档的态度是宁可不加动效也不要糟糕的动效Id rather have NO motion than BAD motion。第一优先与旁白VO时序对齐的顺序揭示——在场景后 50% 的时长里VO 说到哪一句就揭示哪一行/哪一个元素。是顺序揭示而不是环境动效负责填满一个镜头。第二优先微抖动subtle jitter——当画面确实已经定格、但仍需要一点生气时用本规则在振幅范围的低端运行。第三优先罕见情形完整呼吸循环——只保留给单个被长时间持有的 hero 元素真正需要有界环境动效时并且必须保持弱化、小幅度。该规则在 rules-index.md 中被归入Idle Ambient分类索引条目将其概括为连续呼吸/环境动效说明它与 ambient-glow-bloom.md 同属空闲氛围工具族。文档自身定位也强调本规则是实现subtle jitter这一词汇条目的底层手段而不是给每个 hero 都盖章加呼吸的许可证。工作原理相位驱动 sin(0) 0的无跳变衔接规则的核心机制分两步相位推进一个足够长的 tween 把phase值从 0 推向2π或其整数倍2π * CYCLES。每次onUpdate时phase 被喂给Math.sin()产生一个小的周期性偏移量叠加到元素的 transformscale、translateY、rotate上。无跳变衔接的数学保证从入场entry过渡到空闲idle时为什么不跳因为在phase 0时sin(0) 0——偏移量为零元素恰好停留在其入场结束后的静止状态。空闲动效是叠加在静止状态之上而不是替换它。这正是Compose, dont replace原则的数学基础也解释了后文为什么相位 tween 必须以ease: none运行——sine 本身已经提供了缓动若再对 phase 做非线性 tween得到的运动就不再是纯正弦了。为什么必须由 GSAP 时间轴驱动源码级佐证文档Key Principles中专门警告不要使用 CSSkeyframes做 idle 循环——CSS 动画跑在浏览器自己的渲染时钟上与 HyperFrames 的 seek 时钟互相独立HF 是逐帧 seek 的CSS 驱动的 idle 会闪烁/失步。这一点在 HyperFrames 核心技能中有直接印证determinism-rules.md 明确渲染器接收一个时间值并产出像素缓冲不存在播放的概念——每一帧都是一次全新 seek且要求使用gsap.timeline({ paused: true })。SKILL.md 也把单一 paused 时间轴、seek 安全、确定性列为整个 hyperframes-animation 技能的地基禁止repeat: -1、禁止任何依赖经过前帧累积的状态。CSS keyframes 恰恰属于后者它的进度由墙钟累积渲染器并行乱序采样时会失步。完整配方HTML / CSS / GSAP Timeline以下完整继承原文档的三段代码。{...}与全大写占位符为待填 token/常量取值范围见后文参数选择参考。HTMLdiv classscene ididle-scene >.scene { position: relative; width: 100%; height: 100%; display: grid; place-items: center; background: {bgGradient}; } .stack { display: flex; flex-direction: column; align-items: center; gap: STACK_GAP; } .hero { font-family: {font}; font-weight: 900; font-size: HERO_FONT_SIZE; letter-spacing: HERO_LETTER_SPACING; color: {textColor}; text-transform: uppercase; /* Element gets its post-entry resting transform; idle only ADDS to it */ will-change: transform; } .dot { width: DOT_SIZE; height: DOT_SIZE; border-radius: 50%; background: {accentColor}; box-shadow: {accentGlow}; }.hero上的注释是关键元素携带其入场结束后的静止 transformidle 只在其之上做加法。.dot是次级强调元素accent用于演示相位错开的呼吸。GSAP Timelinescript srchttps://cdn.jsdelivr.net/npm/gsap3.14.2/dist/gsap.min.js/script script window.__timelines window.__timelines || {}; const tl gsap.timeline({ paused: true }); const hero document.getElementById(hero); const dot document.getElementById(dot); // Phase 1 — entry beat (e.g. headline fade-up) tl.fromTo( hero, { opacity: 0, y: ENTRY_Y, scale: ENTRY_SCALE }, { opacity: 1, y: 0, scale: 1, duration: ENTRY_DUR, ease: power3.out }, 0, ); tl.fromTo( dot, { opacity: 0, scale: 0 }, { opacity: 1, scale: 1, duration: DOT_ENTRY_DUR, ease: back.out(${BOUNCE_FACTOR}) }, DOT_ENTRY_START, ); // Phase 2 — idle breathing. Starts at IDLE_START_TIME AFTER entry settles. // Drive a phase 0 → 2π * CYCLES via a single tween, write sin() into transforms. const phase { p: 0 }; tl.to( phase, { p: Math.PI * 2 * CYCLES, duration: IDLE_DUR, ease: none, onUpdate: () { // Hero: scale breathes ±SCALE_AMP, y bobs ±Y_AMP_PX const scale 1 Math.sin(phase.p) * SCALE_AMP; const y Math.sin(phase.p) * Y_AMP_PX; hero.style.transform translateY(${y}px) scale(${scale}); // Dot: out-of-phase scale (offset by π/2) — feels alive vs synced const dotScale 1 Math.sin(phase.p Math.PI / 2) * DOT_SCALE_AMP; dot.style.transform scale(${dotScale}); }, }, IDLE_START_TIME, ); window.__timelines[idle-scene] tl; /script代码结构要点时间轴注册window.__timelines[idle-scene] tl键名与data-composition-id一致HyperFrames 靠它逐帧 seek 该场景。Phase 1入场hero 用power3.out淡入上浮dot 用back.out(BOUNCE_FACTOR)弹性弹出在 hero 仍在收拢时就落地。Phase 2空闲一个对象{ p: 0 }作为相位代理tl.to把它从 0 推到2π * CYCLESonUpdate里把Math.sin(phase.p)写进两个元素的 transform。dot 额外加了π/2相位差形成非同步即有生气的观感。IDLE_START_TIME是绝对时间位点tween 的第三参数保证呼吸只在入场落定后开始且sin(0) 0使起点偏移为零。四种进阶变体1. 多频叠加有机多八度呼吸纯正弦略显机械叠加一个更高频的低幅正弦更接近有机const primary Math.sin(phase.p) * SCALE_AMP_PRIMARY; const secondary Math.sin(phase.p * OCTAVE_RATIO) * SCALE_AMP_SECONDARY; // higher-frequency overlay const scale 1 primary secondary;约束SCALE_AMP_PRIMARY SCALE_AMP_SECONDARYsecondary 是叠层不是同级两者合成的峰值振幅仍须落在SCALE_AMP的默认区间内。2. 条件激活入场落定后才启动当入场是交互式的或可跳过时用门控决定 idle 是否生效const idleActive entryProgress GATE_THRESHOLD; const scale idleActive ? 1 Math.sin((time - IDLE_START_TIME) / PERIOD) * SCALE_AMP : 1;3. 落定渐隐Settle and fade长空闲强烈建议当IDLE_DUR 6s时用包络envelope让振幅在最后约 20% 时间线性归零使场景在转场开始前可见地静止下来const phase { p: 0 }; const FADE_FRAC 0.2; // last 20% of idle amplitude ramps to 0 tl.to( phase, { p: Math.PI * 2 * CYCLES, duration: IDLE_DUR, ease: none, onUpdate: () { const t phase.p / (Math.PI * 2 * CYCLES); // 0 → 1 across idle const env t 1 - FADE_FRAC ? 1 : (1 - t) / FADE_FRAC; // 1 → 0 in tail const scale 1 Math.sin(phase.p) * SCALE_AMP * env; const y Math.sin(phase.p) * Y_AMP_PX * env; hero.style.transform translateY(${y}px) scale(${scale}); }, }, IDLE_START_TIME, );效果元素在前 80% 时间内运动最后 20% 静止落定。这与 break-boundary Tier-B 转场天然契合——交叉淡入/推屏开始时出画侧画面已经是静止的。文档指出这是终审快照中出现结尾所有东西还在动时最大的单项修复。4. 周期与循环次数的换算想要精确 N 秒一个完整周期const divisor (idleDurationSec * fps) / (Math.PI * 2); const value Math.sin(frame / divisor) * amplitude;在 HF 的onUpdate中拿不到 frame 直接值因此改用 tween 的phase值驱动p: Math.PI * 2 * cyclesWanted、duration: idleDurationSec由CYCLES idleDurationSec / 周期秒数反推循环次数。参数选择参考完整继承布局 / 排版参数含义取值范围STACK_GAPhero 与 dot 的垂直间距0.2–0.4 × HERO_FONT_SIZEHERO_FONT_SIZE/HERO_LETTER_SPACING字体强调全出血构图 100–240px字距 0.04–0.06emDOT_SIZE强调指示点尺寸约0.15–0.25 × HERO_FONT_SIZE确保 dot 读起来是 accent 而非平级元素{accentGlow}dot 的box-shadow光晕典型0 0 (DOT_SIZE) rgba(accentColor, 0.5–0.7)入场阶段参数含义取值范围 / 约束ENTRY_Y/ENTRY_SCALEfade-up 前的初始状态ENTRY_Y16–32px微升ENTRY_SCALE0.94–0.98微膨胀ENTRY_DURhero 淡入时长0.6–1.2s更大的 hero 需要更长收拢DOT_ENTRY_STARTdot 相对 hero 的弹出时点约束约0.4–0.6 × ENTRY_DUR让 dot 在 hero 仍收拢时落地而非之后DOT_ENTRY_DURdot 的 back.out 弹出时长0.4–0.7sBOUNCE_FACTORdot 弹出的back.out过冲强度1.4柔和→ 2.0干脆→ 2.8卡通空闲阶段本文核心调参区参数含义取值范围 / 约束IDLE_START_TIME呼吸开始时刻约束≥ ENTRY_DUR 约 0.1s缓冲避免呼吸与入场尾段打架此刻sin(0) 0偏移恰好等于入场的静止态——无跳变IDLE_DUR呼吸 tween 时长约束必须等于TOTAL_DURATION − IDLE_START_TIME用动效填满整个合成CYCLESIDLE_DUR内完整呼吸周期数范围IDLE_DUR / 3s ≤ CYCLES ≤ IDLE_DUR / 1.5s周期 1.5–3s 读起来像自然呼吸SCALE_AMPhero 的 scale 正弦振幅默认 0.008–0.015几乎不可察觉——多数场景的正解仅当元素独占画布、场景短于 6s或 brief 明确要求 kinetic/playful 语气时推高到 0.02–0.04Y_AMP_PXhero 的 y 平移正弦振幅默认 2–3px推高到 4–6px 的门槛与SCALE_AMP相同DOT_SCALE_AMPdot 的 scale 振幅相位错开 π/20.04–0.12——比 hero 大也没关系因为 dot 是小尺寸 accentPERIOD条件激活变体(time − IDLE_START_TIME) / PERIOD形式的每周期秒数1.5–3sGATE_THRESHOLD条件激活变体启动 idle 所需的 entryProgress0.85–1.0门限更低可在入场完成前轻微重叠启动多八度变体参数约束 / 范围SCALE_AMP_PRIMARY/SCALE_AMP_SECONDARYPRIMARY SECONDARYsecondary 是高频叠层而非同级合成峰值振幅须保持在SCALE_AMP区间内OCTAVE_RATIO2.0–4.0——接近整数的比值听感音乐化/协调非整数比值则有机/不可预测颜色 token{bgGradient}通常为深色径向渐变让受光 hero 跳出来{textColor}与背景高对比{accentColor}唯一强调色只保留给 dot{accentGlow}的光晕是同色相。关键原则Key Principles逐条解析优先 Reveal其次 Jitter最后 Breath——呼吸是廉价且显弱的先让与 VO 对齐的顺序揭示填满镜头后段真正定格后仍显死板才用本规则在振幅低端做微抖动完整呼吸循环是单个被持有 hero 的罕见最后手段绝不盖章到每个元素上。sin(0) 0——idle 开始瞬间偏移必须为零相位 tween 从phase 0起。振幅默认取区间低端——scale0.008–0.015隔离/短场景/kinetic brief 才到 0.02–0.04旋转±0.3–0.8°几乎用不到平移±2–3px隔离场景才 4–6px。幅度偏大、且处于 idle 中读起来是还在动画而不是活着但在休息观众连续看 5 个场景都在上端运行时会把整片看成在发颤。呼吸周期idle 长时 2.5–4s/次否则 1.5–3s/次——2.5–3s 是舒适的呼吸节奏长 idle 窗口里低于 1.5s 显得慌乱短窗口里超过 4s 显得死气。长 idle 窗口IDLE_DUR 6s或 idle 占比 30%减半法则——SCALE_AMP与Y_AMP_PX减半CYCLES放慢使每口呼吸 3–4s并考虑用包络在最后 20% 把振幅淡出为零让场景在转场前真正落定。N 个并发 idle 元素的1/√N法则——三联列、卡片网格、多统计行、并排面板等单元素振幅 ≤ 默认值/ √N。三列各±6px在视觉上叠加成±18px的竞争性运动三个±2–3px才读作一次集体呼吸。同时错开周期2.1s / 1.9s / 2.4s以获得有机感——但记住必须缩小振幅不只是错开周期。不同元素使用不同相位——次级元素错开Math.PI / 290°避免全体同相。同步运动显机械错相运动显活着。这条在仓库示例中有真实落地comparison-split-cards.html 中左右两张卡的浮动位移与旋转正是用Math.sin(t * speed)与Math.sin(t * speed Math.PI)180° 反相成对驱动的。叠加而非替换Compose, dont replace——idle 运动加在元素的静止 transform 之上而不是覆盖它。入场收拢在translateY(0)则 idle 应产出translateY(0 sin*4)不要覆写入场的最终位移。brand-reveal-assemble-zoom.html 就是这个模式的实例hero 的 scale 写成HERO_FINAL_SCALE * (1 Math.sin(omega) * SCALE_AMP)——呼吸幅度乘在入场的最终静态缩放之上而不是从 1 重新起算。❗ 禁用 CSSkeyframes做 idle 循环——CSS 动画跑在浏览器渲染时钟上与 HF 的逐帧 seek 时钟相互独立会闪烁/失步idle 必须写在 GSAP 时间轴内底层依据见本文工作原理小节的 determinism-rules 佐证。硬性约束Critical Constraints逐条继承文档清单时间轴必须 pausedgsap.timeline({ paused: true })——这是 determinism-rules.md 要求的 seek 契约的一部分渲染器从时间值反推像素不允许自动播放的时间轴。注册表键 data-composition-idwindow.__timelines[idle-scene]必须与场景根元素的data-composition-id一致。idle 不用 CSSanimation——必须时间轴驱动。will-change: transform——当 idle 与其他 tween 在同一元素上复合使用时。相位 tweenease: none——sine 本身即缓动对 phase 做非线性 tween 会产生非正弦运动。不要重启 idle tween——它是横跨整个合成空闲窗口的单个长 tween从空闲窗口起点一直运行到终点。组合路径与技能衔接与其他规则的串联文档 Combinations 节均位于 rules/ 目录同一时间轴内顺序编排press-release-spring.md 之后——按钮在按压释放收拢后进入 idle 呼吸counting-dynamic-scale.md 之后——计数结束的最终数字做呼吸card-morph-anchor.md 之后——形态变换落定的卡片做 idle 浮动orbit-3d-entry.md 之后——物品环绕轨道时中心标签 idle 呼吸。与 HyperFrames 技能族的分工本规则依赖/hyperframes-animationonUpdate写 transform 的通用模式、/hyperframes-core合成结构、data 属性、确定性契约与/hyperframes-clihyperframes lint校验。技能内部的 rules-index.md 建议每个场景组合 2–4 条规则、共用一条 paused 时间轴本文规则通常作为时间轴的收尾段——在前序入场/转场规则把元素推到静止态之后接管。实操自检清单落地本规则时可按以下顺序校验依据均为上文原文档条款相位 tween 是否ease: none、单条、从IDLE_START_TIME贯穿到TOTAL_DURATIONIDLE_START_TIME ≥ ENTRY_DUR 0.1s且起点sin(0) 0与入场静止态无缝振幅是否取了区间低端scale 0.008–0.015 / y 2–3px并发元素是否按1/√N收缩并错开相位与周期IDLE_DUR 6s时是否启用了末 20% 振幅归零的 settle-and-fade 包络时间轴是否 paused、是否以data-composition-id注册到window.__timelinesidle 是否全部写在 GSAP 时间轴内无 CSSkeyframes。全部满足时该场景在 HyperFrames 逐帧 seek 渲染下是确定性的同一时间值必然产出同一像素呼吸的活着感来自数学而非墙钟——这正是本文规则与廉价 CSS 呼吸的本质区别。【免费下载链接】OpenMontageWorlds first open-source, agentic video production system. 12 production pipelines, 100 tools, 700 agent skill and production-knowledge files. Turn your AI coding assistant into a full video production studio.项目地址: https://gitcode.com/GitHub_Trending/op/OpenMontage创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价