首页
/ OpenMontage HyperFrames 深度散点聚合动画规则:用确定性 3D 深度云实现元素重组入场

OpenMontage HyperFrames 深度散点聚合动画规则:用确定性 3D 深度云实现元素重组入场

2026-09-07 19:01:43作者:房伟宁

导读

本文面向在 OpenMontage 仓库中为 AI 视频合成 / Agent 工作流编写 HyperFrames 合成(composition)的开发者与智能体,系统性讲解 hyperframes-animation 技能库中的 depth-scatter-assemble 原子运动规则:N 个元素(字形、卡片、图标、Logo 碎片)从一圈缓慢旋转的 3D"深度云"中散落飞出,并精确落入一个干净的平面版式(或反向执行)。读完本文,你将掌握黄金角索引派生散点的完整数学原理、基于 GSAP 暂停时间轴的装配代码骨架、四种实战变体,以及如何将参数调优到与 HyperFrames 确定性渲染契约完全兼容,确保每一帧都可在任意时间点精确重放。

该规则文档位于 .agents/skills/hyperframes-animation/rules/depth-scatter-assemble.md,是 HyperFrames 动画技能中"布局与网络(Layout & Network)"分类下的一条原子配方,在 rules-index.md 中被登记为 3D 运动规则(tags:3d, scatter, assemble, tumble, depth, perspective, glyphs)。


一、规则定位:先弄懂它在何时被选中

1.1 视觉目标

depth-scatter-assemble 实现的是如下镜头语言:N 个元素从同一个绕 Y 轴缓慢转动的三维点云中飞向镜头并锁定成一个扁平的屏幕版式,或者反过来——已排好的版式解体回点云。每个元素都从由自身索引唯一确定的 3D 偏移量出发(translateZ 深度 + rotateX/rotateY 翻滚 + 由索引算出的 x/y 散点),随后过渡到装配完成的平面位置(z: 0, rotation: 0)。由于每个散点位置都是用三角学在元素索引上算出来的,而绝不使用 Math.random,因此每一帧都渲染得完全一致。

1.2 与相邻规则划清界限

hyperframes-animation 的技能路由表(SKILL.md)要求先按触发场景选规则。这条规则和三个"近亲"容易混淆,规则文档专门做了区分:

规则 关键词 差异点
depth-scatter-assemble 每个元素各自拥有三维点云中的一个位置 结局是一个扁平的装配版式,既不是轨道也不是放射喷散
orbit-3d-entry.md 翻转入场后进入连续椭圆轨道 元素翻入后停泊并沿椭圆持续公转,需要封顶 z-index
center-outward-expansion.md 同一个共享中心平面 2D 爆散 单中心辐射、无深度,属于平面 2D 近亲

实际编排中它们还共享同一套 perspective + preserve-3d 舞台搭建(见下文组合章节)。

1.3 它在 HyperFrames 合成体系中的位置

HyperFrames 的每个合成都是独立的 HTML 文件:根元素用 data-* 属性声明画布(data-width/data-height/data-duration),可见的定时子元素(clip)用 data-start/data-duration/data-track-index 声明时间窗,动画统一交给一条暂停的 GSAP 时间轴,并注册到 window.__timelines["<composition-id>"](见 .agents/skills/hyperframes-core/references/minimal-composition.mddata-attributes.md)。depth-scatter-assemble 提供的正是这样一个合规的"一个场景接一个场景"的时间轴配方,可直接嵌入蓝本(blueprint)使用。


二、工作原理:黄金角 + 索引派生散点 = 逐帧确定性

2.1 单段核心数学

每个元素最终都落在平面版式位置上(targetX/Y,在 CSS 或 data-* 中设定一次)。它的"散开"状态由索引 i 推导而来,核心推导式如下(节选自规则文档):

const GOLDEN = Math.PI * (3 - Math.sqrt(5)); // ~2.39943 rad — even angular spread, no clumping
const a = i * GOLDEN; // this element's angle in the cloud
const scatterX = Math.cos(a) * RADIUS; // index-derived, deterministic
const scatterY = Math.sin(a) * RADIUS;
const scatterZ = Z_NEAR - (i / (n - 1)) * (Z_NEAR - Z_FAR); // stepped depth across the cloud
const rotX = Math.sin(a) * TUMBLE; // tumble orientation, also from the angle
const rotY = Math.cos(a) * TUMBLE;

