首页
/ Hyperframes Studio 组合(Composition)编辑可靠性验收:解析 composition-reliability 最小测试工程

Hyperframes Studio 组合(Composition)编辑可靠性验收:解析 composition-reliability 最小测试工程

2026-09-08 19:08:05作者:薛曦旖Francesca

本篇文章以 Hyperframes Studio 仓库内 packages/studio/tests/e2e/fixtures/composition-reliability/ 目录中的验收夹具说明为主线,剖析这份"无媒体、纯 HTML"的 Studio 工程如何一次性覆盖组合复用、嵌套组合、透明遮罩标题、剪辑碰撞与新轨道放置、跨轨叠层等编辑链路。读完你可以理解 composition-reliability 夹具的验收清单、每个文件的设计意图,以及仓库中对应集成测试是如何以"不改动检入源"的方式守住这些行为的。

一、夹具定位:一段视频工程验证"一整条编辑栈"

在 Hyperframes 的世界里,Studio 的工程本质是 HTML:画布上的每一个剪辑、每一条时间线都是带 data-* 属性的 DOM 节点,编辑操作最终写回 HTML 源码。而"组合编辑是否可靠"正是整条产品栈的地基——组合(composition)可以被实例化为剪辑、可以被嵌套、可以被移动/剪切/撤销,且每一步都必须产生可预期、可复现的源码结果。

composition-reliability 夹具正是为此设计的验收基准工程。README 给出了它的设计约束与验收范围:

Compact, media-free Studio project for validating composition editing as one stack(紧凑、无媒体文件的 Studio 工程,用于把组合编辑作为一整条技术栈来验证)

核心设计目标有五条:

  • 两个**根级宿主(root host)**在不同时间点复用同一个 title-card.html
  • nested-shell.html更深一层托管同一个标题卡,构造嵌套组合场景;
  • 标题卡使用透明 overflow 遮罩包裹可编辑的标题文字;
  • 同一轨道上的相邻剪辑提供干净的碰撞(collision)/"落至新轨道"拖放目标;
  • 一次跨轨道重叠用于验证常规的视觉分层行为。

同时它明确了一种工程纪律:进行浏览器验收前须将整个目录复制到 scratch(临时工作区),验收动作(打开工程、组合插入、单选/多选移动、碰撞放置、重叠分层、剪切、标题颜色/字号、单步撤销)都在副本上进行,仓库内检入的夹具源文件必须保持不变。

二、夹具目录解剖:一个可发布的迷你 Studio 工程

该夹具不是一个零散 HTML 文件,而是一个结构完整的工程根目录(对应一个可被 Studio 打开的组合):

packages/studio/tests/e2e/fixtures/composition-reliability/
├── README.md
├── package.json
├── hyperframes.json
├── index.html                 # 顶层"根组合",1280×720 @ 30fps,时长 12s
└── compositions/
    ├── title-card.html        # 可复用的标题卡组合(480×220)
    └── nested-shell.html      # 嵌套一层托管 title-card 的组合

工程声明文件有两个:

  • package.json 仅含 "name": "composition-reliability-fixture""private": true,避免被误发布;
  • hyperframes.json 声明了工程格式与资源映射(该文件头部还包含 $schemaregistry 键,指向项目官方 schema 与上游 registry;其 paths 字段将组合 HTML 目录映射为资源类别,格式与仓库 schema/hyperframes.json 描述的工程结构对应):
{
  "paths": {
    "blocks": "compositions",
    "components": "compositions/components",
    "assets": "assets"
  }
}

也就是说,compositions/ 下的每个 HTML 被当作组合块(block)源来解析——这正是"打开工程"验收步骤的前提。

三、顶层 index.html:把"验收场景"排版成一条可编辑时间线

index.html 是整个夹具的舞台。根节点是一个组合容器,用 data-* 属性声明画布元信息:

<main id="composition-reliability"
  data-composition-id="composition-reliability"
  data-width="1280" data-height="720"
  data-start="0" data-duration="12" data-fps="30"
  data-no-timeline>

随后六个带 class="clip" 的子节点构成 4 条轨道。把它们的属性汇总如下(这正是验收场景的"排版"):

剪辑 data-composition-src start duration track 画布位置 场景作用
title-host-a compositions/title-card.html 0 4 0 左上 (48,48) 标题卡复用 #1
title-host-b compositions/title-card.html 4 4 0 右上 (600,48) 同一组合再次实例化 #2
nested-host compositions/nested-shell.html 2 6 1 左下 (48,330) 嵌套一层引用标题卡
collision-a 1 2 2 (600,580) #7357ff 碰撞目标 A
collision-b 3 4 2 (740,580) #ff5c7a 与 A 相邻的碰撞目标 B
layer-overlap 3 4 3 (880,580) 半透明绿 跨轨时间重叠对象

