首页
/ HyperFrames Cut the Curve 转场技巧:完整 GSAP 代码模板、Registry Token 机制与调参指南

HyperFrames Cut the Curve 转场技巧:完整 GSAP 代码模板、Registry Token 机制与调参指南

2026-09-05 21:57:56作者:房伟宁

本文基于仓库中的 GSAP 实现模板文档,系统讲解 HyperFrames 视频合成体系里 "Cut the Curve" 技巧目录的 7 种转场/进场代码模板:前向/反向 Zoom-Through、场景级 Cut the Curve、逐词 Waterfall Cut、Rack-Focus Blur-Cut,以及场景内的 Waterfall Entry 与 Nudge Curve。读完本文,你可以直接复用这些模板编写场景切换动画,理解 registry gsap_template 的 token 注入机制,并按文档给出的调参范围精确控制速度匹配(velocity matching)。

模板文档的定位:worker 版与 registry 版两套体系

GSAP 实现模板文档cut-the-curve 技能目录 中"参数与规则在 SKILL.md,代码从这里复制"的配套文件。它维护着两种不同用途的 GSAP 实现:

  • Worker 版:由 worker(作者 agent)手写的、对场景内元素(in-scene elements)做 tween 的完整代码,使用真实的选择器(如 .text-a-wrapper)和具体的时间点变量,适合在单个合成(comp)内手工编排。
  • Registry gsap_template:带 token 占位符的模板代码,由注入器(injector)在装配主时间轴时替换 token 并"盖章"(stamp)到两个 clip wrapper 上。

registry 模板中的 token 含义(见 seam-craft 技能文档 的 Template placeholders 一节):

Token 含义
__OLD__ 出场 clip wrapper 选择器,形如 "#el-<from>"(带引号)
__NEW__ 入场 clip wrapper 选择器,形如 "#el-<to>"(带引号)
__T__ 重叠窗口起点时间(秒,主时钟)
__DUR__ 该边界的 duration_s
__DX__ 水平行程:-1920(LEFT)/ 1920(RIGHT)
__DY__ 垂直行程:-1080(UP)/ 1080(DOWN)
__ORIGIN_OUT__ / __ORIGIN_IN__ squeeze 类型用的 transformOrigin 对

从注入器机制看(seam-craft 文档描述):在场景 i 与场景 i+1 的边界处,注入器会把 #el-<from>data-duration 延长 duration_s(保持其最后一帧)、把 #el-<to>data-start 前移 duration_s 形成重叠窗口,并将所有 clip 的 data-track-index 重新排为 0/1 乒乓(同 track 重叠非法,高 track 的合成在上层),最后把 gsap_template 写入 window.__timelines["main"],时间点取 T = overlap-start。这解释了模板中为什么 __OLD____NEW__ 的 tween 都从同一个 __T__ 起始——两者在主时间轴上是并行重叠的。

1. Zoom-Through(前向穿越)

前向 Zoom-Through 用于"向同一思想更深处推进"的 Z 轴转场:出场文字向镜头加速放大,在峰值模糊处硬切,入场文字从小尺寸继续生长到焦平面。总时长约 0.4s。

Worker 版(场景内 wrapper 交换)

var EXIT_START = /* when readable text starts leaving */;
var CUT = EXIT_START + 0.2;

// Phase 1: Exit — scale/blur accelerate, opacity fades linearly (separate tween)
tl.to(".text-a-wrapper", {
  scale: 1.2,
  filter: "blur(10px)",   // text-scale: 10px
  duration: 0.2,
  ease: "power3.in",
  overwrite: "auto"
}, EXIT_START);
tl.to(".text-a-wrapper", { opacity: 0.15, duration: 0.2, ease: "none" }, EXIT_START);

// Phase 2: Hard cut — matched properties
tl.set(".text-a-wrapper", { opacity: 0 }, CUT);
tl.set(".text-b-wrapper", { opacity: 0.15, scale: 0.75, filter: "blur(10px)" }, CUT);

// Phase 3: Entry — fast initial velocity, long settle
tl.to(".text-b-wrapper", {
  scale: 1, filter: "blur(0px)", opacity: 1,
  duration: 0.5, ease: "expo.out"
}, CUT);

