语义 Scene Tree 与 Mounted Entity Tree
Flamo Runtime 同时维护两棵用途不同的树。Semantic Scene Tree 保存 Artifact 节点、instance-scoped 引用和 Scene API 创建节点,是组件脚本可以稳定查询和修改的语义边界。Mounted Entity Tree 表示当前 ECS 中实际绘制、命中、测量和变换的实体;它会随 Variant 切换、Slot 内容替换和 rematerialization 改变。
二者不能共用一个 children API。Tag 需要稳定的精确名称查询,Scroll 需要当前 viewport 的物理内容;如果 scene.findByName() 为了 Scroll 返回 mounted clone,Tag 的 instance-scoped 查询就会在无法描述的物理节点处中断。
如何选择 API
Section titled “如何选择 API”| 需求 | 使用 | 不要使用 |
|---|---|---|
| 按 role、id、selector 或精确名称找节点 | ctx.scene、ctx.role()、ctx.$()/ctx.$$() |
ECS children 或 clone id |
| 修改/删除 Scene 节点并保持组件语义 | RuntimeNode、ctx.scene.move/remove/apply() |
物理 relation 写入 |
| 获取当前 Variant/Slot 的实际 entity | ctx.mounted.resolve(ref) |
从 id 字符串推导 source |
| 获取 viewport 当前 direct children | ctx.mounted.children(ref) |
scene.findByName() 代替物理遍历 |
| 读取当前物理几何和可见性 | ctx.mounted.probe(ref) 或 snapshot 的 snapshot |
设计态 bounds 猜测 |
| 同帧移动 content 与 scrollbar thumb | ctx.setTransformsBatch() |
多个互不协调的逐节点提交 |
ctx.scene.findByName() 精确、区分大小写,保留重复名称,并按确定性的语义树顺序返回。它不会遍历或返回 mounted ECS clone:
const closeIcons = ctx.scene.findByName('tag-close-icon', { scope: ctx.nodeId,});
for (const icon of closeIcons) icon.setCursor('pointer');当前物理内容通过 ctx.mounted 显式读取:
const tree = ctx.mounted.children('viewport');if (!tree || tree.children.length === 0) return;
const content = tree.children[0];const geometry = content.snapshot;
ctx.setTransformsBatch([ { ref: content.entity, x: nextContentX, y: nextContentY }, { ref: 'horizontal-thumb', x: nextThumbX, y: thumbY },]);children() 只返回 direct physical children,不做递归名称搜索。返回的 entity 是 opaque handle;semanticRef/sourceNodeId/instanceRootId 是 Runtime 尽可能恢复的诊断身份,不能反过来把物理 id 当成持久模型。
生命周期与缓存
Section titled “生命周期与缓存”mounted snapshot 带有 revision。Variant、Slot 或 scene mutation 改变 revision 后,应重新 resolve;旧 handle 可能已经退出当前 materialization。适合 Scroll 的热路径是:setup 或 revision 变化时读取 children,pointerdown 时冻结本次手势需要的 handle/几何,pointermove 中只更新纯状态并每帧提交一批 transform,pointerup/cancel/lost capture 时统一收口。
ctx.mountedContent() 是 ctx.mounted.children() 的兼容投影,保留 viewport/contents/primary 结构;新脚本使用 ctx.mounted。无论使用哪一个入口,都不得把物理 entity id 写入 Artifact、Behavior Contract 或项目配置。
事件与透明命中面
Section titled “事件与透明命中面”事件路由使用当前 canonical mounted target,但脚本仍通过 role、精确名称或 semantic ref 声明意图。event.target 和 composedPath() 只属于当前事件事务,不是可持久化身份。
自动隐藏 scrollbar gutter 如果 opacity 为 0 仍需接收 hover/drag,可以显式声明:
gutter.setInteractive({ mode: 'enabled', pointerEvents: 'box-only', hitTestWhenTransparent: true,});这只让 paint opacity 为 0 的可见节点继续参与 hit-test;visible: false、inert、mode: 'disabled' 和 pointerEvents: 'none' 仍是更强的禁用规则。
完整事件与动态代理用法见事件、节点查询与动态代理;API 签名见 Runtime API。