@ericchen1990/pano-view 2.2.2 → 2.3.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.
package/dist/index.mjs CHANGED
@@ -1,4 +1,2242 @@
1
1
  "use client";
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __commonJS = (cb, mod) => function __require() {
9
+ return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
10
+ };
11
+ var __copyProps = (to, from, except, desc) => {
12
+ if (from && typeof from === "object" || typeof from === "function") {
13
+ for (let key of __getOwnPropNames(from))
14
+ if (!__hasOwnProp.call(to, key) && key !== except)
15
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
16
+ }
17
+ return to;
18
+ };
19
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
20
+ // If the importer is in node compatibility mode or this is not an ESM
21
+ // file that has been converted to a CommonJS file using a Babel-
22
+ // compatible transform (i.e. "__esModule" has not been set), then set
23
+ // "default" to the CommonJS "module.exports" for node compatibility.
24
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
25
+ mod
26
+ ));
27
+
28
+ // ../../node_modules/.pnpm/howler@2.2.4/node_modules/howler/dist/howler.js
29
+ var require_howler = __commonJS({
30
+ "../../node_modules/.pnpm/howler@2.2.4/node_modules/howler/dist/howler.js"(exports) {
31
+ "use strict";
32
+ (function() {
33
+ "use strict";
34
+ var HowlerGlobal2 = function() {
35
+ this.init();
36
+ };
37
+ HowlerGlobal2.prototype = {
38
+ /**
39
+ * Initialize the global Howler object.
40
+ * @return {Howler}
41
+ */
42
+ init: function() {
43
+ var self = this || Howler3;
44
+ self._counter = 1e3;
45
+ self._html5AudioPool = [];
46
+ self.html5PoolSize = 10;
47
+ self._codecs = {};
48
+ self._howls = [];
49
+ self._muted = false;
50
+ self._volume = 1;
51
+ self._canPlayEvent = "canplaythrough";
52
+ self._navigator = typeof window !== "undefined" && window.navigator ? window.navigator : null;
53
+ self.masterGain = null;
54
+ self.noAudio = false;
55
+ self.usingWebAudio = true;
56
+ self.autoSuspend = true;
57
+ self.ctx = null;
58
+ self.autoUnlock = true;
59
+ self._setup();
60
+ return self;
61
+ },
62
+ /**
63
+ * Get/set the global volume for all sounds.
64
+ * @param {Float} vol Volume from 0.0 to 1.0.
65
+ * @return {Howler/Float} Returns self or current volume.
66
+ */
67
+ volume: function(vol) {
68
+ var self = this || Howler3;
69
+ vol = parseFloat(vol);
70
+ if (!self.ctx) {
71
+ setupAudioContext();
72
+ }
73
+ if (typeof vol !== "undefined" && vol >= 0 && vol <= 1) {
74
+ self._volume = vol;
75
+ if (self._muted) {
76
+ return self;
77
+ }
78
+ if (self.usingWebAudio) {
79
+ self.masterGain.gain.setValueAtTime(vol, Howler3.ctx.currentTime);
80
+ }
81
+ for (var i = 0; i < self._howls.length; i++) {
82
+ if (!self._howls[i]._webAudio) {
83
+ var ids = self._howls[i]._getSoundIds();
84
+ for (var j = 0; j < ids.length; j++) {
85
+ var sound = self._howls[i]._soundById(ids[j]);
86
+ if (sound && sound._node) {
87
+ sound._node.volume = sound._volume * vol;
88
+ }
89
+ }
90
+ }
91
+ }
92
+ return self;
93
+ }
94
+ return self._volume;
95
+ },
96
+ /**
97
+ * Handle muting and unmuting globally.
98
+ * @param {Boolean} muted Is muted or not.
99
+ */
100
+ mute: function(muted) {
101
+ var self = this || Howler3;
102
+ if (!self.ctx) {
103
+ setupAudioContext();
104
+ }
105
+ self._muted = muted;
106
+ if (self.usingWebAudio) {
107
+ self.masterGain.gain.setValueAtTime(muted ? 0 : self._volume, Howler3.ctx.currentTime);
108
+ }
109
+ for (var i = 0; i < self._howls.length; i++) {
110
+ if (!self._howls[i]._webAudio) {
111
+ var ids = self._howls[i]._getSoundIds();
112
+ for (var j = 0; j < ids.length; j++) {
113
+ var sound = self._howls[i]._soundById(ids[j]);
114
+ if (sound && sound._node) {
115
+ sound._node.muted = muted ? true : sound._muted;
116
+ }
117
+ }
118
+ }
119
+ }
120
+ return self;
121
+ },
122
+ /**
123
+ * Handle stopping all sounds globally.
124
+ */
125
+ stop: function() {
126
+ var self = this || Howler3;
127
+ for (var i = 0; i < self._howls.length; i++) {
128
+ self._howls[i].stop();
129
+ }
130
+ return self;
131
+ },
132
+ /**
133
+ * Unload and destroy all currently loaded Howl objects.
134
+ * @return {Howler}
135
+ */
136
+ unload: function() {
137
+ var self = this || Howler3;
138
+ for (var i = self._howls.length - 1; i >= 0; i--) {
139
+ self._howls[i].unload();
140
+ }
141
+ if (self.usingWebAudio && self.ctx && typeof self.ctx.close !== "undefined") {
142
+ self.ctx.close();
143
+ self.ctx = null;
144
+ setupAudioContext();
145
+ }
146
+ return self;
147
+ },
148
+ /**
149
+ * Check for codec support of specific extension.
150
+ * @param {String} ext Audio file extention.
151
+ * @return {Boolean}
152
+ */
153
+ codecs: function(ext) {
154
+ return (this || Howler3)._codecs[ext.replace(/^x-/, "")];
155
+ },
156
+ /**
157
+ * Setup various state values for global tracking.
158
+ * @return {Howler}
159
+ */
160
+ _setup: function() {
161
+ var self = this || Howler3;
162
+ self.state = self.ctx ? self.ctx.state || "suspended" : "suspended";
163
+ self._autoSuspend();
164
+ if (!self.usingWebAudio) {
165
+ if (typeof Audio !== "undefined") {
166
+ try {
167
+ var test = new Audio();
168
+ if (typeof test.oncanplaythrough === "undefined") {
169
+ self._canPlayEvent = "canplay";
170
+ }
171
+ } catch (e) {
172
+ self.noAudio = true;
173
+ }
174
+ } else {
175
+ self.noAudio = true;
176
+ }
177
+ }
178
+ try {
179
+ var test = new Audio();
180
+ if (test.muted) {
181
+ self.noAudio = true;
182
+ }
183
+ } catch (e) {
184
+ }
185
+ if (!self.noAudio) {
186
+ self._setupCodecs();
187
+ }
188
+ return self;
189
+ },
190
+ /**
191
+ * Check for browser support for various codecs and cache the results.
192
+ * @return {Howler}
193
+ */
194
+ _setupCodecs: function() {
195
+ var self = this || Howler3;
196
+ var audioTest = null;
197
+ try {
198
+ audioTest = typeof Audio !== "undefined" ? new Audio() : null;
199
+ } catch (err) {
200
+ return self;
201
+ }
202
+ if (!audioTest || typeof audioTest.canPlayType !== "function") {
203
+ return self;
204
+ }
205
+ var mpegTest = audioTest.canPlayType("audio/mpeg;").replace(/^no$/, "");
206
+ var ua = self._navigator ? self._navigator.userAgent : "";
207
+ var checkOpera = ua.match(/OPR\/(\d+)/g);
208
+ var isOldOpera = checkOpera && parseInt(checkOpera[0].split("/")[1], 10) < 33;
209
+ var checkSafari = ua.indexOf("Safari") !== -1 && ua.indexOf("Chrome") === -1;
210
+ var safariVersion = ua.match(/Version\/(.*?) /);
211
+ var isOldSafari = checkSafari && safariVersion && parseInt(safariVersion[1], 10) < 15;
212
+ self._codecs = {
213
+ mp3: !!(!isOldOpera && (mpegTest || audioTest.canPlayType("audio/mp3;").replace(/^no$/, ""))),
214
+ mpeg: !!mpegTest,
215
+ opus: !!audioTest.canPlayType('audio/ogg; codecs="opus"').replace(/^no$/, ""),
216
+ ogg: !!audioTest.canPlayType('audio/ogg; codecs="vorbis"').replace(/^no$/, ""),
217
+ oga: !!audioTest.canPlayType('audio/ogg; codecs="vorbis"').replace(/^no$/, ""),
218
+ wav: !!(audioTest.canPlayType('audio/wav; codecs="1"') || audioTest.canPlayType("audio/wav")).replace(/^no$/, ""),
219
+ aac: !!audioTest.canPlayType("audio/aac;").replace(/^no$/, ""),
220
+ caf: !!audioTest.canPlayType("audio/x-caf;").replace(/^no$/, ""),
221
+ m4a: !!(audioTest.canPlayType("audio/x-m4a;") || audioTest.canPlayType("audio/m4a;") || audioTest.canPlayType("audio/aac;")).replace(/^no$/, ""),
222
+ m4b: !!(audioTest.canPlayType("audio/x-m4b;") || audioTest.canPlayType("audio/m4b;") || audioTest.canPlayType("audio/aac;")).replace(/^no$/, ""),
223
+ mp4: !!(audioTest.canPlayType("audio/x-mp4;") || audioTest.canPlayType("audio/mp4;") || audioTest.canPlayType("audio/aac;")).replace(/^no$/, ""),
224
+ weba: !!(!isOldSafari && audioTest.canPlayType('audio/webm; codecs="vorbis"').replace(/^no$/, "")),
225
+ webm: !!(!isOldSafari && audioTest.canPlayType('audio/webm; codecs="vorbis"').replace(/^no$/, "")),
226
+ dolby: !!audioTest.canPlayType('audio/mp4; codecs="ec-3"').replace(/^no$/, ""),
227
+ flac: !!(audioTest.canPlayType("audio/x-flac;") || audioTest.canPlayType("audio/flac;")).replace(/^no$/, "")
228
+ };
229
+ return self;
230
+ },
231
+ /**
232
+ * Some browsers/devices will only allow audio to be played after a user interaction.
233
+ * Attempt to automatically unlock audio on the first user interaction.
234
+ * Concept from: http://paulbakaus.com/tutorials/html5/web-audio-on-ios/
235
+ * @return {Howler}
236
+ */
237
+ _unlockAudio: function() {
238
+ var self = this || Howler3;
239
+ if (self._audioUnlocked || !self.ctx) {
240
+ return;
241
+ }
242
+ self._audioUnlocked = false;
243
+ self.autoUnlock = false;
244
+ if (!self._mobileUnloaded && self.ctx.sampleRate !== 44100) {
245
+ self._mobileUnloaded = true;
246
+ self.unload();
247
+ }
248
+ self._scratchBuffer = self.ctx.createBuffer(1, 1, 22050);
249
+ var unlock = function(e) {
250
+ while (self._html5AudioPool.length < self.html5PoolSize) {
251
+ try {
252
+ var audioNode = new Audio();
253
+ audioNode._unlocked = true;
254
+ self._releaseHtml5Audio(audioNode);
255
+ } catch (e2) {
256
+ self.noAudio = true;
257
+ break;
258
+ }
259
+ }
260
+ for (var i = 0; i < self._howls.length; i++) {
261
+ if (!self._howls[i]._webAudio) {
262
+ var ids = self._howls[i]._getSoundIds();
263
+ for (var j = 0; j < ids.length; j++) {
264
+ var sound = self._howls[i]._soundById(ids[j]);
265
+ if (sound && sound._node && !sound._node._unlocked) {
266
+ sound._node._unlocked = true;
267
+ sound._node.load();
268
+ }
269
+ }
270
+ }
271
+ }
272
+ self._autoResume();
273
+ var source = self.ctx.createBufferSource();
274
+ source.buffer = self._scratchBuffer;
275
+ source.connect(self.ctx.destination);
276
+ if (typeof source.start === "undefined") {
277
+ source.noteOn(0);
278
+ } else {
279
+ source.start(0);
280
+ }
281
+ if (typeof self.ctx.resume === "function") {
282
+ self.ctx.resume();
283
+ }
284
+ source.onended = function() {
285
+ source.disconnect(0);
286
+ self._audioUnlocked = true;
287
+ document.removeEventListener("touchstart", unlock, true);
288
+ document.removeEventListener("touchend", unlock, true);
289
+ document.removeEventListener("click", unlock, true);
290
+ document.removeEventListener("keydown", unlock, true);
291
+ for (var i2 = 0; i2 < self._howls.length; i2++) {
292
+ self._howls[i2]._emit("unlock");
293
+ }
294
+ };
295
+ };
296
+ document.addEventListener("touchstart", unlock, true);
297
+ document.addEventListener("touchend", unlock, true);
298
+ document.addEventListener("click", unlock, true);
299
+ document.addEventListener("keydown", unlock, true);
300
+ return self;
301
+ },
302
+ /**
303
+ * Get an unlocked HTML5 Audio object from the pool. If none are left,
304
+ * return a new Audio object and throw a warning.
305
+ * @return {Audio} HTML5 Audio object.
306
+ */
307
+ _obtainHtml5Audio: function() {
308
+ var self = this || Howler3;
309
+ if (self._html5AudioPool.length) {
310
+ return self._html5AudioPool.pop();
311
+ }
312
+ var testPlay = new Audio().play();
313
+ if (testPlay && typeof Promise !== "undefined" && (testPlay instanceof Promise || typeof testPlay.then === "function")) {
314
+ testPlay.catch(function() {
315
+ console.warn("HTML5 Audio pool exhausted, returning potentially locked audio object.");
316
+ });
317
+ }
318
+ return new Audio();
319
+ },
320
+ /**
321
+ * Return an activated HTML5 Audio object to the pool.
322
+ * @return {Howler}
323
+ */
324
+ _releaseHtml5Audio: function(audio) {
325
+ var self = this || Howler3;
326
+ if (audio._unlocked) {
327
+ self._html5AudioPool.push(audio);
328
+ }
329
+ return self;
330
+ },
331
+ /**
332
+ * Automatically suspend the Web Audio AudioContext after no sound has played for 30 seconds.
333
+ * This saves processing/energy and fixes various browser-specific bugs with audio getting stuck.
334
+ * @return {Howler}
335
+ */
336
+ _autoSuspend: function() {
337
+ var self = this;
338
+ if (!self.autoSuspend || !self.ctx || typeof self.ctx.suspend === "undefined" || !Howler3.usingWebAudio) {
339
+ return;
340
+ }
341
+ for (var i = 0; i < self._howls.length; i++) {
342
+ if (self._howls[i]._webAudio) {
343
+ for (var j = 0; j < self._howls[i]._sounds.length; j++) {
344
+ if (!self._howls[i]._sounds[j]._paused) {
345
+ return self;
346
+ }
347
+ }
348
+ }
349
+ }
350
+ if (self._suspendTimer) {
351
+ clearTimeout(self._suspendTimer);
352
+ }
353
+ self._suspendTimer = setTimeout(function() {
354
+ if (!self.autoSuspend) {
355
+ return;
356
+ }
357
+ self._suspendTimer = null;
358
+ self.state = "suspending";
359
+ var handleSuspension = function() {
360
+ self.state = "suspended";
361
+ if (self._resumeAfterSuspend) {
362
+ delete self._resumeAfterSuspend;
363
+ self._autoResume();
364
+ }
365
+ };
366
+ self.ctx.suspend().then(handleSuspension, handleSuspension);
367
+ }, 3e4);
368
+ return self;
369
+ },
370
+ /**
371
+ * Automatically resume the Web Audio AudioContext when a new sound is played.
372
+ * @return {Howler}
373
+ */
374
+ _autoResume: function() {
375
+ var self = this;
376
+ if (!self.ctx || typeof self.ctx.resume === "undefined" || !Howler3.usingWebAudio) {
377
+ return;
378
+ }
379
+ if (self.state === "running" && self.ctx.state !== "interrupted" && self._suspendTimer) {
380
+ clearTimeout(self._suspendTimer);
381
+ self._suspendTimer = null;
382
+ } else if (self.state === "suspended" || self.state === "running" && self.ctx.state === "interrupted") {
383
+ self.ctx.resume().then(function() {
384
+ self.state = "running";
385
+ for (var i = 0; i < self._howls.length; i++) {
386
+ self._howls[i]._emit("resume");
387
+ }
388
+ });
389
+ if (self._suspendTimer) {
390
+ clearTimeout(self._suspendTimer);
391
+ self._suspendTimer = null;
392
+ }
393
+ } else if (self.state === "suspending") {
394
+ self._resumeAfterSuspend = true;
395
+ }
396
+ return self;
397
+ }
398
+ };
399
+ var Howler3 = new HowlerGlobal2();
400
+ var Howl3 = function(o) {
401
+ var self = this;
402
+ if (!o.src || o.src.length === 0) {
403
+ console.error("An array of source files must be passed with any new Howl.");
404
+ return;
405
+ }
406
+ self.init(o);
407
+ };
408
+ Howl3.prototype = {
409
+ /**
410
+ * Initialize a new Howl group object.
411
+ * @param {Object} o Passed in properties for this group.
412
+ * @return {Howl}
413
+ */
414
+ init: function(o) {
415
+ var self = this;
416
+ if (!Howler3.ctx) {
417
+ setupAudioContext();
418
+ }
419
+ self._autoplay = o.autoplay || false;
420
+ self._format = typeof o.format !== "string" ? o.format : [o.format];
421
+ self._html5 = o.html5 || false;
422
+ self._muted = o.mute || false;
423
+ self._loop = o.loop || false;
424
+ self._pool = o.pool || 5;
425
+ self._preload = typeof o.preload === "boolean" || o.preload === "metadata" ? o.preload : true;
426
+ self._rate = o.rate || 1;
427
+ self._sprite = o.sprite || {};
428
+ self._src = typeof o.src !== "string" ? o.src : [o.src];
429
+ self._volume = o.volume !== void 0 ? o.volume : 1;
430
+ self._xhr = {
431
+ method: o.xhr && o.xhr.method ? o.xhr.method : "GET",
432
+ headers: o.xhr && o.xhr.headers ? o.xhr.headers : null,
433
+ withCredentials: o.xhr && o.xhr.withCredentials ? o.xhr.withCredentials : false
434
+ };
435
+ self._duration = 0;
436
+ self._state = "unloaded";
437
+ self._sounds = [];
438
+ self._endTimers = {};
439
+ self._queue = [];
440
+ self._playLock = false;
441
+ self._onend = o.onend ? [{ fn: o.onend }] : [];
442
+ self._onfade = o.onfade ? [{ fn: o.onfade }] : [];
443
+ self._onload = o.onload ? [{ fn: o.onload }] : [];
444
+ self._onloaderror = o.onloaderror ? [{ fn: o.onloaderror }] : [];
445
+ self._onplayerror = o.onplayerror ? [{ fn: o.onplayerror }] : [];
446
+ self._onpause = o.onpause ? [{ fn: o.onpause }] : [];
447
+ self._onplay = o.onplay ? [{ fn: o.onplay }] : [];
448
+ self._onstop = o.onstop ? [{ fn: o.onstop }] : [];
449
+ self._onmute = o.onmute ? [{ fn: o.onmute }] : [];
450
+ self._onvolume = o.onvolume ? [{ fn: o.onvolume }] : [];
451
+ self._onrate = o.onrate ? [{ fn: o.onrate }] : [];
452
+ self._onseek = o.onseek ? [{ fn: o.onseek }] : [];
453
+ self._onunlock = o.onunlock ? [{ fn: o.onunlock }] : [];
454
+ self._onresume = [];
455
+ self._webAudio = Howler3.usingWebAudio && !self._html5;
456
+ if (typeof Howler3.ctx !== "undefined" && Howler3.ctx && Howler3.autoUnlock) {
457
+ Howler3._unlockAudio();
458
+ }
459
+ Howler3._howls.push(self);
460
+ if (self._autoplay) {
461
+ self._queue.push({
462
+ event: "play",
463
+ action: function() {
464
+ self.play();
465
+ }
466
+ });
467
+ }
468
+ if (self._preload && self._preload !== "none") {
469
+ self.load();
470
+ }
471
+ return self;
472
+ },
473
+ /**
474
+ * Load the audio file.
475
+ * @return {Howler}
476
+ */
477
+ load: function() {
478
+ var self = this;
479
+ var url = null;
480
+ if (Howler3.noAudio) {
481
+ self._emit("loaderror", null, "No audio support.");
482
+ return;
483
+ }
484
+ if (typeof self._src === "string") {
485
+ self._src = [self._src];
486
+ }
487
+ for (var i = 0; i < self._src.length; i++) {
488
+ var ext, str;
489
+ if (self._format && self._format[i]) {
490
+ ext = self._format[i];
491
+ } else {
492
+ str = self._src[i];
493
+ if (typeof str !== "string") {
494
+ self._emit("loaderror", null, "Non-string found in selected audio sources - ignoring.");
495
+ continue;
496
+ }
497
+ ext = /^data:audio\/([^;,]+);/i.exec(str);
498
+ if (!ext) {
499
+ ext = /\.([^.]+)$/.exec(str.split("?", 1)[0]);
500
+ }
501
+ if (ext) {
502
+ ext = ext[1].toLowerCase();
503
+ }
504
+ }
505
+ if (!ext) {
506
+ console.warn('No file extension was found. Consider using the "format" property or specify an extension.');
507
+ }
508
+ if (ext && Howler3.codecs(ext)) {
509
+ url = self._src[i];
510
+ break;
511
+ }
512
+ }
513
+ if (!url) {
514
+ self._emit("loaderror", null, "No codec support for selected audio sources.");
515
+ return;
516
+ }
517
+ self._src = url;
518
+ self._state = "loading";
519
+ if (window.location.protocol === "https:" && url.slice(0, 5) === "http:") {
520
+ self._html5 = true;
521
+ self._webAudio = false;
522
+ }
523
+ new Sound2(self);
524
+ if (self._webAudio) {
525
+ loadBuffer(self);
526
+ }
527
+ return self;
528
+ },
529
+ /**
530
+ * Play a sound or resume previous playback.
531
+ * @param {String/Number} sprite Sprite name for sprite playback or sound id to continue previous.
532
+ * @param {Boolean} internal Internal Use: true prevents event firing.
533
+ * @return {Number} Sound ID.
534
+ */
535
+ play: function(sprite, internal) {
536
+ var self = this;
537
+ var id = null;
538
+ if (typeof sprite === "number") {
539
+ id = sprite;
540
+ sprite = null;
541
+ } else if (typeof sprite === "string" && self._state === "loaded" && !self._sprite[sprite]) {
542
+ return null;
543
+ } else if (typeof sprite === "undefined") {
544
+ sprite = "__default";
545
+ if (!self._playLock) {
546
+ var num = 0;
547
+ for (var i = 0; i < self._sounds.length; i++) {
548
+ if (self._sounds[i]._paused && !self._sounds[i]._ended) {
549
+ num++;
550
+ id = self._sounds[i]._id;
551
+ }
552
+ }
553
+ if (num === 1) {
554
+ sprite = null;
555
+ } else {
556
+ id = null;
557
+ }
558
+ }
559
+ }
560
+ var sound = id ? self._soundById(id) : self._inactiveSound();
561
+ if (!sound) {
562
+ return null;
563
+ }
564
+ if (id && !sprite) {
565
+ sprite = sound._sprite || "__default";
566
+ }
567
+ if (self._state !== "loaded") {
568
+ sound._sprite = sprite;
569
+ sound._ended = false;
570
+ var soundId = sound._id;
571
+ self._queue.push({
572
+ event: "play",
573
+ action: function() {
574
+ self.play(soundId);
575
+ }
576
+ });
577
+ return soundId;
578
+ }
579
+ if (id && !sound._paused) {
580
+ if (!internal) {
581
+ self._loadQueue("play");
582
+ }
583
+ return sound._id;
584
+ }
585
+ if (self._webAudio) {
586
+ Howler3._autoResume();
587
+ }
588
+ var seek = Math.max(0, sound._seek > 0 ? sound._seek : self._sprite[sprite][0] / 1e3);
589
+ var duration = Math.max(0, (self._sprite[sprite][0] + self._sprite[sprite][1]) / 1e3 - seek);
590
+ var timeout = duration * 1e3 / Math.abs(sound._rate);
591
+ var start = self._sprite[sprite][0] / 1e3;
592
+ var stop = (self._sprite[sprite][0] + self._sprite[sprite][1]) / 1e3;
593
+ sound._sprite = sprite;
594
+ sound._ended = false;
595
+ var setParams = function() {
596
+ sound._paused = false;
597
+ sound._seek = seek;
598
+ sound._start = start;
599
+ sound._stop = stop;
600
+ sound._loop = !!(sound._loop || self._sprite[sprite][2]);
601
+ };
602
+ if (seek >= stop) {
603
+ self._ended(sound);
604
+ return;
605
+ }
606
+ var node = sound._node;
607
+ if (self._webAudio) {
608
+ var playWebAudio = function() {
609
+ self._playLock = false;
610
+ setParams();
611
+ self._refreshBuffer(sound);
612
+ var vol = sound._muted || self._muted ? 0 : sound._volume;
613
+ node.gain.setValueAtTime(vol, Howler3.ctx.currentTime);
614
+ sound._playStart = Howler3.ctx.currentTime;
615
+ if (typeof node.bufferSource.start === "undefined") {
616
+ sound._loop ? node.bufferSource.noteGrainOn(0, seek, 86400) : node.bufferSource.noteGrainOn(0, seek, duration);
617
+ } else {
618
+ sound._loop ? node.bufferSource.start(0, seek, 86400) : node.bufferSource.start(0, seek, duration);
619
+ }
620
+ if (timeout !== Infinity) {
621
+ self._endTimers[sound._id] = setTimeout(self._ended.bind(self, sound), timeout);
622
+ }
623
+ if (!internal) {
624
+ setTimeout(function() {
625
+ self._emit("play", sound._id);
626
+ self._loadQueue();
627
+ }, 0);
628
+ }
629
+ };
630
+ if (Howler3.state === "running" && Howler3.ctx.state !== "interrupted") {
631
+ playWebAudio();
632
+ } else {
633
+ self._playLock = true;
634
+ self.once("resume", playWebAudio);
635
+ self._clearTimer(sound._id);
636
+ }
637
+ } else {
638
+ var playHtml5 = function() {
639
+ node.currentTime = seek;
640
+ node.muted = sound._muted || self._muted || Howler3._muted || node.muted;
641
+ node.volume = sound._volume * Howler3.volume();
642
+ node.playbackRate = sound._rate;
643
+ try {
644
+ var play = node.play();
645
+ if (play && typeof Promise !== "undefined" && (play instanceof Promise || typeof play.then === "function")) {
646
+ self._playLock = true;
647
+ setParams();
648
+ play.then(function() {
649
+ self._playLock = false;
650
+ node._unlocked = true;
651
+ if (!internal) {
652
+ self._emit("play", sound._id);
653
+ } else {
654
+ self._loadQueue();
655
+ }
656
+ }).catch(function() {
657
+ self._playLock = false;
658
+ self._emit("playerror", sound._id, "Playback was unable to start. This is most commonly an issue on mobile devices and Chrome where playback was not within a user interaction.");
659
+ sound._ended = true;
660
+ sound._paused = true;
661
+ });
662
+ } else if (!internal) {
663
+ self._playLock = false;
664
+ setParams();
665
+ self._emit("play", sound._id);
666
+ }
667
+ node.playbackRate = sound._rate;
668
+ if (node.paused) {
669
+ self._emit("playerror", sound._id, "Playback was unable to start. This is most commonly an issue on mobile devices and Chrome where playback was not within a user interaction.");
670
+ return;
671
+ }
672
+ if (sprite !== "__default" || sound._loop) {
673
+ self._endTimers[sound._id] = setTimeout(self._ended.bind(self, sound), timeout);
674
+ } else {
675
+ self._endTimers[sound._id] = function() {
676
+ self._ended(sound);
677
+ node.removeEventListener("ended", self._endTimers[sound._id], false);
678
+ };
679
+ node.addEventListener("ended", self._endTimers[sound._id], false);
680
+ }
681
+ } catch (err) {
682
+ self._emit("playerror", sound._id, err);
683
+ }
684
+ };
685
+ if (node.src === "data:audio/wav;base64,UklGRigAAABXQVZFZm10IBIAAAABAAEARKwAAIhYAQACABAAAABkYXRhAgAAAAEA") {
686
+ node.src = self._src;
687
+ node.load();
688
+ }
689
+ var loadedNoReadyState = window && window.ejecta || !node.readyState && Howler3._navigator.isCocoonJS;
690
+ if (node.readyState >= 3 || loadedNoReadyState) {
691
+ playHtml5();
692
+ } else {
693
+ self._playLock = true;
694
+ self._state = "loading";
695
+ var listener = function() {
696
+ self._state = "loaded";
697
+ playHtml5();
698
+ node.removeEventListener(Howler3._canPlayEvent, listener, false);
699
+ };
700
+ node.addEventListener(Howler3._canPlayEvent, listener, false);
701
+ self._clearTimer(sound._id);
702
+ }
703
+ }
704
+ return sound._id;
705
+ },
706
+ /**
707
+ * Pause playback and save current position.
708
+ * @param {Number} id The sound ID (empty to pause all in group).
709
+ * @return {Howl}
710
+ */
711
+ pause: function(id) {
712
+ var self = this;
713
+ if (self._state !== "loaded" || self._playLock) {
714
+ self._queue.push({
715
+ event: "pause",
716
+ action: function() {
717
+ self.pause(id);
718
+ }
719
+ });
720
+ return self;
721
+ }
722
+ var ids = self._getSoundIds(id);
723
+ for (var i = 0; i < ids.length; i++) {
724
+ self._clearTimer(ids[i]);
725
+ var sound = self._soundById(ids[i]);
726
+ if (sound && !sound._paused) {
727
+ sound._seek = self.seek(ids[i]);
728
+ sound._rateSeek = 0;
729
+ sound._paused = true;
730
+ self._stopFade(ids[i]);
731
+ if (sound._node) {
732
+ if (self._webAudio) {
733
+ if (!sound._node.bufferSource) {
734
+ continue;
735
+ }
736
+ if (typeof sound._node.bufferSource.stop === "undefined") {
737
+ sound._node.bufferSource.noteOff(0);
738
+ } else {
739
+ sound._node.bufferSource.stop(0);
740
+ }
741
+ self._cleanBuffer(sound._node);
742
+ } else if (!isNaN(sound._node.duration) || sound._node.duration === Infinity) {
743
+ sound._node.pause();
744
+ }
745
+ }
746
+ }
747
+ if (!arguments[1]) {
748
+ self._emit("pause", sound ? sound._id : null);
749
+ }
750
+ }
751
+ return self;
752
+ },
753
+ /**
754
+ * Stop playback and reset to start.
755
+ * @param {Number} id The sound ID (empty to stop all in group).
756
+ * @param {Boolean} internal Internal Use: true prevents event firing.
757
+ * @return {Howl}
758
+ */
759
+ stop: function(id, internal) {
760
+ var self = this;
761
+ if (self._state !== "loaded" || self._playLock) {
762
+ self._queue.push({
763
+ event: "stop",
764
+ action: function() {
765
+ self.stop(id);
766
+ }
767
+ });
768
+ return self;
769
+ }
770
+ var ids = self._getSoundIds(id);
771
+ for (var i = 0; i < ids.length; i++) {
772
+ self._clearTimer(ids[i]);
773
+ var sound = self._soundById(ids[i]);
774
+ if (sound) {
775
+ sound._seek = sound._start || 0;
776
+ sound._rateSeek = 0;
777
+ sound._paused = true;
778
+ sound._ended = true;
779
+ self._stopFade(ids[i]);
780
+ if (sound._node) {
781
+ if (self._webAudio) {
782
+ if (sound._node.bufferSource) {
783
+ if (typeof sound._node.bufferSource.stop === "undefined") {
784
+ sound._node.bufferSource.noteOff(0);
785
+ } else {
786
+ sound._node.bufferSource.stop(0);
787
+ }
788
+ self._cleanBuffer(sound._node);
789
+ }
790
+ } else if (!isNaN(sound._node.duration) || sound._node.duration === Infinity) {
791
+ sound._node.currentTime = sound._start || 0;
792
+ sound._node.pause();
793
+ if (sound._node.duration === Infinity) {
794
+ self._clearSound(sound._node);
795
+ }
796
+ }
797
+ }
798
+ if (!internal) {
799
+ self._emit("stop", sound._id);
800
+ }
801
+ }
802
+ }
803
+ return self;
804
+ },
805
+ /**
806
+ * Mute/unmute a single sound or all sounds in this Howl group.
807
+ * @param {Boolean} muted Set to true to mute and false to unmute.
808
+ * @param {Number} id The sound ID to update (omit to mute/unmute all).
809
+ * @return {Howl}
810
+ */
811
+ mute: function(muted, id) {
812
+ var self = this;
813
+ if (self._state !== "loaded" || self._playLock) {
814
+ self._queue.push({
815
+ event: "mute",
816
+ action: function() {
817
+ self.mute(muted, id);
818
+ }
819
+ });
820
+ return self;
821
+ }
822
+ if (typeof id === "undefined") {
823
+ if (typeof muted === "boolean") {
824
+ self._muted = muted;
825
+ } else {
826
+ return self._muted;
827
+ }
828
+ }
829
+ var ids = self._getSoundIds(id);
830
+ for (var i = 0; i < ids.length; i++) {
831
+ var sound = self._soundById(ids[i]);
832
+ if (sound) {
833
+ sound._muted = muted;
834
+ if (sound._interval) {
835
+ self._stopFade(sound._id);
836
+ }
837
+ if (self._webAudio && sound._node) {
838
+ sound._node.gain.setValueAtTime(muted ? 0 : sound._volume, Howler3.ctx.currentTime);
839
+ } else if (sound._node) {
840
+ sound._node.muted = Howler3._muted ? true : muted;
841
+ }
842
+ self._emit("mute", sound._id);
843
+ }
844
+ }
845
+ return self;
846
+ },
847
+ /**
848
+ * Get/set the volume of this sound or of the Howl group. This method can optionally take 0, 1 or 2 arguments.
849
+ * volume() -> Returns the group's volume value.
850
+ * volume(id) -> Returns the sound id's current volume.
851
+ * volume(vol) -> Sets the volume of all sounds in this Howl group.
852
+ * volume(vol, id) -> Sets the volume of passed sound id.
853
+ * @return {Howl/Number} Returns self or current volume.
854
+ */
855
+ volume: function() {
856
+ var self = this;
857
+ var args = arguments;
858
+ var vol, id;
859
+ if (args.length === 0) {
860
+ return self._volume;
861
+ } else if (args.length === 1 || args.length === 2 && typeof args[1] === "undefined") {
862
+ var ids = self._getSoundIds();
863
+ var index = ids.indexOf(args[0]);
864
+ if (index >= 0) {
865
+ id = parseInt(args[0], 10);
866
+ } else {
867
+ vol = parseFloat(args[0]);
868
+ }
869
+ } else if (args.length >= 2) {
870
+ vol = parseFloat(args[0]);
871
+ id = parseInt(args[1], 10);
872
+ }
873
+ var sound;
874
+ if (typeof vol !== "undefined" && vol >= 0 && vol <= 1) {
875
+ if (self._state !== "loaded" || self._playLock) {
876
+ self._queue.push({
877
+ event: "volume",
878
+ action: function() {
879
+ self.volume.apply(self, args);
880
+ }
881
+ });
882
+ return self;
883
+ }
884
+ if (typeof id === "undefined") {
885
+ self._volume = vol;
886
+ }
887
+ id = self._getSoundIds(id);
888
+ for (var i = 0; i < id.length; i++) {
889
+ sound = self._soundById(id[i]);
890
+ if (sound) {
891
+ sound._volume = vol;
892
+ if (!args[2]) {
893
+ self._stopFade(id[i]);
894
+ }
895
+ if (self._webAudio && sound._node && !sound._muted) {
896
+ sound._node.gain.setValueAtTime(vol, Howler3.ctx.currentTime);
897
+ } else if (sound._node && !sound._muted) {
898
+ sound._node.volume = vol * Howler3.volume();
899
+ }
900
+ self._emit("volume", sound._id);
901
+ }
902
+ }
903
+ } else {
904
+ sound = id ? self._soundById(id) : self._sounds[0];
905
+ return sound ? sound._volume : 0;
906
+ }
907
+ return self;
908
+ },
909
+ /**
910
+ * Fade a currently playing sound between two volumes (if no id is passed, all sounds will fade).
911
+ * @param {Number} from The value to fade from (0.0 to 1.0).
912
+ * @param {Number} to The volume to fade to (0.0 to 1.0).
913
+ * @param {Number} len Time in milliseconds to fade.
914
+ * @param {Number} id The sound id (omit to fade all sounds).
915
+ * @return {Howl}
916
+ */
917
+ fade: function(from, to, len, id) {
918
+ var self = this;
919
+ if (self._state !== "loaded" || self._playLock) {
920
+ self._queue.push({
921
+ event: "fade",
922
+ action: function() {
923
+ self.fade(from, to, len, id);
924
+ }
925
+ });
926
+ return self;
927
+ }
928
+ from = Math.min(Math.max(0, parseFloat(from)), 1);
929
+ to = Math.min(Math.max(0, parseFloat(to)), 1);
930
+ len = parseFloat(len);
931
+ self.volume(from, id);
932
+ var ids = self._getSoundIds(id);
933
+ for (var i = 0; i < ids.length; i++) {
934
+ var sound = self._soundById(ids[i]);
935
+ if (sound) {
936
+ if (!id) {
937
+ self._stopFade(ids[i]);
938
+ }
939
+ if (self._webAudio && !sound._muted) {
940
+ var currentTime = Howler3.ctx.currentTime;
941
+ var end = currentTime + len / 1e3;
942
+ sound._volume = from;
943
+ sound._node.gain.setValueAtTime(from, currentTime);
944
+ sound._node.gain.linearRampToValueAtTime(to, end);
945
+ }
946
+ self._startFadeInterval(sound, from, to, len, ids[i], typeof id === "undefined");
947
+ }
948
+ }
949
+ return self;
950
+ },
951
+ /**
952
+ * Starts the internal interval to fade a sound.
953
+ * @param {Object} sound Reference to sound to fade.
954
+ * @param {Number} from The value to fade from (0.0 to 1.0).
955
+ * @param {Number} to The volume to fade to (0.0 to 1.0).
956
+ * @param {Number} len Time in milliseconds to fade.
957
+ * @param {Number} id The sound id to fade.
958
+ * @param {Boolean} isGroup If true, set the volume on the group.
959
+ */
960
+ _startFadeInterval: function(sound, from, to, len, id, isGroup) {
961
+ var self = this;
962
+ var vol = from;
963
+ var diff = to - from;
964
+ var steps = Math.abs(diff / 0.01);
965
+ var stepLen = Math.max(4, steps > 0 ? len / steps : len);
966
+ var lastTick = Date.now();
967
+ sound._fadeTo = to;
968
+ sound._interval = setInterval(function() {
969
+ var tick = (Date.now() - lastTick) / len;
970
+ lastTick = Date.now();
971
+ vol += diff * tick;
972
+ vol = Math.round(vol * 100) / 100;
973
+ if (diff < 0) {
974
+ vol = Math.max(to, vol);
975
+ } else {
976
+ vol = Math.min(to, vol);
977
+ }
978
+ if (self._webAudio) {
979
+ sound._volume = vol;
980
+ } else {
981
+ self.volume(vol, sound._id, true);
982
+ }
983
+ if (isGroup) {
984
+ self._volume = vol;
985
+ }
986
+ if (to < from && vol <= to || to > from && vol >= to) {
987
+ clearInterval(sound._interval);
988
+ sound._interval = null;
989
+ sound._fadeTo = null;
990
+ self.volume(to, sound._id);
991
+ self._emit("fade", sound._id);
992
+ }
993
+ }, stepLen);
994
+ },
995
+ /**
996
+ * Internal method that stops the currently playing fade when
997
+ * a new fade starts, volume is changed or the sound is stopped.
998
+ * @param {Number} id The sound id.
999
+ * @return {Howl}
1000
+ */
1001
+ _stopFade: function(id) {
1002
+ var self = this;
1003
+ var sound = self._soundById(id);
1004
+ if (sound && sound._interval) {
1005
+ if (self._webAudio) {
1006
+ sound._node.gain.cancelScheduledValues(Howler3.ctx.currentTime);
1007
+ }
1008
+ clearInterval(sound._interval);
1009
+ sound._interval = null;
1010
+ self.volume(sound._fadeTo, id);
1011
+ sound._fadeTo = null;
1012
+ self._emit("fade", id);
1013
+ }
1014
+ return self;
1015
+ },
1016
+ /**
1017
+ * Get/set the loop parameter on a sound. This method can optionally take 0, 1 or 2 arguments.
1018
+ * loop() -> Returns the group's loop value.
1019
+ * loop(id) -> Returns the sound id's loop value.
1020
+ * loop(loop) -> Sets the loop value for all sounds in this Howl group.
1021
+ * loop(loop, id) -> Sets the loop value of passed sound id.
1022
+ * @return {Howl/Boolean} Returns self or current loop value.
1023
+ */
1024
+ loop: function() {
1025
+ var self = this;
1026
+ var args = arguments;
1027
+ var loop, id, sound;
1028
+ if (args.length === 0) {
1029
+ return self._loop;
1030
+ } else if (args.length === 1) {
1031
+ if (typeof args[0] === "boolean") {
1032
+ loop = args[0];
1033
+ self._loop = loop;
1034
+ } else {
1035
+ sound = self._soundById(parseInt(args[0], 10));
1036
+ return sound ? sound._loop : false;
1037
+ }
1038
+ } else if (args.length === 2) {
1039
+ loop = args[0];
1040
+ id = parseInt(args[1], 10);
1041
+ }
1042
+ var ids = self._getSoundIds(id);
1043
+ for (var i = 0; i < ids.length; i++) {
1044
+ sound = self._soundById(ids[i]);
1045
+ if (sound) {
1046
+ sound._loop = loop;
1047
+ if (self._webAudio && sound._node && sound._node.bufferSource) {
1048
+ sound._node.bufferSource.loop = loop;
1049
+ if (loop) {
1050
+ sound._node.bufferSource.loopStart = sound._start || 0;
1051
+ sound._node.bufferSource.loopEnd = sound._stop;
1052
+ if (self.playing(ids[i])) {
1053
+ self.pause(ids[i], true);
1054
+ self.play(ids[i], true);
1055
+ }
1056
+ }
1057
+ }
1058
+ }
1059
+ }
1060
+ return self;
1061
+ },
1062
+ /**
1063
+ * Get/set the playback rate of a sound. This method can optionally take 0, 1 or 2 arguments.
1064
+ * rate() -> Returns the first sound node's current playback rate.
1065
+ * rate(id) -> Returns the sound id's current playback rate.
1066
+ * rate(rate) -> Sets the playback rate of all sounds in this Howl group.
1067
+ * rate(rate, id) -> Sets the playback rate of passed sound id.
1068
+ * @return {Howl/Number} Returns self or the current playback rate.
1069
+ */
1070
+ rate: function() {
1071
+ var self = this;
1072
+ var args = arguments;
1073
+ var rate, id;
1074
+ if (args.length === 0) {
1075
+ id = self._sounds[0]._id;
1076
+ } else if (args.length === 1) {
1077
+ var ids = self._getSoundIds();
1078
+ var index = ids.indexOf(args[0]);
1079
+ if (index >= 0) {
1080
+ id = parseInt(args[0], 10);
1081
+ } else {
1082
+ rate = parseFloat(args[0]);
1083
+ }
1084
+ } else if (args.length === 2) {
1085
+ rate = parseFloat(args[0]);
1086
+ id = parseInt(args[1], 10);
1087
+ }
1088
+ var sound;
1089
+ if (typeof rate === "number") {
1090
+ if (self._state !== "loaded" || self._playLock) {
1091
+ self._queue.push({
1092
+ event: "rate",
1093
+ action: function() {
1094
+ self.rate.apply(self, args);
1095
+ }
1096
+ });
1097
+ return self;
1098
+ }
1099
+ if (typeof id === "undefined") {
1100
+ self._rate = rate;
1101
+ }
1102
+ id = self._getSoundIds(id);
1103
+ for (var i = 0; i < id.length; i++) {
1104
+ sound = self._soundById(id[i]);
1105
+ if (sound) {
1106
+ if (self.playing(id[i])) {
1107
+ sound._rateSeek = self.seek(id[i]);
1108
+ sound._playStart = self._webAudio ? Howler3.ctx.currentTime : sound._playStart;
1109
+ }
1110
+ sound._rate = rate;
1111
+ if (self._webAudio && sound._node && sound._node.bufferSource) {
1112
+ sound._node.bufferSource.playbackRate.setValueAtTime(rate, Howler3.ctx.currentTime);
1113
+ } else if (sound._node) {
1114
+ sound._node.playbackRate = rate;
1115
+ }
1116
+ var seek = self.seek(id[i]);
1117
+ var duration = (self._sprite[sound._sprite][0] + self._sprite[sound._sprite][1]) / 1e3 - seek;
1118
+ var timeout = duration * 1e3 / Math.abs(sound._rate);
1119
+ if (self._endTimers[id[i]] || !sound._paused) {
1120
+ self._clearTimer(id[i]);
1121
+ self._endTimers[id[i]] = setTimeout(self._ended.bind(self, sound), timeout);
1122
+ }
1123
+ self._emit("rate", sound._id);
1124
+ }
1125
+ }
1126
+ } else {
1127
+ sound = self._soundById(id);
1128
+ return sound ? sound._rate : self._rate;
1129
+ }
1130
+ return self;
1131
+ },
1132
+ /**
1133
+ * Get/set the seek position of a sound. This method can optionally take 0, 1 or 2 arguments.
1134
+ * seek() -> Returns the first sound node's current seek position.
1135
+ * seek(id) -> Returns the sound id's current seek position.
1136
+ * seek(seek) -> Sets the seek position of the first sound node.
1137
+ * seek(seek, id) -> Sets the seek position of passed sound id.
1138
+ * @return {Howl/Number} Returns self or the current seek position.
1139
+ */
1140
+ seek: function() {
1141
+ var self = this;
1142
+ var args = arguments;
1143
+ var seek, id;
1144
+ if (args.length === 0) {
1145
+ if (self._sounds.length) {
1146
+ id = self._sounds[0]._id;
1147
+ }
1148
+ } else if (args.length === 1) {
1149
+ var ids = self._getSoundIds();
1150
+ var index = ids.indexOf(args[0]);
1151
+ if (index >= 0) {
1152
+ id = parseInt(args[0], 10);
1153
+ } else if (self._sounds.length) {
1154
+ id = self._sounds[0]._id;
1155
+ seek = parseFloat(args[0]);
1156
+ }
1157
+ } else if (args.length === 2) {
1158
+ seek = parseFloat(args[0]);
1159
+ id = parseInt(args[1], 10);
1160
+ }
1161
+ if (typeof id === "undefined") {
1162
+ return 0;
1163
+ }
1164
+ if (typeof seek === "number" && (self._state !== "loaded" || self._playLock)) {
1165
+ self._queue.push({
1166
+ event: "seek",
1167
+ action: function() {
1168
+ self.seek.apply(self, args);
1169
+ }
1170
+ });
1171
+ return self;
1172
+ }
1173
+ var sound = self._soundById(id);
1174
+ if (sound) {
1175
+ if (typeof seek === "number" && seek >= 0) {
1176
+ var playing = self.playing(id);
1177
+ if (playing) {
1178
+ self.pause(id, true);
1179
+ }
1180
+ sound._seek = seek;
1181
+ sound._ended = false;
1182
+ self._clearTimer(id);
1183
+ if (!self._webAudio && sound._node && !isNaN(sound._node.duration)) {
1184
+ sound._node.currentTime = seek;
1185
+ }
1186
+ var seekAndEmit = function() {
1187
+ if (playing) {
1188
+ self.play(id, true);
1189
+ }
1190
+ self._emit("seek", id);
1191
+ };
1192
+ if (playing && !self._webAudio) {
1193
+ var emitSeek = function() {
1194
+ if (!self._playLock) {
1195
+ seekAndEmit();
1196
+ } else {
1197
+ setTimeout(emitSeek, 0);
1198
+ }
1199
+ };
1200
+ setTimeout(emitSeek, 0);
1201
+ } else {
1202
+ seekAndEmit();
1203
+ }
1204
+ } else {
1205
+ if (self._webAudio) {
1206
+ var realTime = self.playing(id) ? Howler3.ctx.currentTime - sound._playStart : 0;
1207
+ var rateSeek = sound._rateSeek ? sound._rateSeek - sound._seek : 0;
1208
+ return sound._seek + (rateSeek + realTime * Math.abs(sound._rate));
1209
+ } else {
1210
+ return sound._node.currentTime;
1211
+ }
1212
+ }
1213
+ }
1214
+ return self;
1215
+ },
1216
+ /**
1217
+ * Check if a specific sound is currently playing or not (if id is provided), or check if at least one of the sounds in the group is playing or not.
1218
+ * @param {Number} id The sound id to check. If none is passed, the whole sound group is checked.
1219
+ * @return {Boolean} True if playing and false if not.
1220
+ */
1221
+ playing: function(id) {
1222
+ var self = this;
1223
+ if (typeof id === "number") {
1224
+ var sound = self._soundById(id);
1225
+ return sound ? !sound._paused : false;
1226
+ }
1227
+ for (var i = 0; i < self._sounds.length; i++) {
1228
+ if (!self._sounds[i]._paused) {
1229
+ return true;
1230
+ }
1231
+ }
1232
+ return false;
1233
+ },
1234
+ /**
1235
+ * Get the duration of this sound. Passing a sound id will return the sprite duration.
1236
+ * @param {Number} id The sound id to check. If none is passed, return full source duration.
1237
+ * @return {Number} Audio duration in seconds.
1238
+ */
1239
+ duration: function(id) {
1240
+ var self = this;
1241
+ var duration = self._duration;
1242
+ var sound = self._soundById(id);
1243
+ if (sound) {
1244
+ duration = self._sprite[sound._sprite][1] / 1e3;
1245
+ }
1246
+ return duration;
1247
+ },
1248
+ /**
1249
+ * Returns the current loaded state of this Howl.
1250
+ * @return {String} 'unloaded', 'loading', 'loaded'
1251
+ */
1252
+ state: function() {
1253
+ return this._state;
1254
+ },
1255
+ /**
1256
+ * Unload and destroy the current Howl object.
1257
+ * This will immediately stop all sound instances attached to this group.
1258
+ */
1259
+ unload: function() {
1260
+ var self = this;
1261
+ var sounds = self._sounds;
1262
+ for (var i = 0; i < sounds.length; i++) {
1263
+ if (!sounds[i]._paused) {
1264
+ self.stop(sounds[i]._id);
1265
+ }
1266
+ if (!self._webAudio) {
1267
+ self._clearSound(sounds[i]._node);
1268
+ sounds[i]._node.removeEventListener("error", sounds[i]._errorFn, false);
1269
+ sounds[i]._node.removeEventListener(Howler3._canPlayEvent, sounds[i]._loadFn, false);
1270
+ sounds[i]._node.removeEventListener("ended", sounds[i]._endFn, false);
1271
+ Howler3._releaseHtml5Audio(sounds[i]._node);
1272
+ }
1273
+ delete sounds[i]._node;
1274
+ self._clearTimer(sounds[i]._id);
1275
+ }
1276
+ var index = Howler3._howls.indexOf(self);
1277
+ if (index >= 0) {
1278
+ Howler3._howls.splice(index, 1);
1279
+ }
1280
+ var remCache = true;
1281
+ for (i = 0; i < Howler3._howls.length; i++) {
1282
+ if (Howler3._howls[i]._src === self._src || self._src.indexOf(Howler3._howls[i]._src) >= 0) {
1283
+ remCache = false;
1284
+ break;
1285
+ }
1286
+ }
1287
+ if (cache && remCache) {
1288
+ delete cache[self._src];
1289
+ }
1290
+ Howler3.noAudio = false;
1291
+ self._state = "unloaded";
1292
+ self._sounds = [];
1293
+ self = null;
1294
+ return null;
1295
+ },
1296
+ /**
1297
+ * Listen to a custom event.
1298
+ * @param {String} event Event name.
1299
+ * @param {Function} fn Listener to call.
1300
+ * @param {Number} id (optional) Only listen to events for this sound.
1301
+ * @param {Number} once (INTERNAL) Marks event to fire only once.
1302
+ * @return {Howl}
1303
+ */
1304
+ on: function(event, fn, id, once) {
1305
+ var self = this;
1306
+ var events = self["_on" + event];
1307
+ if (typeof fn === "function") {
1308
+ events.push(once ? { id, fn, once } : { id, fn });
1309
+ }
1310
+ return self;
1311
+ },
1312
+ /**
1313
+ * Remove a custom event. Call without parameters to remove all events.
1314
+ * @param {String} event Event name.
1315
+ * @param {Function} fn Listener to remove. Leave empty to remove all.
1316
+ * @param {Number} id (optional) Only remove events for this sound.
1317
+ * @return {Howl}
1318
+ */
1319
+ off: function(event, fn, id) {
1320
+ var self = this;
1321
+ var events = self["_on" + event];
1322
+ var i = 0;
1323
+ if (typeof fn === "number") {
1324
+ id = fn;
1325
+ fn = null;
1326
+ }
1327
+ if (fn || id) {
1328
+ for (i = 0; i < events.length; i++) {
1329
+ var isId = id === events[i].id;
1330
+ if (fn === events[i].fn && isId || !fn && isId) {
1331
+ events.splice(i, 1);
1332
+ break;
1333
+ }
1334
+ }
1335
+ } else if (event) {
1336
+ self["_on" + event] = [];
1337
+ } else {
1338
+ var keys = Object.keys(self);
1339
+ for (i = 0; i < keys.length; i++) {
1340
+ if (keys[i].indexOf("_on") === 0 && Array.isArray(self[keys[i]])) {
1341
+ self[keys[i]] = [];
1342
+ }
1343
+ }
1344
+ }
1345
+ return self;
1346
+ },
1347
+ /**
1348
+ * Listen to a custom event and remove it once fired.
1349
+ * @param {String} event Event name.
1350
+ * @param {Function} fn Listener to call.
1351
+ * @param {Number} id (optional) Only listen to events for this sound.
1352
+ * @return {Howl}
1353
+ */
1354
+ once: function(event, fn, id) {
1355
+ var self = this;
1356
+ self.on(event, fn, id, 1);
1357
+ return self;
1358
+ },
1359
+ /**
1360
+ * Emit all events of a specific type and pass the sound id.
1361
+ * @param {String} event Event name.
1362
+ * @param {Number} id Sound ID.
1363
+ * @param {Number} msg Message to go with event.
1364
+ * @return {Howl}
1365
+ */
1366
+ _emit: function(event, id, msg) {
1367
+ var self = this;
1368
+ var events = self["_on" + event];
1369
+ for (var i = events.length - 1; i >= 0; i--) {
1370
+ if (!events[i].id || events[i].id === id || event === "load") {
1371
+ setTimeout(function(fn) {
1372
+ fn.call(this, id, msg);
1373
+ }.bind(self, events[i].fn), 0);
1374
+ if (events[i].once) {
1375
+ self.off(event, events[i].fn, events[i].id);
1376
+ }
1377
+ }
1378
+ }
1379
+ self._loadQueue(event);
1380
+ return self;
1381
+ },
1382
+ /**
1383
+ * Queue of actions initiated before the sound has loaded.
1384
+ * These will be called in sequence, with the next only firing
1385
+ * after the previous has finished executing (even if async like play).
1386
+ * @return {Howl}
1387
+ */
1388
+ _loadQueue: function(event) {
1389
+ var self = this;
1390
+ if (self._queue.length > 0) {
1391
+ var task = self._queue[0];
1392
+ if (task.event === event) {
1393
+ self._queue.shift();
1394
+ self._loadQueue();
1395
+ }
1396
+ if (!event) {
1397
+ task.action();
1398
+ }
1399
+ }
1400
+ return self;
1401
+ },
1402
+ /**
1403
+ * Fired when playback ends at the end of the duration.
1404
+ * @param {Sound} sound The sound object to work with.
1405
+ * @return {Howl}
1406
+ */
1407
+ _ended: function(sound) {
1408
+ var self = this;
1409
+ var sprite = sound._sprite;
1410
+ if (!self._webAudio && sound._node && !sound._node.paused && !sound._node.ended && sound._node.currentTime < sound._stop) {
1411
+ setTimeout(self._ended.bind(self, sound), 100);
1412
+ return self;
1413
+ }
1414
+ var loop = !!(sound._loop || self._sprite[sprite][2]);
1415
+ self._emit("end", sound._id);
1416
+ if (!self._webAudio && loop) {
1417
+ self.stop(sound._id, true).play(sound._id);
1418
+ }
1419
+ if (self._webAudio && loop) {
1420
+ self._emit("play", sound._id);
1421
+ sound._seek = sound._start || 0;
1422
+ sound._rateSeek = 0;
1423
+ sound._playStart = Howler3.ctx.currentTime;
1424
+ var timeout = (sound._stop - sound._start) * 1e3 / Math.abs(sound._rate);
1425
+ self._endTimers[sound._id] = setTimeout(self._ended.bind(self, sound), timeout);
1426
+ }
1427
+ if (self._webAudio && !loop) {
1428
+ sound._paused = true;
1429
+ sound._ended = true;
1430
+ sound._seek = sound._start || 0;
1431
+ sound._rateSeek = 0;
1432
+ self._clearTimer(sound._id);
1433
+ self._cleanBuffer(sound._node);
1434
+ Howler3._autoSuspend();
1435
+ }
1436
+ if (!self._webAudio && !loop) {
1437
+ self.stop(sound._id, true);
1438
+ }
1439
+ return self;
1440
+ },
1441
+ /**
1442
+ * Clear the end timer for a sound playback.
1443
+ * @param {Number} id The sound ID.
1444
+ * @return {Howl}
1445
+ */
1446
+ _clearTimer: function(id) {
1447
+ var self = this;
1448
+ if (self._endTimers[id]) {
1449
+ if (typeof self._endTimers[id] !== "function") {
1450
+ clearTimeout(self._endTimers[id]);
1451
+ } else {
1452
+ var sound = self._soundById(id);
1453
+ if (sound && sound._node) {
1454
+ sound._node.removeEventListener("ended", self._endTimers[id], false);
1455
+ }
1456
+ }
1457
+ delete self._endTimers[id];
1458
+ }
1459
+ return self;
1460
+ },
1461
+ /**
1462
+ * Return the sound identified by this ID, or return null.
1463
+ * @param {Number} id Sound ID
1464
+ * @return {Object} Sound object or null.
1465
+ */
1466
+ _soundById: function(id) {
1467
+ var self = this;
1468
+ for (var i = 0; i < self._sounds.length; i++) {
1469
+ if (id === self._sounds[i]._id) {
1470
+ return self._sounds[i];
1471
+ }
1472
+ }
1473
+ return null;
1474
+ },
1475
+ /**
1476
+ * Return an inactive sound from the pool or create a new one.
1477
+ * @return {Sound} Sound playback object.
1478
+ */
1479
+ _inactiveSound: function() {
1480
+ var self = this;
1481
+ self._drain();
1482
+ for (var i = 0; i < self._sounds.length; i++) {
1483
+ if (self._sounds[i]._ended) {
1484
+ return self._sounds[i].reset();
1485
+ }
1486
+ }
1487
+ return new Sound2(self);
1488
+ },
1489
+ /**
1490
+ * Drain excess inactive sounds from the pool.
1491
+ */
1492
+ _drain: function() {
1493
+ var self = this;
1494
+ var limit = self._pool;
1495
+ var cnt = 0;
1496
+ var i = 0;
1497
+ if (self._sounds.length < limit) {
1498
+ return;
1499
+ }
1500
+ for (i = 0; i < self._sounds.length; i++) {
1501
+ if (self._sounds[i]._ended) {
1502
+ cnt++;
1503
+ }
1504
+ }
1505
+ for (i = self._sounds.length - 1; i >= 0; i--) {
1506
+ if (cnt <= limit) {
1507
+ return;
1508
+ }
1509
+ if (self._sounds[i]._ended) {
1510
+ if (self._webAudio && self._sounds[i]._node) {
1511
+ self._sounds[i]._node.disconnect(0);
1512
+ }
1513
+ self._sounds.splice(i, 1);
1514
+ cnt--;
1515
+ }
1516
+ }
1517
+ },
1518
+ /**
1519
+ * Get all ID's from the sounds pool.
1520
+ * @param {Number} id Only return one ID if one is passed.
1521
+ * @return {Array} Array of IDs.
1522
+ */
1523
+ _getSoundIds: function(id) {
1524
+ var self = this;
1525
+ if (typeof id === "undefined") {
1526
+ var ids = [];
1527
+ for (var i = 0; i < self._sounds.length; i++) {
1528
+ ids.push(self._sounds[i]._id);
1529
+ }
1530
+ return ids;
1531
+ } else {
1532
+ return [id];
1533
+ }
1534
+ },
1535
+ /**
1536
+ * Load the sound back into the buffer source.
1537
+ * @param {Sound} sound The sound object to work with.
1538
+ * @return {Howl}
1539
+ */
1540
+ _refreshBuffer: function(sound) {
1541
+ var self = this;
1542
+ sound._node.bufferSource = Howler3.ctx.createBufferSource();
1543
+ sound._node.bufferSource.buffer = cache[self._src];
1544
+ if (sound._panner) {
1545
+ sound._node.bufferSource.connect(sound._panner);
1546
+ } else {
1547
+ sound._node.bufferSource.connect(sound._node);
1548
+ }
1549
+ sound._node.bufferSource.loop = sound._loop;
1550
+ if (sound._loop) {
1551
+ sound._node.bufferSource.loopStart = sound._start || 0;
1552
+ sound._node.bufferSource.loopEnd = sound._stop || 0;
1553
+ }
1554
+ sound._node.bufferSource.playbackRate.setValueAtTime(sound._rate, Howler3.ctx.currentTime);
1555
+ return self;
1556
+ },
1557
+ /**
1558
+ * Prevent memory leaks by cleaning up the buffer source after playback.
1559
+ * @param {Object} node Sound's audio node containing the buffer source.
1560
+ * @return {Howl}
1561
+ */
1562
+ _cleanBuffer: function(node) {
1563
+ var self = this;
1564
+ var isIOS = Howler3._navigator && Howler3._navigator.vendor.indexOf("Apple") >= 0;
1565
+ if (!node.bufferSource) {
1566
+ return self;
1567
+ }
1568
+ if (Howler3._scratchBuffer && node.bufferSource) {
1569
+ node.bufferSource.onended = null;
1570
+ node.bufferSource.disconnect(0);
1571
+ if (isIOS) {
1572
+ try {
1573
+ node.bufferSource.buffer = Howler3._scratchBuffer;
1574
+ } catch (e) {
1575
+ }
1576
+ }
1577
+ }
1578
+ node.bufferSource = null;
1579
+ return self;
1580
+ },
1581
+ /**
1582
+ * Set the source to a 0-second silence to stop any downloading (except in IE).
1583
+ * @param {Object} node Audio node to clear.
1584
+ */
1585
+ _clearSound: function(node) {
1586
+ var checkIE = /MSIE |Trident\//.test(Howler3._navigator && Howler3._navigator.userAgent);
1587
+ if (!checkIE) {
1588
+ node.src = "data:audio/wav;base64,UklGRigAAABXQVZFZm10IBIAAAABAAEARKwAAIhYAQACABAAAABkYXRhAgAAAAEA";
1589
+ }
1590
+ }
1591
+ };
1592
+ var Sound2 = function(howl) {
1593
+ this._parent = howl;
1594
+ this.init();
1595
+ };
1596
+ Sound2.prototype = {
1597
+ /**
1598
+ * Initialize a new Sound object.
1599
+ * @return {Sound}
1600
+ */
1601
+ init: function() {
1602
+ var self = this;
1603
+ var parent = self._parent;
1604
+ self._muted = parent._muted;
1605
+ self._loop = parent._loop;
1606
+ self._volume = parent._volume;
1607
+ self._rate = parent._rate;
1608
+ self._seek = 0;
1609
+ self._paused = true;
1610
+ self._ended = true;
1611
+ self._sprite = "__default";
1612
+ self._id = ++Howler3._counter;
1613
+ parent._sounds.push(self);
1614
+ self.create();
1615
+ return self;
1616
+ },
1617
+ /**
1618
+ * Create and setup a new sound object, whether HTML5 Audio or Web Audio.
1619
+ * @return {Sound}
1620
+ */
1621
+ create: function() {
1622
+ var self = this;
1623
+ var parent = self._parent;
1624
+ var volume = Howler3._muted || self._muted || self._parent._muted ? 0 : self._volume;
1625
+ if (parent._webAudio) {
1626
+ self._node = typeof Howler3.ctx.createGain === "undefined" ? Howler3.ctx.createGainNode() : Howler3.ctx.createGain();
1627
+ self._node.gain.setValueAtTime(volume, Howler3.ctx.currentTime);
1628
+ self._node.paused = true;
1629
+ self._node.connect(Howler3.masterGain);
1630
+ } else if (!Howler3.noAudio) {
1631
+ self._node = Howler3._obtainHtml5Audio();
1632
+ self._errorFn = self._errorListener.bind(self);
1633
+ self._node.addEventListener("error", self._errorFn, false);
1634
+ self._loadFn = self._loadListener.bind(self);
1635
+ self._node.addEventListener(Howler3._canPlayEvent, self._loadFn, false);
1636
+ self._endFn = self._endListener.bind(self);
1637
+ self._node.addEventListener("ended", self._endFn, false);
1638
+ self._node.src = parent._src;
1639
+ self._node.preload = parent._preload === true ? "auto" : parent._preload;
1640
+ self._node.volume = volume * Howler3.volume();
1641
+ self._node.load();
1642
+ }
1643
+ return self;
1644
+ },
1645
+ /**
1646
+ * Reset the parameters of this sound to the original state (for recycle).
1647
+ * @return {Sound}
1648
+ */
1649
+ reset: function() {
1650
+ var self = this;
1651
+ var parent = self._parent;
1652
+ self._muted = parent._muted;
1653
+ self._loop = parent._loop;
1654
+ self._volume = parent._volume;
1655
+ self._rate = parent._rate;
1656
+ self._seek = 0;
1657
+ self._rateSeek = 0;
1658
+ self._paused = true;
1659
+ self._ended = true;
1660
+ self._sprite = "__default";
1661
+ self._id = ++Howler3._counter;
1662
+ return self;
1663
+ },
1664
+ /**
1665
+ * HTML5 Audio error listener callback.
1666
+ */
1667
+ _errorListener: function() {
1668
+ var self = this;
1669
+ self._parent._emit("loaderror", self._id, self._node.error ? self._node.error.code : 0);
1670
+ self._node.removeEventListener("error", self._errorFn, false);
1671
+ },
1672
+ /**
1673
+ * HTML5 Audio canplaythrough listener callback.
1674
+ */
1675
+ _loadListener: function() {
1676
+ var self = this;
1677
+ var parent = self._parent;
1678
+ parent._duration = Math.ceil(self._node.duration * 10) / 10;
1679
+ if (Object.keys(parent._sprite).length === 0) {
1680
+ parent._sprite = { __default: [0, parent._duration * 1e3] };
1681
+ }
1682
+ if (parent._state !== "loaded") {
1683
+ parent._state = "loaded";
1684
+ parent._emit("load");
1685
+ parent._loadQueue();
1686
+ }
1687
+ self._node.removeEventListener(Howler3._canPlayEvent, self._loadFn, false);
1688
+ },
1689
+ /**
1690
+ * HTML5 Audio ended listener callback.
1691
+ */
1692
+ _endListener: function() {
1693
+ var self = this;
1694
+ var parent = self._parent;
1695
+ if (parent._duration === Infinity) {
1696
+ parent._duration = Math.ceil(self._node.duration * 10) / 10;
1697
+ if (parent._sprite.__default[1] === Infinity) {
1698
+ parent._sprite.__default[1] = parent._duration * 1e3;
1699
+ }
1700
+ parent._ended(self);
1701
+ }
1702
+ self._node.removeEventListener("ended", self._endFn, false);
1703
+ }
1704
+ };
1705
+ var cache = {};
1706
+ var loadBuffer = function(self) {
1707
+ var url = self._src;
1708
+ if (cache[url]) {
1709
+ self._duration = cache[url].duration;
1710
+ loadSound(self);
1711
+ return;
1712
+ }
1713
+ if (/^data:[^;]+;base64,/.test(url)) {
1714
+ var data = atob(url.split(",")[1]);
1715
+ var dataView = new Uint8Array(data.length);
1716
+ for (var i = 0; i < data.length; ++i) {
1717
+ dataView[i] = data.charCodeAt(i);
1718
+ }
1719
+ decodeAudioData(dataView.buffer, self);
1720
+ } else {
1721
+ var xhr = new XMLHttpRequest();
1722
+ xhr.open(self._xhr.method, url, true);
1723
+ xhr.withCredentials = self._xhr.withCredentials;
1724
+ xhr.responseType = "arraybuffer";
1725
+ if (self._xhr.headers) {
1726
+ Object.keys(self._xhr.headers).forEach(function(key) {
1727
+ xhr.setRequestHeader(key, self._xhr.headers[key]);
1728
+ });
1729
+ }
1730
+ xhr.onload = function() {
1731
+ var code = (xhr.status + "")[0];
1732
+ if (code !== "0" && code !== "2" && code !== "3") {
1733
+ self._emit("loaderror", null, "Failed loading audio file with status: " + xhr.status + ".");
1734
+ return;
1735
+ }
1736
+ decodeAudioData(xhr.response, self);
1737
+ };
1738
+ xhr.onerror = function() {
1739
+ if (self._webAudio) {
1740
+ self._html5 = true;
1741
+ self._webAudio = false;
1742
+ self._sounds = [];
1743
+ delete cache[url];
1744
+ self.load();
1745
+ }
1746
+ };
1747
+ safeXhrSend(xhr);
1748
+ }
1749
+ };
1750
+ var safeXhrSend = function(xhr) {
1751
+ try {
1752
+ xhr.send();
1753
+ } catch (e) {
1754
+ xhr.onerror();
1755
+ }
1756
+ };
1757
+ var decodeAudioData = function(arraybuffer, self) {
1758
+ var error = function() {
1759
+ self._emit("loaderror", null, "Decoding audio data failed.");
1760
+ };
1761
+ var success = function(buffer) {
1762
+ if (buffer && self._sounds.length > 0) {
1763
+ cache[self._src] = buffer;
1764
+ loadSound(self, buffer);
1765
+ } else {
1766
+ error();
1767
+ }
1768
+ };
1769
+ if (typeof Promise !== "undefined" && Howler3.ctx.decodeAudioData.length === 1) {
1770
+ Howler3.ctx.decodeAudioData(arraybuffer).then(success).catch(error);
1771
+ } else {
1772
+ Howler3.ctx.decodeAudioData(arraybuffer, success, error);
1773
+ }
1774
+ };
1775
+ var loadSound = function(self, buffer) {
1776
+ if (buffer && !self._duration) {
1777
+ self._duration = buffer.duration;
1778
+ }
1779
+ if (Object.keys(self._sprite).length === 0) {
1780
+ self._sprite = { __default: [0, self._duration * 1e3] };
1781
+ }
1782
+ if (self._state !== "loaded") {
1783
+ self._state = "loaded";
1784
+ self._emit("load");
1785
+ self._loadQueue();
1786
+ }
1787
+ };
1788
+ var setupAudioContext = function() {
1789
+ if (!Howler3.usingWebAudio) {
1790
+ return;
1791
+ }
1792
+ try {
1793
+ if (typeof AudioContext !== "undefined") {
1794
+ Howler3.ctx = new AudioContext();
1795
+ } else if (typeof webkitAudioContext !== "undefined") {
1796
+ Howler3.ctx = new webkitAudioContext();
1797
+ } else {
1798
+ Howler3.usingWebAudio = false;
1799
+ }
1800
+ } catch (e) {
1801
+ Howler3.usingWebAudio = false;
1802
+ }
1803
+ if (!Howler3.ctx) {
1804
+ Howler3.usingWebAudio = false;
1805
+ }
1806
+ var iOS = /iP(hone|od|ad)/.test(Howler3._navigator && Howler3._navigator.platform);
1807
+ var appVersion = Howler3._navigator && Howler3._navigator.appVersion.match(/OS (\d+)_(\d+)_?(\d+)?/);
1808
+ var version = appVersion ? parseInt(appVersion[1], 10) : null;
1809
+ if (iOS && version && version < 9) {
1810
+ var safari = /safari/.test(Howler3._navigator && Howler3._navigator.userAgent.toLowerCase());
1811
+ if (Howler3._navigator && !safari) {
1812
+ Howler3.usingWebAudio = false;
1813
+ }
1814
+ }
1815
+ if (Howler3.usingWebAudio) {
1816
+ Howler3.masterGain = typeof Howler3.ctx.createGain === "undefined" ? Howler3.ctx.createGainNode() : Howler3.ctx.createGain();
1817
+ Howler3.masterGain.gain.setValueAtTime(Howler3._muted ? 0 : Howler3._volume, Howler3.ctx.currentTime);
1818
+ Howler3.masterGain.connect(Howler3.ctx.destination);
1819
+ }
1820
+ Howler3._setup();
1821
+ };
1822
+ if (typeof define === "function" && define.amd) {
1823
+ define([], function() {
1824
+ return {
1825
+ Howler: Howler3,
1826
+ Howl: Howl3
1827
+ };
1828
+ });
1829
+ }
1830
+ if (typeof exports !== "undefined") {
1831
+ exports.Howler = Howler3;
1832
+ exports.Howl = Howl3;
1833
+ }
1834
+ if (typeof global !== "undefined") {
1835
+ global.HowlerGlobal = HowlerGlobal2;
1836
+ global.Howler = Howler3;
1837
+ global.Howl = Howl3;
1838
+ global.Sound = Sound2;
1839
+ } else if (typeof window !== "undefined") {
1840
+ window.HowlerGlobal = HowlerGlobal2;
1841
+ window.Howler = Howler3;
1842
+ window.Howl = Howl3;
1843
+ window.Sound = Sound2;
1844
+ }
1845
+ })();
1846
+ (function() {
1847
+ "use strict";
1848
+ HowlerGlobal.prototype._pos = [0, 0, 0];
1849
+ HowlerGlobal.prototype._orientation = [0, 0, -1, 0, 1, 0];
1850
+ HowlerGlobal.prototype.stereo = function(pan) {
1851
+ var self = this;
1852
+ if (!self.ctx || !self.ctx.listener) {
1853
+ return self;
1854
+ }
1855
+ for (var i = self._howls.length - 1; i >= 0; i--) {
1856
+ self._howls[i].stereo(pan);
1857
+ }
1858
+ return self;
1859
+ };
1860
+ HowlerGlobal.prototype.pos = function(x, y, z) {
1861
+ var self = this;
1862
+ if (!self.ctx || !self.ctx.listener) {
1863
+ return self;
1864
+ }
1865
+ y = typeof y !== "number" ? self._pos[1] : y;
1866
+ z = typeof z !== "number" ? self._pos[2] : z;
1867
+ if (typeof x === "number") {
1868
+ self._pos = [x, y, z];
1869
+ if (typeof self.ctx.listener.positionX !== "undefined") {
1870
+ self.ctx.listener.positionX.setTargetAtTime(self._pos[0], Howler.ctx.currentTime, 0.1);
1871
+ self.ctx.listener.positionY.setTargetAtTime(self._pos[1], Howler.ctx.currentTime, 0.1);
1872
+ self.ctx.listener.positionZ.setTargetAtTime(self._pos[2], Howler.ctx.currentTime, 0.1);
1873
+ } else {
1874
+ self.ctx.listener.setPosition(self._pos[0], self._pos[1], self._pos[2]);
1875
+ }
1876
+ } else {
1877
+ return self._pos;
1878
+ }
1879
+ return self;
1880
+ };
1881
+ HowlerGlobal.prototype.orientation = function(x, y, z, xUp, yUp, zUp) {
1882
+ var self = this;
1883
+ if (!self.ctx || !self.ctx.listener) {
1884
+ return self;
1885
+ }
1886
+ var or = self._orientation;
1887
+ y = typeof y !== "number" ? or[1] : y;
1888
+ z = typeof z !== "number" ? or[2] : z;
1889
+ xUp = typeof xUp !== "number" ? or[3] : xUp;
1890
+ yUp = typeof yUp !== "number" ? or[4] : yUp;
1891
+ zUp = typeof zUp !== "number" ? or[5] : zUp;
1892
+ if (typeof x === "number") {
1893
+ self._orientation = [x, y, z, xUp, yUp, zUp];
1894
+ if (typeof self.ctx.listener.forwardX !== "undefined") {
1895
+ self.ctx.listener.forwardX.setTargetAtTime(x, Howler.ctx.currentTime, 0.1);
1896
+ self.ctx.listener.forwardY.setTargetAtTime(y, Howler.ctx.currentTime, 0.1);
1897
+ self.ctx.listener.forwardZ.setTargetAtTime(z, Howler.ctx.currentTime, 0.1);
1898
+ self.ctx.listener.upX.setTargetAtTime(xUp, Howler.ctx.currentTime, 0.1);
1899
+ self.ctx.listener.upY.setTargetAtTime(yUp, Howler.ctx.currentTime, 0.1);
1900
+ self.ctx.listener.upZ.setTargetAtTime(zUp, Howler.ctx.currentTime, 0.1);
1901
+ } else {
1902
+ self.ctx.listener.setOrientation(x, y, z, xUp, yUp, zUp);
1903
+ }
1904
+ } else {
1905
+ return or;
1906
+ }
1907
+ return self;
1908
+ };
1909
+ Howl.prototype.init = /* @__PURE__ */ (function(_super) {
1910
+ return function(o) {
1911
+ var self = this;
1912
+ self._orientation = o.orientation || [1, 0, 0];
1913
+ self._stereo = o.stereo || null;
1914
+ self._pos = o.pos || null;
1915
+ self._pannerAttr = {
1916
+ coneInnerAngle: typeof o.coneInnerAngle !== "undefined" ? o.coneInnerAngle : 360,
1917
+ coneOuterAngle: typeof o.coneOuterAngle !== "undefined" ? o.coneOuterAngle : 360,
1918
+ coneOuterGain: typeof o.coneOuterGain !== "undefined" ? o.coneOuterGain : 0,
1919
+ distanceModel: typeof o.distanceModel !== "undefined" ? o.distanceModel : "inverse",
1920
+ maxDistance: typeof o.maxDistance !== "undefined" ? o.maxDistance : 1e4,
1921
+ panningModel: typeof o.panningModel !== "undefined" ? o.panningModel : "HRTF",
1922
+ refDistance: typeof o.refDistance !== "undefined" ? o.refDistance : 1,
1923
+ rolloffFactor: typeof o.rolloffFactor !== "undefined" ? o.rolloffFactor : 1
1924
+ };
1925
+ self._onstereo = o.onstereo ? [{ fn: o.onstereo }] : [];
1926
+ self._onpos = o.onpos ? [{ fn: o.onpos }] : [];
1927
+ self._onorientation = o.onorientation ? [{ fn: o.onorientation }] : [];
1928
+ return _super.call(this, o);
1929
+ };
1930
+ })(Howl.prototype.init);
1931
+ Howl.prototype.stereo = function(pan, id) {
1932
+ var self = this;
1933
+ if (!self._webAudio) {
1934
+ return self;
1935
+ }
1936
+ if (self._state !== "loaded") {
1937
+ self._queue.push({
1938
+ event: "stereo",
1939
+ action: function() {
1940
+ self.stereo(pan, id);
1941
+ }
1942
+ });
1943
+ return self;
1944
+ }
1945
+ var pannerType = typeof Howler.ctx.createStereoPanner === "undefined" ? "spatial" : "stereo";
1946
+ if (typeof id === "undefined") {
1947
+ if (typeof pan === "number") {
1948
+ self._stereo = pan;
1949
+ self._pos = [pan, 0, 0];
1950
+ } else {
1951
+ return self._stereo;
1952
+ }
1953
+ }
1954
+ var ids = self._getSoundIds(id);
1955
+ for (var i = 0; i < ids.length; i++) {
1956
+ var sound = self._soundById(ids[i]);
1957
+ if (sound) {
1958
+ if (typeof pan === "number") {
1959
+ sound._stereo = pan;
1960
+ sound._pos = [pan, 0, 0];
1961
+ if (sound._node) {
1962
+ sound._pannerAttr.panningModel = "equalpower";
1963
+ if (!sound._panner || !sound._panner.pan) {
1964
+ setupPanner(sound, pannerType);
1965
+ }
1966
+ if (pannerType === "spatial") {
1967
+ if (typeof sound._panner.positionX !== "undefined") {
1968
+ sound._panner.positionX.setValueAtTime(pan, Howler.ctx.currentTime);
1969
+ sound._panner.positionY.setValueAtTime(0, Howler.ctx.currentTime);
1970
+ sound._panner.positionZ.setValueAtTime(0, Howler.ctx.currentTime);
1971
+ } else {
1972
+ sound._panner.setPosition(pan, 0, 0);
1973
+ }
1974
+ } else {
1975
+ sound._panner.pan.setValueAtTime(pan, Howler.ctx.currentTime);
1976
+ }
1977
+ }
1978
+ self._emit("stereo", sound._id);
1979
+ } else {
1980
+ return sound._stereo;
1981
+ }
1982
+ }
1983
+ }
1984
+ return self;
1985
+ };
1986
+ Howl.prototype.pos = function(x, y, z, id) {
1987
+ var self = this;
1988
+ if (!self._webAudio) {
1989
+ return self;
1990
+ }
1991
+ if (self._state !== "loaded") {
1992
+ self._queue.push({
1993
+ event: "pos",
1994
+ action: function() {
1995
+ self.pos(x, y, z, id);
1996
+ }
1997
+ });
1998
+ return self;
1999
+ }
2000
+ y = typeof y !== "number" ? 0 : y;
2001
+ z = typeof z !== "number" ? -0.5 : z;
2002
+ if (typeof id === "undefined") {
2003
+ if (typeof x === "number") {
2004
+ self._pos = [x, y, z];
2005
+ } else {
2006
+ return self._pos;
2007
+ }
2008
+ }
2009
+ var ids = self._getSoundIds(id);
2010
+ for (var i = 0; i < ids.length; i++) {
2011
+ var sound = self._soundById(ids[i]);
2012
+ if (sound) {
2013
+ if (typeof x === "number") {
2014
+ sound._pos = [x, y, z];
2015
+ if (sound._node) {
2016
+ if (!sound._panner || sound._panner.pan) {
2017
+ setupPanner(sound, "spatial");
2018
+ }
2019
+ if (typeof sound._panner.positionX !== "undefined") {
2020
+ sound._panner.positionX.setValueAtTime(x, Howler.ctx.currentTime);
2021
+ sound._panner.positionY.setValueAtTime(y, Howler.ctx.currentTime);
2022
+ sound._panner.positionZ.setValueAtTime(z, Howler.ctx.currentTime);
2023
+ } else {
2024
+ sound._panner.setPosition(x, y, z);
2025
+ }
2026
+ }
2027
+ self._emit("pos", sound._id);
2028
+ } else {
2029
+ return sound._pos;
2030
+ }
2031
+ }
2032
+ }
2033
+ return self;
2034
+ };
2035
+ Howl.prototype.orientation = function(x, y, z, id) {
2036
+ var self = this;
2037
+ if (!self._webAudio) {
2038
+ return self;
2039
+ }
2040
+ if (self._state !== "loaded") {
2041
+ self._queue.push({
2042
+ event: "orientation",
2043
+ action: function() {
2044
+ self.orientation(x, y, z, id);
2045
+ }
2046
+ });
2047
+ return self;
2048
+ }
2049
+ y = typeof y !== "number" ? self._orientation[1] : y;
2050
+ z = typeof z !== "number" ? self._orientation[2] : z;
2051
+ if (typeof id === "undefined") {
2052
+ if (typeof x === "number") {
2053
+ self._orientation = [x, y, z];
2054
+ } else {
2055
+ return self._orientation;
2056
+ }
2057
+ }
2058
+ var ids = self._getSoundIds(id);
2059
+ for (var i = 0; i < ids.length; i++) {
2060
+ var sound = self._soundById(ids[i]);
2061
+ if (sound) {
2062
+ if (typeof x === "number") {
2063
+ sound._orientation = [x, y, z];
2064
+ if (sound._node) {
2065
+ if (!sound._panner) {
2066
+ if (!sound._pos) {
2067
+ sound._pos = self._pos || [0, 0, -0.5];
2068
+ }
2069
+ setupPanner(sound, "spatial");
2070
+ }
2071
+ if (typeof sound._panner.orientationX !== "undefined") {
2072
+ sound._panner.orientationX.setValueAtTime(x, Howler.ctx.currentTime);
2073
+ sound._panner.orientationY.setValueAtTime(y, Howler.ctx.currentTime);
2074
+ sound._panner.orientationZ.setValueAtTime(z, Howler.ctx.currentTime);
2075
+ } else {
2076
+ sound._panner.setOrientation(x, y, z);
2077
+ }
2078
+ }
2079
+ self._emit("orientation", sound._id);
2080
+ } else {
2081
+ return sound._orientation;
2082
+ }
2083
+ }
2084
+ }
2085
+ return self;
2086
+ };
2087
+ Howl.prototype.pannerAttr = function() {
2088
+ var self = this;
2089
+ var args = arguments;
2090
+ var o, id, sound;
2091
+ if (!self._webAudio) {
2092
+ return self;
2093
+ }
2094
+ if (args.length === 0) {
2095
+ return self._pannerAttr;
2096
+ } else if (args.length === 1) {
2097
+ if (typeof args[0] === "object") {
2098
+ o = args[0];
2099
+ if (typeof id === "undefined") {
2100
+ if (!o.pannerAttr) {
2101
+ o.pannerAttr = {
2102
+ coneInnerAngle: o.coneInnerAngle,
2103
+ coneOuterAngle: o.coneOuterAngle,
2104
+ coneOuterGain: o.coneOuterGain,
2105
+ distanceModel: o.distanceModel,
2106
+ maxDistance: o.maxDistance,
2107
+ refDistance: o.refDistance,
2108
+ rolloffFactor: o.rolloffFactor,
2109
+ panningModel: o.panningModel
2110
+ };
2111
+ }
2112
+ self._pannerAttr = {
2113
+ coneInnerAngle: typeof o.pannerAttr.coneInnerAngle !== "undefined" ? o.pannerAttr.coneInnerAngle : self._coneInnerAngle,
2114
+ coneOuterAngle: typeof o.pannerAttr.coneOuterAngle !== "undefined" ? o.pannerAttr.coneOuterAngle : self._coneOuterAngle,
2115
+ coneOuterGain: typeof o.pannerAttr.coneOuterGain !== "undefined" ? o.pannerAttr.coneOuterGain : self._coneOuterGain,
2116
+ distanceModel: typeof o.pannerAttr.distanceModel !== "undefined" ? o.pannerAttr.distanceModel : self._distanceModel,
2117
+ maxDistance: typeof o.pannerAttr.maxDistance !== "undefined" ? o.pannerAttr.maxDistance : self._maxDistance,
2118
+ refDistance: typeof o.pannerAttr.refDistance !== "undefined" ? o.pannerAttr.refDistance : self._refDistance,
2119
+ rolloffFactor: typeof o.pannerAttr.rolloffFactor !== "undefined" ? o.pannerAttr.rolloffFactor : self._rolloffFactor,
2120
+ panningModel: typeof o.pannerAttr.panningModel !== "undefined" ? o.pannerAttr.panningModel : self._panningModel
2121
+ };
2122
+ }
2123
+ } else {
2124
+ sound = self._soundById(parseInt(args[0], 10));
2125
+ return sound ? sound._pannerAttr : self._pannerAttr;
2126
+ }
2127
+ } else if (args.length === 2) {
2128
+ o = args[0];
2129
+ id = parseInt(args[1], 10);
2130
+ }
2131
+ var ids = self._getSoundIds(id);
2132
+ for (var i = 0; i < ids.length; i++) {
2133
+ sound = self._soundById(ids[i]);
2134
+ if (sound) {
2135
+ var pa = sound._pannerAttr;
2136
+ pa = {
2137
+ coneInnerAngle: typeof o.coneInnerAngle !== "undefined" ? o.coneInnerAngle : pa.coneInnerAngle,
2138
+ coneOuterAngle: typeof o.coneOuterAngle !== "undefined" ? o.coneOuterAngle : pa.coneOuterAngle,
2139
+ coneOuterGain: typeof o.coneOuterGain !== "undefined" ? o.coneOuterGain : pa.coneOuterGain,
2140
+ distanceModel: typeof o.distanceModel !== "undefined" ? o.distanceModel : pa.distanceModel,
2141
+ maxDistance: typeof o.maxDistance !== "undefined" ? o.maxDistance : pa.maxDistance,
2142
+ refDistance: typeof o.refDistance !== "undefined" ? o.refDistance : pa.refDistance,
2143
+ rolloffFactor: typeof o.rolloffFactor !== "undefined" ? o.rolloffFactor : pa.rolloffFactor,
2144
+ panningModel: typeof o.panningModel !== "undefined" ? o.panningModel : pa.panningModel
2145
+ };
2146
+ var panner = sound._panner;
2147
+ if (!panner) {
2148
+ if (!sound._pos) {
2149
+ sound._pos = self._pos || [0, 0, -0.5];
2150
+ }
2151
+ setupPanner(sound, "spatial");
2152
+ panner = sound._panner;
2153
+ }
2154
+ panner.coneInnerAngle = pa.coneInnerAngle;
2155
+ panner.coneOuterAngle = pa.coneOuterAngle;
2156
+ panner.coneOuterGain = pa.coneOuterGain;
2157
+ panner.distanceModel = pa.distanceModel;
2158
+ panner.maxDistance = pa.maxDistance;
2159
+ panner.refDistance = pa.refDistance;
2160
+ panner.rolloffFactor = pa.rolloffFactor;
2161
+ panner.panningModel = pa.panningModel;
2162
+ }
2163
+ }
2164
+ return self;
2165
+ };
2166
+ Sound.prototype.init = /* @__PURE__ */ (function(_super) {
2167
+ return function() {
2168
+ var self = this;
2169
+ var parent = self._parent;
2170
+ self._orientation = parent._orientation;
2171
+ self._stereo = parent._stereo;
2172
+ self._pos = parent._pos;
2173
+ self._pannerAttr = parent._pannerAttr;
2174
+ _super.call(this);
2175
+ if (self._stereo) {
2176
+ parent.stereo(self._stereo);
2177
+ } else if (self._pos) {
2178
+ parent.pos(self._pos[0], self._pos[1], self._pos[2], self._id);
2179
+ }
2180
+ };
2181
+ })(Sound.prototype.init);
2182
+ Sound.prototype.reset = /* @__PURE__ */ (function(_super) {
2183
+ return function() {
2184
+ var self = this;
2185
+ var parent = self._parent;
2186
+ self._orientation = parent._orientation;
2187
+ self._stereo = parent._stereo;
2188
+ self._pos = parent._pos;
2189
+ self._pannerAttr = parent._pannerAttr;
2190
+ if (self._stereo) {
2191
+ parent.stereo(self._stereo);
2192
+ } else if (self._pos) {
2193
+ parent.pos(self._pos[0], self._pos[1], self._pos[2], self._id);
2194
+ } else if (self._panner) {
2195
+ self._panner.disconnect(0);
2196
+ self._panner = void 0;
2197
+ parent._refreshBuffer(self);
2198
+ }
2199
+ return _super.call(this);
2200
+ };
2201
+ })(Sound.prototype.reset);
2202
+ var setupPanner = function(sound, type) {
2203
+ type = type || "spatial";
2204
+ if (type === "spatial") {
2205
+ sound._panner = Howler.ctx.createPanner();
2206
+ sound._panner.coneInnerAngle = sound._pannerAttr.coneInnerAngle;
2207
+ sound._panner.coneOuterAngle = sound._pannerAttr.coneOuterAngle;
2208
+ sound._panner.coneOuterGain = sound._pannerAttr.coneOuterGain;
2209
+ sound._panner.distanceModel = sound._pannerAttr.distanceModel;
2210
+ sound._panner.maxDistance = sound._pannerAttr.maxDistance;
2211
+ sound._panner.refDistance = sound._pannerAttr.refDistance;
2212
+ sound._panner.rolloffFactor = sound._pannerAttr.rolloffFactor;
2213
+ sound._panner.panningModel = sound._pannerAttr.panningModel;
2214
+ if (typeof sound._panner.positionX !== "undefined") {
2215
+ sound._panner.positionX.setValueAtTime(sound._pos[0], Howler.ctx.currentTime);
2216
+ sound._panner.positionY.setValueAtTime(sound._pos[1], Howler.ctx.currentTime);
2217
+ sound._panner.positionZ.setValueAtTime(sound._pos[2], Howler.ctx.currentTime);
2218
+ } else {
2219
+ sound._panner.setPosition(sound._pos[0], sound._pos[1], sound._pos[2]);
2220
+ }
2221
+ if (typeof sound._panner.orientationX !== "undefined") {
2222
+ sound._panner.orientationX.setValueAtTime(sound._orientation[0], Howler.ctx.currentTime);
2223
+ sound._panner.orientationY.setValueAtTime(sound._orientation[1], Howler.ctx.currentTime);
2224
+ sound._panner.orientationZ.setValueAtTime(sound._orientation[2], Howler.ctx.currentTime);
2225
+ } else {
2226
+ sound._panner.setOrientation(sound._orientation[0], sound._orientation[1], sound._orientation[2]);
2227
+ }
2228
+ } else {
2229
+ sound._panner = Howler.ctx.createStereoPanner();
2230
+ sound._panner.pan.setValueAtTime(sound._stereo, Howler.ctx.currentTime);
2231
+ }
2232
+ sound._panner.connect(sound._node);
2233
+ if (!sound._paused) {
2234
+ sound._parent.pause(sound._id, true).play(sound._id, true);
2235
+ }
2236
+ };
2237
+ })();
2238
+ }
2239
+ });
2
2240
 
