@taole/giftstage 0.1.27 → 0.1.29
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 +667 -605
- 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 +198 -171
- package/dist/gift-stage.es.js +2806 -2255
- 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 +15 -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
package/README.md
CHANGED
|
@@ -1,636 +1,698 @@
|
|
|
1
|
-
# GiftStage
|
|
2
|
-
|
|
3
|
-
统一的 Web 礼物播放框架,支持:
|
|
4
|
-
|
|
5
|
-
- `SVGA`
|
|
6
|
-
- `VAP / VAPX`
|
|
1
|
+
# GiftStage
|
|
2
|
+
|
|
3
|
+
统一的 Web 礼物播放框架,支持:
|
|
4
|
+
|
|
5
|
+
- `SVGA`
|
|
6
|
+
- `VAP / VAPX`
|
|
7
7
|
- 透明视频 `AlphaVideo`
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
- `
|
|
13
|
-
- `
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
-
|
|
19
|
-
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
-
|
|
25
|
-
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
- `
|
|
41
|
-
- `
|
|
42
|
-
-
|
|
43
|
-
-
|
|
44
|
-
-
|
|
8
|
+
- 静态图片 `Image`
|
|
9
|
+
|
|
10
|
+
底层支持:
|
|
11
|
+
|
|
12
|
+
- `WebGPU`
|
|
13
|
+
- `WebGL2`
|
|
14
|
+
- `WebGL1` 兼容兜底
|
|
15
|
+
|
|
16
|
+
适用场景:
|
|
17
|
+
|
|
18
|
+
- 直播间礼物
|
|
19
|
+
- 大批同屏动画
|
|
20
|
+
- 需要统一接入 `SVGA / VAP / 透明视频 / 图片` 的业务场景
|
|
21
|
+
|
|
22
|
+
## npm 包信息
|
|
23
|
+
|
|
24
|
+
- 包名:`@taole/giftstage`
|
|
25
|
+
- npm:`npm i @taole/giftstage`
|
|
26
|
+
- ESM 导入:
|
|
27
|
+
|
|
28
|
+
```ts
|
|
29
|
+
import { GiftStage } from '@taole/giftstage';
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
- CommonJS 导入:
|
|
33
|
+
|
|
34
|
+
```js
|
|
35
|
+
const { GiftStage } = require('@taole/giftstage');
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
## 特性
|
|
39
|
+
|
|
40
|
+
- 统一 API:`addGift()` 即可播放四类礼物
|
|
41
|
+
- `SVGA` 支持 Worker 解析、atlas 缓存、slot 替换
|
|
42
|
+
- `VAP / AlphaVideo` 支持实验性的 `WebCodecs` 和稳定的 `HTMLVideoElement` 双路径
|
|
43
|
+
- 同源视频播放实例、纹理、资源复用
|
|
44
|
+
- 内存 LRU 缓存,默认 `128MB`
|
|
45
|
+
- `IndexedDB` 磁盘 LRU 缓存,默认 `2048MB`
|
|
45
46
|
- `x / y` 支持百分比定位
|
|
46
47
|
- `width / height` 支持按礼物原始尺寸自动补全
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
- `gift.
|
|
48
|
+
- 四类礼物共用位移、缩放、透明度、旋转、层级和销毁生命周期
|
|
49
|
+
|
|
50
|
+
## 安装
|
|
51
|
+
|
|
52
|
+
```bash
|
|
53
|
+
npm install
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
安装发布包:
|
|
57
|
+
|
|
58
|
+
```bash
|
|
59
|
+
npm i @taole/giftstage
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
## 开发
|
|
63
|
+
|
|
64
|
+
```bash
|
|
65
|
+
npm run dev
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
## 构建
|
|
69
|
+
|
|
70
|
+
```bash
|
|
71
|
+
npm run build
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
Demo 构建:
|
|
75
|
+
|
|
76
|
+
```bash
|
|
77
|
+
npm run build:demo
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
## 快速开始
|
|
81
|
+
|
|
82
|
+
```ts
|
|
83
|
+
import { GiftStage } from '@taole/giftstage';
|
|
84
|
+
|
|
85
|
+
const container = document.getElementById('app')!;
|
|
86
|
+
|
|
87
|
+
const stage = new GiftStage({
|
|
88
|
+
container,
|
|
89
|
+
preferWebGPU: true,
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
await stage.ready;
|
|
93
|
+
|
|
94
|
+
await stage.addGift({
|
|
95
|
+
type: 'svga',
|
|
96
|
+
source: 'https://example.com/demo.svga',
|
|
97
|
+
x: 100,
|
|
98
|
+
y: 100,
|
|
99
|
+
loop: 0,
|
|
100
|
+
});
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
## 核心 API
|
|
104
|
+
|
|
105
|
+
### `new GiftStage(options)`
|
|
106
|
+
|
|
107
|
+
创建礼物舞台。
|
|
108
|
+
|
|
109
|
+
常用配置:
|
|
110
|
+
|
|
111
|
+
- `container: HTMLElement`
|
|
112
|
+
挂载容器。
|
|
113
|
+
|
|
114
|
+
- `resolution?: number`
|
|
115
|
+
指定 canvas backing store 分辨率倍率。默认跟随 `devicePixelRatio`。
|
|
116
|
+
|
|
117
|
+
- `antialias?: boolean`
|
|
118
|
+
是否开启抗锯齿。
|
|
119
|
+
|
|
120
|
+
- `preferWebGPU?: boolean`
|
|
121
|
+
是否优先使用 `WebGPU`。
|
|
122
|
+
|
|
123
|
+
- `forceWebGL1?: boolean`
|
|
124
|
+
强制走 `WebGL1`,用于兼容性验证。
|
|
125
|
+
|
|
126
|
+
- `preferWebCodecs?: boolean`
|
|
127
|
+
实验性特性。默认关闭;显式传 `true` 时才会尝试用 `WebCodecs` 播放 `VAP / AlphaVideo`。
|
|
128
|
+
|
|
129
|
+
- `shareIdenticalVideoPlayback?: boolean`
|
|
130
|
+
是否复用近同时起播的同源视频播放实例。默认开启。
|
|
131
|
+
|
|
132
|
+
- `sharedVideoPlaybackWindowMs?: number`
|
|
133
|
+
同源视频共享播放窗口,默认 `100ms`。
|
|
134
|
+
|
|
135
|
+
- `webCodecsVideoAtlas?: { width: number; height: number }`
|
|
136
|
+
实验性 `WebCodecs` 视频共享 atlas 配置。
|
|
137
|
+
|
|
138
|
+
- `webCodecsDecodeInWorker?: boolean`
|
|
139
|
+
实验性 `WebCodecs` 选项,控制是否在 Worker 中执行解码。
|
|
140
|
+
|
|
141
|
+
- `webCodecsMaxDecodedFrames?: number`
|
|
142
|
+
实验性 `WebCodecs` 选项,控制保留的最大解码帧数。
|
|
143
|
+
|
|
144
|
+
- `webCodecsDecodeAheadFrames?: number`
|
|
145
|
+
实验性 `WebCodecs` 选项,控制前向解码帧数。
|
|
146
|
+
|
|
147
|
+
- `svgaParseInWorker?: boolean`
|
|
148
|
+
是否在 Worker 中解析 SVGA。
|
|
149
|
+
|
|
150
|
+
- `maxConcurrentParse?: number`
|
|
151
|
+
资源下载 / 解析 / 图像解码的并发数。
|
|
152
|
+
不传时自动跟随 `navigator.hardwareConcurrency`。
|
|
153
|
+
|
|
154
|
+
- `svgaAtlasFrameBudgetMs?: number`
|
|
155
|
+
SVGA atlas 在主线程组合或逐页上传时的单帧时间片上限,默认 `12ms`。
|
|
156
|
+
实际时间片会按当前刷新周期的一半动态调整,避免高刷新率设备上的加载任务挤占渲染帧。
|
|
157
|
+
|
|
158
|
+
- `svgaLoadFrameBudgetMs?: number`
|
|
159
|
+
SVGA 主线程加载任务的共享时间片上限,默认 `12ms`。图片 fallback、atlas、clip、音频、slot 纹理和二进制缓存共用同一帧预算。
|
|
160
|
+
|
|
161
|
+
- `svgaWorkerFrameBudgetMs?: number`
|
|
162
|
+
SVGA Worker 连续执行 JS 循环的时间片上限,默认 `4ms`,范围 `1-8ms`。单次 WASM protobuf 调用和单次原生 API 调用仍不可抢占。
|
|
163
|
+
|
|
164
|
+
- `svgaWorkerTaskConcurrency?: number`
|
|
165
|
+
parser、图片解码、atlas 和 clip 等 CPU 密集 Worker 的全局并发上限,默认 `1`。Atlas 首帧页面可提前返回,但后台 PNG 编码完成前仍持有该名额,避免与其他重载 Worker 叠加。
|
|
166
|
+
|
|
167
|
+
- `svgaWorkerImageDecodeConcurrency?: number`
|
|
168
|
+
图片解码 Worker 内 `createImageBitmap` 并发上限,默认 `2`。运行时可按批次耗时收缩并发,负载恢复后回升,但不会超过该上限。
|
|
169
|
+
|
|
170
|
+
- `svgaParseProfile?: boolean`
|
|
171
|
+
是否输出 `[GiftStage:SVGA:Profile]` 结构化解析日志,默认 `false`。日志包含 `DecompressionStream` 格式尝试、输入/输出 chunk、解压耗时以及 protobuf/payload 构建耗时;WASM payload 路径还会拆分 `prostDecodeMs`、`metadataAndImagesMs`、`frameTableMs`、`finalizeMs` 和 WASM 边界复制耗时。缓存命中不输出。
|
|
172
|
+
|
|
173
|
+
SVGA 礼物在加载阶段被 `destroy()` / `removeGift()` 时,会取消排队任务并终止正在执行的 parser、图片解码、atlas 或 clip Worker。相同 URL 的共享加载按消费者计数,单个礼物取消不会中断其他仍在等待的礼物。
|
|
174
|
+
|
|
175
|
+
- `onError?: (error: Error) => void`
|
|
176
|
+
统一错误回调。
|
|
177
|
+
|
|
178
|
+
### `await stage.ready`
|
|
179
|
+
|
|
180
|
+
等待底层后端和运行环境初始化完成。建议在第一次 `addGift()` 前等待。
|
|
181
|
+
|
|
182
|
+
### `stage.addGift(options)`
|
|
183
|
+
|
|
184
|
+
插入一个礼物,返回:
|
|
185
|
+
|
|
186
|
+
```ts
|
|
187
|
+
Promise<GiftHandle>;
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
### `GiftHandle` API
|
|
191
|
+
|
|
192
|
+
`addGift()` 返回的句柄可用于控制单个礼物:
|
|
193
|
+
|
|
194
|
+
- `gift.id`
|
|
195
|
+
- `gift.type`
|
|
194
196
|
- `gift.pause()`
|
|
195
197
|
- `gift.resume()`
|
|
196
|
-
- `
|
|
197
|
-
|
|
198
|
-
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
-
|
|
206
|
-
|
|
207
|
-
-
|
|
208
|
-
|
|
209
|
-
-
|
|
210
|
-
|
|
211
|
-
- `immediate
|
|
212
|
-
- `
|
|
213
|
-
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
- `
|
|
242
|
-
- `
|
|
243
|
-
- `
|
|
244
|
-
- `
|
|
245
|
-
- `
|
|
246
|
-
- `
|
|
247
|
-
- `
|
|
248
|
-
- `
|
|
249
|
-
- `
|
|
250
|
-
|
|
198
|
+
- 暂停期间礼物播放时钟、图片 `duration` 和后置动画都会冻结
|
|
199
|
+
- `gift.destroy()`
|
|
200
|
+
- 立即移除当前礼物
|
|
201
|
+
- `gift.animate(stepOrSteps?)`
|
|
202
|
+
- 创建链式动画并返回 `GiftAnimationChain`
|
|
203
|
+
|
|
204
|
+
`GiftAnimationChain` 支持:
|
|
205
|
+
|
|
206
|
+
- `.to(step)` / `.then(step)`
|
|
207
|
+
- 追加动画步骤(两者等价)
|
|
208
|
+
- `.delay(milliseconds)`
|
|
209
|
+
- 在链中插入等待,不改变位置、缩放和透明度
|
|
210
|
+
- `.onComplete((gift) => void)`
|
|
211
|
+
- 整条链执行完成后的回调
|
|
212
|
+
- `.start(mode?)`
|
|
213
|
+
- `mode: 'immediate' | 'afterGiftComplete'`
|
|
214
|
+
- `immediate`:立即开始(默认)
|
|
215
|
+
- `afterGiftComplete`:等待礼物主播放结束后再执行链
|
|
216
|
+
- `.cancel()`
|
|
217
|
+
- 取消当前礼物正在执行的链式动画
|
|
218
|
+
|
|
219
|
+
### `stage.removeGift(id)`
|
|
220
|
+
|
|
221
|
+
按 ID 移除礼物。
|
|
222
|
+
|
|
223
|
+
### `stage.removeAll()`
|
|
224
|
+
|
|
225
|
+
移除全部礼物。
|
|
226
|
+
|
|
227
|
+
### `stage.pause()`
|
|
228
|
+
|
|
229
|
+
暂停舞台。
|
|
230
|
+
|
|
231
|
+
### `stage.resume()`
|
|
232
|
+
|
|
233
|
+
恢复舞台。
|
|
234
|
+
|
|
235
|
+
### `stage.destroy()`
|
|
236
|
+
|
|
237
|
+
销毁舞台并释放资源。
|
|
238
|
+
|
|
239
|
+
## `addGift()` 参数
|
|
240
|
+
|
|
241
|
+
### 通用参数
|
|
242
|
+
|
|
243
|
+
- `type: 'svga' | 'vap' | 'alphaVideo' | 'image'`
|
|
244
|
+
- `source: string | ArrayBuffer`
|
|
245
|
+
- `x: number | \`${number}%\``
|
|
246
|
+
- `y: number | \`${number}%\``
|
|
247
|
+
- `zIndex?: number`
|
|
248
|
+
- `width?: number`
|
|
249
|
+
- `height?: number`
|
|
250
|
+
- `useOriginalSize?: boolean`
|
|
251
|
+
- `objectFit?: 'contain' | 'cover'`
|
|
252
|
+
- `loop?: number`
|
|
253
|
+
- `0` 表示无限循环
|
|
251
254
|
- `opacity?: number`
|
|
252
255
|
- 全局透明度,范围 `0 ~ 1`,默认 `1`
|
|
253
|
-
- `
|
|
254
|
-
-
|
|
255
|
-
|
|
256
|
+
- `rotation?: number`
|
|
257
|
+
- 初始旋转弧度;屏幕坐标中正值为顺时针
|
|
258
|
+
- `transformOrigin?: { x: number | \`${number}%\`; y: number | \`${number}%\` }`
|
|
259
|
+
- 相对未缩放礼物框左上角,默认 `50% / 50%`
|
|
260
|
+
- 数值使用 CSS 像素;允许负值或超过礼物宽高,用于绕框外点公转
|
|
261
|
+
- `videoRGBAlphaMode?: 'straight' | 'premultiplied'`
|
|
262
|
+
- 仅用于 `vap` / `alphaVideo` 分离 Alpha 视频源,默认 `premultiplied`
|
|
263
|
+
- `straight`:RGB 区域尚未乘独立 Alpha,播放器负责预乘
|
|
264
|
+
- `premultiplied`:RGB 区域在制作阶段已经乘过独立 Alpha,播放器不会再次相乘
|
|
265
|
+
- 该参数只描述输入视频;最终画布仍统一输出预乘 Alpha
|
|
266
|
+
- `clearsAfterStop?: boolean`
|
|
267
|
+
- 播放结束后,是否自动移除礼物
|
|
268
|
+
- 默认 `true`,传 `false` 时会停留最后一帧,方便后续继续调用 `gift.animate(...).start()`
|
|
256
269
|
- `mute?: boolean`
|
|
257
270
|
- `onComplete?: (gift) => void`
|
|
258
271
|
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
- `
|
|
262
|
-
-
|
|
263
|
-
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
-
|
|
270
|
-
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
272
|
+
图片专用参数:
|
|
273
|
+
|
|
274
|
+
- `duration?: number`
|
|
275
|
+
- 单位毫秒;正数到期后触发 `onComplete`,并遵循 `clearsAfterStop`
|
|
276
|
+
- 不传或传非正数时持续显示到 `destroy()`;加载完成后 `afterGiftComplete` 可立即继续,但不会自动触发 `onComplete`
|
|
277
|
+
- `image` 忽略 `loop` 和 `mute`
|
|
278
|
+
|
|
279
|
+
层级规则:
|
|
280
|
+
|
|
281
|
+
- `zIndex` 在 `SVGA / VAP / AlphaVideo / Image` 四种礼物间通用
|
|
282
|
+
- 数值越大,渲染越靠上
|
|
283
|
+
- 同层级下,后 `addGift()` 的礼物会覆盖先添加的礼物
|
|
284
|
+
|
|
285
|
+
### 宽高默认行为
|
|
286
|
+
|
|
287
|
+
`width / height` 现在是可选参数,规则如下:
|
|
288
|
+
|
|
289
|
+
- 两个都传:按传入值显示
|
|
290
|
+
- 只传 `width`:`height` 按礼物原始宽高比自动补全
|
|
291
|
+
- 只传 `height`:`width` 按礼物原始宽高比自动补全
|
|
292
|
+
- 两个都不传:默认按当前画布尺寸做等比 `contain`
|
|
293
|
+
- 如果 `objectFit: 'cover'` 且两个都不传:按整个画布作为显示区域做等比 `cover`
|
|
294
|
+
- 也就是会在画布内尽可能放大或缩小,并保持礼物原始宽高比
|
|
295
|
+
- 如果 `useOriginalSize: true`,且礼物原始尺寸本身小于画布,则优先使用礼物原始尺寸
|
|
296
|
+
- 如果 `useOriginalSize: true`,但礼物原始尺寸超出画布,则仍会按画布尺寸等比缩小
|
|
297
|
+
|
|
298
|
+
例如:
|
|
299
|
+
|
|
300
|
+
```ts
|
|
301
|
+
await stage.addGift({
|
|
302
|
+
type: 'svga',
|
|
303
|
+
source: 'https://example.com/demo.svga',
|
|
304
|
+
x: '50%',
|
|
305
|
+
y: '50%',
|
|
306
|
+
loop: 0,
|
|
307
|
+
});
|
|
308
|
+
```
|
|
309
|
+
|
|
310
|
+
这时会按舞台尺寸做等比适配,并保持礼物原始宽高比。
|
|
311
|
+
|
|
312
|
+
如果希望礼物铺满整个画布,并按中心裁剪超出的部分,可以使用 `cover`:
|
|
313
|
+
|
|
314
|
+
```ts
|
|
315
|
+
await stage.addGift({
|
|
316
|
+
type: 'svga',
|
|
317
|
+
source: 'https://example.com/demo.svga',
|
|
318
|
+
x: '50%',
|
|
319
|
+
y: '50%',
|
|
320
|
+
objectFit: 'cover',
|
|
321
|
+
loop: 0,
|
|
322
|
+
});
|
|
323
|
+
```
|
|
324
|
+
|
|
325
|
+
当 `x: '50%'`、`y: '50%'` 且未传 `width / height` 时,显示区域会居中放在整个画布上;`cover` 会保持礼物原始宽高比铺满该区域,并从中心裁剪溢出的部分。
|
|
326
|
+
|
|
327
|
+
如果你希望“小礼物保持原始尺寸,大礼物再缩小”,可以这样:
|
|
328
|
+
|
|
329
|
+
```ts
|
|
330
|
+
await stage.addGift({
|
|
331
|
+
type: 'svga',
|
|
332
|
+
source: 'https://example.com/demo.svga',
|
|
333
|
+
x: '50%',
|
|
334
|
+
y: '50%',
|
|
335
|
+
useOriginalSize: true,
|
|
336
|
+
loop: 0,
|
|
337
|
+
});
|
|
338
|
+
```
|
|
339
|
+
|
|
340
|
+
### 百分比坐标
|
|
341
|
+
|
|
342
|
+
`x / y` 支持百分比,例如:
|
|
343
|
+
|
|
344
|
+
```ts
|
|
345
|
+
await stage.addGift({
|
|
346
|
+
type: 'svga',
|
|
347
|
+
source: 'https://example.com/demo.svga',
|
|
348
|
+
x: '50%',
|
|
349
|
+
y: '50%',
|
|
350
|
+
width: 300,
|
|
351
|
+
height: 300,
|
|
352
|
+
loop: 0,
|
|
353
|
+
});
|
|
354
|
+
```
|
|
355
|
+
|
|
356
|
+
语义是:
|
|
357
|
+
|
|
358
|
+
- `x: '50%'` 按容器宽度的 `50%` 定位,并减去自身一半宽度
|
|
359
|
+
- `y: '50%'` 按容器高度的 `50%` 定位,并减去自身一半高度
|
|
360
|
+
|
|
361
|
+
也就是接近:
|
|
362
|
+
|
|
363
|
+
```css
|
|
364
|
+
left: 50%;
|
|
365
|
+
top: 50%;
|
|
366
|
+
transform: translate(-50%, -50%);
|
|
367
|
+
```
|
|
368
|
+
|
|
369
|
+
如果是数值,则继续按原来的像素坐标语义处理。
|
|
370
|
+
|
|
371
|
+
## 四类礼物示例
|
|
372
|
+
|
|
373
|
+
### 播放 SVGA
|
|
374
|
+
|
|
375
|
+
```ts
|
|
376
|
+
await stage.addGift({
|
|
377
|
+
type: 'svga',
|
|
378
|
+
source: 'https://example.com/demo.svga',
|
|
379
|
+
x: 20,
|
|
380
|
+
y: 20,
|
|
381
|
+
width: 300,
|
|
382
|
+
height: 300,
|
|
383
|
+
loop: 1,
|
|
384
|
+
});
|
|
385
|
+
```
|
|
386
|
+
|
|
387
|
+
### 播放 VAP
|
|
388
|
+
|
|
389
|
+
```ts
|
|
390
|
+
await stage.addGift({
|
|
391
|
+
type: 'vap',
|
|
392
|
+
source: 'https://example.com/demo.mp4',
|
|
393
|
+
config: 'https://example.com/demo.json',
|
|
394
|
+
x: 20,
|
|
395
|
+
y: 20,
|
|
396
|
+
width: 400,
|
|
397
|
+
height: 220,
|
|
398
|
+
// 默认 premultiplied;RGB 尚未乘独立 Alpha 的视频源需显式传 straight
|
|
399
|
+
videoRGBAlphaMode: 'premultiplied',
|
|
400
|
+
loop: 0,
|
|
401
|
+
});
|
|
402
|
+
```
|
|
403
|
+
|
|
404
|
+
### 播放透明视频
|
|
405
|
+
|
|
406
|
+
```ts
|
|
407
|
+
await stage.addGift({
|
|
408
|
+
type: 'alphaVideo',
|
|
409
|
+
source: 'https://example.com/demo.mp4',
|
|
410
|
+
x: 20,
|
|
411
|
+
y: 20,
|
|
412
|
+
width: 400,
|
|
413
|
+
height: 220,
|
|
414
|
+
// 默认 premultiplied;未预乘的视频源改为 straight
|
|
415
|
+
videoRGBAlphaMode: 'premultiplied',
|
|
416
|
+
loop: 0,
|
|
287
417
|
});
|
|
288
418
|
```
|
|
289
419
|
|
|
290
|
-
|
|
420
|
+
### 播放图片
|
|
291
421
|
|
|
292
|
-
|
|
422
|
+
`source` 首版支持 URL 和 `ArrayBuffer`。URL 图片会按地址共享 GPU 纹理并引用计数;图片按静态帧处理,不保证 GIF / WebP 动画播放。跨域 URL 必须允许匿名 CORS 读取。
|
|
293
423
|
|
|
294
424
|
```ts
|
|
295
|
-
await stage.addGift({
|
|
296
|
-
type: '
|
|
297
|
-
source: 'https://example.com/
|
|
425
|
+
const avatar = await stage.addGift({
|
|
426
|
+
type: 'image',
|
|
427
|
+
source: 'https://example.com/avatar.png',
|
|
298
428
|
x: '50%',
|
|
299
429
|
y: '50%',
|
|
430
|
+
width: 100,
|
|
431
|
+
height: 100,
|
|
300
432
|
objectFit: 'cover',
|
|
301
|
-
|
|
433
|
+
duration: 5000,
|
|
302
434
|
});
|
|
303
435
|
```
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
type: 'svga',
|
|
327
|
-
source: 'https://example.com/demo.svga',
|
|
328
|
-
x: '50%',
|
|
329
|
-
y: '50%',
|
|
330
|
-
width: 300,
|
|
331
|
-
height: 300,
|
|
332
|
-
loop: 0,
|
|
333
|
-
});
|
|
334
|
-
```
|
|
335
|
-
|
|
336
|
-
语义是:
|
|
337
|
-
|
|
338
|
-
- `x: '50%'` 按容器宽度的 `50%` 定位,并减去自身一半宽度
|
|
339
|
-
- `y: '50%'` 按容器高度的 `50%` 定位,并减去自身一半高度
|
|
340
|
-
|
|
341
|
-
也就是接近:
|
|
342
|
-
|
|
343
|
-
```css
|
|
344
|
-
left: 50%;
|
|
345
|
-
top: 50%;
|
|
346
|
-
transform: translate(-50%, -50%);
|
|
347
|
-
```
|
|
348
|
-
|
|
349
|
-
如果是数值,则继续按原来的像素坐标语义处理。
|
|
350
|
-
|
|
351
|
-
## 三类礼物示例
|
|
352
|
-
|
|
353
|
-
### 播放 SVGA
|
|
354
|
-
|
|
355
|
-
```ts
|
|
356
|
-
await stage.addGift({
|
|
357
|
-
type: 'svga',
|
|
358
|
-
source: 'https://example.com/demo.svga',
|
|
359
|
-
x: 20,
|
|
360
|
-
y: 20,
|
|
361
|
-
width: 300,
|
|
362
|
-
height: 300,
|
|
363
|
-
loop: 1,
|
|
364
|
-
});
|
|
365
|
-
```
|
|
366
|
-
|
|
367
|
-
### 播放 VAP
|
|
368
|
-
|
|
369
|
-
```ts
|
|
370
|
-
await stage.addGift({
|
|
371
|
-
type: 'vap',
|
|
372
|
-
source: 'https://example.com/demo.mp4',
|
|
373
|
-
config: 'https://example.com/demo.json',
|
|
374
|
-
x: 20,
|
|
375
|
-
y: 20,
|
|
376
|
-
width: 400,
|
|
377
|
-
height: 220,
|
|
378
|
-
loop: 0,
|
|
379
|
-
});
|
|
380
|
-
```
|
|
381
|
-
|
|
382
|
-
### 播放透明视频
|
|
383
|
-
|
|
384
|
-
```ts
|
|
385
|
-
await stage.addGift({
|
|
386
|
-
type: 'alphaVideo',
|
|
387
|
-
source: 'https://example.com/demo.mp4',
|
|
388
|
-
x: 20,
|
|
389
|
-
y: 20,
|
|
390
|
-
width: 400,
|
|
391
|
-
height: 220,
|
|
392
|
-
loop: 0,
|
|
393
|
-
});
|
|
394
|
-
```
|
|
395
|
-
|
|
396
|
-
## 动画控制
|
|
397
|
-
|
|
398
|
-
### 链式动画
|
|
399
|
-
|
|
400
|
-
`addGift()` 返回的 `GiftHandle` 支持 `animate()`。一次 `to()` 是组合动画,同一步里可以同时移动、缩放和改变透明度;多个 `to()` / `then()` 会按顺序播放:
|
|
401
|
-
|
|
402
|
-
```ts
|
|
403
|
-
const gift = await stage.addGift({
|
|
404
|
-
type: 'svga',
|
|
405
|
-
source: 'https://example.com/demo.svga',
|
|
406
|
-
x: '50%',
|
|
407
|
-
y: '50%',
|
|
408
|
-
width: 300,
|
|
409
|
-
height: 300,
|
|
410
|
-
loop: 0,
|
|
411
|
-
});
|
|
412
|
-
|
|
413
|
-
await gift
|
|
414
|
-
.animate()
|
|
415
|
-
.to({
|
|
416
|
-
flyTo: { x: 200, y: 240 },
|
|
436
|
+
|
|
437
|
+
## 动画控制
|
|
438
|
+
|
|
439
|
+
### 链式动画
|
|
440
|
+
|
|
441
|
+
`addGift()` 返回的 `GiftHandle` 支持 `animate()`。一次 `to()` 是组合动画,同一步里可以同时移动、缩放、改变透明度和旋转;多个 `to()` / `then()` 会按顺序播放。`rotationTo` 直接按数值线性插值,不做最短角度归一化,因此可以明确表达多圈旋转:
|
|
442
|
+
|
|
443
|
+
```ts
|
|
444
|
+
const gift = await stage.addGift({
|
|
445
|
+
type: 'svga',
|
|
446
|
+
source: 'https://example.com/demo.svga',
|
|
447
|
+
x: '50%',
|
|
448
|
+
y: '50%',
|
|
449
|
+
width: 300,
|
|
450
|
+
height: 300,
|
|
451
|
+
loop: 0,
|
|
452
|
+
});
|
|
453
|
+
|
|
454
|
+
await gift
|
|
455
|
+
.animate()
|
|
456
|
+
.to({
|
|
457
|
+
flyTo: { x: 200, y: 240 },
|
|
417
458
|
scaleTo: 0.8,
|
|
418
459
|
opacity: 0.6,
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
.
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
也可以传入单步或数组:
|
|
439
|
-
|
|
440
|
-
```ts
|
|
441
|
-
gift.animate({ flyTo: { x: 300, y: 300 }, scaleTo: 0.5, opacity: 0.3 }).start();
|
|
442
|
-
|
|
443
|
-
gift
|
|
444
|
-
.animate([
|
|
445
|
-
{ flyTo: { x: 300, y: 300 }, duration: 400 },
|
|
446
|
-
{ scaleTo: 1, opacity: 1, duration: 300 },
|
|
447
|
-
])
|
|
448
|
-
.start();
|
|
460
|
+
rotationTo: Math.PI * 4,
|
|
461
|
+
duration: 500,
|
|
462
|
+
})
|
|
463
|
+
.then({
|
|
464
|
+
flyTo: { x: 600, y: 320 },
|
|
465
|
+
scaleTo: 1.1,
|
|
466
|
+
opacity: 1,
|
|
467
|
+
duration: 700,
|
|
468
|
+
})
|
|
469
|
+
.delay(300)
|
|
470
|
+
.then({
|
|
471
|
+
opacity: 0,
|
|
472
|
+
duration: 400,
|
|
473
|
+
})
|
|
474
|
+
.onComplete((g) => {
|
|
475
|
+
console.log('chain complete', g.id);
|
|
476
|
+
})
|
|
477
|
+
.start();
|
|
449
478
|
```
|
|
450
479
|
|
|
451
|
-
|
|
480
|
+
### 绕外部中心旋转
|
|
452
481
|
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
使用 `svgaSlots`:
|
|
482
|
+
下面的礼物初始位于舞台中心右侧 200px,旋转中心通过框外坐标指回舞台中心:
|
|
456
483
|
|
|
457
484
|
```ts
|
|
458
|
-
await stage.addGift({
|
|
459
|
-
type: '
|
|
460
|
-
source: 'https://example.com/
|
|
461
|
-
x:
|
|
462
|
-
y:
|
|
463
|
-
width:
|
|
464
|
-
height:
|
|
465
|
-
|
|
466
|
-
avatar: { image: avatarImage },
|
|
467
|
-
title: {
|
|
468
|
-
text: 'Hello',
|
|
469
|
-
color: '#ff0000',
|
|
470
|
-
fontSize: 28,
|
|
471
|
-
mode: 'dynamic',
|
|
472
|
-
},
|
|
473
|
-
},
|
|
485
|
+
const orbitGift = await stage.addGift({
|
|
486
|
+
type: 'image',
|
|
487
|
+
source: 'https://example.com/gift.png',
|
|
488
|
+
x: container.clientWidth / 2 + 150,
|
|
489
|
+
y: '50%',
|
|
490
|
+
width: 100,
|
|
491
|
+
height: 100,
|
|
492
|
+
transformOrigin: { x: -150, y: '50%' },
|
|
474
493
|
});
|
|
475
|
-
```
|
|
476
|
-
|
|
477
|
-
支持:
|
|
478
|
-
|
|
479
|
-
- `TexImageSource`
|
|
480
|
-
- 文本配置
|
|
481
|
-
- 图片配置
|
|
482
|
-
|
|
483
|
-
SVGA 文本配置会按目标 frame 自动适配字号,避免文字超出槽位:
|
|
484
|
-
|
|
485
|
-
- `mode: 'dynamic'`:默认行为。生成文字自身尺寸的纹理,渲染时按自身逻辑尺寸居中到 frame 内,不会被拉伸。
|
|
486
|
-
- `mode: 'replace'`:生成和 frame 一样大的纹理,按替换图逻辑铺满 frame。
|
|
487
|
-
- `fontSize?: number`:期望字号;如果文字放不下,会自动缩小。
|
|
488
|
-
- `minFontSize?: number` / `maxFontSize?: number`:限制自适应字号范围。
|
|
489
|
-
- `padding?: number`:文字纹理内边距,默认 `2`。
|
|
490
|
-
- `scale?: number`:文字纹理栅格倍率,SVGA 默认 `3`,用于保持清晰度。
|
|
491
|
-
- `fontStyle?: string | { font?: string; color?: string }`:字体样式,SVGA / VAP 都支持。
|
|
492
|
-
|
|
493
|
-
`fontStyle` 可以直接传 canvas font 字符串:
|
|
494
|
-
|
|
495
|
-
```ts
|
|
496
|
-
svgaSlots: {
|
|
497
|
-
title: {
|
|
498
|
-
text: 'Hello',
|
|
499
|
-
fontStyle: 'bold 40px Arial',
|
|
500
|
-
},
|
|
501
|
-
}
|
|
502
|
-
```
|
|
503
|
-
|
|
504
|
-
也可以传对象:
|
|
505
|
-
|
|
506
|
-
```ts
|
|
507
|
-
vapSlots: {
|
|
508
|
-
welcome01: {
|
|
509
|
-
text: '欢迎进入房间',
|
|
510
|
-
fontStyle: {
|
|
511
|
-
font: 'bold 40px Arial',
|
|
512
|
-
color: '#ffffff',
|
|
513
|
-
},
|
|
514
|
-
},
|
|
515
|
-
}
|
|
516
|
-
```
|
|
517
|
-
|
|
518
|
-
对象形式目前生效字段是 `font` 和 `color`。如果同时传了外层 `color` 和 `fontStyle.color`,以 `fontStyle.color` 为准。VAP 文本如果没有传 `fontStyle`,会回退使用 VAP 配置里的 `src.fontStyle`。
|
|
519
|
-
|
|
520
|
-
### VAP / VAPX
|
|
521
494
|
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
await stage.addGift({
|
|
526
|
-
type: 'vap',
|
|
527
|
-
source: 'https://example.com/demo.mp4',
|
|
528
|
-
config: 'https://example.com/demo.json',
|
|
529
|
-
x: 0,
|
|
530
|
-
y: 0,
|
|
531
|
-
width: 400,
|
|
532
|
-
height: 400,
|
|
533
|
-
vapSlots: {
|
|
534
|
-
welcome01: '欢迎进入房间',
|
|
535
|
-
avatar_left: 'https://example.com/avatar.png',
|
|
536
|
-
},
|
|
537
|
-
});
|
|
495
|
+
await orbitGift
|
|
496
|
+
.animate({ rotationTo: Math.PI * 2, duration: 1200 })
|
|
497
|
+
.start();
|
|
538
498
|
```
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
- `
|
|
592
|
-
|
|
593
|
-
- `
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
499
|
+
|
|
500
|
+
也可以传入单步或数组:
|
|
501
|
+
|
|
502
|
+
```ts
|
|
503
|
+
gift.animate({ flyTo: { x: 300, y: 300 }, scaleTo: 0.5, opacity: 0.3 }).start();
|
|
504
|
+
|
|
505
|
+
gift
|
|
506
|
+
.animate([
|
|
507
|
+
{ flyTo: { x: 300, y: 300 }, duration: 400 },
|
|
508
|
+
{ scaleTo: 1, opacity: 1, duration: 300 },
|
|
509
|
+
])
|
|
510
|
+
.start();
|
|
511
|
+
```
|
|
512
|
+
|
|
513
|
+
## Slot 替换
|
|
514
|
+
|
|
515
|
+
### SVGA
|
|
516
|
+
|
|
517
|
+
使用 `svgaSlots`:
|
|
518
|
+
|
|
519
|
+
```ts
|
|
520
|
+
await stage.addGift({
|
|
521
|
+
type: 'svga',
|
|
522
|
+
source: 'https://example.com/demo.svga',
|
|
523
|
+
x: 0,
|
|
524
|
+
y: 0,
|
|
525
|
+
width: 400,
|
|
526
|
+
height: 400,
|
|
527
|
+
svgaSlots: {
|
|
528
|
+
avatar: { image: avatarImage },
|
|
529
|
+
title: {
|
|
530
|
+
text: 'Hello',
|
|
531
|
+
color: '#ff0000',
|
|
532
|
+
fontSize: 28,
|
|
533
|
+
mode: 'dynamic',
|
|
534
|
+
},
|
|
535
|
+
},
|
|
536
|
+
});
|
|
537
|
+
```
|
|
538
|
+
|
|
539
|
+
支持:
|
|
540
|
+
|
|
541
|
+
- `TexImageSource`
|
|
542
|
+
- 文本配置
|
|
543
|
+
- 图片配置
|
|
544
|
+
|
|
545
|
+
SVGA 文本配置会按目标 frame 自动适配字号,避免文字超出槽位:
|
|
546
|
+
|
|
547
|
+
- `mode: 'dynamic'`:默认行为。生成文字自身尺寸的纹理,渲染时按自身逻辑尺寸居中到 frame 内,不会被拉伸。
|
|
548
|
+
- `mode: 'replace'`:生成和 frame 一样大的纹理,按替换图逻辑铺满 frame。
|
|
549
|
+
- `fontSize?: number`:期望字号;如果文字放不下,会自动缩小。
|
|
550
|
+
- `minFontSize?: number` / `maxFontSize?: number`:限制自适应字号范围。
|
|
551
|
+
- `padding?: number`:文字纹理内边距,默认 `2`。
|
|
552
|
+
- `scale?: number`:文字纹理栅格倍率,SVGA 默认 `3`,用于保持清晰度。
|
|
553
|
+
- `fontStyle?: string | { font?: string; color?: string }`:字体样式,SVGA / VAP 都支持。
|
|
554
|
+
|
|
555
|
+
`fontStyle` 可以直接传 canvas font 字符串:
|
|
556
|
+
|
|
557
|
+
```ts
|
|
558
|
+
svgaSlots: {
|
|
559
|
+
title: {
|
|
560
|
+
text: 'Hello',
|
|
561
|
+
fontStyle: 'bold 40px Arial',
|
|
562
|
+
},
|
|
563
|
+
}
|
|
564
|
+
```
|
|
565
|
+
|
|
566
|
+
也可以传对象:
|
|
567
|
+
|
|
568
|
+
```ts
|
|
569
|
+
vapSlots: {
|
|
570
|
+
welcome01: {
|
|
571
|
+
text: '欢迎进入房间',
|
|
572
|
+
fontStyle: {
|
|
573
|
+
font: 'bold 40px Arial',
|
|
574
|
+
color: '#ffffff',
|
|
575
|
+
},
|
|
576
|
+
},
|
|
577
|
+
}
|
|
578
|
+
```
|
|
579
|
+
|
|
580
|
+
对象形式目前生效字段是 `font` 和 `color`。如果同时传了外层 `color` 和 `fontStyle.color`,以 `fontStyle.color` 为准。VAP 文本如果没有传 `fontStyle`,会回退使用 VAP 配置里的 `src.fontStyle`。
|
|
581
|
+
|
|
582
|
+
### VAP / VAPX
|
|
583
|
+
|
|
584
|
+
使用 `vapSlots`:
|
|
585
|
+
|
|
586
|
+
```ts
|
|
587
|
+
await stage.addGift({
|
|
588
|
+
type: 'vap',
|
|
589
|
+
source: 'https://example.com/demo.mp4',
|
|
590
|
+
config: 'https://example.com/demo.json',
|
|
591
|
+
x: 0,
|
|
592
|
+
y: 0,
|
|
593
|
+
width: 400,
|
|
594
|
+
height: 400,
|
|
595
|
+
vapSlots: {
|
|
596
|
+
welcome01: '欢迎进入房间',
|
|
597
|
+
avatar_left: 'https://example.com/avatar.png',
|
|
598
|
+
},
|
|
599
|
+
});
|
|
600
|
+
```
|
|
601
|
+
|
|
602
|
+
支持:
|
|
603
|
+
|
|
604
|
+
- 文本字符串
|
|
605
|
+
- 图片 URL
|
|
606
|
+
- `TexImageSource`
|
|
607
|
+
- 结构化文本 / 图片对象
|
|
608
|
+
|
|
609
|
+
## 后端策略
|
|
610
|
+
|
|
611
|
+
默认回退顺序:
|
|
612
|
+
|
|
613
|
+
1. `WebGPU`
|
|
614
|
+
2. `WebGL2`
|
|
615
|
+
3. `WebGL1`
|
|
616
|
+
|
|
617
|
+
说明:
|
|
618
|
+
|
|
619
|
+
- `WebGPU` 仅在浏览器支持相关必要能力时启用
|
|
620
|
+
- `WebGL1` 主要用于兼容兜底,不以性能最优为目标
|
|
621
|
+
- demo 中可手动强制切换到 `WebGL1`
|
|
622
|
+
|
|
623
|
+
## 缓存策略
|
|
624
|
+
|
|
625
|
+
### 内存缓存
|
|
626
|
+
|
|
627
|
+
- 默认 `128MB`
|
|
628
|
+
- LRU 淘汰
|
|
629
|
+
|
|
630
|
+
缓存内容包括:
|
|
631
|
+
|
|
632
|
+
- 原始资源字节
|
|
633
|
+
- 文本 / JSON
|
|
634
|
+
- `SVGA` worker payload
|
|
635
|
+
- `SVGA` atlas 资产
|
|
636
|
+
|
|
637
|
+
### `IndexedDB` 磁盘缓存
|
|
638
|
+
|
|
639
|
+
- 默认 `2048MB`
|
|
640
|
+
- LRU 淘汰
|
|
641
|
+
- 读取命中会刷新最近访问时间
|
|
642
|
+
- 超出预算时按最久未使用记录淘汰
|
|
643
|
+
|
|
644
|
+
异常情况处理:
|
|
645
|
+
|
|
646
|
+
- `IndexedDB` 不可用、事务失败、写入失败、容量不足时,会自动降级
|
|
647
|
+
- 损坏的 `SVGA` 磁盘缓存会自动删除并重新生成
|
|
648
|
+
|
|
649
|
+
## 项目结构
|
|
650
|
+
|
|
651
|
+
主要目录:
|
|
652
|
+
|
|
653
|
+
- `src/`
|
|
654
|
+
核心源码
|
|
655
|
+
- `docs/`
|
|
656
|
+
设计与汇总文档
|
|
657
|
+
- `publish/`
|
|
658
|
+
发布脚本
|
|
659
|
+
- `static/`
|
|
660
|
+
demo 依赖资源
|
|
661
|
+
- `tests/`
|
|
662
|
+
测试
|
|
663
|
+
|
|
664
|
+
## 对外导出
|
|
665
|
+
|
|
666
|
+
入口文件:
|
|
667
|
+
|
|
668
|
+
- [src/index.ts](/D:/MyDocuments/UnityProjects/SVGAPlayer-Unity/gift-stage/src/index.ts)
|
|
669
|
+
|
|
670
|
+
主要导出:
|
|
671
|
+
|
|
672
|
+
- `GiftStage`
|
|
673
|
+
- `createBackend`
|
|
674
|
+
- `WebGPUBackend`
|
|
675
|
+
- `WebGL2Backend`
|
|
676
|
+
- `WebGL1Backend`
|
|
677
|
+
- `parseSVGA`
|
|
678
|
+
- `buildAtlas`
|
|
679
|
+
- `parseVAPConfig`
|
|
680
|
+
- 相关类型定义
|
|
681
|
+
|
|
682
|
+
## Demo
|
|
683
|
+
|
|
684
|
+
Demo 入口:
|
|
685
|
+
|
|
686
|
+
- [index.html](/D:/MyDocuments/UnityProjects/SVGAPlayer-Unity/gift-stage/index.html)
|
|
687
|
+
|
|
688
|
+
可用于验证:
|
|
689
|
+
|
|
690
|
+
- `SVGA / VAP / AlphaVideo` 播放
|
|
691
|
+
- slot 替换
|
|
692
|
+
- `WebGPU / WebGL2 / WebGL1` 切换
|
|
693
|
+
- 大批同屏压测
|
|
694
|
+
|
|
695
|
+
## 相关文档
|
|
696
|
+
|
|
697
|
+
- 优化汇总:
|
|
698
|
+
[docs/giftstage-optimization-summary.md](/D:/MyDocuments/UnityProjects/SVGAPlayer-Unity/gift-stage/docs/giftstage-optimization-summary.md)
|