@taole/giftstage 0.1.36 → 0.2.2

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.
Files changed (51) hide show
  1. package/README.md +770 -694
  2. package/dist/core/audio-manager.d.ts +10 -1
  3. package/dist/core/gift-stage.d.ts +63 -1
  4. package/dist/core/index.d.ts +4 -4
  5. package/dist/core/post-animator.d.ts +1 -1
  6. package/dist/core/render-manager.d.ts +55 -6
  7. package/dist/{gift-stage.cjs.js → gift-stage.cjs} +1401 -287
  8. package/dist/gift-stage.es.js +11500 -6094
  9. package/dist/gpu/backend-operation-result.d.ts +6 -0
  10. package/dist/gpu/detect.d.ts +1 -1
  11. package/dist/gpu/index.d.ts +3 -3
  12. package/dist/gpu/webgl1-backend.d.ts +8 -4
  13. package/dist/gpu/webgl2-backend.d.ts +154 -4
  14. package/dist/gpu/webgpu-backend.d.ts +130 -4
  15. package/dist/index.d.ts +36 -27
  16. package/dist/parsers/atlas-builder.d.ts +1 -1
  17. package/dist/parsers/index.d.ts +7 -7
  18. package/dist/parsers/svga-parser-worker-client.d.ts +1 -1
  19. package/dist/parsers/svga-parser.d.ts +1 -1
  20. package/dist/parsers/svga-proto-js.d.ts +1 -1
  21. package/dist/parsers/svga-sprite-table-binary.d.ts +1 -1
  22. package/dist/parsers/svga-sprite-table.d.ts +1 -1
  23. package/dist/parsers/svga-worker-payload-binary.d.ts +3 -3
  24. package/dist/parsers/vap-config-parser.d.ts +1 -1
  25. package/dist/plugin/motion-track.d.ts +19 -0
  26. package/dist/plugin/playback-scope.d.ts +42 -0
  27. package/dist/plugin/types.d.ts +183 -0
  28. package/dist/public.d.ts +2 -0
  29. package/dist/renderers/alpha-video-renderer.d.ts +1 -1
  30. package/dist/renderers/image-renderer.d.ts +1 -1
  31. package/dist/renderers/index.d.ts +4 -4
  32. package/dist/renderers/particle-batch-renderer.d.ts +19 -0
  33. package/dist/renderers/svga-batch-renderer.d.ts +140 -7
  34. package/dist/renderers/vap-renderer.d.ts +1 -1
  35. package/dist/shaders/index.d.ts +20 -0
  36. package/dist/types/index.d.ts +357 -6
  37. package/dist/utils/clip-mesh.d.ts +13 -0
  38. package/dist/utils/gift-object-fit.d.ts +2 -2
  39. package/dist/utils/gift-transform.d.ts +3 -1
  40. package/dist/utils/resource-cache.d.ts +1 -1
  41. package/dist/utils/slot-content.d.ts +1 -1
  42. package/dist/utils/svga-binary-cache.d.ts +2 -2
  43. package/dist/utils/svga-frame-timeline.d.ts +95 -0
  44. package/dist/utils/svga-hybrid-command-table.d.ts +12 -0
  45. package/dist/utils/svga-slot-state-schema.d.ts +28 -0
  46. package/dist/utils/vap-mix-composer.d.ts +1 -1
  47. package/dist/utils/wc-atlas-upload-size.d.ts +1 -1
  48. package/dist/wasm/wasm-bridge.d.ts +1 -1
  49. package/dist/workers/svga-atlas-worker-client.d.ts +1 -1
  50. package/dist/workers/svga-clip-worker-client.d.ts +1 -1
  51. package/package.json +81 -76
@@ -1,5 +1,65 @@
1
1
  export type BackendType = 'webgpu' | 'webgl2' | 'webgl1';