关键细节:

  • 退场的 opacity 必须是独立的线性 tweenease: "none")——若挂在 power3.in 上,opacity 会在接近 1 的区间停留过久,硬切帧上就会看到"还在"的旧文字。
  • 切帧(CUT 时刻的 tl.set)上,两侧属性必须严格对称匹配:出场侧 opacity: 0,入场侧 opacity: 0.15, scale: 0.75, filter: "blur(10px)",保证交换帧两侧的模糊/透明度一致。
  • overwrite: "auto" 防止与其他针对同一 wrapper 的 tween 打架。

Registry gsap_template

tl.to(
  __OLD__,
  { scale: 2.5, opacity: 0, filter: "blur(8px)", duration: __DUR__, ease: "power3.in" },
  __T__,
);
tl.fromTo(
  __NEW__,
  { scale: 0.5, opacity: 0, filter: "blur(8px)" },
  { scale: 1, opacity: 1, filter: "blur(0px)", duration: __DUR__, ease: "power3.out" },
  __T__,
);

注意 registry 版与 worker 版的数值差异:registry 版作用于整帧 clip wrapper,行程更大(0.5 → 1 / 1 → 2.5)、模糊更轻(8px)、且是 fromTo 并行结构;worker 版作用于场景内的文字 wrapper,模糊取 10px(文字级峰值模糊)。这段模板在仓库中有真实的 registry 落地:product-launch-video 技能的 transitions.jsonzoom-through 条目逐字一致,且标注 default_duration_s: 0.4energy: "high",并被登记为该 workflow 的 default_high_energy 转场(skills/pr-to-videoskills/faceless-explainer 下各有一份同构的 vendored 副本)。

2. Inverse Zoom-Through(反向穿越)

反向版本:出场元素后退,入场元素以超大尺寸(仿佛刚从镜头后方探出)收缩回焦平面。整体"都在缩小",用于"更大的东西落地"的到达/高潮 beat(payoff line、巨型回复、收尾定格),不要用于普通边界。总时长约 0.7s,按 30% 退场 / 70% 入场切分。

Registry gsap_template

tl.set(__NEW__, { opacity: 0 }, __T__);
tl.to(
  __OLD__,
  { scale: 0.8, filter: "blur(10px)", duration: __DUR__ * 0.3, ease: "power3.in" },
  __T__,
);
tl.to(__OLD__, { opacity: 0.15, duration: __DUR__ * 0.3, ease: "none" }, __T__);
tl.set(__OLD__, { opacity: 0 }, __T__ + __DUR__ * 0.3);
tl.fromTo(
  __NEW__,
  { opacity: 0.15, scale: 1.25, filter: "blur(10px)" },
  {
    opacity: 1,
    scale: 1,
    filter: "blur(0px)",
    duration: __DUR__ * 0.7,
    ease: "expo.out",
    immediateRender: false,
  },
  __T__ + __DUR__ * 0.3,
);

结构要点:

  • 时间预算用 __DUR__ * 0.3 / __DUR__ * 0.7 表达 30/70 切分,退场(scale 1 → 0.8)在前 30%,入场收缩(1.25 → 1expo.out)占后 70%。
  • 入场侧的 immediateRender: false 很关键:fromTo 的起始值(opacity: 0.15, scale: 1.25)不会在时间轴构建时就提前渲染,而是等到 __T__ + __DUR__ * 0.3 才生效。
  • 同样有独立 ease: "none" 的 opacity 线性 tween,与硬切 tl.set(__OLD__, { opacity: 0 }, __T__ + __DUR__ * 0.3) 衔接。

Worker 版:与 Zoom-Through 同构的三阶段(退场 → 硬切 → 入场),只是 scale 数值翻转——退场 1 → 0.8、切帧切入在 1.25、入场 1.25 → 1

Z 方向符号纪律(来自 SKILL.md):Z 轴上"同轴"还不够,d(scale)/dt符号必须在切帧两侧一致:

