首页
/ OpenMontage HyperFrames 全屏运动模式指南:用共享背景层 + 透明时间层编排跨场景视觉连续性

OpenMontage HyperFrames 全屏运动模式指南:用共享背景层 + 透明时间层编排跨场景视觉连续性

2026-09-08 10:54:14作者:郁楠烈Hubert

导读

本文解读 HyperFrames 组合件创作中最容易被误用的一类需求——全屏帧运动(贯穿多镜头的连续背景、色彩冲洗、跨 Clip 的全出血视觉状态)在 HTML/CSS/GSAP 组合件中的正确写法。它是 HyperFrames Core 组合契约的一个关键模式,在 OpenMontage 中用于 render_runtime = "hyperframes" 的 HTML 渲染路径(产品宣传片、动效字幕、数据可视化等)。读完本文,你将掌握「共享背景层 + 透明定时内容层」的骨架、它为何能规避逐帧重绘与跨场景连续性造假,以及五条硬性规则与对应的 CLI 验证流程(lint/validate/inspect/snapshot)。


一、先回到契约:HyperFrames 如何从 HTML 渲染视频

在深入本模式前,先明确它所在的环境。HyperFrames 将一个 HTML 文件视为一段可渲染的组合件:DOM 用 data-* 属性声明时间结构,动画运行时(默认 GSAP)是可 seek 的,媒体播放由框架接管。一份最小组合件必须包含(详见 minimal-composition.md):

  • 根元素 <div>data-composition-iddata-widthdata-heightdata-duration
  • 至少一个 Clip(任何带 data-start/data-duration/data-track-index 的元素);
  • 一个 paused: true 的 GSAP 时间线,同步注册到 window.__timelines["<composition-id>"]

其中与全屏运动直接相关的契约点有(完整属性表见 data-attributes.md):

属性 含义
data-start / data-duration Clip 可见时间窗,单位秒。可见区间两端均闭合start ≤ t ≤ start + duration,因此最后一帧会保持动画解析后的结束态
data-track-index 轨道是「时间重叠」概念而非视觉堆叠概念;视觉前后关系由 CSS z-index 决定
class="clip" 可见定时元素(<div><img> 等)的必选运行时可见性标记,缺失时元素将全程可见,无视 data-start/data-duration

而确定性渲染要求(见 determinism-rules.md)规定:渲染器对每一帧都是「新的一次 seek」,不存在播放累积状态,因此不能依赖时钟、随机数、网络或输入事件,只能动视觉属性白名单opacityxyscalerotationcolorbackgroundColorborderRadius、变换),且永远不要动画 display/visibility。这些约束正是下面全屏运动模式赖以成立的地基。


二、为什么:堆叠不透明场景的代价

最容易想到的「多场景视频」做法,是给每个场景一个不透明的、铺满画布的 <section>,让它们按时间先后叠加。对视觉上彻底不连续的场景(硬切)这可行,但只要场景之间存在视觉连续性或「全局」视觉状态,堆叠不透明方案就会暴露出三层代价:

  1. 每次场景切换都要整帧重绘。 不透明场景互相遮挡,换场意味着整个像素面的重建。
  2. 跨场景的视觉连续性只能靠「造假」模拟。 例如上一场是深蓝、下一场要承接微妙的色相偏移,你不得不在两个场景里分别硬编码背景色,再祈祷它们衔接得刚好。
  3. 所有「全局状态」都要在每个场景上复制一份。 一次色相偏移(hue shift)、一个暗角(vignette)、一层胶片颗粒(film grain),都必须在每个场景各自叠一遍——你改一处全局效果,就得改动 N 个场景。

而 HyperFrames 的根元素带固定像素尺寸(如 1920×1080)与 overflow 控制,天然适合把「画面底色」抽离成单一共享层。Full-Screen Motion Pattern 的思路因此非常直白:共享背景层(由可 seek 的时间线驱动)+ 透明的定时内容层。共享层提供一块连续视觉表面,场景则变得轻量、透明——场景换场时,背景不会闪断、不需要「补」连续性,全局状态也只存在于一处。