从这份布局可以读出三个刻意的验证维度:

  1. 组合复用title-host-a(0–4s)与 title-host-b(4–8s)在轨道 0 上首尾相接、各自引用 compositions/title-card.html。同一个组合文件被实例化两次且互不干扰,任何编辑都不得在宿主间串扰。
  2. 碰撞/落轨目标collision-acollision-b 位于轨道 2,collision-a 结束的时刻正好是 collision-b 开始(end = start+duration = 3),两者在画布上水平相邻(600–820 与 740–960 存在视觉邻接),为"拖到旁边触发碰撞吸附/落至新轨道"提供了干净的几何目标。
  3. 跨轨重叠分层layer-overlapcollision-b 起点同为 3s,但落在轨道 3,且画布上两者水平范围重叠(880–1100 与 740–960 在 880–960 相交),用于验证"不同轨道同时刻素材如何按轨道上下关系正确分层渲染"。

四、title-card.html:透明 overflow 遮罩包裹可编辑标题

组合被复用的关键前提是"内容可被独立编辑"。标题卡组合 title-card.html 展示了 Hyperframes 组合的标准形态:以 <template> 声明一个 480×220、无内置时间线的组合片段,DOM 结构为"块 → 遮罩 → 标题文字"三层:

<template id="title-card-template">
  <section id="title-card-root" data-composition-id="title-card"
    data-width="480" data-height="220" data-start="0" data-duration="4" data-no-timeline>
    <style>
      #title-card-root { padding: 32px; overflow: hidden; background: #202736; ... }
      .hl-block { width: 100%; }
      .hl-mask { overflow: hidden; background: transparent; }
      .hl-text { color: #f4f7ff; font-size: 52px; line-height: 1.05; }
    </style>
    <div class="hl-block" data-hf-id="title-block">
      <div class="hl-mask" data-hf-id="title-mask">
        <h1 class="hl-text" data-hf-id="title-text">Reliable compositions</h1>
      </div>
    </div>
  </section>
</template>

设计要点在于 .hl-mask:它的 background透明的(因此不会在标题后画出矩形色块),而 overflow: hidden 让超长标题文字在盒子边界被裁剪。换句话说,它是一个"看不见但会裁剪"的容器——这正是"透明 overflow 遮罩"的含义,也使得标题文字的尺寸变化、换行、出格行为都可被稳定观察与测量。文字层则是一个真实的 <h1>data-hf-id="title-text"),承载颜色/字号编辑。

五、nested-shell.html:组合里再放组合

真正的"可靠性"挑战来自嵌套。工程里的第二个组合 nested-shell.html 只有 22 行,却在内部又实例化了一次标题卡:

<template id="nested-shell-template">
  <section id="nested-shell-root" data-composition-id="nested-shell"
    data-width="480" data-height="220" data-start="0" data-duration="6" data-no-timeline">
    <div id="nested-title-host" class="clip"
      data-hf-id="nested-title-host"
      data-composition-id="nested-title-card"
      data-composition-src="title-card.html"
      data-start="1" data-duration="4" data-track-index="0"
      style="position: absolute; inset: 0; ..."></div>
  </section>
</template>

注意它的 data-composition-src="title-card.html"相对本文件的路径(同一目录下),从而在仓库中形成了一条完整的引用链:顶层宿主 → nested-shell 组合 → title-card 组合。运行时需要正确解析"宿主目录级"的相对引用,编辑器则需要保证:在嵌套组合内部发生的编辑落在嵌套组合自己的源码文件里,而不是漏到根组合。这一点与嵌套组合的时间线语义一致——关于嵌套组合内剪辑的分组等编辑规则,可参考 docs/studio/audio-groups.mdx 中对"嵌套组合内剪辑"的相关约束说明。

六、仓库内的自动化守门:集成测试如何验证"编辑分层正确"

除了浏览器人工验收,仓库已经为这份夹具配了一个自动化守门测试compositionReliabilityFixture.integration.test.ts// @vitest-environment jsdom,运行于 jsdom + DOMParser 环境)。

测试第一步就通过固定路径引用夹具目录:

const fixtureDir = join(
  dirname(fileURLToPath(import.meta.url)),
  "../../../tests/e2e/fixtures/composition-reliability",
);

随后用两个用例把 README 的核心主张一一转成断言:

