OpenMontage 镜头规划 IR(shot-plan.json):连接 Director 与 Builder 的统一镜头契约详解
导读
在 OpenMontage 的 motion-graphics 技能体系(设计驱动的短片镜头制作流水线)中,shot-plan IR 是 Director(导演智能体)与 Builder(构建智能体)之间唯一的传令契约:一次任务只对应一个文件 shot-plan.json,所有创意决策与构建指令都在该文件内序列化。本文将完整拆解这份 IR 的字段语义、各动画类别的 content 数据形状、可复用的「复用优先」构建约定,并结合仓库源码说明它在 plan → source → design → build → render → verify 全流程中如何流转,帮助你读懂、编写和消费这份镜头计划文件。
一、这份 IR 在流水线中的位置
1.1 一个技能、两段式导演
参考 .agents/skills/motion-graphics/agents/director.md,Motion-Graphics Director 围绕素材采购节点被切成两段:
- Part 1(plan,素材采购前):做两类关键决策 —— 是否需要进行搜索、走哪个类别,并输出一份 DRAFT
shot-plan.json(envelope + 已选表单类别或搜索意图 +asset_needs+ 一段镜头 brief)。 - Part 2(design,素材采购后):围绕已解析到的真实素材设计镜头,挑选目录 block 与动效规则,最终确定
content.block+content.customize及各类别专属content,输出 FINALshot-plan.json。
而 Builder 智能体则只消费这份文件:.agents/skills/motion-graphics/agents/builder.md 开篇即声明「把 shot-plan.json 变成一份可渲染的 HyperFrames composition」。
1.2 流水线的其余环节
参考 .agents/skills/motion-graphics/SKILL.md,完整流程为:
| 阶段 | 执行者 | 主产物 | 说明 |
|---|---|---|---|
| init | Bash | hyperframes.json |
初始化项目 |
| plan | 子智能体(Director Part 1) | shot-plan.json(草稿) |
决策「是否需要搜索」+ 分类 + 素材策略 |
| source | Bash(当 asset_needs 非空时执行) |
assets/ + assets/index.md |
素材采购(搜索/生成/抓取) |
| design | 子智能体(Director Part 2) | shot-plan.json(终稿) |
围绕已解析素材做镜头设计 |
| build | 子智能体(Builder) | compositions/index.html |
复用优先的组合式搭建 |
| render | Bash | renders/video.mp4 |
HyperFrames 渲染 |
| verify | Bash | 原地修复 | lint / inspect / 失败则派发修复子智能体 |
关键点:source 阶段是条件执行的 —— 纯代码/文本类别(如 kinetic-type、大多数 charts/stat)的 asset_needs 为空数组,会直接从 plan 跳到 design。这正是 IR 中「空 asset_needs ⇒ 跳过 Step 2(source)」这一不变量在设计层面的体现。
二、IR 的整体结构:四层区块
shot-plan.json 是单一文件(位于 PROJECT_DIR 下),其结构按职责分为四层。IR 原文(.agents/skills/motion-graphics/references/shot-plan-ir.md)给出的完整骨架如下:
{
// ── envelope(所有类别通用)──
"category": "kinetic-type | stat | charts | logo-reveal | lower-thirds | webpage | news | tweet | asset-fusion",
"duration_s": 6,
"fps": 30,
"canvas": { "w": 1080, "h": 1920, "aspect": "9:16" },
"style": "自由形态的画面方向(氛围 / 能量 / 参考)",
"palette": ["#…"], // 或 "derive-from-asset"
"font": "<HF embed-list font>",
"beats": [12, 37], // 可选的强调帧/秒
"export": "mp4", // 或 "alpha-overlay"(透明 webm/mov)
// ── sourcing seam(Director Part 1)—— [] 表示跳过素材阶段 ──
"asset_needs": [
{
"role": "hero",
"kind": "image|icon|logo|svg|news|web|tweet",
"query": "…",
"source": "…",
"treatment": "cutout|recolor|vectorize|none",
},
],
// ── build directive(Director Part 2,复用优先)──
"block": "<catalog block id,例如 data-chart | caption-kinetic-slam>", // 可选
"customize": {
/* 要改动 block 的哪些部分:data、text、palette、positions */
},
// ── 类别专属内容 ──
"content": {
/* 形状随类别而变,见下 */
},
}
下面逐层展开讲解。
三、envelope:镜头的基础信封参数
envelope 是所有类别共用的「信封」,定义了镜头最基本的物理与风格参数,由 Director Part 1 在草稿阶段确定。参考 director.md 中 Step 3 的说明:
| 字段 | 取值 / 约束 | 说明 |
|---|---|---|
category |
kinetic-type / stat / charts / logo-reveal / lower-thirds / webpage / news / tweet / asset-fusion |
类别是镜头类型的一等公民 |
duration_s |
3–30 | 时长约束来自 skill 定位(short, ~under 10s 到约 30s) |
fps |
30(默认) | 统一为 30fps 便于与 HyperFrames 引擎对齐 |
canvas |
{w, h, aspect},默认 1080×1920 |
默认竖屏 9:16;16:9 / 1:1 依据平台选择 |
style |
自由形态字符串 | 描述氛围 / 能量 / 视觉参考方向 |
palette |
hex 数组,或 "derive-from-asset" |
色板;asset-fusion 类通常要求从素材中取色 |
font |
HF embed-list 字体 | 必须是 HyperFrames 内嵌字体清单中的字体,保证确定性渲染 |
beats |
可选的秒/帧数组 | 标记节拍 / 强调点,例如 [12, 37] |
export |
mp4 / alpha-overlay |
alpha-overlay 表示透明背景,渲染为透明 webm/mov |
其中 duration_s 有一个硬约束值得注意:在 agents/builder.md 与 SKILL 的 repair 阶段都强调 「repair 时绝不更改已固定的 duration」 —— 因为整条时间线、clip 划分与节拍设计都以此为锚。
beats 允许提前约 0.1s 营造「感知上的同步」(anticipation),这是 Director 启发式规则的一部分:「关键元素保持可读 ≥ ~0.3s;beats 可提前 ~0.1s 以获得感知同步」。
四、sourcing seam:asset_needs 素材采购缝
asset_needs 数组是 Director Part 1 与素材采购阶段(Step 2 / source)之间的接口,即原文档所称的「sourcing seam」。它的存在与否直接决定流水线是否分支。
4.1 字段语义
每个需求项包含:
| 字段 | 含义 |
|---|---|
role |
素材角色(如 hero) |
kind |
image / icon / logo / svg / news / web / tweet |
query |
搜索词 |
source |
来源(当由用户提供时,如 logo-reveal 的用户 logo,直接写 source) |
treatment |
后期处理:cutout(抠图)/ recolor(换色)/ vectorize(矢量化)/ none |
4.2 按类别决定素材策略
结合 director.md Step 2:
- asset-free(
asset_needs: []):kinetic-type、大多数stat/charts。内容由用户提供。 webpage/news/tweet:搜索真实来源(页面 / 文章 / 推文)+ 一张配图。搜索查询遵循两极查询规则:要么原子化(1–3 词、可组合:肖像、logo、物体),要么具体化(5–15 词描述一个新闻事件/推文),绝不取中间态;失败的具体查询直接丢弃而不放宽。asset-fusion:搜索或生成一个 hero 素材。logo-reveal:用户提供 logo(填source)。
4.3 空数组 = 跳过整个素材阶段
IR 中明确:空 asset_needs ⇒ Step 2(source)被跳过。这也解释了 SKILL 中的运行语义:source 是 Bash 执行的 media-use 解析环节,仅当 shot-plan.json.asset_needs 非空时运行;若某个搜索/provider 不可用,类别会优雅降级为 asset-free,并在 context.log 中记录。
五、build directive:复用优先的构建指令
block + customize 是 IR 的「构建指令」部分,由 Director Part 2(design)写入。
block:命名的 catalog block id,例如data-chart、caption-kinetic-slam。可选项 —— 若存在命名 block,意味着 Builder 应复用 + 定制该 block,而非手工创作。customize:具体改动内容(data、text、palette、positions)。
这套机制的背后逻辑(见 catalog-map.md):大多数 block 把内容/数据烘焙进自身脚本里,只有少数暴露 CSS-var params,因此复用 = npx hyperframes add <block> + 原地编辑,而非纯变量注入。手工创作仅限两种情况:(a) 目录 block 覆盖不了的空白;(b) asset-fusion 的 affordance 绑定。
典型 IR 片段:
"content": { "block": "data-chart", "customize": { "data": [...], "headline": "…", "palette": ["…"] } }
Builder 侧的操作约定(builder.md):content.block → hyperframes add(或 inline)+ 应用 content.customize;每类别的 content 按 [类别 module] 落实;解析后的素材引用冻结的项目本地路径(绝不引用远端 URL 或 prompt);export: alpha-overlay 时渲染用 --format webm(或 mov)。
5.1 类别 → block 对照(供 Director 挑选)
catalog-map.md 为 Director 提供了「类别 → 借用哪个 block → 定制什么 → 哪些空白需手写」的映射表,节选关键行:
| 类别 | 借用目录 | 定制点 | 需手写的空白 |
|---|---|---|---|
| kinetic-typo | 18 个 caption-* block 之一(kinetic-slam、editorial-emphasis、clip-wipe、gradient-fill、neon-glow、glitch-rgb、matrix-decode、particle-burst、weight-shift、pill-karaoke、highlight、blend-difference…) |
文案、emphasis_words → word--emphasis、色板、字体、节奏 |
18 个之外的新母题 |
| charts | data-chart(bar+line、staggered、值标签) |
数据数组 + 标题/副标题、--bg/--text |
pie/donut、bar-chart-race、ring/% |
| stat | apple-money-count(金融风:$ 计数器 + burst + SFX)或通用 stat-motion |
target、prefix/suffix、label、色板 | — |
| brand reveal | logo-outro |
logo 素材、tagline、URL、色板 | — |
六、per-category content:九种镜头类型的内容形状
IR 的精髓在于:content 的形状按类别变化。这是 Director 写入、Builder 读取的结构化数据。
6.1 表单类别(用户提供内容,无需搜索)
kinetic-type —— 文字即英雄:
"content": {
"scenes": [
{ "id": "s1", "start": 0, "end": 2, "text": "…", "emphasis_words": ["…"], "emotion": "…", "motion": "slam", "beats": [] }
]
}
结合 kinetic-type module:文案需按意义/气息切分成场景(英文约 3–7 词、中文约 4–12 字),为每场标注 Hook → Build → Punch → Resolve 的结构标签,每场景 1–2 个 emphasis_words + emotion + motion(来自动效词表,如 slam / word_reveal)+ beats。motion 字段的值取自共享动效词汇表 references/motion-vocabulary.md(slide_bottom / scale_punch / fade_blur / typewriter / wave / slam…),该词表同时给出每条原语的 GSAP 配方与适用气质。
stat —— 单一英雄数字:
"content": { "value": 750000000, "prefix": "$", "suffix": "", "label": "…", "ring": true }
按 stat module,数字约 4–6s:计数动画必须时间线驱动(用 onUpdate 写入格式化数字的代理对象,保证 seek-safe,绝不使用 setInterval/壁钟计数器),font-variant-numeric: tabular-nums,减速缓动,约 1.2–1.6s 后保持最终值;圆环用 stroke-dashoffset 与计数同步收尾,label 在数字落地之后再淡入(先数值后意义)。
charts:
"content": { "type": "bar|line|pie|race|pct", "data": [], "labels": [], "headline": "…", "axes": true }
logo-reveal:
"content": { "logo": "<asset path>", "tagline": "…", "url": "…" }
lower-thirds:
"content": { "name": "…", "role": "…", "position": "…", "brand_colors": [] }
6.2 搜索驱动类别(真实内容动画化,RWA 路径)
webpage —— 对真实抓取的页面做步骤高亮:
"content": { "url": "…", "capture": true, "highlights": [ { "selector|region": "…", "label": "…" } ] }
news —— 文章高亮(article-highlight)。注意原文中的关键语义:
把文字以可读尺寸铺开(绝不做 zoom),然后让 marker band 原位扫过关键词。
"content": { "outlet": "…", "headline": "…", "body": "…", "keyword": "…", "layout": "A|B", "logo": "…", "date": "…", "subject": "…" }
Layout A = 9:16 居中强调的纯文字;Layout B = 16:9 完整文章布局,含 logo + date + subject(人物照片需经 remove-background 抠图成透明 cutout)。详见 news module。
tweet:
"content": { "author": "…", "handle": "…", "avatar": "…", "text": "…", "metrics": { "likes": 1234, "retweets": 567 } }
asset-fusion —— 素材几何体"变成"图表(真正的净新增 IP):
"content": {
"data_type": "…",
"asset": "<path>",
"affordance": "…",
"element_positions": { "center": …, "extent": …, "safe": [], "avoid": [] },
"derived_palette": [],
"connectors": []
}
按 catalog-map.md 的 asset-fusion 逻辑:先判断数据类型、读取素材的几何 affordance(线性 → 时间线/仪表盘;体积/纹理 → 饼图;高度 → 柱状;容器 → 爆炸视图);element_positions 是对素材特征(center / extent / safe-zones / avoid-zones)的反向测量(逆向工程步骤,靠视觉完成);色板从素材取色(绝不使用通用 #FFF/#000);分两层 —— 素材为 z0 全出血层 + 数据图形按 element_positions 融合在 z1+,connectors/scribble 把数据物理性地"缝"在素材上,素材始终保持可见。
七、Invariants:IR 的三条硬性不变量
IR 在末尾给出三条约束,它们是这份契约能跨智能体稳定传输的根基:
scenes(若存在)必须将[0, duration_s]无缝隙、无重叠地分区 —— 时间轴完整覆盖镜头时长。- 空
asset_needs⇒ Step 2(source)被跳过 —— 布尔式的流水线分支信号。 - 命名了
block⇒ Builder 复用并定制该 block,而非手工创作 —— 「复用优先」的机器可读表达。
这三条分别锁定了时间轴完整性、素材阶段的条件执行、以及构建方式的默认路径。
八、IR 在整个流程中的两次写入与一次消费
理解 IR 的关键是它何时被写、何时被读:
| 时点 | 动作 | 写入内容 |
|---|---|---|
| Step 1(plan) | Director Part 1 写入 DRAFT | envelope + 所选表单类别 或 搜索意图 + asset_needs + 一段镜头 brief |
| Step 3(design) | Director Part 2 写入 FINAL | content.block + content.customize + per-category content(含 element_positions、取色板等) |
| Step 4(build) | Builder 读取 | 按 IR 添加并定制 block,产出 compositions/index.html |
8.1 IR 校验与防错
SKILL 中提供的基础校验命令是文件非空检查:
[ -s "$PROJECT_DIR/shot-plan.json" ] && echo ok || echo missing
渲染前的完整质量门是 HyperFrames 的 lint + inspect:
(cd "$PROJECT_DIR" && npx hyperframes lint . && npx hyperframes inspect .)
而构建阶段的产出(compositions/index.html)必须遵循 Builder 契约(builder-contract.md):根 #stage 必须设了尺寸(position:relative; width; height),CSS 先排布 hero-frame 终态再 gsap.from() 入场,时间线为唯一一条 paused:true 的 GSAP timeline 并注册到 window.__timelines["<id>"]、以 tl.seek(0) 收尾、绝不对渲染关键动效调用 tl.play(),全程确定性(无 Date.now()/Math.random()/网络)。
8.2 实际例子:news 类别的 IR 如何驱动 marker-band 动画
以搜索驱动类别 news 为例看 IR 的消费链路。Director 从真实文章中抽出 keyword(1–2 词/数字/人名,作为钩子),Layout B 还需要品牌 logo、日期与人物照片,写进 asset_needs: { kind: news|web|image, query }(logo 与人物照片作为独立素材查询从 Wikimedia/simple-icons 等来源请求);人物照片在 source 阶段经 hyperframes remove-background 得到透明 cutout。随后 Builder 按 news module 实现:
- 关键词高亮用 marker band 通过
background-size从左往右生长(而非transform:scaleX横条):
.hl {
--hlw: 0%;
background-image: linear-gradient(var(--hl), var(--hl));
background-repeat: no-repeat;
background-position: 0 72%;
background-size: var(--hlw) 64%;
box-decoration-break: clone;
-webkit-box-decoration-break: clone;
}
box-decoration-break: clone 让高亮带可以跨行无缝包裹(多词关键词跨 2–3 行仍连续高亮,旧 scaleX 方案做不到);GSAP 把 CSS 变量 --hlw 从 0% 补间到 100%,且必须在文字落定之后才扫上,绝不能预先应用;高亮时长随关键词长度在 ~0.5–1.5s 间缩放。这正是 IR 中 keyword、layout 字段与动效实现之间的对应关系。
8.3 参考实现位置
仓库内为各搜索驱动类别提供了可运行的参考样本(samples/),可作为 IR 语义落地的具象参照:
.agents/skills/motion-graphics/samples/asset-fusion/_ref-circle-highlight.html- news 类别的
_ref-centered-emphasis.html与_ref-article-layout.html(后者为真实文章 + 真实 outlet logo + 抠图人物 + 真实故事的完整布局演示)
九、写作 / 维护 IR 的实战要点
汇总各阶段规则,当 Director 要产出合规且高质量的 IR 时需注意:
- 先决策是否需要搜索,再落类别:form category(kinetic-type / stat / charts / logo-reveal / lower-thirds)内容由用户供给、
asset_needs: [];search-driven category(webpage / news / tweet / asset-fusion)最终由搜索返回的内容类型确认。 - envelope 提前锁死:时长(3–30s)、fps(30)、canvas(默认 1080×1920 竖屏)、
font必须在 HF embed-list 内、export决定渲染格式分支。 - 查询两极而非中间态:
asset_needs[].query要么 1–3 词原子查询、要么 5–15 词具体查询;失败的查询丢弃而不放宽。 block是承诺:一旦命名 block,Builder 就走 add + customize 的复用路径;只有 catalog 空白与 asset-fusion affordance 才允许手写。content按类别对号入座:每种形状的字段都有明确消费方 —— 例如 kinetic-type 的scenes分区决定时间轴、stat 的ring决定是否画圆环、news 的layout决定 9:16 纯文字还是 16:9 带人物 cutout。- 写完后自查三条不变量:
scenes是否无缝分区、asset_needs空否决定 source 是否运行、命名block是否走复用。
结语
shot-plan.json 不是一份「文档」,而是运动图形流水线中结构与协议本身:它把创意决策(category、style、beats、brief)、素材需求(asset_needs)、构建指令(block + customize)与类别化内容(content)统一进一个文件,使 Director 的两段式设计与 Builder 的复用优先构建可以解耦协作。读懂这份 IR 的字段与不变量,也就读懂了 OpenMontage 设计驱动短片如何从一句需求稳定地产出可渲染、可验证、确定性的运动图形。
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 StartedRust0629
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证件照制作算法。Python07
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