HyperFrames v0.7.22 版本全解:SDK 编辑能力统一解析(resolveEditingAffordances)、CLI 发布与 Lint/Engine 可靠性修复
【免费下载链接】hyperframesWrite HTML. Render video. Built for agents.项目地址: https://gitcode.com/GitHub_Trending/hy/hyperframes
HyperFrames v0.7.22(发布于 2026-06-30)是一次以"编辑器生态开放"为核心的里程碑版本:它把此前内聚在 Studio 内部的"元素可编辑能力判定"抽象成了跨包共享的resolveEditingAffordancesAPI(含核心纯函数与浏览器端 SDK 适配器),让自定义编辑器也能回答"这个元素现在能编辑什么";同时落地了hyperframes publish --public公开发布、hyperframes feedback --file-issue一键提交带可复现链接的工单、Storyboard 视图默认开启,以及一批针对 Lint、Engine 编码与 CLI 可靠性的修复。读完本文,你将掌握 v0.7.22 的新 API 用法、底层判定规则,以及本次所有 CLI/Lint/Engine 变更的来龙去脉。
版本总览:本次更新要解决什么问题
v0.7.22 的发行说明(releases/v0.7.22.md)把这次更新概括为一句话:让@hyperframes/sdk成为一等公民的编辑引擎。围绕这一目标,本次变更分为四类:
- Features(4 项):共享的
resolveEditingAffordances编辑能力解析(核心层 + Studio 重定向 + SDK 浏览器适配器)、publish --public公开发布、feedback --file-issue一键提工单、Storyboard 视图默认开启。 - Fixes(13 项):覆盖 Lint(Three.js ESM 识别、字体与 GSAP 误报)、Engine(H.264/H.265 奇数尺寸补齐)、CLI(错误输出、渲染摘要、HTTP Range、git 不可用兜底等)。
- Docs & Examples(2 项):完整的 SDK 参考文档与指南;明确"根合成时长是编译期常量"这一语义。
下文按"新特性深挖 → 实战集成 → 可靠性修复 → 文档变更"的顺序逐项展开。
核心特性一:resolveEditingAffordances——统一"元素可编辑能力"的单一事实源
在 v0.7.22 之前,"某个元素现在能不能移动、能不能改样式、该显示哪些编辑面板"这类判定逻辑散落在 Studio 内部实现里,SDK 消费者无法复用。本次更新将其收敛为纯函数 + 浏览器适配器 + Studio 复用的三层结构,单一事实源位于核心包:
- 核心纯函数
resolveEditingAffordances/resolveEditingSections:packages/core/src/editing/affordances.ts; - 浏览器端 SDK 适配器
resolveElementAffordances:packages/sdk/src/editing/affordances.ts; - Studio 编辑面板的复用入口(薄封装,保持向后兼容):packages/studio/src/components/editor/domEditingLayers.ts。
从源码注释可以确认设计意图:"Pure, DOM-free editing-affordance resolution. Single source of truth for what the studio's edit panel (and any SDK consumer) surfaces per selected element"。核心层完全不触碰 DOM(不调用getComputedStyle),由调用方把"归一化事实"(实时或静态)喂进来;@hyperframes/sdk/editing子路径才是浏览器专属的"事实提取器",Studio 内部也有一套自己的映射器,两条路径共用同一份核心判定逻辑,避免漂移。
输入:EditableElementFacts事实集合
判定不是直接传 DOM 节点,而是传一组结构化事实(定义见 affordances.ts):
| 事实字段 | 含义 | Studio / SDK 取值来源 |
|---|---|---|
hasStableTarget | 是否存在稳定的补丁目标 | Studio 用selector\|hfId;SDK 模型中恒为true |
tag | 小写标签名 | 如div、video、audio、img |
inlineStyles | kebab-case 内联样式,能力判定只读left/top/width/height/transform | el.style.getPropertyValue(...) |
computedStyles | kebab-case 计算样式,缺失时canMove/canResize默认false | getComputedStyle提取的 6 个属性 |
isCompositionHost/isCompositionRoot | 是否为子合成宿主 / 根合成 | SDK 场景默认false |
isInsideLockedComposition/isMasterView | 是否处于锁定合成内部 / 主视图 | Studio 概念 |
existsInSource | 元素是否存在于源码模型中 | SDK 传modelEl != null |
hasEditableText | 是否有可编辑文本 | Studio 看textFields.length > 0;SDK 看model.text != null |
hasTimingStart | 是否带data-start | SDK 看model.start != null,否则读属性 |
animationCount | 指向该元素的 GSAP tween 数量 | SDK 取model.animationIds.length |
输出一:capabilities——八项能力开关
DomEditCapabilities(affordances.ts)定义了八项布尔能力与一个reasonIfDisabled说明字段:
canSelect:能否选中(脚本生成元素、锁定合成内元素各有差异);canEditStyles:能否直接编辑样式;canCrop:能否做非破坏性的clip-path: inset()裁剪;canMove/canResize:能否直接编辑作者化的left/top/width/height字段;canApplyManualOffset/canApplyManualSize/canApplyManualRotation:画布拖拽/缩放手柄对应的手动变换能力;reasonIfDisabled:当上述能力被禁用时,给出人类可读的原因文案。
输出二:sections——哪些编辑面板适用
EditingSectionApplicability(affordances.ts)回答"选中的元素应该展示哪些检查器分区":text、media、colorGrading、timing、animation、layout、audioFx、style。源码注释给出几条关键设计决策:
<audio>元素从不绘制可见盒,因此layout与style对它恒为false;<hf-audio-group>是混音总线(mixer bus),没有视觉框也没有自身媒体,但携带data-fx-chain——选中它必须能打开 Audio FX 机架,因此audioFx对它为true,同时timing恒为false(总线没有data-start、没有时长,其自动化时钟是合成时间);colorGrading仅对video与img为true,且只是"元素级"能力,消费方仍需自行 AND 自己的功能开关。
核心特性二:SDK 浏览器适配器resolveElementAffordances与实战集成
SDK 侧暴露的入口是resolveElementAffordances(packages/sdk/src/editing/affordances.ts),完整文档见 docs/sdk/guides/editing-affordances.mdx,自@hyperframes/sdk@0.7.22起通过@hyperframes/sdk/editing子路径提供。
签名与入参
import { resolveElementAffordances } from "@hyperframes/sdk/editing"; function resolveElementAffordances( liveEl: HTMLElement, modelEl: Pick<HyperFramesElement, "text" | "animationIds" | "start"> | null, ctx?: AffordanceContext, ): EditingAffordancesliveEl:合成 iframe 中已完成布局的 DOM 元素。适配器内部会对其调用getComputedStyle,因此必须是已挂载到渲染文档中的节点;modelEl:SDK 模型元素(comp.getElement(id)的结果),脚本生成的元素传null——此时existsInSource为false,进入"仅可选中"模式;ctx:Studio 专属概念的上下文(isCompositionHost、isCompositionRoot、isInsideLockedComposition、isMasterView),独立自定义编辑器可整体省略,全部默认false。
端到端示例:按能力条件渲染检查器
官方指南 editing-affordances.mdx 给出了完整的集成路径,配合 openComposition 与 iframe 预览适配器使用:
import { openComposition, createIframePreviewAdapter } from "@hyperframes/sdk"; import { resolveElementAffordances } from "@hyperframes/sdk/editing"; const iframe = document.querySelector<HTMLIFrameElement>("#composition-frame")!; const preview = createIframePreviewAdapter(iframe, (op) => comp.dispatch(op)); const comp = await openComposition(compositionHtml, { preview }); function onElementSelected(hfId: string) { // 1. 从 iframe 取实时 DOM 元素 const liveEl = iframe.contentDocument?.querySelector<HTMLElement>( `[data-hf-id="${hfId}"]`, ); if (!liveEl) return; // 2. 取 SDK 模型元素——脚本生成元素为 null const modelEl = comp.getElement(hfId); // 3. 解析可编辑能力 const { capabilities, sections } = resolveElementAffordances(liveEl, modelEl); // 4. 条件渲染控件 renderInspector({ capabilities, sections, hfId }); } function renderInspector({ capabilities, sections, hfId }) { // 编辑被锁定时展示禁用态提示 if (!capabilities.canEditStyles && capabilities.reasonIfDisabled) { showDisabledBanner(capabilities.reasonIfDisabled); return; } if (capabilities.canEditStyles) showStylePanel(hfId); // 仅对绝对定位且有 px 值的元素展示位置/尺寸字段 if (capabilities.canMove) showPositionFields(hfId); if (capabilities.canResize) showSizeFields(hfId); // 画布拖拽手柄看 canApplyManualOffset,而不是 canMove if (capabilities.canApplyManualOffset) showDragHandles(hfId); // 分区面板 if (sections.text) showTextPanel(hfId); if (sections.media) showMediaPanel(hfId); if (sections.colorGrading && myFeatureFlags.colorGrading) showColorGradingPanel(hfId); if (sections.timing) showTimingPanel(hfId); if (sections.animation) showAnimationPanel(hfId); }关键坑点(Gotchas)
指南 editing-affordances.mdx 明确警告四类易错点:
- 纯浏览器 API:适配器内部调用
getComputedStyle,严禁在 Node、服务端 action 或任何非浏览器路径导入;这正是核心纯解析器与浏览器适配器分层的原因; - 需要已布局的 DOM:
canMove/canResize依赖实时计算出的position/left/top,若在 iframeload事件或首帧渲染前同步调用,两个标志都会是false; null模型 = 仅可选中:脚本生成元素canSelect: true,但所有编辑能力为false且带reasonIfDisabled文案,可保留选中高亮但隐藏编辑控件;canApplyManualOffset≠canMove:canMove要求绝对/固定定位 + 作者化 px 值 + 无 transform 驱动几何;而基于 translate 的画布拖拽(applyDraft/commitPreview流程)以canApplyManualOffset为闸门(参见 Canvas Integration)。
底层判定规则:从核心源码看能力是如何计算出来的
能力解析:resolveCapabilities
核心实现 affordances.ts 按优先级依次短路:
- 无稳定目标或处于锁定合成:整体不可编辑;锁定合成内连
canSelect都为false,reasonIfDisabled给出 "belongs to a locked composition" 或 "could not resolve a stable patch target"; - 脚本生成元素(不在源码中):仅
canSelect: true,文案为 "generated by a script and cannot be edited visually"; - 合成根:
canEditStyles: true,但canCrop/canMove/canResize全部为false——根定义了画布/预览边界,无可裁剪对象; - 常规元素:进入几何判定。
position必须为absolute或fixed,且left/top有可解析的 px 值,且transform为恒等变换,canMove才为true;canResize再要求width或height存在。值得注意canCrop对子合成宿主依然为true(裁剪是持久化在父源中宿主上的视口裁剪),即使其内部样式需要"钻入"编辑。
其中parsePx是唯一的 px 解析器(affordances.ts),Studio 的 domEditingDom 会重新导出它以杜绝两条路径漂移;isIdentityTransform则用容差 0.0001 判定matrix/matrix3d是否为恒等(affordances.ts)。
分区解析:resolveEditingSections
resolveEditingSections 只读标签与事实标志、不读样式,因此已持有 capabilities 的调用方(如 Studio 面板)可以免重复解析几何。核心规则包括:
text:有可编辑文本,且非合成宿主、非锁定合成内;media:video | audio | img;audioFx:仅audio或音频总线;colorGrading:仅video | img;timing:非总线且(有data-start或有动画);animation:animationCount > 0且标签非audio且非总线——<audio>剪辑和总线没有 transform/opacity/box,tween 在它们身上"动不了任何东西",但<audio>保留timing(剪辑照常上时间线)。
测试用例佐证
配套的 affordances.test.ts 用 20+ 个用例锁定这些规则:锁定合成内"不可选且带原因"、脚本生成元素"仅可选"、合成根"可改样式但不可裁剪"、子合成宿主在主视图中"样式锁定但可裁剪"、transform 驱动的几何阻断canMove(matrix(1,0,0,1,5,5)非恒等)、内联left/top覆盖缺失的 computed、computedStyles缺失时canMove/canResize默认 false、audio有 timing 无 animation 而总线两者皆无等。这些用例既是行为契约,也可作为自定义编辑器复刻判定时的参考实现。
CLI 新特性:publish --public公开发布
v0.7.22 为hyperframes publish增加了--public标志(实现见 packages/cli/src/commands/publish.ts)。从源码可以确认其语义:
- 默认发布是私有的——"Upload the project to a stable URL (private by default)",
public参数默认false; - 加
--public后,"Make the claimed project public to anyone, not just the claimer",任何人持有 URL 即可观看,无需登录; - 源码中还处理了一个细节:原地重复发布(不带
--public)时不发送任何可见性参数,让服务端保留该目录此前的可见性状态,避免把已公开的项目误降级为私有。
相关示例与说明:
# 私有发布到稳定 URL(默认) hyperframes publish # 发布特定目录 hyperframes publish ./my-video # 让已声明的项目对任何人公开 hyperframes publish --public # 原地更新已发布项目 hyperframes publish --update <url|id> # 发布到共享团队空间 hyperframes publish --space <space-id> # 跳过确认提示(脚本场景) hyperframes publish --yes--update目标解析(parseUpdateTarget,publish.ts)支持从完整 URL、无 scheme 的 URL(new URL会拒绝)、带?query/#hash的链接中提取/p/<id>片段,或直接接受裸 id。对应测试 publish.test.ts 验证了可见性提示、默认入口预检以及"重复发布不擅自声明可见性"等行为。
CLI 新特性:feedback --file-issue一键提交带复现链接的工单
另一个提升反馈闭环的 CLI 特性是hyperframes feedback --file-issue(packages/cli/src/commands/feedback.ts):把当前项目发布为最小复现包,然后打开一个预填好的 GitHub issue 草稿,草稿中包含该公开链接与你的反馈内容,由你审阅后手动提交(不会自动提交)。
hyperframes feedback --rating 3 --comment "GSAP timeline froze" --file-issue源码显示其优雅降级策略:发布复现包失败时返回undefined,工单仍会打开只是不带链接("Filing the issue without a repro link.");并配套--dir(指定要发布为复现包的项目目录)与--yes(跳过发布 + 提工单的确认提示)。提交前会明确告知:提工单会把项目发布到公开 URL。
Studio:Storyboard 视图默认开启
v0.7.22 移除了 Storyboard 视图的特性开关(feature flag),使其默认可用(#1794 与 docs/studio/index.mdx。
Lint 修复:Three.js ESM 识别与两处误报消除
识别通过 ESM URL/路径导入加载的 Three.js
此前 Lint 无法识别通过 ESM URL/路径导入(而非传统 script 标签)加载的 Three.js,会把正常的 Three.js 代码误判。v0.7.22 让 lint 规则能识别这种加载方式(#1805(该文件同时承载 Three.js 识别与 GSAP 重叠 tween 判定)。
font_family_without_font_face:不再误报 system-ui 字体栈与var()
字体规则实现见 packages/lint/src/rules/fonts.ts,本次修复(#1796)围绕两点:
- 系统字体栈:
GENERIC_FAMILIES集合(fonts.ts)现在完整覆盖system-ui、ui-serif、ui-sans-serif、-apple-system、blinkmacsystemfont、inherit/initial/unset/revert等关键字——它们由引擎解析为 OS UI 字体,不是可安装文件,绝不能因缺少@font-face被标记,即使后面跟着通用回退(如-apple-system, system-ui, sans-serif); var()间接引用:normalizeUsedFontName(fonts.ts)对任何带括号的函数 token 返回null——var(--heading)是静态无法解析的间接引用,字面量var(...)不是字体名,标记它是误报;var(--x, 'Inter')这种带回退的写法会在回退部分留下悬空的),同样需要跳过。
此外该规则还有两个已注释的设计细节:先stripCssComments去掉 CSS 注释(防止注释里的}截断@font-face\s*\{[^}]*\}块匹配导致漏看真实font-family,见 #1534 上下文);以及system_font_will_alias规则仅在分布式/Lambda 渲染(options.distributed)下激活——本地渲染时系统字体替换是渲染器按设计工作,不是缺陷。
overlapping_gsap_tweens:不再误报互不相同的未解析目标
overlapping_gsap_tweens是检测同一元素上重叠 GSAP tween 的规则(packages/lint/src/rules/gsap.ts)。此前它会把两个互不相同的未解析选择器当成同一个元素(两者都落到统一的__unresolved__占位符,见 gsap.ts),从而产生"两个不同元素 tween 重叠"的误报。v0.7.22 的修复(#1798)让未解析目标保持各自独立,只有真正解析到同一元素时才判定重叠。
Engine 修复:奇数输出尺寸补齐到偶数
H.264/H.265 编码器对画面宽高有偶数对齐要求。v0.7.22 的 Engine 修复(#1802 与 packages/engine 的源码与测试目录。
其余 CLI 可靠性修复汇总
v0.7.22 还包含一批提升 CLI 可靠性与可用性的修复,全部落在 packages/cli/src:
- 不再打印
[object Object]:validate/inspect 的报错路径改为结构化输出(#1810); - git 不可用时跳过 AI skills 安装:避免在无 git 环境(如 CI 沙箱)中安装 skills 失败阻塞命令(#1803);
- feedback 无渲染时长时不输出:避免记录伪造的时长(#1797);
- 渲染摘要显示输出视频时长而非渲染耗时(#1812);
- 项目媒体以 HTTP Range 方式伺服:让 validate 能读取 WAV 时长(#1811);
- Studio 遥测过滤运行时生成节点:resolver-shadow 遥测不再混入脚本动态生成的节点(#1795)。
示例与文档更新
- SDK 综合参考与指南:本次为 SDK 补齐了完整的参考文档与指南(#1817、docs/sdk/reference 下的 adapters/composition/edit-operations/open-composition/types/utilities,以及 docs/sdk/guides 下的 canvas-integration、editing-affordances、embedded-override-mode、persistence、querying-and-editing、timing-and-animation、undo-redo-and-patches 等指南;
- kinetic-type 示例素材托管:把 kinetic-type A-roll 视频素材托管到仓库内,保证该示例真正可渲染(#1799);
- 语义澄清:根合成的时长是编译期常量,不能通过 script 或
--variables参数在运行时参数化(#1818)——这对在脚本中动态设置合成时长的用户是重要的行为边界。
升级建议与总结
如果你是 SDK 自定义编辑器使用者,v0.7.22 的核心动作是:将@hyperframes/sdk升级到>=0.7.22,从@hyperframes/sdk/editing导入resolveElementAffordances,用它替换自己手写的"元素类型 → 面板"映射,并牢记四条 Gotchas(浏览器专属、需已布局 DOM、null 模型仅可选、拖拽看canApplyManualOffset)。如果你是 CLI 用户,可以立即体验publish --public与feedback --file-issue带来的发布与反馈闭环;如果你在 Lambda 上做分布式渲染,本次的system_font_will_alias语义、奇数尺寸补齐与 git 兜底,都会让链路更稳。Lint 侧的font_family_without_font_face与overlapping_gsap_tweens误报修复,则让hyperframes lint在真实工程(尤其是带框架级样式表与复杂 GSAP 时间线)中的可信度进一步提升。完整的逐版本变更可对比 releases 目录下的版本说明查阅。
【免费下载链接】hyperframesWrite HTML. Render video. Built for agents.项目地址: https://gitcode.com/GitHub_Trending/hy/hyperframes
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考