Z 向量 退场 scale 入场 scale 变体
Push(前推) 增长 1 → 1.2 增长 0.75 → 1 zoom-through
Pull(后拉) 收缩 1 → 0.8 收缩 1.25 → 1 inverse zoom-through

被禁止的镜像组合:后退的退场配"从小长出来"的入场(最常见的错误,因为 grow-from-small 是元素入场的默认写法),以及前推退场配超大收缩入场。这条符号纪律约束的是入场场景自己的内部入场动画(切帧 + 约 0.5s 的 seam 窗口内),而不只是 wrapper tween——入场画面要么以"已构图"状态到达,要么其入场动画与 Z 符号匹配。

3. Cut the Curve(默认场景边界)

这是所有场景到场景边界的默认切法:出场 hero 朝一个方向加速,切帧落在运动中段,入场 hero 沿同一方向继续并减速。总时长约 0.6s;方向取 LEFT / RIGHT / UP / DOWN(默认 LEFT)。核心是部分行程:约 12% 画幅(1920 宽下约 230px),绝不做整屏移出。

Worker 版(场景层)

var CUT_TIME = /* scene transition point */;

// Scene A: hero accelerates leftward (partial travel ~12% of frame)
tl.to(".scene-a-layer", { opacity: 0, duration: 0.33, ease: "power2.in" }, CUT_TIME - 0.33);
tl.to(".hero-a-wrapper", {
  x: -230, filter: "blur(8px)",
  duration: 0.33, ease: "power4.in",   // mirrored half of power4.inOut
  overwrite: "auto"
}, CUT_TIME - 0.33);

// Hard cut
tl.set(".scene-b-layer", { opacity: 1 }, CUT_TIME);
tl.set(".hero-b-wrapper", { x: 230, filter: "blur(8px)" }, CUT_TIME);

// Scene B: hero decelerates leftward
tl.to(".hero-b-wrapper", {
  x: 0, filter: "blur(0px)",
  duration: 0.33, ease: "power4.out"   // matched velocity at the cut
}, CUT_TIME);

原理是镜像缓动:退场 power4.in + 入场 power4.out,同样的距离与时长——它们正是同一个 power4.inOut 的前后半段,因此切帧处速度精确相等。四方向的行程表:

方向 退场 入场 起点 → 终点
向左 x: 0 → −230 x: +230 → 0
向右 x: 0 → +230 x: −230 → 0
向上 y: 0 → −230 y: +230 → 0
向下 y: 0 → +230 y: −230 → 0

Registry gsap_template

__DX__ = -1920(LEFT)/ 1920(RIGHT);__DY__ = -1080(UP)/ 1080(DOWN)。* 0.12 / * 0.21 系数产出约 12% 的部分行程(垂直方向 1080 × 0.21 ≈ 227px,与水平 230px 对齐)。

// horizontal
tl.set(__NEW__, { opacity: 0 }, __T__);
tl.to(__OLD__, { x: __DX__ * 0.12, duration: __DUR__ * 0.5, ease: "power4.in" }, __T__);
tl.to(__OLD__, { opacity: 0, duration: __DUR__ * 0.47, ease: "power2.in" }, __T__ + __DUR__ * 0.03);
tl.fromTo(
  __NEW__,
  { x: __DXIN__ * 0.12, opacity: 0.35 },
  { x: 0, opacity: 1, duration: __DUR__ * 0.5, ease: "power4.out", immediateRender: false },
  __T__ + __DUR__ * 0.5,
);

// vertical
tl.set(__NEW__, { opacity: 0 }, __T__);
tl.to(__OLD__, { y: __DY__ * 0.21, duration: __DUR__ * 0.5, ease: "power4.in" }, __T__);
tl.to(__OLD__, { opacity: 0, duration: __DUR__ * 0.47, ease: "power2.in" }, __T__ + __DUR__ * 0.03);
tl.fromTo(
  __NEW__,
  { y: __DYIN__ * 0.21, opacity: 0.35 },
  { y: 0, opacity: 1, duration: __DUR__ * 0.5, ease: "power4.out", immediateRender: false },
  __T__ + __DUR__ * 0.5,
);