3
2241
  // src/pano-viewer.tsx
4
2242
  import { Canvas } from "@react-three/fiber";
@@ -4771,14 +7009,385 @@ var PanoViewer = forwardRef2(
4771
7009
  }
4772
7010
  );
4773
7011
 
7012
+ // src/background-audio.tsx
7013
+ import { useContext as useContext15, useEffect as useEffect13, useRef as useRef13 } from "react";
7014
+
7015
+ // src/audio/howl.ts
7016
+ var import_howler = __toESM(require_howler());
7017
+ import_howler.Howler.autoUnlock = true;
7018
+ function sourceList(src) {
7019
+ if (src == null) {
7020
+ return [];
7021
+ }
7022
+ if (typeof src === "string") {
7023
+ return src ? [src] : [];
7024
+ }
7025
+ return src.filter((item) => Boolean(item));
7026
+ }
7027
+ function createUnlockingHowl({
7028
+ src,
7029
+ loop,
7030
+ crossOrigin,
7031
+ isActive,
7032
+ shouldRetryPlay,
7033
+ onEnded,
7034
+ onPlay,
7035
+ onPause,
7036
+ onLoadError,
7037
+ onPlayError
7038
+ }) {
7039
+ let disposed = false;
7040
+ let blockedNotified = false;
7041
+ const unlockListeners = [];
7042
+ const removeUnlockListeners = () => {
7043
+ for (const { type, listener } of unlockListeners) {
7044
+ window.removeEventListener(type, listener, true);
7045
+ }
7046
+ unlockListeners.length = 0;
7047
+ };
7048
+ const instance = new import_howler.Howl({
7049
+ src: [...src],
7050
+ html5: false,
7051
+ preload: true,
7052
+ loop,
7053
+ xhr: crossOrigin === "use-credentials" ? { withCredentials: true } : void 0,
7054
+ onend: () => {
7055
+ if (disposed || !isActive() || instance.loop()) {
7056
+ return;
7057
+ }
7058
+ onEnded?.();
7059
+ },
7060
+ onplay: () => {
7061
+ if (!disposed && isActive()) {
7062
+ onPlay?.();
7063
+ }
7064
+ },
7065
+ onpause: () => {
7066
+ if (!disposed && isActive()) {
7067
+ onPause?.();
7068
+ }
7069
+ },
7070
+ onloaderror: (_soundId, error) => {
7071
+ if (!disposed && isActive()) {
7072
+ onLoadError?.(error);
7073
+ }
7074
+ },
7075
+ onplayerror: (_soundId, error) => {
7076
+ if (disposed || !isActive()) {
7077
+ return;
7078
+ }
7079
+ if (!blockedNotified) {
7080
+ blockedNotified = true;
7081
+ onPlayError?.(error);
7082
+ }
7083
+ const retry = () => {
7084
+ removeUnlockListeners();
7085
+ if (!disposed && isActive() && shouldRetryPlay()) {
7086
+ void import_howler.Howler.ctx?.resume();
7087
+ instance.play();
7088
+ }
7089
+ };
7090
+ removeUnlockListeners();
7091
+ unlockListeners.push({ type: "pointerdown", listener: retry });
7092
+ unlockListeners.push({ type: "keydown", listener: retry });
7093
+ window.addEventListener("pointerdown", retry, { capture: true });
7094
+ window.addEventListener("keydown", retry, { capture: true });
7095
+ }
7096
+ });
7097
+ return {
7098
+ howl: instance,
7099
+ dispose: () => {
7100
+ if (disposed) {
7101
+ return;
7102
+ }
7103
+ disposed = true;
7104
+ removeUnlockListeners();
7105
+ instance.unload();
7106
+ }
7107
+ };
7108
+ }
7109
+
7110
+ // src/hotspot/audio-spatial.ts
7111
+ import { MathUtils as MathUtils3, Vector3 as Vector35 } from "three";
7112
+ var LOOK_DIR = new Vector35();
7113
+ var SOURCE_DIR = new Vector35();
7114
+ var RIGHT_DIR = new Vector35();
7115
+ function clampAudioVolume(volume) {
7116
+ if (!Number.isFinite(volume)) {
7117
+ return 1;
7118
+ }
7119
+ return Math.max(0, Math.min(volume, 1));
7120
+ }
7121
+ function clampLookRange(range) {
7122
+ if (!Number.isFinite(range)) {
7123
+ return 360;
7124
+ }
7125
+ return Math.max(0, range);
7126
+ }
7127
+ function lookRangeGain(angleDegrees, range) {
7128
+ if (range > 180) {
7129
+ return 1;
7130
+ }
7131
+ if (range <= 0) {
7132
+ return 0;
7133
+ }
7134
+ return Math.max(0, Math.min(1, 1 - angleDegrees / range));
7135
+ }
7136
+ function audioSpatialFromView(camera, position, range) {
7137
+ camera.getWorldDirection(LOOK_DIR);
7138
+ SOURCE_DIR.copy(panoPositionToVector3(position)).normalize();
7139
+ const angleDegrees = MathUtils3.radToDeg(
7140
+ Math.acos(MathUtils3.clamp(LOOK_DIR.dot(SOURCE_DIR), -1, 1))
7141
+ );
7142
+ RIGHT_DIR.set(1, 0, 0).applyQuaternion(camera.quaternion);
7143
+ const pan = MathUtils3.clamp(
7144
+ Math.atan2(SOURCE_DIR.dot(RIGHT_DIR), SOURCE_DIR.dot(LOOK_DIR)) / (Math.PI / 2),
7145
+ -1,
7146
+ 1
7147
+ );
7148
+ return {
7149
+ pan,
7150
+ gain: lookRangeGain(angleDegrees, range)
7151
+ };
7152
+ }
7153
+
7154
+ // src/background-audio.tsx
7155
+ var DEFAULT_FADE_MS = 400;
7156
+ function resolveFadeMs(value) {
7157
+ if (!Number.isFinite(value)) {
7158
+ return DEFAULT_FADE_MS;
7159
+ }
7160
+ return Math.max(0, value);
7161
+ }
7162
+ function resolveBackgroundAudioUrls(src, sources, sceneId) {
7163
+ if (sources !== void 0) {
7164
+ if (sceneId === void 0) {
7165
+ throw new Error("<BackgroundAudio> requires sceneId when sources is set.");
7166
+ }
7167
+ if (Object.prototype.hasOwnProperty.call(sources, sceneId)) {
7168
+ return sourceList(sources[sceneId]);
7169
+ }
7170
+ }
7171
+ return sourceList(src);
7172
+ }
7173
+ function applyNonSpatialMix(slot, loop, muted, volume) {
7174
+ slot.handle.howl.stereo(0);
7175
+ slot.handle.howl.loop(loop);
7176
+ slot.handle.howl.mute(muted);
7177
+ slot.handle.howl.volume(clampAudioVolume(volume));
7178
+ }
7179
+ function BackgroundAudio({
7180
+ src,
7181
+ sources,
7182
+ sceneId,
7183
+ playing,
7184
+ loop = true,
7185
+ muted = false,
7186
+ volume = 1,
7187
+ pauseWhenHidden = true,
7188
+ fadeMs,
7189
+ crossOrigin,
7190
+ onPlaybackStateChange,
7191
+ onPlaybackError,
7192
+ onEnded,
7193
+ onError
7194
+ }) {
7195
+ const controlsRef = useContext15(PanoramaViewContext);
7196
+ if (!controlsRef) {
7197
+ throw new Error("<BackgroundAudio> must be rendered inside <PanoViewer>.");
7198
+ }
7199
+ const urls = resolveBackgroundAudioUrls(src, sources, sceneId);
7200
+ const trackKey = urls.join("\0");
7201
+ const currentRef = useRef13(null);
7202
+ const outgoingRef = useRef13([]);
7203
+ const fadingInRef = useRef13(false);
7204
+ const isFirstTrackRef = useRef13(true);
7205
+ const playingRef = useRef13(playing);
7206
+ const loopRef = useRef13(loop);
7207
+ const mutedRef = useRef13(muted);
7208
+ const volumeRef = useRef13(volume);
7209
+ const fadeMsRef = useRef13(resolveFadeMs(fadeMs));
7210
+ const onPlaybackStateChangeRef = useRef13(onPlaybackStateChange);
7211
+ const onPlaybackErrorRef = useRef13(onPlaybackError);
7212
+ const onEndedRef = useRef13(onEnded);
7213
+ const onErrorRef = useRef13(onError);
7214
+ playingRef.current = playing;
7215
+ loopRef.current = loop;
7216
+ mutedRef.current = muted;
7217
+ volumeRef.current = volume;
7218
+ fadeMsRef.current = resolveFadeMs(fadeMs);
7219
+ onPlaybackStateChangeRef.current = onPlaybackStateChange;
7220
+ onPlaybackErrorRef.current = onPlaybackError;
7221
+ onEndedRef.current = onEnded;
7222
+ onErrorRef.current = onError;
7223
+ useEffect13(() => {
7224
+ return () => {
7225
+ fadingInRef.current = false;
7226
+ isFirstTrackRef.current = true;
7227
+ currentRef.current?.handle.dispose();
7228
+ currentRef.current = null;
7229
+ for (const slot of outgoingRef.current) {
7230
+ slot.handle.dispose();
7231
+ }
7232
+ outgoingRef.current = [];
7233
+ };
7234
+ }, []);
7235
+ useEffect13(() => {
7236
+ const previous = currentRef.current;
7237
+ if (previous?.key === trackKey && previous.crossOrigin === crossOrigin) {
7238
+ return;
7239
+ }
7240
+ const durationMs = fadeMsRef.current;
7241
+ const targetVolume = clampAudioVolume(volumeRef.current);
7242
+ const nextUrls = trackKey.length > 0 ? trackKey.split("\0") : [];
7243
+ const retire = (slot) => {
7244
+ const howl = slot.handle.howl;
7245
+ const from = howl.volume();
7246
+ outgoingRef.current.push(slot);
7247
+ if (durationMs <= 0 || from <= 0 || !howl.playing()) {
7248
+ slot.handle.dispose();
7249
+ outgoingRef.current = outgoingRef.current.filter((item) => item !== slot);
7250
+ return;
7251
+ }
7252
+ howl.once("fade", () => {
7253
+ slot.handle.dispose();
7254
+ outgoingRef.current = outgoingRef.current.filter((item) => item !== slot);
7255
+ });
7256
+ howl.fade(from, 0, durationMs);
7257
+ };
7258
+ if (nextUrls.length > 0) {
7259
+ const incoming = {
7260
+ key: trackKey,
7261
+ crossOrigin,
7262
+ handle: createUnlockingHowl({
7263
+ src: nextUrls,
7264
+ loop: loopRef.current,
7265
+ crossOrigin,
7266
+ isActive: () => currentRef.current?.key === trackKey,
7267
+ shouldRetryPlay: () => currentRef.current?.key === trackKey && playingRef.current,
7268
+ onEnded: () => {
7269
+ onPlaybackStateChangeRef.current?.("ended");
7270
+ onEndedRef.current?.();
7271
+ },
7272
+ onPlay: () => {
7273
+ if (fadingInRef.current && currentRef.current === incoming) {
7274
+ incoming.handle.howl.fade(
7275
+ 0,
7276
+ clampAudioVolume(volumeRef.current),
7277
+ durationMs
7278
+ );
7279
+ }
7280
+ onPlaybackStateChangeRef.current?.("playing");
7281
+ },
7282
+ onPause: () => {
7283
+ onPlaybackStateChangeRef.current?.("paused");
7284
+ },
7285
+ onLoadError: (error) => {
7286
+ onErrorRef.current?.({ error });
7287
+ },
7288
+ onPlayError: (error) => {
7289
+ onPlaybackStateChangeRef.current?.("blocked");
7290
+ onPlaybackErrorRef.current?.(error);
7291
+ }
7292
+ })
7293
+ };
7294
+ const fadeIn = durationMs > 0 && !isFirstTrackRef.current;
7295
+ isFirstTrackRef.current = false;
7296
+ fadingInRef.current = fadeIn;
7297
+ applyNonSpatialMix(
7298
+ incoming,
7299
+ loopRef.current,
7300
+ mutedRef.current,
7301
+ fadeIn ? 0 : targetVolume
7302
+ );
7303
+ if (fadeIn) {
7304
+ incoming.handle.howl.once("fade", () => {
7305
+ if (currentRef.current === incoming) {
7306
+ fadingInRef.current = false;
7307
+ incoming.handle.howl.volume(clampAudioVolume(volumeRef.current));
7308
+ }
7309
+ });
7310
+ }
7311
+ currentRef.current = incoming;
7312
+ if (playingRef.current) {
7313
+ incoming.handle.howl.play();
7314
+ }
7315
+ } else {
7316
+ fadingInRef.current = false;
7317
+ isFirstTrackRef.current = false;
7318
+ currentRef.current = null;
7319
+ if (previous && durationMs > 0 && previous.handle.howl.playing()) {
7320
+ previous.handle.howl.once("fade", () => {
7321
+ onPlaybackStateChangeRef.current?.("paused");
7322
+ });
7323
+ } else if (previous) {
7324
+ onPlaybackStateChangeRef.current?.("paused");
7325
+ }
7326
+ }
7327
+ if (previous) {
7328
+ retire(previous);
7329
+ }
7330
+ }, [crossOrigin, trackKey]);
7331
+ useEffect13(() => {
7332
+ const howl = currentRef.current?.handle.howl;
7333
+ if (!howl) {
7334
+ return;
7335
+ }
7336
+ if (!playing) {
7337
+ fadingInRef.current = false;
7338
+ howl.pause();
7339
+ for (const slot of outgoingRef.current) {
7340
+ slot.handle.dispose();
7341
+ }
7342
+ outgoingRef.current = [];
7343
+ return;
7344
+ }
7345
+ howl.play();
7346
+ }, [playing, trackKey]);
7347
+ useEffect13(() => {
7348
+ const slot = currentRef.current;
7349
+ if (!slot) {
7350
+ return;
7351
+ }
7352
+ slot.handle.howl.loop(loop);
7353
+ slot.handle.howl.mute(muted);
7354
+ if (!fadingInRef.current) {
7355
+ slot.handle.howl.volume(clampAudioVolume(volume));
7356
+ }
7357
+ }, [loop, muted, trackKey, volume]);
7358
+ useEffect13(() => {
7359
+ if (!pauseWhenHidden) {
7360
+ return;
7361
+ }
7362
+ const handleVisibility = () => {
7363
+ const howl = currentRef.current?.handle.howl;
7364
+ if (document.hidden) {
7365
+ howl?.pause();
7366
+ for (const slot of outgoingRef.current) {
7367
+ slot.handle.howl.pause();
7368
+ }
7369
+ return;
7370
+ }
7371
+ if (playingRef.current && howl) {
7372
+ howl.play();
7373
+ }
7374
+ };
7375
+ document.addEventListener("visibilitychange", handleVisibility);
7376
+ return () => {
7377
+ document.removeEventListener("visibilitychange", handleVisibility);
7378
+ };
7379
+ }, [pauseWhenHidden, trackKey]);
7380
+ return null;
7381
+ }
7382
+
4774
7383
  // src/pano-filter/pano-filter.tsx
