@taole/giftstage 0.2.2 → 0.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -142,8 +142,20 @@ mounted.destroy();
142
142
  - `preload()`:复用 GiftStage 的 SVGA/Image 缓存并返回引用计数资源租约。
143
143
  - `createPlaybackScope()`:使用 GiftStage 唯一 RAF、逻辑时钟和作用域清理;SVGA、WebCodecs、HTMLVideo 回退与定时图片均按 Scope 绝对时间定位,不叠加 RenderManager 的全局 `dt`。SVGA 的可见帧、`onFrame` 与嵌入音频由同一个绝对时间入口同步,跨帧、seek、循环和暂停恢复会重建正确音频偏移,且 `start()` 前不会触发首帧音频/回调。HTMLVideo 在 Scope 内保持暂停并使用独立实例,显式暂停和页面隐藏期间逻辑时间冻结。
144
144
  - `createMotionTrack()`:接收 8-float TypedArray/SoA 父级轨道。WebGPU 可把它与核心 SVGA 帧表在同一顶点着色器中合成;WebGL2 的 SVGA 内部帧仍可走 GPU Direct/Hybrid,但父级 MotionTrack 继续使用确定性 CPU reference sampler。图片与 WebGL1 同样使用 CPU reference。
145
- - `createParticleBatch()`:WebGPU/WebGL2 使用持久实例缓冲和 GPU 弹道求值;WebGL1 明确不可用,不提供 Canvas2D 粒子后端。粒子统一在媒体礼物之后合成,`zIndex` 只控制粒子批次之间的顺序。
146
- - `stage.capabilities`:插件可在播放前判断实际后端、GPU 轨道媒体范围和粒子能力。
145
+ - `createParticleBatch()`:保留 16-float `ballistic-v1` ABI,WebGPU/WebGL2 使用持久实例缓冲和 GPU 弹道求值;缺省仍在媒体之后合成。
146
+ - `host.createParticleAtlas()` + `scope.createParticleBatchGroup()`:可选 `sprite-v2` 能力。插件上传一次不可变预乘 RGBA8 atlas,再以原子 group 发布多个 24-float sprite batch。group 任一 draw 失败会 abort 整帧并以同一权威时间重放,不会显示 smoke-only 等局部结果。
147
+ - 粒子 `compositeLayer` 支持 `behind-media` / `above-media`;正式帧顺序为 `begin → behind particles → media → above particles → end`,`zIndex` 只在同一 phase 内排序。WebGL1 明确不可用,不提供 Canvas2D 粒子后端。
148
+ - `stage.capabilities`:插件可在播放前判断实际后端、GPU 轨道媒体范围和粒子能力。
149
+
150
+ ### ParticleBatch v2 迁移
151
+
152
+ `stage.capabilities.particles.formats` 包含 `sprite-v2`,且同时具备 `spriteAtlas`、`compositeLayers`、`batchEnvelope`、`atomicBatchGroup` 和 `maxInstancesPerBatch` 时,插件才能启用纹理粒子;不得只按 `apiVersion` 判断。旧核心缺少这些可选字段时继续使用原有 v1 或明确跳过效果。
153
+
154
+ `sprite-v2` 每实例为 24 floats:`0–15` 完全延续 birth/lifetime/弹道/scale/rotation/RGBA,`16–17` 是 CSS 逻辑宽高,`18–19` 是归一化 anchor,`20–23` 是 atlas UV。header 为 8 floats:秒制时间、已求值 opacity、已求值 size、fade mode、`sx/sy` 与两个零 padding。WebGL2 的实例 stride 为 96 bytes、header 为 32 bytes;WebGPU 从 `8 + instanceIndex × 24` 读取。非均匀 backing scale 只在最终顶点应用,不能再用 `sqrt(sx × sy)` 近似 v2 尺寸。
155
+
156
+ atlas descriptor 必须提供 `width × height × 4` 的不可变 `Uint8Array`,声明 `colorSpace:'srgb'` 与 `alphaMode:'premultiplied'`。透明像素 RGB 应为零;shader 不会再次乘采样 alpha。`ParticleAtlasHandle.destroy()` 只释放调用方 lease,存活 group 会保留内部引用;context/device loss 后旧 handle 的 `lost` 为 true,不能在新设备上复活。
157
+
158
+ envelope 使用绝对毫秒半开区间 `[startMs,endMs)`,支持 `linear` / `hold`,边界右连续,因此可以表达中心闪光的瞬时跳变。`setTime()` 仅更新每 batch header,实例 buffer 创建后保持不变;pause 不产生写入,seek 直接求值绝对时间。
147
159
 
148
160
  ## 核心 API
149
161
 
@@ -230,7 +242,7 @@ SVGA 礼物在加载阶段被 `destroy()` / `removeGift()` 时,会取消排队
230
242
  当 SVGA 礼物完成资格分析、帧表上传、原子晋升或发生回退时通知路径变化。除资源与路径字段外,`info` 还包含 `pathState`、`frameTableBytes`、`commandTableBytes`、`drawBatchMode` 和 `drawCompatibleInstanceCount`。
231
243
 