2
- export type BufferUsage = 'vertex' | 'index' | 'uniform';
2
+ /**
3
+ * How an SVGA slot obtains its per-frame transform/alpha state.
4
+ *
5
+ * `gpu-direct` evaluates the complete atlas-sprite frame row in the vertex
6
+ * shader. `gpu-hybrid` keeps the same GPU frame-table evaluation but lets the
7
+ * CPU precompile/schedule shape and clip draws. `cpu-reference` is the
8
+ * deterministic compatibility path.
9
+ */
10
+ export type SVGARenderPath = 'gpu-direct' | 'gpu-hybrid' | 'cpu-reference';
11
+ export type SVGAFrameTimelinePath = SVGARenderPath;
12
+ /** Public policy used by the stage and by an individual gift. */
13
+ export type SVGAFrameEvaluation = 'auto' | 'cpu';
14
+ /** Descriptive alias used by utility APIs. GPU selection is intentionally auto-only. */
15
+ export type SVGAFrameEvaluationStrategy = SVGAFrameEvaluation;
16
+ export type SVGAFrameTimelineStrategy = SVGAFrameEvaluation;
17
+ export type SVGAFrameTimelineTransport = 'storage-buffer' | 'float-texture' | 'unavailable';
18
+ export type ParentMotionMode = 'gpu-table' | 'cpu-reference';
19
+ export type SVGARenderPathState = 'preparing' | 'settled' | 'fallback';
20
+ export type SVGADrawBatchMode = 'multi-slot' | 'per-slot' | 'hybrid-scheduled';
21
+ /** Why a slot did not use the direct SVGA GPU frame-table path. */
22
+ export type SVGARenderFallbackReason = 'device-capability' | 'table-too-large-or-budget' | 'table-preparing' | 'upload-failed' | 'slot-overrides' | 'plan-not-ready-or-unsupported' | 'validation-failed' | 'policy-disabled';
23
+ export type SVGAFrameTimelineFallbackReason = SVGARenderFallbackReason;
24
+ export type GiftStageRuntimeDiagnosticType = 'svga-frame-abort' | 'svga-frame-replay-failed' | 'svga-frame-retry' | 'svga-runtime-fallback' | 'gpu-uncaptured-error' | 'backend-lost' | 'observer-error' | 'clip-protocol-error' | 'clip-mesh-invalid' | 'stencil-transaction-failure' | 'backend-operation-rejected' | 'atlas-command-invalid' | 'backend-quarantined';
25
+ /** One production-safe runtime event. GiftStage never uploads these events. */
26
+ export interface GiftStageRuntimeDiagnosticEvent {
27
+ type: GiftStageRuntimeDiagnosticType;
28
+ timestampMs: number;
29
+ backend: BackendType;
30
+ source?: string | null;
31
+ giftIds?: string[];
32
+ reason?: SVGAFrameTimelineFallbackReason;
33
+ message?: string;
34
+ }
35
+ /** Monotonic diagnostics accumulated for one GiftStage lifetime. */
36
+ export interface GiftStageRuntimeDiagnostics {
37
+ backend: BackendType;
38
+ frameAbortCount: number;
39
+ replayFailureCount: number;
40
+ retryFrameCount: number;
41
+ runtimeFallbackCount: number;
42
+ submittedDrawCalls: number;
43
+ rejectedDrawCalls: number;
44
+ webgpuUncapturedErrorCount: number;
45
+ backendLossCount: number;
46
+ observerErrorCount: number;
47
+ lastEvent: GiftStageRuntimeDiagnosticEvent | null;
48
+ }
49
+ export type BufferUsage = 'vertex' | 'index' | 'uniform' | 'storage';
50
+ /** Stable reason reported when a backend operation cannot be completed. */
51
+ export type BackendOperationFailureReason = 'backend-lost' | 'invalid-command' | 'missing-resource' | 'capacity' | 'validation-error' | 'submission-error';
52
+ /**
53
+ * Explicit result for frame and draw operations. Built-in backends reuse the
54
+ * successful singleton, so the hot draw path does not allocate per command.
55
+ */
56
+ export type BackendOperationResult = {
57
+ readonly submitted: true;
58
+ } | {
59
+ readonly submitted: false;
60
+ readonly reason: BackendOperationFailureReason;
61
+ readonly message?: string;
62
+ };
3
63
  export type GPUBufferSource = ArrayBufferLike | ArrayBufferView;
