@taole/giftstage 0.1.34 → 0.1.36

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.
@@ -22,8 +22,16 @@ export declare class WebGL2Backend implements GPUBackend {
22
22
  private videoElementDirectUploadValidated;
23
23
  /** DYNAMIC_DRAW upload target for `svga-instanced-premul` (`FrameJobData` per instance). */
24
24
  private static readonly INST_SVGA_GL_MAX;
25
+ private static readonly INST_SVGA_GL_FLOATS;
26
+ private static readonly INST_SVGA_GL_STRIDE;
25
27
  private static readonly INST_SVGA_GL_BYTES;
26
28
  private instancedSvgaInstanceGLBuffer;
29
+ /** DYNAMIC_DRAW upload target for instanced clip-mask affine transforms. */
30
+ private static readonly INST_CLIP_MASK_GL_MAX;
31
+ private static readonly INST_CLIP_MASK_GL_FLOATS;
32
+ private static readonly INST_CLIP_MASK_GL_STRIDE;
33
+ private static readonly INST_CLIP_MASK_GL_BYTES;
34
+ private instancedClipMaskGLBuffer;
27
35
  /** DYNAMIC_DRAW upload target for `alpha-video-instanced` (rect+atlasRemap+opacity per instance). */
28
36
  private static readonly INST_ALPHA_GL_MAX;
29
37
  private static readonly INST_ALPHA_GL_BYTES;
@@ -81,6 +89,8 @@ export declare class WebGL2Backend implements GPUBackend {
81
89
  private deleteAllVertexArrays;
82
90
  private ensureInstancedSvgaInstanceBuffer;
83
91
  private drawInstancedSvgaGL;
92
+ private ensureInstancedClipMaskBuffer;
93
+ private drawInstancedClipMaskGL;
84
94
  private ensureInstancedAlphaInstanceBuffer;
85
95
  private drawInstancedAlphaGL;
86
96
  private ensureInstancedVapInstanceBuffer;
@@ -85,18 +85,16 @@ export declare class WebGPUBackend implements GPUBackend {
85
85
  private dualTexturedBindGroupCache;
86
86
  /** All instanced pipelines also share one texture layout. */
87
87
  private instancedTextureBindGroupCache;
88
- /** Batched SVGA sprites (FrameJobData packed as 13 floats per instance). */
88
+ /** Batched SVGA sprites (pre-scaled affine, UVs, and packed framebuffer clip rect). */
89
89
  private static readonly SVGA_INSTANCED_MAX;
90
90
  private static readonly SVGA_INSTANCED_STRIDE;
91
+ private static readonly CLIP_MASK_INSTANCED_MAX;
92
+ private static readonly CLIP_MASK_INSTANCED_STRIDE;
91
93
  /** Batched alpha-video (storage instances + projection uniform). */
92
94
  private static readonly ALPHA_INSTANCED_MAX;
93
95
  private static readonly ALPHA_INSTANCED_STRIDE;
94
96
  private static readonly VAP_INSTANCED_MAX;
95
97
  private static readonly VAP_INSTANCED_STRIDE;
96
- /** One draw may bind up to this many bytes of instance storage (max instances × stride). */
97
- private static readonly INSTANCED_SVGA_CHUNK_BYTES;
98
- private static readonly INSTANCED_ALPHA_CHUNK_BYTES;
99
- private static readonly INSTANCED_VAP_CHUNK_BYTES;
100
98
  /**
101
99
  * Multiple `queue.writeBuffer(..., offset 0)` to the same storage buffer before one `submit` only keep the
102
100
  * last write; one shared ring + dynamic offsets keeps all instanced paths non-overlapping until submit.
@@ -107,9 +105,19 @@ export declare class WebGPUBackend implements GPUBackend {
107
105
  private storageBindOffsetAlign;
108
106
  /** Reset in `beginFrame`; all instanced draw types reserve non-overlapping chunks. */
109
107
  private instancedStorageRingOffset;
108
+ /** Grow-only CPU mirror; expands to the frame's actual storage high-water mark. */
109
+ private instancedStorageShadow;
110
+ private instancedStorageShadowDirtyMax;
110
111
  private readonly instancedProjectionCache;
111
112
  private instancedProjectionValid;
113
+ /** Storage range written by the latest instanced clip-mask write pass; reused by its clear. */
114
+ private lastClipMaskStorageBase;
115
+ private lastClipMaskStorageByteLength;
112
116
  private lastInstancedTextureBindGroup;
117
+ private performanceBufferWrites;
118
+ private performanceBufferWriteBytes;
119
+ private performanceStorageBufferWrites;
120
+ private performanceStorageBufferWriteBytes;
113
121
  constructor(canvas: HTMLCanvasElement, adapter: GPUAdapter, wantAntialias?: boolean);
114
122
  init(): Promise<void>;
115
123
  private configureCanvasContext;
@@ -118,10 +126,13 @@ export declare class WebGPUBackend implements GPUBackend {
118
126
  private ensureStencilPipelines;
119
127
  private ensureInstancedProjectionBuffer;
120
128
  private ensureInstancedStorageBuffer;
129
+ private ensureInstancedDataBindGroup;
121
130
  private ensureInstancedSvgaPipeline;
131
+ private ensureInstancedClipMaskPipeline;
122
132
  private ensureInstancedAlphaPipeline;
123
133
  private ensureInstancedVapPipeline;
124
134
  private createInstancedSvgaPipeline;
135
+ private createInstancedClipMaskPipeline;
125
136
  private createVapInstancedPipeline;
126
137
  private createInstancedAlphaVideoPipeline;
127
138
  private createTexturedPipeline;
@@ -130,8 +141,19 @@ export declare class WebGPUBackend implements GPUBackend {
130
141
  stencil?: boolean;
131
142
  }): void;
132
143
  endFrame(): void;
144
+ getPerformanceSnapshot(): {
145
+ bufferWrites: number;
146
+ bufferWriteBytes: number;
147
+ storageBufferWrites: number;
148
+ storageBufferWriteBytes: number;
149
+ };
150
+ resetPerformanceSnapshot(): void;
151
+ private writeBuffer;
133
152
  /** Uploads the touched range of `uniformShadow` in one call — must run before `queue.submit`. */
134
153
  private flushUniformShadow;
154
+ /** Uploads every instanced draw's non-overlapping shadow range in one call before submit. */
155
+ private flushInstancedStorageShadow;
156
+ private writeInstancedStorageShadow;
135
157
  /** Records a per-draw uniform write into the CPU shadow instead of touching the GPU buffer. */
136
158
  private writeUniformShadow;
137
159
  private ensureInstancedProjection;
@@ -167,6 +189,7 @@ export declare class WebGPUBackend implements GPUBackend {
167
189
  draw(cmd: DrawCommand): void;
168
190
  /** One `drawIndexed` with `instanceCount` for all SVGA sprites sharing the same atlas. */
169
191
  private drawInstancedSvga;
192
+ private drawInstancedClipMask;
170
193
  /** One `drawIndexed` with `instanceCount` for all gifts sharing the same video texture (e.g. atlas). */
171
194
  private drawInstancedAlpha;
172
195
  private drawInstancedVap;
@@ -2,7 +2,7 @@
2
2
  * SVGA sprite SoA table: flat frame floats + deduped clip/shapes side tables.
3
3
  * Replaces per-sprite `frames: SVGAFrame[]` object graphs on the hot path.
4
4
  */
5
- import type { SVGAShape, SVGATransform } from '../types';
5
+ import type { SVGAParams, SVGAShape, SVGATransform } from '../types';
6
6
  /** Floats per frame in `frameData`: layoutW, layoutH, a, b, c, d, tx, ty, alpha. */
7
7
  export declare const SPRITE_FRAME_FLOATS = 9;
8
8
  export interface SVGASpriteTable {
@@ -20,6 +20,7 @@ export interface SVGASpriteTable {
20
20
  /** spriteCount × frameCount; -1 = none. */
21
21
  shapesIndex: Int32Array;
22
22
  hasAnyShapes: boolean;
23
+ allFramesInsideViewBox?: boolean;
23
24
  }
24
25
  /** Loose frame shape used when converting from AoS decode (JS proto / fixtures). */
25
26
  export interface SVGAFrameLike {
@@ -55,5 +56,10 @@ export declare function getSpriteClipPath(table: SVGASpriteTable, spriteIndex: n
55
56
  * Resolves shape `keep` chains to shared array references.
56
57
  */
57
58
  export declare function spriteTableFromSprites(sprites: SVGASpriteLike[], frameCountHint?: number): SVGASpriteTable;
59
+ /**
60
+ * Compute the renderer's scissor-elision flag before the entity becomes renderable. Shapes are
61
+ * conservative because their geometry is not represented by the sprite layout rectangle.
62
+ */
63
+ export declare function ensureAllFramesInsideViewBox(params: Pick<SVGAParams, 'viewBoxWidth' | 'viewBoxHeight'>, table: SVGASpriteTable): boolean;
58
64
  /** Empty table used when there are no sprites. */
59
65
  export declare function emptySpriteTable(frameCount?: number): SVGASpriteTable;
@@ -1,20 +1,22 @@
1
1
  import type { VAPConfig, VAPFrameItem } from '../types';
2
2
  export declare function parseVAPConfig(config: string | object): Promise<VAPConfig>;
3
3
  export declare function getVAPFrame(config: VAPConfig, frameIndex: number): VAPFrameItem | undefined;
4
- /**
5
- * Logical content size for layout/aspect (matches visible RGB frame, not full mp4 frame).
6
- * `videoW`/`videoH` often include separate alpha bands; use `w`/`h` or `rgbFrame` w×h.
7
- */
8
- export declare function getVAPContentSize(info: VAPConfig['info']): {
4
+ export interface VAPContentSize {
9
5
  w: number;
10
6
  h: number;
11
- };
7
+ }
12
8
  /**
13
- * Compute normalized UV coordinates for a frame region within the video texture.
9
+ * Logical content size for layout/aspect (matches visible RGB frame, not full mp4 frame).
10
+ * `videoW`/`videoH` often include separate alpha bands; use `w`/`h` or `rgbFrame` w×h.
14
11
  */
15
- export declare function computeVAPUV(region: [number, number, number, number], videoW: number, videoH: number): {
12
+ export declare function getVAPContentSize(info: VAPConfig['info'], out?: VAPContentSize): VAPContentSize;
13
+ export interface VAPUVRect {
16
14
  left: number;
17
15
  right: number;
18
16
  top: number;
19
17
  bottom: number;
20
- };
18
+ }
19
+ /**
20
+ * Compute normalized UV coordinates for a frame region within the video texture.
21
+ */
22
+ export declare function computeVAPUV(region: [number, number, number, number], videoW: number, videoH: number, out?: VAPUVRect): VAPUVRect;
@@ -8,6 +8,9 @@ export declare class ImageRenderer {
8
8
  private projCacheW;
9
9
  private projCacheH;
10
10
  private projCache;
11
+ private readonly texturesScratch;
12
+ private readonly uniformsScratch;
13
+ private readonly drawCommand;
11
14
  private static readonly QUAD_VERTS;
12
15
  private static readonly QUAD_INDICES;
13
16
  drawSlot(backend: GPUBackend, slot: GiftSlot): void;
@@ -12,6 +12,13 @@ export interface ClipMeshCache {
12
12
  w: number;
13
13
  h: number;
14
14
  } | null;
15
+ /** Local-space bounds cached for conservative instanced stencil safety checks. */
16
+ bounds?: {
17
+ x0: number;
18
+ y0: number;
19
+ x1: number;
20
+ y1: number;
21
+ };
15
22
  /** Lazily created static GPU buffers (local-space vertices, transformed via u_transform). */
16
23
  vertexBuf?: GPUBufferHandle | null;
17
24
  indexBuf?: GPUBufferHandle | null;
@@ -59,8 +66,10 @@ export declare class SVGABatchRenderer {
59
66
  * back — each captured entry clones out of it immediately via `.slice()`. */
60
67
  private staticBatchCacheRowScratch;
61
68
  private instancedFrameDataScratch;
69
+ private instancedFrameDataWords;
62
70
  private clipSpriteVertsScratch;
63
71
  private clipSpriteIndicesScratch;
72
+ private clipMaskBatchTransformsScratch;
64
73
  private instancedQuadVB;
65
74
  private instancedQuadIB;
66
75
  private whiteTexture;
@@ -73,10 +82,14 @@ export declare class SVGABatchRenderer {
73
82
  private shapeTransformMat;
74
83
  /** Scissor rect of the slot currently being drawn (canvas pixels), for clip intersection/restore. */
75
84
  private slotScissor;
85
+ private slotClipX0;
86
+ private slotClipY0;
87
+ private slotClipX1;
88
+ private slotClipY1;
76
89
  /**
77
90
  * Whether `slotScissor` is currently the *active* GPU scissor rect (vs. the outer scissor
78
91
  * having been intentionally skipped for a slot that cannot draw outside its own box — see
79
- * `allFramesInsideViewBox`). Drives `restoreSlotScissor`'s fallback target.
92
+ * `spriteTable.allFramesInsideViewBox`). Drives `restoreSlotScissor`'s fallback target.
80
93
  */
81
94
  private slotScissorActive;
82
95
  /**
@@ -92,6 +105,10 @@ export declare class SVGABatchRenderer {
92
105
  /** Reused scratch arrays (consumed synchronously). */
93
106
  private batchSpritesScratch;
94
107
  private drawGroupScratch;
108
+ private sharedSlotLayerWorkPool;
109
+ private sharedSlotLayerWorksScratch;
110
+ private clipLayerBatchPool;
111
+ private clipLayerBatchesScratch;
95
112
  /** Per-entity result of the "any frame has shapes" scan (no-atlas render check). */
96
113
  private entityHasShapesCache;
97
114
  /** 0=no clip, 1=scissor-compatible clips only, 2=stencil required, 255=not analyzed. */
@@ -103,15 +120,6 @@ export declare class SVGABatchRenderer {
103
120
  * resolution always goes through `getClipMesh`'s string cache, so array entries never go stale.
104
121
  */
105
122
  private entityClipMeshArrayCache;
106
- /**
107
- * Per-entity result of scanning every sprite×frame layout AABB (in local viewBox space) to see
108
- * whether it ever draws outside the entity's own viewBox. Entities with vector shapes are
109
- * excluded (`false`) since shape geometry isn't covered by this scan. Used by `flushGroup` to
110
- * skip the redundant outer scissor for contain/fill, non-rotated slots — such slots structurally
111
- * cannot paint outside their own box, so consecutive same-atlas slots can share one scissor-free
112
- * batch run instead of forcing a draw call per slot.
113
- */
114
- private entityAllFramesInsideViewBoxCache;
115
123
  private readonly affineScratch;
116
124
  /**
117
125
  * Reused DrawCommand/uniforms/textures per rendering branch (never allocated per draw).
@@ -142,6 +150,8 @@ export declare class SVGABatchRenderer {
142
150
  private readonly clipMaskTexturesScratch;
143
151
  private readonly clipMaskUniformsScratch;
144
152
  private readonly clipMaskDrawCommand;
153
+ private readonly clipMaskInstancedUniformsScratch;
154
+ private readonly clipMaskInstancedDrawCommand;
145
155
  /**
146
156
  * `drawShapeFrame`'s fill/stroke draw (always the shared white texture). `u_transform`
147
157
  * carries the per-frame sprite x slot transform so the static shape mesh stays on the GPU;
@@ -155,8 +165,17 @@ export declare class SVGABatchRenderer {
155
165
  drawSlot(backend: GPUBackend, slot: GiftSlot): void;
156
166
  drawSlots(backend: GPUBackend, slots: Iterable<GiftSlot>): void;
157
167
  requiresStencil(slots: Iterable<GiftSlot>): boolean;
168
+ /**
169
+ * Returns the target frame only when every clip path referenced by its visible sprites has a
170
+ * resolved cache entry. A miss queues background triangulation and keeps the previous complete
171
+ * frame on screen, preventing a partially built frame from being drawn without clipping.
172
+ */
173
+ private resolveRenderableFrame;
174
+ private isFrameClipReady;
158
175
  private getFrameClipMode;
159
176
  prewarmClipMeshes(entity: Pick<VideoEntity, 'spriteTable'>, options?: SVGAClipPrewarmOptions): Promise<number>;
177
+ prewarmClipMeshesForFrame(entity: Pick<VideoEntity, 'spriteTable'>, frame: number, options?: SVGAClipPrewarmOptions): Promise<number>;
178
+ private collectFrameClipPaths;
160
179
  /** Builds every not-yet-cached path in `paths`, worker-first with a frame-budgeted fallback. */
161
180
  private buildMissingClipMeshes;
162
181
  /**
@@ -171,6 +190,17 @@ export declare class SVGABatchRenderer {
171
190
  hydrateClipMeshes(meshes: SVGAClipMeshMap | null | undefined): void;
172
191
  snapshotClipMeshes(entity: Pick<VideoEntity, 'spriteTable'>): SVGAClipMeshMap;
173
192
  private flushGroup;
193
+ /**
194
+ * Transposes disjoint slots sharing one entity into sprite layers. Reordering across slots is
195
+ * safe because their outer clip bounds do not overlap; order within every slot remains sprite
196
+ * index order. Non-rect clips sharing one mesh become write -> instanced test -> clear.
197
+ */
198
+ private tryFlushDisjointSharedEntityLayers;
199
+ private resetClipLayerBatches;
200
+ private acquireClipLayerBatch;
201
+ private resolveClipTransform;
202
+ private intersectWorkClipRect;
203
+ private drawBatchedClipLayer;
174
204
  private acquireSpriteWork;
175
205
  /**
176
206
  * Like `acquireSpriteWork`, but for a P1-10 static batch cache replay entry: only `handle` and
@@ -178,6 +208,8 @@ export declare class SVGABatchRenderer {
178
208
  * call only reads `work.handle`.
179
209
  */
180
210
  private acquireCachedSpriteWork;
211
+ private updateSlotClipBounds;
212
+ private copyCurrentSlotClipToWork;
181
213
  /** Drop object references so removed slots/entities are not retained by the pool. */
182
214
  private releaseSpriteWorks;
183
215
  /** Snapshot check for a P1-10 static batch cache: any mismatch means rebuild, never a stale hit. */
@@ -201,12 +233,16 @@ export declare class SVGABatchRenderer {
201
233
  private applyClipRectScissor;
202
234
  private restoreSlotScissor;
203
235
  private getClipRect;
236
+ private getClipMeshBounds;
204
237
  private ensureClipMeshBuffers;
205
238
  private packClipTransform;
206
239
  private drawSingleSprite;
207
240
  private clearClipStencil;
208
241
  private rotateTransform;
209
242
  private packFrameData;
243
+ private packInstancedFrameData;
244
+ private packClipCoordinatePair;
245
+ private packFrameDataAt;
210
246
  /** Resolve atlas/override texture into a pooled SpriteWork entry. Returns false when missing. */
211
247
  private resolveSpriteTextureInto;
212
248
  private drawShapeFrame;
@@ -219,14 +255,6 @@ export declare class SVGABatchRenderer {
219
255
  private packShapeTransform;
220
256
  private hasAtlasTexture;
221
257
  private hasRenderableSVGA;
222
- /**
223
- * True when every sprite frame's transformed layout rect stays within the entity's own
224
- * viewBox (with a small epsilon for float error). Computed once per entity and cached — the
225
- * scan touches every sprite×frame combination, which is only affordable as a one-time cost.
226
- * Entities with vector shapes always return `false`: shape geometry has its own coordinate
227
- * system that this scan does not cover, so we conservatively keep per-slot scissoring for them.
228
- */
229
- private allFramesInsideViewBox;
230
258
  private getWhiteTexture;
231
259
  private getShapeMesh;
232
260
  private appendShape;
@@ -15,6 +15,10 @@ export declare class VAPRenderer {
15
15
  private readonly scratchAtlasRemap;
16
16
  private instancePackScratch;
17
17
  private scratchTransform;
18
+ private readonly contentSizeScratch;
19
+ private readonly rgbUVScratch;
20
+ private readonly alphaUVScratch;
21
+ private readonly maskUVScratch;
18
22
  private readonly processedHtmlGatesScratch;
19
23
  private readonly vapVertexScratch;
20
24
  private readonly layoutScratch;
@@ -35,6 +35,10 @@ export declare const glsl: {
35
35
  readonly vert: string;
36
36
  readonly frag: string;
37
37
  };
38
+ readonly clipMaskInstanced: {
39
+ readonly vert: string;
40
+ readonly frag: string;
41
+ };
38
42
  };
39
43
  export declare const wgsl: {
40
44
  readonly svgaBatchPremul: string;
@@ -46,4 +50,5 @@ export declare const wgsl: {
46
50
  readonly alphaVideoInstanced: string;
47
51
  readonly rgbaTextured: string;
48
52
  readonly clipMask: string;
53
+ readonly clipMaskInstanced: string;
49
54
  };
@@ -26,14 +26,16 @@ export interface TextureOpts {
26
26
  sourcePremultiplied?: boolean;
27
27
  }
28
28
  export type ShaderType = 'svga-batch-premul'
29
- /** WebGPU / WebGL2: SVGA premultiplied atlas sprites batched as instances using `FrameJobData` payloads. */
29
+ /** WebGPU / WebGL2: SVGA premultiplied atlas sprites batched as packed instances. */
30
30
  | 'svga-instanced-premul' | 'vap'
31
31
  /** Main-context VAP mixed resource draw: resource texture multiplied by raw-video mask. */
32
32
  | 'vap-mix-overlay'
33
33
  /** WebGPU / WebGL2: batched VAP sharing one texture; see `instanceCount` / `instanceData` (32 floats/instance). */
34
34
  | 'vap-instanced' | 'alpha-video'
35
35
  /** WebGPU: batched draws sharing one texture (e.g. atlas); see `instanceCount` / `instanceData`. */
36
- | 'alpha-video-instanced' | 'rgba-textured' | 'clip-mask';
36
+ | 'alpha-video-instanced' | 'rgba-textured' | 'clip-mask'
37
+ /** WebGPU / WebGL2: one local-space clip mesh transformed by per-instance affine data. */
38
+ | 'clip-mask-instanced';
37
39
  export type StencilMode = 'none' | 'write' | 'test' | 'clear';
38
40
  export interface DrawCommand {
39
41
  shader: ShaderType;
@@ -44,13 +46,15 @@ export interface DrawCommand {
44
46
  uniforms: Record<string, Float32Array | number>;
45
47
  stencil?: StencilMode;
46
48
  /**
47
- * `svga-instanced-premul`: the first `instanceCount * 13` floats are consumed
48
- * (layout + transform + alpha + uv rect).
49
+ * `svga-instanced-premul`: the first `instanceCount * 13` words are consumed
50
+ * (pre-scaled transform, alpha, UV rect, and two packed framebuffer clip pairs).
49
51
  *
50
52
  * `alpha-video-instanced`: the first `instanceCount * 12` floats are consumed
51
53
  * (display rect + atlasRemap + opacity/source-alpha-mode vec4).
52
54
  * `vap-instanced`: the first `instanceCount * 32` floats are consumed
53
55
  * (mat4 + atlasRemap + rgb/alpha rects + opacity/source-alpha-mode vec4).
56
+ * `clip-mask-instanced`: the first `instanceCount * 6` floats are consumed
57
+ * (a, b, c, d, tx, ty affine transform).
54
58
  * Renderers may pass a larger reused scratch array to avoid allocating a subarray view per draw.
55
59
  */
56
60
  instanceCount?: number;
@@ -80,6 +84,15 @@ export interface GPUBackend {
80
84
  clearStencil?(): void;
81
85
  setScissor(x: number, y: number, w: number, h: number): void;
82
86
  resetScissor(): void;
87
+ /** Internal performance-harness diagnostics; absent on backends without native buffer uploads. */
88
+ getPerformanceSnapshot?(): {
89
+ bufferWrites: number;
90
+ bufferWriteBytes: number;
91
+ storageBufferWrites: number;
92
+ storageBufferWriteBytes: number;
93
+ };
94
+ /** Resets the internal performance-harness diagnostics for a new sampling window. */
95
+ resetPerformanceSnapshot?(): void;
83
96
  destroy(): void;
84
97
  }
85
98
  export interface SVGAParams {
@@ -148,6 +161,8 @@ export interface SVGASpriteTable {
148
161
  shapesTable: SVGAShape[][];
149
162
  shapesIndex: Int32Array;
150
163
  hasAnyShapes: boolean;
164
+ /** Internal parser-derived fast-path flag; undefined only for legacy/incomplete data. */
165
+ allFramesInsideViewBox?: boolean;
151
166
  }
152
167
  export interface SVGAAudio {
153
168
  audioKey: string;
@@ -607,6 +622,11 @@ export interface GiftSlot {
607
622
  accumulatedTime: number;
608
623
  lastTickTime: number;
609
624
  loopCount: number;
625
+ /**
626
+ * SVGABatchRenderer internal: most recent frame whose complete set of referenced clip meshes
627
+ * is ready. A later frame with a mesh miss renders this frame until the missing meshes land.
628
+ */
629
+ svgaClipReadyFrame?: number | null;
610
630
  videoEntity: VideoEntity | null;
611
631
  loadAbortController?: AbortController | null;
612
632
  /** HTMLVideoElement finite-playback watchdog; cleared on normal completion or resource release. */
@@ -34,6 +34,8 @@ export declare function decodeH264ToFrames(codec: string, description: ArrayBuff
34
34
  }>;
35
35
  export interface IncrementalH264DecoderCallbacks {
36
36
  onFrame: (index: number, frame: VideoFrame) => void;
37
+ onDecoded?: () => void;
38
+ onDropped?: () => void;
37
39
  onEos?: () => void;
38
40
  onError?: (error: unknown) => void;
39
41
  }
@@ -61,11 +63,13 @@ export declare class IncrementalH264Decoder {
61
63
  private lastPostedMax;
62
64
  private minPosted;
63
65
  private playbackNeedFloor;
66
+ /** Remaining output budget from the latest `ensure`; decremented only when a frame is posted. */
64
67
  private freeSlots;
65
68
  private eosClosed;
66
69
  private pumpScheduled;
67
70
  private pumping;
68
71
  private destroyed;
72
+ private readonly onDecoderDequeue;
69
73
  constructor(decodeOrder: Sample[], presTimes: Float64Array, timescale: number, codec: string, description: ArrayBuffer | undefined, duration: number, callbacks: IncrementalH264DecoderCallbacks, initialNeedIdx: number);
70
74
  /** Raise the decode target and/or update main-thread ring headroom; resumes the pump if idle. */
71
75
  ensure(needIdx: number, freeSlots: number): void;
@@ -1,3 +1,12 @@
1
+ export interface WebCodecsPerformanceSnapshot {
2
+ decodedFrames: number;
3
+ postedFrames: number;
4
+ closedFrames: number;
5
+ residentPeak: number;
6
+ workerMessages: number;
7
+ }
8
+ export declare function resetWebCodecsPerformanceSnapshot(): void;
9
+ export declare function getWebCodecsPerformanceSnapshot(): WebCodecsPerformanceSnapshot;
1
10
  /**
2
11
  * Presentation-index → VideoFrame with bounded size.
3
12
  * Eviction follows the playhead (see {@link setPlaybackHint}) so we keep a window around the
@@ -11,6 +20,7 @@ export declare class VideoFrameRing {
11
20
  private playbackHint;
12
21
  constructor(maxSize: number);
13
22
  setPlaybackHint(idx: number): void;
23
+ private evictConsumedFrames;
14
24
  minKey(): number | undefined;
15
25
  set(idx: number, frame: VideoFrame): void;
16
26
  private evictDownToCapacity;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@taole/giftstage",
3
- "version": "0.1.34",
3
+ "version": "0.1.36",
4
4
  "description": "High-performance WebGPU/WebGL gift animation player unifying SVGA, VAP, AlphaVideo, and images",
5
5
  "type": "module",
6
6
  "main": "dist/gift-stage.cjs.js",