4775
- import { useContext as useContext15, useEffect as useEffect13, useMemo as useMemo8 } from "react";
7384
+ import { useContext as useContext16, useEffect as useEffect14, useMemo as useMemo8 } from "react";
4776
7385
  function PanoFilter({
4777
7386
  preset = "none",
4778
7387
  intensity,
4779
7388
  enabled = true
4780
7389
  }) {
4781
- const host = useContext15(PanoFilterHostContext);
7390
+ const host = useContext16(PanoFilterHostContext);
4782
7391
  if (!host) {
4783
7392
  throw new Error("<PanoFilter> must be rendered inside <PanoViewer>.");
4784
7393
  }
@@ -4786,13 +7395,13 @@ function PanoFilter({
4786
7395
  () => resolvePanoFilterSnapshot({ preset, intensity, enabled }),
4787
7396
  [enabled, intensity, preset]
4788
7397
  );
4789
- useEffect13(() => {
7398
+ useEffect14(() => {
4790
7399
  claimPanoFilter(host);
4791
7400
  return () => {
4792
7401
  releasePanoFilter(host);
4793
7402
  };
4794
7403
  }, [host]);
4795
- useEffect13(() => {
7404
+ useEffect14(() => {
4796
7405
  setPanoFilterSnapshot(host, snapshot);
4797
7406
  }, [host, snapshot]);
4798
7407
  return null;
@@ -4803,20 +7412,20 @@ import { useFrame as useFrame6, useThree as useThree9 } from "@react-three/fiber
4803
7412
  import {
4804
7413
  forwardRef as forwardRef3,
4805
7414
  useCallback as useCallback7,
4806
- useContext as useContext16,
4807
- useEffect as useEffect14,
7415
+ useContext as useContext17,
7416
+ useEffect as useEffect15,
4808
7417
  useImperativeHandle as useImperativeHandle3,
4809
- useRef as useRef13,
7418
+ useRef as useRef14,
4810
7419
  useState as useState6
4811
7420
  } from "react";
4812
7421
 
4813
7422
  // src/gyro-orientation.ts
4814
- import { Euler as Euler2, MathUtils as MathUtils3, Quaternion, Vector3 as Vector35 } from "three";
7423
+ import { Euler as Euler2, MathUtils as MathUtils4, Quaternion, Vector3 as Vector36 } from "three";
4815
7424
  var DEVICE_FORWARD_CORRECTION = new Quaternion().setFromAxisAngle(
4816
- new Vector35(1, 0, 0),
7425
+ new Vector36(1, 0, 0),
4817
7426
  -Math.PI / 2
4818
7427
  );
4819
- var SCREEN_AXIS = new Vector35(0, 0, 1);
7428
+ var SCREEN_AXIS = new Vector36(0, 0, 1);
4820
7429
  function getScreenOrientationAngle() {
4821
7430
  if (typeof window === "undefined") {
4822
7431
  return 0;
@@ -4831,30 +7440,30 @@ function getScreenOrientationAngle() {
4831
7440
  function deviceOrientationToQuaternion(sample, screenOrientation) {
4832
7441
  const alpha = Number.isFinite(sample.compassHeading) ? 360 - sample.compassHeading : sample.alpha;
4833
7442
  const deviceEuler = new Euler2(
4834
- MathUtils3.degToRad(sample.beta),
4835
- MathUtils3.degToRad(alpha),
4836
- MathUtils3.degToRad(-sample.gamma),
7443
+ MathUtils4.degToRad(sample.beta),
7444
+ MathUtils4.degToRad(alpha),
7445
+ MathUtils4.degToRad(-sample.gamma),
4837
7446
  "YXZ"
4838
7447
  );
4839
7448
  const screenCorrection = new Quaternion().setFromAxisAngle(
4840
7449
  SCREEN_AXIS,
4841
- -MathUtils3.degToRad(screenOrientation)
7450
+ -MathUtils4.degToRad(screenOrientation)
4842
7451
  );
4843
7452
  return new Quaternion().setFromEuler(deviceEuler).multiply(DEVICE_FORWARD_CORRECTION).multiply(screenCorrection).normalize();
4844
7453
  }
4845
7454
  function quaternionToGyroPose(quaternion) {
4846
7455
  const euler = new Euler2().setFromQuaternion(quaternion, "YXZ");
4847
7456
  return {
4848
- yaw: MathUtils3.radToDeg(-euler.y),
4849
- pitch: MathUtils3.radToDeg(euler.x),
4850
- roll: MathUtils3.radToDeg(euler.z)
7457
+ yaw: MathUtils4.radToDeg(-euler.y),
7458
+ pitch: MathUtils4.radToDeg(euler.x),
7459
+ roll: MathUtils4.radToDeg(euler.z)
4851
7460
  };
4852
7461
  }
4853
7462
  function createRelativeCalibration(deviceQuaternion, yaw, pitch) {
4854
7463
  const targetQuaternion = new Quaternion().setFromEuler(
4855
7464
  new Euler2(
4856
- MathUtils3.degToRad(pitch),
4857
- MathUtils3.degToRad(-yaw),
7465
+ MathUtils4.degToRad(pitch),
7466
+ MathUtils4.degToRad(-yaw),
4858
7467
  0,
4859
7468
  "YXZ"
4860
7469
  )
@@ -4908,24 +7517,24 @@ var Gyro = forwardRef3(function Gyro2({
4908
7517
  onDisable,
4909
7518
  onDenied
4910
7519
  }, ref) {
4911
- const controlsRef = useContext16(PanoramaViewContext);
4912
- const eventBus = useContext16(PanoEventBusContext);
7520
+ const controlsRef = useContext17(PanoramaViewContext);
7521
+ const eventBus = useContext17(PanoEventBusContext);
4913
7522
  const { gl } = useThree9();
4914
7523
  const [internallyDisabled, setInternallyDisabled] = useState6(false);
4915
- const availableRef = useRef13(false);
4916
- const availabilityReportedRef = useRef13(null);
4917
- const activeRef = useRef13(false);
4918
- const permissionRef = useRef13(deviceOrientationPermissionState);
4919
- const absoluteEventSourceRef = useRef13(null);
4920
- const rawQuaternionRef = useRef13(null);
4921
- const calibrationRef = useRef13(null);
4922
- const absoluteOffsetRef = useRef13({ yaw: 0, pitch: 0 });
4923
- const screenAngleRef = useRef13(getScreenOrientationAngle());
4924
- const startPoseRef = useRef13(null);
4925
- const enabledAtRef = useRef13(0);
4926
- const filteredPoseRef = useRef13(null);
4927
- const lastAppliedPoseRef = useRef13(null);
4928
- const callbacksRef = useRef13({
7524
+ const availableRef = useRef14(false);
7525
+ const availabilityReportedRef = useRef14(null);
7526
+ const activeRef = useRef14(false);
7527
+ const permissionRef = useRef14(deviceOrientationPermissionState);
7528
+ const absoluteEventSourceRef = useRef14(null);
7529
+ const rawQuaternionRef = useRef14(null);
7530
+ const calibrationRef = useRef14(null);
7531
+ const absoluteOffsetRef = useRef14({ yaw: 0, pitch: 0 });
7532
+ const screenAngleRef = useRef14(getScreenOrientationAngle());
7533
+ const startPoseRef = useRef14(null);
7534
+ const enabledAtRef = useRef14(0);
7535
+ const filteredPoseRef = useRef14(null);
7536
+ const lastAppliedPoseRef = useRef14(null);
7537
+ const callbacksRef = useRef14({
4929
7538
  onAvailable,
4930
7539
  onUnavailable,
4931
7540
  onEnable,
@@ -5070,22 +7679,22 @@ var Gyro = forwardRef3(function Gyro2({
5070
7679
  }),
5071
7680
  [requestPermission, resetSensor]
5072
7681
  );
5073
- useEffect14(() => {
7682
+ useEffect15(() => {
5074
7683
  if (!enabled) {
5075
7684
  setInternallyDisabled(false);
5076
7685
  }
5077
7686
  }, [enabled]);
5078
- useEffect14(() => {
7687
+ useEffect15(() => {
5079
7688
  const supported = typeof window !== "undefined" && window.isSecureContext && typeof DeviceOrientationEvent !== "undefined" && (desktopSupport || isMobileDevice());
5080
7689
  setAvailable(supported);
5081
7690
  return () => {
5082
7691
  availableRef.current = false;
5083
7692
  };
5084
7693
  }, [desktopSupport, setAvailable]);
5085
- useEffect14(() => {
7694
+ useEffect15(() => {
5086
7695
  controlsRef.current?.setGyroTouchMode(touchMode);
5087
7696
  }, [controlsRef, touchMode]);
5088
- useEffect14(() => {
7697
+ useEffect15(() => {
5089
7698
  if (!enabled || internallyDisabled || touchMode !== "disablegyro") {
5090
7699
  return;
5091
7700
  }
@@ -5099,7 +7708,7 @@ var Gyro = forwardRef3(function Gyro2({
5099
7708
  gl.domElement.removeEventListener("pointerdown", onPointerDown);
5100
7709
  };
5101
7710
  }, [enabled, gl, internallyDisabled, touchMode]);
5102
- useEffect14(() => {
7711
+ useEffect15(() => {
5103
7712
  if (!enabled || internallyDisabled || !availableRef.current) {
5104
7713
  deactivate();
5105
7714
  return;
@@ -5264,11 +7873,11 @@ import { useThree as useThree12 } from "@react-three/fiber";
5264
7873
  import {
5265
7874
  forwardRef as forwardRef4,
5266
7875
  useCallback as useCallback8,
5267
- useContext as useContext18,
5268
- useEffect as useEffect18,
7876
+ useContext as useContext19,
7877
+ useEffect as useEffect19,
5269
7878
  useImperativeHandle as useImperativeHandle4,
5270
7879
  useMemo as useMemo10,
5271
- useRef as useRef17,
7880
+ useRef as useRef18,
5272
7881
  useState as useState7
5273
7882
  } from "react";
5274
7883
 
@@ -5293,12 +7902,12 @@ async function detectWebVRCapabilities() {
5293
7902
 
5294
7903
  // src/webvr/reticle.tsx
5295
7904
  import { useFrame as useFrame7, useThree as useThree10 } from "@react-three/fiber";
5296
- import { useRef as useRef14 } from "react";
7905
+ import { useRef as useRef15 } from "react";
5297
7906
  import {
5298
7907
  DoubleSide,
5299
7908
  Raycaster as Raycaster2,
5300
7909
  Vector2 as Vector22,
5301
- Vector3 as Vector36
7910
+ Vector3 as Vector37
5302
7911
  } from "three";
5303
7912
  import { jsx as jsx12, jsxs as jsxs7 } from "react/jsx-runtime";
5304
7913
  var CENTER_NDC = new Vector22(0, 0);
@@ -5384,13 +7993,13 @@ function WebVRReticle({
5384
7993
  dwellMs,
5385
7994
  visible
5386
7995
  }) {
5387
- const groupRef = useRef14(null);
5388
- const ringMeshRef = useRef14(null);
5389
- const directionRef = useRef14(new Vector36());
5390
- const raycasterRef = useRef14(new Raycaster2());
5391
- const hoveredRef = useRef14(null);
5392
- const dwellRef = useRef14(0);
5393
- const clickedRef = useRef14(false);
7996
+ const groupRef = useRef15(null);
7997
+ const ringMeshRef = useRef15(null);
7998
+ const directionRef = useRef15(new Vector37());
7999
+ const raycasterRef = useRef15(new Raycaster2());
8000
+ const hoveredRef = useRef15(null);
8001
+ const dwellRef = useRef15(0);
8002
+ const clickedRef = useRef15(false);
5394
8003
  const { camera, gl, scene } = useThree10();
5395
8004
  useFrame7((_, deltaSeconds) => {
5396
8005
  const group = groupRef.current;
@@ -5553,7 +8162,7 @@ function WebVRReticle({
5553
8162
 
5554
8163
  // src/webvr/stereo.tsx
5555
8164
  import { useFrame as useFrame8, useThree as useThree11 } from "@react-three/fiber";
5556
- import { useContext as useContext17, useEffect as useEffect15, useMemo as useMemo9, useRef as useRef15 } from "react";
8165
+ import { useContext as useContext18, useEffect as useEffect16, useMemo as useMemo9, useRef as useRef16 } from "react";
5557
8166
  import {
5558
8167
  Mesh as Mesh2,
5559
8168
  OrthographicCamera,
@@ -5639,25 +8248,25 @@ function WebVRStereoRenderer({
5639
8248
  screensize
5640
8249
  }) {
5641
8250
  const { camera, gl } = useThree11();
5642
- const runtime = useContext17(WebVRRuntimeContext);
5643
- const fallbackStereoRef = useRef15(null);
8251
+ const runtime = useContext18(WebVRRuntimeContext);
8252
+ const fallbackStereoRef = useRef16(null);
5644
8253
  if (!fallbackStereoRef.current) {
5645
8254
  fallbackStereoRef.current = new StereoCamera2();
5646
8255
  }
5647
8256
  const stereo = runtime?.stereoView.stereo ?? fallbackStereoRef.current;
5648
- const stereoRef = useRef15(stereo);
8257
+ const stereoRef = useRef16(stereo);
5649
8258
  stereoRef.current = stereo;
5650
8259
  const resources = useMemo9(createDistortionResources, []);
5651
- const drawingSizeRef = useRef15(new Vector23());
5652
- const viewportRef = useRef15(new Vector4());
5653
- const scissorRef = useRef15(new Vector4());
5654
- const originalFovRef = useRef15(null);
5655
- const stereoActiveRef = useRef15(false);
5656
- const profileRef = useRef15(profile);
5657
- const screensizeRef = useRef15(screensize);
8260
+ const drawingSizeRef = useRef16(new Vector23());
8261
+ const viewportRef = useRef16(new Vector4());
8262
+ const scissorRef = useRef16(new Vector4());
8263
+ const originalFovRef = useRef16(null);
8264
+ const stereoActiveRef = useRef16(false);
8265
+ const profileRef = useRef16(profile);
8266
+ const screensizeRef = useRef16(screensize);
5658
8267
  profileRef.current = profile;
5659
8268
  screensizeRef.current = screensize;
5660
- useEffect15(
8269
+ useEffect16(
5661
8270
  () => () => {
5662
8271
  resources.geometry.dispose();
5663
8272
  resources.material.dispose();
@@ -5665,7 +8274,7 @@ function WebVRStereoRenderer({
5665
8274
  },
5666
8275
  [resources]
5667
8276
  );
5668
- useEffect15(() => {
8277
+ useEffect16(() => {
5669
8278
  const originalRender = gl.render.bind(gl);
5670
8279
  gl.render = (sceneToRender, cameraToRender) => {
5671
8280
  if (!stereoActiveRef.current || !(cameraToRender instanceof PerspectiveCamera2)) {
@@ -5729,7 +8338,7 @@ function WebVRStereoRenderer({
5729
8338
  gl.render = originalRender;
5730
8339
  };
5731
8340
  }, [gl, resources]);
5732
- useEffect15(
8341
+ useEffect16(
5733
8342
  () => () => {
5734
8343
  if (runtime) {
5735
8344
  runtime.stereoView.active = false;
@@ -5764,7 +8373,7 @@ function WebVRStereoRenderer({
5764
8373
  }
5765
8374
 
5766
8375
  // src/webvr/pointerlock.ts
5767
- import { useEffect as useEffect16, useRef as useRef16 } from "react";
8376
+ import { useEffect as useEffect17, useRef as useRef17 } from "react";
5768
8377
  var POINTER_LOCK_CURSOR_ID = "webvr:pointerlock";
5769
8378
  async function requestWebVRPointerLock(element) {
5770
8379
  if (typeof document === "undefined") {
@@ -5797,11 +8406,11 @@ function exitWebVRPointerLock(element) {
5797
8406
  }
5798
8407
  function useWebVRPointerLock(enabled, element) {
5799
8408
  const cursor = usePanoCursor();
5800
- const cursorRef = useRef16(cursor);
5801
- const enabledRef = useRef16(enabled);
8409
+ const cursorRef = useRef17(cursor);
8410
+ const enabledRef = useRef17(enabled);
5802
8411
  cursorRef.current = cursor;
5803
8412
  enabledRef.current = enabled;
5804
- useEffect16(() => {
8413
+ useEffect17(() => {
5805
8414
  if (!enabled || !element) {
5806
8415
  return;
5807
8416
  }
@@ -5831,7 +8440,7 @@ function useWebVRPointerLock(enabled, element) {
5831
8440
  }
5832
8441
 
5833
8442
  // src/webvr/wakelock.ts
5834
- import { useEffect as useEffect17 } from "react";
8443
+ import { useEffect as useEffect18 } from "react";
5835
8444
 
5836
8445
  // src/webvr/wakelock-fallback.ts
5837
8446
  var WEBVR_WAKELOCK_FALLBACK_VIDEO_BASE64 = "AAAAIGZ0eXBpc29tAAACAGlzb21pc28yYXZjMW1wNDEAAAbBbW9vdgAAAGxtdmhkAAAAAAAAAAAAAAAAAAAD6AAAD4AAAQAAAQAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAwAAAxt0cmFrAAAAXHRraGQAAAADAAAAAAAAAAAAAAABAAAAAAAAAggAAAAAAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAABAAAAAABAAAAAQAAAAAAAkZWR0cwAAABxlbHN0AAAAAAAAAAEAAAIIAAAEAAABAAAAAAKTbWRpYQAAACBtZGhkAAAAAAAAAAAAAAAAAAAyAAAAGgBVxAAAAAAALWhkbHIAAAAAAAAAAHZpZGUAAAAAAAAAAAAAAABWaWRlb0hhbmRsZXIAAAACPm1pbmYAAAAUdm1oZAAAAAEAAAAAAAAAAAAAACRkaW5mAAAAHGRyZWYAAAAAAAAAAQAAAAx1cmwgAAAAAQAAAf5zdGJsAAAAvnN0c2QAAAAAAAAAAQAAAK5hdmMxAAAAAAAAAAEAAAAAAAAAAAAAAAAAAAAAABAAEABIAAAASAAAAAAAAAABFUxhdmM2Mi4xMS4xMDAgbGlieDI2NAAAAAAAAAAAAAAAGP//AAAANGF2Y0MBZAAK/+EAF2dkAAqs2V7ARAAAAwAEAAADAMg8SJZYAQAGaOvjyyLA/fj4AAAAABBwYXNwAAAAAQAAAAEAAAAUYnRydAAAAAAAADQ5AAAAAAAAABhzdHRzAAAAAAAAAAEAAAANAAACAAAAABRzdHNzAAAAAAAAAAEAAAABAAAAeGN0dHMAAAAAAAAADQAAAAEAAAQAAAAAAQAACgAAAAABAAAEAAAAAAEAAAAAAAAAAQAAAgAAAAABAAAKAAAAAAEAAAQAAAAAAQAAAAAAAAABAAACAAAAAAEAAAoAAAAAAQAABAAAAAABAAAAAAAAAAEAAAIAAAAAKHN0c2MAAAAAAAAAAgAAAAEAAAADAAAAAQAAAAUAAAABAAAAAQAAAEhzdHN6AAAAAAAAAAAAAAANAAACxQAAAAwAAAAMAAAADAAAAAwAAAASAAAADgAAAAwAAAAMAAAAEgAAAA4AAAAMAAAADAAAACRzdGNvAAAAAAAAAAUAAAcGAAAJ5wAAChUAAAo/AAAKbwAAAtF0cmFrAAAAXHRraGQAAAADAAAAAAAAAAAAAAACAAAAAAAAD4AAAAAAAAAAAAAAAAEBAAAAAAEAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAAkZWR0cwAAABxlbHN0AAAAAAAAAAEAAA+AAAAEAAABAAAAAAJJbWRpYQAAACBtZGhkAAAAAAAAAAAAAAAAAAAfQAAAgABVxAAAAAAALWhkbHIAAAAAAAAAAHNvdW4AAAAAAAAAAAAAAABTb3VuZEhhbmRsZXIAAAAB9G1pbmYAAAAQc21oZAAAAAAAAAAAAAAAJGRpbmYAAAAcZHJlZgAAAAAAAAABAAAADHVybCAAAAABAAABuHN0YmwAAAB+c3RzZAAAAAAAAAABAAAAbm1wNGEAAAAAAAAAAQAAAAAAAAAAAAEAEAAAAAAfQAAAAAAANmVzZHMAAAAAA4CAgCUAAgAEgICAF0AVAAAAAAAfQAAAARsFgICABRWIVuUABoCAgAECAAAAFGJ0cnQAAAAAAAAfQAAAARsAAAAYc3R0cwAAAAAAAAABAAAAIAAABAAAAAAoc3RzYwAAAAAAAAACAAAAAQAAAAEAAAABAAAABgAAABsAAAABAAAAlHN0c3oAAAAAAAAAAAAAACAAAAAVAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAChzdGNvAAAAAAAAAAYAAAbxAAAJ4wAAChEAAAo7AAAKawAACnsAAAAac2dwZAEAAAByb2xsAAAAAgAAAAH//wAAABxzYmdwAAAAAHJvbGwAAAABAAAAIAAAAAEAAABhdWR0YQAAAFltZXRhAAAAAAAAACFoZGxyAAAAAAAAAABtZGlyYXBwbAAAAAAAAAAAAAAAACxpbHN0AAAAJKl0b28AAAAcZGF0YQAAAAEAAAAATGF2ZjYyLjMuMTAwAAAACGZyZWUAAAP+bWRhdN4CAExhdmM2Mi4xMS4xMDAAAjBADgAAAq4GBf//qtxF6b3m2Ui3lizYINkj7u94MjY0IC0gY29yZSAxNjUgcjMyMjIgYjM1NjA1YSAtIEguMjY0L01QRUctNCBBVkMgY29kZWMgLSBDb3B5bGVmdCAyMDAzLTIwMjUgLSBodHRwOi8vd3d3LnZpZGVvbGFuLm9yZy94MjY0Lmh0bWwgLSBvcHRpb25zOiBjYWJhYz0xIHJlZj0zIGRlYmxvY2s9MTowOjAgYW5hbHlzZT0weDM6MHgxMTMgbWU9aGV4IHN1Ym1lPTcgcHN5PTEgcHN5X3JkPTEuMDA6MC4wMCBtaXhlZF9yZWY9MSBtZV9yYW5nZT0xNiBjaHJvbWFfbWU9MSB0cmVsbGlzPTEgOHg4ZGN0PTEgY3FtPTAgZGVhZHpvbmU9MjEsMTEgZmFzdF9wc2tpcD0xIGNocm9tYV9xcF9vZmZzZXQ9LTIgdGhyZWFkcz0xIGxvb2thaGVhZF90aHJlYWRzPTEgc2xpY2VkX3RocmVhZHM9MCBucj0wIGRlY2ltYXRlPTEgaW50ZXJsYWNlZD0wIGJsdXJheV9jb21wYXQ9MCBjb25zdHJhaW5lZF9pbnRyYT0wIGJmcmFtZXM9MyBiX3B5cmFtaWQ9MiBiX2FkYXB0PTEgYl9iaWFzPTAgZGlyZWN0PTEgd2VpZ2h0Yj0xIG9wZW5fZ29wPTAgd2VpZ2h0cD0yIGtleWludD0yNTAga2V5aW50X21pbj0yNSBzY2VuZWN1dD00MCBpbnRyYV9yZWZyZXNoPTAgcmNfbG9va2FoZWFkPTQwIHJjPWNyZiBtYnRyZWU9MSBjcmY9MjMuMCBxY29tcD0wLjYwIHFwbWluPTAgcXBtYXg9NjkgcXBzdGVwPTQgaXBfcmF0aW89MS40MCBhcT0xOjEuMDAAgAAAAA9liIQAO//+906/AptUwmEAAAAIQZokbEN//uAAAAAIQZ5CeIX/wYEBGCAHAAAACAGeYXRCv8SAAAAACAGeY2pCv8SBAAAADkGaaEmoQWiZTAhn//7hARggBwAAAApBnoZFESwv/8GBAAAACAGepXRCv8SBAAAACAGep2pCv8SAARggBwAAAA5BmqxJqEFsmUwIV//+wAAAAApBnspFFSwv/8GBAAAACAGe6XRCv8SAARggBwAAAAgBnutqQr/EgAEYIAcBGCAHARggBwEYIAcBGCAHARggBwEYIAcBGCAHARggBwEYIAcBGCAHARggBwEYIAcBGCAHARggBwEYIAcBGCAHARggBwEYIAcBGCAHARggBwEYIAcBGCAHARggBwEYIAcBGCAHARggBw==";
@@ -5965,7 +8574,7 @@ function releaseWebVRWakeLock() {
5965
8574
  stopFallbackVideo();
5966
8575
  }
5967
8576
  function useWebVRWakeLock(enabled) {
5968
- useEffect17(() => {
8577
+ useEffect18(() => {
5969
8578
  if (!enabled) {
5970
8579
  return;
5971
8580
  }
@@ -6013,24 +8622,24 @@ var WebVR = forwardRef4(function WebVR2({
6013
8622
  onDenied,
6014
8623
  onUnknownDevice
6015
8624
  }, ref) {
6016
- const runtime = useContext18(WebVRRuntimeContext);
6017
- const controlsRef = useContext18(PanoramaViewContext);
6018
- const eventBus = useContext18(PanoEventBusContext);
8625
+ const runtime = useContext19(WebVRRuntimeContext);
8626
+ const controlsRef = useContext19(PanoramaViewContext);
8627
+ const eventBus = useContext19(PanoEventBusContext);
6019
8628
  const gl = useThree12((state) => state.gl);
6020
- const gyroRef = useRef17(null);
6021
- const capabilitiesRef = useRef17({
8629
+ const gyroRef = useRef18(null);
8630
+ const capabilitiesRef = useRef18({
6022
8631
  mobile: false,
6023
8632
  sensor: false,
6024
8633
  webxr: false
6025
8634
  });
6026
- const availableRef = useRef17(false);
6027
- const modeRef = useRef17(null);
6028
- const webXRSessionRef = useRef17(null);
8635
+ const availableRef = useRef18(false);
8636
+ const modeRef = useRef18(null);
8637
+ const webXRSessionRef = useRef18(null);
6029
8638
  const [mode, setMode] = useState7(null);
6030
8639
  const [settings, setSettings] = useState7(
6031
8640
  () => initializeSettings(screensize, profile)
6032
8641
  );
6033
- const callbacksRef = useRef17({
8642
+ const callbacksRef = useRef18({
6034
8643
  onAvailable,
6035
8644
  onDenied,
6036
8645
  onEnterVR,
@@ -6239,7 +8848,7 @@ var WebVR = forwardRef4(function WebVR2({
6239
8848
  }),
6240
8849
  [enterVR, exitVR, requestPermission, toggleVR]
6241
8850
  );
6242
- useEffect18(() => {
8851
+ useEffect19(() => {
6243
8852
  let active = true;
6244
8853
  void detectWebVRCapabilities().then((capabilities) => {
6245
8854
  if (!active) {
@@ -6261,7 +8870,7 @@ var WebVR = forwardRef4(function WebVR2({
6261
8870
  active = false;
6262
8871
  };
6263
8872
  }, [desktopSupport, eventBus, fakeSupport, host, mobileVr]);
6264
- useEffect18(() => {
8873
+ useEffect19(() => {
6265
8874
  host.controller = controller;
6266
8875
  return () => {
6267
8876
  if (host.controller === controller) {
@@ -6270,10 +8879,10 @@ var WebVR = forwardRef4(function WebVR2({
6270
8879
  }
6271
8880
  };
6272
8881
  }, [controller, host]);
6273
- useEffect18(() => {
8882
+ useEffect19(() => {
6274
8883
  updateWebVRHost(host, { chrome, mode, settings });
6275
8884
  }, [chrome, host, mode, settings]);
6276
- useEffect18(() => {
8885
+ useEffect19(() => {
6277
8886
  if (mode !== "fake") {
6278
8887
  return;
6279
8888
  }
@@ -6297,7 +8906,7 @@ var WebVR = forwardRef4(function WebVR2({
6297
8906
  document.removeEventListener("mousemove", onMouseMove);
6298
8907
  };
6299
8908
  }, [controlsRef, gl.domElement, mode, mousePointerLock]);
6300
- useEffect18(
8909
+ useEffect19(
6301
8910
  () => () => {
6302
8911
  const session2 = webXRSessionRef.current;
6303
8912
  if (session2) {
@@ -6351,12 +8960,12 @@ var WebVR = forwardRef4(function WebVR2({
6351
8960
 
6352
8961
  // src/sphere.tsx
6353
8962
  import { useThree as useThree13 } from "@react-three/fiber";
6354
- import { useEffect as useEffect19, useMemo as useMemo12, useRef as useRef19, useState as useState8 } from "react";
8963
+ import { useEffect as useEffect20, useMemo as useMemo12, useRef as useRef20, useState as useState8 } from "react";
6355
8964
  import {
6356
8965
  BackSide as BackSide2,
6357
8966
  LinearFilter,
6358
8967
  LinearMipmapLinearFilter,
6359
- MathUtils as MathUtils4,
8968
+ MathUtils as MathUtils5,
6360
8969
  RepeatWrapping,
6361
8970
  SRGBColorSpace,
6362
8971
  TextureLoader
@@ -6384,7 +8993,7 @@ function resolveUrlAgainstFile(fileUrl, path) {
6384
8993
  }
6385
8994
 
6386
8995
  // src/pano-filter/pano-basic-material.tsx
6387
- import { useLayoutEffect as useLayoutEffect2, useMemo as useMemo11, useRef as useRef18 } from "react";
8996
+ import { useLayoutEffect as useLayoutEffect2, useMemo as useMemo11, useRef as useRef19 } from "react";
6388
8997
 
6389
8998
  // src/pano-filter/shaders.ts
6390
8999
  var GLSL_FILTER_COMMON = `
@@ -6544,9 +9153,9 @@ function PanoBasicMaterial({
6544
9153
  toneMapped = false
6545
9154
  }) {
6546
9155
  const snapshot = usePanoFilterSnapshot();
6547
- const materialRef = useRef18(null);
6548
- const intensityRef = useRef18(snapshot.intensity);
6549
- const intensityUniformRef = useRef18(null);
9156
+ const materialRef = useRef19(null);
9157
+ const intensityRef = useRef19(snapshot.intensity);
9158
+ const intensityUniformRef = useRef19(null);
6550
9159
  intensityRef.current = snapshot.intensity;
6551
9160
  const active = isPanoFilterActive(snapshot);
6552
9161
  const preset = snapshot.preset;
@@ -6601,11 +9210,11 @@ function PanoBasicMaterial({
6601
9210
  import { jsx as jsx15, jsxs as jsxs9 } from "react/jsx-runtime";
6602
9211
  function useEquirectTexture(url, anisotropy, generateMipmaps, onLoad, onError) {
6603
9212
  const [texture, setTexture] = useState8(null);
6604
- const onLoadRef = useRef19(onLoad);
6605
- const onErrorRef = useRef19(onError);
9213
+ const onLoadRef = useRef20(onLoad);
9214
+ const onErrorRef = useRef20(onError);
6606
9215
  onLoadRef.current = onLoad;
6607
9216
  onErrorRef.current = onError;
6608
- useEffect19(() => {
9217
+ useEffect20(() => {
6609
9218
  if (!url) {
6610
9219
  setTexture(null);
6611
9220
  return;
@@ -6644,7 +9253,7 @@ function useEquirectTexture(url, anisotropy, generateMipmaps, onLoad, onError) {
6644
9253
  active = false;
6645
9254
  };
6646
9255
  }, [anisotropy, generateMipmaps, url]);
6647
- useEffect19(
9256
+ useEffect20(
6648
9257
  () => () => {
6649
9258
  texture?.dispose();
6650
9259
  },
@@ -6683,11 +9292,11 @@ function Sphere({
6683
9292
  onPreviewError
6684
9293
  );
6685
9294
  const displayTexture = texture ?? previewTexture;
6686
- const readyRef = useRef19(false);
6687
- useEffect19(() => {
9295
+ const readyRef = useRef20(false);
9296
+ useEffect20(() => {
6688
9297
  readyRef.current = false;
6689
9298
  }, [resolvedPreviewUrl, src]);
6690
- useEffect19(() => {
9299
+ useEffect20(() => {
6691
9300
  if (!displayTexture || readyRef.current) {
6692
9301
  return;
6693
9302
  }
@@ -6700,7 +9309,7 @@ function Sphere({
6700
9309
  return /* @__PURE__ */ jsxs9(
6701
9310
  "mesh",
6702
9311
  {
6703
- rotation: [0, MathUtils4.degToRad(90 + yawOffset), 0],
9312
+ rotation: [0, MathUtils5.degToRad(90 + yawOffset), 0],
6704
9313
  visible,
6705
9314
  children: [
6706
9315
  /* @__PURE__ */ jsx15("sphereGeometry", { args: [DEFAULT_PANORAMA_RADIUS, 128, 64] }),
@@ -6721,18 +9330,18 @@ function Sphere({
6721
9330
  import { useThree as useThree14 } from "@react-three/fiber";
6722
9331
  import {
6723
9332
  useCallback as useCallback9,
6724
- useContext as useContext19,
6725
- useEffect as useEffect20,
9333
+ useContext as useContext20,
9334
+ useEffect as useEffect21,
6726
9335
  useLayoutEffect as useLayoutEffect3,
6727
9336
  useMemo as useMemo13,
6728
- useRef as useRef20,
9337
+ useRef as useRef21,
6729
9338
  useState as useState9
6730
9339
  } from "react";
6731
9340
  import {
6732
9341
  BackSide as BackSide3,
6733
9342
  LinearFilter as LinearFilter2,
6734
9343
  LinearMipmapLinearFilter as LinearMipmapLinearFilter2,
6735
- MathUtils as MathUtils5,
9344
+ MathUtils as MathUtils6,
6736
9345
  RepeatWrapping as RepeatWrapping2,
6737
9346
  SRGBColorSpace as SRGBColorSpace2,
6738
9347
  TextureLoader as TextureLoader2,
@@ -6824,9 +9433,9 @@ function applyEquirectangularLayout(texture, anisotropy) {
6824
9433
  function usePosterTexture(poster, onError) {
6825
9434
  const gl = useThree14((state) => state.gl);
6826
9435
  const [texture, setTexture] = useState9(null);
6827
- const onErrorRef = useRef20(onError);
9436
+ const onErrorRef = useRef21(onError);
6828
9437
  onErrorRef.current = onError;
6829
- useEffect20(() => {
9438
+ useEffect21(() => {
6830
9439
  let active = true;
6831
9440
  setTexture(null);
6832
9441
  if (!poster) {
@@ -6863,7 +9472,7 @@ function usePosterTexture(poster, onError) {
6863
9472
  active = false;
6864
9473
  };
6865
9474
  }, [gl, poster]);
6866
- useEffect20(
9475
+ useEffect21(
6867
9476
  () => () => {
6868
9477
  texture?.dispose();
6869
9478
  },
@@ -6921,8 +9530,8 @@ function PanoVideo({
6921
9530
  onTrackChange
6922
9531
  }) {
6923
9532
  const gl = useThree14((state) => state.gl);
6924
- const host = useContext19(PanoVideoHostContext);
6925
- const overlay = useContext19(PanoChromeOverlayContext);
9533
+ const host = useContext20(PanoVideoHostContext);
9534
+ const overlay = useContext20(PanoChromeOverlayContext);
6926
9535
  const variants = useMemo13(
6927
9536
  () => resolvePanoVideoVariants({ poster, src, variants: variantsProp }),
6928
9537
  [poster, src, variantsProp]
@@ -6942,17 +9551,17 @@ function PanoVideo({
6942
9551
  () => captionsEnabled ? defaultPanoVideoTrackId(tracks) : null
6943
9552
  );
6944
9553
  const [ready, setReady] = useState9(false);
6945
- const autoPlayRef = useRef20(autoPlay);
9554
+ const autoPlayRef = useRef21(autoPlay);
6946
9555
  autoPlayRef.current = autoPlay;
6947
- const blockedRef = useRef20(false);
6948
- const captionAppearanceOverrideRef = useRef20(
9556
+ const blockedRef = useRef21(false);
9557
+ const captionAppearanceOverrideRef = useRef21(
6949
9558
  {}
6950
9559
  );
6951
- const mediaCapabilitiesRef = useRef20({
9560
+ const mediaCapabilitiesRef = useRef21({
6952
9561
  volumeAdjustable: true,
6953
9562
  playbackRates: [...DEFAULT_PANO_VIDEO_PLAYBACK_RATES]
6954
9563
  });
6955
- const storeRef = useRef20(null);
9564
+ const storeRef = useRef21(null);
6956
9565
  if (!storeRef.current) {
6957
9566
  storeRef.current = {
6958
9567
  snapshot: {
@@ -6962,7 +9571,7 @@ function PanoVideo({
6962
9571
  listeners: /* @__PURE__ */ new Set()
6963
9572
  };
6964
9573
  }
6965
- const actionsRef = useRef20({
9574
+ const actionsRef = useRef21({
6966
9575
  play: async () => {
6967
9576
  },
6968
9577
  pause: () => {
@@ -6982,12 +9591,12 @@ function PanoVideo({
6982
9591
  setCaptionAppearance: (_appearance) => {
6983
9592
  }
6984
9593
  });
6985
- const onLoadRef = useRef20(onLoad);
6986
- const onErrorRef = useRef20(onError);
6987
- const onPlaybackStateChangeRef = useRef20(onPlaybackStateChange);
6988
- const onEndedRef = useRef20(onEnded);
6989
- const onVariantChangeRef = useRef20(onVariantChange);
6990
- const onTrackChangeRef = useRef20(onTrackChange);
9594
+ const onLoadRef = useRef21(onLoad);
9595
+ const onErrorRef = useRef21(onError);
9596
+ const onPlaybackStateChangeRef = useRef21(onPlaybackStateChange);
9597
+ const onEndedRef = useRef21(onEnded);
9598
+ const onVariantChangeRef = useRef21(onVariantChange);
9599
+ const onTrackChangeRef = useRef21(onTrackChange);
6991
9600
  onLoadRef.current = onLoad;
6992
9601
  onErrorRef.current = onError;
6993
9602
  onPlaybackStateChangeRef.current = onPlaybackStateChange;
@@ -7011,7 +9620,7 @@ function PanoVideo({
7011
9620
  texture.generateMipmaps = false;
7012
9621
  return { video, texture };
7013
9622
  }, []);
7014
- useEffect20(
9623
+ useEffect21(
7015
9624
  () => () => {
7016
9625
  if (!resource) {
7017
9626
  return;
@@ -7026,13 +9635,13 @@ function PanoVideo({
7026
9635
  },
7027
9636
  [resource]
7028
9637
  );
7029
- useEffect20(() => {
9638
+ useEffect21(() => {
7030
9639
  if (!resource) {
7031
9640
  return;
7032
9641
  }
7033
9642
  resource.texture.anisotropy = gl.capabilities.getMaxAnisotropy();
7034
9643
  }, [gl, resource]);
7035
- useEffect20(() => {
9644
+ useEffect21(() => {
7036
9645
  if (!resource || !overlay?.overlayElement) {
7037
9646
  return;
7038
9647
  }
@@ -7185,10 +9794,10 @@ function PanoVideo({
7185
9794
  };
7186
9795
  emitSnapshot();
7187
9796
  }, [emitSnapshot, playbackRates, resource]);
7188
- useEffect20(() => {
9797
+ useEffect21(() => {
7189
9798
  emitSnapshot();
7190
9799
  }, [emitSnapshot]);
7191
- useEffect20(() => {
9800
+ useEffect21(() => {
7192
9801
  if (!resource || !activeVariant || !mediaKey) {
7193
9802
  return;
7194
9803
  }
@@ -7245,7 +9854,7 @@ function PanoVideo({
7245
9854
  video.removeEventListener("error", handleError);
7246
9855
  };
7247
9856
  }, [mediaKey, resource]);
7248
- useEffect20(() => {
9857
+ useEffect21(() => {
7249
9858
  if (!resource) {
7250
9859
  return;
7251
9860
  }
@@ -7335,7 +9944,7 @@ function PanoVideo({
7335
9944
  }
7336
9945
  };
7337
9946
  }, [emitSnapshot, resource]);
7338
- useEffect20(() => {
9947
+ useEffect21(() => {
7339
9948
  if (!resource) {
7340
9949
  return;
7341
9950
  }
@@ -7348,7 +9957,7 @@ function PanoVideo({
7348
9957
  video.playsInline = playsInline;
7349
9958
  video.preload = preload;
7350
9959
  }, [loop, muted, playsInline, preload, resource, volume]);
7351
- useEffect20(() => {
9960
+ useEffect21(() => {
7352
9961
  if (!resource) {
7353
9962
  return;
7354
9963
  }
@@ -7398,7 +10007,7 @@ function PanoVideo({
7398
10007
  video.removeEventListener("ratechange", handleVolume);
7399
10008
  };
7400
10009
  }, [emitSnapshot, resource]);
7401
- useEffect20(() => {
10010
+ useEffect21(() => {
7402
10011
  if (!resource) {
7403
10012
  return;
7404
10013
  }
@@ -7433,7 +10042,7 @@ function PanoVideo({
7433
10042
  video.textTracks.removeEventListener("change", applyModes);
7434
10043
  };
7435
10044
  }, [emitSnapshot, resource, trackId, tracks]);
7436
- useEffect20(() => {
10045
+ useEffect21(() => {
7437
10046
  if (!captionsEnabled) {
7438
10047
  setTrackId(null);
7439
10048
  return;
@@ -7448,7 +10057,7 @@ function PanoVideo({
7448
10057
  activeTexture ? /* @__PURE__ */ jsxs10(
7449
10058
  "mesh",
7450
10059
  {
7451
- rotation: [0, MathUtils5.degToRad(90 + yawOffset), 0],
10060
+ rotation: [0, MathUtils6.degToRad(90 + yawOffset), 0],
7452
10061
  visible,
7453
10062
  children: [
7454
10063
  /* @__PURE__ */ jsx16("sphereGeometry", { args: [DEFAULT_PANORAMA_RADIUS, 128, 64] }),
@@ -7472,10 +10081,10 @@ import { useFrame as useFrame12, useThree as useThree19 } from "@react-three/fib
7472
10081
  import {
7473
10082
  Fragment as Fragment6,
7474
10083
  useCallback as useCallback10,
7475
- useContext as useContext21,
7476
- useEffect as useEffect25,
10084
+ useContext as useContext22,
10085
+ useEffect as useEffect26,
7477
10086
  useMemo as useMemo18,
7478
- useRef as useRef24,
10087
+ useRef as useRef25,
7479
10088
  useState as useState11
7480
10089
  } from "react";
7481
10090
  import {
@@ -7532,7 +10141,7 @@ function isSnapshotTransition(preset) {
7532
10141
 
7533
10142
  // src/scene-transitions/particle-overlay.tsx
7534
10143
  import { useFrame as useFrame9, useThree as useThree15 } from "@react-three/fiber";
7535
- import { useEffect as useEffect21, useMemo as useMemo14, useRef as useRef21 } from "react";
10144
+ import { useEffect as useEffect22, useMemo as useMemo14, useRef as useRef22 } from "react";
7536
10145
  import {
7537
10146
  DoubleSide as DoubleSide2,
7538
10147
  InstancedBufferAttribute,
@@ -7540,7 +10149,7 @@ import {
7540
10149
  PlaneGeometry as PlaneGeometry3,
7541
10150
  ShaderMaterial as ShaderMaterial2,
7542
10151
  Vector2 as Vector24,
7543
- Vector3 as Vector38
10152
+ Vector3 as Vector39
7544
10153
  } from "three";
7545
10154
 
7546
10155
  // src/scene-transitions/glsl.ts
@@ -7672,10 +10281,10 @@ function ParticleOverlay({
7672
10281
  onFinish
7673
10282
  }) {
7674
10283
  const { camera } = useThree15();
7675
- const meshRef = useRef21(null);
7676
- const startRef = useRef21(null);
7677
- const finishedRef = useRef21(false);
7678
- const directionRef = useRef21(new Vector38());
10284
+ const meshRef = useRef22(null);
10285
+ const startRef = useRef22(null);
10286
+ const finishedRef = useRef22(false);
10287
+ const directionRef = useRef22(new Vector39());
7679
10288
  const geometry = useMemo14(() => createParticleGeometry(), []);
7680
10289
  const material = useMemo14(
7681
10290
  () => new ShaderMaterial2({
@@ -7693,9 +10302,9 @@ function ParticleOverlay({
7693
10302
  }),
7694
10303
  [snapshot.texture]
7695
10304
  );
7696
- useEffect21(() => () => geometry.dispose(), [geometry]);
7697
- useEffect21(() => () => material.dispose(), [material]);
7698
- useEffect21(() => {
10305
+ useEffect22(() => () => geometry.dispose(), [geometry]);
10306
+ useEffect22(() => () => material.dispose(), [material]);
10307
+ useEffect22(() => {
7699
10308
  startRef.current = null;
7700
10309
  finishedRef.current = false;
7701
10310
  material.uniforms.progress.value = 0;
@@ -7731,8 +10340,8 @@ function ParticleOverlay({
7731
10340
 
7732
10341
  // src/scene-transitions/snapshot-overlay.tsx
7733
10342
  import { useFrame as useFrame10, useThree as useThree16 } from "@react-three/fiber";
7734
- import { useEffect as useEffect22, useMemo as useMemo15, useRef as useRef22 } from "react";
7735
- import { Vector3 as Vector39 } from "three";
10343
+ import { useEffect as useEffect23, useMemo as useMemo15, useRef as useRef23 } from "react";
10344
+ import { Vector3 as Vector310 } from "three";
7736
10345
 
7737
10346
  // src/scene-transitions/snapshot-shaders.ts
7738
10347
  import { DoubleSide as DoubleSide3, ShaderMaterial as ShaderMaterial3, Vector2 as Vector25 } from "three";
@@ -8020,18 +10629,18 @@ function SnapshotOverlay({
8020
10629
  onFinish
8021
10630
  }) {
8022
10631
  const { camera, gl } = useThree16();
8023
- const meshRef = useRef22(null);
8024
- const startRef = useRef22(null);
8025
- const finishedRef = useRef22(false);
8026
- const directionRef = useRef22(new Vector39());
10632
+ const meshRef = useRef23(null);
10633
+ const startRef = useRef23(null);
10634
+ const finishedRef = useRef23(false);
10635
+ const directionRef = useRef23(new Vector310());
8027
10636
  const material = useMemo15(() => {
8028
10637
  if (!isSnapshotTransition(transition.preset)) {
8029
10638
  return null;
8030
10639
  }
8031
10640
  return createSnapshotMaterial(transition.preset, snapshot.texture);
8032
10641
  }, [snapshot.texture, transition.preset]);
8033
- useEffect22(() => () => material?.dispose(), [material]);
8034
- useEffect22(() => {
10642
+ useEffect23(() => () => material?.dispose(), [material]);
10643
+ useEffect23(() => {
8035
10644
  startRef.current = null;
8036
10645
  finishedRef.current = false;
8037
10646
  if (material) {
@@ -8115,8 +10724,8 @@ function TransitionOverlay(props) {
8115
10724
  import { useThree as useThree17 } from "@react-three/fiber";
8116
10725
  import {
8117
10726
  createContext as createContext11,
8118
- useContext as useContext20,
8119
- useEffect as useEffect23,
10727
+ useContext as useContext21,
10728
+ useEffect as useEffect24,
8120
10729
  useMemo as useMemo16
8121
10730
  } from "react";
8122
10731
 
@@ -8367,23 +10976,23 @@ function TileTextureManagerProvider({
8367
10976
  }),
8368
10977
  [anisotropy, maxConcurrentLoads, maxTextureMemoryMb]
8369
10978
  );
8370
- useEffect23(() => {
10979
+ useEffect24(() => {
8371
10980
  manager.resume();
8372
10981
  return () => manager.dispose();
8373
10982
  }, [manager]);
8374
10983
  return /* @__PURE__ */ jsx20(TileTextureManagerContext.Provider, { value: manager, children });
8375
10984
  }
8376
10985
  function useSharedTileTextureManager() {
8377
- return useContext20(TileTextureManagerContext);
10986
+ return useContext21(TileTextureManagerContext);
8378
10987
  }
8379
10988
 
8380
10989
  // src/tile/tile.tsx
8381
10990
  import { useFrame as useFrame11, useThree as useThree18 } from "@react-three/fiber";
8382
10991
  import {
8383
10992
  memo,
8384
- useEffect as useEffect24,
10993
+ useEffect as useEffect25,
8385
10994
  useMemo as useMemo17,
8386
- useRef as useRef23,
10995
+ useRef as useRef24,
8387
10996
  useState as useState10
8388
10997
  } from "react";
8389
10998
  import {
@@ -8395,7 +11004,7 @@ import {
8395
11004
  PerspectiveCamera as PerspectiveCamera4,
8396
11005
  SRGBColorSpace as SRGBColorSpace4,
8397
11006
  TextureLoader as TextureLoader4,
8398
- Vector3 as Vector311
11007
+ Vector3 as Vector312
8399
11008
  } from "three";
8400
11009
 
8401
11010
  // src/tile/face-layout.ts
@@ -8403,7 +11012,7 @@ import {
8403
11012
  Box3,
8404
11013
  Euler as Euler3,
8405
11014
  Quaternion as Quaternion2,
8406
- Vector3 as Vector310
11015
+ Vector3 as Vector311
8407
11016
  } from "three";
8408
11017
  var CUBE_FACES = ["f", "r", "b", "l", "u", "d"];
8409
11018
  var PREVIEW_FACE_ORDER = ["l", "f", "r", "b", "u", "d"];
@@ -8467,12 +11076,12 @@ function getTileBoundingBox(address, radius = CUBE_RADIUS) {
8467
11076
  const halfWidth = local.width / 2;
8468
11077
  const halfHeight = local.height / 2;
8469
11078
  const quaternion = getFaceQuaternion(address.face);
8470
- const position = new Vector310(...transform.position);
11079
+ const position = new Vector311(...transform.position);
8471
11080
  const corners = [
8472
- new Vector310(local.x - halfWidth, local.y - halfHeight, 0),
8473
- new Vector310(local.x + halfWidth, local.y - halfHeight, 0),
8474
- new Vector310(local.x - halfWidth, local.y + halfHeight, 0),
8475
- new Vector310(local.x + halfWidth, local.y + halfHeight, 0)
11081
+ new Vector311(local.x - halfWidth, local.y - halfHeight, 0),
11082
+ new Vector311(local.x + halfWidth, local.y - halfHeight, 0),
11083
+ new Vector311(local.x - halfWidth, local.y + halfHeight, 0),
11084
+ new Vector311(local.x + halfWidth, local.y + halfHeight, 0)
8476
11085
  ];
8477
11086
  for (const corner of corners) {
8478
11087
  corner.applyQuaternion(quaternion).add(position);
@@ -8590,9 +11199,9 @@ var PREVIEW_RADIUS = CUBE_RADIUS + 0.05;
8590
11199
  var SHARED_TILE_GEOMETRY = new PlaneGeometry4(1, 1);
8591
11200
  function usePreviewTexture(url, anisotropy, onError) {
8592
11201
  const [texture, setTexture] = useState10(null);
8593
- const onErrorRef = useRef23(onError);
11202
+ const onErrorRef = useRef24(onError);
8594
11203
  onErrorRef.current = onError;
8595
- useEffect24(() => {
11204
+ useEffect25(() => {
8596
11205
  if (!url) {
8597
11206
  setTexture(null);
8598
11207
  return;
@@ -8629,7 +11238,7 @@ function usePreviewTexture(url, anisotropy, onError) {
8629
11238
  active = false;
8630
11239
  };
8631
11240
  }, [anisotropy, url]);
8632
- useEffect24(
11241
+ useEffect25(
8633
11242
  () => () => {
8634
11243
  texture?.dispose();
8635
11244
  },
@@ -8660,7 +11269,7 @@ function PreviewFace({
8660
11269
  uv.needsUpdate = true;
8661
11270
  return nextGeometry;
8662
11271
  }, [face, faceOrder]);
8663
- useEffect24(
11272
+ useEffect25(
8664
11273
  () => () => {
8665
11274
  geometry.dispose();
8666
11275
  },
@@ -8708,7 +11317,7 @@ function useManagedTexture(manager, key, url, address) {
8708
11317
  snapshot: manager.getSnapshot(key)
8709
11318
  }));
8710
11319
  const snapshot = managedState.manager === manager && managedState.key === key && managedState.url === url ? managedState.snapshot : manager.getSnapshot(key);
8711
- useEffect24(
11320
+ useEffect25(
8712
11321
  () => manager.acquire(key, url, address, (nextSnapshot) => {
8713
11322
  setManagedState({
8714
11323
  manager,
@@ -8859,8 +11468,8 @@ function parentAddresses(child, parentLevel, parentFaceSize, tileSize) {
8859
11468
  return addresses;
8860
11469
  }
8861
11470
  function centerFacingAddress(candidates, camera) {
8862
- const direction = camera.getWorldDirection(new Vector311());
8863
- const center = new Vector311();
11471
+ const direction = camera.getWorldDirection(new Vector312());
11472
+ const center = new Vector312();
8864
11473
  let bestCandidate = candidates[0];
8865
11474
  let bestAlignment = -Infinity;
8866
11475
  for (const candidate of candidates) {
@@ -8943,9 +11552,9 @@ function Tile({
8943
11552
  onPreviewError
8944
11553
  );
8945
11554
  const sharedManager = useSharedTileTextureManager();
8946
- const progressRef = useRef23(onLoadProgress);
8947
- const errorRef = useRef23(onTileError);
8948
- const levelChangeRef = useRef23(onLevelChange);
11555
+ const progressRef = useRef24(onLoadProgress);
11556
+ const errorRef = useRef24(onTileError);
11557
+ const levelChangeRef = useRef24(onLevelChange);
8949
11558
  progressRef.current = onLoadProgress;
8950
11559
  errorRef.current = onTileError;
8951
11560
  levelChangeRef.current = onLevelChange;
@@ -8970,7 +11579,7 @@ function Tile({
8970
11579
  ]
8971
11580
  );
8972
11581
  const manager = sharedManager ?? ownedManager;
8973
- useEffect24(() => {
11582
+ useEffect25(() => {
8974
11583
  manager.resume();
8975
11584
  return () => {
8976
11585
  if (manager === ownedManager) {
@@ -8980,11 +11589,11 @@ function Tile({
8980
11589
  queueMicrotask(() => manager.releaseUnused());
8981
11590
  };
8982
11591
  }, [manager, ownedManager]);
8983
- const readyRef = useRef23(false);
8984
- useEffect24(() => {
11592
+ const readyRef = useRef24(false);
11593
+ useEffect25(() => {
8985
11594
  readyRef.current = false;
8986
11595
  }, [effectivePreviewUrl]);
8987
- useEffect24(() => {
11596
+ useEffect25(() => {
8988
11597
  if (!previewTexture || readyRef.current) {
8989
11598
  return;
8990
11599
  }
@@ -9000,23 +11609,23 @@ function Tile({
9000
11609
  [baseUrl, resolveTileUrl, template]
9001
11610
  );
9002
11611
  const [layers, setLayers] = useState10([]);
9003
- const layerTokenRef = useRef23("");
9004
- const currentLevelRef = useRef23(1);
9005
- const lastUpdateAtRef = useRef23(-Infinity);
9006
- const visibilityDirtyRef = useRef23(true);
9007
- const lastVisibilityQuaternionRef = useRef23(camera.quaternion.clone());
9008
- const lastVisibilityFovRef = useRef23(Number.NaN);
9009
- const lastViewportRef = useRef23({ width: 0, height: 0, dpr: 0 });
9010
- const frustumRef = useRef23(new Frustum());
9011
- const projectionMatrixRef = useRef23(new Matrix4());
9012
- const visibilityCameraRef = useRef23(new PerspectiveCamera4());
9013
- useEffect24(() => {
11612
+ const layerTokenRef = useRef24("");
11613
+ const currentLevelRef = useRef24(1);
11614
+ const lastUpdateAtRef = useRef24(-Infinity);
11615
+ const visibilityDirtyRef = useRef24(true);
11616
+ const lastVisibilityQuaternionRef = useRef24(camera.quaternion.clone());
11617
+ const lastVisibilityFovRef = useRef24(Number.NaN);
11618
+ const lastViewportRef = useRef24({ width: 0, height: 0, dpr: 0 });
11619
+ const frustumRef = useRef24(new Frustum());
11620
+ const projectionMatrixRef = useRef24(new Matrix4());
11621
+ const visibilityCameraRef = useRef24(new PerspectiveCamera4());
11622
+ useEffect25(() => {
9014
11623
  currentLevelRef.current = 1;
9015
11624
  layerTokenRef.current = "";
9016
11625
  visibilityDirtyRef.current = true;
9017
11626
  setLayers([]);
9018
11627
  }, [manager, multiresToken]);
9019
- useEffect24(() => {
11628
+ useEffect25(() => {
9020
11629
  if (loadMode !== "preview") {
9021
11630
  return;
9022
11631
  }
@@ -9167,9 +11776,9 @@ function SnapshotCapture({
9167
11776
  onCaptured
9168
11777
  }) {
9169
11778
  const { camera, gl, scene, size } = useThree19();
9170
- const capturedRequestRef = useRef24(0);
9171
- const renderTargetRef = useRef24(null);
9172
- useEffect25(
11779
+ const capturedRequestRef = useRef25(0);
11780
+ const renderTargetRef = useRef25(null);
11781
+ useEffect26(
9173
11782
  () => () => {
9174
11783
  renderTargetRef.current?.dispose();
9175
11784
  renderTargetRef.current = null;
@@ -9224,7 +11833,7 @@ function ScenesController({
9224
11833
  onTransitionError,
9225
11834
  snapshotMaxPixels = 3686400
9226
11835
  }) {
9227
- const controlsRef = useContext21(PanoramaViewContext);
11836
+ const controlsRef = useContext22(PanoramaViewContext);
9228
11837
  const manager = useSharedTileTextureManager();
9229
11838
  const transition = useMemo18(
9230
11839
  () => resolveTransition(transitionInput),
@@ -9247,13 +11856,13 @@ function ScenesController({
9247
11856
  const [transitionRunId, setTransitionRunId] = useState11(0);
9248
11857
  const [snapshot, setSnapshot] = useState11(null);
9249
11858
  const [recoveryKey, setRecoveryKey] = useState11(0);
9250
- const requestedSceneIdRef = useRef24(activeSceneId);
9251
- const captureReasonRef = useRef24("start");
9252
- const interactionReleaseRef = useRef24(null);
9253
- const slotsRef = useRef24(slots);
9254
- const phaseRef = useRef24(phase);
9255
- const liveSlotRef = useRef24(liveSlot);
9256
- const transitionFromRef = useRef24(initialScene);
11859
+ const requestedSceneIdRef = useRef25(activeSceneId);
11860
+ const captureReasonRef = useRef25("start");
11861
+ const interactionReleaseRef = useRef25(null);
11862
+ const slotsRef = useRef25(slots);
11863
+ const phaseRef = useRef25(phase);
11864
+ const liveSlotRef = useRef25(liveSlot);
11865
+ const transitionFromRef = useRef25(initialScene);
9257
11866
  slotsRef.current = slots;
9258
11867
  phaseRef.current = phase;
9259
11868
  liveSlotRef.current = liveSlot;
@@ -9275,7 +11884,7 @@ function ScenesController({
9275
11884
  setPendingSlot(nextSlot);
9276
11885
  setPhase("preloading");
9277
11886
  }, []);
9278
- useEffect25(() => {
11887
+ useEffect26(() => {
9279
11888
  const requested = sceneMap.get(activeSceneId);
9280
11889
  if (!requested) {
9281
11890
  reportError(activeSceneId, new Error(`Unknown panorama scene: ${activeSceneId}`));
@@ -9377,12 +11986,12 @@ function ScenesController({
9377
11986
  });
9378
11987
  }
9379
11988
  }, [onTransitionEnd, pendingSlot, releaseInteraction, snapshot, transition.preset]);
9380
- useEffect25(() => () => {
11989
+ useEffect26(() => () => {
9381
11990
  releaseInteraction();
9382
11991
  snapshot?.dispose();
9383
11992
  }, [releaseInteraction, snapshot]);
9384
11993
  const { gl } = useThree19();
9385
- useEffect25(() => {
11994
+ useEffect26(() => {
9386
11995
  const canvas = gl.domElement;
9387
11996
  const onContextLost = (event) => {
9388
11997
  event.preventDefault();
@@ -9465,7 +12074,7 @@ function Scenes({
9465
12074
 
9466
12075
  // src/hotspot/image-hotspot.tsx
9467
12076
  import { useThree as useThree21 } from "@react-three/fiber";
9468
- import { useEffect as useEffect28, useRef as useRef26, useState as useState14 } from "react";
12077
+ import { useEffect as useEffect29, useRef as useRef27, useState as useState14 } from "react";
9469
12078
  import {
9470
12079
  ClampToEdgeWrapping as ClampToEdgeWrapping3,
9471
12080
  LinearFilter as LinearFilter6,
@@ -9477,35 +12086,35 @@ import {
9477
12086
  // src/hotspot/hotspot-anchor.tsx
9478
12087
  import { useFrame as useFrame13, useThree as useThree20 } from "@react-three/fiber";
9479
12088
  import {
9480
- useContext as useContext23,
9481
- useEffect as useEffect27,
12089
+ useContext as useContext24,
12090
+ useEffect as useEffect28,
9482
12091
  useLayoutEffect as useLayoutEffect4,
9483
12092
  useMemo as useMemo20,
9484
- useRef as useRef25,
12093
+ useRef as useRef26,
9485
12094
  useState as useState13
9486
12095
  } from "react";
9487
12096
  import {
9488
12097
  Box3 as Box33,
9489
12098
  EdgesGeometry,
9490
- MathUtils as MathUtils6,
12099
+ MathUtils as MathUtils7,
9491
12100
  Matrix4 as Matrix42,
9492
12101
  Plane,
9493
12102
  PlaneGeometry as PlaneGeometry5,
9494
12103
  PerspectiveCamera as PerspectiveCamera5,
9495
12104
  Quaternion as Quaternion3,
9496
12105
  Ray,
9497
- Vector3 as Vector312
12106
+ Vector3 as Vector313
9498
12107
  } from "three";
9499
12108
 
9500
12109
  // src/hotspot/hotspot-tooltip.tsx
9501
- import { useEffect as useEffect26, useMemo as useMemo19, useState as useState12 } from "react";
12110
+ import { useEffect as useEffect27, useMemo as useMemo19, useState as useState12 } from "react";
9502
12111
 
9503
12112
  // src/webvr/stereo-html.tsx
9504
12113
  import { Html } from "@react-three/drei";
9505
- import { useContext as useContext22, useSyncExternalStore as useSyncExternalStore6 } from "react";
12114
+ import { useContext as useContext23, useSyncExternalStore as useSyncExternalStore6 } from "react";
9506
12115
  import { Fragment as Fragment7, jsx as jsx23, jsxs as jsxs14 } from "react/jsx-runtime";
9507
12116
  function useFallbackStereoView() {
9508
- const runtime = useContext22(WebVRRuntimeContext);
12117
+ const runtime = useContext23(WebVRRuntimeContext);
9509
12118
  const host = runtime?.host ?? null;
9510
12119
  const fallback = useSyncExternalStore6(
9511
12120
  (onStoreChange) => host ? subscribeWebVRHost(host, onStoreChange) : () => void 0,
@@ -9622,7 +12231,7 @@ function HotspotTooltip({
9622
12231
  appearance
9623
12232
  }) {
9624
12233
  const [imageFailed, setImageFailed] = useState12(false);
9625
- useEffect26(() => {
12234
+ useEffect27(() => {
9626
12235
  setImageFailed(false);
9627
12236
  }, [content.image]);
9628
12237
  const showImage = Boolean(content.image) && !imageFailed;
@@ -9680,28 +12289,28 @@ var DEFAULT_REFERENCE_FOV = 75;
9680
12289
  var MIN_ANGULAR_SIZE = 0.01;
9681
12290
  var MAX_ANGULAR_SIZE = 179;
9682
12291
  var DRAG_EPSILON_DEGREES = 1e-3;
9683
- var LOCAL_FORWARD = new Vector312(0, 0, 1);
12292
+ var LOCAL_FORWARD = new Vector313(0, 0, 1);
9684
12293
  var TOOLTIP_WORLD_BOX = new Box33();
9685
12294
  var TOOLTIP_LOCAL_BOX = new Box33();
9686
- var TOOLTIP_CORNER = new Vector312();
12295
+ var TOOLTIP_CORNER = new Vector313();
9687
12296
  var TOOLTIP_INVERSE = new Matrix42();
9688
- var TOOLTIP_WORLD_CORNER = new Vector312();
9689
- var TOOLTIP_PROJECTED = new Vector312();
9690
- var TOOLTIP_RAY_ORIGIN = new Vector312();
9691
- var TOOLTIP_RAY_FAR = new Vector312();
9692
- var TOOLTIP_RAY_DIRECTION = new Vector312();
12297
+ var TOOLTIP_WORLD_CORNER = new Vector313();
12298
+ var TOOLTIP_PROJECTED = new Vector313();
12299
+ var TOOLTIP_RAY_ORIGIN = new Vector313();
12300
+ var TOOLTIP_RAY_FAR = new Vector313();
12301
+ var TOOLTIP_RAY_DIRECTION = new Vector313();
9693
12302
  var TOOLTIP_RAY = new Ray();
9694
12303
  var TOOLTIP_PLANE = new Plane();
9695
- var TOOLTIP_INTERSECTION = new Vector312();
9696
- var TOOLTIP_PLANE_NORMAL = new Vector312();
9697
- var TOOLTIP_PLANE_POINT = new Vector312();
12304
+ var TOOLTIP_INTERSECTION = new Vector313();
12305
+ var TOOLTIP_PLANE_NORMAL = new Vector313();
12306
+ var TOOLTIP_PLANE_POINT = new Vector313();
9698
12307
  var HOTSPOT_MODE_RENDERING = {
9699
12308
  surface: { orientation: "surface", placement: "surface" },
9700
12309
  billboard: { orientation: "billboard", placement: "floating" }
9701
12310
  };
9702
12311
  function angularSizeToWorldSize(size, radius) {
9703
- const safeSize = Number.isFinite(size) ? MathUtils6.clamp(Math.abs(size), MIN_ANGULAR_SIZE, MAX_ANGULAR_SIZE) : MIN_ANGULAR_SIZE;
9704
- return 2 * radius * Math.tan(MathUtils6.degToRad(safeSize) / 2);
12312
+ const safeSize = Number.isFinite(size) ? MathUtils7.clamp(Math.abs(size), MIN_ANGULAR_SIZE, MAX_ANGULAR_SIZE) : MIN_ANGULAR_SIZE;
12313
+ return 2 * radius * Math.tan(MathUtils7.degToRad(safeSize) / 2);
9705
12314
  }
9706
12315
  function resolveScale(scale) {
9707
12316
  return Number.isFinite(scale) && scale > 0 ? scale : 1;
@@ -9714,7 +12323,7 @@ function resolveDistance(placement, distance, width, height) {
9714
12323
  if (!Number.isFinite(distance)) {
9715
12324
  return DEFAULT_FLOATING_DISTANCE;
9716
12325
  }
9717
- return MathUtils6.clamp(Math.abs(distance), 0.1, maximumDistance);
12326
+ return MathUtils7.clamp(Math.abs(distance), 0.1, maximumDistance);
9718
12327
  }
9719
12328
  function applyHotspotTransform(group, camera, orientation2, surfaceQuaternion3, rotation, scaleMode, referenceFov, useAngularScale, worldWidth, worldHeight) {
9720
12329
  if (orientation2 === "billboard") {
@@ -9722,7 +12331,7 @@ function applyHotspotTransform(group, camera, orientation2, surfaceQuaternion3,
9722
12331
  } else {
9723
12332
  group.quaternion.copy(surfaceQuaternion3);
9724
12333
  }
9725
- group.rotateOnAxis(LOCAL_FORWARD, MathUtils6.degToRad(-rotation));
12334
+ group.rotateOnAxis(LOCAL_FORWARD, MathUtils7.degToRad(-rotation));
9726
12335
  const scaleFactor = scaleMode === "fixed" && camera instanceof PerspectiveCamera5 ? fixedScaleFactor(camera.fov, referenceFov) : 1;
9727
12336
  group.scale.set(
9728
12337
  (useAngularScale ? worldWidth : 1) * scaleFactor,
@@ -9732,33 +12341,33 @@ function applyHotspotTransform(group, camera, orientation2, surfaceQuaternion3,
9732
12341
  group.updateMatrixWorld();
9733
12342
  }
9734
12343
  function maximumHotspotDistance(width, height) {
9735
- const safeWidth = MathUtils6.clamp(
12344
+ const safeWidth = MathUtils7.clamp(
9736
12345
  Math.abs(Number.isFinite(width) ? width : MIN_ANGULAR_SIZE),
9737
12346
  MIN_ANGULAR_SIZE,
9738
12347
  MAX_ANGULAR_SIZE
9739
12348
  );
9740
- const safeHeight = MathUtils6.clamp(
12349
+ const safeHeight = MathUtils7.clamp(
9741
12350
  Math.abs(Number.isFinite(height) ? height : MIN_ANGULAR_SIZE),
9742
12351
  MIN_ANGULAR_SIZE,
9743
12352
  MAX_ANGULAR_SIZE
9744
12353
  );
9745
12354
  const cornerFactor = Math.hypot(
9746
12355
  1,
9747
- Math.tan(MathUtils6.degToRad(safeWidth) / 2),
9748
- Math.tan(MathUtils6.degToRad(safeHeight) / 2)
12356
+ Math.tan(MathUtils7.degToRad(safeWidth) / 2),
12357
+ Math.tan(MathUtils7.degToRad(safeHeight) / 2)
9749
12358
  );
9750
12359
  return (PANORAMA_RADIUS - PANORAMA_SURFACE_INSET) / cornerFactor;
9751
12360
  }
9752
12361
  function fixedScaleFactor(cameraFov, referenceFov) {
9753
- const safeReferenceFov = MathUtils6.clamp(referenceFov, 1, 179);
9754
- return Math.tan(MathUtils6.degToRad(cameraFov) / 2) / Math.tan(MathUtils6.degToRad(safeReferenceFov) / 2);
12362
+ const safeReferenceFov = MathUtils7.clamp(referenceFov, 1, 179);
12363
+ return Math.tan(MathUtils7.degToRad(cameraFov) / 2) / Math.tan(MathUtils7.degToRad(safeReferenceFov) / 2);
9755
12364
  }
9756
12365
  function createSurfaceQuaternion(position) {
9757
12366
  const outward = panoPositionToVector3(position).normalize();
9758
12367
  const inward = outward.clone().negate();
9759
- const pitch = MathUtils6.degToRad(position.pitch);
9760
- const yaw = MathUtils6.degToRad(position.yaw);
9761
- const localUp = new Vector312(
12368
+ const pitch = MathUtils7.degToRad(position.pitch);
12369
+ const yaw = MathUtils7.degToRad(position.yaw);
12370
+ const localUp = new Vector313(
9762
12371
  -Math.sin(pitch) * Math.sin(yaw),
9763
12372
  Math.cos(pitch),
9764
12373
  Math.sin(pitch) * Math.cos(yaw)
@@ -9778,7 +12387,7 @@ function makeInteractionEvent(id, position, event) {
9778
12387
  function angularDistance(a, b) {
9779
12388
  const aVector = panoPositionToVector3(a);
9780
12389
  const bVector = panoPositionToVector3(b);
9781
- return MathUtils6.radToDeg(aVector.angleTo(bVector));
12390
+ return MathUtils7.radToDeg(aVector.angleTo(bVector));
9782
12391
  }
9783
12392
  function isTooltipOpen(trigger, hovered, focused, pinned) {
9784
12393
  switch (trigger) {
@@ -10009,14 +12618,14 @@ function HotspotAnchor({
10009
12618
  onPositionChange,
10010
12619
  onDragEnd
10011
12620
  }) {
10012
- const controlsRef = useContext23(PanoramaViewContext);
10013
- const eventBus = useContext23(PanoEventBusContext);
12621
+ const controlsRef = useContext24(PanoramaViewContext);
12622
+ const eventBus = useContext24(PanoEventBusContext);
10014
12623
  const cursorApi = usePanoCursor();
10015
12624
  const { camera, size } = useThree20();
10016
- const groupRef = useRef25(null);
10017
- const tooltipAnchorRef = useRef25(null);
10018
- const dragStateRef = useRef25(null);
10019
- const suppressNextClickRef = useRef25(false);
12625
+ const groupRef = useRef26(null);
12626
+ const tooltipAnchorRef = useRef26(null);
12627
+ const dragStateRef = useRef26(null);
12628
+ const suppressNextClickRef = useRef26(false);
10020
12629
  const [hovered, setHovered] = useState13(false);
10021
12630
  const [dragging, setDragging] = useState13(false);
10022
12631
  const [pinned, setPinned] = useState13(false);
@@ -10073,14 +12682,14 @@ function HotspotAnchor({
10073
12682
  });
10074
12683
  const tooltipOpen = visible && tooltipContent !== null && isTooltipOpen(tooltipTrigger, hovered, focused, pinned);
10075
12684
  const cursorClaimId = hotspotCursorClaimId(id);
10076
- useEffect27(
12685
+ useEffect28(
10077
12686
  () => () => {
10078
12687
  dragStateRef.current?.releaseInteractionLock();
10079
12688
  dragStateRef.current = null;
10080
12689
  },
10081
12690
  []
10082
12691
  );
10083
- useEffect27(() => {
12692
+ useEffect28(() => {
10084
12693
  if (!cursorApi) {
10085
12694
  return;
10086
12695
  }
@@ -10102,14 +12711,14 @@ function HotspotAnchor({
10102
12711
  hovered,
10103
12712
  visible
10104
12713
  ]);
10105
- useEffect27(
12714
+ useEffect28(
10106
12715
  () => () => {
10107
12716
  cursorApi?.release(cursorClaimId);
10108
12717
  },
10109
12718
  [cursorApi, cursorClaimId]
10110
12719
  );
10111
- useEffect27(() => () => focusGeometry.dispose(), [focusGeometry]);
10112
- useEffect27(() => {
12720
+ useEffect28(() => () => focusGeometry.dispose(), [focusGeometry]);
12721
+ useEffect28(() => {
10113
12722
  if (tooltipTrigger !== "click") {
10114
12723
  setPinned(false);
10115
12724
  return;
@@ -10118,12 +12727,12 @@ function HotspotAnchor({
10118
12727
  setPinned(false);
10119
12728
  });
10120
12729
  }, [eventBus, tooltipTrigger]);
10121
- useEffect27(() => {
12730
+ useEffect28(() => {
10122
12731
  if (tooltipTrigger !== "hover") {
10123
12732
  setHovered(false);
10124
12733
  }
10125
12734
  }, [tooltipTrigger]);
10126
- useEffect27(() => {
12735
+ useEffect28(() => {
10127
12736
  if (acceptsPointer) {
10128
12737
  return;
10129
12738
  }
@@ -10468,11 +13077,11 @@ import { jsx as jsx27 } from "react/jsx-runtime";
10468
13077
  function useHotspotImageTexture(src, onLoad, onError) {
10469
13078
  const gl = useThree21((state) => state.gl);
10470
13079
  const [texture, setTexture] = useState14(null);
10471
- const onLoadRef = useRef26(onLoad);
10472
- const onErrorRef = useRef26(onError);
13080
+ const onLoadRef = useRef27(onLoad);
13081
+ const onErrorRef = useRef27(onError);
10473
13082
  onLoadRef.current = onLoad;
10474
13083
  onErrorRef.current = onError;
10475
- useEffect28(() => {
13084
+ useEffect29(() => {
10476
13085
  let active = true;
10477
13086
  setTexture(null);
10478
13087
  if (!src) {
@@ -10510,7 +13119,7 @@ function useHotspotImageTexture(src, onLoad, onError) {
10510
13119
  active = false;
10511
13120
  };
10512
13121
  }, [gl, src]);
10513
- useEffect28(
13122
+ useEffect29(
10514
13123
  () => () => {
10515
13124
  texture?.dispose();
10516
13125
  },
@@ -10532,7 +13141,7 @@ function ImageHotspot({
10532
13141
  }
10533
13142
 
10534
13143
  // src/hotspot/polygon-hotspot.tsx
10535
- import { useEffect as useEffect29, useMemo as useMemo21, useRef as useRef28 } from "react";
13144
+ import { useEffect as useEffect30, useMemo as useMemo21, useRef as useRef29 } from "react";
10536
13145
  import {
10537
13146
  BufferGeometry,
10538
13147
  DoubleSide as DoubleSide5,
@@ -10541,20 +13150,20 @@ import {
10541
13150
  Quaternion as Quaternion4,
10542
13151
  ShapeUtils,
10543
13152
  Vector2 as Vector27,
10544
- Vector3 as Vector314
13153
+ Vector3 as Vector315
10545
13154
  } from "three";
10546
13155
 
10547
13156
  // src/hotspot/hotspot-stroke-line.tsx
10548
13157
  import { Line } from "@react-three/drei";
10549
13158
  import { useFrame as useFrame14, useThree as useThree22 } from "@react-three/fiber";
10550
- import { useLayoutEffect as useLayoutEffect5, useRef as useRef27 } from "react";
13159
+ import { useLayoutEffect as useLayoutEffect5, useRef as useRef28 } from "react";
10551
13160
  import {
10552
- MathUtils as MathUtils7,
13161
+ MathUtils as MathUtils8,
10553
13162
  PerspectiveCamera as PerspectiveCamera6,
10554
- Vector3 as Vector313
13163
+ Vector3 as Vector314
10555
13164
  } from "three";
10556
13165
  import { jsx as jsx28 } from "react/jsx-runtime";
10557
- var LINE_WORLD_POSITION = new Vector313();
13166
+ var LINE_WORLD_POSITION = new Vector314();
10558
13167
  function applyScreenSpaceDashScale(object, camera, viewportHeight) {
10559
13168
  const material = object?.material;
10560
13169
  if (!object || typeof material?.dashScale !== "number") {
@@ -10563,7 +13172,7 @@ function applyScreenSpaceDashScale(object, camera, viewportHeight) {
10563
13172
  object.getWorldPosition(LINE_WORLD_POSITION);
10564
13173
  const depth = Math.max(camera.position.distanceTo(LINE_WORLD_POSITION), 1);
10565
13174
  const fov = camera instanceof PerspectiveCamera6 ? camera.fov : 75;
10566
- material.dashScale = viewportHeight / (2 * Math.tan(MathUtils7.degToRad(fov) * 0.5) * depth);
13175
+ material.dashScale = viewportHeight / (2 * Math.tan(MathUtils8.degToRad(fov) * 0.5) * depth);
10567
13176
  }
10568
13177
  function resolveDash(dashSize, gapSize) {
10569
13178
  if (dashSize === void 0 || !Number.isFinite(dashSize) || dashSize <= 0) {
@@ -10584,7 +13193,7 @@ function HotspotStrokeLine({
10584
13193
  dashSize,
10585
13194
  gapSize
10586
13195
  }) {
10587
- const lineRef = useRef27(null);
13196
+ const lineRef = useRef28(null);
10588
13197
  const { camera, size } = useThree22();
10589
13198
  const dash = resolveDash(dashSize, gapSize);
10590
13199
  useLayoutEffect5(() => {
@@ -10693,7 +13302,7 @@ function polygonContainsDirection(vertices, direction) {
10693
13302
  }
10694
13303
  function fitsHemisphere(vertices) {
10695
13304
  const directions = vertices.map((vertex) => panoPositionToVector3(vertex).normalize());
10696
- const candidates = [new Vector314()];
13305
+ const candidates = [new Vector315()];
10697
13306
  for (const direction of directions) {
10698
13307
  candidates[0].add(direction);
10699
13308
  candidates.push(direction.clone());
@@ -10717,7 +13326,7 @@ function validatePolygonVertices(vertices) {
10717
13326
  if (hasSelfIntersection(unwrapped)) {
10718
13327
  issues.push({ code: "self_intersection", message: "Polygon edges cannot cross." });
10719
13328
  }
10720
- if (polygonContainsDirection(normalized, new Vector314(0, 1, 0)) || polygonContainsDirection(normalized, new Vector314(0, -1, 0))) {
13329
+ if (polygonContainsDirection(normalized, new Vector315(0, 1, 0)) || polygonContainsDirection(normalized, new Vector315(0, -1, 0))) {
10721
13330
  issues.push({ code: "contains_pole", message: "Polygons cannot contain a panorama pole." });
10722
13331
  }
10723
13332
  if (!fitsHemisphere(normalized)) {
@@ -10728,7 +13337,7 @@ function validatePolygonVertices(vertices) {
10728
13337
  function polygonCenter(vertices) {
10729
13338
  const sum = vertices.reduce(
10730
13339
  (total, vertex) => total.add(panoPositionToVector3(vertex).normalize()),
10731
- new Vector314()
13340
+ new Vector315()
10732
13341
  );
10733
13342
  return sum.lengthSq() > 1e-8 ? vector3ToPanoPosition(sum) : normalizePanoPosition(vertices[0]);
10734
13343
  }
@@ -10737,7 +13346,7 @@ function surfaceQuaternion(position) {
10737
13346
  const inward = outward.clone().negate();
10738
13347
  const pitch = position.pitch * Math.PI / 180;
10739
13348
  const yaw = position.yaw * Math.PI / 180;
10740
- const localUp = new Vector314(
13349
+ const localUp = new Vector315(
10741
13350
  -Math.sin(pitch) * Math.sin(yaw),
10742
13351
  Math.cos(pitch),
10743
13352
  Math.sin(pitch) * Math.cos(yaw)
@@ -10750,7 +13359,7 @@ function makeWorldToLocal(center) {
10750
13359
  return new Matrix43().compose(
10751
13360
  panoPositionToVector3(center, POLYGON_RADIUS),
10752
13361
  surfaceQuaternion(center),
10753
- new Vector314(1, 1, 1)
13362
+ new Vector315(1, 1, 1)
10754
13363
  ).invert();
10755
13364
  }
10756
13365
  function projectedPoint(a, b, c, weightB, weightC, radius, worldToLocal) {
@@ -10889,12 +13498,12 @@ function PolygonHotspot({
10889
13498
  [center, valid, vertices]
10890
13499
  );
10891
13500
  const resolvedStrokeOpacity = Math.max(0, Math.min(strokeOpacity, 1));
10892
- const startVerticesRef = useRef28(null);
13501
+ const startVerticesRef = useRef29(null);
10893
13502
  const issuesKey = issues.map((issue) => issue.code).join(",");
10894
- useEffect29(() => {
13503
+ useEffect30(() => {
10895
13504
  if (!valid) onInvalid?.(issues);
10896
13505
  }, [issues, issuesKey, onInvalid, valid]);
10897
- useEffect29(() => () => fillGeometry?.dispose(), [fillGeometry]);
13506
+ useEffect30(() => () => fillGeometry?.dispose(), [fillGeometry]);
10898
13507
  if (!valid || !center || !fillGeometry || !strokePoints || strokePoints.length < 2) {
10899
13508
  return null;
10900
13509
  }
@@ -10974,12 +13583,12 @@ function PolygonHotspot({
10974
13583
  }
10975
13584
 
10976
13585
  // src/hotspot/polyline-hotspot.tsx
10977
- import { useEffect as useEffect30, useMemo as useMemo22, useRef as useRef29 } from "react";
13586
+ import { useEffect as useEffect31, useMemo as useMemo22, useRef as useRef30 } from "react";
10978
13587
  import {
10979
- MathUtils as MathUtils8,
13588
+ MathUtils as MathUtils9,
10980
13589
  Matrix4 as Matrix44,
10981
13590
  Quaternion as Quaternion5,
10982
- Vector3 as Vector315
13591
+ Vector3 as Vector316
10983
13592
  } from "three";
10984
13593
  import { jsx as jsx30 } from "react/jsx-runtime";
10985
13594
  var POLYLINE_RADIUS = 990;
@@ -11006,16 +13615,16 @@ function unwrapVertices(vertices) {
11006
13615
  function polylineCenter(vertices) {
11007
13616
  const sum = vertices.reduce(
11008
13617
  (total, vertex) => total.add(panoPositionToVector3(vertex).normalize()),
11009
- new Vector315()
13618
+ new Vector316()
11010
13619
  );
11011
13620
  return sum.lengthSq() > 1e-8 ? vector3ToPanoPosition(sum) : normalizePanoPosition(vertices[0]);
11012
13621
  }
11013
13622
  function surfaceQuaternion2(position) {
11014
13623
  const outward = panoPositionToVector3(position).normalize();
11015
13624
  const inward = outward.clone().negate();
11016
- const pitch = MathUtils8.degToRad(position.pitch);
11017
- const yaw = MathUtils8.degToRad(position.yaw);
11018
- const localUp = new Vector315(
13625
+ const pitch = MathUtils9.degToRad(position.pitch);
13626
+ const yaw = MathUtils9.degToRad(position.yaw);
13627
+ const localUp = new Vector316(
11019
13628
  -Math.sin(pitch) * Math.sin(yaw),
11020
13629
  Math.cos(pitch),
11021
13630
  Math.sin(pitch) * Math.cos(yaw)
@@ -11028,7 +13637,7 @@ function makeWorldToLocal2(center) {
11028
13637
  return new Matrix44().compose(
11029
13638
  panoPositionToVector3(center, POLYLINE_RADIUS),
11030
13639
  surfaceQuaternion2(center),
11031
- new Vector315(1, 1, 1)
13640
+ new Vector316(1, 1, 1)
11032
13641
  ).invert();
11033
13642
  }
11034
13643
  function subdivisionSteps(vertices) {
@@ -11043,7 +13652,7 @@ function subdivisionSteps(vertices) {
11043
13652
  }
11044
13653
  return Math.min(
11045
13654
  8,
11046
- Math.max(1, Math.ceil(MathUtils8.radToDeg(maxAngle) / MAX_SEGMENT_DEGREES))
13655
+ Math.max(1, Math.ceil(MathUtils9.radToDeg(maxAngle) / MAX_SEGMENT_DEGREES))
11047
13656
  );
11048
13657
  }
11049
13658
  function makeLinePositions(vertices, center) {
@@ -11106,8 +13715,8 @@ function PolylineHotspot({
11106
13715
  [center, valid, vertices]
11107
13716
  );
11108
13717
  const opacity = Math.max(0, Math.min(strokeOpacity, 1));
11109
- const startVerticesRef = useRef29(null);
11110
- useEffect30(() => {
13718
+ const startVerticesRef = useRef30(null);
13719
+ useEffect31(() => {
11111
13720
  if (!valid) onInvalid?.(issues);
11112
13721
  }, [issues, onInvalid, valid]);
11113
13722
  if (!valid || !center || !linePoints || linePoints.length < 2) return null;
@@ -11173,7 +13782,7 @@ function PolylineHotspot({
11173
13782
  }
11174
13783
 
11175
13784
  // src/hotspot/graphic-hotspot.tsx
11176
- import { useEffect as useEffect31, useRef as useRef30, useState as useState15 } from "react";
13785
+ import { useEffect as useEffect32, useRef as useRef31, useState as useState15 } from "react";
11177
13786
  import {
11178
13787
  CanvasTexture,
11179
13788
  ClampToEdgeWrapping as ClampToEdgeWrapping4,
@@ -11371,11 +13980,11 @@ function createGraphicTexture(graphic, aspectWidth, aspectHeight) {
11371
13980
  }
11372
13981
  function useGraphicTexture(graphic, aspectWidth, aspectHeight, onLoad, onError) {
11373
13982
  const [texture, setTexture] = useState15(null);
11374
- const onLoadRef = useRef30(onLoad);
11375
- const onErrorRef = useRef30(onError);
13983
+ const onLoadRef = useRef31(onLoad);
13984
+ const onErrorRef = useRef31(onError);
11376
13985
  onLoadRef.current = onLoad;
11377
13986
  onErrorRef.current = onError;
11378
- useEffect31(() => {
13987
+ useEffect32(() => {
11379
13988
  let nextTexture = null;
11380
13989
  try {
11381
13990
  nextTexture = createGraphicTexture(graphic, aspectWidth, aspectHeight);
@@ -11414,7 +14023,7 @@ function GraphicHotspot(props) {
11414
14023
 
11415
14024
  // src/hotspot/sequence-hotspot.tsx
11416
14025
  import { useFrame as useFrame15, useThree as useThree23 } from "@react-three/fiber";
11417
- import { useEffect as useEffect32, useRef as useRef31, useState as useState16 } from "react";
14026
+ import { useEffect as useEffect33, useRef as useRef32, useState as useState16 } from "react";
11418
14027
  import {
11419
14028
  ClampToEdgeWrapping as ClampToEdgeWrapping5,
11420
14029
  LinearFilter as LinearFilter8,
@@ -11438,11 +14047,11 @@ function useSpriteTexture({
11438
14047
  }) {
11439
14048
  const gl = useThree23((state) => state.gl);
11440
14049
  const [texture, setTexture] = useState16(null);
11441
- const onErrorRef = useRef31(onError);
11442
- const onLoadProgressRef = useRef31(onLoadProgress);
14050
+ const onErrorRef = useRef32(onError);
14051
+ const onLoadProgressRef = useRef32(onLoadProgress);
11443
14052
  onErrorRef.current = onError;
11444
14053
  onLoadProgressRef.current = onLoadProgress;
11445
- useEffect32(() => {
14054
+ useEffect33(() => {
11446
14055
  let active = true;
11447
14056
  setTexture(null);
11448
14057
  if (!src) {
@@ -11483,7 +14092,7 @@ function useSpriteTexture({
11483
14092
  active = false;
11484
14093
  };
11485
14094
  }, [gl, id, src]);
11486
- useEffect32(
14095
+ useEffect33(
11487
14096
  () => () => {
11488
14097
  texture?.dispose();
11489
14098
  },
@@ -11513,23 +14122,23 @@ function SequenceHotspot({
11513
14122
  const frameCount = resolveFrameCount(requestedFrameCount);
11514
14123
  const safeFps = resolveFps(fps);
11515
14124
  const [frameIndex, setFrameIndex] = useState16(0);
11516
- const elapsedRef = useRef31(0);
11517
- const frameIndexRef = useRef31(0);
11518
- const endedRef = useRef31(false);
11519
- const lastPlaybackStateRef = useRef31(null);
11520
- const onFrameChangeRef = useRef31(onFrameChange);
11521
- const onPlaybackStateChangeRef = useRef31(onPlaybackStateChange);
11522
- const onEndedRef = useRef31(onEnded);
14125
+ const elapsedRef = useRef32(0);
14126
+ const frameIndexRef = useRef32(0);
14127
+ const endedRef = useRef32(false);
14128
+ const lastPlaybackStateRef = useRef32(null);
14129
+ const onFrameChangeRef = useRef32(onFrameChange);
14130
+ const onPlaybackStateChangeRef = useRef32(onPlaybackStateChange);
14131
+ const onEndedRef = useRef32(onEnded);
11523
14132
  onFrameChangeRef.current = onFrameChange;
11524
14133
  onPlaybackStateChangeRef.current = onPlaybackStateChange;
11525
14134
  onEndedRef.current = onEnded;
11526
- useEffect32(() => {
14135
+ useEffect33(() => {
11527
14136
  elapsedRef.current = 0;
11528
14137
  frameIndexRef.current = 0;
11529
14138
  endedRef.current = false;
11530
14139
  setFrameIndex(0);
11531
14140
  }, [frameCount, frameDirection, src]);
11532
- useEffect32(() => {
14141
+ useEffect33(() => {
11533
14142
  if (!texture) {
11534
14143
  return;
11535
14144
  }
@@ -11543,13 +14152,13 @@ function SequenceHotspot({
11543
14152
  );
11544
14153
  texture.needsUpdate = true;
11545
14154
  }, [frameCount, frameDirection, frameIndex, texture]);
11546
- useEffect32(() => {
14155
+ useEffect33(() => {
11547
14156
  if (!texture) {
11548
14157
  return;
11549
14158
  }
11550
14159
  onFrameChangeRef.current?.({ id, index: 0, src });
11551
14160
  }, [id, src, texture]);
11552
- useEffect32(() => {
14161
+ useEffect33(() => {
11553
14162
  if (!texture) {
11554
14163
  return;
11555
14164
  }
@@ -11603,7 +14212,7 @@ function SequenceHotspot({
11603
14212
 
11604
14213
  // src/hotspot/video-hotspot.tsx
11605
14214
  import { useThree as useThree24 } from "@react-three/fiber";
11606
- import { useEffect as useEffect33, useRef as useRef32, useState as useState17 } from "react";
14215
+ import { useEffect as useEffect34, useRef as useRef33, useState as useState17 } from "react";
11607
14216
  import {
11608
14217
  ClampToEdgeWrapping as ClampToEdgeWrapping6,
11609
14218
  LinearFilter as LinearFilter9,
@@ -11622,9 +14231,9 @@ function clampVolume2(volume) {
11622
14231
  function usePosterTexture2(id, poster, onError) {
11623
14232
  const gl = useThree24((state) => state.gl);
11624
14233
  const [texture, setTexture] = useState17(null);
11625
- const onErrorRef = useRef32(onError);
14234
+ const onErrorRef = useRef33(onError);
11626
14235
  onErrorRef.current = onError;
11627
- useEffect33(() => {
14236
+ useEffect34(() => {
11628
14237
  let active = true;
11629
14238
  setTexture(null);
11630
14239
  if (!poster) {
@@ -11661,7 +14270,7 @@ function usePosterTexture2(id, poster, onError) {
11661
14270
  active = false;
11662
14271
  };
11663
14272
  }, [gl, id, poster]);
11664
- useEffect33(
14273
+ useEffect34(
11665
14274
  () => () => {
11666
14275
  texture?.dispose();
11667
14276
  },
@@ -11680,13 +14289,13 @@ function useVideoResource({
11680
14289
  src
11681
14290
  }) {
11682
14291
  const [resource, setResource] = useState17(null);
11683
- const onEndedRef = useRef32(onEnded);
11684
- const onErrorRef = useRef32(onError);
11685
- const onPlaybackStateChangeRef = useRef32(onPlaybackStateChange);
14292
+ const onEndedRef = useRef33(onEnded);
14293
+ const onErrorRef = useRef33(onError);
14294
+ const onPlaybackStateChangeRef = useRef33(onPlaybackStateChange);
11686
14295
  onEndedRef.current = onEnded;
11687
14296
  onErrorRef.current = onError;
11688
14297
  onPlaybackStateChangeRef.current = onPlaybackStateChange;
11689
- useEffect33(() => {
14298
+ useEffect34(() => {
11690
14299
  if (!src) {
11691
14300
  setResource(null);
11692
14301
  return;
@@ -11787,11 +14396,11 @@ function VideoHotspot({
11787
14396
  src
11788
14397
  });
11789
14398
  const posterTexture = usePosterTexture2(id, poster, onError);
11790
- const onPlaybackErrorRef = useRef32(onPlaybackError);
11791
- const onPlaybackStateChangeRef = useRef32(onPlaybackStateChange);
14399
+ const onPlaybackErrorRef = useRef33(onPlaybackError);
14400
+ const onPlaybackStateChangeRef = useRef33(onPlaybackStateChange);
11792
14401
  onPlaybackErrorRef.current = onPlaybackError;
11793
14402
  onPlaybackStateChangeRef.current = onPlaybackStateChange;
11794
- useEffect33(() => {
14403
+ useEffect34(() => {
11795
14404
  if (!resource) {
11796
14405
  return;
11797
14406
  }
@@ -11801,7 +14410,7 @@ function VideoHotspot({
11801
14410
  resource.video.playsInline = playsInline;
11802
14411
  resource.video.preload = preload;
11803
14412
  }, [loop, muted, playsInline, preload, resource, volume]);
11804
- useEffect33(() => {
14413
+ useEffect34(() => {
11805
14414
  if (!resource) {
11806
14415
  return;
11807
14416
  }
@@ -11827,16 +14436,314 @@ function VideoHotspot({
11827
14436
  return /* @__PURE__ */ jsx33(HotspotAnchor, { ...anchorProps, id, height, width, children: /* @__PURE__ */ jsx33(HotspotPlane, { map: activeTexture, opacity }) });
11828
14437
  }
11829
14438
 
11830
- // src/hotspot/text-hotspot.tsx
11831
- import { useEffect as useEffect34, useRef as useRef33, useState as useState18 } from "react";
14439
+ // src/hotspot/audio-hotspot.tsx
14440
+ import { useFrame as useFrame16, useThree as useThree25 } from "@react-three/fiber";
14441
+ import { useEffect as useEffect35, useRef as useRef34, useState as useState18 } from "react";
11832
14442
  import {
11833
14443
  CanvasTexture as CanvasTexture2,
11834
14444
  ClampToEdgeWrapping as ClampToEdgeWrapping7,
11835
14445
  LinearFilter as LinearFilter10,
11836
14446
  LinearMipmapLinearFilter as LinearMipmapLinearFilter7,
11837
- SRGBColorSpace as SRGBColorSpace9
14447
+ SRGBColorSpace as SRGBColorSpace9,
14448
+ TextureLoader as TextureLoader8
11838
14449
  } from "three";
11839
14450
  import { jsx as jsx34 } from "react/jsx-runtime";
14451
+ var SPEAKER_TEXTURE_SIZE = 512;
14452
+ function paintSpeakerBody(context, center) {
14453
+ context.fillStyle = "#f5fbfc";
14454
+ context.beginPath();
14455
+ context.moveTo(center - 92, center - 36);
14456
+ context.lineTo(center - 28, center - 36);
14457
+ context.lineTo(center + 28, center - 96);
14458
+ context.lineTo(center + 28, center + 96);
14459
+ context.lineTo(center - 28, center + 36);
14460
+ context.lineTo(center - 92, center + 36);
14461
+ context.closePath();
14462
+ context.fill();
14463
+ }
14464
+ function createSpeakerTexture(state) {
14465
+ const canvas = document.createElement("canvas");
14466
+ canvas.width = SPEAKER_TEXTURE_SIZE;
14467
+ canvas.height = SPEAKER_TEXTURE_SIZE;
14468
+ const context = canvas.getContext("2d");
14469
+ if (!context) {
14470
+ throw new Error("Canvas 2D is unavailable for this audio hotspot.");
14471
+ }
14472
+ const center = SPEAKER_TEXTURE_SIZE / 2;
14473
+ context.clearRect(0, 0, SPEAKER_TEXTURE_SIZE, SPEAKER_TEXTURE_SIZE);
14474
+ context.lineJoin = "round";
14475
+ context.lineCap = "round";
14476
+ context.beginPath();
14477
+ context.arc(center, center, center - 18, 0, Math.PI * 2);
14478
+ context.fillStyle = state === "playing" ? "#df6b42" : "#1a3a40";
14479
+ context.fill();
14480
+ context.strokeStyle = "#f5fbfc";
14481
+ context.lineWidth = 22;
14482
+ context.stroke();
14483
+ paintSpeakerBody(context, center);
14484
+ context.strokeStyle = "#f5fbfc";
14485
+ context.lineWidth = 18;
14486
+ switch (state) {
14487
+ case "stopped":
14488
+ break;
14489
+ case "playing": {
14490
+ context.beginPath();
14491
+ context.arc(center + 44, center, 44, -Math.PI / 2.6, Math.PI / 2.6);
14492
+ context.stroke();
14493
+ context.beginPath();
14494
+ context.arc(center + 44, center, 78, -Math.PI / 2.8, Math.PI / 2.8);
14495
+ context.stroke();
14496
+ break;
14497
+ }
14498
+ default: {
14499
+ const exhaustive = state;
14500
+ return exhaustive;
14501
+ }
14502
+ }
14503
+ const texture = new CanvasTexture2(canvas);
14504
+ texture.colorSpace = SRGBColorSpace9;
14505
+ texture.wrapS = ClampToEdgeWrapping7;
14506
+ texture.wrapT = ClampToEdgeWrapping7;
14507
+ texture.magFilter = LinearFilter10;
14508
+ texture.minFilter = LinearMipmapLinearFilter7;
14509
+ texture.generateMipmaps = true;
14510
+ texture.needsUpdate = true;
14511
+ return texture;
14512
+ }
14513
+ function useSpeakerTextures(enabled) {
14514
+ const [textures, setTextures] = useState18({ playing: null, stopped: null });
14515
+ useEffect35(() => {
14516
+ if (!enabled) {
14517
+ setTextures({ playing: null, stopped: null });
14518
+ return;
14519
+ }
14520
+ const playing = createSpeakerTexture("playing");
14521
+ const stopped = createSpeakerTexture("stopped");
14522
+ setTextures({ playing, stopped });
14523
+ return () => {
14524
+ playing.dispose();
14525
+ stopped.dispose();
14526
+ };
14527
+ }, [enabled]);
14528
+ return textures;
14529
+ }
14530
+ function useIconTexture(icon, enabled, onError, id) {
14531
+ const gl = useThree25((state) => state.gl);
14532
+ const [texture, setTexture] = useState18(null);
14533
+ const onErrorRef = useRef34(onError);
14534
+ onErrorRef.current = onError;
14535
+ useEffect35(() => {
14536
+ let active = true;
14537
+ setTexture(null);
14538
+ if (!enabled || !icon) {
14539
+ return () => {
14540
+ active = false;
14541
+ };
14542
+ }
14543
+ const loader = new TextureLoader8();
14544
+ loader.load(
14545
+ icon,
14546
+ (loadedTexture) => {
14547
+ if (!active) {
14548
+ loadedTexture.dispose();
14549
+ return;
14550
+ }
14551
+ loadedTexture.colorSpace = SRGBColorSpace9;
14552
+ loadedTexture.wrapS = ClampToEdgeWrapping7;
14553
+ loadedTexture.wrapT = ClampToEdgeWrapping7;
14554
+ loadedTexture.magFilter = LinearFilter10;
14555
+ loadedTexture.minFilter = LinearMipmapLinearFilter7;
14556
+ loadedTexture.generateMipmaps = true;
14557
+ loadedTexture.anisotropy = gl.capabilities.getMaxAnisotropy();
14558
+ loadedTexture.needsUpdate = true;
14559
+ setTexture(loadedTexture);
14560
+ },
14561
+ void 0,
14562
+ (error) => {
14563
+ if (active) {
14564
+ onErrorRef.current?.({ id, error });
14565
+ }
14566
+ }
14567
+ );
14568
+ return () => {
14569
+ active = false;
14570
+ };
14571
+ }, [enabled, gl, icon, id]);
14572
+ useEffect35(
14573
+ () => () => {
14574
+ texture?.dispose();
14575
+ },
14576
+ [texture]
14577
+ );
14578
+ return texture;
14579
+ }
14580
+ function useAudioHowl({
14581
+ crossOrigin,
14582
+ id,
14583
+ loop,
14584
+ onEnded,
14585
+ onError,
14586
+ onPlaybackError,
14587
+ onPlaybackStateChange,
14588
+ playing,
14589
+ src
14590
+ }) {
14591
+ const [howl, setHowl] = useState18(null);
14592
+ const playingRef = useRef34(playing);
14593
+ const loopRef = useRef34(loop ?? false);
14594
+ const onEndedRef = useRef34(onEnded);
14595
+ const onErrorRef = useRef34(onError);
14596
+ const onPlaybackErrorRef = useRef34(onPlaybackError);
14597
+ const onPlaybackStateChangeRef = useRef34(onPlaybackStateChange);
14598
+ playingRef.current = playing;
14599
+ loopRef.current = loop ?? false;
14600
+ onEndedRef.current = onEnded;
14601
+ onErrorRef.current = onError;
14602
+ onPlaybackErrorRef.current = onPlaybackError;
14603
+ onPlaybackStateChangeRef.current = onPlaybackStateChange;
14604
+ const sourcesKey = sourceList(src).join("\0");
14605
+ useEffect35(() => {
14606
+ const sources = sourcesKey.length > 0 ? sourcesKey.split("\0") : [];
14607
+ if (sources.length === 0) {
14608
+ setHowl(null);
14609
+ return;
14610
+ }
14611
+ let active = true;
14612
+ const handle = createUnlockingHowl({
14613
+ src: sources,
14614
+ loop: loopRef.current,
14615
+ crossOrigin,
14616
+ isActive: () => active,
14617
+ shouldRetryPlay: () => playingRef.current,
14618
+ onEnded: () => {
14619
+ onPlaybackStateChangeRef.current?.("ended");
14620
+ onEndedRef.current?.();
14621
+ },
14622
+ onPlay: () => {
14623
+ onPlaybackStateChangeRef.current?.("playing");
14624
+ },
14625
+ onPause: () => {
14626
+ onPlaybackStateChangeRef.current?.("paused");
14627
+ },
14628
+ onLoadError: (error) => {
14629
+ onErrorRef.current?.({ id, error });
14630
+ },
14631
+ onPlayError: (error) => {
14632
+ onPlaybackStateChangeRef.current?.("blocked");
14633
+ onPlaybackErrorRef.current?.(error);
14634
+ }
14635
+ });
14636
+ setHowl(handle.howl);
14637
+ return () => {
14638
+ active = false;
14639
+ handle.dispose();
14640
+ };
14641
+ }, [crossOrigin, id, sourcesKey]);
14642
+ useEffect35(() => {
14643
+ howl?.loop(loop ?? false);
14644
+ }, [howl, loop]);
14645
+ return howl;
14646
+ }
14647
+ function AudioHotspot({
14648
+ id,
14649
+ src,
14650
+ playing,
14651
+ loop = false,
14652
+ muted = false,
14653
+ volume = 1,
14654
+ range = 360,
14655
+ pauseWhenHidden = true,
14656
+ icon,
14657
+ playingIcon,
14658
+ marker = true,
14659
+ crossOrigin,
14660
+ width = 8,
14661
+ height = 8,
14662
+ opacity,
14663
+ onPlaybackStateChange,
14664
+ onPlaybackError,
14665
+ onEnded,
14666
+ onError,
14667
+ ...anchorProps
14668
+ }) {
14669
+ const camera = useThree25((state) => state.camera);
14670
+ const howl = useAudioHowl({
14671
+ crossOrigin,
14672
+ id,
14673
+ loop,
14674
+ onEnded,
14675
+ onError,
14676
+ onPlaybackError,
14677
+ onPlaybackStateChange,
14678
+ playing,
14679
+ src
14680
+ });
14681
+ const speakerTextures = useSpeakerTextures(marker && !icon);
14682
+ const stoppedIconTexture = useIconTexture(icon, marker, onError, id);
14683
+ const playingIconTexture = useIconTexture(playingIcon, marker, onError, id);
14684
+ const markerTexture = playing ? playingIconTexture ?? stoppedIconTexture ?? speakerTextures.playing : stoppedIconTexture ?? speakerTextures.stopped;
14685
+ const playingRef = useRef34(playing);
14686
+ playingRef.current = playing;
14687
+ const mutedRef = useRef34(muted);
14688
+ const volumeRef = useRef34(volume);
14689
+ const rangeRef = useRef34(range);
14690
+ mutedRef.current = muted;
14691
+ volumeRef.current = volume;
14692
+ rangeRef.current = range;
14693
+ useEffect35(() => {
14694
+ if (!howl) {
14695
+ return;
14696
+ }
14697
+ if (!playing) {
14698
+ howl.pause();
14699
+ return;
14700
+ }
14701
+ howl.play();
14702
+ }, [howl, playing]);
14703
+ useEffect35(() => {
14704
+ if (!howl || !pauseWhenHidden) {
14705
+ return;
14706
+ }
14707
+ const handleVisibility = () => {
14708
+ if (document.hidden) {
14709
+ howl.pause();
14710
+ return;
14711
+ }
14712
+ if (playingRef.current) {
14713
+ howl.play();
14714
+ }
14715
+ };
14716
+ document.addEventListener("visibilitychange", handleVisibility);
14717
+ return () => {
14718
+ document.removeEventListener("visibilitychange", handleVisibility);
14719
+ };
14720
+ }, [howl, pauseWhenHidden]);
14721
+ useFrame16(() => {
14722
+ if (!howl) {
14723
+ return;
14724
+ }
14725
+ const spatial = audioSpatialFromView(
14726
+ camera,
14727
+ anchorProps.position,
14728
+ clampLookRange(rangeRef.current)
14729
+ );
14730
+ howl.stereo(spatial.pan);
14731
+ howl.mute(mutedRef.current);
14732
+ howl.volume(clampAudioVolume(volumeRef.current) * spatial.gain);
14733
+ });
14734
+ return /* @__PURE__ */ jsx34(HotspotAnchor, { ...anchorProps, id, height, width, children: marker ? /* @__PURE__ */ jsx34(HotspotPlane, { map: markerTexture, opacity }) : null });
14735
+ }
14736
+
14737
+ // src/hotspot/text-hotspot.tsx
14738
+ import { useEffect as useEffect36, useRef as useRef35, useState as useState19 } from "react";
14739
+ import {
14740
+ CanvasTexture as CanvasTexture3,
14741
+ ClampToEdgeWrapping as ClampToEdgeWrapping8,
14742
+ LinearFilter as LinearFilter11,
14743
+ LinearMipmapLinearFilter as LinearMipmapLinearFilter8,
14744
+ SRGBColorSpace as SRGBColorSpace10
14745
+ } from "three";
14746
+ import { jsx as jsx35 } from "react/jsx-runtime";
11840
14747
  var TEXT_TEXTURE_LONG_SIDE = 1024;
11841
14748
  var DEFAULT_FONT_FAMILY = "system-ui, sans-serif";
11842
14749
  var DEFAULT_FONT_SIZE = 96;
@@ -12045,23 +14952,23 @@ function createTextTexture(text, width, height, style) {
12045
14952
  throw new Error("Canvas 2D is unavailable for this text hotspot.");
12046
14953
  }
12047
14954
  drawTextHotspot(context, canvasWidth, canvasHeight, text, style);
12048
- const texture = new CanvasTexture2(canvas);
12049
- texture.colorSpace = SRGBColorSpace9;
12050
- texture.wrapS = ClampToEdgeWrapping7;
12051
- texture.wrapT = ClampToEdgeWrapping7;
12052
- texture.magFilter = LinearFilter10;
12053
- texture.minFilter = LinearMipmapLinearFilter7;
14955
+ const texture = new CanvasTexture3(canvas);
14956
+ texture.colorSpace = SRGBColorSpace10;
14957
+ texture.wrapS = ClampToEdgeWrapping8;
14958
+ texture.wrapT = ClampToEdgeWrapping8;
14959
+ texture.magFilter = LinearFilter11;
14960
+ texture.minFilter = LinearMipmapLinearFilter8;
12054
14961
  texture.generateMipmaps = true;
12055
14962
  texture.needsUpdate = true;
12056
14963
  return texture;
12057
14964
  }
12058
14965
  function useTextTexture(text, width, height, style, onLoad, onError) {
12059
- const [texture, setTexture] = useState18(null);
12060
- const onLoadRef = useRef33(onLoad);
12061
- const onErrorRef = useRef33(onError);
14966
+ const [texture, setTexture] = useState19(null);
14967
+ const onLoadRef = useRef35(onLoad);
14968
+ const onErrorRef = useRef35(onError);
12062
14969
  onLoadRef.current = onLoad;
12063
14970
  onErrorRef.current = onError;
12064
- useEffect34(() => {
14971
+ useEffect36(() => {
12065
14972
  let cancelled = false;
12066
14973
  let nextTexture = null;
12067
14974
  const run = async () => {
@@ -12154,13 +15061,13 @@ function TextHotspot({
12154
15061
  whiteSpace
12155
15062
  };
12156
15063
  const texture = useTextTexture(text, width, height, style, onLoad, onError);
12157
- return /* @__PURE__ */ jsx34(HotspotAnchor, { ...anchorProps, height, width, children: /* @__PURE__ */ jsx34(HotspotPlane, { map: texture, opacity }) });
15064
+ return /* @__PURE__ */ jsx35(HotspotAnchor, { ...anchorProps, height, width, children: /* @__PURE__ */ jsx35(HotspotPlane, { map: texture, opacity }) });
12158
15065
  }
12159
15066
 
12160
15067
  // src/hotspot/iframe-hotspot.tsx
12161
15068
  import { Html as Html2 } from "@react-three/drei";
12162
15069
  import { DoubleSide as DoubleSide6 } from "three";
12163
- import { jsx as jsx35, jsxs as jsxs19 } from "react/jsx-runtime";
15070
+ import { jsx as jsx36, jsxs as jsxs19 } from "react/jsx-runtime";
12164
15071
  var IFRAME_LONG_SIDE = 800;
12165
15072
  var CSS3D_DISTANCE_FACTOR = 400;
12166
15073
  var DEFAULT_SANDBOX = "allow-scripts allow-popups allow-forms";
@@ -12227,8 +15134,8 @@ function IframeHotspot({
12227
15134
  width,
12228
15135
  children: [
12229
15136
  /* @__PURE__ */ jsxs19("mesh", { children: [
12230
- /* @__PURE__ */ jsx35("planeGeometry", { args: [1, 1] }),
12231
- /* @__PURE__ */ jsx35(
15137
+ /* @__PURE__ */ jsx36("planeGeometry", { args: [1, 1] }),
15138
+ /* @__PURE__ */ jsx36(
12232
15139
  "meshBasicMaterial",
12233
15140
  {
12234
15141
  depthWrite: false,
@@ -12239,7 +15146,7 @@ function IframeHotspot({
12239
15146
  }
12240
15147
  )
12241
15148
  ] }),
12242
- /* @__PURE__ */ jsx35(
15149
+ /* @__PURE__ */ jsx36(
12243
15150
  Html2,
12244
15151
  {
12245
15152
  distanceFactor: CSS3D_DISTANCE_FACTOR,
@@ -12254,7 +15161,7 @@ function IframeHotspot({
12254
15161
  },
12255
15162
  transform: true,
12256
15163
  zIndexRange: [10, 0],
12257
- children: /* @__PURE__ */ jsx35(
15164
+ children: /* @__PURE__ */ jsx36(
12258
15165
  "iframe",
12259
15166
  {
12260
15167
  allow,
@@ -12275,7 +15182,9 @@ function IframeHotspot({
12275
15182
  );
12276
15183
  }
12277
15184
  export {
15185
+ AudioHotspot,
12278
15186
  AutoRotate,
15187
+ BackgroundAudio,
12279
15188
  DEFAULT_HOTSPOT_TOOLTIP_APPEARANCE,
12280
15189
  DEFAULT_HOTSPOT_TOOLTIP_OFFSET,
12281
15190
  DEFAULT_PANO_CURSORS,
@@ -12326,4 +15235,28 @@ export {
12326
15235
  validatePolylineVertices,
12327
15236
  vector3ToPanoPosition
12328
15237
  };
15238
+ /*! Bundled license information:
15239
+
15240
+ howler/dist/howler.js:
15241
+ (*!
15242
+ * howler.js v2.2.4
15243
+ * howlerjs.com
15244
+ *
15245
+ * (c) 2013-2020, James Simpson of GoldFire Studios
15246
+ * goldfirestudios.com
15247
+ *
15248
+ * MIT License
15249
+ *)
15250
+ (*!
15251
+ * Spatial Plugin - Adds support for stereo and 3D audio where Web Audio is supported.
15252
+ *
15253
+ * howler.js v2.2.4
15254
+ * howlerjs.com
15255
+ *
15256
+ * (c) 2013-2020, James Simpson of GoldFire Studios
15257
+ * goldfirestudios.com
15258
+ *
15259
+ * MIT License
15260
+ *)
15261
+ */
12329
15262
  //# sourceMappingURL=index.mjs.map