HyperFrames 变量与媒体系统完全指南:声明式参数注入与多层级媒体时间轴解析
【免费下载链接】hyperframesWrite HTML. Render video. Built for agents.项目地址: https://gitcode.com/GitHub_Trending/hy/hyperframes
HyperFrames 以「写 HTML、渲视频」为核心设计,其变量(Variables)与媒体(Media)机制共同决定了「什么从 HTML 外部流入画面」:运行时参数通过data-composition-variables声明并在渲染时被 CLI 覆盖,外部视频/音频则通过<video>/<audio>元素在任意嵌套深度被自动发现与调度。本文以 skills/hyperframes-core/references/variables-and-media.md 为骨架,结合仓库源码与 lint 规则,系统讲解变量声明、声明式绑定、CSS 变量注入、两种 JSON 形状的区分,以及媒体时间轴基准(data-start rebase)、音频混音约束与预览/渲染一致性保障,帮助你在自己的合成(composition)中写出可参数化、可复用的 HTML 视频模板。
一、为什么把变量与媒体放在一起讲
两者虽然独立,但归属同一个问题:控制「从 HTML 外部流入」的内容。变量是运行时参数(标题文案、强调色、图片地址),媒体是外部文件(视频、音频)。它们的共同特征是——值不在 HTML 内部硬编码,而是在预览、渲染、Studio 编辑三个环境里保持一致地解析。理解了这一点,就能理解文档为何将二者归为一组:它们共用同一套作用域链(composition 作用域)与同一套「预览即渲染」的一致性保障机制。
二、变量:从声明到注入的完整链路
2.1 在<html>上声明变量
在<html>元素上通过data-composition-variables声明变量,每条声明需要id、type、label和default:
<html ><img class="clip">const { title, accent } = window.__hyperframes.getVariables(); document.getElementById("title").textContent = title;getVariables返回的是部分类型(Partial<T>),因为并非每个声明变量都有 default、也并非每个覆盖键都已被声明。源码建议调用方自行提供兜底(getVariables.ts):
const { title = "Untitled", theme = "light" } = getVariables<MyVars>();注意:变量在渲染过程中不会变化,所以应在初始化时读取一次,绝不能放进动画 tick 里每帧读取。枚举值越界时运行时会回退到声明默认值并打印runtime_unknown_enum_value告警(getVariables.ts),保证一个坏值永远不会破坏某一帧,同时去重避免 Studio 重挂载时刷屏。
2.4 变量规则速查
- 支持的类型及 Studio 编辑 UI 消费的附加选项:
string— 可选placeholder、maxLengthnumber— 可选min、max、step、unitcolor— 无附加选项boolean— 无附加选项enum—必填options: [{ "value": "...", "label": "..." }, ...]- 此外仓库类型系统还支持
font(对象{name, source}或字符串兜底)与image(对象{url}或字符串兜底),见 packages/core/src/runtime/validateVariables.ts
- 始终提供有用的
default值,这样预览在没有 CLI 覆盖时也能正常工作。 - 子合成实例级覆盖用
data-variable-values='{"title":"Pro"}'写在子合成宿主元素上。 - 渲染期覆盖用
npx hyperframes render --variables '{"title":"Q4 Report"}'或--variables-file。 - CI 中加
--strict-variables:把未声明键、类型不匹配、不在options里的枚举值从警告升级为错误。 - 变量值在初始化时读取一次,不要在动画 tick 中重复读取。
- 媒体调色(color grading)可以在
data-color-gradingJSON 中引用变量:把$gradingPreset或${gradingIntensity}作为整个字段值,运行时会在应用 shader 调整、finishing 细节、模糊/像素化效果与自定义 LUT 之前,从当前 composition 的变量中解析它。
2.5 两种容易混淆的 JSON 形状
这是最常见的踩坑点,务必区分:
data-composition-variables是声明数组(schema):[{id, type, label, default}, ...]--variables和data-variable-values是以 id 为键的值对象(values):{ title: "Q4", accent: "#fff" }
前者的作用是把变量「定义出来」并描述类型;后者的作用是给已定义的变量「赋值」。类型校验只发生在值对象与声明数组比对时(validateVariables.ts):--variables里出现未声明键、或值类型与声明类型不符,才会产生 issue 并在--strict-variables下终止渲染。
三、媒体:任意深度的自动发现与时间轴基准
3.1 媒体元素在任意嵌套深度都可用
<video>/<audio>可以放在任何嵌套深度,包括子合成<template>内部或一个包装<div>里。运行时的发现与解析机制是(见 packages/core/src/runtime/init.ts 中多处document.querySelectorAll("video, audio"),以及第 678、3238 行的closest("[data-composition-id]")):
- 用扁平化的
document.querySelectorAll("video, audio")发现全部媒体元素; - 通过
element.closest("[data-composition-id]")解析每个元素所属的宿主 composition; - 按所有祖先 composition 的绝对起始时间累加 rebase该元素的局部
data-start。
举例:宿主 composition 的 slot 在根时间2,其内部子合成的媒体data-start="2",那么该媒体在根时间轴上从4开始——预览、快照(snapshot)、音轨提取(extraction)与最终渲染四者一致。旧项目如果刻意按根时间写媒体起始,必须给元素加data-hf-media-start-basis="global"标记;绝不能靠「数字是否重叠」去猜基准,新合成一律使用 scene-local 的data-start。如果某个面板渲染后一片空白,应抓取逐帧snapshot并视为渲染阻断问题处理。
3.2 真正的约束在时间轴,不在媒体位置
媒体可以任意摆放,但子合成的时间轴无法触及或驱动宿主元素:无论是document.querySelector("#host-id")还是 gsap 选择器字符串(tl.to("#host-id", …))都无法跨越 composition 边界——子合成时间轴只能驱动自身子树。
因此,如果媒体元素位于宿主根上,它的逐场景运动(缩放/透明度/morph/tilt/breathing)必须写在index.html的 MAIN 时间轴上,使用全局时间(scene-local 时间 + 该场景 slot 的data-start)。更简单的做法是把媒体放进场景子合成内部,让子合成自己的时间轴用 scene-local 时间驱动它。对于没有 perspective 父级的 3D tilt,请在元素上使用 gsap 的transformPerspective。此模式可对照 skills/hyperframes-core/references/composition-patterns.md 中的 archetype B。
3.3 视频必须静音内联,音频必须独立元素
视频元素必须muted且playsinline;即使与视频共用同一个源文件,音频也必须放在独立的<audio>元素上:
<video id="a-roll" class="clip" src="assets/demo.mp4" contenteditable="false">【免费下载链接】hyperframesWrite HTML. Render video. Built for agents.
项目地址: https://gitcode.com/GitHub_Trending/hy/hyperframes创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考