@taole/giftstage 0.1.28 → 0.1.30

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 (74) hide show
  1. package/README.md +89 -36
  2. package/dist/core/audio-manager.d.ts +19 -0
  3. package/dist/core/gift-stage.d.ts +117 -0
  4. package/dist/core/index.d.ts +4 -0
  5. package/dist/core/post-animator.d.ts +43 -0
  6. package/dist/core/render-manager.d.ts +99 -0
  7. package/dist/core/webcodecs-video-atlas.d.ts +30 -0
  8. package/dist/gift-stage.cjs.js +225 -225
  9. package/dist/gift-stage.es.js +2537 -2062
  10. package/dist/gpu/detect.d.ts +2 -0
  11. package/dist/gpu/gl-utils.d.ts +10 -0
  12. package/dist/gpu/index.d.ts +3 -0
  13. package/dist/gpu/webgl1-backend.d.ts +43 -0
  14. package/dist/gpu/webgl2-backend.d.ts +69 -0
  15. package/dist/gpu/webgpu-backend.d.ts +155 -0
  16. package/dist/index.d.ts +27 -0
  17. package/dist/parsers/atlas-builder.d.ts +37 -0
  18. package/dist/parsers/atlas-packing.d.ts +31 -0
  19. package/dist/parsers/index.d.ts +7 -0
  20. package/dist/parsers/inflate-js.d.ts +37 -0
  21. package/dist/parsers/svga-image-decode-worker-client.d.ts +14 -0
  22. package/dist/parsers/svga-parser-worker-client.d.ts +31 -0
  23. package/dist/parsers/svga-parser.d.ts +49 -0
  24. package/dist/parsers/svga-proto-js.d.ts +7 -0
  25. package/dist/parsers/svga-sprite-table-binary.d.ts +36 -0
  26. package/dist/parsers/svga-sprite-table.d.ts +59 -0
  27. package/dist/parsers/svga-worker-payload-binary.d.ts +10 -0
  28. package/dist/parsers/vap-config-parser.d.ts +20 -0
  29. package/dist/renderers/alpha-video-renderer.d.ts +48 -0
  30. package/dist/renderers/image-renderer.d.ts +13 -0
  31. package/dist/renderers/index.d.ts +4 -0
  32. package/dist/renderers/svga-batch-renderer.d.ts +113 -0
  33. package/dist/renderers/vap-renderer.d.ts +58 -0
  34. package/dist/renderers/vertex-builder.d.ts +5 -0
  35. package/dist/shaders/index.d.ts +49 -0
  36. package/dist/types/index.d.ts +699 -0
  37. package/dist/utils/abort.d.ts +3 -0
  38. package/dist/utils/atlas-constants.d.ts +9 -0
  39. package/dist/utils/buffer-pool.d.ts +14 -0
  40. package/dist/utils/canvas-dpr.d.ts +37 -0
  41. package/dist/utils/clip-mesh.d.ts +6 -0
  42. package/dist/utils/detect.d.ts +7 -0
  43. package/dist/utils/easing.d.ts +7 -0
  44. package/dist/utils/frame-budget.d.ts +36 -0
  45. package/dist/utils/gift-object-fit.d.ts +14 -0
  46. package/dist/utils/gift-position.d.ts +5 -0
  47. package/dist/utils/gift-size.d.ts +11 -0
  48. package/dist/utils/gift-transform.d.ts +29 -0
  49. package/dist/utils/html-video-upload-gate.d.ts +35 -0
  50. package/dist/utils/image-source.d.ts +9 -0
  51. package/dist/utils/math.d.ts +9 -0
  52. package/dist/utils/resource-cache.d.ts +20 -0
  53. package/dist/utils/slot-content.d.ts +17 -0
  54. package/dist/utils/svg-path-parser.d.ts +11 -0
  55. package/dist/utils/svga-binary-cache.d.ts +26 -0
  56. package/dist/utils/svga-work-scheduler.d.ts +7 -0
  57. package/dist/utils/triangulate.d.ts +11 -0
  58. package/dist/utils/utf8.d.ts +2 -0
  59. package/dist/utils/vap-mix-composer.d.ts +26 -0
  60. package/dist/utils/wc-atlas-upload-size.d.ts +9 -0
  61. package/dist/video/mp4box-loader.d.ts +2 -0
  62. package/dist/video/webcodecs-mp4-core.d.ts +49 -0
  63. package/dist/video/webcodecs-mp4-playback.d.ts +71 -0
  64. package/dist/video/webcodecs-mp4.worker.d.ts +18 -0
  65. package/dist/wasm/wasm-bridge.d.ts +36 -0
  66. package/dist/workers/parser-worker.d.ts +13 -0
  67. package/dist/workers/svga-atlas-worker-client.d.ts +25 -0
  68. package/dist/workers/svga-atlas-worker.d.ts +37 -0
  69. package/dist/workers/svga-clip-worker-client.d.ts +6 -0
  70. package/dist/workers/svga-clip-worker.d.ts +17 -0
  71. package/dist/workers/svga-image-decode-worker.d.ts +19 -0
  72. package/dist/workers/vertex-worker.d.ts +15 -0
  73. package/dist/workers/worker-scheduler.d.ts +19 -0
  74. package/package.json +7 -5
