Stage(舞台)
| 项 | 内容 |
|---|---|
| 契约版本 | stage@1 |
| 当前状态 | 测试中 |
| 源码目录 | src/core/stage/ |
| 页面定位 | 演出舞台参考:画面如何挂载、立绘如何取值、图层如何合成、合成器如何切换 |
Stage 负责「看得见的部分」:背景、立绘、镜头、过渡与图层顺序。它不解释剧本,也不解码资源;所有资产一律经 Asset 管线取用。
职责
负责:
- 在播放区挂载舞台容器,建立逻辑画面与缩放规则。
- 背景、立绘、镜头与整屏过渡的状态管理。
- 图层合成:背景 → 立绘 → 特效,并允许经机制插槽调整次序。
- 渲染器实现位:合成器、立绘渲染器、背景渲染器、过渡渲染器。
- Canvas 默认渲染与 PixiJS 按需渲染的切换。
- 资源失效后重取与重画。
不负责:
- 不读取或解码资源字节;纹理经
asset:acquire以texture取得。 - 不决定演出何时发生;指令由 ScriptPlay 的 VM 推进、经
script:presentation@1交给 Stage。 - 不播放音频。
- 不实现输入路由与界面导航。
- 不解释
params的内容;它原样交给立绘渲染器。
对外接口
服务
| 名称 | policy | 说明 |
|---|---|---|
stage:bg | trusted | set(vpath|null, { transition?, ms? }) |
stage:cast | trusted | apply({ id, action, asset?, position?, layer?, params?, transition?, ms? }),与 core:cast 同形 |
stage:camera | trusted | apply({ action, params?, ms? }) |
stage:compose | trusted | snapshot() → { bg, cast: [{ id, asset, position, layer, params? }], camera: { zoom, x, y } }(只读) |
机制插槽
| 名称 | policy | 说明 |
|---|---|---|
stage:resolve-effect | trusted | 输入 { name, target, params },输出效果执行者 { run(scene, { target, params, ms, signal }) };输出空即降级 |
stage:resolve-composition | trusted | 输入图层列表 [{ kind, id?, layer, seq }],输出排好序的列表 |
本期无内置效果;stage:resolve-effect 是留给 Mod 的接缝。stage:resolve-composition 只改次序,不新增或删除图层。
通知与实现位
| 名称 | 类别 | policy | 说明 |
|---|---|---|---|
stage:on-transition | 通知 | — | { kind: 'bg'|'cast'|'screen', name, state: 'start'|'end' } |
stage:on-cast-change | 通知 | — | { id, action } |
stage:compositor@1 | 实现位(single) | public | 内置 canvas(默认)与 pixi;{ backend, mount(root, size) → 场景|Promise<场景> } |
stage:cast-renderer@1 | 实现位(multi) | public | 内置 canvas-image、pixi-image;{ backend, kinds, mount, update, unmount } |
stage:bg-renderer@1 | 实现位(multi) | public | 同上 |
stage:transition-renderer@1 | 实现位(multi,按过渡名) | public | 内置 core:fade、core:fade-out、core:fade-in;{ backend(一个或多个), run(scene, { target, from?, to?, ms, signal }) } |
场景为 { layer(kind, order), camera(state, { ms, signal }), screen(opacity), dispose() };渲染器句柄须提供可读写的 opacity。
关键语义
挂载与坐标
- 第一条演出指令到来时,在
platform:host.surface()最前面放一个div.adv-stage,位于对话框之下。 - 逻辑画面为 1280×720,按容器尺寸等比缩放、居中留黑边;横竖屏排布由外壳样式负责。
- 站位
left/center/right为横向 0.25/0.5/0.75;数字 0–1 为立绘水平中心的比例。 show不写站位即center;layer缺省 0。- 立绘按原像素放进逻辑画面、底边对齐画面底边;背景等比铺满、多出部分裁掉。
合成顺序
text
背景层
└─ 立绘层(layer 从小到大;同层按登场先后)
└─ 特效层stage:resolve-composition 在排序前收到 [{ kind, id?, layer, seq }],返回排好序的列表。Stage 不解释排序理由,只按结果合成。
资产类别与渲染器选择
- 资产类别取 VPath 的「类型」段,例如
assets/<ns>/image/...。 image类由 Stage 以as: 'texture'取纹理,并在替换、退场时释放。- 其他类别(如私有 l2d)由渲染器自取,Stage 只传递 VPath。
- 同一后端、同一类别有多个渲染器时,插件条目按登记先后在前,内置在后。
- 没有匹配渲染器时,该立绘保持逻辑状态但不绘制;演出流程不因此中止。
立绘动作
| 动作 | 语义 |
|---|---|
show | 对已在场的视同 change;不写站位即 center |
change | 对不在场的视同 show;可不写 asset,保留现模型 |
hide | 对不在场的不报错 |
move | 对不在场的报 not-found |
params为交给立绘渲染器的对象;Stage 复制后冻结可冻结的部分,不解释内容。含有 typed array 时,渲染器与snapshot()各取独立副本,避免修改数组元素反向污染导演状态或存档;这不表示 typed array 本身已冻结。- 每条指令的
params整体取代上一条,不做深合并。 - 模型不变时只调用渲染器
update,不重挂、不过渡;换模型才重新取图挂载。 hide/move不带params。snapshot()与读档都带上params。
过渡与镜头
- 不写
transition即直接切换;ms缺省 500。 core:fade交叉淡化;core:fade-out/core:fade-in用于整屏黑场(core:transition)。- 同一目标的新指令到来时,正在进行的过渡直接跳到终态,不排队。
- 交给过渡渲染器的
from/to是带读写控制的代理句柄;过渡完成或中止后再写opacity会被忽略并只告警一次。signal用于通知协作取消,不是强制停止;导演在过渡结束后用真实句柄写入最终状态。 - 镜头动作:
shake { amplitude?=12 }、zoom { scale, x?=0.5, y?=0.5 }、pan { x, y }、reset;ms缺省 0。 - 抖动是瞬时表现,不进状态;快照只记录
zoom、x、y。
合成器切换与失效
- 切换
stage:compositor@1条目时,按当前舞台状态整台重建:沿用已取的纹理,恢复镜头与黑幕。 - 舞台记录挂载时的播放区节点;播放区被替换后,即使合成器条目没变也会整台重建,旧节点上的场景会被销毁,不复用到新播放区。
- 立绘操作令牌全局递增;操作失败、立绘撤下或舞台销毁后,已无在场立绘的令牌会清掉,避免失败指令在大量唯一标识下积累状态或与新操作撞号。
asset:on-invalidate命中在场资源时,Stage 重新取用并重画;取不到的立绘保持逻辑状态。- 读档时由 Save 依快照依次调用
stage:bg.set、stage:cast.apply(带params)、stage:camera.apply。
Canvas 与 Pixi
canvas是默认合成器,使用 Canvas 2D;不引入额外依赖。pixi合成器首次挂载时才按需载入pixi.js8.22.0,并先载入pixi.js/unsafe-eval,以便在不放行unsafe-eval的 CSP 下运行。- 两个后端提供同样的服务语义;差异只在绘制实现与可用渲染器条目。
- 后端名称由
stage:compositor@1条目的backend字段声明,立绘/背景/过渡渲染器按backend与类别匹配。
当前实现范围
已完成:
- 四个服务、两个机制插槽、两个通知、四个实现位与内置条目。
- 调度器单元测试用假后端覆盖语义;契约用例在 Node 与系统 Edge 中通过,Edge 中含 canvas 实际绘制、插件渲染器优先与切换到 pixi 整台重建。
- pixi 后端另在带开发 CSP 的页面里实测载入、渲染、镜头与卸载,未触发 CSP 违规。
- 向
script:presentation@1登记core:bg/core:cast/core:camera/core:transition/core:effect的执行者;快进中一律以ms: 0立即完成。
未完成/限制:
- Phase 2 已完成;真实章节在 Windows WebView2 与 Android 各通过 409 项检查,并有 Android 实际显示器画面证据。
- 本期无内置效果,
stage:resolve-effect仅提供接缝。 - 其他类别(如私有 l2d)的渲染器尚未在本仓提供实现,需由插件登记。