VYBE 动态设计 是做什么的?
运动即信息。每一次移动都必须传达出关于主题的某种信息—— 重量、速度、自信、惊奇——否则就不应该存在。
所有配方均为 HyperFrames 设计:每个合成使用一条暂停的 GSAP 时间线,
确定性强,可定位。使用 fromTo 处理入场,transform + opacity +
clipPath + filter 处理动画,绝不使用布局属性。
参考文件(按需加载)
| 文件 | 用途 |
|---|---|
references/animation-principles.md | 12 项原则在 UI/排版/图形中的应用,缓动词汇,时间表 |
references/transitions.md | 14 种转场配方及 GSAP 代码,以及每种的使用场景 |
references/camera-movements.md | 推拉、平移、升降、环绕、穿越式缩放、甩镜、焦点偏移、视差 — 2D 和 3D |
references/visual-effects.md | 辉光、泛光、漏光、胶片颗粒、色差分离、运动模糊、遮罩、变形 |
十条规则
- 编排,而非单纯动画。 规划谁先移动,谁回应,谁静止。一个场景就是一句话:主语 → 谓语 → 宾语。
- 缓动即性格。
expo.out= 高级感/自信;back.out= 趣味性;power2.inOut= 机械感相机;sine.inOut= 呼吸感/氛围;none= 持续漂移。每部影片选用 2-3 种缓动并保持一致。 - 快进慢停。 大多数入场:0.5-0.9 秒,在前 30% 的时间内完成 80% 的位移。
- 出场比入场更快(约 60%)并使用
.in缓动。 - 交错揭示层级 — 字母间 0.04-0.08 秒,单词间 0.1-0.18 秒,列表项间 0.3-0.6 秒。切勿对所有元素使用相同的交错时间。
- 重叠动作。 下一个元素在前一个元素完成之前开始(使用位置参数
"<0.2"/ 绝对时间)。顺序执行 = 机械感。 - 预留阅读时间。 约每词 0.3 秒 + 0.5 秒;结尾行 ≥2 秒。
- 始终有动态。 在保持期间,使用慢速推进(
scale 1→1.04)、漂移或光线扫掠防止画面沉寂——但每层只能有一个氛围动画。 - 变换转场。 每部影片最多使用一次黑场过渡。优先使用运动剪辑、匹配剪辑、遮罩擦拭、穿越式缩放、共享元素。
- 尊重节拍。 如果有音乐,每次主要变化都应落在节拍上(
60/bpm);重音落在正拍上,预备动作在节拍前开始。
可定位的 GSAP 模式
const tl = gsap.timeline({ paused: true });
// 入场:由模糊到清晰的上升效果(高级感)
tl.fromTo("#s1-title", { opacity: 0, y: 40, filter: "blur(12px)" },
{ opacity: 1, y: 0, filter: "blur(0px)", duration: 0.9, ease: "expo.out" }, 0.2);
// 遮罩擦拭揭示效果(编辑风格)
tl.fromTo("#s1-line", { clipPath: "inset(0 100% 0 0)" }, { clipPath: "inset(0 0% 0 0)", duration: 0.8, ease: "expo.inOut" }, 0.5);
// 逐字形扩散(替代 letterSpacing —— 因为 letterSpacing 会被 lint 拒绝)
gsap.utils.toArray("#s1-word .ch").forEach((c, i, all) => {
const off = (i - (all.length - 1) / 2) * -30;
tl.fromTo(c, { x: off, opacity: 0 }, { x: 0, opacity: 1, duration: 1, ease: "expo.out" }, 1 + Math.abs(i - (all.length - 1) / 2) * 0.05);
});
// 数字递增(可定位:onUpdate 在每次定位时都会执行)
const n = { v: 0 }, el = document.getElementById("s1-num");
tl.fromTo(n, { v: 0 }, { v: 97, duration: 1.4, ease: "expo.out", onUpdate: () => (el.textContent = Math.round(n.v)) }, 1.2);
// 保持动态
tl.fromTo("#s1-stack", { scale: 1 }, { scale: 1.04, duration: 3, ease: "sine.inOut" }, 0);
window.__timelines["s1"] = tl;
拆分文本:将单词/字母包裹在 <span class="w|ch" style="display:inline-block"> 中(transform 在行内元素上无效)。保持空格在 span 之外。
交付前检查
- 相邻两个场景不得使用相同的入场动画。
- 同一元素不得在时间重叠区域对同一属性进行两次补间。
npx hyperframes check中的 Motion 部分应无问题;如需编排审计,请运行随 HyperFrames 的/hyperframes-animation技能一起安装的animation-map.mjs脚本。