补充一个来自 composition-patterns.mdhyperframes-core/SKILL.md 的实现层佐证:全屏场景填充必须放在一个全出血的 position:absolute; inset:0 子元素上,绝不要放在组合件根元素自身的 background——生产器做帧合成时可能丢弃根元素自身的背景导致帧发黑,即便 preview/snapshot 看起来正常。共享背景层这条规则正好满足「全出血子元素」的要求。


三、模式骨架:共享背景 + 透明时间层

完整示例(源自 full-screen-motion.md 并补充注释):

<div id="root" data-composition-id="main" data-width="1920" data-height="1080" data-duration="20">
  <!-- 共享背景 —— 不是 Clip,始终可见,由时间线驱动。 -->
  <div id="bg" class="full-bleed"></div>

  <!-- 定时内容层 —— 透明背景。 -->
  <section
    id="scene1"
    class="clip transparent"
    data-start="0"
    data-duration="6"
    data-track-index="1"
  >
    <!-- content -->
  </section>
  <section
    id="scene2"
    class="clip transparent"
    data-start="6"
    data-duration="14"
    data-track-index="1"
  >
    <!-- content -->
  </section>
</div>

<script>
  window.__timelines = window.__timelines || {};
  const tl = gsap.timeline({ paused: true });

  // 用可 seek 的时间线驱动共享背景。
  tl.to("#bg", { backgroundColor: "#0a1530", duration: 6, ease: "sine.inOut" }, 0);
  tl.to("#bg", { backgroundColor: "#1a0a30", duration: 14, ease: "sine.inOut" }, 6);

  // 场景内动画透明地叠加在上方。
  tl.from("#scene1 h1", { y: 48, opacity: 0, duration: 0.6 }, 0.2);

  window.__timelines["main"] = tl;
</script>

结构拆解

根元素data-composition-id="main" 必须与 window.__timelines["main"] 键一致;data-width/height 声明固定像素帧(常见 1920×10801080×19201080×1080);data-duration="20" 是渲染时长而非时间线长度。根元素 CSS 应带明确像素尺寸并 overflow: hidden(除非故意在画布外构图)。

共享背景 #bg:一个 .full-bleed 的绝对定位铺满子元素(position:absolute; inset:0)。它不是 Clip——不带 data-start/data-duration/data-track-index、不加 class="clip",因此不会被 Clip 生命周期隐藏,在整个组合件存活期间持续可见。它的每一帧状态都来自时间线的 tl.time(),保证确定性渲染。

内容层 <section>:每个场景是带 class="clip transparent" 的定时层。data-start/data-duration 声明可见时间窗,data-track-index 放在同一轨道(示例均为 1,时间上首尾相接不重叠,符合 tracks-and-clips.md 的同轨不可重叠规则)。transparent 意味着背景完全透明,让下层 #bg 透出来。

时间线驱动背景:两个 tl.to(...) 以绝对时间位置参数(06)把 #bg 的背景色从深蓝 #0a1530 平滑过渡到暗紫 #1a0a30。因为背景被时间线驱动而非 Clip 机制驱动,整段 20 秒内它是一块连续运动表面——这正是「背景属于运动语言」的体现。而场景内容层各自做局部动画(如 h1y/opacity 入场),透明叠加在背景之上。

让它可运行的 CSS

参考 minimal-composition.md 的布局契约,组合件还需要这样一段骨架样式:

body {
  margin: 0;
  background: #000;
}
#root {
  position: relative;
  width: 1920px;      /* 显式像素尺寸:根未定尺寸是静默布局 bug */
  height: 1080px;
  overflow: hidden;
}
.full-bleed {
  position: absolute;
  inset: 0;
}
.clip.transparent {
  position: absolute;
  inset: 0;
  background: transparent; /* 内容层透明,让共享背景透出 */
}

注意 SKILL.md 强调:独立根元素需要显式定尺寸盒子(px),且祖先链直到某个 height:100% 元素都必须解析出高度,否则 flex/100% 子元素会塌缩成 ~0 并堆到左上角——lint/validate/inspect 都抓不到这类问题。


四、五条规则详解

