OpenMontage 运镜蓝图深度拆解:spatial-pan-stations 空间平移站点动画
本文是 OpenMontage 仓库中 spatial-pan-stations 蓝图 的技术解读与实战指南。该蓝图属于
hyperframes-animation技能包的 15 个"经生产验证"的时间编码镜头模板之一,面向 Hook(开头钩子)与 Problem(痛点渲染)两类故事板帧,用"一张超大画布预置多个标注站点 + 单台虚拟相机反复平移"的方式,在 7–10 秒内完成里程碑时间线、痛点网络的叙事推进。读完本文,你将掌握该蓝图的完整镜头结构、两种变体的差异、其与viewport-change/multi-phase-camera/coordinate-target-zoom等原子规则的映射原理,以及如何在 HyperFrames 组合中落地实现。
蓝图是什么:从一份时间编码镜头模板说起
在 OpenMontage 的 hyperframes-animation 技能体系中,动画知识被划分为四层:rules(原子级动作配方)、blueprints(多阶段场景模板)、transitions(场景间过渡)与 adapters(各运行时 API),详见 SKILL.md。其中 blueprints-index.md 对 blueprint 的定义是:
一个与产品无关的、带时间码的镜头模板——
Scene N (a–b s): …,内含[slots]占位与一个具名的 signature move(标志性动作),由 50 段黄金产品发布短片逆向工程而来。它编码了一整段镜头的完整时长——揭示节奏配合台词推进,而不是在 t=0 一次性倾倒。
spatial-pan-stations 就是这 15 个蓝图之一。它的 intent(意图)可以浓缩为一句话:
在一张超大画布上预置一排带标签的"站点",然后用一台虚拟摄像机去"遍历"它——通过反复的横向/斜向平移把每个站点逐一居中,并在每次停靠时揭示一个 callout,最后停在某个最终站点上并保持住。
这个蓝图之所以有独特价值,在于它把 "空间性" 当作了叙事手段:站点不是被逐个 fade-in 出来的,而是预先存在于一个更大的世界坐标系中,靠镜头的移动把它们"滑入"取景框。这模拟了真实纪录片的运镜逻辑——先有一张完整的地图,镜头决定观众先看哪里、后看哪里。
服务哪些故事板角色
从 blueprints-index.md 的 Role→blueprint 菜单与蓝图本体可知,它服务三个角色:
| 角色 | 来源场景 | 叙事诉求 |
|---|---|---|
Hook(hook) |
hook-pan-timeline / #1 Hook_02 |
"进化/里程碑一路走到我们"——一条水平时间线,逐拍向左平移 |
Problem(pain_point) |
problem-camera-pan-stations / #8 Problem_01 |
"太多断开的步骤——简直一团糟"——一个由手绘连线串起来的痛点站点网络 |
Product_Intro(product_intro) |
concept-demo-decode-pan |
双镜头条带用一次横向平移桥接:静态短语 3D-flap-DECODE 后,镜头带视差平移进第二个镜头,光标驱动实时打字 demo |
时长预算为 7–10 秒(取三者的并集:Hook 8–10s、Problem 约 7s、concept-demo 约 7s)。在 15 个蓝图中属于中长镜头的"叙事跑动型",区别于 titlecard-reveal 这类短促平静的落点。
镜头结构:一张画布、N 个站点、一台相机
蓝图把一整段镜头拆成三幕式骨架,全部建立在一个前提之上:
一个放在纯色
[bg color]底上的超大扁平画布;所有站点/标记预先摆进世界空间;[accent color]文字 + 简单线框图标;一台虚拟.world相机以 ease-in-out 在站点间来回平移。每个站点约停留 1.0 秒。
这是理解本蓝图最核心的一条:内容不动,相机动;站点不等戏,戏被相机"路过"。
时间编码骨架(Scene 1 → Scene N)
- Scene 1(0.0–约 1.0s):镜头开场即对准站点 1——
[label 1 / first step]居中。一个 reveal 落在它身上(具体形态见下方变体)。随后镜头开始向站点 2 PAN,把站点 1 滑出画面。 - Scene 2 → Scene N-1(每站约 1.0s):相机以 ease-in-out 平移到下一个站点;抵达瞬间,它的
[label k](+ 可选的[secondary label])以该角色的 reveal 方式被揭示。逐站重复。 - Scene N(最终,最后一拍):最后一次平移落到终点站;最终的
[callout / landing element]揭示并保持到结束。相机在"包袱点"上完全静止。
注意这里的节奏纪律:reveal 是被台词/节拍驱动到各站点的 arrival 时刻的,而不是在 t=0 一次性出现。这与 blueprints 层"reveals paced to the spoken line, not dumped at t=0"的总原则一致,也是该蓝图与简单循环动画的本质区别。
相机是"唯一的演员"
蓝图的 camera modifier 一节写得非常明确:"The pan IS the camera"(平移本身就是相机)。整段镜头只有一个 .world 虚拟相机变换处于 PAN 模式,站点通过平移到站来揭示,而不是站点在静止画面里自行入场。这一约束同时把本蓝图与另外两个"推近型"蓝图划清了界限:
不做纵深推进(depth push-in)——这正是它与 cluster-push-in / dataviz-pushthrough 类蓝图的关键区别。
两种变体:Hook 的"时间线行军" vs Problem 的"乱麻收束"
同一套"站点+平移"骨架,蓝图为两种叙事各设计了一套完全不同的"皮与骨"。成文时请务必对照需求选择变体,二者的运动语汇几乎不重叠。
Variant — Hook:横向时间线行军
- 布局:站点作为等间距的
[markers]排布在一条位于下三分之一处的细水平[timeline]上。 - 运镜:平移只向左、沿单轴进行(时间线向左滚动)——营造"沿着时间往前走到今天"的语义。
- 站点揭示形态(三档节奏):
- 主要站点的 callout:一个带边框的
[callout box]+ 向下的三角形箭头(带偏移投影),以 SPRING-POP 弹起(scale 0→100%,弹性过冲,transform-origin 锚定在三角形尖端),内容读取[label k]; - 次要标签:如年份
[secondary label, e.g. year]淡入并在 callout 上方上升(RISES); - 中间标记:部分中段 marker 以纯静态文字揭示——仅靠平移本身带出,不加盒子。这制造了节奏的疏密对比,避免每个站点都弹盒子导致视觉疲劳。
- 主要站点的 callout:一个带边框的
- 落点:最后一个场景落在
[present-day label](今天/当下标签)上,spring 弹起并保持,形成"一路进化到我们"的完形。
Variant — Problem:斜向扫视的痛点乱麻
- 布局:站点散布在 2D 平面网络上(非线性的空间关系,暗示流程的割裂)。
- 运镜:平移是斜向(DIAGONAL)的,并且被
[accent color]的手绘连线"掌舵"(steered)——每个站点都有一条粗糙的 write-on 线/箭头指向下一个站点,相机沿着它移动(Scene 1 还在主标题关键词周围画一个圈/环)。 - 站点形态:每个站点 = 一个白色
[line-icon](线框图标,位于[label]之上),仅由平移朴素地带入画面——不加 spring 盒子。这种"平静的逐站揭示"让积累感逐步上升,为终局蓄力。 - 终局视觉包袱:最后一个场景中,强调色线条螺旋式卷曲成一团密集混乱的 SCRIBBLE KNOT(涂鸦线团),正对画面中心;相机保持静止,让观众盯着这团乱麻——画面语言直接喊出"流程太碎、毫无章法"。
Product_Intro 的轻量用法(双镜头单次平移)
第三个角色用法与上面两种不同:它本质是 "两镜头条带"被一次横向平移桥接。镜头 1 先保持一个静态短语,其强调词以 3D-flap-DECODE 的方式翻转变体(概念"落地");随后相机带着背景视差横移进入镜头 2,那里一个光标正在驱动实时的打字 demo。该用法与本蓝图之外另一个蓝图 cursor-ui-demo 的 focal-locked(焦点锁定)追踪打字配对使用——可见蓝图之间可以组合嵌套。
运动语汇:一张动作清单
蓝图将"可以使用哪些动作、哪些不该出现"明确定为 motion vocabulary。归纳如下,可直接当作验收清单使用:
- 反复的 ease-in-out 相机平移(Hook 为水平向左;Problem 为斜向受控)横跨一张静态大画布;
- 预置站点经由平移滑入/滑出画面;
- spring 过冲的 callout 弹起(Hook,带三角形尖端 origin);
- 次要标签的 rise-and-fade(上升+淡出,Hook);
- 纯标签/图标仅随平移朴素抵达;
- 粗糙手绘 "write-on" 引导线/箭头 + 关键词圈/环标记(Problem);
- 终局的混乱涂鸦线团绘制(Problem);
- 最终站点/包袱点上的静止保持(static hold)。
规则映射:从蓝图到原子规则的实现路径
blueprint 之所以可复用,是因为它把"做什么"与"怎么实现"解耦。本蓝图末尾的 rule mapping 明确列出了一条条落到 rules/ 原子规则的路径,这是从"设计"走向"代码"的关键桥:
| 镜头需求 | 对应原子规则 | 说明 |
|---|---|---|
| 画布上的相机平移/遍历(主规则) | viewport-change | 单一 .world 包裹层变换,PAN 模式 |
| 把反复的平移节拍排成站点停靠序列 | multi-phase-camera | 多阶段相机编排 |
| 每站作为平移目标被居中 | coordinate-target-zoom | 作为"pan-to-target",不加 zoom |
| spring 过冲 callout 弹起(Hook) | spring-pop-entrance | transform-origin 锚在三角尖端 |
| 次要标签 rise-and-fade + 各站朴素标签/图标揭示 | discrete-text-sequence | 离散文本状态序列 |
| 手绘引导线/箭头/圈环/终局涂鸦线团(Problem) | svg-path-draw | stroke-dasharray/offset 路径描画 |
| 站点的线框图标(Problem) | svg-icon-enrichment | SVG 图标丰富化 |
| 最终站点/包袱点的静止保持 | 无需规则 | 持续静止帧,刻意不运动 |
这套映射体现了 hyperframes-animation 的设计哲学:蓝图解决"编排",规则解决"质感"。如果场景需求恰好符合某个预设计模板(例如品牌揭示、社会证明墙),复用其 phase pipeline 能显著省时——SKILL.md 建议"load a blueprint when the scene matches an existing pre-designed multi-phase template";反之则用 2–4 条规则自行组合,后者代码更少、更快。
深入实现:三类相机规则的取舍
由于相机是本蓝图的主角,这里值得把三条被引用的相机规则彻底讲透——它们代表了三套不同的变换架构,混用是常见的返工源头。
viewport-change:单包裹层的复合变换(蓝图主规则)
viewport-change.md 的核心是把相机变换放在一个包裹所有场景内容的 wrapper 上,相机右移 = 世界 translateX(-距离)。其"单元素复合变换"形式把缩放与平移都写进同一个 translate(x, y) scale(S):
- CSS 变换按右到左的矩阵组合,scale 先于 translate 生效,因此世界坐标
(ox, oy)落在屏幕(S × ox + x, S × oy + y); - 要把目标映射到视口中线,需要
T = -offset × S(依赖于 S)。
实现上推荐一个 cam = { scale, x, y } 对象作为相机状态的唯一事实源,所有帧通过同一个 applyCamera() 拼接变换字符串,避免 scale 与 translate 被拆到不同 tween 导致矩阵组合次序不可预测:
const cam = { scale: 1, x: 0, y: 0 };
function applyCamera() {
world.style.transform = `translate(${cam.x}px, ${cam.y}px) scale(${cam.scale})`;
}
tl.to(cam, { x: -600, duration: 1.2, ease: "power2.inOut", onUpdate: applyCamera }, PAN_START);
该规则同时给出透视阈值参考:<5% 缩放不可感知,10–15% 为舒适的强调,>30% 即进入电影化/戏剧化区间——对以横向平移为主的 PAN 模式,缩放通常保持在 1.0 附近,克制是产品视频的默认审美。
coordinate-target-zoom:嵌套包裹层的"目标居中"
coordinate-target-zoom.md 是另一种架构:外层做 scale、内层做 translate 的负向补偿(T = -offset,不依赖 S),让非居中元素最终落在视口中线。它在蓝图中的角色被特意限定为 "pan-to-target, no zoom"——即把两个目标站点之间的居中换算交给这套"目标→中线"的推导,但镜头本身不放大。
该规则文档还包含一条对任何虚拟相机都通用的硬经验,直接关系到本蓝图多站点的正确性:
- offset 用实测,不要手推——在 setup 阶段
await document.fonts.ready后,用getBoundingClientRect()读一次目标真实中心并烘焙(bake),绝不在 onUpdate 里逐帧测量(并行渲染采样下逐帧 DOM 读取会失步);手算非对称布局的符号极易出错。 - 头部余量预算——目标在峰值时应 ≤ 画面约 88%,
ZOOM_SCALE = Math.min(DESIRED, 0.88×W/r.width, 0.88×H/r.height),否则轻微偏差就会被放大成裁切。 - scale tween 与 counter-translate tween 必须共享 duration 与 ease,否则目标在平移途中"漂移"。
multi-phase-camera:把平移编排成"停靠节奏"
multi-phase-camera.md 描述相机通过若干离散相位推进(pull-back / focus / push),并叠加连续的正弦 micro-drift。蓝图正是借它把"反复的平移节拍"组织成有停靠感的序列——每站到来如一个"相位",ease 从 power2.inOut / power3.out 家族选择。文档强调相位弹簧要软过 UI 弹簧:相机上用 spring/back 缓动会显得"不舒服",应选平滑进出;同时逐站"落得越来越深"(后一相位 settle 强于前一相位)能营造"唤醒→落定→更深落定"的观感。
此外该规则支持用内容节拍而非固定时钟触发相位(phase trigger by content beat),与本蓝图"reveal 跟随台词节拍"的要求天然契合。若要给停留段添加轻微生命力,也可叠加 micro-drift(振幅建议 X 2–8px / Y 1–4px、两轴频率比约 1.3 避免机械对角运动),但幅度必须低到逐帧不可感知。
三种非相机规则的落地要点
站点揭示涉及的 spring-pop-entrance、discrete-text-sequence、svg-path-draw 三条规则,同样决定了本蓝图观感的上限。
spring-pop-entrance:平滑优先于弹跳
这条规则的立场在文档开篇即被声明:"Smooth beats bouncy"(顺滑胜过弹跳)。默认入场是 scale: 0 → 1 + power3.out 长尾减速,无过冲;back.out(OVERSHOOT) 弹跳被降级为"罕见的、明确搞怪"的例外(消费/娱乐品牌才用),且 OVERSHOOT 也需 ≤ 约 2,否则变成卡通摇晃。对本蓝图而言,Hook 变体终点"present-day label 的 spring 弹起"应理解为有节制的 overshoot,多数站点揭示采用 firm settle 默认形态(power3.out + 可选 24px 的 y-rise)更稳妥。
关键实现细节还有:入场必须用 fromTo 显式声明 { scale: 0, opacity: 0 } 起始态,使 seek 到 t=0 时元素处于正确状态(CSS 隐藏态起步会在 HyperFrames seek 下闪烁);组队 pop 的 stagger 由循环索引确定(绝不用 Math.random),且整体入场窗须 ≤ 约 0.5s 才读作"一个到达节拍"。Hook callout "从三角尖端长出"的观感来自 origin-anchored pop:把 transform-origin 设到三角形尖端而非中心,scale 的生长才读作"从锚点冒出来"而非"原地膨胀"。
discrete-text-sequence:标签跟随站点到达
discrete-text-sequence.md 提供的机制是把整段文本状态按时间阈值替换(而非逐字符打字),由 SEQUENCE 数组 + 每帧反向扫描渲染。它非常适合实现"每站到点时,标签随镜头的到来而更替"——非线性的"整段切换"反而比连续打字更像定格揭示。实现上注意三点:文本包裹容器要定 min-width(≥ 最长状态的宽度)防右侧抖动;光标闪烁必须用 sin 驱动而非 CSS animation(HF 逐帧 seek,CSS 动画会失步);文本本身及其父级禁用 CSS transition(离散跳变必须瞬间完成)。
svg-path-draw:Problem 变体的手绘连线
svg-path-draw.md 是本蓝图 Problem 变体的灵魂——引导线、箭头、关键词圈环乃至终局涂鸦线团都靠它"一笔画成"。原理是对每条 <path> 用 path.getTotalLength() 实测长度后设置 stroke-dasharray = length、stroke-dashoffset 从 length 动画到 0。关键实践:
- dasharray 必须取自实测几何而非拍脑袋数字;
- 多段路径按上一段时长的约 70–80% 错开起始,观感才是连续描画而非 N 段孤立动画;
- stroke 描画用
power2.out(笔在收笔时轻微减速),不要用back.out/elastic.out(钢笔不弹跳);要"真实笔速"可换ease: "none"; - 纯描边记得
fill: none,否则填充区域提前出现会毁掉 reveal。
落地与约束:把蓝图放进 HyperFrames 组合
hyperframes-animation 建立在 HyperFrames 的确定性渲染契约上(详见 hyperframes-core skill 的 Non-Negotiable Rules)。无论用哪条规则实现本蓝图,都必须遵守以下通用硬约束(散见于每条规则的 Critical Constraints 与 SKILL.md):
- 单一暂停时间线:
gsap.timeline({ paused: true }),注册键 = 根元素data-composition-id; - 时长由根元素
data-duration决定;每段镜头结构(Scene 1→N)都映射为时间线上的相位区间; - 确定性:禁止
Math.random/Date.now/performance.now,禁止repeat: -1,禁止在async/setTimeout/Promise内构造时间线; - 空间运动只用 GSAP 变换别名(
x/y/scale/rotation),不 tweenwidth/height/top/left;不动画display/visibility; - 预计算布局常量:绝不在 tween 时用
getBoundingClientRect()推导坐标(渲染器并行采样会失步);setup 阶段算一次并复用; .scene必须overflow: hidden、背景画在.scene而非.world、.world设will-change: transform与transform-origin: 50% 50%——平移中一旦放大/缩小,错误归属的背景会被扭曲或露出画布边缘;- 巅峰停留 ≥ 1s:蓝图让相机在终点站静止保持,正是为了让观众读完包袱点。
验证工具:编写完成后可用 scripts/animation-map.mjs 审计编排——它会读取注册在 window.__timelines 上的每条 GSAP 时间线、枚举 tween、采样包围盒并输出 animation-map.json,用来检查死区(dead zones)、stagger 一致性等生命周期问题:
node .agents/skills/hyperframes-animation/scripts/animation-map.mjs <composition-dir> --out <composition-dir>/.hyperframes/anim-map
(若在当前仓库内直接运行,请将命令中的路径替换为实际仓库根目录对应的 .agents/skills/hyperframes-animation 绝对位置。)
使用流程:五步把一个 frame 落到 spatial-pan-stations
综合 blueprints-index.md 的 picking guidance 与 SKILL.md 的路由表,把本蓝图用于某一帧的标准动作是:
- 定位角色:确认该帧的 role 属于 Hook / Problem / Product_Intro 之一(对应 storyboard frame
type枚举hook/pain_point/product_intro),从 Role→blueprint 菜单选中本蓝图。 - 读取蓝图:打开 spatial-pan-stations.md,对照其时间编码的 Scene 骨架与
[slots]([label k]、[secondary label]、[timeline]、[callout box]、[accent color]等)。 - 选姿态:Reproduce(槽位干净映射)——例如标准的"演进时间线 + 当下落点"Hook;Adapt(结构契合、内容/表面不同,保留 signature move)——例如自定义类型的痛点网络;都不合适则Compose——从运动语汇自行组合,不要硬套。
- 按 rule mapping 逐项装配:主相机用 viewport-change,停靠序列交给 multi-phase-camera,到站居中换算用 coordinate-target-zoom 的 pan-to-target 形式,各揭示动作分别落到 spring-pop / discrete-text-sequence / svg-path-draw / svg-icon-enrichment。
- 按台词排 reveal:把各站点的到达时刻对齐到旁白节拍,保持最终站点 ≥1s 的静止保持,然后跑 lint/动画图脚本自检。
若跳过蓝图直接组合,也可参照同一流程从 rules-index.md 挑选 2–4 条规则、用单条暂停 GSAP 时间线拼接——SKILL.md 明确指出这对简单场景通常更快且代码更少。蓝图的意义在于:当需求与预设计的多相位模板吻合时,复用其 phase pipeline 能拿到一段"有真实 ground-truth"的复杂 4–5 相编排,省去从零设计的时间。
小结
spatial-pan-stations 是 HyperFrames 动画库中把"空间"当叙事的代表作:预置站点的世界 + 单台平移相机,让时间(Hook 的横向演进)与空间(Problem 的斜向网络)都以"路过"的方式被讲述。它的工程实现横跨五类规则——相机(viewport-change / multi-phase-camera / coordinate-target-zoom)、入场(spring-pop-entrance)、文本状态(discrete-text-sequence)、SVG 描画(svg-path-draw)与图标(svg-icon-enrichment),并被确定性渲染契约约束为可逐帧 seek 的单一暂停时间线。掌握了这份蓝图,你就掌握了 HyperFrames 里一类高频叙事手段,也建立起了"蓝图编排 + 规则质感"的分层实现心智。
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 StartedRust0627
Hy4-previewHy4 preview 是由腾讯混元团队研发的新一代混合专家(MoE)旗舰模型。模型总参数量 770B,每个 token 激活 49B,主干共包含78层,第一层采用标准 FFN,其余 77 层均为 MoE 结构,每层包含 256 个路由专家与 1 个共享专家,每个 token 激活 top-8 路由专家及共享专家。主干之外原生内置 1 层 MTP(总参数量 10B,激活 0.7B)以支持投机解码。Python00
GLM-5.3GLM-5.3 与 GLM-5.2 使用相同的基座模型——所有提升均来自后训练。与 GLM-5.2 相比,它在复杂编程和长程任务上的表现显著提升。Jinja00
GLM-5.3-FlashGLM-5.3-Flash (320B-A18B),是GLM-5系列的首个原生多模态模型。320B总参数,能力超过GLM-5.2Jinja00
Spark-X2.5-4BSpark-X2.5-4B 旨在让强大的 AI 更实用、更高效、更易获得。在广泛日常任务中表现强劲,涵盖对话、写作、翻译、推理、编码、工具调用以及智能体工作流,并在同等规模的开源模型中取得领先成绩。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00
Spark-X2.5-1.7BSpark-X2.5-1.7B 旨在让强大的 AI 更加实用、高效且易于获取。这些模型在广泛的日常任务中表现出色,涵盖对话、写作、翻译、推理、编程、工具调用和智能体工作流,并在同等规模的开源模型中取得领先结果。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00