registry 版与 worker 版的结构差异在于"淡出技巧"的时间化:退场透明度从 __T__ + __DUR__ * 0.03 开始、历时 __DUR__ * 0.47,即约在行程的 25–30% 处完成(对应 SKILL.md 规则"fade ≈ 0.18–0.3s vs motion 0.3–0.34s");入场侧从 opacity: 0.35 在中途"点燃"(mid-path ignition),而不是二进制的 0→1 跳变——二进制的 0→1 会闪。

两个工程性细节(均出自 SKILL.md 与 seam-craft):

  • 舞台地必须不透明#root 需要 background: var(--canvas-deep, var(--canvas, #000))。cut-the-curve 的"中段窗口"会打开一个两侧透明度之和 < 1 的窗口,若 #root 无底色,渲染器会把透明凹陷合成到默认白色页面之上——深色影片上每个切点都会白闪。
  • 同 track 的 wrapper 重叠是非法的(core/src/lint/rules/composition.ts 校验),所以注入器要做 0/1 track 乒乓重排;filter 属性在主时间轴上是 lint-clean 的(core/src/lint/rules/gsap.ts 的属性白名单只约束场景 worker,不约束 index.html)。

组合版:cut-the-curve + zoom

横向切割上叠加一个温和的 Z 分量。scale 分量同样服从 Z 符号规则:两侧都收缩(退场 1 → 0.92,入场 1.08 → 1)——一致的温和"拉"叠在横向切割上;不要在这里把收缩退场配从小生长入场。

// Scene A: hero slides left + mild pull + blur
tl.to(
  ".hero-a-wrapper",
  {
    x: -230,
    scale: 0.92,
    filter: "blur(8px)",
    duration: 0.33,
    ease: "power4.in",
  },
  CUT_TIME - 0.33,
);

// Cut + Scene B: continues leftward, arrives slightly oversized and retracts
tl.set(".hero-b-wrapper", { x: 230, scale: 1.08, filter: "blur(8px)" }, CUT_TIME);
tl.to(
  ".hero-b-wrapper",
  {
    x: 0,
    scale: 1,
    filter: "blur(0px)",
    duration: 0.42,
    ease: "power4.out",
  },
  CUT_TIME,
);

4. Waterfall Cut(逐词瀑布切割)

Cut the Curve 的词级(word-level)版本,是文本到文本 seam 最强的左向切法:出场词在各自的曲线上逐词退出,入场词在飞行中途级联点燃——一道眼睛可以沿 seam 骑过去的波。

作用域:worker 在单个多 beat 合成内手写(叠放的全帧 .beat 层),不是 registry/injector 类型——它 tween 的是词 span 而非 clip wrapper。进出文本 beat 块的边界仍然使用普通 registry 转场,且不计入 2–3 个转场的预算。

DOM + CSS

<div class="beat" id="b1"><div class="line">And until now</div></div>
<div class="beat" id="b2">
  <div class="line">
    <span class="w">that</span> <span class="w">changes</span> <span class="w">today.</span>
  </div>
</div>
.beat {
  position: absolute;
  inset: 0;
  display: grid;
  place-items: center;
  will-change: transform, opacity;
}
.w {
  display: inline-block;
  will-change: transform, opacity;
}

时间轴

// Pre-set at build time — immediateRender:false alone leaves un-started words visible.
gsap.set([...w1, ...w2], { x: 230, opacity: 0 });

function wordExit(words, C) {
  // C = cut time on the comp timeline
  let s = C - 0.32; // exits START before the cut
  words.forEach((el) => {
    tl.to(el, { x: -230, duration: 0.34, ease: "power4.in" }, s);
    tl.to(el, { opacity: 0, duration: 0.18, ease: "power1.in" }, s); // fade ends ~25-30% into travel
    s += 0.022; // reading-order stagger
  });
}

function wordEnter(words, C) {
  let off = 0,
    gap = 0.05;
  words.forEach((el) => {
    tl.fromTo(
      el,
      { x: 230, opacity: 0.35 }, // ignites MID-PATH, already moving
      { x: 0, opacity: 1, duration: 0.3, ease: "power4.out", immediateRender: false },
      C + off,
    );
    off += gap;
    gap *= 0.84; // shrinking gaps — the cascade accelerates
  });
}