232
244
  - `onRuntimeDiagnostic?: (event) => void`
233
- 接收 frame abort、replay failure、无时钟 retry、运行期 fallback、Clip 协议/网格异常、Stencil 事务失败、Atlas 命令无效、Backend 操作拒绝/隔离、WebGPU uncaptured error、backend loss 和 observer error 等结构化事件。事件只在本地回调,不会由 GiftStage 上传;回调异常会被隔离,不能中断渲染降级事务。
245
+ 接收 frame abort、replay failure、无时钟 retry、frame controller failure、运行期 fallback、Clip 协议/网格异常、Stencil 事务失败、Atlas 命令无效、Particle group 原子失败、Backend 操作拒绝/隔离、WebGPU uncaptured error、backend loss 和 observer error 等结构化事件。事件只在本地回调,不会由 GiftStage 上传;回调异常会被隔离,不能中断渲染降级事务。
234
246
 
235
247
  ### `await stage.ready`
236
248
 
@@ -1,5 +1,5 @@
1
1
  import type { GiftStageOptions, AddGiftOptions, GiftHandle, BackendType, GiftStageRuntimeDiagnostics } from '../types/index.js';
2
- import { type GiftAssetLease, type GiftStageCapabilities, type GiftStagePlugin, type MountedGiftStagePlugin, type PlaybackScope } from '../plugin/types.js';
2
+ import { type GiftAssetLease, type GiftStageCapabilities, type GiftStagePlugin, type MountedGiftStagePlugin, type ParticleAtlasDescriptor, type ParticleAtlasHandle, type PlaybackScope } from '../plugin/types.js';
3
3
  export declare function resolveResourcePipelineConcurrency(explicit: number | undefined, hardwareConcurrency?: number | undefined): number;
4
4
  export declare class GiftStage {
5
5
  private static readonly SVGA_ATLAS_MAX_SIZE;
@@ -197,6 +197,7 @@ export declare class GiftStage {
197
197
  private waitVideoReady;
198
198
  get capabilities(): GiftStageCapabilities;
199
199
  preload(type: 'svga' | 'image', source: string | ArrayBuffer, signal?: AbortSignal): Promise<GiftAssetLease>;
200
+ createParticleAtlas(descriptor: ParticleAtlasDescriptor): Promise<ParticleAtlasHandle>;
200
201
  createPlaybackScope(id?: string): PlaybackScope;
201
202
  mount<TApi>(plugin: GiftStagePlugin<TApi>): Promise<MountedGiftStagePlugin<TApi>>;
202
203
  removeGift(id: string): void;
@@ -4,14 +4,14 @@ import { PostAnimator } from './post-animator.js';
4
4
  import { AudioManager } from './audio-manager.js';
5
5
  import { type WebCodecsAtlasRect } from './webcodecs-video-atlas.js';
6
6
  import type { PlaybackFrameController } from '../plugin/types.js';
7
- import type { ParticleBatchDescriptor, ParticleBatchHandle } from '../plugin/types.js';
7
+ import type { ParticleAtlasDescriptor, ParticleAtlasHandle, ParticleBatchDescriptor, ParticleBatchGroupHandle, ParticleBatchHandle } from '../plugin/types.js';
8
8
  export interface RenderManagerRuntimeDiagnostics {
9
9
  frameAbortCount: number;
10
10
  replayFailureCount: number;
11
11
  retryFrameCount: number;
12
12
  }
13
13
  export interface RenderManagerRuntimeDiagnosticEvent {
14
- type: 'svga-frame-abort' | 'svga-frame-replay-failed' | 'svga-frame-retry' | 'backend-operation-rejected' | 'backend-quarantined' | 'stencil-transaction-failure' | 'clip-protocol-error' | 'clip-mesh-invalid' | 'atlas-command-invalid';
14
+ type: 'svga-frame-abort' | 'svga-frame-replay-failed' | 'svga-frame-retry' | 'backend-operation-rejected' | 'backend-quarantined' | 'stencil-transaction-failure' | 'clip-protocol-error' | 'clip-mesh-invalid' | 'atlas-command-invalid' | 'frame-controller-failure' | 'particle-group-failure';
15
15
  message?: string;
16
16
  }
17
17
  export declare class RenderManager {
@@ -72,6 +72,9 @@ export declare class RenderManager {
72
72
  countCompatibleSVGAInstances(entity: VideoEntity): number;
73
73
  registerFrameController(controller: PlaybackFrameController): () => void;
74
74
  createParticleBatch(descriptor: ParticleBatchDescriptor): ParticleBatchHandle;
75
+ createParticleAtlas(descriptor: ParticleAtlasDescriptor): Promise<ParticleAtlasHandle>;
76
+ createParticleBatchGroup(descriptors: readonly ParticleBatchDescriptor[]): ParticleBatchGroupHandle;
77
+ handleBackendLoss(): void;
75
78
  /**
76
79
  * Reserve a sub-rectangle in the shared WebCodecs atlas (when `webCodecsVideoAtlas` is configured).
77
80
  * Returns null if disabled, full, or size mismatch while the atlas is still in use.