@@ -0,0 +1,2 @@
1
+ import type { GPUBackend } from '../types';
2
+ export declare function createBackend(canvas: HTMLCanvasElement, preferWebGPU?: boolean, antialias?: boolean, forceWebGL1?: boolean): Promise<GPUBackend>;
@@ -0,0 +1,10 @@
1
+ export declare function compileShader(gl: WebGL2RenderingContext, type: number, source: string): WebGLShader;
2
+ export declare function createProgram(gl: WebGL2RenderingContext, vertSource: string, fragSource: string): WebGLProgram;
3
+ export declare function createTexture(gl: WebGL2RenderingContext, filter?: number, wrap?: number): WebGLTexture;
4
+ /**
5
+ * iOS/iPadOS WebKit has historically been less reliable for direct video-to-WebGL uploads.
6
+ * Keep the canvas bridge there, while other WebGL2 implementations probe the direct path first.
7
+ */
8
+ export declare function preferWebGLVideoCanvasBridge(nav?: Pick<Navigator, 'userAgent' | 'maxTouchPoints'> | null | undefined): boolean;
9
+ export declare function texImageSourceWidth(source: TexImageSource): number;
10
+ export declare function texImageSourceHeight(source: TexImageSource): number;
@@ -0,0 +1,3 @@
1
+ export { createBackend } from './detect';
2
+ export { WebGL2Backend } from './webgl2-backend';
3
+ export { WebGPUBackend } from './webgpu-backend';
@@ -0,0 +1,43 @@
1
+ import type { GPUBackend, GPUBufferHandle, GPUTextureHandle, TextureOpts, BufferUsage, DrawCommand, GPUBufferSource } from '../types';
2
+ export declare class WebGL1Backend implements GPUBackend {
3
+ readonly type: "webgl1";
4
+ readonly canvas: HTMLCanvasElement;
5
+ maxTextureSize: number;
6
+ private antialias;
7
+ private gl;
8
+ private nextId;
9
+ private buffers;
10
+ private textures;
11
+ private programs;
12
+ private cachedDrawProgram;
13
+ private cachedTex0Id;
14
+ private cachedProjectionRef;
15
+ private cachedProjectionShader;
16
+ private videoUploadCanvas;
17
+ private videoUploadCtx;
18
+ private supportsUintIndices;
19
+ constructor(canvas: HTMLCanvasElement, antialias?: boolean);
20
+ init(): Promise<void>;
21
+ private initPrograms;
22
+ private getUniforms;
23
+ beginFrame(): void;
24
+ endFrame(): void;
25
+ private getBufferSourceByteLength;
26
+ private normalizeIndexSource;
27
+ createBuffer(data: GPUBufferSource, usage: BufferUsage): GPUBufferHandle;
28
+ updateBuffer(handle: GPUBufferHandle, data: GPUBufferSource, offset?: number): void;
29
+ deleteBuffer(handle: GPUBufferHandle): void;
30
+ private ensureVideoUploadCanvas;
31
+ private uploadVideoFrameToTexture;
32
+ createTexture(source: TexImageSource | ArrayBuffer, opts: TextureOpts): GPUTextureHandle;
33
+ createEmptyTexture(width: number, height: number, opts?: TextureOpts): GPUTextureHandle;
34
+ updateTexture(handle: GPUTextureHandle, source: TexImageSource): void;
35
+ updateTextureRegion(handle: GPUTextureHandle, source: TexImageSource, x: number, y: number, destWidth?: number, destHeight?: number): void;
36
+ deleteTexture(handle: GPUTextureHandle): void;
37
+ draw(cmd: DrawCommand): void;
38
+ clearStencil(): void;
39
+ setScissor(x: number, y: number, w: number, h: number): void;
40
+ resetScissor(): void;
41
+ private setupAttributes;
42
+ destroy(): void;
43
+ }
@@ -0,0 +1,69 @@
1
+ import type { GPUBackend, GPUBufferHandle, GPUTextureHandle, TextureOpts, BufferUsage, DrawCommand, GPUBufferSource } from '../types';
2
+ export declare class WebGL2Backend implements GPUBackend {
3
+ readonly type: "webgl2";
4
+ readonly canvas: HTMLCanvasElement;
5
+ maxTextureSize: number;
6
+ private antialias;
7
+ private gl;
8
+ private nextId;
9
+ private buffers;
10
+ private textures;
11
+ private programs;
12
+ private vertexArrays;
13
+ /** Per-frame GL state caches (aligned with WebGPU bind-group / uniform write dedup). */
14
+ private cachedDrawProgram;
15
+ private cachedTex0Id;
16
+ private cachedProjectionRef;
17
+ private cachedProjectionShader;
18
+ /** Canvas bridge retained for iOS/iPadOS WebKit and as a one-way runtime fallback. */
19
+ private videoUploadCanvas;
20
+ private videoUploadCtx;
21
+ private videoElementPreferCanvasBridge;
22
+ private videoElementDirectUploadValidated;
23
+ /** DYNAMIC_DRAW upload target for `svga-instanced-premul` (`FrameJobData` per instance). */
24
+ private static readonly INST_SVGA_GL_MAX;
25
+ private static readonly INST_SVGA_GL_BYTES;
26
+ private instancedSvgaInstanceGLBuffer;
27
+ /** DYNAMIC_DRAW upload target for `alpha-video-instanced` (rect+atlasRemap+opacity per instance). */
28
+ private static readonly INST_ALPHA_GL_MAX;
29
+ private static readonly INST_ALPHA_GL_BYTES;
30
+ private instancedAlphaInstanceGLBuffer;
31
+ private static readonly INST_VAP_GL_MAX;
32
+ private static readonly INST_VAP_GL_BYTES;
33
+ private instancedVapInstanceGLBuffer;
34
+ constructor(canvas: HTMLCanvasElement, antialias?: boolean);
35
+ init(): Promise<void>;
36
+ private initPrograms;
37
+ private getUniforms;
38
+ beginFrame(): void;
39
+ endFrame(): void;
40
+ private getBufferSourceByteLength;
41
+ createBuffer(data: GPUBufferSource, usage: BufferUsage): GPUBufferHandle;
42
+ updateBuffer(handle: GPUBufferHandle, data: GPUBufferSource, offset?: number): void;
43
+ deleteBuffer(handle: GPUBufferHandle): void;
44
+ private uploadVideoFrameToTexture;
45
+ createTexture(source: TexImageSource | ArrayBuffer, opts: TextureOpts): GPUTextureHandle;
46
+ createEmptyTexture(width: number, height: number, opts?: TextureOpts): GPUTextureHandle;
47
+ updateTexture(handle: GPUTextureHandle, source: TexImageSource): void;
48
+ updateTextureRegion(handle: GPUTextureHandle, source: TexImageSource, x: number, y: number, destWidth?: number, destHeight?: number): void;
49
+ deleteTexture(handle: GPUTextureHandle): void;
50
+ draw(cmd: DrawCommand): void;
51
+ clearStencil(): void;
52
+ setScissor(x: number, y: number, w: number, h: number): void;
53
+ resetScissor(): void;
54
+ private setupAttributes;
55
+ /**
56
+ * Bind a VAO for the exact shader + vertex/index buffer tuple.
57
+ * Returns true when the VAO was just created and still needs attribute setup.
58
+ */
59
+ private bindCachedVertexArray;
60
+ private deleteVertexArraysForBuffer;
61
+ private deleteAllVertexArrays;
62
+ private ensureInstancedSvgaInstanceBuffer;
63
+ private drawInstancedSvgaGL;
64
+ private ensureInstancedAlphaInstanceBuffer;
65
+ private drawInstancedAlphaGL;
66
+ private ensureInstancedVapInstanceBuffer;
67
+ private drawInstancedVapGL;
68
+ destroy(): void;
69
+ }
@@ -0,0 +1,155 @@
1
+ import type { GPUBackend, GPUBufferHandle, GPUTextureHandle, TextureOpts, BufferUsage, DrawCommand, GPUBufferSource } from '../types';
2
+ export declare const WEBGPU_INSTANCED_STORAGE_RING_BYTES: number;
3
+ export declare function alignWebGPUByteLength(byteLength: number, alignment: number): number;
4
+ export declare class WebGPUBackend implements GPUBackend {
5
+ readonly type: "webgpu";
6
+ readonly canvas: HTMLCanvasElement;
7
+ readonly maxTextureSize: number;
8
+ private adapter;
9
+ private device;
10
+ private context;
11
+ private format;
12
+ private encoder;
13
+ private passEncoder;
14
+ private nextId;
15
+ private buffers;
16
+ private textures;
17
+ private pipelines;
18
+ private sampler;
19
+ private uniformBuffer;
20
+ private texturedBindGroupLayout;
21
+ private dualTexturedBindGroupLayout;
22
+ private instancedTextureBindGroupLayout;
23
+ /** `device.limits.minUniformBufferOffsetAlignment` (typically 256). */
24
+ private uniformSlotStride;
25
+ /** Ring size for per-draw uniforms (`queue.writeBuffer` must not overwrite before draw — see `draw()`). */
26
+ private readonly maxUniformSlots;
27
+ /** Resets each `beginFrame`. */
28
+ private uniformSlotIndex;
29
+ /** Skip redundant `setPipeline` / stencil / VB-IB when drawing many quads with the same geometry. */
30
+ private lastDrawPipeline;
31
+ private lastStencilRef;
32
+ private lastVertexBufferId;
33
+ private lastIndexBufferId;
34
+ /** Single 160-byte upload for textured draws (replaces multiple `writeBuffer` calls). */
35
+ private readonly uniformScratch160;
36
+ /** Single 128-byte upload for uniform-only draws (clip-mask: projection + transform). */
37
+ private readonly uniformScratch128;
38
+ private readonly uniformOpacityScratch;
39
+ private depthStencilTexture;
40
+ private depthStencilView;
41
+ private msaaColorTexture;
42
+ private msaaColorView;
43
+ private lastCanvasWidth;
44
+ private lastCanvasHeight;
45
+ private lastDepthStencilSampleCount;
46
+ /** 1 = off; 4 = multisampled color + resolve to swapchain when `wantAntialias`. */
47
+ private msaaSampleCount;
48
+ private readonly wantAntialias;
49
+ /** Canvas buffer size last passed to configure(); must reconfigure when it changes. */
50
+ private configuredCanvasWidth;
51
+ private configuredCanvasHeight;
52
+ private dummyTexture;
53
+ private dummyTextureView;
54
+ /**
55
+ * Video / `VideoFrame` → 2D canvas → `copyExternalImageToTexture` (GPU-side upload, matches WebGL2 cost model).
56
+ * Avoid `getImageData` here — CPU readback tanks FPS vs WebGL2 `texImage2D`.
57
+ */
58
+ private videoUploadCanvas;
59
+ private videoUploadCtx;
60
+ /**
61
+ * `<video>` can use `copyExternalImageToTexture(video)` directly (no canvas `drawImage`), which is much cheaper
62
+ * than the canvas bridge. If a runtime throws (rare), we fall back once and stay on canvas.
63
+ */
64
+ private videoElementPreferCanvasBridge;
65
+ /** Same for WebCodecs `VideoFrame` — direct copy matches WebGL2 `texImage2D(VideoFrame)` cost. */
66
+ private videoFramePreferCanvasBridge;
67
+ /** Standard textured pipelines share one layout, so one bind group per texture is sufficient. */
68
+ private texturedBindGroupCache;
69
+ /** VAP mixed overlay bind groups, keyed by resource texture id then raw-video texture id. */
70
+ private dualTexturedBindGroupCache;
71
+ /** All instanced pipelines also share one texture layout. */
72
+ private instancedTextureBindGroupCache;
73
+ /** Batched SVGA sprites (FrameJobData packed as 13 floats per instance). */
74
+ private static readonly SVGA_INSTANCED_MAX;
75
+ private static readonly SVGA_INSTANCED_STRIDE;
76
+ /** Batched alpha-video (storage instances + projection uniform). */
77
+ private static readonly ALPHA_INSTANCED_MAX;
78
+ private static readonly ALPHA_INSTANCED_STRIDE;
79
+ private static readonly VAP_INSTANCED_MAX;
80
+ private static readonly VAP_INSTANCED_STRIDE;
81
+ /** One draw may bind up to this many bytes of instance storage (max instances × stride). */
82
+ private static readonly INSTANCED_SVGA_CHUNK_BYTES;
83
+ private static readonly INSTANCED_ALPHA_CHUNK_BYTES;
84
+ private static readonly INSTANCED_VAP_CHUNK_BYTES;
85
+ /**
86
+ * Multiple `queue.writeBuffer(..., offset 0)` to the same storage buffer before one `submit` only keep the
87
+ * last write; one shared ring + dynamic offsets keeps all instanced paths non-overlapping until submit.
88
+ */
89
+ private instancedProjectionBuffer;
90
+ private instancedStorageBuffer;
91
+ /** `device.limits.minStorageBufferOffsetAlignment` (typically 256). */
92
+ private storageBindOffsetAlign;
93
+ /** Reset in `beginFrame`; all instanced draw types reserve non-overlapping chunks. */
94
+ private instancedStorageRingOffset;
95
+ private readonly instancedProjectionCache;
96
+ private instancedProjectionValid;
97
+ private lastInstancedTextureBindGroup;
98
+ constructor(canvas: HTMLCanvasElement, adapter: GPUAdapter, wantAntialias?: boolean);
99
+ init(): Promise<void>;
100
+ private configureCanvasContext;
101
+ private ensureDepthStencil;
102
+ private initPipelines;
103
+ private ensureInstancedProjectionBuffer;
104
+ private ensureInstancedStorageBuffer;
105
+ private ensureInstancedSvgaPipeline;
106
+ private ensureInstancedAlphaPipeline;
107
+ private ensureInstancedVapPipeline;
108
+ private createInstancedSvgaPipeline;
109
+ private createVapInstancedPipeline;
110
+ private createInstancedAlphaVideoPipeline;
111
+ private createTexturedPipeline;
112
+ private createClipMaskPipeline;
113
+ beginFrame(): void;
114
+ endFrame(): void;
115
+ private ensureInstancedProjection;
116
+ private gpuBufferUsage;
117
+ private bufferSourceByteLength;
118
+ private mappedUploadView;
119
+ private writeBufferSource;
120
+ createBuffer(data: GPUBufferSource, usage: BufferUsage): GPUBufferHandle;
121
+ updateBuffer(handle: GPUBufferHandle, data: GPUBufferSource, offset?: number): void;
122
+ deleteBuffer(handle: GPUBufferHandle): void;
123
+ /**
124
+ * Fast path for decoded `<video>` frames: GPU copy from the element (no 2D canvas), aligned with WebGL `texImage2D(video)`.
125
+ */
126
+ private copyHtmlVideoToTextureDirect;
127
+ private copyVideoFrameToTextureDirect;
128
+ /**
129
+ * Fallback: 2D canvas + `copyExternalImageToTexture` (`flipY: true` matches WebGL `UNPACK_FLIP_Y`).
130
+ */
131
+ private drawVideoLikeSourceToTexture;
132
+ /**
133
+ * Upload ImageBitmap / canvas / video frame to a GPU texture.
134
+ * `HTMLVideoElement` and `VideoFrame` prefer direct `copyExternalImageToTexture` when supported.
135
+ */
136
+ private copyImageSourceToTexture;
137
+ createTexture(source: TexImageSource | ArrayBuffer, opts: TextureOpts): GPUTextureHandle;
138
+ createEmptyTexture(width: number, height: number, _opts?: TextureOpts): GPUTextureHandle;
139
+ updateTexture(handle: GPUTextureHandle, source: TexImageSource): void;
140
+ updateTextureRegion(handle: GPUTextureHandle, source: TexImageSource, x: number, y: number, destWidth?: number, destHeight?: number): void;
141
+ private copyHtmlVideoToTextureRegionDirect;
142
+ private copyVideoFrameToTextureRegionDirect;
143
+ private drawVideoLikeSourceToTextureRegion;
144
+ deleteTexture(handle: GPUTextureHandle): void;
145
+ draw(cmd: DrawCommand): void;
146
+ /** One `drawIndexed` with `instanceCount` for all SVGA sprites sharing the same atlas. */
147
+ private drawInstancedSvga;
148
+ /** One `drawIndexed` with `instanceCount` for all gifts sharing the same video texture (e.g. atlas). */
149
+ private drawInstancedAlpha;
150
+ private drawInstancedVap;
151
+ clearStencil(): void;
152
+ setScissor(x: number, y: number, w: number, h: number): void;
153
+ resetScissor(): void;
154
+ destroy(): void;
155
+ }
@@ -0,0 +1,27 @@
1
+ export { GiftStage } from './core/gift-stage';
2
+ export { RenderManager } from './core/render-manager';
3
+ export { AudioManager } from './core/audio-manager';
4
+ export { PostAnimator } from './core/post-animator';
5
+ export { WebGL2Backend } from './gpu/webgl2-backend';
6
+ export { WebGL1Backend } from './gpu/webgl1-backend';
7
+ export { WebGPUBackend } from './gpu/webgpu-backend';
8
+ export { createBackend } from './gpu/detect';
9
+ export { SVGABatchRenderer } from './renderers/svga-batch-renderer';
10
+ export { VAPRenderer } from './renderers/vap-renderer';
11
+ export { AlphaVideoRenderer } from './renderers/alpha-video-renderer';
12
+ export { ImageRenderer } from './renderers/image-renderer';
13
+ export { buildBatchVerticesJS } from './renderers/vertex-builder';
14
+ export { parseSVGA } from './parsers/svga-parser';
15
+ export type { ParseSVGAOptions } from './parsers/svga-parser';
16
+ export { buildAtlas } from './parsers/atlas-builder';
17
+ export { parseVAPConfig } from './parsers/vap-config-parser';
18
+ export { inflateJS } from './parsers/inflate-js';
19
+ export { decodeSVGAProto } from './parsers/svga-proto-js';
20
+ export * from './utils/easing';
21
+ export { ortho, lerp, clamp, generateId } from './utils/math';
22
+ export { BufferPool } from './utils/buffer-pool';
23
+ export { canWebGPU, canWebGL2, canWebGL1, canSharedArrayBuffer } from './utils/detect';
24
+ export { initWasm, isWasmReady } from './wasm/wasm-bridge';
25
+ export { WebCodecsMp4Playback } from './video/webcodecs-mp4-playback';
26
+ export type { WebCodecsMp4CreateOptions } from './video/webcodecs-mp4-playback';
27
+ export type { WebCodecsPlaybackHandle, GPUBackend, GPUBufferHandle, GPUTextureHandle, TextureOpts, BufferUsage, DrawCommand, ShaderType, BackendType, GiftStageOptions, AddGiftOptions, GiftHandle, GiftSlot, GiftType, GiftObjectFit, GiftCoordinate, GiftState, GiftAnimationStep, GiftAnimationChain, SVGAMovieEntity, SVGAParams, SVGASpriteTable, SVGAAudio, SVGATransform, SVGAShape, VideoEntity, UVRect, FrameJobData, FlyAnimation, VAPConfig, VAPSrcItem, VAPFrameItem, VAPFrameObj, } from './types';
@@ -0,0 +1,37 @@
1
+ import type { GPUBackend, GPUTextureHandle, UVRect } from '../types';
2
+ export interface AtlasPageResult {
3
+ textureHandle: GPUTextureHandle;
4
+ atlasWidth: number;
5
+ atlasHeight: number;
6
+ encodedPngBytesPromise?: Promise<ArrayBuffer | null>;
7
+ }
8
+ export interface AtlasResult {
9
+ /** First page, kept for compatibility with older single-atlas consumers. */
10
+ textureHandle: GPUTextureHandle;
11
+ textureHandles: GPUTextureHandle[];
12
+ pages: AtlasPageResult[];
13
+ rects: Map<string, UVRect>;
14
+ /** First page width, kept for compatibility with older single-atlas consumers. */
15
+ atlasWidth: number;
16
+ /** First page height, kept for compatibility with older single-atlas consumers. */
17
+ atlasHeight: number;
18
+ /** First page PNG promise, kept for compatibility with older single-atlas consumers. */
19
+ encodedPngBytesPromise?: Promise<ArrayBuffer | null>;
20
+ encodedPngBytesPromises?: Array<Promise<ArrayBuffer | null>>;
21
+ }
22
+ export interface AtlasBuildOptions {
23
+ captureEncodedPng?: boolean;
24
+ maxPages?: number;
25
+ /**
26
+ * Main-thread atlas compose/upload slice cap. The actual slice tracks half
27
+ * of the observed frame interval and is capped at this value. Default: 12.
28
+ */
29
+ mainThreadFrameBudgetMs?: number;
30
+ /** Worker cooperative CPU slice cap. Defaults to 4ms. */
31
+ workerTimeSliceMs?: number;
32
+ /** Internal recovery switch: false forces main-thread composition even when the worker is available. */
33
+ useWorker?: boolean;
34
+ /** Cancels cooperative work and terminates an active atlas worker request. */
35
+ signal?: AbortSignal;
36
+ }
37
+ export declare function buildAtlas(images: Map<string, ImageBitmap>, backend: GPUBackend, maxSize?: number, padding?: number, opts?: AtlasBuildOptions): Promise<AtlasResult>;
@@ -0,0 +1,31 @@
1
+ /**
2
+ * Pure shelf bin-packing for SVGA atlases (shared by main thread and atlas worker).
3
+ * Mirrors Unity Texture2D.PackTextures: oversized images downscale; many images split across pages.
4
+ */
5
+ export interface ImageSizeEntry {
6
+ key: string;
7
+ width: number;
8
+ height: number;
9
+ }
10
+ export interface PackedRect {
11
+ key: string;
12
+ pageIndex: number;
13
+ x: number;
14
+ y: number;
15
+ w: number;
16
+ h: number;
17
+ }
18
+ export interface PackedAtlasPage {
19
+ rects: PackedRect[];
20
+ atlasW: number;
21
+ atlasH: number;
22
+ }
23
+ export type AtlasPackingCheckpoint = () => Promise<void>;
24
+ /**
25
+ * Shelf bin-packing with multiple pages.
26
+ * Prefer splitting across pages; when page count exceeds maxPages, binary-search a global downscale.
27
+ */
28
+ export declare function shelfPackPages(images: ImageSizeEntry[], padding: number, maxSize: number, maxPages: number): PackedAtlasPage[];
29
+ export declare function shelfPackPagesCooperative(images: ImageSizeEntry[], padding: number, maxSize: number, maxPages: number, checkpoint: AtlasPackingCheckpoint): Promise<PackedAtlasPage[]>;
30
+ /** Edge bleed for linear filtering (shared by main-thread and worker compose). */
31
+ export declare function extrudeAtlasRect(surface: OffscreenCanvas | HTMLCanvasElement, ctx: OffscreenCanvasRenderingContext2D | CanvasRenderingContext2D, rect: PackedRect, atlasW: number, atlasH: number, padding: number): void;
@@ -0,0 +1,7 @@
1
+ export { parseSVGA } from './svga-parser';
2
+ export type { ParseResult } from './svga-parser';
3
+ export { buildAtlas } from './atlas-builder';
4
+ export type { AtlasResult } from './atlas-builder';
5
+ export { parseVAPConfig, getVAPFrame, computeVAPUV } from './vap-config-parser';
6
+ export { inflateJS } from './inflate-js';
7
+ export { decodeSVGAProto } from './svga-proto-js';
@@ -0,0 +1,37 @@
1
+ export declare function canUseNativeInflate(): boolean;
2
+ export interface InflateAttemptProfile {
3
+ format: CompressionFormat;
4
+ inputBytes: number;
5
+ inputChunks: 1;
6
+ writerSubmitMs: number;
7
+ readMs: number;
8
+ concatMs: number;
9
+ totalMs: number;
10
+ outputChunks: number;
11
+ outputBytes: number;
12
+ status: 'success' | 'failed';
13
+ error?: string;
14
+ }
15
+ export interface InflateProfile {
16
+ inputBytes: number;
17
+ nativeAvailable: boolean;
18
+ nativeAttempts: InflateAttemptProfile[];
19
+ selectedPath?: 'native' | 'wasm' | 'native-retry';
20
+ wasmMs?: number;
21
+ outputBytes?: number;
22
+ totalMs?: number;
23
+ error?: string;
24
+ }
25
+ export type InflateProfileSink = (profile: InflateProfile) => void;
26
+ /**
27
+ * Inflate preferring the browser-native DecompressionStream (usually faster than WASM
28
+ * and runs off the JS thread); falls back to the provided WASM inflate, then to
29
+ * `inflateJS` (which throws a meaningful error when nothing is available).
30
+ */
31
+ export declare function inflatePreferNative(data: Uint8Array, wasmInflate: () => Uint8Array | null | false, onProfile?: InflateProfileSink): Promise<Uint8Array>;
32
+ /**
33
+ * JS fallback inflate using DecompressionStream API (no WASM needed).
34
+ * SVGA files are zlib-compressed (2-byte header + deflate data + 4-byte Adler32).
35
+ * 'deflate' mode handles the full zlib envelope natively.
36
+ */
37
+ export declare function inflateJS(data: Uint8Array, profile?: Pick<InflateProfile, 'nativeAttempts'>): Promise<Uint8Array>;
@@ -0,0 +1,14 @@
1
+ /**
2
+ * Whether the environment can use a worker for ImageBitmap decode (best-effort).
3
+ */
4
+ export declare function canUseSVGAImageDecodeWorker(): boolean;
5
+ export interface SVGAImageDecodeWorkerOptions {
6
+ workerTimeSliceMs?: number;
7
+ maxConcurrency?: number;
8
+ mainThreadFrameBudgetMs?: number;
9
+ signal?: AbortSignal;
10
+ }
11
+ /**
12
+ * Decode many image blobs to ImageBitmaps in a dedicated worker, in chunks to limit message size.
13
+ */
14
+ export declare function decodeSVGAImagesInWorker(imageEntries: Array<[string, Uint8Array]>, chunkSize: number, options?: SVGAImageDecodeWorkerOptions): Promise<Map<string, ImageBitmap>>;
@@ -0,0 +1,31 @@
1
+ /**
2
+ * Dedicated Worker client for SVGA inflate + protobuf (see ../workers/parser-worker.ts).
3
+ * ImageBitmap creation stays on the main thread.
4
+ */
5
+ import type { SVGAMovieEntity, SVGASpriteTable } from '../types';
6
+ export interface SVGAParserWorkerOptions {
7
+ profile?: boolean;
8
+ workerTimeSliceMs?: number;
9
+ mainThreadFrameBudgetMs?: number;
10
+ signal?: AbortSignal;
11
+ }
12
+ export interface SVGAWorkerMoviePayload {
13
+ version: string;
14
+ params: SVGAMovieEntity['params'];
15
+ spriteTable: SVGASpriteTable;
16
+ audios: SVGAMovieEntity['audios'];
17
+ images?: Record<string, ArrayBuffer>;
18
+ imageBlob?: ArrayBuffer;
19
+ imageEntries?: Array<{
20
+ key: string;
21
+ offset: number;
22
+ length: number;
23
+ }>;
24
+ __debug?: Record<string, unknown>;
25
+ }
26
+ /**
27
+ * Transfers `fileBuffer` to the parser worker (the buffer is detached — the caller must not
28
+ * use it afterwards); resolves with decoded movie payload (no ImageBitmaps).
29
+ */
30
+ export declare function requestSVGAParseInWorker(fileBuffer: ArrayBuffer, options?: SVGAParserWorkerOptions): Promise<SVGAWorkerMoviePayload>;
31
+ export declare function workerPayloadToMovieEntity(payload: SVGAWorkerMoviePayload): SVGAMovieEntity;
@@ -0,0 +1,49 @@
1
+ import type { SVGAMovieEntity } from '../types';
2
+ export interface ParseResult {
3
+ movie: SVGAMovieEntity;
4
+ imageBitmaps: Map<string, ImageBitmap>;
5
+ audioBlobs: Map<string, ArrayBuffer>;
6
+ }
7
+ export interface ParseSVGAOptions {
8
+ /**
9
+ * When true (default), inflate + protobuf decode run in a Dedicated Worker (main thread only builds ImageBitmaps).
10
+ * Set false for tests or environments without Workers.
11
+ */
12
+ useWorker?: boolean;
13
+ /**
14
+ * When true (default), decode embedded images to ImageBitmap in a Dedicated Worker (off main thread).
15
+ * On failure, falls back to main-thread decode (adaptive batch unless disabled).
16
+ */
17
+ useImageBitmapDecodeWorker?: boolean;
18
+ /**
19
+ * Max images per postMessage to the image decode worker. Default 32.
20
+ */
21
+ imageDecodeWorkerChunkSize?: number;
22
+ /**
23
+ * When decoding on the main thread, adjust batch size from measured time and yield when over budget.
24
+ * Default true.
25
+ */
26
+ imageDecodeAdaptiveOnMainThread?: boolean;
27
+ /**
28
+ * Target ms per main-thread batch before considering a frame yield (adaptive path). Default 12.
29
+ */
30
+ imageDecodeFrameBudgetMs?: number;
31
+ /**
32
+ * Fixed batch size on main thread when `imageDecodeAdaptiveOnMainThread` is false. Default 4.
33
+ */
34
+ imageDecodeFixedBatchSize?: number;
35
+ /** Shared SVGA main-thread frame-budget cap. Defaults to 12ms. */
36
+ svgaLoadFrameBudgetMs?: number;
37
+ /** Worker cooperative CPU slice cap. Defaults to 4ms and is clamped to 1-8ms. */
38
+ svgaWorkerFrameBudgetMs?: number;
39
+ /** Global SVGA heavy-worker concurrency cap. Defaults to 1. */
40
+ svgaWorkerTaskConcurrency?: number;
41
+ /** Initial ImageBitmap decode concurrency inside the image worker. Defaults to 2. */
42
+ svgaWorkerImageDecodeConcurrency?: number;
43
+ /** Emit a single structured profile for each actual parse. Default false. */
44
+ svgaParseProfile?: boolean;
45
+ /** Cancels this parse consumer. Shared payload work stops only after all consumers cancel. */
46
+ signal?: AbortSignal;
47
+ }
48
+ export declare function parseSVGAParams(source: string | ArrayBuffer, options?: ParseSVGAOptions): Promise<SVGAMovieEntity['params']>;
49
+ export declare function parseSVGA(source: string | ArrayBuffer, options?: ParseSVGAOptions): Promise<ParseResult>;
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Lightweight JS protobuf decoder for SVGA MovieEntity.
3
+ * Falls back to this when WASM is unavailable.
4
+ * Implements just enough proto2 wire format to decode the SVGA schema.
5
+ */
6
+ import type { SVGAMovieEntity } from '../types';
7
+ export declare function decodeSVGAProto(data: Uint8Array): SVGAMovieEntity;
@@ -0,0 +1,36 @@
1
+ /**
2
+ * Shared SoA sprite-table binary section (SGPB v2 / SGBC v14).
3
+ */
4
+ import type { SVGASpriteTable } from '../types';
5
+ declare function align4(offset: number): number;
6
+ export interface SpriteTableBinaryWriter {
7
+ u8(value: number): void;
8
+ u32(value: number): void;
9
+ i32(value: number): void;
10
+ f32(value: number): void;
11
+ string(value: string): void;
12
+ rawBytes(value: Uint8Array): void;
13
+ pad4(): void;
14
+ }
15
+ export interface SpriteTableBinaryReader {
16
+ u8(): number;
17
+ u32(): number;
18
+ i32(): number;
19
+ f32(): number;
20
+ string(): string;
21
+ pad4(): void;
22
+ readonly position: number;
23
+ skip(bytes: number): void;
24
+ sourceBuffer(): ArrayBuffer;
25
+ }
26
+ export interface CooperativeSpriteTableBinaryWriter extends SpriteTableBinaryWriter {
27
+ stringCooperative(value: string, checkpoint: SpriteTableCheckpoint): Promise<void>;
28
+ rawBytesCooperative(value: Uint8Array, checkpoint: SpriteTableCheckpoint): Promise<void>;
29
+ }
30
+ export type SpriteTableCheckpoint = () => Promise<void>;
31
+ export declare function writeSpriteTable(writer: SpriteTableBinaryWriter, table: SVGASpriteTable): void;
32
+ export declare function writeSpriteTableCooperative(writer: CooperativeSpriteTableBinaryWriter, table: SVGASpriteTable, checkpoint: SpriteTableCheckpoint): Promise<void>;
33
+ export declare function readSpriteTable(reader: SpriteTableBinaryReader): SVGASpriteTable;
34
+ export declare function readSpriteTableCooperative(reader: SpriteTableBinaryReader, checkpoint: SpriteTableCheckpoint): Promise<SVGASpriteTable>;
35
+ /** Pad offset to 4-byte boundary (for standalone writers). */
36
+ export { align4 };
@@ -0,0 +1,59 @@
1
+ /**
2
+ * SVGA sprite SoA table: flat frame floats + deduped clip/shapes side tables.
3
+ * Replaces per-sprite `frames: SVGAFrame[]` object graphs on the hot path.
4
+ */
5
+ import type { SVGAShape, SVGATransform } from '../types';
6
+ /** Floats per frame in `frameData`: layoutW, layoutH, a, b, c, d, tx, ty, alpha. */
7
+ export declare const SPRITE_FRAME_FLOATS = 9;
8
+ export interface SVGASpriteTable {
9
+ spriteCount: number;
10
+ frameCount: number;
11
+ imageKeys: string[];
12
+ /** spriteCount × frameCount × 9, row-major (sprite, then frame). */
13
+ frameData: Float32Array;
14
+ /** Deduped non-empty clipPath strings. */
15
+ clipPaths: string[];
16
+ /** spriteCount × frameCount; -1 = none. */
17
+ clipPathIndex: Int32Array;
18
+ /** Deduped shape groups; keep-chains share the same array reference. */
19
+ shapesTable: SVGAShape[][];
20
+ /** spriteCount × frameCount; -1 = none. */
21
+ shapesIndex: Int32Array;
22
+ hasAnyShapes: boolean;
23
+ }
24
+ /** Loose frame shape used when converting from AoS decode (JS proto / fixtures). */
25
+ export interface SVGAFrameLike {
26
+ alpha: number;
27
+ layout: {
28
+ width: number;
29
+ height: number;
30
+ } | null;
31
+ transform: SVGATransform | null;
32
+ clipPath: string;
33
+ shapes?: SVGAShape[] | null;
34
+ }
35
+ export interface SVGASpriteLike {
36
+ imageKey: string;
37
+ frames: SVGAFrameLike[];
38
+ }
39
+ export declare function readSpriteFrameAlpha(table: SVGASpriteTable, spriteIndex: number, frameIndex: number): number;
40
+ export declare function readSpriteFrameTransform(table: SVGASpriteTable, spriteIndex: number, frameIndex: number): {
41
+ layoutW: number;
42
+ layoutH: number;
43
+ a: number;
44
+ b: number;
45
+ c: number;
46
+ d: number;
47
+ tx: number;
48
+ ty: number;
49
+ alpha: number;
50
+ };
51
+ export declare function getSpriteShapes(table: SVGASpriteTable, spriteIndex: number, frameIndex: number): SVGAShape[] | null;
52
+ export declare function getSpriteClipPath(table: SVGASpriteTable, spriteIndex: number, frameIndex: number): string;
53
+ /**
54
+ * Build a SoA table from AoS sprites (JS protobuf decode / test fixtures).
55
+ * Resolves shape `keep` chains to shared array references.
56
+ */
57
+ export declare function spriteTableFromSprites(sprites: SVGASpriteLike[], frameCountHint?: number): SVGASpriteTable;
58
+ /** Empty table used when there are no sprites. */
59
+ export declare function emptySpriteTable(frameCount?: number): SVGASpriteTable;
@@ -0,0 +1,10 @@
1
+ import type { SVGAMovieEntity } from '../types';
2
+ import type { SVGAWorkerMoviePayload } from './svga-parser-worker-client';
3
+ import { type SpriteTableCheckpoint } from './svga-sprite-table-binary';
4
+ export declare function serializeSVGAWorkerPayload(payload: SVGAWorkerMoviePayload): ArrayBuffer;
5
+ export declare function serializeSVGAWorkerPayloadCooperative(payload: SVGAWorkerMoviePayload, checkpoint: SpriteTableCheckpoint): Promise<ArrayBuffer>;
6
+ export declare function deserializeSVGAWorkerPayload(buffer: ArrayBuffer, debug?: Record<string, unknown>): SVGAWorkerMoviePayload;
7
+ export declare function deserializeSVGAWorkerPayloadCooperative(buffer: ArrayBuffer, debug?: Record<string, unknown>, frameBudgetMs?: number, signal?: AbortSignal): Promise<SVGAWorkerMoviePayload>;
8
+ export declare function movieEntityToWorkerPayloadBinary(movie: SVGAMovieEntity): ArrayBuffer;
9
+ export declare function workerPayloadImageBytes(payload: SVGAWorkerMoviePayload): number;
10
+ export declare function workerPayloadImageCount(payload: SVGAWorkerMoviePayload): number;