关键点逐一拆解:

  • 黄金角 GOLDEN ≈ 2.39943 rad(137.5°):这是"向日葵籽排列"式的角度。对索引 i 连续乘以黄金角,得到的角在圆周上均匀铺开、不会聚成一团(no clumping)——这是云团视觉均匀度的根本来源。
  • x/y 由角度经 cos/sin 得到:以 RADIUS 为半径把元素均匀撒在 x/y 平面上。
  • zi/(n-1) 做线性插值:索引靠前的靠近 Z_NEAR(近镜头),索引靠后的推向 Z_FAR(远镜头),形成一条深度带,视觉上呈现"由近及远纵深展开"。
  • 翻滚角 rotX/rotY 仍由同一个角度 a 驱动TUMBLE 给出峰值角度,sin/cos(a) 让每个碎片带着不同的姿态在空间里翻滚。

2.2 单一 progress 代理插值装配

规则文档规定,用一个 0→1 的 progress 代理,把每个元素从散开态插值到装配态(每个通道做 lerp):

  • progress = 0 → 元素组成 3D 深度云;
  • progress = 1 → 元素以平面姿态坐进版式。

正向播放即为"assemble(装配)";与此同时,舞台本身有一支缓慢的 rotateY tween,让云团在锁定前"先活起来",避免看起来像一张冻结的爆炸分解图。

2.3 关键的 3D 上下文要求

文档强调,必须有 perspective(设在场景根上),并且 transform-style: preserve-3d同时出现在舞台容器和每个元素上;否则 z 深度与翻滚会被压平为 2D 缩放效果,整个纵深叙事失效。这在第 3.3 节 CSS 中会看到具体写法。

源码佐证:这条"逐元素确定位置 + 单一进度代理 + 禁止随机"的要求,与 hyperframes-core 的确定性契约完全同构——.agents/skills/hyperframes-core/references/determinism-rules.md 明确指出渲染器"按时间值逐帧 seek、没有 playback 概念",任何依赖前一帧累计状态的视觉(时钟、随机、事件驱动动画)都会在乱序采样时失步;Math.random/Date.now 被明文禁用,随机外观若要实现须用带种子的 PRNG。depth-scatter-assemble 用"索引三角函数"这一确定性替代方案,从根上规避了该问题。


三、标准骨架:HTML + CSS + GSAP Timeline

下文三层代码来自规则文档,是可直接套用的最小实现。为便于讨论,文中用到了几个命名常量(RADIUSZ_NEARZ_FARTUMBLEASSEMBLE_DURASSEMBLE_EASESTAGGERCLOUD_SPIN_DEGCLOUD_SPIN_DUR),取值建议见第四章参数表。

3.1 HTML:舞台 + 目标位声明

<div
  class="scene"
  id="assemble-scene"
  data-composition-id="assemble-scene"
  data-start="0"
  data-duration="4"
  data-track-index="0"
>
  <!-- The cloud rotates; the layout lives inside it. targetX/Y = each
       element's FLAT assembled offset from stage center (px). -->
  <div class="cloud-stage">
    <div class="frag" data-target-x="-260" data-target-y="0">{glyph1}</div>
    <div class="frag" data-target-x="-130" data-target-y="0">{glyph2}</div>
    <div class="frag" data-target-x="0" data-target-y="0">{glyph3}</div>
    <div class="frag" data-target-x="130" data-target-y="0">{glyph4}</div>
    <div class="frag" data-target-x="260" data-target-y="0">{glyph5}</div>
  </div>
</div>

解读与 HyperFrames 契约对照:

  • data-target-x/y 是"平面装配偏移":以舞台中心为原点(px)。示例给 5 个字形分别赋 -260 / -130 / 0 / 130 / 260,装配后就是一条水平五连排。
  • .scene 根节点即 composition 根:在 HyperFrames 中需配合 data-width/data-height 定义画布像素尺寸(常见 1920x10801080x1920),data-duration渲染时长(这里是 4 秒),data-composition-id 必须与时间轴注册键一致(见第 3.4 节)。clip 的 data-start/data-track-index 决定它在时间轴上的归属轨道。
  • 使用场景映射:做 Logo lockup 时,targetX/Y 描述各部分静止后的版式;做 kinetic type 时,一个 .frag 对应一个字(见第 5.1 节,setup 阶段从字符串注入 span 以保证宽度精确)。