用例一:夹具结构自身的"静态契约"

  • index.html 中引用 compositions/title-card.html 的宿主恰好有两个,且 data-start 依次为 ["0","4"](复用 + 时间错开);
  • nested-shell.html 内部的嵌套宿主存在,且其 data-composition-src="title-card.html" 指向的依赖文件确实存在于 compositions/ 目录(existsSync 校验,堵住引用悬空);
  • 标题模板里 .hl-mask 文本包含 "Reliable compositions",其 <style> 匹配 /\.hl-mask\s*\{[^}]*overflow:\s*hidden;[^}]*background:\s*transparent;/,且文字节点是 H1(透明遮罩拓扑得到机器可读的保证);
  • collision-acollision-b 同轨道,且 A 的 start+duration 恰好等于 B 的 start(相邻不重叠);layer-overlapcollision-b 起点相同但轨道不同(跨轨时间重叠成立)。

用例二:编辑会落到"正确的源码层"

这是整个夹具最有价值的守门点。测试通过 @hyperframes/studio-server/source-mutation 导出的 patchElementInHtml,以及同目录 domEditing 模块导出的 buildDomEditStylePatchOperation,模拟两类真实编辑:

  1. 移动时间线上的宿主:对 index.html 中的 title-host-a 打补丁,把 start 改为 5、duration 改为 2。断言结果是:修改只出现在根工程源码里(data-hf-id="title-host-a"data-start="5"data-duration="2" 均被命中),根源码不出现 data-hf-id="title-text",标题模板源文件也不含新颜色——时间线宿主编辑不会泄漏进被复用的组合模板。
  2. 给标题文字换色:对模板里的 title-text 打一个 style 补丁(color: #12b886)。断言结果是:补丁命中,颜色只写到 title-text 元素自身的 style 上,title-maskstyle 属性保持为空,且重着色后的 HTML 不含根工程宿主标记、根源码也不含该颜色——内容级编辑只落在组合模板层,绝不外溢。

把两个用例合起来看,它验证的正是 README 所说的 "composition editing as one stack":时间线型编辑与内容型编辑虽然走同一条 DOM 补丁管线(patchElementInHtmldata-hf-id 精确寻址),却因为 data-hf-id 归属的文件不同而天然分层,编辑结果永远落在声明它的那份源码里。这与仓库中 packages/studio/src/utils/blockInstaller.tstimelineElement.tstimelineElementHelpers.ts 等模块持续读写 data-composition-src/宿主属性的事实相互印证:data-* 属性就是 Studio 把 HTML 转成可编辑时间线的那份共享契约。

七、验收操作矩阵:复制到 scratch 后逐项演练

README 给出的浏览器验收操作清单与夹具元素的对应关系如下,可直接作为手工验收脚本:

验收操作 在夹具中如何发生
打开(open) 打开工程根 index.html,校验 1280×720 画布与 4 条轨道、6 个剪辑正确物化
组合插入(composition insert) 从组合源插入/复用 title-card,观察新宿主出现在预期时间与轨道
单/多移动(single/multi move) 单选拖动 title-host-a 或框选两个标题宿主一起移动,校验源码 data-start 同步
碰撞放置(collision placement) 把一个剪辑拖向 collision-a/collision-b 邻接处,验证碰撞吸附或"落至新轨道"
重叠分层(overlap layering) 观察 collision-b(轨道 2)与 layer-overlap(轨道 3)同时刻重叠时的视觉层序
剪切(cut) 对标题宿主执行剪切,校验剩余片段与模板不受影响
标题颜色/字号 修改 title-text 的颜色与 font-size,验证只落在模板文件对应元素上
单步撤销(one-step undo) 执行一次撤销,校验所有文件回到操作前状态

每条操作都应遵循同一条前提:先复制目录到 scratch 再动手——因为浏览器验收会实际改写工程文件,检入的夹具源必须保持原样,才能让集成测试与后续验收永远在同一份"标准答案"上运行。

八、小结:一份夹具如何撑起一整套可靠性主张

回看整个 fixture,它的巧妙之处在于用极少的素材完成了极强的覆盖:一个可复用的标题卡、一个嵌套壳、两条纯色碰撞条与一块半透明叠层,就构造出"复用 / 嵌套 / 透明遮罩 / 碰撞落轨 / 跨轨分层"五个正交的编辑风险面;而 compositionReliabilityFixture.integration.test.ts 则把其中"可自动化断言"的部分(结构契约、编辑归属分层)变成了 CI 里每次都跑的守门测试。对于想要为 Studio 贡献组合相关功能或新增验收夹具的开发者,这份 fixture 就是现成的模板:一个能被搜索、被引用、被复制到 scratch 反复演练的最小工程,胜过一段随时可能过期的口头验收清单。

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

项目优选

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