OpenMontage 动效技能实战:用 `webpage` 分类模块把真实网页做成无旁白动效短片
导读
在 OpenMontage 的 motion-graphics 技能体系里,webpage 是一个 search-driven(搜索驱动) 的分类模块,用于解决"把一个真实网页 / 链接做成一段动效短片"这一需求:用户给出或说出一个 URL → 抓取 / 捕获页面 → 用滚动浏览、UI 逐个浮现、光标演示、区域标注等手段把页面"演"出来。它的定位与给已有视频加字幕(embedded-captions)不同,也与"对网站做带旁白的解说视频"(website-to-video)不同——本模块的源素材是一张网页,产出是一段简短、无旁白的高光短片(highlight shot)。读完本文,你将掌握网页捕获、滚动 + 聚光 / 光标点击 / 缩放定位 / 标注图钉等动效原语的编排方法,以及两条贯穿始终的硬性规则(标注"扫"上去而不是预先贴上、一切锚定真实 DOM 元素的坐标)。
一、模块在技能树中的位置:先回答"要不要搜索"
webpage 分类模块定义在 .agents/skills/motion-graphics/categories/webpage/module.md,属于 motion-graphics(设计驱动的短动效编排技能)。该技能把全流程拆成 init → plan → source ◇ → design → build → render → verify 七个阶段;其中 plan 阶段的第一个决策就是:这个需求需不需要搜索?
根据这个分叉,分类被切成两组:
- Form categories(无搜索,用户自带内容):
kinetic-type、stat、charts、logo-reveal、lower-thirds,asset_needs为空,plan 后直接进入 design; - Search-driven categories(先搜索再按返回内容类型动画):返回网页/链接 →
webpage;返回新闻文章 →news;返回推文 →tweet;返回图片/实体 →asset-fusion。
webpage 和 news、tweet、asset-fusion 一起构成了技能的 RWA(Real Web Asset)路径:先分析需求、搜索真实素材、评审取舍,再围绕素材设计镜头、最后用 catalog 复用组件来合成。webpage 在 分类表格 中对应的动画描述是:"webpage / UI animation (scroll, reveal, cursor, callouts)"。
二、Source(Step 2):如何捕获真实网页
2.1 两种取源方式
模块规定网页素材来自两条途径,取其一即可:
- 用
hyperframes capture抓取页面,得到 DOM + 截图; - 用户直接提供一个现成截图。
抓下来的页面会被冻结(frozen)为项目本地的图片 / DOM,后续动画全部基于这份冻结素材,杜绝渲染期对网络的依赖。在 shot-plan IR 中,这一步的声明方式是向 asset_needs[] 写入一条资源需求:
{ "kind": "web", "source": "<url>", "treatment": "none" }
其中 kind: web 表示要捕获网页,source 是目标 URL,treatment: none 表示捕获后无需裁切、重着色或矢量化处理(对比 news 模块里人物照片要跑 hyperframes remove-background 得到透明抠像,网页素材通常直接整页冻存)。
source 阶段只在 asset_needs 非空时运行(详见 phases/source/guide.md),对每一条需求执行 analyze → search → review → freeze,并把最终结果写入 assets/ 与台账 assets/index.md。若搜索/捕获能力不可用,则在 context.log 中标记需求未满足,类别降级为无素材版本——但 webpage 类别的核心前提就是拿到可量测的页面 DOM,所以捕获是它的"灵魂步骤"。
2.2 hyperframes capture 的真实 CLI 形态
hyperframes capture 是 HyperFrames CLI 的脚手架命令,完整用法记录在 hyperframes-cli/references/init-and-scaffold.md。在 OpenMontage 技能库中可以看到它支持以下常用形态:
npx hyperframes capture https://stripe.com # 从网站抓取并脚手架化
npx hyperframes capture https://linear.app -o linear-video # 自定义输出目录
npx hyperframes capture https://example.com --json # 给 Agent 用的 JSON 输出
npx hyperframes capture https://example.com --skip-assets # 跳过图片 / SVG 下载
npx hyperframes capture https://example.com --max-screenshots 12 # 限制截图张数
npx hyperframes capture https://example.com --timeout 60000 # 页面加载超时(毫秒)
这些参数的价值在 webpage 动画里非常直接:--json 让 Director / 自动化流程能结构化地读取捕获结果;捕获出的 HTML/DOM 正是后面"锚定真实元素位置"的技术前提(见第五节);--max-screenshots 控制整页采样密度,配合滚动浏览的分段镜头使用。
三、动效词汇与依赖规则:webpage 用到的原语
webpage 模块明确列出了它"借力"的规则和原语。规则侧指向 hyperframes-animation 的规则库({3d-page-scroll, demo-page-scroll-spotlight, cursor-click-ripple, coordinate-target-zoom, viewport-change}),其中实际存在的文件与作用如下:
| 规则 / 参考 | 文件 | 作用 |
|---|---|---|
3d-page-scroll |
rules/3d-page-scroll.md | 整页做成有 3D 倾角的卡片,内部内容滚动以逐段揭示页面区块 |
| demo-page-scroll-spotlight | examples/demo-page-scroll-spotlight.html | 滚动 + 聚光演示示例:页面滚动后高亮目标区(真实可渲染参考) |
cursor-click-ripple |
rules/cursor-click-ripple.md | 光标移到目标、按下(压扁回弹)、从点击点放射涟漪 |
coordinate-target-zoom |
rules/coordinate-target-zoom.md | 缩放进入某个非居中元素(双层嵌套 + 反向平移) |
viewport-change |
rules/viewport-change.md | 单包装层模拟虚拟相机 zoom / pan / focus-lock |
原语侧(共享词汇表见 references/motion-vocabulary.md)归结为五类:
- scroll pan——滚动平移,对应整页滚动浏览;
- spotlight/dim——聚光 / 压暗,突出关键区域;
- cursor move + click-ripple——光标移动 + 点击涟漪,演示交互;
- zoom-to-region——缩放到某个坐标区域;
- callout pin + label——锚定在页面区域上的标注图钉与文字标签。
四、Build(reuse-first):把五个原语串成一段网页高光
模块对 build 阶段给出的是复用优先的组装指令,而不是从零写代码:
把捕获到的页面作为 base layer;做一个 scroll-through(沿页面高度做
translateY)、给关键区域打 spotlight(压暗 + 高亮)、让一个 cursor 移动并点击(涟漪)、zoom 到某个坐标,并在页面区域上锚定 callout 图钉 / 标签。全程遵守 builder-contract.md。
结合 catalog-map.md 与 builder-contract.md,reuse-first 的实际含义是:优先执行 npx hyperframes add <block> 把 catalog 里现成组件的源码拉进 compositions/,然后在原位改数据 / 文案 / 配色 / 时间轴,只有 catalog 覆盖不到的缺口才手写。模块要求 Builder 在 shot-plan.json 的 IR 里把这些变成可执行指令。
4.1 webpage 在 shot-plan IR 中的 content 形态
shot-plan-ir.md 为每个分类定义了专属 content 结构,webpage 对应:
"webpage": {
"url": "<源 URL>",
"capture": "<冻结的捕获路径>",
"highlights": [
{ "selector": "<CSS selector|region>", "label": "<标注文案>" }
]
}
注意 highlights 数组元素是 selector | region + label 的组合——这正是"高亮真实元素"这一技术路线的产物:Director 用 CSS selector 指名要讲解的真实 DOM 节点(或区域),Builder 再去测量它并做精确高亮,而不是凭感觉给坐标。
4.2 五段式的标准编排节奏
把模块描述的动画意图和规则库的参考实现合起来看,一条典型的 webpage 高光镜头大致是这种节奏:
- 入场:捕获页(base layer)落定,可以是 3D 倾角卡片或平面整页;
- scroll-through:把内容容器沿
translateY从页首滚动到目标区块(见 3d-page-scroll 的实现); - spotlight:滚动落定后,一个径向渐变聚光罩淡入,压暗四周、突出焦点区(同一规则里的 spotlight overlay);
- cursor + click / zoom-to-region:光标移动到页面某个可交互元素上,压下并释放涟漪(cursor-click-ripple),或相机缩放进入某个非居中区域(coordinate-target-zoom / viewport-change);
- callout:缩放或点击落定后,图钉 + 标签浮现,给出说明性文案,然后停留足够让观众阅读的"高潮驻留"时长。
examples/demo-page-scroll-spotlight.html 就是这个能力的可渲染参照:它的时间轴注释清楚写了 9 秒四阶段的编排——3D 倾角卡片入场(0.00–0.80s)、导航/标题/CTA 逐个淡入(0.12–2.80s)、页面内容向上滚 280px(3.08–4.08s)、主视频以 translateZ 前冲 + 径向聚光压暗四周(3.58–8.84s)。其中滚动是通过 tl.to("#scroll-content", { y: -280, ease: "power2.inOut" }) 这类 y 平移完成的"程序化滚动感",聚光则是独立的 opacity 叠加层——两者都不会和 GSAP 抢同一个 transform。
五、两条不可违背的规则(与 news 模块共用的设计铁律)
模块花最大篇幅强调的两条规则,和同目录的新闻文章高亮模块(news/module.md)是同源设计:
规则一:标注是"扫"上去 / "动"上去的,绝不预先贴好(Highlights are swept ON, never pre-applied)
页面的任何讲解性标注都不允许在镜头开始时就已经存在。模块给出的禁止/允许对照如下:
- 聚光框应当擦入(
scaleX 0→1),而不是开画就有; - marker 应当扫过某个区域;
- callout 应当在 zoom 落定之后才弹出。
这样做的动效原因是观众的眼睛需要被引导:页面永远从"干净未标注"的状态开始,讲解信息在节奏点被表演出来,而不是一开始就铺满批注让观众无从看起。这与 news 模块 中"关键词高亮带在文字安定后才 L→R 扫出"(用 background-size 生长而不是 transform:scaleX 的 bar)是同一个原则的两种实现,也都指向"先呈现内容,再高亮局部"。
规则二:锚定真实元素位置,别靠肉眼估坐标(Anchor to REAL element positions)
因为 hyperframes capture 给的是页面真实的 HTML/DOM,所以:
- 用 DOM 拿到目标元素的真实量测结果;
- 把页面坐标换算成舞台局部坐标(
getBoundingClientRect→ stage-local); - 用这个精确值去 zoom / 高亮,做到"step-by-step 高亮真实元素"。
模块明确禁止"Don't eyeball coords"。这条规则在 coordinate-target-zoom 规则里有完整的工程化落地方案:缩放的目标偏移要在 setup 时量一次真实 DOM,而不是手推公式。该规则文件给出的测量模板是:
await document.fonts.ready; // 等字体就绪,fallback 字体测量会偏 10–30px,放大 3× 后会被放大成几十像素
const W = 1920, H = 1080;
const r = document.getElementById("target-card").getBoundingClientRect();
const TARGET_OFFSET_X = r.left + r.width / 2 - W / 2;
const TARGET_OFFSET_Y = r.top + r.height / 2 - H / 2;
// 把 -TARGET_OFFSET_X / -TARGET_OFFSET_Y 作为 counter 平移喂给内层 tween
并且明确两个边界:
- 缩放封顶:目标在峰值时不要超过画布的 ~88%——
maxScale = Math.min((0.88*W)/r.width, (0.88*H)/r.height)。填满画面意味着中心一偏就被裁切。 - 只在"等宽对称卡片行"里才允许跳过测量,其余一律
getBoundingClientRect实测,因为手推 offset 最容易犯的就是符号错误,而缩放会把错误放大到画面之外。
六、zoom 的两种实现:coordinate-target-zoom vs viewport-change
webpage 的"zoom to region / coordinate"有两种等价但数学不同的实现,规则库刻意对比,避免混用:
| 维度 | coordinate-target-zoom | viewport-change |
|---|---|---|
| 结构 | 两层嵌套:外层缩放 scale、内层反向平移 translate |
单层包装:一个 .world 上写 translate(x,y) scale(S) |
| 反推公式 | T = -offset(与 S 无关) |
T = -offset × S(与缩放相关) |
| 适用 | 缩放和平移可以各自独立 tween、共享 duration/ease | 需要单一相机状态源 cam{scale,x,y}、用 onUpdate 统一写 transform |
| 陷阱 | 变换顺序不能放同一元素上,会与直觉相反 | CSS 先应用 scale 再应用 translate(矩阵从右往左),混用两层公式会漂移离靶 |
两者共享的关键纪律是一致的:transform-origin: 50% 50%、场景必须 overflow: hidden、不要给包装元素写 CSS transition(会和 GSAP 打架)、will-change: transform、缩放落定后至少驻留 ≥1s 让人看清目标(Climax dwell)。对网页动效而言,一般做法是:需要把焦点"安放在画面中央"用嵌套双层;而想让光标移动 / 页面滚动与相机联动、需要逐帧换算世界坐标的 focus-lock,用单层 viewport 形式。
七、光标演示:cursor-click-ripple 的实现细节
网页动效里"演示点击某个按钮 / 表单"是高频镜头。规则 cursor-click-ripple 给出三阶段时间轴:Move → Click(压下+回弹)→ Ripple(涟漪)。
- Move:光标从入场角平移到目标中心,时长建议 0.4–1.0s;移动必须在
CLICK_AT前结束,否则"边移动边点击"会读成误触。缓动可选power2.inOut(沉稳)、back.out(1.2–1.4)(轻微过冲"落座"感)、power3.out(果断)。 - Click:光标和目标一起压扁再弹回(
yoyo:true, repeat:1),半程PRESS_DUR建议 0.06–0.12s;光标压缩幅度(0.80–0.90)应大于目标(0.92–0.97),因为光标是施动者。 - Ripple:从点击点(目标的视觉中心,不是包围盒原点)向外扩散 1–3 圈涟漪,建议
RIPPLE_DUR0.5–1.0s、scale 3–6、stagger0.06–0.12s、缓动power2.out;必须用immediateRender: false让涟漪在 t=0 保持不可见,否则会在错误尺寸下预渲染出来。
光标与涟漪元素全程 pointer-events: none、高 z-index、无 CSS transition/动画,保证 seek 时确定性成立。
八、builder-contract:所有编排都必须守住的底层契约
webpage 模块要求 build 全程遵守 references/builder-contract.md。结合网页动效场景,要点如下:
- 舞台根节点必须有确定尺寸:
#stage需要position: relative; width/height显式设好,否则 flex 子元素高度塌陷、内容堆到左上角,而lint/inspect并不会发现; - 先静态 CSS 后动画:先找"hero frame"(大多数元素同框的那一帧)用纯 CSS 摆好,再上 GSAP;入场一律
gsap.from(),CSS 里摆好的位置是"终点真值",tween 只是到达它的路径; - 时间轴契约:全局只有一条
gsap.timeline({ paused: true })挂到window.__timelines["<id>"],以data-composition-id为注册键;tl.seek(0)定位,永不tl.play();带时间的元素用class="clip"+data-start/data-duration/data-track-index+ 稳定id; - 确定性:禁用
Date.now()/Math.random()/ 网络;数字动画 tween 代理对象走onUpdate(seek 安全),不做墙钟计数; - seek-safe 揭示:延迟元素用
gsap.set(el,{autoAlpha:0})一次性藏起,再在入场时gsap.to(...,{autoAlpha:1})揭示;禁止用set(opacity:1) + from(opacity:0)的组合——在暂停/seek 渲染下元素会永远隐形; - 允许的缓动:
power1–4、back、bounce、circ、elastic、expo、sine各.in/.out/.inOut; - 调色板纪律:颜色统一收敛到一个
palette对象 / CSS 自定义属性里,不散落内联 hex。
九、把整段流程跑起来:从 URL 到成品 MP4
把 webpage 模块放进 motion-graphics 主流程 看,一次完整的"网页动效"交付包含以下动作(工作目录按技能约定统一在 PROJECT_DIR = videos/<project-name>/ 下,所有 Bash 用 (cd "$PROJECT_DIR" && ...) 子 shell,绝不裸 cd):
Step 0 · init:仅在 $PROJECT_DIR/hyperframes.json 缺失时执行:
PROJECT_DIR="${MOTION_GRAPHICS_DIR:-videos/<project-name>}"
mkdir -p "$(dirname "$PROJECT_DIR")"
npx hyperframes init "$PROJECT_DIR" --non-interactive --example=blank
Step 1 · plan(Director Part 1):决策是否搜索 → 属于 search-driven → 按"返回内容类型"确认走 webpage 分类 → 写 draft shot-plan.json(envelope + asset_needs + 一段 shot brief)。
Step 2 · source ◇:asset_needs 非空则执行,hyperframes capture 冻结页面 DOM/截图到 assets/,写 assets/index.md 台账。
Step 3 · design(Director Part 2):围绕冻结素材设计镜头,把 content.webpage 的 url/capture/highlights、block、customize 写入最终 shot-plan.json。
Step 4 · build(Builder):复用优先合成 compositions/index.html——npx hyperframes add <block> + 原位定制,遵守第五节与第八节全部约束。
Step 5 · render:
(cd "$PROJECT_DIR" && npx hyperframes render . --skill=motion-graphics -q draft -o ./renders/video.mp4)
# 透明叠加变体:--format webm(或 mov)
Step 6 · verify:
(cd "$PROJECT_DIR" && npx hyperframes lint . && npx hyperframes inspect .)
出错则由 finalize 子代理做一版快照 QA + 单次原地修复 + 重渲染,期间不得改动已固定的时长。成功后报告 renders/video.mp4(或 webm/mov 叠加变体)与时长,渲染结束后如用户要求再提供 npx hyperframes preview / play 预览。
十、与相邻类别的边界与协同
把 webpage 放回分类全景更能看清它的边界:
- vs
news(文章高亮):news 是把文章文本以可读字号(不放大)铺开、用 marker 带原位扫过高亮关键词,主版式是"居中强调(9:16 纯文字)"或"整篇文章卡(16:9 带 logo/人物)";webpage高亮的是捕获页面上的真实 DOM 区域,手段是滚动 + 聚光 + 光标 + 缩放,二者共用"高亮扫入不预置"与"锚真实元素"两条铁律; - vs
tweet/asset-fusion:都属于 search-driven 分支,只是返回内容类型不同; - vs
website-to-video(.agents/skills/website-to-video/ 技能):那是带解说、更长叙事的"网站解说视频",而webpage是"动效即信息"的无旁白短片,时长通常在 10s 上下;路由上不确定时先读/hyperframes。
十一、给自动化与手工调度的提示
- resume 表(见 SKILL.md):无
shot-plan.json从 plan 继续;有asset_needs但无assets/从 source 继续;shot-plan.json定稿但无compositions/index.html从 design+build 继续;有 index.html 无 render 从 render+verify 继续;MP4 已存在即收尾。这让网页动效任务天然支持断点续跑。 - 环境前提:macOS Apple Silicon 或 Linux x64;
brew install node ffmpeg;跑一次npx hyperframes doctor。macOS GPU 渲染加export PRODUCER_BROWSER_GPU_MODE=hardware。 - 素材冻结是底线:网页在 build/render 阶段是纯本地资产,不依赖网络;若页面后续变化,需要重新 capture 以保持证据与视觉一致。
结语
webpage 分类模块的价值在于把"真实网页"这种高信息密度、高真实感的素材安全地引入短动效流水线:capture 冻结 DOM 让你拥有可以精确量测与定位的真实页面,scroll / spotlight / cursor / zoom / callout 五个原语构成叙事语言,"标注扫入、锚真实坐标"两条铁律保证成品既清晰又可信。它不是一个孤立小工具,而是 OpenMontage 搜索驱动动效路径(webpage / news / tweet / asset-fusion)中的一环,其产出可直接落到 compositions/index.html,经 hyperframes lint/inspect/render 变成一段可在社交平台上直接投放的无旁白高光短片。
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
video-shotcraftAI宣传片skill,使用 Remotion 制作电影级产品视频:提供106 张镜头配方卡和可复用的视频魔板。适用于 Claude Code 与 Codex以及所有其他智能体Markdown00
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