3.2 CSS:perspective 与 preserve-3d 缺一不可

.scene {
  position: relative;
  width: 100%;
  height: 100%;
  display: grid;
  place-items: center;
  background: {bgColor};
  perspective: 1400px; /* REQUIRED — without it, z-depth + tumble read as flat 2D scale */
}
.cloud-stage {
  position: relative;
  width: 100%;
  height: 100%;
  display: grid;
  place-items: center;
  transform-style: preserve-3d; /* REQUIRED — preserves child 3D context */
  will-change: transform;
}
.frag {
  position: absolute;
  /* Live at stage center; GSAP translates each one to its layout / cloud point. */
  top: 50%;
  left: 50%;
  display: grid;
  place-items: center;
  font-family: {font};
  font-weight: 900;
  font-size: 120px;
  color: {textColor};
  transform-style: preserve-3d; /* each fragment keeps its own 3D context */
  backface-visibility: hidden; /* hides the mirrored face mid-tumble */
  will-change: transform, opacity;
}

三层结构的职责:

  1. .sceneperspective: 1400px 定义观者的视锥——深度越大,z 位移带来的"飞向镜头/远离镜头"越明显。若省略,全部 3D 退化为平面 2D 缩放。
  2. .cloud-stagepreserve-3d 让内部子元素保留三维上下文,从而得以"同住一个三维云团";will-change: transform 给合成器提示。CSS 变量占位符 {bgColor}{font}{textColor} 在 HyperFrames 里由样式体系/变量机制注入(对应 hyperframes-core 的 variables-and-media 机制 所定义的变量声明方式)。
  3. .frag:每个碎片 top/left: 50% 停在舞台中心,真正的位移完全交给 GSAP 的 x/y/z 变换;transform-style: preserve-3d 维持其独立 3D 上下文;backface-visibility: hidden 在翻转中途隐藏镜像面(对带单面内容的卡片尤其重要)。

3.3 GSAP 时间轴:先 gsap.set 停泊,再逐元素装配

<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 });

  const frags = Array.from(document.querySelectorAll(".frag"));
  const n = frags.length;
  const GOLDEN = Math.PI * (3 - Math.sqrt(5)); // ~2.39943 — even spread, no clumps

  // RADIUS, Z_NEAR, Z_FAR, TUMBLE, ASSEMBLE_DUR, ASSEMBLE_EASE, STAGGER,
  // CLOUD_SPIN_DEG, CLOUD_SPIN_DUR — named constants per "How to Choose Values".

  // Precompute each fragment's deterministic scattered state from its index.
  const scatter = frags.map((el, i) => {
    const a = i * GOLDEN;
    const depthT = n > 1 ? i / (n - 1) : 0;
    return {
      x: Math.cos(a) * RADIUS,
      y: Math.sin(a) * RADIUS,
      z: Z_NEAR - depthT * (Z_NEAR - Z_FAR),
      rotationX: Math.sin(a) * TUMBLE,
      rotationY: Math.cos(a) * TUMBLE,
    };
  });

  // 1) Park every fragment in the cloud BEFORE any tween fires.
  frags.forEach((el, i) => {
    const s = scatter[i];
    gsap.set(el, {
      xPercent: -50,
      yPercent: -50, // bake self-centering so x/y are offsets from stage center
      x: s.x,
      y: s.y,
      z: s.z,
      rotationX: s.rotationX,
      rotationY: s.rotationY,
      opacity: 0,
    });
  });

  // 2) The cloud rotates so the scatter has life before / during assembly.
  tl.to(
    ".cloud-stage",
    { rotationY: CLOUD_SPIN_DEG, duration: CLOUD_SPIN_DUR, ease: "power1.out" },
    0,
  );

  // 3) ASSEMBLE — each fragment tweens from its cloud point to its flat target.
  frags.forEach((el, i) => {
    tl.to(
      el,
      {
        x: Number(el.dataset.targetX),
        y: Number(el.dataset.targetY),
        z: 0,
        rotationX: 0,
        rotationY: 0,
        opacity: 1,
        duration: ASSEMBLE_DUR,
        ease: ASSEMBLE_EASE, // out-ease — fragments fly in then settle
      },
      i * STAGGER, // index stagger reads as "cloud collapsing inward"
    );
  });

  window.__timelines["assemble-scene"] = tl;