原文档把模式提炼为五条硬规则,每一条都与 HyperFrames 运行时契约深度绑定:

规则 1:背景不是 Clip

共享背景不得携带 data-start/data-duration/data-track-index,不加 class="clip"。它服务于整个组合件。这与 class="clip" 的运行时语义互为镜像(见 data-attributes.md):带 class="clip" 的可见定时元素才受 data-start/data-duration 显隐控制,缺了它反而全程可见。把背景做成 Clip 等于给它套上显隐窗口,视觉连续性就会在换场时断裂。

规则 2:内容场景必须透明

内容层背景必须透明(background: transparent 或干脆不设背景),让共享 #bg 中的一切透出。这条与规则 1 配合,才产生「背景连续、场景轻量」的效果。

规则 3:全局状态只从共享层驱动一次

色相偏移、暗角、颗粒、胶片滤镜这类全局视觉状态,在共享层动画一次,绝不要按场景复制。示例中若想加全局暗角,就应把它做成覆盖全画布的 #bg 之上的兄弟元素(或 #bg 内部的伪元素/子层),用同一时间线驱动其 opacity——改动一处即可作用于所有场景。

规则 4:不要在 .clip 元素上动画可见性

HyperFrames 运行时已经根据 data-start/data-duration 负责 Clip 的显示/隐藏。若你再在 .clip 元素上动画 display/visibility,会与框架自身的显隐机制互相竞争(race),时序结果不可预测。这与 determinism-rules.md 的「可动画属性白名单」完全一致:用 opacity/变换来表达过渡,用定时 Clip 可见性来表达显隐。需要做显隐式动画时,去动画 Clip 内部的子包装元素(child wrapper),而不是 Clip 本身。

规则 5:用 snapshot 验证「有意的溢出」

在加 data-layout-allow-overflow 去消除 inspect 警告之前,先运行 npx hyperframes snapshot 并人工确认那个溢出正是你想要的。原因在 lint-validate-inspect.mddata-attributes.md 中写得很清楚:

  • inspectgetBoundingClientRect 在采样时间戳上量测,而非量渲染像素——overflow: hidden 会裁掉视觉,却不会消除 inspect 的溢出发现;data-layout-allow-overflow 才是逃生舱,CSS overflow 不是。
  • 该属性会沿子树继承(感知探针会向上走祖先链),同时会压制 text-clippingcontent-cramped-containerforeground-over-panel 等渲染级感知检查。因此优先最小范围逃生:把 data-layout-allow-overflow 放在最小的装饰包装元素上,而不是整块常驻面板;primary-offscreenforeground-over-panel 两个画布/边缘检查即使在 allow-overflow 下仍会运行,它掩盖不了被画框切掉的 wordmark 或溢出到面板边缘的文字。
  • 与动画耦合的实践是:进场/退场动画的中间态溢出属于「有意溢出」,应在构建时在场景主元素/共享层标注好,而不是等 inspect 报出后再逐个打补丁。

五、何时不要用这个模式

文档对边界定义得很克制:如果场景在视觉上真的互不相干——不同色彩世界之间的硬切、毫无连续性——那么堆叠不透明场景(stacked-opaque)完全够用,不必引入共享层。共享背景模式只适用于背景本身就是运动语言的一部分的组合件,而不只是可有可无的衬底。

实践中可以这样判断:

  • 背景全程是单一静态底色,只是换场时整体变一下 → 不需要共享层,直接在内容场景里各自设底色即可;
  • 背景承载色相漂移、暗角渐变、颗粒质感、光斑流动,且跨越多个 Clip 连续演进 → 使用共享层;
  • 场景间存在「同一元素跨场延续」(一个持续长大的标题词、一张跨越切点的话术列表、单一 canvas 的内部相位变化)→ 更进一步可参考 composition-patterns.md多场景合并子组合件(内部相位 div)与「单文件 vs 子组合件」取舍,让共享状态留在同一个子组合件内部。

六、放入工程:模块化项目里的背景与媒体分层