const C = 2.3;
wordExit(w1, C);
tl.set(b1, { opacity: 0 }, C); // hard layer swap AT the cut
tl.set(b2, { opacity: 1 }, C);
wordEnter(w2, C);

关键机制:

  • 构建期预置:所有词在构建时 gsap.setx: 230, opacity: 0。只靠 immediateRender: false 会让未启动的词静止可见。
  • 退场先于切帧开始C - 0.32),逐词 stagger +0.022s 按阅读顺序——行是"剥落"而不是整块滑动;每个词的 fade 在行程 25–30% 处结束,词在到达切帧前已消失,不留拖影。
  • 入场中途点燃:从 opacity: 0.35 起、x: 230 处已经在运动中;间隔以 ×0.84 逐词衰减,级联自我加速,最终收敛到构图态。
  • 切帧处硬层交换tl.set(b1, {opacity:0}, C)tl.set(b2, {opacity:1}, C) 精确落在切帧。
  • 短的首 beat 可以整行退出:作为单一元素 x: -230, 0.34s, power4.in,opacity fade 几乎贯穿整个行程(在切帧前约 0.02s 结束)——下一波词点燃时它还在飞,没有死档。
  • 只动 transform/opacity(seek-safe),不透明舞台地规则同样适用。

参数速查(SKILL.md 表格):行程 ±230px(约 12% 画幅);退场 0.34s power4.in;退场 fade 0.18s 与 x 同时开始;退场 stagger 按阅读顺序 +0.022s;入场 0.3s power4.out;入场起始 opacity 0.35(中途点燃,二进 0→1 会闪);入场间隔 0.05s × 0.84 衰减(加速级联)。

5. Rack-Focus Blur-Cut(可见的切)

唯一"让切被看见"的变体:失焦模糊尖峰隐藏单帧硬交换,模拟手持 DSLR 跟焦。用于同一视觉主题内同一表面(same surface)的状态切换,作为偶发的花招(每约 8s 至多一次);永远不是默认边界。与其他变体的区别:出场侧保持完全不透明直到切帧(靠模糊隐藏交换,不做提前 fade),缓动用 power2.in / power2.out(柔和光学感,而非动量感)。

var T = /* transition start */;
// Phase 1: outgoing pans + blurs, held fully opaque
tl.to("#scene-out", { x: -80, scale: 1.06, filter: "blur(12px)", duration: 0.3, ease: "power2.in" }, T);
// Phase 2: hard cut at peak blur
tl.set("#scene-out", { opacity: 0 }, T + 0.3);
tl.fromTo("#scene-in",
  { opacity: 1, x: 80, scale: 1.06, filter: "blur(12px)" },
  { x: 0, scale: 1, filter: "blur(0px)", duration: 0.35, ease: "power2.out" },
  T + 0.3);

规则要点:

  • 切帧必须落在峰值模糊(≥6px;峰值 8–12px,最大 ≤16–18px)——在模糊上升途中交换会露出切。
  • 约 1.06 的微妙 scale("镜头呼吸感")让它读作光学现象。
  • 两侧同方向——矢量定律仍然成立;入场时长 ≥ 退场时长。
  • 模糊打在 wrapper 上;同一元素不要在一个 tween 里同时 blur + opacity(headless 合成 bug);不要直接 blur <video>(要包一层)。
  • 若做 Z dolly 变体,去掉 x 偏移,改用 scale 0.92 → / → 1.08

调参范围(Tuning ranges)

Zoom-Through / Inverse Zoom

参数 默认值 取值范围
退场 scale 1.2(前向)/ 0.8(反向) ±0.1
入场 scale 0.75(前向)/ 1.25(反向) ±0.1
切帧处模糊 文字 10px / 整帧 18–20px
切帧处透明度 0.15 0.1–0.2
退场时长 0.2s 0.15–0.3s
入场时长 0.5s 0.4–0.6s

Cut the Curve

参数 默认值 取值范围
行程 230px(约 12% 画幅) 150–300px
切帧处模糊 8px 6–10px
退场时长 0.33s 0.2–0.4s
入场时长 0.33–0.42s ≥ 退场