</script>

这个代码骨架暗含了 HyperFrames 渲染正确性的五个关键约定(与 determinism-rules.md 完全对齐):

  1. 时间轴在页面初始化时同步创建,且必须 paused: true——渲染器是"逐帧 seek"而非播放,任何 tl.play()、在 async/Promise/setTimeout 里建时间轴都会导致采样器先于时间轴就绪而失步。
  2. gsap.set 必须在加 tween 之前先把每个碎片停泊在散点位置、opacity: 0——否则第 0 帧显示的是"已装配"的版式,随后第一个 tween 触发时元素会发生一次瞬移跳变(teleport)。
  3. 装配 tween 必须 FROM 散点 TO 目标x/y 来自 data-target-x/yz/rotationX/rotationY 全部归零,opacity 翻转为 1——结局"躺平"是这条规则的灵魂(详见第 6 节原则)。
  4. xPercent/yPercent: -50 自居中烘焙:CSS 中元素 top/left: 50%,再用 -50% 平移把几何中心对准舞台中心,此后 GSAP 的 x/y 才真正表达"相对舞台中心的偏移"。这正是 HyperFrames 布局契约推荐的方式——只用 x/y/scale/rotation 等 transform 别名做运动,严禁 tween width/height/left/top(见 .agents/skills/hyperframes-animation/SKILL.md 的 Animation-craft 要求)。
  5. window.__timelines["assemble-scene"] = tl:注册键必须与 HTML 根上的 data-composition-id="assemble-scene" 精确一致,否则 HyperFrames 运行时找不到该场景的时间轴。

3.4 时间轴三阶段的编排语义

时间轴里其实只有三件事,被刻意做成了"可预见"的有限运动:

