@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.
- package/README.md +89 -36
- package/dist/core/audio-manager.d.ts +19 -0
- package/dist/core/gift-stage.d.ts +117 -0
- package/dist/core/index.d.ts +4 -0
- package/dist/core/post-animator.d.ts +43 -0
- package/dist/core/render-manager.d.ts +99 -0
- package/dist/core/webcodecs-video-atlas.d.ts +30 -0
- package/dist/gift-stage.cjs.js +225 -225
- package/dist/gift-stage.es.js +2537 -2062
- package/dist/gpu/detect.d.ts +2 -0
- package/dist/gpu/gl-utils.d.ts +10 -0
- package/dist/gpu/index.d.ts +3 -0
- package/dist/gpu/webgl1-backend.d.ts +43 -0
- package/dist/gpu/webgl2-backend.d.ts +69 -0
- package/dist/gpu/webgpu-backend.d.ts +155 -0
- package/dist/index.d.ts +27 -0
- package/dist/parsers/atlas-builder.d.ts +37 -0
- package/dist/parsers/atlas-packing.d.ts +31 -0
- package/dist/parsers/index.d.ts +7 -0
- package/dist/parsers/inflate-js.d.ts +37 -0
- package/dist/parsers/svga-image-decode-worker-client.d.ts +14 -0
- package/dist/parsers/svga-parser-worker-client.d.ts +31 -0
- package/dist/parsers/svga-parser.d.ts +49 -0
- package/dist/parsers/svga-proto-js.d.ts +7 -0
- package/dist/parsers/svga-sprite-table-binary.d.ts +36 -0
- package/dist/parsers/svga-sprite-table.d.ts +59 -0
- package/dist/parsers/svga-worker-payload-binary.d.ts +10 -0
- package/dist/parsers/vap-config-parser.d.ts +20 -0
- package/dist/renderers/alpha-video-renderer.d.ts +48 -0
- package/dist/renderers/image-renderer.d.ts +13 -0
- package/dist/renderers/index.d.ts +4 -0
- package/dist/renderers/svga-batch-renderer.d.ts +113 -0
- package/dist/renderers/vap-renderer.d.ts +58 -0
- package/dist/renderers/vertex-builder.d.ts +5 -0
- package/dist/shaders/index.d.ts +49 -0
- package/dist/types/index.d.ts +699 -0
- package/dist/utils/abort.d.ts +3 -0
- package/dist/utils/atlas-constants.d.ts +9 -0
- package/dist/utils/buffer-pool.d.ts +14 -0
- package/dist/utils/canvas-dpr.d.ts +37 -0
- package/dist/utils/clip-mesh.d.ts +6 -0
- package/dist/utils/detect.d.ts +7 -0
- package/dist/utils/easing.d.ts +7 -0
- package/dist/utils/frame-budget.d.ts +36 -0
- package/dist/utils/gift-object-fit.d.ts +14 -0
- package/dist/utils/gift-position.d.ts +5 -0
- package/dist/utils/gift-size.d.ts +11 -0
- package/dist/utils/gift-transform.d.ts +29 -0
- package/dist/utils/html-video-upload-gate.d.ts +35 -0
- package/dist/utils/image-source.d.ts +9 -0
- package/dist/utils/math.d.ts +9 -0
- package/dist/utils/resource-cache.d.ts +20 -0
- package/dist/utils/slot-content.d.ts +17 -0
- package/dist/utils/svg-path-parser.d.ts +11 -0
- package/dist/utils/svga-binary-cache.d.ts +26 -0
- package/dist/utils/svga-work-scheduler.d.ts +7 -0
- package/dist/utils/triangulate.d.ts +11 -0
- package/dist/utils/utf8.d.ts +2 -0
- package/dist/utils/vap-mix-composer.d.ts +26 -0
- package/dist/utils/wc-atlas-upload-size.d.ts +9 -0
- package/dist/video/mp4box-loader.d.ts +2 -0
- package/dist/video/webcodecs-mp4-core.d.ts +49 -0
- package/dist/video/webcodecs-mp4-playback.d.ts +71 -0
- package/dist/video/webcodecs-mp4.worker.d.ts +18 -0
- package/dist/wasm/wasm-bridge.d.ts +36 -0
- package/dist/workers/parser-worker.d.ts +13 -0
- package/dist/workers/svga-atlas-worker-client.d.ts +25 -0
- package/dist/workers/svga-atlas-worker.d.ts +37 -0
- package/dist/workers/svga-clip-worker-client.d.ts +6 -0
- package/dist/workers/svga-clip-worker.d.ts +17 -0
- package/dist/workers/svga-image-decode-worker.d.ts +19 -0
- package/dist/workers/vertex-worker.d.ts +15 -0
- package/dist/workers/worker-scheduler.d.ts +19 -0
- package/package.json +7 -5
|
@@ -0,0 +1,699 @@
|
|
|
1
|
+
export type BackendType = 'webgpu' | 'webgl2' | 'webgl1';
|
|
2
|
+
export type BufferUsage = 'vertex' | 'index' | 'uniform';
|
|
3
|
+
export type GPUBufferSource = ArrayBufferLike | ArrayBufferView;
|
|
4
|
+
export interface GPUBufferHandle {
|
|
5
|
+
readonly id: number;
|
|
6
|
+
readonly usage: BufferUsage;
|
|
7
|
+
}
|
|
8
|
+
export interface GPUTextureHandle {
|
|
9
|
+
readonly id: number;
|
|
10
|
+
readonly width: number;
|
|
11
|
+
readonly height: number;
|
|
12
|
+
}
|
|
13
|
+
export interface TextureOpts {
|
|
14
|
+
width?: number;
|
|
15
|
+
height?: number;
|
|
16
|
+
format?: 'rgba8' | 'rgb8';
|
|
17
|
+
filter?: 'linear' | 'nearest';
|
|
18
|
+
wrap?: 'clamp' | 'repeat';
|
|
19
|
+
/** Upload external image sources as premultiplied RGBA. ArrayBuffer sources are assumed already in final pixel format. */
|
|
20
|
+
premultiplyAlpha?: boolean;
|
|
21
|
+
/**
|
|
22
|
+
* When true, the external source (e.g. `ImageBitmap` from `createImageBitmap(…, { premultiplyAlpha: 'premultiply' })`)
|
|
23
|
+
* is already premultiplied; WebGL must not set `UNPACK_PREMULTIPLY_ALPHA_WEBGL` for this upload (avoids double
|
|
24
|
+
* premultiply). WebGPU infers from the `ImageBitmap`; this flag is mainly for the GL path.
|
|
25
|
+
*/
|
|
26
|
+
sourcePremultiplied?: boolean;
|
|
27
|
+
}
|
|
28
|
+
export type ShaderType = 'svga-batch-premul'
|
|
29
|
+
/** WebGPU / WebGL2: SVGA premultiplied atlas sprites batched as instances using `FrameJobData` payloads. */
|
|
30
|
+
| 'svga-instanced-premul' | 'vap'
|
|
31
|
+
/** Main-context VAP mixed resource draw: resource texture multiplied by raw-video mask. */
|
|
32
|
+
| 'vap-mix-overlay'
|
|
33
|
+
/** WebGPU / WebGL2: batched VAP sharing one texture; see `instanceCount` / `instanceData` (32 floats/instance). */
|
|
34
|
+
| 'vap-instanced' | 'alpha-video'
|
|
35
|
+
/** WebGPU: batched draws sharing one texture (e.g. atlas); see `instanceCount` / `instanceData`. */
|
|
36
|
+
| 'alpha-video-instanced' | 'rgba-textured' | 'clip-mask';
|
|
37
|
+
export type StencilMode = 'none' | 'write' | 'test' | 'clear';
|
|
38
|
+
export interface DrawCommand {
|
|
39
|
+
shader: ShaderType;
|
|
40
|
+
vertexBuffer: GPUBufferHandle;
|
|
41
|
+
indexBuffer: GPUBufferHandle;
|
|
42
|
+
indexCount: number;
|
|
43
|
+
textures: GPUTextureHandle[];
|
|
44
|
+
uniforms: Record<string, Float32Array | number>;
|
|
45
|
+
stencil?: StencilMode;
|
|
46
|
+
/**
|
|
47
|
+
* `svga-instanced-premul`: the first `instanceCount * 13` floats are consumed
|
|
48
|
+
* (layout + transform + alpha + uv rect).
|
|
49
|
+
*
|
|
50
|
+
* `alpha-video-instanced`: the first `instanceCount * 12` floats are consumed
|
|
51
|
+
* (display rect + atlasRemap + opacity/source-alpha-mode vec4).
|
|
52
|
+
* `vap-instanced`: the first `instanceCount * 32` floats are consumed
|
|
53
|
+
* (mat4 + atlasRemap + rgb/alpha rects + opacity/source-alpha-mode vec4).
|
|
54
|
+
* Renderers may pass a larger reused scratch array to avoid allocating a subarray view per draw.
|
|
55
|
+
*/
|
|
56
|
+
instanceCount?: number;
|
|
57
|
+
instanceData?: Float32Array;
|
|
58
|
+
}
|
|
59
|
+
export interface GPUBackend {
|
|
60
|
+
readonly type: BackendType;
|
|
61
|
+
readonly canvas: HTMLCanvasElement;
|
|
62
|
+
/** Maximum supported 2D texture dimension for this backend/device. */
|
|
63
|
+
readonly maxTextureSize?: number;
|
|
64
|
+
init(): Promise<void>;
|
|
65
|
+
beginFrame(): void;
|
|
66
|
+
endFrame(): void;
|
|
67
|
+
createBuffer(data: GPUBufferSource, usage: BufferUsage): GPUBufferHandle;
|
|
68
|
+
updateBuffer(handle: GPUBufferHandle, data: GPUBufferSource, offset?: number): void;
|
|
69
|
+
deleteBuffer(handle: GPUBufferHandle): void;
|
|
70
|
+
createTexture(source: TexImageSource | ArrayBuffer, opts: TextureOpts): GPUTextureHandle;
|
|
71
|
+
/** Uninitialized RGBA texture (e.g. WebCodecs atlas backing store). */
|
|
72
|
+
createEmptyTexture(width: number, height: number, opts?: TextureOpts): GPUTextureHandle;
|
|
73
|
+
updateTexture(handle: GPUTextureHandle, source: TexImageSource): void;
|
|
74
|
+
/** When `destWidth`/`destHeight` differ from source size, uploads a uniformly scaled copy into the region. */
|
|
75
|
+
updateTextureRegion(handle: GPUTextureHandle, source: TexImageSource, x: number, y: number, destWidth?: number, destHeight?: number): void;
|
|
76
|
+
deleteTexture(handle: GPUTextureHandle): void;
|
|
77
|
+
draw(cmd: DrawCommand): void;
|
|
78
|
+
clearStencil?(): void;
|
|
79
|
+
setScissor(x: number, y: number, w: number, h: number): void;
|
|
80
|
+
resetScissor(): void;
|
|
81
|
+
destroy(): void;
|
|
82
|
+
}
|
|
83
|
+
export interface SVGAParams {
|
|
84
|
+
viewBoxWidth: number;
|
|
85
|
+
viewBoxHeight: number;
|
|
86
|
+
fps: number;
|
|
87
|
+
frames: number;
|
|
88
|
+
}
|
|
89
|
+
export interface SVGATransform {
|
|
90
|
+
a: number;
|
|
91
|
+
b: number;
|
|
92
|
+
c: number;
|
|
93
|
+
d: number;
|
|
94
|
+
tx: number;
|
|
95
|
+
ty: number;
|
|
96
|
+
}
|
|
97
|
+
export type SVGAShapeKind = 'path' | 'rect' | 'ellipse';
|
|
98
|
+
export interface SVGAColor {
|
|
99
|
+
r: number;
|
|
100
|
+
g: number;
|
|
101
|
+
b: number;
|
|
102
|
+
a: number;
|
|
103
|
+
}
|
|
104
|
+
export interface SVGAShapeStyle {
|
|
105
|
+
fill: SVGAColor | null;
|
|
106
|
+
stroke: SVGAColor | null;
|
|
107
|
+
strokeWidth: number;
|
|
108
|
+
lineCap?: number;
|
|
109
|
+
lineJoin?: number;
|
|
110
|
+
miterLimit?: number;
|
|
111
|
+
lineDash?: number[];
|
|
112
|
+
}
|
|
113
|
+
export interface SVGAShape {
|
|
114
|
+
kind: SVGAShapeKind;
|
|
115
|
+
pathData?: string;
|
|
116
|
+
rect?: {
|
|
117
|
+
x: number;
|
|
118
|
+
y: number;
|
|
119
|
+
width: number;
|
|
120
|
+
height: number;
|
|
121
|
+
cornerRadius?: number;
|
|
122
|
+
};
|
|
123
|
+
ellipse?: {
|
|
124
|
+
x: number;
|
|
125
|
+
y: number;
|
|
126
|
+
radiusX: number;
|
|
127
|
+
radiusY: number;
|
|
128
|
+
};
|
|
129
|
+
style: SVGAShapeStyle;
|
|
130
|
+
transform: SVGATransform;
|
|
131
|
+
}
|
|
132
|
+
/** Floats per frame in SVGASpriteTable.frameData. */
|
|
133
|
+
export declare const SPRITE_FRAME_FLOATS = 9;
|
|
134
|
+
/**
|
|
135
|
+
* SoA sprite table: contiguous frame floats + deduped clip/shapes side tables.
|
|
136
|
+
* Replaces per-sprite `frames: SVGAFrame[]` object graphs.
|
|
137
|
+
*/
|
|
138
|
+
export interface SVGASpriteTable {
|
|
139
|
+
spriteCount: number;
|
|
140
|
+
frameCount: number;
|
|
141
|
+
imageKeys: string[];
|
|
142
|
+
/** spriteCount × frameCount × 9: layoutW, layoutH, a, b, c, d, tx, ty, alpha. */
|
|
143
|
+
frameData: Float32Array;
|
|
144
|
+
clipPaths: string[];
|
|
145
|
+
clipPathIndex: Int32Array;
|
|
146
|
+
shapesTable: SVGAShape[][];
|
|
147
|
+
shapesIndex: Int32Array;
|
|
148
|
+
hasAnyShapes: boolean;
|
|
149
|
+
}
|
|
150
|
+
export interface SVGAAudio {
|
|
151
|
+
audioKey: string;
|
|
152
|
+
startFrame: number;
|
|
153
|
+
endFrame: number;
|
|
154
|
+
startTime: number;
|
|
155
|
+
totalTime: number;
|
|
156
|
+
}
|
|
157
|
+
export interface SVGAMovieEntity {
|
|
158
|
+
version: string;
|
|
159
|
+
params: SVGAParams;
|
|
160
|
+
images: Map<string, Uint8Array>;
|
|
161
|
+
spriteTable: SVGASpriteTable;
|
|
162
|
+
audios: SVGAAudio[];
|
|
163
|
+
}
|
|
164
|
+
export interface UVRect {
|
|
165
|
+
x: number;
|
|
166
|
+
y: number;
|
|
167
|
+
w: number;
|
|
168
|
+
h: number;
|
|
169
|
+
/** Atlas page index. Omitted means page 0 for older single-atlas data. */
|
|
170
|
+
textureIndex?: number;
|
|
171
|
+
}
|
|
172
|
+
export interface VideoEntity {
|
|
173
|
+
params: SVGAParams;
|
|
174
|
+
spriteTable: SVGASpriteTable;
|
|
175
|
+
audios: SVGAAudio[];
|
|
176
|
+
atlasTextureHandle: GPUTextureHandle | null;
|
|
177
|
+
atlasTextureHandles?: GPUTextureHandle[];
|
|
178
|
+
atlasRects: Map<string, UVRect>;
|
|
179
|
+
audioBuffers: Map<string, ArrayBuffer>;
|
|
180
|
+
}
|
|
181
|
+
export declare const FRAME_DATA_FLOATS = 13;
|
|
182
|
+
export declare const VERTEX_FLOATS = 9;
|
|
183
|
+
export declare const VERTS_PER_QUAD = 4;
|
|
184
|
+
export declare const INDICES_PER_QUAD = 6;
|
|
185
|
+
export interface FrameJobData {
|
|
186
|
+
layoutW: number;
|
|
187
|
+
layoutH: number;
|
|
188
|
+
a: number;
|
|
189
|
+
b: number;
|
|
190
|
+
c: number;
|
|
191
|
+
d: number;
|
|
192
|
+
tx: number;
|
|
193
|
+
ty: number;
|
|
194
|
+
alpha: number;
|
|
195
|
+
uvMinX: number;
|
|
196
|
+
uvMinY: number;
|
|
197
|
+
uvMaxX: number;
|
|
198
|
+
uvMaxY: number;
|
|
199
|
+
}
|
|
200
|
+
export type GiftType = 'svga' | 'vap' | 'alphaVideo' | 'image';
|
|
201
|
+
export type GiftCoordinate = number | `${number}%`;
|
|
202
|
+
/** How the RGB region of a split-alpha video is encoded before the separate alpha mask is applied. */
|
|
203
|
+
export type VideoRGBAlphaMode = 'straight' | 'premultiplied';
|
|
204
|
+
/** Narrow interface so `GiftSlot` does not import the mp4/WebCodecs module. */
|
|
205
|
+
export interface WebCodecsPlaybackHandle {
|
|
206
|
+
readonly duration: number;
|
|
207
|
+
readonly videoWidth: number;
|
|
208
|
+
readonly videoHeight: number;
|
|
209
|
+
getFrameForTime(tSec: number): VideoFrame | null;
|
|
210
|
+
/** Optional: request decode ahead of `tSec` (Worker streaming + main-thread ring). */
|
|
211
|
+
ensureDecodedThrough?(tSec: number): void;
|
|
212
|
+
destroy(): void;
|
|
213
|
+
}
|
|
214
|
+
/** GiftStage-internal shared playback group. All consumers use the same looping clock. */
|
|
215
|
+
export interface WebCodecsSharedPlaybackState {
|
|
216
|
+
readonly id: number;
|
|
217
|
+
readonly playback: WebCodecsPlaybackHandle;
|
|
218
|
+
readonly startedAtMs: number;
|
|
219
|
+
}
|
|
220
|
+
/** GiftStage-internal upload target shared by compatible WebCodecs consumers. */
|
|
221
|
+
export interface WebCodecsTextureSurface {
|
|
222
|
+
readonly id: number;
|
|
223
|
+
readonly texture: GPUTextureHandle;
|
|
224
|
+
readonly atlasRect?: {
|
|
225
|
+
x: number;
|
|
226
|
+
y: number;
|
|
227
|
+
w: number;
|
|
228
|
+
h: number;
|
|
229
|
+
};
|
|
230
|
+
lastUploadedFrame: VideoFrame | null;
|
|
231
|
+
}
|
|
232
|
+
/** `contain`: uniform inside box. `cover`: uniform over box and clipped. `fill`: stretch to box. */
|
|
233
|
+
export type GiftObjectFit = 'contain' | 'cover' | 'fill';
|
|
234
|
+
export type GiftFontStyle = string | Record<string, string>;
|
|
235
|
+
export interface GiftTextSlotContent {
|
|
236
|
+
text: string;
|
|
237
|
+
color?: string;
|
|
238
|
+
style?: 'b' | 'normal';
|
|
239
|
+
fontStyle?: GiftFontStyle;
|
|
240
|
+
/** Preferred logical font size in CSS pixels. Omit to auto-fit inside the target slot. */
|
|
241
|
+
fontSize?: number;
|
|
242
|
+
/** Minimum auto-fit font size. Default: `8`. */
|
|
243
|
+
minFontSize?: number;
|
|
244
|
+
/** Maximum auto-fit font size. Omit to derive from the target slot height. */
|
|
245
|
+
maxFontSize?: number;
|
|
246
|
+
/** Logical padding around generated text. Default: `2`. */
|
|
247
|
+
padding?: number;
|
|
248
|
+
/**
|
|
249
|
+
* SVGA only: `dynamic` centers by intrinsic size; `replace` stretches to frame layout.
|
|
250
|
+
* VAP text resources ignore this and always fit into the configured frame box.
|
|
251
|
+
*/
|
|
252
|
+
mode?: 'replace' | 'dynamic';
|
|
253
|
+
/** Raster scale for generated text textures. Default: `3` for SVGA, `1` for VAP. */
|
|
254
|
+
scale?: number;
|
|
255
|
+
}
|
|
256
|
+
export interface GiftImageSlotContent {
|
|
257
|
+
image: TexImageSource | string;
|
|
258
|
+
/** SVGA only; defaults to `replace`. */
|
|
259
|
+
mode?: 'replace' | 'dynamic';
|
|
260
|
+
}
|
|
261
|
+
export interface VAPImageSlotContent {
|
|
262
|
+
image: TexImageSource | string;
|
|
263
|
+
}
|
|
264
|
+
export type SVGASlotContent = string | TexImageSource | GiftTextSlotContent | GiftImageSlotContent;
|
|
265
|
+
export type VAPSlotContent = string | TexImageSource | GiftTextSlotContent | VAPImageSlotContent;
|
|
266
|
+
export interface ResolvedSVGASlotTexture {
|
|
267
|
+
texture: GPUTextureHandle;
|
|
268
|
+
mode: 'replace' | 'dynamic';
|
|
269
|
+
logicalWidth: number;
|
|
270
|
+
logicalHeight: number;
|
|
271
|
+
}
|
|
272
|
+
export interface ResolvedVAPResource {
|
|
273
|
+
source: CanvasImageSource;
|
|
274
|
+
width: number;
|
|
275
|
+
height: number;
|
|
276
|
+
}
|
|
277
|
+
export interface VAPMixComposerHandle {
|
|
278
|
+
render(source: TexImageSource, frameIndex: number): HTMLCanvasElement;
|
|
279
|
+
destroy(): void;
|
|
280
|
+
}
|
|
281
|
+
export interface VAPMixState {
|
|
282
|
+
mode: 'direct' | 'composited';
|
|
283
|
+
texture?: GPUTextureHandle;
|
|
284
|
+
width: number;
|
|
285
|
+
height: number;
|
|
286
|
+
/** Main-context mixed resource textures, keyed by VAP srcId. */
|
|
287
|
+
resourceTextures?: Map<string, GPUTextureHandle>;
|
|
288
|
+
composer?: VAPMixComposerHandle | null;
|
|
289
|
+
compositeCanvas?: HTMLCanvasElement;
|
|
290
|
+
compositeCtx?: CanvasRenderingContext2D;
|
|
291
|
+
rawCanvas?: HTMLCanvasElement;
|
|
292
|
+
rawCtx?: CanvasRenderingContext2D;
|
|
293
|
+
scratchCanvas?: HTMLCanvasElement;
|
|
294
|
+
scratchCtx?: CanvasRenderingContext2D;
|
|
295
|
+
frameMap: Map<number, VAPFrameObj[]>;
|
|
296
|
+
/** Retained only by the CPU compositor fallback. */
|
|
297
|
+
resources?: Map<string, ResolvedVAPResource>;
|
|
298
|
+
lastFrameIndex: number;
|
|
299
|
+
lastSourceRef: CanvasImageSource | null;
|
|
300
|
+
}
|
|
301
|
+
export interface GiftStageOptions {
|
|
302
|
+
container: HTMLElement;
|
|
303
|
+
/**
|
|
304
|
+
* Overrides `window.devicePixelRatio` for the canvas backing store (bitmap px = CSS px × ratio).
|
|
305
|
+
* Omit to use device DPR (capped at 2 by default) so fullscreen overlays stay sharp on retina / mobile.
|
|
306
|
+
*/
|
|
307
|
+
resolution?: number;
|
|
308
|
+
/**
|
|
309
|
+
* Maximum backing-store resolution (orientation-adaptive: long edge ≤ max(width, height),
|
|
310
|
+
* short edge ≤ min(width, height)).
|
|
311
|
+
* Default: mobile `{ width: 1920, height: 1080 }`, desktop `{ width: 2560, height: 1440 }`.
|
|
312
|
+
* When exceeded, the buffer is scaled down proportionally and the browser stretches the
|
|
313
|
+
* canvas via CSS. Set `false` to disable the cap. Applies even with an explicit {@link resolution}.
|
|
314
|
+
*/
|
|
315
|
+
maxRenderSize?: {
|
|
316
|
+
width: number;
|
|
317
|
+
height: number;
|
|
318
|
+
} | false;
|
|
319
|
+
/**
|
|
320
|
+
* Edge smoothing: WebGL2 uses the context multisampled framebuffer; WebGPU uses 4× MSAA + resolve.
|
|
321
|
+
* Default: **true** for WebGL2, **false** for WebGPU (MSAA is expensive with large transparent-video fills).
|
|
322
|
+
* Set `true` explicitly when using WebGPU + sharp SVGA edges.
|
|
323
|
+
* Many concurrent transparent videos: keep WebGPU `antialias` off (default) and consider lowering {@link resolution}.
|
|
324
|
+
*/
|
|
325
|
+
antialias?: boolean;
|
|
326
|
+
/**
|
|
327
|
+
* Default true. On phones/tablets with WebCodecs video, WebGL2 can still be faster than WebGPU
|
|
328
|
+
* (driver + MSAA); set `false` to prefer WebGL2 when you measure lower FPS with WebGPU.
|
|
329
|
+
*/
|
|
330
|
+
preferWebGPU?: boolean;
|
|
331
|
+
/**
|
|
332
|
+
* Force WebGL1 backend for compatibility testing.
|
|
333
|
+
* When enabled, skips WebGPU/WebGL2 probing and uses the WebGL1 fallback directly.
|
|
334
|
+
*/
|
|
335
|
+
forceWebGL1?: boolean;
|
|
336
|
+
/**
|
|
337
|
+
* Experimental.
|
|
338
|
+
* When explicitly set to `true`, VAP / alphaVideo try WebCodecs + mp4box on H.264 MP4
|
|
339
|
+
* and fall back to `HTMLVideoElement` if unsupported or on error.
|
|
340
|
+
* Default: false.
|
|
341
|
+
*/
|
|
342
|
+
preferWebCodecs?: boolean;
|
|
343
|
+
/**
|
|
344
|
+
* Reuse playback resources for identical media sources that start almost together and loop forever.
|
|
345
|
+
* HTMLVideoElement shares the element; WebCodecs additionally shares its Worker, decoder, frame ring,
|
|
346
|
+
* looping clock and compatible GPU upload surface. Default: true.
|
|
347
|
+
*/
|
|
348
|
+
shareIdenticalVideoPlayback?: boolean;
|
|
349
|
+
/**
|
|
350
|
+
* Max start-time gap, in milliseconds, for reusing an already-started shared HTMLVideoElement.
|
|
351
|
+
* Gifts added after this window create their own playback instance so they can still start from frame 0.
|
|
352
|
+
* Default: 100.
|
|
353
|
+
*/
|
|
354
|
+
sharedVideoPlaybackWindowMs?: number;
|
|
355
|
+
/**
|
|
356
|
+
* Experimental WebCodecs-only option.
|
|
357
|
+
* When set, WebCodecs VAP / alphaVideo share one RGBA atlas (single texture bind per frame batch when possible).
|
|
358
|
+
* Reduces bind churn for many concurrent gifts; requires all packed clips to fit in `width×height` (row-packed).
|
|
359
|
+
* If a clip does not fit, that gift falls back to a dedicated texture (same as no atlas).
|
|
360
|
+
*/
|
|
361
|
+
webCodecsVideoAtlas?: {
|
|
362
|
+
width: number;
|
|
363
|
+
height: number;
|
|
364
|
+
};
|
|
365
|
+
/**
|
|
366
|
+
* Experimental WebCodecs-only option.
|
|
367
|
+
* When true (default), H.264 MP4 demux + WebCodecs decode run in a Dedicated Worker; frames transfer to the main thread.
|
|
368
|
+
* Set false to force main-thread decode (e.g. tests).
|
|
369
|
+
*/
|
|
370
|
+
webCodecsDecodeInWorker?: boolean;
|
|
371
|
+
/**
|
|
372
|
+
* Experimental WebCodecs-only option.
|
|
373
|
+
* Max number of decoded VideoFrame instances retained per WebCodecs clip on the main thread (ring).
|
|
374
|
+
* Default 28. Lower values reduce memory; too low may cause brief stalls until decode catches up.
|
|
375
|
+
*/
|
|
376
|
+
webCodecsMaxDecodedFrames?: number;
|
|
377
|
+
/**
|
|
378
|
+
* Experimental WebCodecs-only option.
|
|
379
|
+
* How many frames ahead of the playhead the Worker tries to decode (after demux and on each tick).
|
|
380
|
+
* Default 8. Ignored when {@link webCodecsDecodeInWorker} is false (main-thread path decodes the full clip).
|
|
381
|
+
*/
|
|
382
|
+
webCodecsDecodeAheadFrames?: number;
|
|
383
|
+
/**
|
|
384
|
+
* When true (default), SVGA inflate + protobuf run in a Dedicated Worker.
|
|
385
|
+
* ImageBitmap decode and atlas compose also prefer workers when available.
|
|
386
|
+
* Set false to parse SVGA entirely on the main thread (e.g. tests without Workers).
|
|
387
|
+
*/
|
|
388
|
+
svgaParseInWorker?: boolean;
|
|
389
|
+
/**
|
|
390
|
+
* Max dimension for each SVGA atlas page. Large SVGA image sets are split across pages.
|
|
391
|
+
* Default: 4096, clamped to the backend/device max texture size.
|
|
392
|
+
*/
|
|
393
|
+
svgaAtlasMaxSize?: number;
|
|
394
|
+
/**
|
|
395
|
+
* Max number of SVGA atlas pages before images are globally downscaled.
|
|
396
|
+
* Default: 4.
|
|
397
|
+
*/
|
|
398
|
+
svgaAtlasMaxPages?: number;
|
|
399
|
+
/**
|
|
400
|
+
* Main-thread SVGA atlas compose/upload slice cap in milliseconds.
|
|
401
|
+
* The actual slice tracks half of the observed frame interval, capped here.
|
|
402
|
+
* Default: `12`.
|
|
403
|
+
*/
|
|
404
|
+
svgaAtlasFrameBudgetMs?: number;
|
|
405
|
+
/**
|
|
406
|
+
* Shared main-thread SVGA load slice cap. The actual slice tracks half of
|
|
407
|
+
* the observed display interval and is capped at this value. Default: 12.
|
|
408
|
+
*/
|
|
409
|
+
svgaLoadFrameBudgetMs?: number;
|
|
410
|
+
/**
|
|
411
|
+
* Worker cooperative CPU slice cap in milliseconds. Default: 4, clamped to
|
|
412
|
+
* 1-8. This does not split an individual WASM protobuf call.
|
|
413
|
+
*/
|
|
414
|
+
svgaWorkerFrameBudgetMs?: number;
|
|
415
|
+
/**
|
|
416
|
+
* Global concurrency cap for CPU-heavy SVGA worker tasks (parser, image
|
|
417
|
+
* decode, atlas and clip prewarm). Default: 1.
|
|
418
|
+
*/
|
|
419
|
+
svgaWorkerTaskConcurrency?: number;
|
|
420
|
+
/**
|
|
421
|
+
* Maximum concurrent createImageBitmap calls inside the SVGA image worker.
|
|
422
|
+
* Default: 2; the worker may temporarily reduce concurrency under load.
|
|
423
|
+
*/
|
|
424
|
+
svgaWorkerImageDecodeConcurrency?: number;
|
|
425
|
+
/**
|
|
426
|
+
* Emit one structured parser profile for each actual SVGA parse. Default:
|
|
427
|
+
* false. Cache hits do not emit a profile.
|
|
428
|
+
*/
|
|
429
|
+
svgaParseProfile?: boolean;
|
|
430
|
+
/**
|
|
431
|
+
* Prebuild SVGA clip-path stencil meshes during load instead of first use during playback.
|
|
432
|
+
* Default: true.
|
|
433
|
+
*/
|
|
434
|
+
svgaPrewarmClipMeshes?: boolean;
|
|
435
|
+
/**
|
|
436
|
+
* Main-thread time slice, in milliseconds, used while prewarming SVGA clip meshes.
|
|
437
|
+
* Used only when worker prewarm is unavailable or disabled. Default: 8.
|
|
438
|
+
*/
|
|
439
|
+
svgaClipPrewarmFrameBudgetMs?: number;
|
|
440
|
+
/**
|
|
441
|
+
* Build SVGA clip-path stencil meshes in a Dedicated Worker during load.
|
|
442
|
+
* Preserves the same geometry as main-thread mesh building while avoiding playback-frame stalls.
|
|
443
|
+
* Default: true.
|
|
444
|
+
*/
|
|
445
|
+
svgaClipPrewarmInWorker?: boolean;
|
|
446
|
+
/**
|
|
447
|
+
* Global web-side concurrent resource pipeline limit (download / parse / image decode).
|
|
448
|
+
* Omit to auto-derive from `navigator.hardwareConcurrency`.
|
|
449
|
+
* When provided explicitly, the value is respected as-is (minimum `1`).
|
|
450
|
+
*/
|
|
451
|
+
maxConcurrentParse?: number;
|
|
452
|
+
onError?: (error: Error) => void;
|
|
453
|
+
}
|
|
454
|
+
export interface AddGiftOptions {
|
|
455
|
+
type: GiftType;
|
|
456
|
+
source: string | ArrayBuffer;
|
|
457
|
+
config?: string | object;
|
|
458
|
+
/** SVGA imageKey -> replacement source (TexImageSource or generated text). */
|
|
459
|
+
svgaSlots?: Record<string, SVGASlotContent>;
|
|
460
|
+
/** VAPX srcTag/srcId -> replacement source (text string, image URL, TexImageSource, or structured text/image). */
|
|
461
|
+
vapSlots?: Record<string, VAPSlotContent>;
|
|
462
|
+
/**
|
|
463
|
+
* Layout relative to the stage canvas element.
|
|
464
|
+
* Numbers are treated as CSS pixels.
|
|
465
|
+
* Percentage strings like `50%` use the gift center as anchor on that axis,
|
|
466
|
+
* equivalent to `left/top: 50%` plus `translate(-50%, -50%)` on that axis.
|
|
467
|
+
*/
|
|
468
|
+
x: GiftCoordinate;
|
|
469
|
+
y: GiftCoordinate;
|
|
470
|
+
/**
|
|
471
|
+
* Global render order shared across SVGA / VAP / alphaVideo.
|
|
472
|
+
* Higher values render later and appear above lower values.
|
|
473
|
+
*/
|
|
474
|
+
zIndex?: number;
|
|
475
|
+
/**
|
|
476
|
+
* Display width in CSS pixels. Omit to use the gift's intrinsic width.
|
|
477
|
+
* If only one of `width` / `height` is provided, the other axis is derived from the intrinsic aspect ratio.
|
|
478
|
+
*/
|
|
479
|
+
width?: number;
|
|
480
|
+
/**
|
|
481
|
+
* Display height in CSS pixels. Omit to use the gift's intrinsic height.
|
|
482
|
+
* If both are omitted and the gift is larger than the stage, it is uniformly scaled down to fit the stage.
|
|
483
|
+
*/
|
|
484
|
+
height?: number;
|
|
485
|
+
/**
|
|
486
|
+
* When `true`, and both `width` / `height` are omitted, prefer the gift's intrinsic size
|
|
487
|
+
* if it already fits inside the stage; otherwise scale it down to fit.
|
|
488
|
+
* Default: `false`.
|
|
489
|
+
*/
|
|
490
|
+
useOriginalSize?: boolean;
|
|
491
|
+
/**
|
|
492
|
+
* Omit: `contain` (uniform fit inside width×height) for all types.
|
|
493
|
+
* `cover`: uniform scale to cover width×height; if width/height are both omitted,
|
|
494
|
+
* uses the full stage canvas.
|
|
495
|
+
*/
|
|
496
|
+
objectFit?: GiftObjectFit;
|
|
497
|
+
/** SVGA / video: `0` = loop forever. Video uses `ended` + manual restart when `HTMLVideoElement.loop` is unreliable (e.g. some mobile WebKit). */
|
|
498
|
+
loop?: number;
|
|
499
|
+
/** Global opacity multiplied into the rendered gift. Default: `1`. */
|
|
500
|
+
opacity?: number;
|
|
501
|
+
/** Initial clockwise rotation in radians. Default: `0`. */
|
|
502
|
+
rotation?: number;
|
|
503
|
+
/**
|
|
504
|
+
* Rotation origin inside the unscaled gift box. Numbers are CSS pixels from the
|
|
505
|
+
* top-left corner; percentages are relative to the gift width / height. Values
|
|
506
|
+
* outside the box are allowed so a gift can orbit around an external point.
|
|
507
|
+
* Default: `{ x: '50%', y: '50%' }`.
|
|
508
|
+
*/
|
|
509
|
+
transformOrigin?: {
|
|
510
|
+
x: GiftCoordinate;
|
|
511
|
+
y: GiftCoordinate;
|
|
512
|
+
};
|
|
513
|
+
/**
|
|
514
|
+
* Static image lifetime in milliseconds. Only used by `image` gifts.
|
|
515
|
+
* A positive value completes the gift after the duration; omitted / non-positive
|
|
516
|
+
* values keep the image alive until `destroy()`.
|
|
517
|
+
*/
|
|
518
|
+
duration?: number;
|
|
519
|
+
/**
|
|
520
|
+
* How the RGB region of a split-alpha `vap` / `alphaVideo` source is encoded.
|
|
521
|
+
*
|
|
522
|
+
* - `premultiplied` (default): RGB was already multiplied by that mask; the renderer only applies global opacity.
|
|
523
|
+
* - `straight`: RGB is unassociated; the renderer multiplies it by the separate alpha mask.
|
|
524
|
+
*
|
|
525
|
+
* The stage framebuffer always remains premultiplied regardless of this input setting.
|
|
526
|
+
*/
|
|
527
|
+
videoRGBAlphaMode?: VideoRGBAlphaMode;
|
|
528
|
+
/** Whether to auto-remove after playback stops. Default: true. */
|
|
529
|
+
clearsAfterStop?: boolean;
|
|
530
|
+
mute?: boolean;
|
|
531
|
+
onComplete?: (gift: GiftHandle) => void;
|
|
532
|
+
}
|
|
533
|
+
export interface GiftHandle {
|
|
534
|
+
readonly id: string;
|
|
535
|
+
readonly type: GiftType;
|
|
536
|
+
pause(): void;
|
|
537
|
+
resume(): void;
|
|
538
|
+
destroy(): void;
|
|
539
|
+
animate(options?: GiftAnimationStep | GiftAnimationStep[]): GiftAnimationChain;
|
|
540
|
+
}
|
|
541
|
+
export type GiftState = 'loading' | 'playing' | 'fly' | 'stopped' | 'finished';
|
|
542
|
+
export interface GiftSlot {
|
|
543
|
+
id: string;
|
|
544
|
+
type: GiftType;
|
|
545
|
+
state: GiftState;
|
|
546
|
+
options: AddGiftOptions;
|
|
547
|
+
zIndex?: number;
|
|
548
|
+
renderOrder?: number;
|
|
549
|
+
x: number;
|
|
550
|
+
y: number;
|
|
551
|
+
width: number;
|
|
552
|
+
height: number;
|
|
553
|
+
scale: number;
|
|
554
|
+
opacity: number;
|
|
555
|
+
rotation?: number;
|
|
556
|
+
paused: boolean;
|
|
557
|
+
currentFrame: number;
|
|
558
|
+
accumulatedTime: number;
|
|
559
|
+
lastTickTime: number;
|
|
560
|
+
loopCount: number;
|
|
561
|
+
videoEntity: VideoEntity | null;
|
|
562
|
+
loadAbortController?: AbortController | null;
|
|
563
|
+
svgaSlotTextures?: Map<string, ResolvedSVGASlotTexture>;
|
|
564
|
+
videoElement: HTMLVideoElement | null;
|
|
565
|
+
releaseMediaSource?: (() => void) | null;
|
|
566
|
+
releaseSharedSVGAAsset?: (() => void) | null;
|
|
567
|
+
releaseSharedVideoPlayback?: (() => void) | null;
|
|
568
|
+
releaseSharedVideoTexture?: (() => void) | null;
|
|
569
|
+
/** WebCodecs path: decoded frames + clock; mutually exclusive with `videoElement` for playback. */
|
|
570
|
+
webcodecsPlayback: WebCodecsPlaybackHandle | null;
|
|
571
|
+
/** Shared WebCodecs group, present only for identical infinite-loop sources acquired together. */
|
|
572
|
+
webcodecsSharedState?: WebCodecsSharedPlaybackState | null;
|
|
573
|
+
/** Idempotent release for either a shared or dedicated WebCodecs playback acquisition. */
|
|
574
|
+
releaseWebCodecsPlayback?: (() => void) | null;
|
|
575
|
+
/** Playback time in seconds for {@link webcodecsPlayback}. */
|
|
576
|
+
wcPlaybackTime: number;
|
|
577
|
+
videoTextureHandle: GPUTextureHandle | null;
|
|
578
|
+
imageTextureHandle?: GPUTextureHandle | null;
|
|
579
|
+
releaseSharedImageTexture?: (() => void) | null;
|
|
580
|
+
/** Shared WebCodecs GPU upload target; owns cross-renderer per-frame upload de-duplication. */
|
|
581
|
+
webcodecsSurface?: WebCodecsTextureSurface | null;
|
|
582
|
+
releaseWebCodecsSurface?: (() => void) | null;
|
|
583
|
+
vapMixState?: VAPMixState | null;
|
|
584
|
+
/** WebCodecs + atlas: sub-rect in shared atlas (texels). Omit when using a dedicated texture. */
|
|
585
|
+
wcAtlasRect?: {
|
|
586
|
+
x: number;
|
|
587
|
+
y: number;
|
|
588
|
+
w: number;
|
|
589
|
+
h: number;
|
|
590
|
+
};
|
|
591
|
+
/** RenderManager internal: cached batch key + its dependencies (avoids per-frame string builds). */
|
|
592
|
+
batchKeyCache?: {
|
|
593
|
+
key: string;
|
|
594
|
+
d0: unknown;
|
|
595
|
+
d1: unknown;
|
|
596
|
+
d2: unknown;
|
|
597
|
+
};
|
|
598
|
+
/** RenderManager internal: cached svga slot-texture key (recomputed when the map ref/size changes). */
|
|
599
|
+
svgaSlotTextureKeyCache?: {
|
|
600
|
+
key: string;
|
|
601
|
+
map: unknown;
|
|
602
|
+
size: number;
|
|
603
|
+
};
|
|
604
|
+
onComplete?: (gift: GiftHandle) => void;
|
|
605
|
+
}
|
|
606
|
+
export interface VAPConfig {
|
|
607
|
+
info: {
|
|
608
|
+
v?: number;
|
|
609
|
+
f?: number;
|
|
610
|
+
w: number;
|
|
611
|
+
h: number;
|
|
612
|
+
fps: number;
|
|
613
|
+
videoW: number;
|
|
614
|
+
videoH: number;
|
|
615
|
+
rgbFrame: [number, number, number, number];
|
|
616
|
+
aFrame: [number, number, number, number];
|
|
617
|
+
};
|
|
618
|
+
src?: VAPSrcItem[];
|
|
619
|
+
frame?: VAPFrameItem[];
|
|
620
|
+
}
|
|
621
|
+
export interface VAPSrcItem {
|
|
622
|
+
srcId: string | number;
|
|
623
|
+
srcType: 'img' | 'txt';
|
|
624
|
+
srcTag: string;
|
|
625
|
+
srcUrl?: string;
|
|
626
|
+
loadType?: string;
|
|
627
|
+
w?: number;
|
|
628
|
+
h?: number;
|
|
629
|
+
color?: string;
|
|
630
|
+
style?: string;
|
|
631
|
+
fitType?: string;
|
|
632
|
+
fontStyle?: Record<string, string>;
|
|
633
|
+
}
|
|
634
|
+
export interface VAPFrameItem {
|
|
635
|
+
i: number;
|
|
636
|
+
obj: VAPFrameObj[];
|
|
637
|
+
}
|
|
638
|
+
export interface VAPFrameObj {
|
|
639
|
+
srcId: string | number;
|
|
640
|
+
z?: number;
|
|
641
|
+
mt?: number;
|
|
642
|
+
frame: [number, number, number, number];
|
|
643
|
+
mFrame: [number, number, number, number];
|
|
644
|
+
}
|
|
645
|
+
export interface FlyAnimation {
|
|
646
|
+
giftId: string;
|
|
647
|
+
startX: number;
|
|
648
|
+
startY: number;
|
|
649
|
+
startScale: number;
|
|
650
|
+
startOpacity: number;
|
|
651
|
+
startRotation: number;
|
|
652
|
+
targetX: number;
|
|
653
|
+
targetY: number;
|
|
654
|
+
targetScale: number;
|
|
655
|
+
targetOpacity: number;
|
|
656
|
+
targetRotation: number;
|
|
657
|
+
startTime: number;
|
|
658
|
+
pausedAt?: number;
|
|
659
|
+
duration: number;
|
|
660
|
+
easing: (t: number) => number;
|
|
661
|
+
onComplete?: () => void;
|
|
662
|
+
onCancel?: () => void;
|
|
663
|
+
}
|
|
664
|
+
export interface GiftAnimationStep {
|
|
665
|
+
/** Target center position in CSS pixels. Omit to keep the current visual center. */
|
|
666
|
+
flyTo?: {
|
|
667
|
+
x: number;
|
|
668
|
+
y: number;
|
|
669
|
+
};
|
|
670
|
+
/** Target render scale. Omit to keep the current scale. */
|
|
671
|
+
scaleTo?: number;
|
|
672
|
+
/** Target opacity. Omit to keep the current opacity. */
|
|
673
|
+
opacity?: number;
|
|
674
|
+
/** Target clockwise rotation in radians. Values are interpolated without angle normalization. */
|
|
675
|
+
rotationTo?: number;
|
|
676
|
+
/** Duration in milliseconds. Default: 600. */
|
|
677
|
+
duration?: number;
|
|
678
|
+
/** Easing function receiving normalized time [0, 1]. Default: easeOutCubic. */
|
|
679
|
+
easing?: (t: number) => number;
|
|
680
|
+
onComplete?: (gift: GiftHandle) => void;
|
|
681
|
+
}
|
|
682
|
+
export interface GiftAnimationChain {
|
|
683
|
+
/** Add a step after the current chain. `to` and `then` are aliases. */
|
|
684
|
+
to(options: GiftAnimationStep): GiftAnimationChain;
|
|
685
|
+
/** Add a step after the current chain. `to` and `then` are aliases. */
|
|
686
|
+
then(options: GiftAnimationStep): GiftAnimationChain;
|
|
687
|
+
/** Insert a wait step into the chain. */
|
|
688
|
+
delay(milliseconds: number): GiftAnimationChain;
|
|
689
|
+
/** Callback fired when the whole chain completes. */
|
|
690
|
+
onComplete(callback: (gift: GiftHandle) => void): GiftAnimationChain;
|
|
691
|
+
/**
|
|
692
|
+
* Play the chain and resolve when all steps complete.
|
|
693
|
+
* - `immediate`: run now (default).
|
|
694
|
+
* - `afterGiftComplete`: wait until gift playback completes, then run.
|
|
695
|
+
*/
|
|
696
|
+
start(mode?: 'immediate' | 'afterGiftComplete'): Promise<GiftHandle>;
|
|
697
|
+
/** Cancel the active animation for this gift. */
|
|
698
|
+
cancel(): void;
|
|
699
|
+
}
|