当项目是多场景模块化结构(index.html + compositions/<scene>.html)时,全屏运动模式依然成立,但要注意层归属(详见 composition-patterns.md 的 Modular Orchestrator Pattern):

  • 共享背景应属于宿主根(host root),而不是子组合件。 index.html 保持瘦身:根元素直接放置 #bg 全出血层与若干子组合件槽位 <div data-composition-src=...>,槽位视觉场景共用同一个低轨道(如 1),顺序相接;需要交叉淡化时把其中一个放到更高轨道并重叠淡入时长。
  • 媒体必须直属于宿主根。 <video>/<audio> 若被包进子组合件 <template> 或任意包装 <div>,永远不会被 seek/解码,渲染为黑帧——这是 lint/validate/inspect 都不会抓到的盲点。跨场景连续 BGM 以根级 <audio> 存在,轨道索引应明显高于视觉轨道(如 10)。
  • 根时间线保持近空。 所有场景动画在子组合件内部;共享背景的色相过渡这类「全局状态」如需由根时间线驱动,请用全局时间坐标(场景槽 data-start + 场景内偏移),并遵守「每个组合件只注册一条 paused 时间线」的契约。

从 OpenMontage 工程层面看,这一整条 HTML 渲染路径由 hyperframes_compose.py 拥有:当 edit_decisions.render_runtime == "hyperframes" 时,video_compose 会调用它完成工作区物化、hyperframes lint/checkhyperframes render,属于 capability="video_post"、确定性(DETERMINISTIC)的 CORE 级工具;其安装说明强调 HyperFrames CLI 通过 npx hyperframes 获取(npm 包名 hyperframes,内部名 @hyperframes/cli 不在公共 npm 上,会 404),并可用 npx hyperframes doctor 校验环境。


七、验证闭环:动手确认模式写对了

文档规定的验证顺序是静态 → 运行时 → 布局 → 抽帧(命令详见 lint-validate-inspect.md):

npx hyperframes lint                       # 静态契约:同轨重叠、未注册时间线等
npx hyperframes validate                   # headless Chrome 运行时:console 错误、WCAG AA 对比度
npx hyperframes inspect                    # 布局巡检:文字溢出容器/画布、被裁剪等
npx hyperframes snapshot --frames 10       # 抽 10 帧 PNG,肉眼核对共享背景过渡与溢出
npx hyperframes render --quality standard  # 用户批准后才渲染 MP4

针对全屏运动模式,重点核对:

  1. #bg 不应触发任何 Clip 相关告警(它没有 data-start/data-duration);
  2. inspect 若报告溢出,先用 snapshot 判定是否为入场/退场动画的有意中间态,再决定最小范围加 data-layout-allow-overflow
  3. snapshot --at <midpoints> 检查跨场中间帧:背景色过渡是否顺滑连续,内容层是否透明透出背景(而不是带出不透明底色块);
  4. 对动画驱动的组合件,可在组合件旁放 *.motion.json 边车文件,让 inspect 自动断言入场时序、帧内驻留与动画活性,把「看 MP4」变成可自动化的检查(详见 lint-validate-inspect.md 的 Motion verification 一节)。

八、小结

Full-Screen Motion Pattern 是 HyperFrames 确定性渲染模型下处理全帧运动的标准答案:一块非 Clip 的全出血共享背景层承载所有全局视觉状态,由 paused 的可 seek 时间线连续驱动;场景退化为透明的定时内容层,只管自己的局部动画。它把「逐帧 seek 仍要像素级可复现」的硬约束,转化为「背景即运动、场景即透明的分层结构」,同时规避了根元素背景被合成丢弃、display/visibility 与框架显隐竞态、以及滥用 data-layout-allow-overflow 压掉感知检查这三类常见陷阱。

相关延伸阅读:模式总览见 hyperframes-core/SKILL.md 的 References 索引;时间线/轨道规则见 tracks-and-clips.md;单文件与模块化架构取舍见 composition-patterns.md;确定性契约与可动画属性白名单见 determinism-rules.md;CLI 正确性流水线见 lint-validate-inspect.md。在 OpenMontage 中,HyperFrames 技能族的分工(core / animation / creative / media / cli / registry)见 .agents/skills/hyperframes/hyperframes.md 的能力映射。

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

项目优选

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