OpenMontage HyperFrames 深度散点聚合动画规则:用确定性 3D 深度云实现元素重组入场
导读
本文面向在 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.md 与 data-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 平面上。z用i/(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
下文三层代码来自规则文档,是可直接套用的最小实现。为便于讨论,文中用到了几个命名常量(RADIUS、Z_NEAR、Z_FAR、TUMBLE、ASSEMBLE_DUR、ASSEMBLE_EASE、STAGGER、CLOUD_SPIN_DEG、CLOUD_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定义画布像素尺寸(常见1920x1080、1080x1920),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;
}
三层结构的职责:
.scene:perspective: 1400px定义观者的视锥——深度越大,z 位移带来的"飞向镜头/远离镜头"越明显。若省略,全部 3D 退化为平面 2D 缩放。.cloud-stage:preserve-3d让内部子元素保留三维上下文,从而得以"同住一个三维云团";will-change: transform给合成器提示。CSS 变量占位符{bgColor}、{font}、{textColor}在 HyperFrames 里由样式体系/变量机制注入(对应 hyperframes-core 的 variables-and-media 机制 所定义的变量声明方式)。.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 完全对齐):
- 时间轴在页面初始化时同步创建,且必须
paused: true——渲染器是"逐帧 seek"而非播放,任何tl.play()、在async/Promise/setTimeout里建时间轴都会导致采样器先于时间轴就绪而失步。 gsap.set必须在加 tween 之前先把每个碎片停泊在散点位置、opacity: 0——否则第 0 帧显示的是"已装配"的版式,随后第一个 tween 触发时元素会发生一次瞬移跳变(teleport)。- 装配 tween 必须 FROM 散点 TO 目标:
x/y来自data-target-x/y,z/rotationX/rotationY全部归零,opacity翻转为 1——结局"躺平"是这条规则的灵魂(详见第 6 节原则)。 xPercent/yPercent: -50自居中烘焙:CSS 中元素top/left: 50%,再用 -50% 平移把几何中心对准舞台中心,此后 GSAP 的x/y才真正表达"相对舞台中心的偏移"。这正是 HyperFrames 布局契约推荐的方式——只用x/y/scale/rotation等 transform 别名做运动,严禁 tweenwidth/height/left/top(见 .agents/skills/hyperframes-animation/SKILL.md 的 Animation-craft 要求)。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-stage 的 rotationY 从 0 → CLOUD_SPIN_DEG |
云团先"活"起来,赋予纵深生命感 |
| 装配(逐元素插入) | 每个 .frag 从散点 tween 到 targetX/Y、z:0、rotation:0、opacity: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.out、expo.out、back.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.md 中 3D 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 +onUpdateAPI 的典型运用。- 每个字形的 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 = 0、TUMBLE调小,让云退化为一个 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.md 的 parallax 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 运动词汇,可作为阅读该规则后对照真实可运行示例的入口。
六、关键原则:判断"做得对不对"的七条标尺
规则文档沉淀出以下原则,几乎每条都对应一个可验证的代码事实:
- 三层 3D 上下文缺一不可——
perspective在场景根、preserve-3d在舞台和每个碎片。少任何一层,z 深度与翻滚都会塌缩成平面缩放。 - 每个散点值都由索引派生——
cos/sin(i × GOLDEN)均匀铺角不聚团,z按i/(n−1)步进。关键:绝无Math.random,云团每次渲染字节级一致。 - tween 前必须
gsap.set停泊——先把每个碎片放到散点处且opacity: 0,装配 tween 才"从那里出发"。漏掉 set,第 0 帧就会先显示已装配版式、然后首帧 tween 触发时元素瞬移。 - 结局必须躺平(resolve flat)——settle 态是
z: 0, rotationX: 0, rotationY: 0,落在版式内。仍旧倾斜的云会被读成"没做完"。 - 只有 assemble / 交接,scatter-out 是退场——碎片中途离场读作镜头结束。入场用正向 assemble,节拍切换用 tumble-swap,scatter-out 留给最后一帧。
- 深度排序自动发生——在
preserve-3d内,绘制顺序按真实 Z 坐标走,近碎片自动遮挡远碎片,无需手动 z-index(与 orbit-3d-entry 的 2D 假轨道需要封顶 z-index 的情况正好相反)。 - 云团自转要有、且有限——给散点生命力但不抢戏,单次结束于 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:二者不一致即运行时找不到时间轴。 - 只用变换别名:
x、y、z、scale、rotation/rotationX/rotationY。永不用width/height/left/top;x/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联合盒,CSSoverflow: 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 锁屏成组"等高质量镜头。
atomcodeClaude Code 的开源替代方案。连接任意大模型,编辑代码,运行命令,自动验证 — 全自动执行。用 Rust 构建,极致性能。 | An open-source alternative to Claude Code. Connect any LLM, edit code, run commands, and verify changes — autonomously. Built in Rust for speed. Get StartedRust0631
MiniCPM5-2BMiniCPM5-2B 是一款面向端侧、本地部署和资源受限场景的 2B 稠密 Transformer,能够达到同尺寸开源模型 SOTA 水平。Markdown00
GLM-5.3GLM-5.3 与 GLM-5.2 使用相同的基座模型——所有提升均来自后训练。与 GLM-5.2 相比,它在复杂编程和长程任务上的表现显著提升。Jinja00
HivisionIDPhotos⚡️HivisionIDPhotos: a lightweight and efficient AI ID photos tools. 一个轻量级的AI证件照制作算法。Python09
DragonOSDragonOS is an operating system developed from scratch using Rust, with Linux compatibility. It is designed for **Serverless** scenarios. 使用Rust从0自研内核,具有Linux兼容性的操作系统,面向云计算Serverless场景而设计。Rust00
Spark-X2.5-1.7BSpark-X2.5-1.7B 旨在让强大的 AI 更加实用、高效且易于获取。这些模型在广泛的日常任务中表现出色,涵盖对话、写作、翻译、推理、编程、工具调用和智能体工作流,并在同等规模的开源模型中取得领先结果。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00