@eigong/effekseer-webgpu-runtime 0.1.0

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.
@@ -0,0 +1,2215 @@
1
+ const effekseer = (() => {
2
+ let Module = {};
3
+ let Core = {};
4
+ let loadingEffect = null;
5
+ let runtimeInitialized = false;
6
+ let runtimeInitializing = false;
7
+ let preinitializedDevice = null;
8
+ let externalWebGPUDevice = null;
9
+ let imageCrossOrigin = "";
10
+ let contextId = 0;
11
+ let onRuntimeReadyQueue = [];
12
+
13
+ const toArrayBuffer = (data) => {
14
+ if (data instanceof ArrayBuffer) {
15
+ return data;
16
+ }
17
+ if (ArrayBuffer.isView(data)) {
18
+ return data.buffer.slice(data.byteOffset, data.byteOffset + data.byteLength);
19
+ }
20
+ return null;
21
+ };
22
+
23
+ const normalizePackagePath = (value) => {
24
+ if (typeof value !== "string" || value.length === 0) {
25
+ return "";
26
+ }
27
+
28
+ const parts = value.replace(/\\/g, "/").split("/");
29
+ const normalizedParts = [];
30
+ for (let i = 0; i < parts.length; i++) {
31
+ const part = parts[i];
32
+ if (!part || part === ".") {
33
+ continue;
34
+ }
35
+ if (part === "..") {
36
+ if (normalizedParts.length > 0) {
37
+ normalizedParts.pop();
38
+ }
39
+ continue;
40
+ }
41
+ normalizedParts.push(part);
42
+ }
43
+
44
+ let normalized = normalizedParts.join("/");
45
+ while (normalized.startsWith("/")) {
46
+ normalized = normalized.slice(1);
47
+ }
48
+ return normalized.replace(/[A-Z]/g, (c) => c.toLowerCase());
49
+ };
50
+
51
+ const EFWGPK_MAGIC = "EFWGPKG2";
52
+ const EFWGPK_HEADER_SIZE_V2 = 64;
53
+ const EFWGPK_HEADER_SIZE_V3 = 80;
54
+ const EFWGPK_ENTRY_SIZE = 48;
55
+ const EFWGPK_FORMAT_REVISION_V2 = 2;
56
+ const EFWGPK_FORMAT_REVISION_V3 = 3;
57
+ const EFWGPK_GLOBAL_AES128_CTR = 1 << 2;
58
+ const EFWGPK_NONCE_SIZE = 16;
59
+ const EFWGPK_ENTRY_DEFLATE = 1 << 0;
60
+ const EFWGPK_META_MAIN = "__efwgpk__/main_effect_path.txt";
61
+ const EFWGPK_RESOURCE_SCHEME = "efwgpk://";
62
+ const EFWGPK_BASIS_BYTES = new Uint8Array([
63
+ 0x45, 0x66, 0x6b, 0x57, 0x67, 0x2e, 0x57, 0x65,
64
+ 0x62, 0x47, 0x50, 0x55, 0x2e, 0x43, 0x54, 0x52,
65
+ ]);
66
+ let efwgpkPackageId = 0;
67
+ let efwgpkCtrKeyPromise = null;
68
+
69
+ const crcTable = (() => {
70
+ const table = new Uint32Array(256);
71
+ for (let i = 0; i < 256; i++) {
72
+ let value = i;
73
+ for (let j = 0; j < 8; j++) {
74
+ value = (value & 1) ? (0xedb88320 ^ (value >>> 1)) : (value >>> 1);
75
+ }
76
+ table[i] = value >>> 0;
77
+ }
78
+ return table;
79
+ })();
80
+
81
+ const crc32Bytes = (bytes) => {
82
+ if (!(bytes instanceof Uint8Array)) {
83
+ return 0;
84
+ }
85
+ let crc = 0xffffffff;
86
+ for (let i = 0; i < bytes.length; i++) {
87
+ const index = (crc ^ bytes[i]) & 0xff;
88
+ crc = (crc >>> 8) ^ crcTable[index];
89
+ }
90
+ return (~crc) >>> 0;
91
+ };
92
+
93
+ const getEfwgpkCtrKey = async () => {
94
+ if (efwgpkCtrKeyPromise) {
95
+ return efwgpkCtrKeyPromise;
96
+ }
97
+ if (!globalThis.crypto || !globalThis.crypto.subtle || typeof globalThis.crypto.subtle.importKey !== "function") {
98
+ throw new Error("Web Crypto AES-CTR is required for encrypted efkwgpk payloads");
99
+ }
100
+ efwgpkCtrKeyPromise = globalThis.crypto.subtle.importKey("raw", EFWGPK_BASIS_BYTES, "AES-CTR", false, ["decrypt"]);
101
+ return efwgpkCtrKeyPromise;
102
+ };
103
+
104
+ const decryptEfwgpkPayload = async (payloadBytes, nonceBytes) => {
105
+ const key = await getEfwgpkCtrKey();
106
+ return globalThis.crypto.subtle.decrypt({
107
+ name: "AES-CTR",
108
+ counter: nonceBytes,
109
+ length: 128,
110
+ }, key, payloadBytes);
111
+ };
112
+
113
+ const stripUrlDecorations = (value) => {
114
+ return String(value || "").replace(/\\/g, "/").split("?")[0].split("#")[0];
115
+ };
116
+
117
+ const isEfkWgPath = (value) => {
118
+ if (typeof value !== "string" || value.length === 0) {
119
+ return false;
120
+ }
121
+ const normalized = value.replace(/\\/g, "/").split("?")[0].split("#")[0].toLowerCase();
122
+ return normalized.endsWith(".efkwg");
123
+ };
124
+
125
+ const isEfwgpkPath = (value) => {
126
+ if (typeof value !== "string" || value.length === 0) {
127
+ return false;
128
+ }
129
+ const normalized = stripUrlDecorations(value).toLowerCase();
130
+ return normalized.endsWith(".efkwgpk");
131
+ };
132
+
133
+ const readMagic8 = (buffer) => {
134
+ const ab = toArrayBuffer(buffer);
135
+ if (!ab || ab.byteLength < 8) {
136
+ return "";
137
+ }
138
+ const view = new Uint8Array(ab, 0, 8);
139
+ return String.fromCharCode(...view);
140
+ };
141
+
142
+ const getEfwgpkHeaderInfo = (buffer) => {
143
+ const totalSize = buffer ? buffer.byteLength : 0;
144
+ if (!buffer || totalSize < EFWGPK_HEADER_SIZE_V2) {
145
+ return null;
146
+ }
147
+
148
+ const view = new DataView(buffer);
149
+ if (readMagic8(buffer) !== EFWGPK_MAGIC) {
150
+ return null;
151
+ }
152
+
153
+ const headerSize = view.getUint32(8, true);
154
+ const globalFlags = view.getUint32(12, true);
155
+ const formatRevision = view.getUint32(16, true);
156
+ const entryCount = view.getUint32(20, true);
157
+ const entryStride = view.getUint32(24, true);
158
+ const entriesOffset = view.getUint32(28, true);
159
+ const stringPoolOffset = view.getUint32(32, true);
160
+ const stringPoolSize = view.getUint32(36, true);
161
+ const payloadOffset = view.getUint32(40, true);
162
+ const payloadSize = view.getUint32(44, true);
163
+ const tocCrc = view.getUint32(48, true);
164
+ const payloadCrc = view.getUint32(52, true);
165
+
166
+ const expectedHeaderSize = formatRevision === EFWGPK_FORMAT_REVISION_V2
167
+ ? EFWGPK_HEADER_SIZE_V2
168
+ : formatRevision === EFWGPK_FORMAT_REVISION_V3
169
+ ? EFWGPK_HEADER_SIZE_V3
170
+ : 0;
171
+
172
+ if (expectedHeaderSize === 0 || headerSize !== expectedHeaderSize || entryStride !== EFWGPK_ENTRY_SIZE) {
173
+ return null;
174
+ }
175
+
176
+ let payloadNonce = null;
177
+ if ((globalFlags & EFWGPK_GLOBAL_AES128_CTR) !== 0) {
178
+ if (formatRevision < EFWGPK_FORMAT_REVISION_V3 || totalSize < EFWGPK_HEADER_SIZE_V3) {
179
+ return null;
180
+ }
181
+ payloadNonce = new Uint8Array(buffer.slice(56, 56 + EFWGPK_NONCE_SIZE));
182
+ if (payloadNonce.byteLength !== EFWGPK_NONCE_SIZE) {
183
+ return null;
184
+ }
185
+ }
186
+
187
+ return {
188
+ headerSize,
189
+ globalFlags,
190
+ formatRevision,
191
+ entryCount,
192
+ entryStride,
193
+ entriesOffset,
194
+ stringPoolOffset,
195
+ stringPoolSize,
196
+ payloadOffset,
197
+ payloadSize,
198
+ tocCrc,
199
+ payloadCrc,
200
+ payloadNonce,
201
+ payloadEncrypted: (globalFlags & EFWGPK_GLOBAL_AES128_CTR) !== 0,
202
+ };
203
+ };
204
+
205
+ const buildEfwgpkEntryMap = (buffer) => {
206
+ const map = new Map();
207
+ const totalSize = buffer ? buffer.byteLength : 0;
208
+ const headerInfo = getEfwgpkHeaderInfo(buffer);
209
+ if (!headerInfo) {
210
+ return map;
211
+ }
212
+ const view = new DataView(buffer);
213
+ const { headerSize, entryCount, entryStride, entriesOffset, stringPoolOffset, stringPoolSize, payloadOffset, payloadSize, tocCrc, payloadCrc } = headerInfo;
214
+
215
+ const entryTableSizeBig = BigInt(entryCount) * BigInt(entryStride);
216
+ if (entryTableSizeBig > BigInt(totalSize)) {
217
+ return map;
218
+ }
219
+ const entryTableSize = Number(entryTableSizeBig);
220
+ if (!isValidBufferSpan(entriesOffset, entryTableSize, totalSize)) {
221
+ return map;
222
+ }
223
+ if (!isValidBufferSpan(stringPoolOffset, stringPoolSize, totalSize)) {
224
+ return map;
225
+ }
226
+ if (!isValidBufferSpan(payloadOffset, payloadSize, totalSize)) {
227
+ return map;
228
+ }
229
+
230
+ const stringPoolEnd = stringPoolOffset + stringPoolSize;
231
+ const payloadEnd = payloadOffset + payloadSize;
232
+ const headerBytes = new Uint8Array(buffer, 0, headerSize).slice();
233
+ headerBytes.fill(0, 48, 56);
234
+ const tocBytes = new Uint8Array(headerSize + entryTableSize + stringPoolSize);
235
+ tocBytes.set(headerBytes, 0);
236
+ tocBytes.set(new Uint8Array(buffer, entriesOffset, entryTableSize), headerSize);
237
+ tocBytes.set(new Uint8Array(buffer, stringPoolOffset, stringPoolSize), headerSize + entryTableSize);
238
+ if (crc32Bytes(tocBytes) !== (tocCrc >>> 0)) {
239
+ return map;
240
+ }
241
+ const payloadBytes = new Uint8Array(buffer, payloadOffset, payloadSize);
242
+ if (crc32Bytes(payloadBytes) !== (payloadCrc >>> 0)) {
243
+ return map;
244
+ }
245
+
246
+ const decoder = new TextDecoder("utf-8");
247
+ for (let i = 0; i < entryCount; i++) {
248
+ const base = entriesOffset + i * entryStride;
249
+ const pathOffset = view.getUint32(base + 8, true);
250
+ const pathLength = view.getUint32(base + 12, true);
251
+ const flags = view.getUint32(base + 16, true);
252
+ const entryPayloadOffset = view.getUint32(base + 20, true);
253
+ const packedSize = view.getUint32(base + 24, true);
254
+ const rawSize = view.getUint32(base + 28, true);
255
+ const packedCrc = view.getUint32(base + 32, true);
256
+ const rawCrc = view.getUint32(base + 36, true);
257
+
258
+ if (!isValidBufferSpan(pathOffset, pathLength, totalSize)) {
259
+ continue;
260
+ }
261
+ if (pathOffset < stringPoolOffset || (pathOffset + pathLength) > stringPoolEnd) {
262
+ continue;
263
+ }
264
+ if (!isValidBufferSpan(entryPayloadOffset, packedSize, totalSize)) {
265
+ continue;
266
+ }
267
+ if (entryPayloadOffset < payloadOffset || (entryPayloadOffset + packedSize) > payloadEnd) {
268
+ continue;
269
+ }
270
+
271
+ let path = "";
272
+ try {
273
+ path = decoder.decode(new Uint8Array(buffer, pathOffset, pathLength));
274
+ } catch {
275
+ continue;
276
+ }
277
+
278
+ const normalizedPath = normalizePackagePath(path);
279
+ if (!normalizedPath) {
280
+ continue;
281
+ }
282
+
283
+ const entry = {
284
+ index: i,
285
+ path,
286
+ normalizedPath,
287
+ flags,
288
+ payloadOffset: entryPayloadOffset,
289
+ packedSize,
290
+ rawSize,
291
+ packedCrc,
292
+ rawCrc
293
+ };
294
+ const bucket = map.get(normalizedPath);
295
+ if (bucket) {
296
+ bucket.push(entry);
297
+ } else {
298
+ map.set(normalizedPath, [entry]);
299
+ }
300
+ }
301
+
302
+ map._efwgpkMeta = {
303
+ payloadOffset,
304
+ payloadSize,
305
+ payloadEncrypted: headerInfo.payloadEncrypted,
306
+ payloadNonce: headerInfo.payloadNonce,
307
+ decryptedPayloadPromise: null,
308
+ };
309
+
310
+ return map;
311
+ };
312
+
313
+ const inflateEfwgpkPayload = async (packedBytes) => {
314
+ const fflateApi = globalThis.fflate;
315
+ if (fflateApi && typeof fflateApi.unzlibSync === "function") {
316
+ const inflatedBytes = fflateApi.unzlibSync(new Uint8Array(packedBytes));
317
+ const inflated = toArrayBuffer(inflatedBytes);
318
+ return inflated;
319
+ }
320
+
321
+ if (typeof DecompressionStream !== "function") {
322
+ throw new Error("No zlib inflate backend available for efkwgpk payload");
323
+ }
324
+
325
+ const stream = new DecompressionStream("deflate");
326
+ const writer = stream.writable.getWriter();
327
+ await writer.write(packedBytes);
328
+ await writer.close();
329
+ const inflated = await new Response(stream.readable).arrayBuffer();
330
+ return inflated;
331
+ };
332
+
333
+ const getEfwgpkPackedBytes = async (buffer, entryMap, entry) => {
334
+ const meta = entryMap && entryMap._efwgpkMeta ? entryMap._efwgpkMeta : null;
335
+ if (!meta || !meta.payloadEncrypted) {
336
+ return new Uint8Array(buffer, entry.payloadOffset, entry.packedSize);
337
+ }
338
+
339
+ if (!meta.decryptedPayloadPromise) {
340
+ const encryptedPayload = new Uint8Array(buffer, meta.payloadOffset, meta.payloadSize);
341
+ meta.decryptedPayloadPromise = decryptEfwgpkPayload(encryptedPayload, meta.payloadNonce).then((decrypted) => new Uint8Array(decrypted));
342
+ }
343
+
344
+ const decryptedPayload = await meta.decryptedPayloadPromise;
345
+ const relativeOffset = entry.payloadOffset - meta.payloadOffset;
346
+ if (relativeOffset < 0 || (relativeOffset + entry.packedSize) > decryptedPayload.byteLength) {
347
+ return null;
348
+ }
349
+ return decryptedPayload.subarray(relativeOffset, relativeOffset + entry.packedSize);
350
+ };
351
+
352
+ const getEfwgpkEntryBytes = async (buffer, entryMap, path) => {
353
+ const normalizedPath = normalizePackagePath(path);
354
+ if (!normalizedPath || !buffer || !entryMap || entryMap.size === 0) {
355
+ return null;
356
+ }
357
+
358
+ const bucket = entryMap.get(normalizedPath);
359
+ if (!bucket || bucket.length === 0) {
360
+ return null;
361
+ }
362
+
363
+ for (let i = 0; i < bucket.length; i++) {
364
+ const entry = bucket[i];
365
+ if (!isValidBufferSpan(entry.payloadOffset, entry.packedSize, buffer.byteLength)) {
366
+ continue;
367
+ }
368
+ const packedBytes = await getEfwgpkPackedBytes(buffer, entryMap, entry);
369
+ if (!packedBytes) {
370
+ continue;
371
+ }
372
+ if (crc32Bytes(packedBytes) !== (entry.packedCrc >>> 0)) {
373
+ continue;
374
+ }
375
+ if (entry.flags === 0 && entry.packedSize === entry.rawSize) {
376
+ const rawBytes = packedBytes.slice();
377
+ if (crc32Bytes(rawBytes) !== (entry.rawCrc >>> 0)) {
378
+ continue;
379
+ }
380
+ return rawBytes.buffer;
381
+ }
382
+ if (entry.flags === EFWGPK_ENTRY_DEFLATE) {
383
+ const inflated = await inflateEfwgpkPayload(packedBytes);
384
+ if (!inflated || inflated.byteLength !== entry.rawSize) {
385
+ continue;
386
+ }
387
+ if (crc32Bytes(new Uint8Array(inflated)) !== (entry.rawCrc >>> 0)) {
388
+ continue;
389
+ }
390
+ return inflated;
391
+ }
392
+ }
393
+
394
+ return null;
395
+ };
396
+
397
+ const getEfwgpkEntryPayloadKey = (entry) => {
398
+ if (!entry || !Number.isFinite(entry.payloadOffset) || !Number.isFinite(entry.packedSize) || !Number.isFinite(entry.rawSize) || !Number.isFinite(entry.flags)) {
399
+ return "";
400
+ }
401
+ return `${entry.flags}:${entry.payloadOffset}:${entry.packedSize}:${entry.rawSize}`;
402
+ };
403
+
404
+ const getEfwgpkCanonicalEntry = (buffer, entryMap, path) => {
405
+ const normalizedPath = normalizePackagePath(path);
406
+ if (!normalizedPath || !buffer || !entryMap || entryMap.size === 0) {
407
+ return null;
408
+ }
409
+
410
+ const bucket = entryMap.get(normalizedPath);
411
+ if (!bucket || bucket.length === 0) {
412
+ return null;
413
+ }
414
+
415
+ for (let i = 0; i < bucket.length; i++) {
416
+ const entry = bucket[i];
417
+ if (!isValidBufferSpan(entry.payloadOffset, entry.packedSize, buffer.byteLength)) {
418
+ continue;
419
+ }
420
+ if (entry.flags === 0 && entry.packedSize === entry.rawSize) {
421
+ return entry;
422
+ }
423
+ if (entry.flags === EFWGPK_ENTRY_DEFLATE) {
424
+ return entry;
425
+ }
426
+ }
427
+
428
+ return null;
429
+ };
430
+
431
+ const getEfwgpkMainEffectPath = async (buffer, entryMap) => {
432
+ const metaBytes = await getEfwgpkEntryBytes(buffer, entryMap, EFWGPK_META_MAIN);
433
+ if (metaBytes) {
434
+ try {
435
+ const decoded = new TextDecoder("utf-8").decode(new Uint8Array(metaBytes)).replace(/\0+$/, "");
436
+ const normalized = normalizePackagePath(decoded);
437
+ if (normalized) {
438
+ return normalized;
439
+ }
440
+ } catch {
441
+ // ignore malformed metadata
442
+ }
443
+ }
444
+
445
+ for (const [normalizedPath, bucket] of entryMap.entries()) {
446
+ if (!normalizedPath.endsWith(".efkwg")) {
447
+ continue;
448
+ }
449
+ if (bucket && bucket.length > 0) {
450
+ return normalizedPath;
451
+ }
452
+ }
453
+
454
+ return "";
455
+ };
456
+
457
+ const isValidBufferSpan = (offset, size, totalSize) => {
458
+ if (!Number.isFinite(offset) || !Number.isFinite(size) || !Number.isFinite(totalSize)) {
459
+ return false;
460
+ }
461
+ if (offset < 0 || size < 0 || totalSize < 0) {
462
+ return false;
463
+ }
464
+ if (offset > totalSize) {
465
+ return false;
466
+ }
467
+ return size <= (totalSize - offset);
468
+ };
469
+
470
+ const requestPreinitializedDevice = async () => {
471
+ if (externalWebGPUDevice) {
472
+ return externalWebGPUDevice;
473
+ }
474
+ if (!navigator.gpu) {
475
+ throw new Error("WebGPU is not available in this browser.");
476
+ }
477
+ const adapter = await navigator.gpu.requestAdapter();
478
+ if (!adapter) {
479
+ throw new Error("Failed to acquire a WebGPU adapter.");
480
+ }
481
+ const requiredFeatures = [];
482
+ if (adapter.features && adapter.features.has("float32-filterable")) {
483
+ requiredFeatures.push("float32-filterable");
484
+ }
485
+ const hasTimestampOps =
486
+ (typeof GPUCommandEncoder !== "undefined") &&
487
+ GPUCommandEncoder.prototype &&
488
+ (typeof GPUCommandEncoder.prototype.writeTimestamp === "function") &&
489
+ (typeof GPUCommandEncoder.prototype.resolveQuerySet === "function");
490
+ if (hasTimestampOps && adapter.features && adapter.features.has("timestamp-query")) {
491
+ requiredFeatures.push("timestamp-query");
492
+ }
493
+ return await adapter.requestDevice(requiredFeatures.length > 0 ? { requiredFeatures } : undefined);
494
+ };
495
+
496
+ const loadBinary = (url, onload, onerror) => {
497
+ const xhr = new XMLHttpRequest();
498
+ xhr.open("GET", url, true);
499
+ xhr.responseType = "arraybuffer";
500
+ xhr.onload = () => {
501
+ const status = xhr.status | 0;
502
+ if ((status >= 200 && status < 300) || status === 0) {
503
+ onload(xhr.response);
504
+ } else if (onerror) {
505
+ onerror("not found", url);
506
+ }
507
+ };
508
+ xhr.onerror = () => {
509
+ if (onerror) {
510
+ onerror("not found", url);
511
+ }
512
+ };
513
+ xhr.send(null);
514
+ };
515
+
516
+ const loadBinarySync = (url) => {
517
+ try {
518
+ const xhr = new XMLHttpRequest();
519
+ xhr.open("GET", url, false);
520
+ xhr.responseType = "arraybuffer";
521
+ xhr.send(null);
522
+ const status = xhr.status | 0;
523
+ if ((status >= 200 && status < 300) || status === 0) {
524
+ return xhr.response;
525
+ }
526
+ } catch {
527
+ }
528
+ return null;
529
+ };
530
+
531
+ const deferCallback = (callback) => {
532
+ if (typeof callback !== "function") {
533
+ return;
534
+ }
535
+ if (typeof queueMicrotask === "function") {
536
+ queueMicrotask(callback);
537
+ } else {
538
+ Promise.resolve().then(callback);
539
+ }
540
+ };
541
+
542
+ const normalizeEffectSourcePath = (value) => String(value || "").replace(/\\/g, "/");
543
+
544
+ const buildEffectCacheKey = (path, scale) => {
545
+ const normalizedPath = normalizeEffectSourcePath(path);
546
+ const numericScale = Number(scale);
547
+ const normalizedScale = Number.isFinite(numericScale) ? numericScale : 1.0;
548
+ return `${normalizedPath}::${normalizedScale}`;
549
+ };
550
+
551
+ const clearCachedEffectReference = (effect) => {
552
+ if (!effect || !effect.context || !effect._cacheKey || !effect.context._effectCache) {
553
+ return;
554
+ }
555
+ if (effect.context._effectCache.get(effect._cacheKey) === effect) {
556
+ effect.context._effectCache.delete(effect._cacheKey);
557
+ }
558
+ };
559
+
560
+ const clearOwnedResourceAliases = (aliases) => {
561
+ if (!aliases || !Module.resourcesMap) {
562
+ return;
563
+ }
564
+ for (let i = 0; i < aliases.length; i++) {
565
+ const alias = aliases[i];
566
+ if (typeof alias !== "string" || alias.length === 0) {
567
+ continue;
568
+ }
569
+ delete Module.resourcesMap[alias];
570
+ }
571
+ };
572
+
573
+ const createManagedEffectSnapshot = (state) => {
574
+ if (!state) {
575
+ return null;
576
+ }
577
+ return {
578
+ id: state.id,
579
+ path: state.path,
580
+ scale: state.scale,
581
+ enabled: state.enabled,
582
+ status: state.status,
583
+ effect: state.status === "loaded" ? state.effect : null,
584
+ errorMessage: state.errorMessage,
585
+ errorPath: state.errorPath,
586
+ loadPromise: state.loadPromise,
587
+ activeHandles: new Set(state.activeHandles),
588
+ ownedResourceAliases: state.ownedResourceAliases.slice(),
589
+ };
590
+ };
591
+
592
+ const registerEffectCallbacks = (effect, onload, onerror) => {
593
+ if (!effect) {
594
+ return;
595
+ }
596
+
597
+ if (typeof onload === "function") {
598
+ if (effect.isLoaded) {
599
+ deferCallback(() => onload());
600
+ } else if (!effect._loadFailed) {
601
+ effect._onloadListeners.push(onload);
602
+ }
603
+ }
604
+
605
+ if (typeof onerror === "function") {
606
+ if (effect._loadFailed) {
607
+ const errorMessage = effect._loadErrorMessage || "failed to load effect";
608
+ const errorPath = effect._loadErrorPath || "";
609
+ deferCallback(() => onerror(errorMessage, errorPath));
610
+ } else if (!effect.isLoaded) {
611
+ effect._onerrorListeners.push(onerror);
612
+ }
613
+ }
614
+ };
615
+
616
+ const dispatchEffectLoaded = (effect) => {
617
+ if (!effect) {
618
+ return;
619
+ }
620
+
621
+ const listeners = effect._onloadListeners.slice();
622
+ effect._onloadListeners.length = 0;
623
+ effect._onerrorListeners.length = 0;
624
+ for (let i = 0; i < listeners.length; i++) {
625
+ const listener = listeners[i];
626
+ deferCallback(() => listener());
627
+ }
628
+ };
629
+
630
+ const dispatchEffectError = (effect, message, path = "") => {
631
+ if (!effect || effect._loadFailed) {
632
+ return;
633
+ }
634
+
635
+ effect._loadFailed = true;
636
+ effect._loadErrorMessage = String(message || "failed to load effect");
637
+ effect._loadErrorPath = String(path || "");
638
+ clearCachedEffectReference(effect);
639
+
640
+ const listeners = effect._onerrorListeners.slice();
641
+ effect._onloadListeners.length = 0;
642
+ effect._onerrorListeners.length = 0;
643
+ for (let i = 0; i < listeners.length; i++) {
644
+ const listener = listeners[i];
645
+ deferCallback(() => listener(effect._loadErrorMessage, effect._loadErrorPath));
646
+ }
647
+ };
648
+
649
+ let loadResource = (path, onload, onerror) => {
650
+ loadBinary(path, onload, onerror);
651
+ };
652
+
653
+ // Reusable WASM scratch for matrix uploads.
654
+ // Avoids per-call malloc/free in hot paths (setMatrix / setProjectionMatrix / setCameraMatrix).
655
+ const floatArrayScratch = {
656
+ ptr: 0,
657
+ capacity: 0,
658
+ };
659
+
660
+ const ensureFloatArrayScratch = (requiredCount) => {
661
+ if (requiredCount <= floatArrayScratch.capacity && floatArrayScratch.ptr !== 0) {
662
+ return floatArrayScratch.ptr;
663
+ }
664
+
665
+ if (floatArrayScratch.ptr !== 0) {
666
+ Module._free(floatArrayScratch.ptr);
667
+ floatArrayScratch.ptr = 0;
668
+ floatArrayScratch.capacity = 0;
669
+ }
670
+
671
+ floatArrayScratch.ptr = Module._malloc(requiredCount * 4);
672
+ floatArrayScratch.capacity = requiredCount;
673
+ return floatArrayScratch.ptr;
674
+ };
675
+
676
+ const withFloatArray = (arrayLike, callback) => {
677
+ const arr = (arrayLike instanceof Float32Array) ? arrayLike : new Float32Array(arrayLike);
678
+ if (arr.length <= 0) {
679
+ callback(0);
680
+ return;
681
+ }
682
+
683
+ const ptr = ensureFloatArrayScratch(arr.length);
684
+ Module.HEAPF32.set(arr, ptr >> 2);
685
+ callback(ptr);
686
+ };
687
+
688
+ const WGPUTextureFormatValues = Object.freeze({
689
+ "rgba8unorm": 0x16,
690
+ "rgba8unorm-srgb": 0x17,
691
+ "bgra8unorm": 0x1B,
692
+ "bgra8unorm-srgb": 0x1C,
693
+ "rgba16float": 0x28,
694
+ "depth24plus": 0x2E,
695
+ "depth24plus-stencil8": 0x2F,
696
+ "depth32float": 0x30
697
+ });
698
+ const WGPUTextureFormatNames = Object.freeze(
699
+ Object.fromEntries(Object.entries(WGPUTextureFormatValues).map(([k, v]) => [v, k]))
700
+ );
701
+
702
+ const toTextureFormatValue = (value) => {
703
+ if (typeof value === "number" && Number.isFinite(value)) {
704
+ return value | 0;
705
+ }
706
+ if (typeof value !== "string") {
707
+ return null;
708
+ }
709
+ const key = value.trim().toLowerCase();
710
+ if (!key) {
711
+ return null;
712
+ }
713
+ return Object.prototype.hasOwnProperty.call(WGPUTextureFormatValues, key)
714
+ ? WGPUTextureFormatValues[key]
715
+ : null;
716
+ };
717
+
718
+ const toTextureFormatName = (value) => {
719
+ if (typeof value === "string") {
720
+ const key = value.trim().toLowerCase();
721
+ if (!key) {
722
+ return null;
723
+ }
724
+ return Object.prototype.hasOwnProperty.call(WGPUTextureFormatValues, key) ? key : null;
725
+ }
726
+ if (typeof value === "number" && Number.isFinite(value)) {
727
+ return WGPUTextureFormatNames[value | 0] || null;
728
+ }
729
+ return null;
730
+ };
731
+
732
+ const toSampleCountValue = (value) => {
733
+ const n = Number(value);
734
+ if (!Number.isFinite(n) || n <= 0) {
735
+ return 1;
736
+ }
737
+ return Math.max(1, Math.floor(n));
738
+ };
739
+
740
+ const setRendererLinearWorkingColorSpace = (colorSpaceApiLike = null) => {
741
+ const colorSpaceApi = colorSpaceApiLike;
742
+ if (!colorSpaceApi || !colorSpaceApi.ColorManagement) {
743
+ return false;
744
+ }
745
+ if (!("workingColorSpace" in colorSpaceApi.ColorManagement)) {
746
+ return false;
747
+ }
748
+ // Keep renderer color management in linear working space for stable blending/math.
749
+ if (typeof colorSpaceApi.LinearSRGBColorSpace !== "undefined") {
750
+ colorSpaceApi.ColorManagement.workingColorSpace = colorSpaceApi.LinearSRGBColorSpace;
751
+ return true;
752
+ }
753
+ return false;
754
+ };
755
+
756
+ const initCoreBindings = () => {
757
+ Core = {
758
+ InitInternal: Module.cwrap("EffekseerInitInternal", "number", ["number", "number", "string", "number", "number"]),
759
+ InitExternal: Module.cwrap("EffekseerInitExternal", "number", ["number", "number", "number", "number"]),
760
+ Init: Module.cwrap("EffekseerInit", "number", ["number", "number", "string", "number", "number", "number"]),
761
+ Terminate: Module.cwrap("EffekseerTerminate", "void", ["number"]),
762
+ Update: Module.cwrap("EffekseerUpdate", "void", ["number", "number"]),
763
+ BeginUpdate: Module.cwrap("EffekseerBeginUpdate", "void", ["number"]),
764
+ EndUpdate: Module.cwrap("EffekseerEndUpdate", "void", ["number"]),
765
+ UpdateHandle: Module.cwrap("EffekseerUpdateHandle", "void", ["number", "number", "number"]),
766
+ Draw: Module.cwrap("EffekseerDraw", "void", ["number"]),
767
+ DrawExternal: Module.cwrap("EffekseerDrawExternal", "void", ["number"]),
768
+ BeginDraw: Module.cwrap("EffekseerBeginDraw", "void", ["number"]),
769
+ EndDraw: Module.cwrap("EffekseerEndDraw", "void", ["number"]),
770
+ DrawHandle: Module.cwrap("EffekseerDrawHandle", "void", ["number", "number"]),
771
+ SetProjectionMatrix: Module.cwrap("EffekseerSetProjectionMatrix", "void", ["number", "number"]),
772
+ SetProjectionPerspective: Module.cwrap("EffekseerSetProjectionPerspective", "void", ["number", "number", "number", "number", "number"]),
773
+ SetProjectionOrthographic: Module.cwrap("EffekseerSetProjectionOrthographic", "void", ["number", "number", "number", "number", "number"]),
774
+ SetCameraMatrix: Module.cwrap("EffekseerSetCameraMatrix", "void", ["number", "number"]),
775
+ SetCameraLookAt: Module.cwrap("EffekseerSetCameraLookAt", "void", ["number", "number", "number", "number", "number", "number", "number", "number", "number", "number"]),
776
+ LoadEffect: Module.cwrap("EffekseerLoadEffect", "number", ["number", "number", "number", "number"]),
777
+ ReleaseEffect: Module.cwrap("EffekseerReleaseEffect", "void", ["number", "number"]),
778
+ ReloadResources: Module.cwrap("EffekseerReloadResources", "void", ["number", "number", "number", "number"]),
779
+ StopAllEffects: Module.cwrap("EffekseerStopAllEffects", "void", ["number"]),
780
+ PlayEffect: Module.cwrap("EffekseerPlayEffect", "number", ["number", "number", "number", "number", "number"]),
781
+ StopEffect: Module.cwrap("EffekseerStopEffect", "void", ["number", "number"]),
782
+ StopRoot: Module.cwrap("EffekseerStopRoot", "void", ["number", "number"]),
783
+ Exists: Module.cwrap("EffekseerExists", "number", ["number", "number"]),
784
+ SetFrame: Module.cwrap("EffekseerSetFrame", "void", ["number", "number", "number"]),
785
+ SetLocation: Module.cwrap("EffekseerSetLocation", "void", ["number", "number", "number", "number", "number"]),
786
+ SetRotation: Module.cwrap("EffekseerSetRotation", "void", ["number", "number", "number", "number", "number"]),
787
+ SetScale: Module.cwrap("EffekseerSetScale", "void", ["number", "number", "number", "number", "number"]),
788
+ SetMatrix: Module.cwrap("EffekseerSetMatrix", "void", ["number", "number", "number"]),
789
+ SetAllColor: Module.cwrap("EffekseerSetAllColor", "void", ["number", "number", "number", "number", "number", "number"]),
790
+ SetTargetLocation: Module.cwrap("EffekseerSetTargetLocation", "void", ["number", "number", "number", "number", "number"]),
791
+ GetDynamicInput: Module.cwrap("EffekseerGetDynamicInput", "number", ["number", "number", "number"]),
792
+ SetDynamicInput: Module.cwrap("EffekseerSetDynamicInput", "void", ["number", "number", "number", "number"]),
793
+ SendTrigger: Module.cwrap("EffekseerSendTrigger", "void", ["number", "number", "number"]),
794
+ SetPaused: Module.cwrap("EffekseerSetPaused", "void", ["number", "number", "number"]),
795
+ SetShown: Module.cwrap("EffekseerSetShown", "void", ["number", "number", "number"]),
796
+ SetSpeed: Module.cwrap("EffekseerSetSpeed", "void", ["number", "number", "number"]),
797
+ SetRandomSeed: Module.cwrap("EffekseerSetRandomSeed", "void", ["number", "number", "number"]),
798
+ SetCompositeMode: Module.cwrap("EffekseerSetCompositeMode", "void", ["number", "number"]),
799
+ GetRestInstancesCount: Module.cwrap("EffekseerGetRestInstancesCount", "number", ["number"]),
800
+ GetUpdateTime: Module.cwrap("EffekseerGetUpdateTime", "number", ["number"]),
801
+ GetDrawTime: Module.cwrap("EffekseerGetDrawTime", "number", ["number"]),
802
+ GetDrawFlushComputeTime: Module.cwrap("EffekseerGetDrawFlushComputeTime", "number", ["number"]),
803
+ GetDrawBeginFrameTime: Module.cwrap("EffekseerGetDrawBeginFrameTime", "number", ["number"]),
804
+ GetDrawManagerTime: Module.cwrap("EffekseerGetDrawManagerTime", "number", ["number"]),
805
+ GetDrawEndFrameTime: Module.cwrap("EffekseerGetDrawEndFrameTime", "number", ["number"]),
806
+ GetDrawTotalTime: Module.cwrap("EffekseerGetDrawTotalTime", "number", ["number"]),
807
+ GetGpuTimestampSupported: Module.cwrap("EffekseerGetGpuTimestampSupported", "number", ["number"]),
808
+ GetGpuTimestampValid: Module.cwrap("EffekseerGetGpuTimestampValid", "number", ["number"]),
809
+ GetGpuTimestampEffekseerPassTime: Module.cwrap("EffekseerGetGpuTimestampEffekseerPassTime", "number", ["number"]),
810
+ GetGpuTimestampFrameTime: Module.cwrap("EffekseerGetGpuTimestampFrameTime", "number", ["number"]),
811
+ GetGpuTimestampReadPending: Module.cwrap("EffekseerGetGpuTimestampReadPending", "number", ["number"]),
812
+ GetGpuTimestampLastMapStatus: Module.cwrap("EffekseerGetGpuTimestampLastMapStatus", "number", ["number"]),
813
+ GetGpuTimestampMapState: Module.cwrap("EffekseerGetGpuTimestampMapState", "number", ["number"]),
814
+ GetGpuTimestampMapMode: Module.cwrap("EffekseerGetGpuTimestampMapMode", "number", ["number"]),
815
+ GetGpuTimestampStallRecoveries: Module.cwrap("EffekseerGetGpuTimestampStallRecoveries", "number", ["number"]),
816
+ GetRendererProfileBindGroupTime: Module.cwrap("EffekseerGetRendererProfileBindGroupTime", "number", ["number"]),
817
+ GetRendererProfileBindGroupCacheFlushCount: Module.cwrap("EffekseerGetRendererProfileBindGroupCacheFlushCount", "number", ["number"]),
818
+ GetRendererProfileBindGroupCacheHits: Module.cwrap("EffekseerGetRendererProfileBindGroupCacheHits", "number", ["number"]),
819
+ GetRendererProfileBindGroupCacheMisses: Module.cwrap("EffekseerGetRendererProfileBindGroupCacheMisses", "number", ["number"]),
820
+ GetRendererProfileBindGroupCreates: Module.cwrap("EffekseerGetRendererProfileBindGroupCreates", "number", ["number"]),
821
+ GetRendererProfilePipelineTime: Module.cwrap("EffekseerGetRendererProfilePipelineTime", "number", ["number"]),
822
+ GetRendererProfileSetStateTime: Module.cwrap("EffekseerGetRendererProfileSetStateTime", "number", ["number"]),
823
+ GetRendererProfileIssueDrawTime: Module.cwrap("EffekseerGetRendererProfileIssueDrawTime", "number", ["number"]),
824
+ GetRendererProfileDrawTotalTime: Module.cwrap("EffekseerGetRendererProfileDrawTotalTime", "number", ["number"]),
825
+ GetRendererProfileDrawSpritesCalls: Module.cwrap("EffekseerGetRendererProfileDrawSpritesCalls", "number", ["number"]),
826
+ GetRendererProfileDrawPolygonCalls: Module.cwrap("EffekseerGetRendererProfileDrawPolygonCalls", "number", ["number"]),
827
+ GetInternalStandardRendererTextureSetupTime: Module.cwrap("EffekseerGetInternalStandardRendererTextureSetupTime", "number", ["number"]),
828
+ GetInternalStandardRendererShaderSelectTime: Module.cwrap("EffekseerGetInternalStandardRendererShaderSelectTime", "number", ["number"]),
829
+ GetInternalStandardRendererVertexPackTime: Module.cwrap("EffekseerGetInternalStandardRendererVertexPackTime", "number", ["number"]),
830
+ GetInternalStandardRendererPixelPackTime: Module.cwrap("EffekseerGetInternalStandardRendererPixelPackTime", "number", ["number"]),
831
+ GetInternalStandardRendererConstantUploadTime: Module.cwrap("EffekseerGetInternalStandardRendererConstantUploadTime", "number", ["number"]),
832
+ GetInternalStandardRendererRenderStateTime: Module.cwrap("EffekseerGetInternalStandardRendererRenderStateTime", "number", ["number"]),
833
+ GetInternalStandardRendererVertexBindTime: Module.cwrap("EffekseerGetInternalStandardRendererVertexBindTime", "number", ["number"]),
834
+ GetInternalStandardRendererIndexBindTime: Module.cwrap("EffekseerGetInternalStandardRendererIndexBindTime", "number", ["number"]),
835
+ GetInternalStandardRendererLayoutTime: Module.cwrap("EffekseerGetInternalStandardRendererLayoutTime", "number", ["number"]),
836
+ GetInternalStandardRendererDrawTime: Module.cwrap("EffekseerGetInternalStandardRendererDrawTime", "number", ["number"]),
837
+ GetManagerProfileFrustumTime: Module.cwrap("EffekseerGetManagerProfileFrustumTime", "number", ["number"]),
838
+ GetManagerProfileSortTime: Module.cwrap("EffekseerGetManagerProfileSortTime", "number", ["number"]),
839
+ GetManagerProfileCanDrawTime: Module.cwrap("EffekseerGetManagerProfileCanDrawTime", "number", ["number"]),
840
+ GetManagerProfileContainerDrawTime: Module.cwrap("EffekseerGetManagerProfileContainerDrawTime", "number", ["number"]),
841
+ GetManagerProfileGpuParticleTime: Module.cwrap("EffekseerGetManagerProfileGpuParticleTime", "number", ["number"]),
842
+ GetManagerProfileDrawSetCount: Module.cwrap("EffekseerGetManagerProfileDrawSetCount", "number", ["number"]),
843
+ GetManagerProfileVisibleDrawSetCount: Module.cwrap("EffekseerGetManagerProfileVisibleDrawSetCount", "number", ["number"]),
844
+ GetManagerProfileContainersTotal: Module.cwrap("EffekseerGetManagerProfileContainersTotal", "number", ["number"]),
845
+ GetManagerProfileContainersDrawn: Module.cwrap("EffekseerGetManagerProfileContainersDrawn", "number", ["number"]),
846
+ GetManagerProfileContainersDepthCulled: Module.cwrap("EffekseerGetManagerProfileContainersDepthCulled", "number", ["number"]),
847
+ GetDrawCallCount: Module.cwrap("EffekseerGetDrawCallCount", "number", ["number"]),
848
+ GetDrawVertexCount: Module.cwrap("EffekseerGetDrawVertexCount", "number", ["number"]),
849
+ GetTotalParticleCount: Module.cwrap("EffekseerGetTotalParticleCount", "number", ["number"]),
850
+ DrawExternalBack: Module.cwrap("EffekseerDrawExternalBack", "void", ["number"]),
851
+ DrawExternalFront: Module.cwrap("EffekseerDrawExternalFront", "void", ["number"]),
852
+ IsVertexArrayObjectSupported: Module.cwrap("EffekseerIsVertexArrayObjectSupported", "number", ["number"]),
853
+ SetRestorationOfStatesFlag: Module.cwrap("EffekseerSetRestorationOfStatesFlag", "void", ["number", "number"]),
854
+ CaptureBackground: Module.cwrap("EffekseerCaptureBackground", "void", ["number", "number", "number", "number", "number"]),
855
+ ResetBackground: Module.cwrap("EffekseerResetBackground", "void", ["number"]),
856
+ SetLogEnabled: Module.cwrap("EffekseerSetLogEnabled", "void", ["number"]),
857
+ SetDepthTexture: Module.cwrap("EffekseerSetDepthTexture", "void", ["number", "number"]),
858
+ SetBackgroundTexture: Module.cwrap("EffekseerSetBackgroundTexture", "void", ["number", "number"]),
859
+ };
860
+
861
+ Module.resourcesMap = {};
862
+
863
+ Module._loadBinary = (path, isRequired) => {
864
+ const effect = loadingEffect;
865
+ if (!effect) {
866
+ return null;
867
+ }
868
+
869
+ let res = effect.resources.find((r) => r.path === path);
870
+ if (res) {
871
+ return res.isLoaded ? res.buffer : null;
872
+ }
873
+
874
+ res = { path, isLoaded: false, buffer: null, isRequired: !!isRequired };
875
+ effect.resources.push(res);
876
+
877
+ const normalizePath = (value) => String(value || "").replace(/\\/g, "/");
878
+ const buildCandidates = (value) => {
879
+ const normalized = normalizePath(value);
880
+ const out = [];
881
+ const seen = new Set();
882
+ const add = (v) => {
883
+ if (!v || seen.has(v)) {
884
+ return;
885
+ }
886
+ seen.add(v);
887
+ out.push(v);
888
+ };
889
+ const addFolderHints = (v) => {
890
+ if (!v || v.includes("/")) {
891
+ return;
892
+ }
893
+ const lower = v.toLowerCase();
894
+ if (lower.endsWith(".png") || lower.endsWith(".jpg") || lower.endsWith(".jpeg") || lower.endsWith(".dds")) {
895
+ add(`Texture/${v}`);
896
+ }
897
+ if (lower.endsWith(".efkmodel") || lower.endsWith(".mqo")) {
898
+ add(`Model/${v}`);
899
+ }
900
+ };
901
+
902
+ // When Effekseer reports resource paths like:
903
+ // "<main_effect>.efkefc/Texture/foo.png"
904
+ // prioritize the path without the first segment so file-mode-relative
905
+ // resources resolve from baseDir (e.g. "Texture/foo.png").
906
+ const firstSlash = normalized.indexOf("/");
907
+ if (firstSlash > 0) {
908
+ const head = normalized.slice(0, firstSlash).toLowerCase();
909
+ if (head.endsWith(".efk") || head.endsWith(".efkefc") || head.endsWith(".efkproj")) {
910
+ add(normalized.slice(firstSlash + 1));
911
+ }
912
+ }
913
+
914
+ add(normalized);
915
+ addFolderHints(normalized);
916
+ let slashPos = normalized.indexOf("/");
917
+ while (slashPos >= 0) {
918
+ const suffix = normalized.slice(slashPos + 1);
919
+ add(suffix);
920
+ addFolderHints(suffix);
921
+ slashPos = normalized.indexOf("/", slashPos + 1);
922
+ }
923
+ return out;
924
+ };
925
+
926
+ const resolvePath = (candidatePath) => {
927
+ const candidate = normalizePath(candidatePath);
928
+ const isAbsolute =
929
+ candidate.startsWith("/") ||
930
+ /^[a-zA-Z]+:\/\//.test(candidate);
931
+ let resolved = isAbsolute ? candidate : ((effect.baseDir || "") + candidate);
932
+ if (effect.redirect) {
933
+ resolved = effect.redirect(resolved);
934
+ }
935
+ return resolved;
936
+ };
937
+
938
+ const candidates = buildCandidates(path);
939
+ if (effect.syncResourceLoad) {
940
+ for (let i = 0; i < candidates.length; i++) {
941
+ const candidate = candidates[i];
942
+ const resolvedPath = resolvePath(candidate);
943
+ const inlineBuffer =
944
+ Module.resourcesMap[resolvedPath] ||
945
+ Module.resourcesMap[candidate] ||
946
+ Module.resourcesMap[path];
947
+ if (inlineBuffer != null) {
948
+ res.buffer = inlineBuffer;
949
+ res.isLoaded = true;
950
+ return inlineBuffer;
951
+ }
952
+
953
+ const fetched = loadBinarySync(resolvedPath);
954
+ if (fetched != null) {
955
+ res.buffer = fetched;
956
+ res.isLoaded = true;
957
+ Module.resourcesMap[resolvedPath] = fetched;
958
+ Module.resourcesMap[candidate] = fetched;
959
+ return fetched;
960
+ }
961
+ }
962
+
963
+ res.buffer = null;
964
+ res.isLoaded = true;
965
+ return null;
966
+ }
967
+
968
+ for (let i = 0; i < candidates.length; i++) {
969
+ const candidate = candidates[i];
970
+ const resolvedPath = resolvePath(candidate);
971
+ const inlineBuffer =
972
+ Module.resourcesMap[resolvedPath] ||
973
+ Module.resourcesMap[candidate] ||
974
+ Module.resourcesMap[path];
975
+ if (inlineBuffer != null) {
976
+ res.buffer = inlineBuffer;
977
+ res.isLoaded = true;
978
+ Promise.resolve().then(() => effect._update());
979
+ return null;
980
+ }
981
+ }
982
+
983
+ let candidateIndex = 0;
984
+ const tryLoadNext = () => {
985
+ if (candidateIndex >= candidates.length) {
986
+ res.buffer = null;
987
+ res.isLoaded = true;
988
+ effect._update();
989
+ return;
990
+ }
991
+
992
+ const candidate = candidates[candidateIndex++];
993
+ const resolvedPath = resolvePath(candidate);
994
+ loadResource(
995
+ resolvedPath,
996
+ (buffer) => {
997
+ if (buffer != null) {
998
+ res.buffer = buffer;
999
+ res.isLoaded = true;
1000
+ effect._update();
1001
+ return;
1002
+ }
1003
+ tryLoadNext();
1004
+ },
1005
+ () => {
1006
+ tryLoadNext();
1007
+ }
1008
+ );
1009
+ };
1010
+ tryLoadNext();
1011
+
1012
+ return null;
1013
+ };
1014
+
1015
+ runtimeInitialized = true;
1016
+ runtimeInitializing = false;
1017
+ const callbacks = onRuntimeReadyQueue;
1018
+ onRuntimeReadyQueue = [];
1019
+ callbacks.forEach((cb) => cb(true));
1020
+ };
1021
+
1022
+ const initializeRuntimeInternal = async (wasmPath) => {
1023
+ if (runtimeInitialized) {
1024
+ return;
1025
+ }
1026
+ if (runtimeInitializing) {
1027
+ await new Promise((resolve, reject) => {
1028
+ onRuntimeReadyQueue.push((ok) => ok ? resolve() : reject(new Error("Runtime initialization failed.")));
1029
+ });
1030
+ return;
1031
+ }
1032
+
1033
+ runtimeInitializing = true;
1034
+
1035
+ if (typeof effekseer_webgpu_native === "undefined") {
1036
+ runtimeInitializing = false;
1037
+ throw new Error("effekseer_webgpu_native is not loaded.");
1038
+ }
1039
+
1040
+ const params = {};
1041
+ if (typeof wasmPath === "string" && wasmPath.length > 0) {
1042
+ params.locateFile = (path) => {
1043
+ if (path.endsWith(".wasm")) {
1044
+ return wasmPath;
1045
+ }
1046
+ return path;
1047
+ };
1048
+ }
1049
+
1050
+ if (preinitializedDevice) {
1051
+ params.preinitializedWebGPUDevice = preinitializedDevice;
1052
+ }
1053
+
1054
+ const moduleOrPromise = effekseer_webgpu_native(params);
1055
+ Module = (moduleOrPromise instanceof Promise) ? await moduleOrPromise : moduleOrPromise;
1056
+ if (!preinitializedDevice && Module?.preinitializedWebGPUDevice) {
1057
+ preinitializedDevice = Module.preinitializedWebGPUDevice;
1058
+ }
1059
+ if (preinitializedDevice) {
1060
+ Module.preinitializedWebGPUDevice = preinitializedDevice;
1061
+ }
1062
+ initCoreBindings();
1063
+ };
1064
+
1065
+ class EffekseerEffect {
1066
+ constructor(context) {
1067
+ this.context = context;
1068
+ this.nativeptr = 0;
1069
+ this.baseDir = "";
1070
+ this.syncResourceLoad = false;
1071
+ this.isLoaded = false;
1072
+ this.scale = 1.0;
1073
+ this.resources = [];
1074
+ this.mainBuffer = null;
1075
+ this.onload = null;
1076
+ this.onerror = null;
1077
+ this._onloadListeners = [];
1078
+ this._onerrorListeners = [];
1079
+ this._loadFailed = false;
1080
+ this._loadErrorMessage = "";
1081
+ this._loadErrorPath = "";
1082
+ this._cacheKey = "";
1083
+ this.redirect = null;
1084
+ this.packageOnly = false;
1085
+ this._ownedResourceAliases = [];
1086
+ this._managedRefIds = new Set();
1087
+ }
1088
+
1089
+ _load(buffer) {
1090
+ const ab = toArrayBuffer(buffer);
1091
+ if (!ab) {
1092
+ dispatchEffectError(this, "invalid data", "");
1093
+ return;
1094
+ }
1095
+
1096
+ loadingEffect = this;
1097
+ this.mainBuffer = ab;
1098
+ const memptr = Module._malloc(ab.byteLength);
1099
+ Module.HEAPU8.set(new Uint8Array(ab), memptr);
1100
+ this.nativeptr = Core.LoadEffect(this.context.nativeptr, memptr, ab.byteLength, this.scale);
1101
+ Module._free(memptr);
1102
+ loadingEffect = null;
1103
+
1104
+ this._update();
1105
+ }
1106
+
1107
+ _reload() {
1108
+ if (!this.mainBuffer || !this.nativeptr) {
1109
+ return;
1110
+ }
1111
+
1112
+ loadingEffect = this;
1113
+ const memptr = Module._malloc(this.mainBuffer.byteLength);
1114
+ Module.HEAPU8.set(new Uint8Array(this.mainBuffer), memptr);
1115
+ Core.ReloadResources(this.context.nativeptr, this.nativeptr, memptr, this.mainBuffer.byteLength);
1116
+ Module._free(memptr);
1117
+ loadingEffect = null;
1118
+ }
1119
+
1120
+ _update() {
1121
+ let hasPendingResources = false;
1122
+ const missingRequiredResources = [];
1123
+ for (let i = 0; i < this.resources.length; i++) {
1124
+ const resource = this.resources[i];
1125
+ if (!resource.isLoaded) {
1126
+ hasPendingResources = true;
1127
+ break;
1128
+ }
1129
+ if (resource.isRequired && resource.buffer == null) {
1130
+ missingRequiredResources.push(resource.path);
1131
+ }
1132
+ }
1133
+
1134
+ if (hasPendingResources) {
1135
+ return;
1136
+ }
1137
+
1138
+ if (missingRequiredResources.length > 0) {
1139
+ console.warn(
1140
+ `[EffekseerWebGPU] missing required resources ignored: ${missingRequiredResources.join(", ")}`
1141
+ );
1142
+ }
1143
+
1144
+ const loaded = this.nativeptr !== 0;
1145
+ if (!loaded) {
1146
+ const detail = missingRequiredResources.length > 0
1147
+ ? `failed to load effect. missing resources: ${missingRequiredResources.join(", ")}`
1148
+ : "failed to load effect";
1149
+ dispatchEffectError(this, detail, this.baseDir || "");
1150
+ return;
1151
+ }
1152
+
1153
+ if (loaded && this.resources.length > 0) {
1154
+ this._reload();
1155
+ }
1156
+
1157
+ if (!this.isLoaded && loaded) {
1158
+ this.isLoaded = true;
1159
+ dispatchEffectLoaded(this);
1160
+ }
1161
+ }
1162
+ }
1163
+
1164
+ const createPackageEffect = (context, packageBuffer, sourcePath, scale, onload, onerror, redirect, existingEffect = null) => {
1165
+ const effect = existingEffect || new EffekseerEffect(context);
1166
+ effect.scale = scale;
1167
+ effect._ownedResourceAliases = [];
1168
+ registerEffectCallbacks(effect, onload, onerror);
1169
+
1170
+ const entryMap = buildEfwgpkEntryMap(packageBuffer);
1171
+ if (entryMap.size === 0) {
1172
+ dispatchEffectError(effect, "invalid data. expected efkwgpk package", sourcePath || "");
1173
+ return effect;
1174
+ }
1175
+
1176
+ const packageDir = (() => {
1177
+ if (typeof sourcePath !== "string" || sourcePath.length === 0) {
1178
+ return "";
1179
+ }
1180
+ const normalized = stripUrlDecorations(sourcePath);
1181
+ const dirIndex = normalized.lastIndexOf("/");
1182
+ return dirIndex >= 0 ? normalized.slice(0, dirIndex + 1) : "";
1183
+ })();
1184
+ const packageDirLower = packageDir.toLowerCase();
1185
+ const packagePrefix = `${EFWGPK_RESOURCE_SCHEME}${++efwgpkPackageId}/`;
1186
+ const resourceAliasMap = new Map();
1187
+
1188
+ effect.baseDir = packageDir;
1189
+ effect.syncResourceLoad = true;
1190
+ effect.packageOnly = true;
1191
+ effect.redirect = (resolvedPath) => {
1192
+ const normalizedResolved = stripUrlDecorations(resolvedPath);
1193
+ const candidates = [];
1194
+
1195
+ if (packageDirLower && normalizedResolved.toLowerCase().startsWith(packageDirLower)) {
1196
+ candidates.push(normalizedResolved.slice(packageDir.length));
1197
+ }
1198
+ candidates.push(normalizedResolved);
1199
+
1200
+ for (let i = 0; i < candidates.length; i++) {
1201
+ const normalizedCandidate = normalizePackagePath(candidates[i]);
1202
+ if (!normalizedCandidate) {
1203
+ continue;
1204
+ }
1205
+ const alias = resourceAliasMap.get(normalizedCandidate);
1206
+ if (alias) {
1207
+ return alias;
1208
+ }
1209
+ }
1210
+
1211
+ return resolvedPath;
1212
+ };
1213
+
1214
+ (async () => {
1215
+ try {
1216
+ const mainEffectPath = await getEfwgpkMainEffectPath(packageBuffer, entryMap);
1217
+ if (!mainEffectPath) {
1218
+ throw new Error("main effect path not found in efkwgpk package");
1219
+ }
1220
+
1221
+ const mainBuffer = await getEfwgpkEntryBytes(packageBuffer, entryMap, mainEffectPath);
1222
+ const mainMagic4 = String.fromCharCode(...new Uint8Array(mainBuffer || new ArrayBuffer(0), 0, Math.min(4, mainBuffer ? mainBuffer.byteLength : 0)));
1223
+ if (!mainBuffer || (mainMagic4 !== "EFWG" && mainMagic4 !== "SKFE")) {
1224
+ throw new Error("main effect inside efkwgpk is not a valid .efkwg");
1225
+ }
1226
+
1227
+ const payloadAliasMap = new Map();
1228
+ const payloadBytesCache = new Map();
1229
+ for (const [normalizedPath] of entryMap.entries()) {
1230
+ if (normalizedPath === mainEffectPath || normalizedPath === normalizePackagePath(EFWGPK_META_MAIN)) {
1231
+ continue;
1232
+ }
1233
+ const canonicalEntry = getEfwgpkCanonicalEntry(packageBuffer, entryMap, normalizedPath);
1234
+ if (!canonicalEntry) {
1235
+ continue;
1236
+ }
1237
+ const payloadKey = getEfwgpkEntryPayloadKey(canonicalEntry);
1238
+ if (!payloadKey) {
1239
+ continue;
1240
+ }
1241
+
1242
+ let alias = payloadAliasMap.get(payloadKey);
1243
+ if (!alias) {
1244
+ let entryBytes = payloadBytesCache.get(payloadKey);
1245
+ if (entryBytes === undefined) {
1246
+ entryBytes = await getEfwgpkEntryBytes(packageBuffer, entryMap, normalizedPath);
1247
+ payloadBytesCache.set(payloadKey, entryBytes || null);
1248
+ }
1249
+ if (!entryBytes) {
1250
+ continue;
1251
+ }
1252
+ alias = `${packagePrefix}__payload/${payloadAliasMap.size}`;
1253
+ Module.resourcesMap[alias] = entryBytes;
1254
+ payloadAliasMap.set(payloadKey, alias);
1255
+ }
1256
+
1257
+ resourceAliasMap.set(normalizedPath, alias);
1258
+ }
1259
+
1260
+ effect._ownedResourceAliases = Array.from(payloadAliasMap.values());
1261
+
1262
+ effect._load(mainBuffer);
1263
+ if (!effect.nativeptr) {
1264
+ dispatchEffectError(effect, "failed to load effect from efkwgpk package", sourcePath || mainEffectPath);
1265
+ }
1266
+ } catch (error) {
1267
+ dispatchEffectError(effect, error && error.message ? error.message : "failed to load effect from efkwgpk package", sourcePath || "");
1268
+ }
1269
+ })();
1270
+
1271
+ return effect;
1272
+ };
1273
+
1274
+ class EffekseerHandle {
1275
+ constructor(context, nativeHandle) {
1276
+ this.context = context;
1277
+ this.native = nativeHandle;
1278
+ }
1279
+
1280
+ stop() { Core.StopEffect(this.context.nativeptr, this.native); }
1281
+ stopRoot() { Core.StopRoot(this.context.nativeptr, this.native); }
1282
+ get exists() { return !!Core.Exists(this.context.nativeptr, this.native); }
1283
+ setFrame(frame) { Core.SetFrame(this.context.nativeptr, this.native, frame); }
1284
+ setLocation(x, y, z) { Core.SetLocation(this.context.nativeptr, this.native, x, y, z); }
1285
+ setRotation(x, y, z) { Core.SetRotation(this.context.nativeptr, this.native, x, y, z); }
1286
+ setScale(x, y, z) { Core.SetScale(this.context.nativeptr, this.native, x, y, z); }
1287
+ setAllColor(r, g, b, a) { Core.SetAllColor(this.context.nativeptr, this.native, r, g, b, a); }
1288
+ setTargetLocation(x, y, z) { Core.SetTargetLocation(this.context.nativeptr, this.native, x, y, z); }
1289
+ getDynamicInput(index) { return Core.GetDynamicInput(this.context.nativeptr, this.native, index); }
1290
+ setDynamicInput(index, value) { Core.SetDynamicInput(this.context.nativeptr, this.native, index, value); }
1291
+ sendTrigger(index) { Core.SendTrigger(this.context.nativeptr, this.native, index); }
1292
+ setPaused(paused) { Core.SetPaused(this.context.nativeptr, this.native, paused ? 1 : 0); }
1293
+ setShown(shown) { Core.SetShown(this.context.nativeptr, this.native, shown ? 1 : 0); }
1294
+ setSpeed(speed) { Core.SetSpeed(this.context.nativeptr, this.native, speed); }
1295
+ setRandomSeed(seed) { Core.SetRandomSeed(this.context.nativeptr, this.native, seed); }
1296
+
1297
+ setMatrix(matrixArray) {
1298
+ withFloatArray(matrixArray, (ptr) => Core.SetMatrix(this.context.nativeptr, this.native, ptr));
1299
+ }
1300
+ }
1301
+
1302
+ class EffekseerContext {
1303
+ constructor() {
1304
+ this.nativeptr = 0;
1305
+ this._effectCache = new Map();
1306
+ this._registeredEffects = new Map();
1307
+ this._registeredEffectStates = new Map();
1308
+ this.fixedUpdateStepFrames = 1.0;
1309
+ this.fixedUpdateMaxSubsteps = 4;
1310
+ this.fixedUpdateAccumulator = 0.0;
1311
+ this.externalRenderPassEnabled = false;
1312
+ }
1313
+
1314
+ _normalizeManagedEffectDescriptor(id, value) {
1315
+ const effectId = String(id || "").trim();
1316
+ if (!effectId) {
1317
+ throw new Error("registerEffects() requires non-empty effect ids.");
1318
+ }
1319
+
1320
+ let descriptor = null;
1321
+ if (typeof value === "string") {
1322
+ descriptor = { path: value };
1323
+ } else if (value && typeof value === "object" && !Array.isArray(value)) {
1324
+ descriptor = value;
1325
+ } else {
1326
+ throw new Error(`registerEffects() entry "${effectId}" must be a string path or config object.`);
1327
+ }
1328
+
1329
+ const path = String(descriptor.path || "").trim();
1330
+ if (!path) {
1331
+ throw new Error(`registerEffects() entry "${effectId}" requires a non-empty path.`);
1332
+ }
1333
+
1334
+ const numericScale = Number(descriptor.scale);
1335
+ return {
1336
+ id: effectId,
1337
+ path,
1338
+ scale: Number.isFinite(numericScale) ? numericScale : 1.0,
1339
+ enabled: descriptor.enabled !== false,
1340
+ };
1341
+ }
1342
+
1343
+ _createManagedEffectState(descriptor) {
1344
+ return {
1345
+ id: descriptor.id,
1346
+ path: descriptor.path,
1347
+ scale: descriptor.scale,
1348
+ enabled: descriptor.enabled,
1349
+ status: "unloaded",
1350
+ effect: null,
1351
+ errorMessage: "",
1352
+ errorPath: "",
1353
+ loadPromise: null,
1354
+ activeHandles: new Set(),
1355
+ ownedResourceAliases: [],
1356
+ _generation: 0,
1357
+ _loadingEffect: null,
1358
+ };
1359
+ }
1360
+
1361
+ _resolveManagedEffectIds(ids, enabledOnly = false) {
1362
+ if (ids == null) {
1363
+ const resolvedIds = [];
1364
+ for (const [id, state] of this._registeredEffectStates.entries()) {
1365
+ if (!enabledOnly || state.enabled) {
1366
+ resolvedIds.push(id);
1367
+ }
1368
+ }
1369
+ return resolvedIds;
1370
+ }
1371
+
1372
+ const inputIds = Array.isArray(ids) ? ids : [ids];
1373
+ const uniqueIds = [];
1374
+ const seen = new Set();
1375
+ for (let i = 0; i < inputIds.length; i++) {
1376
+ const id = String(inputIds[i] || "").trim();
1377
+ if (!id || seen.has(id)) {
1378
+ continue;
1379
+ }
1380
+ seen.add(id);
1381
+ uniqueIds.push(id);
1382
+ }
1383
+ return uniqueIds;
1384
+ }
1385
+
1386
+ _registerManagedEffectReference(effect, id) {
1387
+ if (!effect) {
1388
+ return;
1389
+ }
1390
+ if (!(effect._managedRefIds instanceof Set)) {
1391
+ effect._managedRefIds = new Set();
1392
+ }
1393
+ effect._managedRefIds.add(id);
1394
+ }
1395
+
1396
+ _releaseManagedEffectReference(effect, id) {
1397
+ if (!effect || !(effect._managedRefIds instanceof Set)) {
1398
+ return;
1399
+ }
1400
+ effect._managedRefIds.delete(id);
1401
+ }
1402
+
1403
+ _releaseManagedEffectIfUnused(effect) {
1404
+ if (!effect) {
1405
+ return;
1406
+ }
1407
+ const managedRefIds = effect._managedRefIds instanceof Set ? effect._managedRefIds : null;
1408
+ if (managedRefIds && managedRefIds.size > 0) {
1409
+ return;
1410
+ }
1411
+
1412
+ clearCachedEffectReference(effect);
1413
+ clearOwnedResourceAliases(effect._ownedResourceAliases);
1414
+ effect._ownedResourceAliases = [];
1415
+
1416
+ if (this.nativeptr && effect.nativeptr) {
1417
+ Core.ReleaseEffect(this.nativeptr, effect.nativeptr);
1418
+ effect.nativeptr = 0;
1419
+ }
1420
+ }
1421
+
1422
+ _stopManagedHandles(state) {
1423
+ if (!state) {
1424
+ return;
1425
+ }
1426
+ for (const handle of state.activeHandles) {
1427
+ try {
1428
+ handle?.stopRoot?.();
1429
+ } catch {
1430
+ // Swallow stale-handle errors during managed teardown.
1431
+ }
1432
+ }
1433
+ state.activeHandles.clear();
1434
+ }
1435
+
1436
+ _cleanupManagedHandles() {
1437
+ for (const state of this._registeredEffectStates.values()) {
1438
+ if (!state || state.activeHandles.size === 0) {
1439
+ continue;
1440
+ }
1441
+ for (const handle of Array.from(state.activeHandles)) {
1442
+ if (!handle || handle.exists === false) {
1443
+ state.activeHandles.delete(handle);
1444
+ }
1445
+ }
1446
+ }
1447
+ }
1448
+
1449
+ _resetManagedEffectStateToUnloaded(state) {
1450
+ if (!state) {
1451
+ return;
1452
+ }
1453
+ state.effect = null;
1454
+ state.status = "unloaded";
1455
+ state.errorMessage = "";
1456
+ state.errorPath = "";
1457
+ state.loadPromise = null;
1458
+ state.ownedResourceAliases = [];
1459
+ state._loadingEffect = null;
1460
+ }
1461
+
1462
+ _loadRegisteredEffectState(state) {
1463
+ if (!state || !this.nativeptr) {
1464
+ return Promise.resolve(null);
1465
+ }
1466
+
1467
+ const descriptor = this._registeredEffects.get(state.id);
1468
+ if (!descriptor) {
1469
+ return Promise.resolve(null);
1470
+ }
1471
+
1472
+ const generation = state._generation + 1;
1473
+ state._generation = generation;
1474
+ state.status = "loading";
1475
+ state.errorMessage = "";
1476
+ state.errorPath = "";
1477
+ state.effect = null;
1478
+ state.ownedResourceAliases = [];
1479
+ state._loadingEffect = null;
1480
+
1481
+ const loadPromise = new Promise((resolve) => {
1482
+ let settled = false;
1483
+ let requestedEffect = null;
1484
+
1485
+ const finishSuccess = (loadedEffect) => {
1486
+ if (settled) {
1487
+ return;
1488
+ }
1489
+ settled = true;
1490
+
1491
+ const currentState = this._registeredEffectStates.get(state.id);
1492
+ if (currentState !== state || state._generation !== generation) {
1493
+ this._releaseManagedEffectIfUnused(loadedEffect);
1494
+ resolve(null);
1495
+ return;
1496
+ }
1497
+
1498
+ state._loadingEffect = null;
1499
+ state.loadPromise = null;
1500
+
1501
+ if (!loadedEffect || !loadedEffect.isLoaded) {
1502
+ state.status = "failed";
1503
+ state.errorMessage = "failed to load effect";
1504
+ state.errorPath = descriptor.path;
1505
+ resolve(null);
1506
+ return;
1507
+ }
1508
+
1509
+ state.effect = loadedEffect;
1510
+ state.status = "loaded";
1511
+ state.errorMessage = "";
1512
+ state.errorPath = "";
1513
+ state.ownedResourceAliases = Array.isArray(loadedEffect._ownedResourceAliases)
1514
+ ? loadedEffect._ownedResourceAliases.slice()
1515
+ : [];
1516
+ resolve(loadedEffect);
1517
+ };
1518
+
1519
+ const finishError = (message, path = "") => {
1520
+ if (settled) {
1521
+ return;
1522
+ }
1523
+ settled = true;
1524
+
1525
+ if (requestedEffect) {
1526
+ this._releaseManagedEffectReference(requestedEffect, state.id);
1527
+ }
1528
+
1529
+ const currentState = this._registeredEffectStates.get(state.id);
1530
+ if (currentState !== state || state._generation !== generation) {
1531
+ if (requestedEffect) {
1532
+ this._releaseManagedEffectIfUnused(requestedEffect);
1533
+ }
1534
+ resolve(null);
1535
+ return;
1536
+ }
1537
+
1538
+ state._loadingEffect = null;
1539
+ state.loadPromise = null;
1540
+ state.effect = null;
1541
+ state.status = "failed";
1542
+ state.errorMessage = String(message || "failed to load effect");
1543
+ state.errorPath = String(path || descriptor.path || "");
1544
+ state.ownedResourceAliases = [];
1545
+ if (requestedEffect) {
1546
+ this._releaseManagedEffectIfUnused(requestedEffect);
1547
+ }
1548
+ resolve(null);
1549
+ };
1550
+
1551
+ try {
1552
+ requestedEffect = this.loadEffect(
1553
+ descriptor.path,
1554
+ descriptor.scale,
1555
+ () => finishSuccess(requestedEffect),
1556
+ (message, path) => finishError(message, path)
1557
+ );
1558
+ } catch (error) {
1559
+ finishError(error && error.message ? error.message : "failed to load effect", descriptor.path);
1560
+ return;
1561
+ }
1562
+
1563
+ state._loadingEffect = requestedEffect;
1564
+ if (!requestedEffect) {
1565
+ finishError("failed to create effect", descriptor.path);
1566
+ return;
1567
+ }
1568
+
1569
+ this._registerManagedEffectReference(requestedEffect, state.id);
1570
+
1571
+ if (requestedEffect.isLoaded) {
1572
+ finishSuccess(requestedEffect);
1573
+ return;
1574
+ }
1575
+
1576
+ if (requestedEffect._loadFailed) {
1577
+ finishError(requestedEffect._loadErrorMessage, requestedEffect._loadErrorPath);
1578
+ }
1579
+ });
1580
+
1581
+ state.loadPromise = loadPromise;
1582
+ return loadPromise;
1583
+ }
1584
+
1585
+ _prepareInitSettings(settings = {}, externalRenderPassEnabled = false) {
1586
+ const instanceMaxCount = settings.instanceMaxCount || 4000;
1587
+ const squareMaxCount = settings.squareMaxCount || 10000;
1588
+ const linearColorSpace = settings.linearColorSpace !== false ? 1 : 0;
1589
+ const compositeWithBackground = settings.compositeWithBackground ? 1 : 0;
1590
+ this.externalRenderPassEnabled = externalRenderPassEnabled;
1591
+
1592
+ // Always use stable fixed-step simulation.
1593
+ this.fixedUpdateAccumulator = 0.0;
1594
+
1595
+ return {
1596
+ instanceMaxCount,
1597
+ squareMaxCount,
1598
+ linearColorSpace,
1599
+ compositeWithBackground,
1600
+ };
1601
+ }
1602
+
1603
+ _finishContextInit(settings = {}) {
1604
+ if (this.nativeptr && settings.effects) {
1605
+ this.registerEffects(settings.effects);
1606
+ void this.preloadEffects();
1607
+ }
1608
+ return !!this.nativeptr;
1609
+ }
1610
+
1611
+ init(target, settings = {}) {
1612
+ if (settings.externalRenderPass === true) {
1613
+ return this.initExternal(settings);
1614
+ }
1615
+
1616
+ let selector = "#canvas";
1617
+ if (typeof target === "string") {
1618
+ selector = target.startsWith("#") ? target : `#${target}`;
1619
+ } else if (typeof HTMLCanvasElement !== "undefined" && target instanceof HTMLCanvasElement) {
1620
+ if (!target.id) {
1621
+ contextId += 1;
1622
+ target.id = `effekseer_webgpu_canvas_${contextId}`;
1623
+ }
1624
+ selector = `#${target.id}`;
1625
+ }
1626
+
1627
+ const config = this._prepareInitSettings(settings, false);
1628
+ this.nativeptr = Core.InitInternal(
1629
+ config.instanceMaxCount,
1630
+ config.squareMaxCount,
1631
+ selector,
1632
+ config.linearColorSpace,
1633
+ config.compositeWithBackground
1634
+ );
1635
+ return this._finishContextInit(settings);
1636
+ }
1637
+
1638
+ initExternal(settings = {}) {
1639
+ const config = this._prepareInitSettings(settings, true);
1640
+ this.nativeptr = Core.InitExternal(
1641
+ config.instanceMaxCount,
1642
+ config.squareMaxCount,
1643
+ config.linearColorSpace,
1644
+ config.compositeWithBackground
1645
+ );
1646
+ return this._finishContextInit(settings);
1647
+ }
1648
+
1649
+ update(deltaFrames = 1.0) {
1650
+ const delta = Number(deltaFrames);
1651
+ if (!Number.isFinite(delta) || delta <= 0.0) {
1652
+ this._cleanupManagedHandles();
1653
+ return;
1654
+ }
1655
+
1656
+ this.fixedUpdateAccumulator += delta;
1657
+ let substeps = 0;
1658
+ while (this.fixedUpdateAccumulator >= this.fixedUpdateStepFrames && substeps < this.fixedUpdateMaxSubsteps) {
1659
+ Core.Update(this.nativeptr, this.fixedUpdateStepFrames);
1660
+ this.fixedUpdateAccumulator -= this.fixedUpdateStepFrames;
1661
+ substeps++;
1662
+ }
1663
+
1664
+ if (substeps >= this.fixedUpdateMaxSubsteps && this.fixedUpdateAccumulator >= this.fixedUpdateStepFrames) {
1665
+ // Drop backlog to avoid long simulation bursts after frame hitches.
1666
+ this.fixedUpdateAccumulator = 0.0;
1667
+ }
1668
+ this._cleanupManagedHandles();
1669
+ }
1670
+ beginUpdate() { Core.BeginUpdate(this.nativeptr); }
1671
+ endUpdate() { Core.EndUpdate(this.nativeptr); }
1672
+ updateHandle(handle, deltaFrames = 1.0) { Core.UpdateHandle(this.nativeptr, handle.native, deltaFrames); }
1673
+ draw() {
1674
+ if (this.externalRenderPassEnabled) {
1675
+ return;
1676
+ }
1677
+
1678
+ Core.Draw(this.nativeptr);
1679
+ }
1680
+ drawExternal(renderPassEncoder, renderPassState = null, mode = "all") {
1681
+ if (!renderPassEncoder) {
1682
+ return;
1683
+ }
1684
+
1685
+ const colorFormatRaw = toTextureFormatValue(renderPassState && renderPassState.colorFormat);
1686
+ // Explicitly pass Undefined (0) when the external pass has no depth attachment.
1687
+ const depthFormatRaw = (() => {
1688
+ const v = toTextureFormatValue(renderPassState && renderPassState.depthFormat);
1689
+ return (v === null) ? 0 : v;
1690
+ })();
1691
+ const sampleCountRaw = toSampleCountValue(renderPassState && renderPassState.sampleCount);
1692
+ const hasOwn = (obj, key) => !!obj && Object.prototype.hasOwnProperty.call(obj, key);
1693
+ const hasDepthViewInState = hasOwn(renderPassState, "depthTextureView") || hasOwn(renderPassState, "importDepthTextureView");
1694
+ const hasBackgroundViewInState = hasOwn(renderPassState, "backgroundTextureView") || hasOwn(renderPassState, "importBackgroundTextureView");
1695
+ const depthTextureViewFromState = hasDepthViewInState
1696
+ ? (hasOwn(renderPassState, "depthTextureView") ? renderPassState.depthTextureView : renderPassState.importDepthTextureView)
1697
+ : null;
1698
+ const backgroundTextureViewFromState = hasBackgroundViewInState
1699
+ ? (hasOwn(renderPassState, "backgroundTextureView") ? renderPassState.backgroundTextureView : renderPassState.importBackgroundTextureView)
1700
+ : null;
1701
+ const prevDepthTextureView = hasDepthViewInState ? Module.__effekseerDepthTextureView : null;
1702
+ const prevBackgroundTextureView = hasBackgroundViewInState ? Module.__effekseerBackgroundTextureView : null;
1703
+
1704
+ Module.__effekseerExternalRenderPass = renderPassEncoder;
1705
+ Module.__effekseerExternalPassColorFormat = colorFormatRaw;
1706
+ Module.__effekseerExternalPassDepthFormat = depthFormatRaw;
1707
+ Module.__effekseerExternalPassSampleCount = sampleCountRaw;
1708
+ if (hasDepthViewInState) {
1709
+ Module.__effekseerDepthTextureView = depthTextureViewFromState || null;
1710
+ }
1711
+ if (hasBackgroundViewInState) {
1712
+ Module.__effekseerBackgroundTextureView = backgroundTextureViewFromState || null;
1713
+ }
1714
+ const drawMode = (() => {
1715
+ if (mode === "back") {
1716
+ return "back";
1717
+ }
1718
+ if (mode === "front") {
1719
+ return "front";
1720
+ }
1721
+ return "all";
1722
+ })();
1723
+ try {
1724
+ if (drawMode === "back") {
1725
+ Core.DrawExternalBack(this.nativeptr);
1726
+ } else if (drawMode === "front") {
1727
+ Core.DrawExternalFront(this.nativeptr);
1728
+ } else {
1729
+ Core.DrawExternal(this.nativeptr);
1730
+ }
1731
+ } finally {
1732
+ if (hasDepthViewInState) {
1733
+ Module.__effekseerDepthTextureView = prevDepthTextureView || null;
1734
+ }
1735
+ if (hasBackgroundViewInState) {
1736
+ Module.__effekseerBackgroundTextureView = prevBackgroundTextureView || null;
1737
+ }
1738
+ Module.__effekseerExternalRenderPass = null;
1739
+ Module.__effekseerExternalPassColorFormat = null;
1740
+ Module.__effekseerExternalPassDepthFormat = null;
1741
+ Module.__effekseerExternalPassSampleCount = null;
1742
+ }
1743
+ }
1744
+ beginDraw() { Core.BeginDraw(this.nativeptr); }
1745
+ endDraw() { Core.EndDraw(this.nativeptr); }
1746
+ drawHandle(handle) { Core.DrawHandle(this.nativeptr, handle.native); }
1747
+
1748
+ setProjectionMatrix(matrixArray) {
1749
+ withFloatArray(matrixArray, (ptr) => Core.SetProjectionMatrix(this.nativeptr, ptr));
1750
+ }
1751
+
1752
+ setProjectionPerspective(fov, aspect, near, far) {
1753
+ Core.SetProjectionPerspective(this.nativeptr, fov, aspect, near, far);
1754
+ }
1755
+
1756
+ setProjectionOrthographic(width, height, near, far) {
1757
+ Core.SetProjectionOrthographic(this.nativeptr, width, height, near, far);
1758
+ }
1759
+
1760
+ setCameraMatrix(matrixArray) {
1761
+ withFloatArray(matrixArray, (ptr) => Core.SetCameraMatrix(this.nativeptr, ptr));
1762
+ }
1763
+
1764
+ setCameraLookAt(positionX, positionY, positionZ, targetX, targetY, targetZ, upvecX, upvecY, upvecZ) {
1765
+ Core.SetCameraLookAt(this.nativeptr, positionX, positionY, positionZ, targetX, targetY, targetZ, upvecX, upvecY, upvecZ);
1766
+ }
1767
+
1768
+ setCameraLookAtFromVector(position, target, upvec = { x: 0, y: 1, z: 0 }) {
1769
+ this.setCameraLookAt(position.x, position.y, position.z, target.x, target.y, target.z, upvec.x, upvec.y, upvec.z);
1770
+ }
1771
+
1772
+ setCompositeMode(enabled) {
1773
+ Core.SetCompositeMode(this.nativeptr, enabled ? 1 : 0);
1774
+ }
1775
+
1776
+ loadEffect(data, scale = 1.0, onload, onerror, redirect) {
1777
+ const effectScale = (typeof scale === "function") ? 1.0 : scale;
1778
+ const effectOnload = (typeof scale === "function") ? scale : onload;
1779
+ const effectOnerror = (typeof scale === "function") ? onload : onerror;
1780
+ const effectRedirect = redirect;
1781
+ let cacheKey = null;
1782
+ if (typeof data === "string" && effectRedirect == null) {
1783
+ cacheKey = buildEffectCacheKey(data, effectScale);
1784
+ const cachedEffect = this._effectCache.get(cacheKey);
1785
+ if (cachedEffect) {
1786
+ registerEffectCallbacks(cachedEffect, effectOnload, effectOnerror);
1787
+ return cachedEffect;
1788
+ }
1789
+ }
1790
+
1791
+ const effect = new EffekseerEffect(this);
1792
+ effect.scale = effectScale;
1793
+ effect.redirect = effectRedirect;
1794
+ effect._cacheKey = cacheKey || "";
1795
+ registerEffectCallbacks(effect, effectOnload, effectOnerror);
1796
+
1797
+ if (cacheKey) {
1798
+ this._effectCache.set(cacheKey, effect);
1799
+ }
1800
+
1801
+ const fail = (message, path = "") => {
1802
+ dispatchEffectError(effect, message, path);
1803
+ return effect;
1804
+ };
1805
+
1806
+ if (typeof data === "string") {
1807
+ if (isEfkWgPath(data)) {
1808
+ loadBinary(data, (effectBytes) => {
1809
+ const effectBuffer = toArrayBuffer(effectBytes);
1810
+ if (!effectBuffer) {
1811
+ fail("failed to fetch efkwg effect", data);
1812
+ return;
1813
+ }
1814
+ const normalized = data.replace(/\\/g, "/").split("?")[0].split("#")[0];
1815
+ const dirIndex = normalized.lastIndexOf("/");
1816
+ effect.baseDir = dirIndex >= 0 ? normalized.slice(0, dirIndex + 1) : "";
1817
+ effect.syncResourceLoad = false;
1818
+ effect._load(effectBuffer);
1819
+ if (!effect.nativeptr) {
1820
+ fail("failed to load efkwg effect", data);
1821
+ }
1822
+ }, () => {
1823
+ fail("failed to fetch efkwg effect", data);
1824
+ });
1825
+ return effect;
1826
+ }
1827
+
1828
+ if (isEfwgpkPath(data)) {
1829
+ loadBinary(data, (packageBytes) => {
1830
+ const packageBuffer = toArrayBuffer(packageBytes);
1831
+ if (!packageBuffer) {
1832
+ fail("failed to fetch efkwgpk package", data);
1833
+ return;
1834
+ }
1835
+ createPackageEffect(this, packageBuffer, data, effectScale, null, null, effectRedirect, effect);
1836
+ }, () => {
1837
+ fail("failed to fetch efkwgpk package", data);
1838
+ });
1839
+ return effect;
1840
+ }
1841
+
1842
+ return fail("unsupported effect format. expected .efkwg or .efkwgpk", data);
1843
+ }
1844
+
1845
+ const packageBuffer = toArrayBuffer(data);
1846
+ if (!packageBuffer) {
1847
+ return fail("invalid data. expected efkwg or efkwgpk bytes", "");
1848
+ }
1849
+
1850
+ if (readMagic8(packageBuffer) === EFWGPK_MAGIC) {
1851
+ return createPackageEffect(this, packageBuffer, "", effectScale, null, null, effectRedirect, effect);
1852
+ }
1853
+
1854
+ const magic4 = String.fromCharCode(...new Uint8Array(packageBuffer, 0, Math.min(4, packageBuffer.byteLength)));
1855
+ if (magic4 === "EFWG" || magic4 === "SKFE") {
1856
+ effect._load(packageBuffer);
1857
+ if (!effect.nativeptr) {
1858
+ return fail("failed to load efkwg effect", "");
1859
+ }
1860
+ return effect;
1861
+ }
1862
+
1863
+ return fail("invalid data. expected efkwg or efkwgpk bytes", "");
1864
+ }
1865
+
1866
+ loadEffectPackage(data, Unzip, scale = 1.0, onload, onerror) {
1867
+ let effectScale = scale;
1868
+ let effectOnload = onload;
1869
+ let effectOnerror = onerror;
1870
+ if (typeof scale === "function") {
1871
+ effectScale = 1.0;
1872
+ effectOnload = scale;
1873
+ effectOnerror = onload;
1874
+ }
1875
+ void Unzip;
1876
+ return this.loadEffect(data, effectScale, effectOnload, effectOnerror);
1877
+ }
1878
+
1879
+ registerEffects(effects) {
1880
+ if (!effects || typeof effects !== "object" || Array.isArray(effects)) {
1881
+ throw new Error("registerEffects() expects an object map of effect ids to paths/configs.");
1882
+ }
1883
+
1884
+ const nextDescriptors = [];
1885
+ for (const [id, value] of Object.entries(effects)) {
1886
+ if (this._registeredEffects.has(id)) {
1887
+ throw new Error(`registerEffects() duplicate id "${id}".`);
1888
+ }
1889
+ nextDescriptors.push(this._normalizeManagedEffectDescriptor(id, value));
1890
+ }
1891
+
1892
+ for (let i = 0; i < nextDescriptors.length; i++) {
1893
+ const descriptor = nextDescriptors[i];
1894
+ if (this._registeredEffects.has(descriptor.id)) {
1895
+ throw new Error(`registerEffects() duplicate id "${descriptor.id}".`);
1896
+ }
1897
+ }
1898
+
1899
+ for (let i = 0; i < nextDescriptors.length; i++) {
1900
+ const descriptor = nextDescriptors[i];
1901
+ this._registeredEffects.set(descriptor.id, descriptor);
1902
+ this._registeredEffectStates.set(descriptor.id, this._createManagedEffectState(descriptor));
1903
+ }
1904
+
1905
+ if (!this.nativeptr) {
1906
+ return;
1907
+ }
1908
+
1909
+ for (let i = 0; i < nextDescriptors.length; i++) {
1910
+ const descriptor = nextDescriptors[i];
1911
+ if (descriptor.enabled) {
1912
+ void this.preloadEffects([descriptor.id]);
1913
+ }
1914
+ }
1915
+ }
1916
+
1917
+ preloadEffects(ids) {
1918
+ const targetIds = this._resolveManagedEffectIds(ids, ids == null);
1919
+ return Promise.all(targetIds.map(async (id) => {
1920
+ const state = this._registeredEffectStates.get(id);
1921
+ if (!state) {
1922
+ return [id, null];
1923
+ }
1924
+ if (state.status === "loaded" && state.effect?.isLoaded) {
1925
+ return [id, state.effect];
1926
+ }
1927
+ if (state.status === "loading" && state.loadPromise) {
1928
+ return [id, await state.loadPromise];
1929
+ }
1930
+ return [id, await this._loadRegisteredEffectState(state)];
1931
+ })).then((entries) => new Map(entries));
1932
+ }
1933
+
1934
+ reloadEffects(ids) {
1935
+ const targetIds = this._resolveManagedEffectIds(ids, ids == null);
1936
+ this.unloadEffects(targetIds);
1937
+ return this.preloadEffects(targetIds);
1938
+ }
1939
+
1940
+ unloadEffects(ids) {
1941
+ const targetIds = this._resolveManagedEffectIds(ids);
1942
+ for (let i = 0; i < targetIds.length; i++) {
1943
+ const id = targetIds[i];
1944
+ const state = this._registeredEffectStates.get(id);
1945
+ if (!state) {
1946
+ continue;
1947
+ }
1948
+
1949
+ state._generation += 1;
1950
+ this._stopManagedHandles(state);
1951
+
1952
+ const loadingEffect = state._loadingEffect;
1953
+ if (loadingEffect) {
1954
+ this._releaseManagedEffectReference(loadingEffect, id);
1955
+ this._releaseManagedEffectIfUnused(loadingEffect);
1956
+ }
1957
+
1958
+ const loadedEffect = state.effect;
1959
+ if (loadedEffect) {
1960
+ this._releaseManagedEffectReference(loadedEffect, id);
1961
+ this._releaseManagedEffectIfUnused(loadedEffect);
1962
+ }
1963
+
1964
+ this._resetManagedEffectStateToUnloaded(state);
1965
+ }
1966
+ }
1967
+
1968
+ unregisterEffects(ids) {
1969
+ const targetIds = this._resolveManagedEffectIds(ids);
1970
+ this.unloadEffects(targetIds);
1971
+ for (let i = 0; i < targetIds.length; i++) {
1972
+ const id = targetIds[i];
1973
+ this._registeredEffects.delete(id);
1974
+ this._registeredEffectStates.delete(id);
1975
+ }
1976
+ }
1977
+
1978
+ getEffect(id) {
1979
+ const state = this._registeredEffectStates.get(String(id || ""));
1980
+ return (state?.status === "loaded" && state.effect?.isLoaded) ? state.effect : null;
1981
+ }
1982
+
1983
+ getEffectState(id) {
1984
+ return createManagedEffectSnapshot(this._registeredEffectStates.get(String(id || "")));
1985
+ }
1986
+
1987
+ getEffectStates() {
1988
+ return Array.from(this._registeredEffectStates.values(), (state) => createManagedEffectSnapshot(state));
1989
+ }
1990
+
1991
+ whenEffectsReady(ids) {
1992
+ return this.preloadEffects(ids);
1993
+ }
1994
+
1995
+ playEffect(id, x = 0, y = 0, z = 0) {
1996
+ const state = this._registeredEffectStates.get(String(id || ""));
1997
+ if (!state || state.status !== "loaded" || !state.effect?.isLoaded) {
1998
+ return null;
1999
+ }
2000
+
2001
+ const nextHandle = this.play(state.effect, x, y, z);
2002
+ if (nextHandle) {
2003
+ state.activeHandles.add(nextHandle);
2004
+ }
2005
+ return nextHandle;
2006
+ }
2007
+
2008
+ releaseEffect(effect) {
2009
+ if (!effect || !effect.nativeptr) {
2010
+ return;
2011
+ }
2012
+ clearCachedEffectReference(effect);
2013
+ Core.ReleaseEffect(this.nativeptr, effect.nativeptr);
2014
+ effect.nativeptr = 0;
2015
+ }
2016
+
2017
+ play(effect, x = 0, y = 0, z = 0) {
2018
+ if (!effect || !effect.isLoaded) {
2019
+ return null;
2020
+ }
2021
+ const handle = Core.PlayEffect(this.nativeptr, effect.nativeptr, x, y, z);
2022
+ return handle >= 0 ? new EffekseerHandle(this, handle) : null;
2023
+ }
2024
+
2025
+ stopAll() { Core.StopAllEffects(this.nativeptr); }
2026
+ setResourceLoader(loader) { loadResource = loader; }
2027
+ getRestInstancesCount() { return Core.GetRestInstancesCount(this.nativeptr); }
2028
+ getUpdateTime() { return Core.GetUpdateTime(this.nativeptr); }
2029
+ getDrawTime() { return Core.GetDrawTime(this.nativeptr); }
2030
+ getDrawFlushComputeTime() { return Core.GetDrawFlushComputeTime(this.nativeptr); }
2031
+ getDrawBeginFrameTime() { return Core.GetDrawBeginFrameTime(this.nativeptr); }
2032
+ getDrawManagerTime() { return Core.GetDrawManagerTime(this.nativeptr); }
2033
+ getDrawEndFrameTime() { return Core.GetDrawEndFrameTime(this.nativeptr); }
2034
+ getDrawTotalTime() { return Core.GetDrawTotalTime(this.nativeptr); }
2035
+ getGpuTimestampSupported() { return !!Core.GetGpuTimestampSupported(this.nativeptr); }
2036
+ getGpuTimestampValid() { return !!Core.GetGpuTimestampValid(this.nativeptr); }
2037
+ getGpuTimestampEffekseerPassTime() { return Core.GetGpuTimestampEffekseerPassTime(this.nativeptr); }
2038
+ getGpuTimestampFrameTime() { return Core.GetGpuTimestampFrameTime(this.nativeptr); }
2039
+ getGpuTimestampReadPending() { return !!Core.GetGpuTimestampReadPending(this.nativeptr); }
2040
+ getGpuTimestampLastMapStatus() { return Core.GetGpuTimestampLastMapStatus(this.nativeptr); }
2041
+ getGpuTimestampMapState() { return Core.GetGpuTimestampMapState(this.nativeptr); }
2042
+ getGpuTimestampMapMode() { return Core.GetGpuTimestampMapMode(this.nativeptr); }
2043
+ getGpuTimestampStallRecoveries() { return Core.GetGpuTimestampStallRecoveries(this.nativeptr); }
2044
+ getRendererProfileBindGroupTime() { return Core.GetRendererProfileBindGroupTime(this.nativeptr); }
2045
+ getRendererProfileBindGroupCacheFlushCount() { return Core.GetRendererProfileBindGroupCacheFlushCount(this.nativeptr); }
2046
+ getRendererProfileBindGroupCacheHits() { return Core.GetRendererProfileBindGroupCacheHits(this.nativeptr); }
2047
+ getRendererProfileBindGroupCacheMisses() { return Core.GetRendererProfileBindGroupCacheMisses(this.nativeptr); }
2048
+ getRendererProfileBindGroupCreates() { return Core.GetRendererProfileBindGroupCreates(this.nativeptr); }
2049
+ getRendererProfilePipelineTime() { return Core.GetRendererProfilePipelineTime(this.nativeptr); }
2050
+ getRendererProfileSetStateTime() { return Core.GetRendererProfileSetStateTime(this.nativeptr); }
2051
+ getRendererProfileIssueDrawTime() { return Core.GetRendererProfileIssueDrawTime(this.nativeptr); }
2052
+ getRendererProfileDrawTotalTime() { return Core.GetRendererProfileDrawTotalTime(this.nativeptr); }
2053
+ getRendererProfileDrawSpritesCalls() { return Core.GetRendererProfileDrawSpritesCalls(this.nativeptr); }
2054
+ getRendererProfileDrawPolygonCalls() { return Core.GetRendererProfileDrawPolygonCalls(this.nativeptr); }
2055
+ getInternalStandardRendererTextureSetupTime() { return Core.GetInternalStandardRendererTextureSetupTime(this.nativeptr); }
2056
+ getInternalStandardRendererShaderSelectTime() { return Core.GetInternalStandardRendererShaderSelectTime(this.nativeptr); }
2057
+ getInternalStandardRendererVertexPackTime() { return Core.GetInternalStandardRendererVertexPackTime(this.nativeptr); }
2058
+ getInternalStandardRendererPixelPackTime() { return Core.GetInternalStandardRendererPixelPackTime(this.nativeptr); }
2059
+ getInternalStandardRendererConstantUploadTime() { return Core.GetInternalStandardRendererConstantUploadTime(this.nativeptr); }
2060
+ getInternalStandardRendererRenderStateTime() { return Core.GetInternalStandardRendererRenderStateTime(this.nativeptr); }
2061
+ getInternalStandardRendererVertexBindTime() { return Core.GetInternalStandardRendererVertexBindTime(this.nativeptr); }
2062
+ getInternalStandardRendererIndexBindTime() { return Core.GetInternalStandardRendererIndexBindTime(this.nativeptr); }
2063
+ getInternalStandardRendererLayoutTime() { return Core.GetInternalStandardRendererLayoutTime(this.nativeptr); }
2064
+ getInternalStandardRendererDrawTime() { return Core.GetInternalStandardRendererDrawTime(this.nativeptr); }
2065
+ getManagerProfileFrustumTime() { return Core.GetManagerProfileFrustumTime(this.nativeptr); }
2066
+ getManagerProfileSortTime() { return Core.GetManagerProfileSortTime(this.nativeptr); }
2067
+ getManagerProfileCanDrawTime() { return Core.GetManagerProfileCanDrawTime(this.nativeptr); }
2068
+ getManagerProfileContainerDrawTime() { return Core.GetManagerProfileContainerDrawTime(this.nativeptr); }
2069
+ getManagerProfileGpuParticleTime() { return Core.GetManagerProfileGpuParticleTime(this.nativeptr); }
2070
+ getManagerProfileDrawSetCount() { return Core.GetManagerProfileDrawSetCount(this.nativeptr); }
2071
+ getManagerProfileVisibleDrawSetCount() { return Core.GetManagerProfileVisibleDrawSetCount(this.nativeptr); }
2072
+ getManagerProfileContainersTotal() { return Core.GetManagerProfileContainersTotal(this.nativeptr); }
2073
+ getManagerProfileContainersDrawn() { return Core.GetManagerProfileContainersDrawn(this.nativeptr); }
2074
+ getManagerProfileContainersDepthCulled() { return Core.GetManagerProfileContainersDepthCulled(this.nativeptr); }
2075
+ getDrawCallCount() { return Core.GetDrawCallCount(this.nativeptr); }
2076
+ getDrawVertexCount() { return Core.GetDrawVertexCount(this.nativeptr); }
2077
+ getTotalParticleCount() { return Core.GetTotalParticleCount(this.nativeptr); }
2078
+ isVertexArrayObjectSupported() { return !!Core.IsVertexArrayObjectSupported(this.nativeptr); }
2079
+ setRestorationOfStatesFlag(flag) { Core.SetRestorationOfStatesFlag(this.nativeptr, flag ? 1 : 0); }
2080
+ captureBackground(x, y, width, height) { Core.CaptureBackground(this.nativeptr, x, y, width, height); }
2081
+ resetBackground() { Core.ResetBackground(this.nativeptr); }
2082
+ }
2083
+
2084
+ class Effekseer {
2085
+ async initRuntime(path, onload, onerror) {
2086
+ try {
2087
+ await initializeRuntimeInternal(path);
2088
+ if (onload) {
2089
+ onload();
2090
+ }
2091
+ } catch (e) {
2092
+ runtimeInitializing = false;
2093
+ runtimeInitialized = false;
2094
+ onRuntimeReadyQueue = [];
2095
+ if (onerror) {
2096
+ onerror(e);
2097
+ } else {
2098
+ console.error(e);
2099
+ }
2100
+ }
2101
+ }
2102
+
2103
+ createContext() {
2104
+ if (!runtimeInitialized) {
2105
+ return null;
2106
+ }
2107
+ return new EffekseerContext();
2108
+ }
2109
+
2110
+ releaseContext(context) {
2111
+ if (!context || !context.nativeptr) {
2112
+ return;
2113
+ }
2114
+ context.unloadEffects?.();
2115
+ Core.Terminate(context.nativeptr);
2116
+ context.nativeptr = 0;
2117
+ context._effectCache?.clear?.();
2118
+ context._registeredEffects?.clear?.();
2119
+ context._registeredEffectStates?.clear?.();
2120
+ }
2121
+
2122
+ setLogEnabled(flag) {
2123
+ if (!runtimeInitialized) {
2124
+ return;
2125
+ }
2126
+ Core.SetLogEnabled(flag ? 1 : 0);
2127
+ }
2128
+
2129
+ setImageCrossOrigin(crossOrigin) {
2130
+ imageCrossOrigin = crossOrigin;
2131
+ void imageCrossOrigin;
2132
+ }
2133
+
2134
+ setWebGPUDevice(device) {
2135
+ if (runtimeInitialized || runtimeInitializing) {
2136
+ throw new Error("setWebGPUDevice() must be called before initRuntime().");
2137
+ }
2138
+ if (device == null) {
2139
+ externalWebGPUDevice = null;
2140
+ preinitializedDevice = null;
2141
+ return;
2142
+ }
2143
+ if (
2144
+ typeof device !== "object" ||
2145
+ typeof device.createCommandEncoder !== "function" ||
2146
+ !device.queue
2147
+ ) {
2148
+ throw new Error("setWebGPUDevice() expects a valid GPUDevice.");
2149
+ }
2150
+ externalWebGPUDevice = device;
2151
+ preinitializedDevice = device;
2152
+ }
2153
+
2154
+ setRendererWorkingColorSpace(colorSpaceApi) {
2155
+ return setRendererLinearWorkingColorSpace(colorSpaceApi);
2156
+ }
2157
+
2158
+ getWebGPUDevice() {
2159
+ return preinitializedDevice || (Module ? Module.preinitializedWebGPUDevice : null) || null;
2160
+ }
2161
+
2162
+ init(target, settings) {
2163
+ if (this.defaultContext?.nativeptr) {
2164
+ this.releaseContext(this.defaultContext);
2165
+ }
2166
+ this.defaultContext = new EffekseerContext();
2167
+ return this.defaultContext.init(target, settings);
2168
+ }
2169
+
2170
+ update(deltaFrames) { this.defaultContext.update(deltaFrames); }
2171
+ beginUpdate() { this.defaultContext.beginUpdate(); }
2172
+ endUpdate() { this.defaultContext.endUpdate(); }
2173
+ updateHandle(handle, deltaFrames) { this.defaultContext.updateHandle(handle, deltaFrames); }
2174
+ draw() { this.defaultContext.draw(); }
2175
+ drawExternal(renderPassEncoder, renderPassState, mode = "all") { this.defaultContext.drawExternal(renderPassEncoder, renderPassState, mode); }
2176
+ beginDraw() { this.defaultContext.beginDraw(); }
2177
+ endDraw() { this.defaultContext.endDraw(); }
2178
+ drawHandle(handle) { this.defaultContext.drawHandle(handle); }
2179
+ setProjectionMatrix(matrixArray) { this.defaultContext.setProjectionMatrix(matrixArray); }
2180
+ setProjectionPerspective(fov, aspect, near, far) { this.defaultContext.setProjectionPerspective(fov, aspect, near, far); }
2181
+ setProjectionOrthographic(width, height, near, far) { this.defaultContext.setProjectionOrthographic(width, height, near, far); }
2182
+ setCameraMatrix(matrixArray) { this.defaultContext.setCameraMatrix(matrixArray); }
2183
+ setCameraLookAt(positionX, positionY, positionZ, targetX, targetY, targetZ, upvecX, upvecY, upvecZ) {
2184
+ this.defaultContext.setCameraLookAt(positionX, positionY, positionZ, targetX, targetY, targetZ, upvecX, upvecY, upvecZ);
2185
+ }
2186
+ setCameraLookAtFromVector(position, target, upvec) { this.defaultContext.setCameraLookAtFromVector(position, target, upvec); }
2187
+ setCompositeMode(enabled) { this.defaultContext.setCompositeMode(enabled); }
2188
+ loadEffect(pathOrBuffer, scale, onload, onerror, redirect) { return this.defaultContext.loadEffect(pathOrBuffer, scale, onload, onerror, redirect); }
2189
+ loadEffectPackage(pathOrBuffer, Unzip, scale, onload, onerror) { return this.defaultContext.loadEffectPackage(pathOrBuffer, Unzip, scale, onload, onerror); }
2190
+ registerEffects(effects) { this.defaultContext.registerEffects(effects); }
2191
+ preloadEffects(ids) { return this.defaultContext.preloadEffects(ids); }
2192
+ reloadEffects(ids) { return this.defaultContext.reloadEffects(ids); }
2193
+ unloadEffects(ids) { this.defaultContext.unloadEffects(ids); }
2194
+ unregisterEffects(ids) { this.defaultContext.unregisterEffects(ids); }
2195
+ getEffect(id) { return this.defaultContext.getEffect(id); }
2196
+ getEffectState(id) { return this.defaultContext.getEffectState(id); }
2197
+ getEffectStates() { return this.defaultContext.getEffectStates(); }
2198
+ whenEffectsReady(ids) { return this.defaultContext.whenEffectsReady(ids); }
2199
+ playEffect(id, x, y, z) { return this.defaultContext.playEffect(id, x, y, z); }
2200
+ releaseEffect(effect) { this.defaultContext.releaseEffect(effect); }
2201
+ play(effect, x, y, z) { return this.defaultContext.play(effect, x, y, z); }
2202
+ stopAll() { this.defaultContext.stopAll(); }
2203
+ setResourceLoader(loader) { this.defaultContext.setResourceLoader(loader); }
2204
+ getRestInstancesCount() { return this.defaultContext.getRestInstancesCount(); }
2205
+ getUpdateTime() { return this.defaultContext.getUpdateTime(); }
2206
+ getDrawTime() { return this.defaultContext.getDrawTime(); }
2207
+ isVertexArrayObjectSupported() { return this.defaultContext.isVertexArrayObjectSupported(); }
2208
+ }
2209
+
2210
+ return new Effekseer();
2211
+ })();
2212
+
2213
+ if (typeof exports !== "undefined") {
2214
+ exports = effekseer;
2215
+ }