阶段 内容 目的
预停泊(同步 gsap.set 全部碎片按 scatter[i] 落到 3D 云、透明度 0 保证第 0 帧即呈云团,杜绝瞬移
舞台旋转(tl.to 到 0 时刻) .cloud-stagerotationY 从 0 → CLOUD_SPIN_DEG 云团先"活"起来,赋予纵深生命感
装配(逐元素插入) 每个 .frag 从散点 tween 到 targetX/Yz:0rotation:0opacity:1,起始时间按 i * STAGGER 索引错峰让视觉呈现"云团向内坍缩"

注意 gsap.set 只是停泊而非动画,所以它不会触发"逐帧累计"问题;舞台旋转和装配都是有限、一次性、在 settle 之前结束的 tween,与 data-duration 时长窗口严格匹配。


四、参数选择指南:九个旋钮的取值表

规则文档提供了详尽的调参指导,本节将其整理为可对照的参数表。所有值都从"运动读感 + 确定性约束"两个维度给出建议:

4.1 元素数与空间尺度

参数 推荐范围 视觉/运动效果 约束(超出即出问题)
n(元素数量) 4–14(字形组随词长走;碎片/卡片建议 4–9) 少=克制有序的组装;多=密集"蜂群"逐渐凝结 超过约 14 个,云团拥挤到中心、单一路径不再可读
RADIUS(x/y 平面散点半径,px) 250–700 px 小=几乎不分层的紧结;大=碎片从画面边缘抵达 以所设 perspective 为准,最远散点必须仍在画面内,否则元素从画面外"凭空蹦出",没有飞行过程可读
Z_NEAR / Z_FAR(云的深度带,px,前/后) Z_NEAR +150~+450;Z_FAR −150~−500 宽带(如 +400/−400)=强烈的"向镜头飞来/后退远去"纵深;窄带≈近平铺 |z| 过大而 perspective 过短时过度畸变(碎片先巨大后微小)——应同步加大 perspective
TUMBLE(散点碎片的峰值 rotateX/Y,deg) 40–110° 低=近乎直立飘入;高=空间翻滚、落位时转正 启用 backface-visibility: hidden 时超过 90° 会出现中段空白(翻滚需要这种效果);单面内容的卡片建议上限约 80°

4.2 装配节奏

参数 推荐范围 视觉/运动效果 约束
ASSEMBLE_DUR(单碎片 云→版式 时长,s) 0.7–1.4 s 短=利落锁定;长=漂浮式凝结 需满足 (n−1)×STAGGER + ASSEMBLE_DUR 落在场景装配窗口内
ASSEMBLE_EASE(共享缓动) 枚举:power3.outexpo.outback.out(1.4) 默认 power3.out(飞入、沉降);expo.out 结尾猛然锁死;back.out 带小幅过冲"坐实" 禁止 in 系缓动——碎片会在空中像被吸回云团
STAGGER(相邻碎片装配启动间隔,s) 0.03–0.09 s <0.03=整团一声和弦同时坍缩;>0.09=慢滴落,失去"蜂群"感 要求 n×STAGGER 小于 ASSEMBLE_DUR,让云团是"一个整体在坍缩"而不是排队
CLOUD_SPIN_DEG / CLOUD_SPIN_DUR(舞台旋转量/时长) 15–60°,时长 ≥ ASSEMBLE_DUR 轻微自转让散点有生命力,不像冻结的爆炸示意图;过快会与装配抢戏 必须有限、且于 settle 前结束——禁止 repeat

4.3 切换变体的专有参数

参数 推荐范围 视觉/运动效果 约束
SWAP_DUR / SWAP_AT(tumble-swap 交接时长/触发时刻) SWAP_DUR 0.5–1.0 s;SWAP_AT 落在节拍边界 短=利落交叉;长=可见的"穿过云团溶解" 出组与入组必须共享同一个 progress(同一支 tween),保证在同一瞬交叉

五、四种变体:从逐字交接延展到 Logo 视差

5.1 Tumble-swap:两句话之间的 3D 空中交接

kinetic-type-beats 蓝本中最具标志性的用法(见 blueprints/kinetic-type-beats.md3D letter-tumble scatter-into-depth-cloud then reassemble 词条):上一句的字形在同一刻散入云团,下一句的字形散出云团——两个状态之间是 3D 交接,绝无空帧。规则文档要求两组字形共享同一片云,且必须用同一个共享 0→1 progress 驱动二者,保证确定性交叉:

// outgoing[] and incoming[] are two glyph arrays, each with precomputed scatter[] (above).
const swap = { p: 0 };
tl.to(
  swap,
  {
    p: 1,
    duration: SWAP_DUR,
    ease: "power2.inOut",
    onUpdate: () => {
      const p = swap.p;
      outgoing.forEach((el, i) => {
        // 1 → 0: layout → cloud (scatters AWAY)
        const s = outScatter[i];
        const tx = Number(el.dataset.targetX);
        const ty = Number(el.dataset.targetY);
        el.style.opacity = String(1 - p);
        el.style.transform =
          `translate(-50%,-50%) translate3d(${tx + (s.x - tx) * p}px,${ty + (s.y - ty) * p}px,${s.z * p}px)` +
          ` rotateX(${s.rotationX * p}deg) rotateY(${s.rotationY * p}deg)`;
      });
      incoming.forEach((el, i) => {
        // 0 → 1: cloud → layout (assembles IN)
        const s = inScatter[i];
        const tx = Number(el.dataset.targetX);
        const ty = Number(el.dataset.targetY);
        el.style.opacity = String(p);
        el.style.transform =
          `translate(-50%,-50%) translate3d(${s.x + (tx - s.x) * p}px,${s.y + (ty - s.y) * p}px,${s.z * (1 - p)}px)` +
          ` rotateX(${s.rotationX * (1 - p)}deg) rotateY(${s.rotationY * (1 - p)}deg)`;
      });
    },
  },
  SWAP_AT,
);

工程要点:

  • onUpdate 中通过内联 transform 直接写每帧状态(translate3d + rotateX/Y),因为两组元素方向相反(出组 p 递增时从版式走向散点、入组相反),无法用同一支 tl.to 表达——这正是 hyperframes-animation 技能中 timeline + onUpdate API 的典型运用。
  • 每个字形的 span 需要在 setup 阶段注入,data-target-x精确排版进深(advance width)——务必在 document.fonts.ready 之后再测量。
  • 各句集合的 opacity 在其时间窗到来之前保持为 0。

为什么不能拆成两支独立 tween? 规则文档给出的理由很硬核:两支 tween 在 seek 下可能相位漂移,交叉就不再是"一次交接"。这与 HyperFrames 的确定性 seek 渲染模型(determinism-rules.md:"同一时刻多时间轴驱动同一属性时 GSAP overwrite 行为与顺序相关,可能随渲染翻转")是同一类陷阱,统一规避。

5.2 径向字母爆散 → 复位(radial letter-explode → resolve)

kinetic-type-beats 蓝本中的 letters explode radially then resolve GAP 变体(Problem 场景的"字母径向爆开再复原"):

  • Z_NEAR = Z_FAR = 0TUMBLE 调小,让云退化为一个 2D 圆环
  • 然后反向执行装配即可得到"explode":碎片飞向 scatter[i](爆散到环上),再弹回版式。
  • 纯平面、无纵深,是这条 3D 规则的一个平面特例(kinetic-type-beats 规则映射第 70 行明确标注径向爆散属 depth-scatter-assemble 管辖范围)。

5.3 Scatter-OUT:只许作为收尾最后一拍

把装配反向(版式 → 云、透明度 1→0),仅限作为该合成最后一个节拍(final-frame exit)。规则文档给出明确告诫:镜头中途的 scatter-out 会被读成"镜头结束"并打断整个镜头。因此:

  • 入场(entrance)→ 正向 assemble;
  • 节拍切换(beat change)→ tumble-swap;
  • scatter-out → 只保留给最后一帧退场。

5.4 视差深度滑入(Logo lockup 专用)

logo-assemble-lockup 蓝本要求"后层形状以不同纵深滑入锁屏"(见 blueprints/logo-assemble-lockup.mdparallax shape slide-in 词条与 CTA push 变体的 solid mark-shapes parallax-sliding in behind)。参数化方法:

  • 后层给更大的 |Z_FAR|更长的 ASSEMBLE_DUR
  • 前景给更浅的深度与更短的时长
  • 于是不同深度的部件以不同表观速度滑入(视差),最终锁入 lockup。

示例佐证:仓库中 examples/brand-reveal-assemble-zoom.html(assemble-zoom 品牌揭示)与 examples/problem-mockup-overwhelm.html 都使用了 assemble/scatter 相关的 3D 运动词汇,可作为阅读该规则后对照真实可运行示例的入口。


六、关键原则:判断"做得对不对"的七条标尺

规则文档沉淀出以下原则,几乎每条都对应一个可验证的代码事实:

  1. 三层 3D 上下文缺一不可——perspective 在场景根、preserve-3d 在舞台和每个碎片。少任何一层,z 深度与翻滚都会塌缩成平面缩放。
  2. 每个散点值都由索引派生——cos/sin(i × GOLDEN) 均匀铺角不聚团,zi/(n−1) 步进。关键:绝无 Math.random,云团每次渲染字节级一致。
  3. tween 前必须 gsap.set 停泊——先把每个碎片放到散点处且 opacity: 0,装配 tween 才"从那里出发"。漏掉 set,第 0 帧就会先显示已装配版式、然后首帧 tween 触发时元素瞬移。
  4. 结局必须躺平(resolve flat)——settle 态是 z: 0, rotationX: 0, rotationY: 0,落在版式内。仍旧倾斜的云会被读成"没做完"。
  5. 只有 assemble / 交接,scatter-out 是退场——碎片中途离场读作镜头结束。入场用正向 assemble,节拍切换用 tumble-swap,scatter-out 留给最后一帧。
  6. 深度排序自动发生——在 preserve-3d 内,绘制顺序按真实 Z 坐标走,近碎片自动遮挡远碎片,无需手动 z-index(与 orbit-3d-entry 的 2D 假轨道需要封顶 z-index 的情况正好相反)。
  7. 云团自转要有、且有限——给散点生命力但不抢戏,单次结束于 settle 前。

七、关键约束:踩到即渲染翻车

规则文档列出的硬性约束,多数直接继承自 hyperframes-core 的非协商规则(见 .agents/skills/hyperframes-core/references/determinism-rules.md 的 Non-Negotiable Rules),在此与动画细节合并陈述:

  • Math.random / Date.now:所有散点坐标必须由索引(黄金角三角 + 步进深度)推导——这正是这条规则存在的全部意义:随机云每帧渲染都不同,seek 会失效。
  • 禁 CSS transition:所有运动都走暂停时间轴上的 GSAP tween,因为 CSS transition 无法从任意 seek 起点正确初始化。
  • repeat / yoyo / infinite:云团自转与每次装配都是有限、一次性 tween,且必须于 settle 前结束。
  • 时间轴必须暂停gsap.timeline({ paused: true })
  • 注册键 = data-composition-id:二者不一致即运行时找不到时间轴。
  • 只用变换别名xyzscalerotation/rotationX/rotationY永不用 width/height/left/topx/y 通过 xPercent/yPercent: -50 自居中组合。
  • will-change: transform 打在舞台和碎片上——大量并发的 3D transform 需要合成器提示(SKILL.md 的 performance 原则)。
  • tumble-swap 两组字形必须共享一个 progress:拆两支 tween 会在 seek 下相位漂移,交接便不再像一次交接。

八、在蓝本与运行示例中的真实用法

8.1 蓝本映射一览

depth-scatter-assemble 不是孤立配方,hyperframes-animation 的多个场景蓝本把它列为指定实现:

蓝本 引用位置与运动描述 仓库路径
kinetic-type-beats 3D 字母翻滚:字形散入旋转深度云再聚成下一句;也可混搭 3d-text-depth-layers(挤出效果)或 hacker-flip-3d(就地逐字翻转解码);Problem 场景的径向爆散同理 blueprints/kinetic-type-beats.md
logo-assemble-lockup 锁屏背后的视差形状滑入(不同纵深不同速度),可配合 3d-text-depth-layers blueprints/logo-assemble-lockup.md
cursor-ui-demo 3D 容器/物体的飞入与翻滚沉降(区别于只做平面元素公转的 orbit-3d-entry blueprints/cursor-ui-demo.md

由此可以形成两种创作路径(对应 SKILL.md 的选择策略):默认组合原子规则(每次从 rules 挑 2–4 条、用一条暂停 GSAP 时间轴粘合),或加载蓝本(场景已匹配既有多阶段模板,复用其阶段管线更快)。当角色镜头需要"逐字打拍子 + 每拍独立入场动作"或"品牌锁屏建组"时,depth-scatter-assemble 就是该组合中的 3D 引擎。

8.2 用 CLI 验证正确性

运动密集的合成,最好在 preview/render 之前跑完 HyperFrames CLI 的正确性管线(详见 .agents/skills/hyperframes-cli/references/lint-validate-inspect.md):

npx hyperframes lint                  # 静态:缺 data-composition-id、同轨重叠、未注册时间轴
npx hyperframes validate              # 无头 Chrome 运行态:控制台报错/失败请求/WCAG 对比度
npx hyperframes inspect               # 布局扫描:文本越界、被裁、出画布、子元素逃出裁剪容器
npx hyperframes snapshot --frames 10  # 取 10 张均匀分布 PNG 目检

针对本规则的调试建议:

  • 对散点云执行 snapshot:在时间轴有意义的状态点(云团成形、旋转中段、装配完成)截图并查看 PNG——如果第 0 帧已见"装配态",说明漏了 gsap.set 预停泊。
  • *.motion.json 边车做运动意图断言:把"元素应在 ≤0.5s 出现""卡片不得离画布""场景内不得静止超过 2s"写成断言交给 inspect 自动执行,比肉眼盯 MP4 更接近"渲染 ≠ 预览"缺陷(如 seek 越过的入场揭示、错乱的 stagger 顺序、中段漂移出画、冻结镜头):
{
  "duration": 6,
  "assertions": [
    { "kind": "appearsBy", "selector": "#assemble-scene .frag", "bySec": 1.2 },
    { "kind": "staysInFrame", "selector": ".cloud-stage" },
    { "kind": "keepsMoving", "withinSelector": ".scene" }
  ]
}
  • 若某层有意在入场瞬时溢出画布,用 data-layout-allow-overflow(窄范围标注)替代放大字体之类无效收敛手段——inspect 测量的是采样时刻的 getBoundingClientRect 联合盒,CSS overflow: hidden 并不会抑制它的溢出报告。

九、组合参考:同镜头叠加的相邻规则

规则文档为同一场景的"叠加式增强"提供了直接指针(内部相对链接已转换为仓库根路径):

  • orbit-3d-entry.md —— 另一种 3D 入场(落入连续轨道而非扁平 lockup);与本规则共享 perspective + preserve-3d 舞台。
  • hacker-flip-3d.md —— 碎片落座时叠加逐字 3D 翻转/解码,得到"字滚进来并在抵达瞬间解码"的读感。
  • 3d-text-depth-layers.md —— 装配锁死后,给完成的 wordmark 加一层堆叠挤出。
  • center-outward-expansion.md —— 不需要透视时的平面 2D 近亲(单一共享中心、无深度)。
  • press-release-spring.md —— 云团解析后在装配 lockup 上加一次弹簧沉降。
  • sine-wave-loop.md —— 解析后版式上的空闲呼吸,避免死寂定格。

组合时遵守 hyperframes-core 的编排纪律:每个属性在同一时刻只能被一条时间轴驱动;所有实例在各自运行时全局上注册,HyperFrames 一次 seek 全部驱动(见 SKILL.md)。


十、结语:一条规则背后的系统哲学

depth-scatter-assemble 表面上是一个 3D 散点/装配动画配方,实则是 HyperFrames"运动即数据、每帧可重现"设计哲学的浓缩体现:用黄金角取代随机数、用索引取代状态、用单一暂停时间轴取代播放器心智模型。在 OpenMontage 面向 AI 编码助手的技能体系里,它作为原子规则与 rules-index.md、蓝本目录与 CLI 校验管线共同构成"可组合、可验证、可重现"的运动创作闭环——这也正是把 AI 助手训练成完整视频制作工作室(agentic video production)所需的一砖一瓦。落地时,建议按此顺序自查:先确认三层 3D 上下文齐全、再确认 gsap.set 先于 tween 停泊、最后用 lint → validate → inspect → snapshot 走完正确性管线,即可在确定性渲染契约下放心产出"字母翻滚入位、Logo 锁屏成组"等高质量镜头。

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

项目优选

收起
kernelkernel
deepin linux kernel
C
33
18
ops-transformerops-transformer
本项目是CANN提供的transformer类大模型算子库,实现网络在NPU上加速计算。
C++
1.14 K
2.76 K
pytorchpytorch
作为 Ascend for PyTorch 社区的核心组件,TorchNPU 是昇腾专为 PyTorch 打造的深度学习适配插件,使 PyTorch 框架能够直接调用昇腾 NPU,为开发者提供昇腾 AI 处理器的超强算力。
Python
858
1.35 K
docsdocs
暂无描述
Markdown
899
5.82 K
ops-nnops-nn
本项目是CANN提供的神经网络类计算算子库,实现网络在NPU上加速计算。
C++
923
1.85 K
jiuwenswarmjiuwenswarm
JiuwenSwarm 是一款基于openJiuwen开发的智能AI Agent,它能够将大语言模型的强大能力,通过你日常使用的各类通讯应用,直接延伸至你的指尖。
Python
3.83 K
1.02 K
kernelkernel
openEuler内核是openEuler操作系统的核心,既是系统性能与稳定性的基石,也是连接处理器、设备与服务的桥梁。
C
532
596
cann-learning-hubcann-learning-hub
CANN 学习中心仓,支持在线互动运行、边学边练,提供教程、示例与优化方案,一站式助力昇腾开发者快速上手。
Jupyter Notebook
1.03 K
524
ops-mathops-math
本项目是CANN提供的数学类基础计算算子库,实现网络在NPU上加速计算。
C++
1.37 K
1.46 K
AscendNPU-IRAscendNPU-IR
AscendNPU-IR是基于MLIR(Multi-Level Intermediate Representation)构建的,面向昇腾亲和算子编译时使用的中间表示,提供昇腾完备表达能力,通过编译优化提升昇腾AI处理器计算效率,支持通过生态框架使能昇腾AI处理器与深度调优
C++
548
393