4
64
  export interface GPUBufferHandle {
5
65
  readonly id: number;
@@ -10,6 +70,110 @@ export interface GPUTextureHandle {
10
70
  readonly width: number;
11
71
  readonly height: number;
12
72
  }
73
+ /** Packed SVGA frame-table layout consumed by the production GPU FastPaths. */
74
+ export declare const SVGA_FRAME_TABLE_FLOATS = 12;
75
+ /** Default cap for one resident SVGA frame table (32 MiB). */
76
+ export declare const SVGA_GPU_FRAME_TABLE_BUDGET_BYTES: number;
77
+ /** Backward/descriptive alias; use the GPU-prefixed name in stage options. */
78
+ export declare const SVGA_FRAME_TABLE_BUDGET_BYTES: number;
79
+ /** Floats per sprite in the immutable UV/page metadata table. */
80
+ export declare const SVGA_SPRITE_METADATA_FLOATS = 8;
81
+ /** Three vec4 values per sparse Hybrid operation, including an optional local clip rect. */
82
+ export declare const SVGA_HYBRID_SPRITE_METADATA_FLOATS = 12;
83
+ export interface SVGAFrameTableCreateOptions {
84
+ /** Number of logical sprites represented by the table. */
85
+ spriteCount: number;
86
+ /** Number of frames represented for each sprite. */
87
+ frameCount: number;
88
+ /** One packed 2-vec4 row per sprite: uvMin/uvMax and atlasPage/flags. */
89
+ spriteMetadata?: Float32Array;
90
+ /** Operation-ordered metadata used by sparse Hybrid texture runs. */
91
+ hybridSpriteMetadata?: Float32Array;
92
+ /** Compatibility alias for backend adapters during the migration. */
93
+ metadata?: Float32Array;
94
+ /** Optional pre-created metadata texture for a WebGL2 adapter. */
95
+ metadataTexture?: GPUTextureHandle;
96
+ /** Number of atlas pages represented by `spriteMetadata`. */
97
+ atlasPageCount?: number;
98
+ /** Optional backend/debug label. */
99
+ label?: string;
100
+ }
101
+ export interface SVGAFrameTableBindingBase {
102
+ readonly spriteCount: number;
103
+ readonly frameCount: number;
104
+ /** Set by the backend when metadata/table planning knows the page count. */
105
+ readonly atlasPageCount?: number;
106
+ /** Packed row width. Always three vec4 values / twelve floats. */
107
+ readonly strideFloats: typeof SVGA_FRAME_TABLE_FLOATS;
108
+ readonly byteLength: number;
109
+ }
110
+ /** WebGPU stores the packed rows in a storage buffer. */
111
+ export interface WebGPUFrameTableBinding extends SVGAFrameTableBindingBase {
112
+ readonly backend: 'webgpu';
113
+ readonly kind: 'webgpu-buffer';
114
+ readonly buffer: GPUBufferHandle;
115
+ readonly spriteMetadataBuffer?: GPUBufferHandle;
116
+ readonly hybridSpriteMetadataBuffer?: GPUBufferHandle;
117
+ }
118
+ /** WebGL2 stores the same rows in a float texture because it has no storage buffer path here. */
119
+ export interface WebGL2FrameTableBinding extends SVGAFrameTableBindingBase {
120
+ readonly backend: 'webgl2';
121
+ readonly kind: 'webgl2-texture';
122
+ readonly texture: GPUTextureHandle;
123
+ readonly spriteMetadataTexture?: GPUTextureHandle;
124
+ readonly hybridSpriteMetadataTexture?: GPUTextureHandle;
125
+ /** Width/height in texels when a backend uses a packed 2D table texture. */
126
+ readonly textureWidth?: number;
127
+ readonly textureHeight?: number;
128
+ }
129
+ export type SVGAFrameTableBinding = WebGPUFrameTableBinding | WebGL2FrameTableBinding;
130
+ /** Public diagnostic state shared by an asset and its active slots. */
131
+ export interface SVGARenderInfo {
132
+ selectedPath: SVGARenderPath;
133
+ /** Explicit alias for the actual core SVGA frame path. */
134
+ svgaFramePath?: SVGARenderPath;
135
+ /** Actual parent-track evaluator when a playback scope has bound one. */
136
+ parentMotionMode?: ParentMotionMode;
137
+ backend: BackendType;
138
+ requested: SVGAFrameEvaluation;
139
+ spriteCount: number;
140
+ frameCount: number;
141
+ /** Number of simultaneously compatible instances included by the planner. */
142
+ compatibleInstanceCount: number;
143
+ /** Number of atlas pages referenced by the planned resource. */
144
+ atlasPageCount: number;
145
+ tableBytes: number;
146
+ /** Resident immutable child-frame table bytes. */
147
+ frameTableBytes?: number;
148
+ /** Resident immutable Hybrid command-table bytes. Zero for Direct. */
149
+ commandTableBytes?: number;
150
+ budgetBytes: number;
151
+ pathState?: SVGARenderPathState;
152
+ drawBatchMode?: SVGADrawBatchMode;
153
+ /** Instances that are compatible with the draw batch containing this slot. */
154
+ drawCompatibleInstanceCount?: number;
155
+ /** Present when the direct path was rejected or policy selected a fallback. */
156
+ fallbackReasons: SVGARenderFallbackReason[];
157
+ /** Primary fallback reason, when the selected path is CPU reference. */
158
+ fallbackReason?: SVGAFrameTimelineFallbackReason;
159
+ }
160
+ export interface SVGARenderPathChangeInfo extends SVGARenderInfo {
161
+ giftId: string;
162
+ }
163
+ /** Extended diagnostic shape retained for the frame-table planner. */
164
+ export interface SVGAFrameTimelineRenderInfo extends SVGARenderInfo {
165
+ /** Alias for `selectedPath` used by frame-table-specific callers. */
166
+ path: SVGAFrameTimelinePath;
167
+ /** Alias for `requested` used by frame-table-specific callers. */
168
+ requestedStrategy: SVGAFrameEvaluation;
169
+ }
170
+ /** Runtime frame-table state. The binding is null until GPU allocation completes. */
171
+ export interface SVGAFrameTableState {
172
+ binding: SVGAFrameTableBinding | null;
173
+ renderInfo: SVGAFrameTimelineRenderInfo;
174
+ currentTimeMs: number;
175
+ frameIndex: number;
176
+ }
13
177
  export interface TextureOpts {
14
178
  width?: number;
15
179
  height?: number;
@@ -27,7 +191,11 @@ export interface TextureOpts {
27
191
  }
28
192
  export type ShaderType = 'svga-batch-premul'
29
193
  /** WebGPU / WebGL2: SVGA premultiplied atlas sprites batched as packed instances. */
30
- | 'svga-instanced-premul' | 'vap'
194
+ | 'svga-instanced-premul' | 'svga-motion-instanced-premul'
195
+ /** GPU frame-table path; backend-specific fields carry slot state. */
196
+ | 'svga-frame-table-instanced-premul' | 'svga-frame-table-shape-premul' | 'svga-frame-table-clip-mask'
197
+ /** Migration alias used by the table-aware renderer. */
198
+ | 'svga-timeline-instanced-premul' | 'vap'
31
199
  /** Main-context VAP mixed resource draw: resource texture multiplied by raw-video mask. */
32
200
  | 'vap-mix-overlay'
33
201
  /** WebGPU / WebGL2: batched VAP sharing one texture; see `instanceCount` / `instanceData` (32 floats/instance). */
@@ -35,7 +203,9 @@ export type ShaderType = 'svga-batch-premul'
35
203
  /** WebGPU: batched draws sharing one texture (e.g. atlas); see `instanceCount` / `instanceData`. */
36
204
  | 'alpha-video-instanced' | 'rgba-textured' | 'clip-mask'
37
205
  /** WebGPU / WebGL2: one local-space clip mesh transformed by per-instance affine data. */
38
- | 'clip-mask-instanced';
206
+ | 'clip-mask-instanced'
207
+ /** WebGPU / WebGL2: immutable ballistic particle instances evaluated in the vertex shader. */
208
+ | 'particle-instanced';
39
209
  export type StencilMode = 'none' | 'write' | 'test' | 'clear';
40
210
  export interface DrawCommand {
41
211
  shader: ShaderType;
@@ -55,24 +225,93 @@ export interface DrawCommand {
55
225
  * (mat4 + atlasRemap + rgb/alpha rects + opacity/source-alpha-mode vec4).
56
226
  * `clip-mask-instanced`: the first `instanceCount * 6` floats are consumed
57
227
  * (a, b, c, d, tx, ty affine transform).
228
+ * `svga-frame-table-instanced-premul` may carry `instanceCount * 16`
229
+ * floats for Hybrid batches spanning multiple slots (parent affine,
230
+ * translate/opacity/frame, clip rect, metadata row/page). The SVGA-local
231
+ * transform and alpha still come from the resident GPU frame table.
58
232
  * Renderers may pass a larger reused scratch array to avoid allocating a subarray view per draw.
59
233
  */
60
234
  instanceCount?: number;
61
235
  instanceData?: Float32Array;
236
+ /** Persistent instance table used by particle batches; avoids re-uploading immutable particles per frame. */
237
+ instanceBuffer?: GPUBufferHandle;
238
+ particleBlend?: 'normal' | 'additive';
239
+ motionTrackBuffer?: GPUBufferHandle;
240
+ motionTrackGlobalsBuffer?: GPUBufferHandle;
241
+ motionTrackSampleCount?: number;
242
+ motionTrackSampleIntervalMs?: number;
243
+ motionTrackTimeMs?: number;
244
+ motionTrackCssScaleX?: number;
245
+ motionTrackCssScaleY?: number;
246
+ /** Parent MotionTrack row selected for this slot; omitted when no parent track is bound. */
247
+ motionTrackIndex?: number;
248
+ /**
249
+ * O(slot) SVGA frame-table state. Immutable frame rows and sprite metadata
250
+ * live in the binding; only the current slot/frame state belongs here.
251
+ */
252
+ svgaFrameTable?: SVGAFrameTableBinding | GPUBufferHandle | GPUTextureHandle | null;
253
+ svgaFrameTableBuffer?: GPUBufferHandle | null;
254
+ svgaFrameTableTexture?: GPUTextureHandle | null;
255
+ svgaSpriteMetadata?: GPUBufferHandle | GPUTextureHandle | null;
256
+ svgaSpriteMetadataBuffer?: GPUBufferHandle | null;
257
+ svgaSpriteMetadataTexture?: GPUTextureHandle | null;
258
+ /** Float stride of the selected metadata table; Direct=8, Hybrid=12. */
259
+ svgaSpriteMetadataStrideFloats?: number;
260
+ /** Canonical table-aware slot fields. */
261
+ svgaFrameIndex?: number;
262
+ svgaSpriteBase?: number;
263
+ /** [parent a,b,c,d,tx,ty,opacity,clip x0,y0,x1,y1]. */
264
+ svgaSlotState?: Float32Array;
265
+ svgaFrameTableFrameCount?: number;
266
+ svgaFrameTableSpriteCount?: number;
267
+ svgaFrameTableFrameIndex?: number;
268
+ svgaFrameTableSpriteBase?: number;
269
+ svgaFrameTableAtlasPage?: number;
270
+ svgaFrameTableParentAffine?: Float32Array;
271
+ svgaFrameTableParentTranslate?: Float32Array;
272
+ svgaFrameTableOpacity?: number;
273
+ svgaFrameTableClipRect?: Float32Array;
274
+ /** Packed slot-state alias used by backend adapters. */
275
+ svgaFrameTableSlotState?: Float32Array;
276
+ /**
277
+ * Compact four-vec4 state per slot for Direct multi-slot draws. The shader
278
+ * derives slot/sprite indices from the GPU instance index, so this array is
279
+ * uploaded once per slot rather than once per visible sprite.
280
+ */
281
+ svgaFrameTableSlotStates?: Float32Array;
282
+ svgaFrameTableSlotStateCount?: number;
283
+ svgaFrameTableSpritesPerSlot?: number;
284
+ /** Monotonic renderer token allowing backends to upload one compact slot block once per frame. */
285
+ svgaFrameTableSlotStateUploadId?: number;
62
286
  }
63
287
  export interface GPUBackend {
64
288
  readonly type: BackendType;
65
289
  readonly canvas: HTMLCanvasElement;
66
290
  /** Maximum supported 2D texture dimension for this backend/device. */
67
291
  readonly maxTextureSize?: number;
292
+ /** Built-in backends set this when an unsubmitted frame can be discarded and replayed. */
293
+ readonly supportsAtomicFrameReplay?: boolean;
68
294
  init(): Promise<void>;
69
295
  beginFrame(options?: {
70
296
  stencil?: boolean;
71
- }): void;
72
- endFrame(): void;
297
+ }): BackendOperationResult;
298
+ endFrame(): BackendOperationResult;
299
+ /** Discards the current unsubmitted frame. */
300
+ abortFrame(): BackendOperationResult;
73
301
  createBuffer(data: GPUBufferSource, usage: BufferUsage): GPUBufferHandle;
74
302
  updateBuffer(handle: GPUBufferHandle, data: GPUBufferSource, offset?: number): void;
75
303
  deleteBuffer(handle: GPUBufferHandle): void;
304
+ /**
305
+ * Creates a resident packed SVGA frame table. Implementations may use a
306
+ * WebGPU storage buffer or a WebGL2 float texture; older backends can omit
307
+ * this optional capability and remain on the CPU reference path.
308
+ *
309
+ * `packedData` contains `spriteCount × frameCount` rows of three vec4s
310
+ * (twelve floats per row), as produced by `packSVGAFrameTable`.
311
+ */
312
+ createSVGAFrameTable?(packedData: Float32Array, options: SVGAFrameTableCreateOptions): SVGAFrameTableBinding;
313
+ /** Releases a frame table returned by `createSVGAFrameTable`. */
314
+ deleteSVGAFrameTable?(binding: SVGAFrameTableBinding): void;
76
315
  createTexture(source: TexImageSource | ArrayBuffer, opts: TextureOpts): GPUTextureHandle;
77
316
  /** Uninitialized RGBA texture (e.g. WebCodecs atlas backing store). */
78
317
  createEmptyTexture(width: number, height: number, opts?: TextureOpts): GPUTextureHandle;
@@ -80,7 +319,7 @@ export interface GPUBackend {
80
319
  /** When `destWidth`/`destHeight` differ from source size, uploads a uniformly scaled copy into the region. */
81
320
  updateTextureRegion(handle: GPUTextureHandle, source: TexImageSource, x: number, y: number, destWidth?: number, destHeight?: number): void;
82
321
  deleteTexture(handle: GPUTextureHandle): void;
83
- draw(cmd: DrawCommand): void;
322
+ draw(cmd: DrawCommand): BackendOperationResult;
84
323
  clearStencil?(): void;
85
324
  setScissor(x: number, y: number, w: number, h: number): void;
86
325
  resetScissor(): void;
@@ -90,9 +329,28 @@ export interface GPUBackend {
90
329
  bufferWriteBytes: number;
91
330
  storageBufferWrites: number;
92
331
  storageBufferWriteBytes: number;
332
+ /** Draw calls that reached the backend's native drawElements/drawIndexed call. */
333
+ submittedDrawCalls?: number;
334
+ /** Draw calls rejected by backend validation before native submission. */
335
+ rejectedDrawCalls?: number;
336
+ /** Dynamic SVGA CPU-reference/slot-state uploads performed by the backend. */
337
+ svgaDynamicUploadWrites?: number;
338
+ svgaDynamicUploadBytes?: number;
93
339
  };
94
340
  /** Resets the internal performance-harness diagnostics for a new sampling window. */
95
341
  resetPerformanceSnapshot?(): void;
342
+ /** Monotonic production diagnostics; unlike performance counters these are never reset. */
343
+ getRuntimeDiagnosticsSnapshot?(): {
344
+ submittedDrawCalls: number;
345
+ rejectedDrawCalls: number;
346
+ webgpuUncapturedErrors: number;
347
+ backendLosses: number;
348
+ };
349
+ /** Internal bridge used by GiftStage to surface asynchronous backend faults. */
350
+ setRuntimeDiagnosticHandler?(handler: ((event: {
351
+ type: 'gpu-uncaptured-error' | 'backend-lost';
352
+ message?: string;
353
+ }) => void) | null): void;
96
354
  destroy(): void;
97
355
  }
98
356
  export interface SVGAParams {
@@ -186,6 +444,12 @@ export interface UVRect {
186
444
  /** Atlas page index. Omitted means page 0 for older single-atlas data. */
187
445
  textureIndex?: number;
188
446
  }
447
+ /** Consecutive sprite range that can share one atlas-page draw. */
448
+ export interface SVGATimelineDrawRun {
449
+ spriteBase: number;
450
+ spriteCount: number;
451
+ textureIndex: number;
452
+ }
189
453
  export interface VideoEntity {
190
454
  params: SVGAParams;
191
455
  spriteTable: SVGASpriteTable;
@@ -194,6 +458,39 @@ export interface VideoEntity {
194
458
  atlasTextureHandles?: GPUTextureHandle[];
195
459
  atlasRects: Map<string, UVRect>;
196
460
  audioBuffers: Map<string, ArrayBuffer>;
461
+ /** Shared immutable GPU frame table for this parsed SVGA asset, when eligible. */
462
+ svgaFrameTableState?: SVGAFrameTableState | null;
463
+ /** Resource-level draw plan preserving sprite order across atlas pages. */
464
+ svgaTimelineDrawRuns?: SVGATimelineDrawRun[];
465
+ /** Immutable Hybrid paint schedule; populated before atomic GPU promotion. */
466
+ svgaHybridCommandTable?: SVGAHybridCommandTable;
467
+ }
468
+ export type SVGAHybridOperationType = 'texture' | 'shape' | 'clip-write' | 'clip-test' | 'clip-clear';
469
+ export interface SVGAHybridOperation {
470
+ type: SVGAHybridOperationType;
471
+ spriteIndex: number;
472
+ atlasPage: number;
473
+ shapeIndex: number;
474
+ clipPathIndex: number;
475
+ }
476
+ /** Resource-level immutable, frame-addressable Hybrid paint schedule. */
477
+ export interface SVGAHybridCommandTable {
478
+ frameOffsets: Uint32Array;
479
+ /** Canonical ID for structurally identical frame command slices. */
480
+ frameScheduleIds: Uint32Array;
481
+ /** Numeric SVGAHybridOperationType code per operation. */
482
+ operations: Uint8Array;
483
+ spriteIndices: Uint32Array;
484
+ /** shapeIndex, clipPathIndex, atlasPage packed as three i32 values per operation. */
485
+ meshReferences: Int32Array;
486
+ /** UV/page/source-sprite rows in operation order for immutable sparse texture draws. */
487
+ spriteMetadata: Float32Array;
488
+ /** Frame-addressable immutable execution runs over the operation arrays. */
489
+ runFrameOffsets: Uint32Array;
490
+ runOperationStarts: Uint32Array;
491
+ runOperationCounts: Uint32Array;
492
+ runTypes: Uint8Array;
493
+ byteLength: number;
197
494
  }
198
495
  export declare const FRAME_DATA_FLOATS = 13;
199
496
  export declare const VERTEX_FLOATS = 9;
@@ -321,6 +618,8 @@ export interface SVGAStaticBatchCache {
321
618
  width: number;
322
619
  height: number;
323
620
  scale: number;
621
+ motionScaleX: number;
622
+ motionScaleY: number;
324
623
  rotation: number;
325
624
  sx: number;
326
625
  sy: number;
@@ -480,6 +779,14 @@ export interface GiftStageOptions {
480
779
  * Default: 2; the worker may temporarily reduce concurrency under load.
481
780
  */
482
781
  svgaWorkerImageDecodeConcurrency?: number;
782
+ /**
783
+ * SVGA frame-animation policy. `auto` selects the GPU direct/hybrid path
784
+ * when the backend and table budget allow it; `cpu` disables frame-table
785
+ * allocation. Default: `auto`.
786
+ */
787
+ svgaFrameEvaluation?: SVGAFrameEvaluation;
788
+ /** Global active-table budget for SVGA GPU frame evaluation. Default: 32 MiB. */
789
+ svgaGpuFrameTableBudgetBytes?: number;
483
790
  /**
484
791
  * Emit one structured parser profile for each actual SVGA parse. Default:
485
792
  * false. Cache hits do not emit a profile.
@@ -501,6 +808,10 @@ export interface GiftStageOptions {
501
808
  * Default: true.
502
809
  */
503
810
  svgaClipPrewarmInWorker?: boolean;
811
+ /** Called when a gift's selected SVGA rendering path changes. */
812
+ onSVGARenderPathChange?: (info: SVGARenderPathChangeInfo) => void;
813
+ /** Receives production runtime diagnostics. GiftStage does not upload these events. */
814
+ onRuntimeDiagnostic?: (event: GiftStageRuntimeDiagnosticEvent) => void;
504
815
  /**
505
816
  * Global web-side concurrent resource pipeline limit (download / parse / image decode).
506
817
  * Omit to auto-derive from `navigator.hardwareConcurrency`.
@@ -512,9 +823,20 @@ export interface GiftStageOptions {
512
823
  export interface AddGiftOptions {
513
824
  type: GiftType;
514
825
  source: string | ArrayBuffer;
826
+ /** Abort pending decode/upload work without affecting other consumers of the same shared asset. */
827
+ signal?: AbortSignal;
828
+ /** Keep media and its timeline paused until the caller explicitly resumes the returned handle. */
829
+ startPaused?: boolean;
830
+ /**
831
+ * @internal PlaybackScope owns this gift's media clock and seeks it from the
832
+ * shared absolute timeline. Ordinary RenderManager deltas must not advance it.
833
+ */
834
+ playbackScopeControlled?: boolean;
515
835
  config?: string | object;
516
836
  /** SVGA imageKey -> replacement source (TexImageSource or generated text). */
517
837
  svgaSlots?: Record<string, SVGASlotContent>;
838
+ /** Per-gift override for the stage-level SVGA frame-animation policy. */
839
+ svgaFrameEvaluation?: SVGAFrameEvaluation;
518
840
  /** VAPX srcTag/srcId -> replacement source (text string, image URL, TexImageSource, or structured text/image). */
519
841
  vapSlots?: Record<string, VAPSlotContent>;
520
842
  /**
@@ -600,6 +922,8 @@ export interface GiftHandle {
600
922
  pause(): void;
601
923
  resume(): void;
602
924
  destroy(): void;
925
+ /** Snapshot of the selected SVGA path and its planner diagnostics. */
926
+ getRenderInfo(): SVGARenderInfo | null;
603
927
  animate(options?: GiftAnimationStep | GiftAnimationStep[]): GiftAnimationChain;
604
928
  }
605
929
  export type GiftState = 'loading' | 'playing' | 'fly' | 'stopped' | 'finished';
@@ -615,13 +939,36 @@ export interface GiftSlot {
615
939
  width: number;
616
940
  height: number;
617
941
  scale: number;
942
+ /** Optional non-uniform parent scale supplied by a plugin motion track. */
943
+ motionScaleX?: number;
944
+ /** Optional non-uniform parent scale supplied by a plugin motion track. */
945
+ motionScaleY?: number;
946
+ /** WebGPU renderer binding for an immutable parent-motion table. */
947
+ motionTrackBinding?: {
948
+ buffer: GPUBufferHandle;
949
+ globalsBuffer: GPUBufferHandle;
950
+ trackIndex: number;
951
+ sampleCount: number;
952
+ sampleIntervalMs: number;
953
+ currentTimeMs: number;
954
+ } | null;
618
955
  opacity: number;
619
956
  rotation?: number;
620
957
  paused: boolean;
958
+ /** @internal True when a PlaybackScope owns the media clock. */
959
+ playbackScopeControlled?: boolean;
960
+ /** @internal Tracks the public/audio frame-0 priming contract. */
961
+ svgaInitialFrameEmitted?: boolean;
621
962
  currentFrame: number;
622
963
  accumulatedTime: number;
623
964
  lastTickTime: number;
624
965
  loopCount: number;
966
+ /** Per-instance SVGA frame-table binding and path diagnostics. */
967
+ svgaFrameTableState?: SVGAFrameTableState | null;
968
+ /** @internal Last draw batching decision, surfaced through getRenderInfo(). */
969
+ svgaDrawBatchMode?: SVGADrawBatchMode;
970
+ /** @internal Number of slots in the last compatible Direct/Hybrid batch. */
971
+ svgaDrawCompatibleInstanceCount?: number;
625
972
  /**
626
973
  * SVGABatchRenderer internal: most recent frame whose complete set of referenced clip meshes
627
974
  * is ready. A later frame with a mesh miss renders this frame until the missing meshes land.
@@ -629,6 +976,8 @@ export interface GiftSlot {
629
976
  svgaClipReadyFrame?: number | null;
630
977
  videoEntity: VideoEntity | null;
631
978
  loadAbortController?: AbortController | null;
979
+ /** Removes the caller AbortSignal bridge installed while loading. */
980
+ detachLoadAbortSignal?: (() => void) | null;
632
981
  /** HTMLVideoElement finite-playback watchdog; cleared on normal completion or resource release. */
633
982
  videoPlaybackWatchdogTimer?: ReturnType<typeof setTimeout> | null;
634
983
  /** Guards the HTMLVideo ended/watchdog race so completion is dispatched exactly once. */
@@ -647,6 +996,8 @@ export interface GiftSlot {
647
996
  releaseWebCodecsPlayback?: (() => void) | null;
648
997
  /** Playback time in seconds for {@link webcodecsPlayback}. */
649
998
  wcPlaybackTime: number;
999
+ /** Per-slot offset from a shared WebCodecs wall clock, used by playback-scope seek. */
1000
+ wcSharedTimeOffset?: number;
650
1001
  videoTextureHandle: GPUTextureHandle | null;
651
1002
  imageTextureHandle?: GPUTextureHandle | null;
652
1003
  releaseSharedImageTexture?: (() => void) | null;
@@ -2,5 +2,18 @@ export interface ClipMeshData {
2
2
  vertices: Float32Array;
3
3
  indices: Uint32Array;
4
4
  }
5
+ /** Returns a stable validation failure, or null for a renderable triangle mesh. */
6
+ export declare function validateClipMeshData(mesh: ClipMeshData): string | null;
5
7
  export type ClipMeshTriangulator = (vertices: Float64Array, polygonStarts: Uint32Array) => Uint32Array | null;
8
+ export type ClipPathGeometryKind = 'empty' | 'fillable' | 'invalid';
9
+ /**
10
+ * Classifies SVG clip geometry before mesh preparation. Canvas/SVG define a
11
+ * MoveTo-only, line-only, duplicate-point, or zero-area clip as an empty clip
12
+ * region; it must hide the sprite rather than degrade to "no clip".
13
+ *
14
+ * A non-collinear contour is deliberately reported as `fillable` even when
15
+ * its signed area is zero (for example a bow-tie). The triangulator/mesh
16
+ * validation remains authoritative for those genuinely malformed contours.
17
+ */
18
+ export declare function classifyClipPathGeometry(clipPath: string): ClipPathGeometryKind;
6
19
  export declare function buildClipMeshFromPath(clipPath: string, triangulator?: ClipMeshTriangulator): ClipMeshData | null;
@@ -1,4 +1,4 @@
1
- import type { GiftObjectFit, GiftSlot } from '../types';
1
+ import type { GiftObjectFit, GiftSlot } from '../types/index.js';
2
2
  /**
3
3
  * Default when `objectFit` is omitted: all gift types use `contain` (uniform fit inside width×height).
4
4
  */
@@ -11,4 +11,4 @@ export interface GiftObjectFitLayout {
11
11
  offsetX: number;
12
12
  offsetY: number;
13
13
  }
14
- export declare function resolveGiftObjectFitLayout(slot: GiftSlot, contentWidth: number, contentHeight: number, out?: GiftObjectFitLayout): GiftObjectFitLayout;
14
+ export declare function resolveGiftObjectFitLayout(slot: GiftSlot, contentWidth: number, contentHeight: number, out?: GiftObjectFitLayout, ignoreMotionScale?: boolean): GiftObjectFitLayout;
@@ -1,4 +1,4 @@
1
- import type { GiftSlot } from '../types';
1
+ import type { GiftSlot } from '../types/index.js';
2
2
  export interface GiftTransformOrigin {
3
3
  x: number;
4
4
  y: number;
@@ -11,6 +11,8 @@ export interface Affine2D {
11
11
  tx: number;
12
12
  ty: number;
13
13
  }
14
+ export declare function effectiveGiftScaleX(slot: GiftSlot): number;
15
+ export declare function effectiveGiftScaleY(slot: GiftSlot): number;
14
16
  /** Resolve the fixed local origin to stage buffer pixels for the slot's current scale. */
15
17
  export declare function resolveGiftTransformOrigin(slot: GiftSlot, out?: GiftTransformOrigin): GiftTransformOrigin;
16
18
  /**
@@ -1,4 +1,4 @@
1
- import type { SVGAWorkerMoviePayload } from '../parsers/svga-parser-worker-client';
1
+ import type { SVGAWorkerMoviePayload } from '../parsers/svga-parser-worker-client.js';
2
2
  type PersistKind = 'arrayBuffer' | 'text';
3
3
  type MemoryKind = PersistKind | 'json' | 'svga-payload' | 'svga-asset';
4
4
  export declare class AsyncLimiter {
@@ -1,4 +1,4 @@
1
- import type { GPUBackend, ResolvedSVGASlotTexture, ResolvedVAPResource, SVGASlotContent, VAPConfig, VAPFrameObj, VAPMixState, VAPSlotContent, VAPSrcItem, VideoEntity } from '../types';
1
+ import type { GPUBackend, ResolvedSVGASlotTexture, ResolvedVAPResource, SVGASlotContent, VAPConfig, VAPFrameObj, VAPMixState, VAPSlotContent, VAPSrcItem, VideoEntity } from '../types/index.js';
2
2
  export declare function resolveSVGASlotTextures(backend: GPUBackend, entity: VideoEntity, slots: Record<string, SVGASlotContent> | undefined, options?: {
3
3
  frameBudgetMs?: number;
4
4
  checkActive?: () => void;
@@ -1,5 +1,5 @@
1
- import type { SVGAParams, SVGAAudio, SVGASpriteTable, UVRect } from '../types';
2
- import type { ClipMeshData } from './clip-mesh';
1
+ import type { SVGAParams, SVGAAudio, SVGASpriteTable, UVRect } from '../types/index.js';
2
+ import type { ClipMeshData } from './clip-mesh.js';
3
3
  export interface SVGACachedAsset {
4
4
  params: SVGAParams;
5
5
  spriteTable: SVGASpriteTable;
@@ -0,0 +1,95 @@
1
+ import type { BackendType, GiftObjectFit, SVGAFrameEvaluation, SVGAFrameTimelineRenderInfo, SVGASpriteTable, UVRect } from '../types/index.js';
2
+ import { SVGA_FRAME_TABLE_BUDGET_BYTES, SVGA_FRAME_TABLE_FLOATS, SVGA_GPU_FRAME_TABLE_BUDGET_BYTES, SVGA_SPRITE_METADATA_FLOATS } from '../types/index.js';
3
+ /** Result of the pure frame-table eligibility check. */
4
+ export interface SVGAFrameTimelineEligibility extends SVGAFrameTimelineRenderInfo {
5
+ /** `true` for either GPU path; `false` means use the CPU reference path. */
6
+ eligible: boolean;
7
+ }
8
+ /**
9
+ * Input accepted by {@link analyzeSVGAFrameTimelineEligibility}.
10
+ *
11
+ * Callers can pass a parsed `spriteTable`, or the counts/flags directly when
12
+ * the asset is represented by a lightweight metadata object. Explicit flags
13
+ * override values read from `spriteTable`.
14
+ */
15
+ export interface SVGAFrameTimelineEligibilityInput {
16
+ backend: BackendType;
17
+ spriteTable?: Pick<SVGASpriteTable, 'spriteCount' | 'frameCount' | 'frameData' | 'hasAnyShapes' | 'clipPaths' | 'clipPathIndex' | 'allFramesInsideViewBox'>;
18
+ spriteCount?: number;
19
+ frameCount?: number;
20
+ /** Optional source length check without retaining the full frame array. */
21
+ frameDataLength?: number;
22
+ hasAnyShapes?: boolean;
23
+ hasClipPaths?: boolean;
24
+ allFramesInsideViewBox?: boolean;
25
+ /** Defaults to true when omitted; false means the asset has no usable atlas. */
26
+ hasAtlas?: boolean;
27
+ hasSlotTextureOverride?: boolean;
28
+ objectFit?: GiftObjectFit;
29
+ hasTransformOrigin?: boolean;
30
+ strategy?: SVGAFrameEvaluation;
31
+ budgetBytes?: number;
32
+ /** Planner has not finished producing an immutable packed table yet. */
33
+ tablePreparing?: boolean;
34
+ /** Backend allocation/upload failed after validation. */
35
+ uploadFailed?: boolean;
36
+ /** Number of compatible active instances currently sharing this plan. */
37
+ compatibleInstanceCount?: number;
38
+ /** Number of atlas pages used by the asset. */
39
+ atlasPageCount?: number;
40
+ }
41
+ /**
42
+ * Packs the nine-float SVGA frame row into three vec4 rows.
43
+ *
44
+ * The first nine values retain the existing layout exactly:
45
+ * `[layoutW, layoutH, a, b]`, `[c, d, tx, ty]`, `[alpha, 0, 0, 0]`.
46
+ * The zero padding makes every row naturally addressable as storage-buffer
47
+ * vec4 data and as RGBA float texels on WebGL2.
48
+ */
49
+ export declare function packSVGAFrameTable(frameData: ArrayLike<number>, output?: Float32Array): Float32Array;
50
+ /** Descriptive alias for callers that want to emphasize the source layout. */
51
+ export declare function packSVGAFrameDataToVec4(frameData: ArrayLike<number>, output?: Float32Array): Float32Array;
52
+ /** Returns the byte size of a packed frame table. */
53
+ export declare function estimateSVGAFrameTableBytes(spriteCount: number, frameCount: number, strideFloats?: number): number;
54
+ /** Checks whether one packed table fits the default or caller-supplied cap. */
55
+ export declare function isSVGAFrameTableWithinBudget(spriteCount: number, frameCount: number, budgetBytes?: number): boolean;
56
+ /** Checks whether a new table can be added to the stage-wide active-table budget. */
57
+ export declare function isSVGAFrameTableBudgetAvailable(activeBytes: number, spriteCount: number, frameCount: number, budgetBytes?: number): boolean;
58
+ export interface SVGASpriteMetadataPackOptions {
59
+ /** Atlas page dimensions in texels, used to normalize UV rectangles. */
60
+ atlasPageSizes?: ReadonlyArray<{
61
+ width: number;
62
+ height: number;
63
+ }>;
64
+ /** Used when all rectangles belong to one known page. */
65
+ fallbackPageSize?: {
66
+ width: number;
67
+ height: number;
68
+ };
69
+ }
70
+ /** Metadata flags stored in the second vec4's `flags` component. */
71
+ export declare const SVGA_SPRITE_METADATA_FLAG_MISSING_RECT = 1;
72
+ /** Hybrid operation carries an axis-aligned clip rectangle in its third vec4. */
73
+ export declare const SVGA_SPRITE_METADATA_FLAG_LOCAL_RECT_CLIP = 2;
74
+ /**
75
+ * Packs one two-vec4 metadata row for every SVGA sprite.
76
+ *
77
+ * `imageKeys` is the sprite-table order and `atlasRects` uses GiftStage's
78
+ * normalized UV convention. The second vec4 stores
79
+ * `[sourceSpriteIndex, atlasPage, flags, 0]`.
80
+ */
81
+ export declare function packSVGASpriteMetadata(imageKeys: readonly string[], atlasRects: ReadonlyMap<string, UVRect>, _options?: SVGASpriteMetadataPackOptions): Float32Array;
82
+ /** Computes the atlas page count represented by sprite metadata inputs. */
83
+ export declare function countSVGASpriteAtlasPages(imageKeys: readonly string[], atlasRects: ReadonlyMap<string, UVRect>): number;
84
+ /**
85
+ * Determines the safe SVGA frame-table path without touching renderer state.
86
+ *
87
+ * Direct mode owns the complete sprite transform and supports the normal
88
+ * object-fit, parent-transform and out-of-viewBox cases. Shape/clip geometry
89
+ * and runtime slot texture overrides remain eligible for `gpu-hybrid`, where
90
+ * CPU draw scheduling can coexist with GPU frame-row evaluation. Invalid
91
+ * data, missing atlas data, unsupported backends and budget overflow use the
92
+ * `cpu-reference` path.
93
+ */
94
+ export declare function analyzeSVGAFrameTimelineEligibility(input: SVGAFrameTimelineEligibilityInput): SVGAFrameTimelineEligibility;
95
+ export { SVGA_FRAME_TABLE_BUDGET_BYTES, SVGA_FRAME_TABLE_FLOATS, SVGA_GPU_FRAME_TABLE_BUDGET_BYTES, SVGA_SPRITE_METADATA_FLOATS, };