模糊量的依据(SKILL.md 的 Blur logic 表):文字级主体(标题、词组)峰值 10px——20px 会让字形糊成一片,切帧读起来像 glitch 而不是速度;整帧表面(窗口、卡片、截图)峰值 18–20px——大表面上过轻的模糊会读成渲染卡顿。交换帧上两侧取相同峰值模糊。

6. Waterfall Entry(场景内到达,非 seam)

逐元素"闪现 + 冲刺归位"的级联:每个元素先 tl.set(瞬时显现 + 偏移)再 tl.to(鞭打到静止)。排布公式:nextStart = prevStart + prevDuration − (overlapFrames × F);正 overlap 级联,负 overlap 刻意留空。CSS 上元素从 opacity: 0; display: inline-block 开始。用于标题卡、段落开场、列表/特性介绍,方向默认 Y(从下方来)。

var F = 1 / 60;
var t0 = 0.1;
// anchor (heaviest): biggest travel, longest settle
tl.set("#el-1", { opacity: 1, y: 80 }, t0);
tl.to("#el-1", { y: 0, duration: 0.18, ease: "power4.out" }, t0);
// normal word: 2 frames after the anchor finishes
var t1 = t0 + 0.18 + 2 * F;
tl.set("#el-2", { opacity: 1, y: 45 }, t1);
tl.to("#el-2", { y: 0, duration: 0.15, ease: "power4.out" }, t1);
// light word: 1 frame BEFORE the previous finishes (overlap)
var t3_placeholder = 0; // (illustrative)
var t2 = t1 + 0.15 - F;
tl.set("#el-3", { opacity: 1, y: 40 }, t2);
tl.to("#el-3", { y: 0, duration: 0.14, ease: "power4.out" }, t2);
// split final-word fragments: tightest overlap, extra travel (lighter)
var t3 = t2 + 0.14 - F;
tl.set("#frag-a", { opacity: 1, y: 70 }, t3);
tl.to("#frag-a", { y: 0, duration: 0.16, ease: "power4.out" }, t3);
var t4 = t3 + 0.14 - F;
tl.set("#frag-b", { opacity: 1, y: 70 }, t4);
tl.to("#frag-b", { y: 0, duration: 0.15, ease: "power4.out" }, t4);
// punctuation: lightest, fastest
var t5 = t4 + 0.13 - 2 * F;
tl.set("#dot", { opacity: 1, y: 48 }, t5);
tl.to("#dot", { y: 0, duration: 0.12, ease: "power4.out" }, t5);

(注:上面 var t3_placeholder 一行是排版占位,实际模板中不存在该行;原模板直接从 t2 推到 t3。)

编排规则(SKILL.md 表格):

参数 锚点/重元素 普通词 轻元素/标点
Y 偏移 60–80px 40–50px 30–48px
时长 0.16–0.20s 0.13–0.16s 0.10–0.13s
Overlap 0–2 帧留空 1 帧重叠 1–2 帧重叠
  • 重叠而非排队:下一元素在前一个落定的 ±2 帧内启动;间隔沿级联收缩;最后元素"啪"地落定。
  • 速度按重量分级:重/锚点元素行程更远、时长更长;轻词与标点快速闪现。
  • 缓动统一 power4.out(要更强 snap 用 expo.out);入场永远不要 .inOut
  • 每条级联一个方向;把最后一个词拆成碎片以延长高潮,碎片行程更远。
  • 与 §4 Waterfall Cut 的边界:§6 Entry 的 opacity 是 tl.set 二进 0→1(绝不 fade——seam 切才 fade,arrival 不 fade);§4 则在 0.35 处中途点燃。
  • 落定后整组通常会再滑开给下一个 beat 让位——那就是 §7 Nudge Curve。

7. Nudge Curve(场景内群组滑动,非 seam)

已构图群组(词行、卡片堆、列表)的"慢-快-慢"重定位,用于揭示内容或腾出空间。没有单一内置缓动能产出它——power4.inOut 会"啪"地刹停。在同一个属性上串联三个 tween:

阶段 缓动 距离占比 时间占比 感受
1 ramp-in power3.in ~10% ~20% 几乎不动——运动被感知但没有冲击
2 burst none(线性) ~65% ~18% 约 2 倍平均 px/帧——目的明确
3 tail power4.out ~25% ~62% 衰减蠕变到静止——消掉"啪"的刹车感

参考值:270px 左向滑动(总时长 0.57s)。其他行程按比例缩放距离,保持时间比;tail 时间 ≥ 3× ramp-in。

var t = /* start after content settles */;
tl.to(".text-row", { x: -30,  duration: 0.12, ease: "power3.in"  }, t);          // ramp-in: 11% dist / 21% time
tl.to(".text-row", { x: -210, duration: 0.10, ease: "none"       }, t + 0.12);   // burst:   67% dist / 18% time
tl.to(".text-row", { x: -270, duration: 0.35, ease: "power4.out" }, t + 0.22);   // tail:    22% dist / 61% time
// vertical: same ratios on y. 150px variant: -15 / -115 / -150 at the same times.

规则:

  • 若仍然"啪"地刹车:延长 tail 的时间(不是距离),或改用 power5.out
  • Phase 2 保持线性——给它加缓动会失去 burst 的对比。
  • 在 phase 2 期间揭示新内容——burst 会掩盖其出现。
  • 垂直方向同理;距离按比例缩放,时间比不变(150px 变体:同一时间点 -15 / -115 / -150)。

变体选择速查与工程验证

四/五种 seam 变体的选择矩阵(SKILL.md):

Zoom-Through Inverse Zoom Cut the Curve Waterfall Cut
作用域 场景内文本交换 到达/高潮 beat 场景之间 文本到文本 seam
Z 符号/轴 增长(push) 收缩(pull) X / Y X,逐词
行程/scale 1→1.2,然后 0.75→1 1→0.8,然后 1.25→1 ±230px ±230px
峰值模糊 文字 10px / 整帧 18–20px 同左 8–10px 可选
缓动 power3.in / expo.out power3.in / expo.out power4.in / power4.out power4.in / power4.out
感受 向前推进 抵达 被侧向带走 一道骑过 seam 的波

工程侧验证链:这些模板不是"凭感觉对",仓库配套了机器验证。motion-doctrine 技能 提供 seam-stamp.mjs + seam-gate.mjs 生成-校验对:项目根目录的 ledger.json 按行记录每个 seam 的 cut 时间、technique、exit/entry 的 axis 与 dir(z +1 = push,z −1 = pull);seam-gate.mjs verify 会用无头 Chrome 逐帧测量(基于 getBoundingClientRect,自动包含祖先 wrapper 变换),检查切帧两侧是否"一帧只见一侧"(zero-overlap)、实测速度是否匹配(speed-match)、入场场景内部入场是否对抗 Z 符号(z-sign-scan,对应 SKILL.md 的 Seam Gate rule 7)。probe 子命令可以在某切帧时刻附近发现 mover 元素,辅助填写 ledger。

此外,各生产型技能(如 product-launch-video、pr-to-video、faceless-explainer)各自 vendored 了一份 registry JSON,其中模板 token(__OLD__/__NEW__/__T__/__DUR__/__DX__/__DXIN__/__DY__/__DYIN__)与本文模板文档完全一致——registry 版的代码就是从这些模板注入的,而 worker 版的代码则由 worker 在单个 comp 内按参数表手写。更完整的转场总目录可参考 TRANSITION-REGISTRY

适用前提与限制:本文所有模板面向 1920×1080 / 30fps 级别的 HyperFrames 合成(__DX__/__DY__ 的 1920/1080 常数、12% 行程与 230px 默认值均以此为基准);Tier-B 转场的前提是纯 transform/opacity/filter 作用于两个 clip wrapper,不注入 overlay DOM;filter 在主时间轴可用但在单元素上与 opacity 同 tween 存在 headless 合成 bug(rack-focus 规则);不同分辨率下应按比例换算行程常数而非照抄 230px。

登录后查看全文
热门项目推荐
相关项目推荐