@ericchen1990/pano-view 2.2.1 → 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";
@@ -4576,6 +6814,19 @@ var PanoViewer = forwardRef2(
4576
6814
  syncFullscreen();
4577
6815
  return subscribeFullscreenChange(syncFullscreen);
4578
6816
  }, []);
6817
+ useEffect12(() => {
6818
+ const root = rootRef.current;
6819
+ if (!root) {
6820
+ return;
6821
+ }
6822
+ const suppressNativeContextMenu = (event) => {
6823
+ event.preventDefault();
6824
+ };
6825
+ root.addEventListener("contextmenu", suppressNativeContextMenu, true);
6826
+ return () => {
6827
+ root.removeEventListener("contextmenu", suppressNativeContextMenu, true);
6828
+ };
6829
+ }, []);
4579
6830
  const contextMenuActions = useMemo7(
4580
6831
  () => ({
4581
6832
  reset: () => {
@@ -4758,14 +7009,385 @@ var PanoViewer = forwardRef2(
4758
7009
  }
4759
7010
  );
4760
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
+
4761
7383
  // src/pano-filter/pano-filter.tsx
4762
- 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";
4763
7385
  function PanoFilter({
4764
7386
  preset = "none",
4765
7387
  intensity,
4766
7388
  enabled = true
4767
7389
  }) {
4768
- const host = useContext15(PanoFilterHostContext);
7390
+ const host = useContext16(PanoFilterHostContext);
4769
7391
  if (!host) {
4770
7392
  throw new Error("<PanoFilter> must be rendered inside <PanoViewer>.");
4771
7393
  }
@@ -4773,13 +7395,13 @@ function PanoFilter({
4773
7395
  () => resolvePanoFilterSnapshot({ preset, intensity, enabled }),
4774
7396
  [enabled, intensity, preset]
4775
7397
  );
4776
- useEffect13(() => {
7398
+ useEffect14(() => {
4777
7399
  claimPanoFilter(host);
4778
7400
  return () => {
4779
7401
  releasePanoFilter(host);
4780
7402
  };
4781
7403
  }, [host]);
4782
- useEffect13(() => {
7404
+ useEffect14(() => {
4783
7405
  setPanoFilterSnapshot(host, snapshot);
4784
7406
  }, [host, snapshot]);
4785
7407
  return null;
@@ -4790,20 +7412,20 @@ import { useFrame as useFrame6, useThree as useThree9 } from "@react-three/fiber
4790
7412
  import {
4791
7413
  forwardRef as forwardRef3,
4792
7414
  useCallback as useCallback7,
4793
- useContext as useContext16,
4794
- useEffect as useEffect14,
7415
+ useContext as useContext17,
7416
+ useEffect as useEffect15,
4795
7417
  useImperativeHandle as useImperativeHandle3,
4796
- useRef as useRef13,
7418
+ useRef as useRef14,
4797
7419
  useState as useState6
4798
7420
  } from "react";
4799
7421
 
4800
7422
  // src/gyro-orientation.ts
4801
- 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";
4802
7424
  var DEVICE_FORWARD_CORRECTION = new Quaternion().setFromAxisAngle(
4803
- new Vector35(1, 0, 0),
7425
+ new Vector36(1, 0, 0),
4804
7426
  -Math.PI / 2
4805
7427
  );
4806
- var SCREEN_AXIS = new Vector35(0, 0, 1);
7428
+ var SCREEN_AXIS = new Vector36(0, 0, 1);
4807
7429
  function getScreenOrientationAngle() {
4808
7430
  if (typeof window === "undefined") {
4809
7431
  return 0;
@@ -4818,30 +7440,30 @@ function getScreenOrientationAngle() {
4818
7440
  function deviceOrientationToQuaternion(sample, screenOrientation) {
4819
7441
  const alpha = Number.isFinite(sample.compassHeading) ? 360 - sample.compassHeading : sample.alpha;
4820
7442
  const deviceEuler = new Euler2(
4821
- MathUtils3.degToRad(sample.beta),
4822
- MathUtils3.degToRad(alpha),
4823
- MathUtils3.degToRad(-sample.gamma),
7443
+ MathUtils4.degToRad(sample.beta),
7444
+ MathUtils4.degToRad(alpha),
7445
+ MathUtils4.degToRad(-sample.gamma),
4824
7446
  "YXZ"
4825
7447
  );
4826
7448
  const screenCorrection = new Quaternion().setFromAxisAngle(
4827
7449
  SCREEN_AXIS,
4828
- -MathUtils3.degToRad(screenOrientation)
7450
+ -MathUtils4.degToRad(screenOrientation)
4829
7451
  );
4830
7452
  return new Quaternion().setFromEuler(deviceEuler).multiply(DEVICE_FORWARD_CORRECTION).multiply(screenCorrection).normalize();
4831
7453
  }
4832
7454
  function quaternionToGyroPose(quaternion) {
4833
7455
  const euler = new Euler2().setFromQuaternion(quaternion, "YXZ");
4834
7456
  return {
4835
- yaw: MathUtils3.radToDeg(-euler.y),
4836
- pitch: MathUtils3.radToDeg(euler.x),
4837
- roll: MathUtils3.radToDeg(euler.z)
7457
+ yaw: MathUtils4.radToDeg(-euler.y),
7458
+ pitch: MathUtils4.radToDeg(euler.x),
7459
+ roll: MathUtils4.radToDeg(euler.z)
4838
7460
  };
4839
7461
  }
4840
7462
  function createRelativeCalibration(deviceQuaternion, yaw, pitch) {
4841
7463
  const targetQuaternion = new Quaternion().setFromEuler(
4842
7464
  new Euler2(
4843
- MathUtils3.degToRad(pitch),
4844
- MathUtils3.degToRad(-yaw),
7465
+ MathUtils4.degToRad(pitch),
7466
+ MathUtils4.degToRad(-yaw),
4845
7467
  0,
4846
7468
  "YXZ"
4847
7469
  )
@@ -4895,24 +7517,24 @@ var Gyro = forwardRef3(function Gyro2({
4895
7517
  onDisable,
4896
7518
  onDenied
4897
7519
  }, ref) {
4898
- const controlsRef = useContext16(PanoramaViewContext);
4899
- const eventBus = useContext16(PanoEventBusContext);
7520
+ const controlsRef = useContext17(PanoramaViewContext);
7521
+ const eventBus = useContext17(PanoEventBusContext);
4900
7522
  const { gl } = useThree9();
4901
7523
  const [internallyDisabled, setInternallyDisabled] = useState6(false);
4902
- const availableRef = useRef13(false);
4903
- const availabilityReportedRef = useRef13(null);
4904
- const activeRef = useRef13(false);
4905
- const permissionRef = useRef13(deviceOrientationPermissionState);
4906
- const absoluteEventSourceRef = useRef13(null);
4907
- const rawQuaternionRef = useRef13(null);
4908
- const calibrationRef = useRef13(null);
4909
- const absoluteOffsetRef = useRef13({ yaw: 0, pitch: 0 });
4910
- const screenAngleRef = useRef13(getScreenOrientationAngle());
4911
- const startPoseRef = useRef13(null);
4912
- const enabledAtRef = useRef13(0);
4913
- const filteredPoseRef = useRef13(null);
4914
- const lastAppliedPoseRef = useRef13(null);
4915
- 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({
4916
7538
  onAvailable,
4917
7539
  onUnavailable,
4918
7540
  onEnable,
@@ -5057,22 +7679,22 @@ var Gyro = forwardRef3(function Gyro2({
5057
7679
  }),
5058
7680
  [requestPermission, resetSensor]
5059
7681
  );
5060
- useEffect14(() => {
7682
+ useEffect15(() => {
5061
7683
  if (!enabled) {
5062
7684
  setInternallyDisabled(false);
5063
7685
  }
5064
7686
  }, [enabled]);
5065
- useEffect14(() => {
7687
+ useEffect15(() => {
5066
7688
  const supported = typeof window !== "undefined" && window.isSecureContext && typeof DeviceOrientationEvent !== "undefined" && (desktopSupport || isMobileDevice());
5067
7689
  setAvailable(supported);
5068
7690
  return () => {
5069
7691
  availableRef.current = false;
5070
7692
  };
5071
7693
  }, [desktopSupport, setAvailable]);
5072
- useEffect14(() => {
7694
+ useEffect15(() => {
5073
7695
  controlsRef.current?.setGyroTouchMode(touchMode);
5074
7696
  }, [controlsRef, touchMode]);
5075
- useEffect14(() => {
7697
+ useEffect15(() => {
5076
7698
  if (!enabled || internallyDisabled || touchMode !== "disablegyro") {
5077
7699
  return;
5078
7700
  }
@@ -5086,7 +7708,7 @@ var Gyro = forwardRef3(function Gyro2({
5086
7708
  gl.domElement.removeEventListener("pointerdown", onPointerDown);
5087
7709
  };
5088
7710
  }, [enabled, gl, internallyDisabled, touchMode]);
5089
- useEffect14(() => {
7711
+ useEffect15(() => {
5090
7712
  if (!enabled || internallyDisabled || !availableRef.current) {
5091
7713
  deactivate();
5092
7714
  return;
@@ -5251,11 +7873,11 @@ import { useThree as useThree12 } from "@react-three/fiber";
5251
7873
  import {
5252
7874
  forwardRef as forwardRef4,
5253
7875
  useCallback as useCallback8,
5254
- useContext as useContext18,
5255
- useEffect as useEffect18,
7876
+ useContext as useContext19,
7877
+ useEffect as useEffect19,
5256
7878
  useImperativeHandle as useImperativeHandle4,
5257
7879
  useMemo as useMemo10,
5258
- useRef as useRef17,
7880
+ useRef as useRef18,
5259
7881
  useState as useState7
5260
7882
  } from "react";
5261
7883
 
@@ -5280,12 +7902,12 @@ async function detectWebVRCapabilities() {
5280
7902
 
5281
7903
  // src/webvr/reticle.tsx
5282
7904
  import { useFrame as useFrame7, useThree as useThree10 } from "@react-three/fiber";
5283
- import { useRef as useRef14 } from "react";
7905
+ import { useRef as useRef15 } from "react";
5284
7906
  import {
5285
7907
  DoubleSide,
5286
7908
  Raycaster as Raycaster2,
5287
7909
  Vector2 as Vector22,
5288
- Vector3 as Vector36
7910
+ Vector3 as Vector37
5289
7911
  } from "three";
5290
7912
  import { jsx as jsx12, jsxs as jsxs7 } from "react/jsx-runtime";
5291
7913
  var CENTER_NDC = new Vector22(0, 0);
@@ -5371,13 +7993,13 @@ function WebVRReticle({
5371
7993
  dwellMs,
5372
7994
  visible
5373
7995
  }) {
5374
- const groupRef = useRef14(null);
5375
- const ringMeshRef = useRef14(null);
5376
- const directionRef = useRef14(new Vector36());
5377
- const raycasterRef = useRef14(new Raycaster2());
5378
- const hoveredRef = useRef14(null);
5379
- const dwellRef = useRef14(0);
5380
- 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);
5381
8003
  const { camera, gl, scene } = useThree10();
5382
8004
  useFrame7((_, deltaSeconds) => {
5383
8005
  const group = groupRef.current;
@@ -5540,7 +8162,7 @@ function WebVRReticle({
5540
8162
 
5541
8163
  // src/webvr/stereo.tsx
5542
8164
  import { useFrame as useFrame8, useThree as useThree11 } from "@react-three/fiber";
5543
- 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";
5544
8166
  import {
5545
8167
  Mesh as Mesh2,
5546
8168
  OrthographicCamera,
@@ -5626,25 +8248,25 @@ function WebVRStereoRenderer({
5626
8248
  screensize
5627
8249
  }) {
5628
8250
  const { camera, gl } = useThree11();
5629
- const runtime = useContext17(WebVRRuntimeContext);
5630
- const fallbackStereoRef = useRef15(null);
8251
+ const runtime = useContext18(WebVRRuntimeContext);
8252
+ const fallbackStereoRef = useRef16(null);
5631
8253
  if (!fallbackStereoRef.current) {
5632
8254
  fallbackStereoRef.current = new StereoCamera2();
5633
8255
  }
5634
8256
  const stereo = runtime?.stereoView.stereo ?? fallbackStereoRef.current;
5635
- const stereoRef = useRef15(stereo);
8257
+ const stereoRef = useRef16(stereo);
5636
8258
  stereoRef.current = stereo;
5637
8259
  const resources = useMemo9(createDistortionResources, []);
5638
- const drawingSizeRef = useRef15(new Vector23());
5639
- const viewportRef = useRef15(new Vector4());
5640
- const scissorRef = useRef15(new Vector4());
5641
- const originalFovRef = useRef15(null);
5642
- const stereoActiveRef = useRef15(false);
5643
- const profileRef = useRef15(profile);
5644
- 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);
5645
8267
  profileRef.current = profile;
5646
8268
  screensizeRef.current = screensize;
5647
- useEffect15(
8269
+ useEffect16(
5648
8270
  () => () => {
5649
8271
  resources.geometry.dispose();
5650
8272
  resources.material.dispose();
@@ -5652,7 +8274,7 @@ function WebVRStereoRenderer({
5652
8274
  },
5653
8275
  [resources]
5654
8276
  );
5655
- useEffect15(() => {
8277
+ useEffect16(() => {
5656
8278
  const originalRender = gl.render.bind(gl);
5657
8279
  gl.render = (sceneToRender, cameraToRender) => {
5658
8280
  if (!stereoActiveRef.current || !(cameraToRender instanceof PerspectiveCamera2)) {
@@ -5716,7 +8338,7 @@ function WebVRStereoRenderer({
5716
8338
  gl.render = originalRender;
5717
8339
  };
5718
8340
  }, [gl, resources]);
5719
- useEffect15(
8341
+ useEffect16(
5720
8342
  () => () => {
5721
8343
  if (runtime) {
5722
8344
  runtime.stereoView.active = false;
@@ -5751,7 +8373,7 @@ function WebVRStereoRenderer({
5751
8373
  }
5752
8374
 
5753
8375
  // src/webvr/pointerlock.ts
5754
- import { useEffect as useEffect16, useRef as useRef16 } from "react";
8376
+ import { useEffect as useEffect17, useRef as useRef17 } from "react";
5755
8377
  var POINTER_LOCK_CURSOR_ID = "webvr:pointerlock";
5756
8378
  async function requestWebVRPointerLock(element) {
5757
8379
  if (typeof document === "undefined") {
@@ -5784,11 +8406,11 @@ function exitWebVRPointerLock(element) {
5784
8406
  }
5785
8407
  function useWebVRPointerLock(enabled, element) {
5786
8408
  const cursor = usePanoCursor();
5787
- const cursorRef = useRef16(cursor);
5788
- const enabledRef = useRef16(enabled);
8409
+ const cursorRef = useRef17(cursor);
8410
+ const enabledRef = useRef17(enabled);
5789
8411
  cursorRef.current = cursor;
5790
8412
  enabledRef.current = enabled;
5791
- useEffect16(() => {
8413
+ useEffect17(() => {
5792
8414
  if (!enabled || !element) {
5793
8415
  return;
5794
8416
  }
@@ -5818,7 +8440,7 @@ function useWebVRPointerLock(enabled, element) {
5818
8440
  }
5819
8441
 
5820
8442
  // src/webvr/wakelock.ts
5821
- import { useEffect as useEffect17 } from "react";
8443
+ import { useEffect as useEffect18 } from "react";
5822
8444
 
5823
8445
  // src/webvr/wakelock-fallback.ts
5824
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==";
@@ -5952,7 +8574,7 @@ function releaseWebVRWakeLock() {
5952
8574
  stopFallbackVideo();
5953
8575
  }
5954
8576
  function useWebVRWakeLock(enabled) {
5955
- useEffect17(() => {
8577
+ useEffect18(() => {
5956
8578
  if (!enabled) {
5957
8579
  return;
5958
8580
  }
@@ -6000,24 +8622,24 @@ var WebVR = forwardRef4(function WebVR2({
6000
8622
  onDenied,
6001
8623
  onUnknownDevice
6002
8624
  }, ref) {
6003
- const runtime = useContext18(WebVRRuntimeContext);
6004
- const controlsRef = useContext18(PanoramaViewContext);
6005
- const eventBus = useContext18(PanoEventBusContext);
8625
+ const runtime = useContext19(WebVRRuntimeContext);
8626
+ const controlsRef = useContext19(PanoramaViewContext);
8627
+ const eventBus = useContext19(PanoEventBusContext);
6006
8628
  const gl = useThree12((state) => state.gl);
6007
- const gyroRef = useRef17(null);
6008
- const capabilitiesRef = useRef17({
8629
+ const gyroRef = useRef18(null);
8630
+ const capabilitiesRef = useRef18({
6009
8631
  mobile: false,
6010
8632
  sensor: false,
6011
8633
  webxr: false
6012
8634
  });
6013
- const availableRef = useRef17(false);
6014
- const modeRef = useRef17(null);
6015
- const webXRSessionRef = useRef17(null);
8635
+ const availableRef = useRef18(false);
8636
+ const modeRef = useRef18(null);
8637
+ const webXRSessionRef = useRef18(null);
6016
8638
  const [mode, setMode] = useState7(null);
6017
8639
  const [settings, setSettings] = useState7(
6018
8640
  () => initializeSettings(screensize, profile)
6019
8641
  );
6020
- const callbacksRef = useRef17({
8642
+ const callbacksRef = useRef18({
6021
8643
  onAvailable,
6022
8644
  onDenied,
6023
8645
  onEnterVR,
@@ -6226,7 +8848,7 @@ var WebVR = forwardRef4(function WebVR2({
6226
8848
  }),
6227
8849
  [enterVR, exitVR, requestPermission, toggleVR]
6228
8850
  );
6229
- useEffect18(() => {
8851
+ useEffect19(() => {
6230
8852
  let active = true;
6231
8853
  void detectWebVRCapabilities().then((capabilities) => {
6232
8854
  if (!active) {
@@ -6248,7 +8870,7 @@ var WebVR = forwardRef4(function WebVR2({
6248
8870
  active = false;
6249
8871
  };
6250
8872
  }, [desktopSupport, eventBus, fakeSupport, host, mobileVr]);
6251
- useEffect18(() => {
8873
+ useEffect19(() => {
6252
8874
  host.controller = controller;
6253
8875
  return () => {
6254
8876
  if (host.controller === controller) {
@@ -6257,10 +8879,10 @@ var WebVR = forwardRef4(function WebVR2({
6257
8879
  }
6258
8880
  };
6259
8881
  }, [controller, host]);
6260
- useEffect18(() => {
8882
+ useEffect19(() => {
6261
8883
  updateWebVRHost(host, { chrome, mode, settings });
6262
8884
  }, [chrome, host, mode, settings]);
6263
- useEffect18(() => {
8885
+ useEffect19(() => {
6264
8886
  if (mode !== "fake") {
6265
8887
  return;
6266
8888
  }
@@ -6284,7 +8906,7 @@ var WebVR = forwardRef4(function WebVR2({
6284
8906
  document.removeEventListener("mousemove", onMouseMove);
6285
8907
  };
6286
8908
  }, [controlsRef, gl.domElement, mode, mousePointerLock]);
6287
- useEffect18(
8909
+ useEffect19(
6288
8910
  () => () => {
6289
8911
  const session2 = webXRSessionRef.current;
6290
8912
  if (session2) {
@@ -6338,12 +8960,12 @@ var WebVR = forwardRef4(function WebVR2({
6338
8960
 
6339
8961
  // src/sphere.tsx
6340
8962
  import { useThree as useThree13 } from "@react-three/fiber";
6341
- 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";
6342
8964
  import {
6343
8965
  BackSide as BackSide2,
6344
8966
  LinearFilter,
6345
8967
  LinearMipmapLinearFilter,
6346
- MathUtils as MathUtils4,
8968
+ MathUtils as MathUtils5,
6347
8969
  RepeatWrapping,
6348
8970
  SRGBColorSpace,
6349
8971
  TextureLoader
@@ -6371,7 +8993,7 @@ function resolveUrlAgainstFile(fileUrl, path) {
6371
8993
  }
6372
8994
 
6373
8995
  // src/pano-filter/pano-basic-material.tsx
6374
- 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";
6375
8997
 
6376
8998
  // src/pano-filter/shaders.ts
6377
8999
  var GLSL_FILTER_COMMON = `
@@ -6531,9 +9153,9 @@ function PanoBasicMaterial({
6531
9153
  toneMapped = false
6532
9154
  }) {
6533
9155
  const snapshot = usePanoFilterSnapshot();
6534
- const materialRef = useRef18(null);
6535
- const intensityRef = useRef18(snapshot.intensity);
6536
- const intensityUniformRef = useRef18(null);
9156
+ const materialRef = useRef19(null);
9157
+ const intensityRef = useRef19(snapshot.intensity);
9158
+ const intensityUniformRef = useRef19(null);
6537
9159
  intensityRef.current = snapshot.intensity;
6538
9160
  const active = isPanoFilterActive(snapshot);
6539
9161
  const preset = snapshot.preset;
@@ -6588,11 +9210,11 @@ function PanoBasicMaterial({
6588
9210
  import { jsx as jsx15, jsxs as jsxs9 } from "react/jsx-runtime";
6589
9211
  function useEquirectTexture(url, anisotropy, generateMipmaps, onLoad, onError) {
6590
9212
  const [texture, setTexture] = useState8(null);
6591
- const onLoadRef = useRef19(onLoad);
6592
- const onErrorRef = useRef19(onError);
9213
+ const onLoadRef = useRef20(onLoad);
9214
+ const onErrorRef = useRef20(onError);
6593
9215
  onLoadRef.current = onLoad;
6594
9216
  onErrorRef.current = onError;
6595
- useEffect19(() => {
9217
+ useEffect20(() => {
6596
9218
  if (!url) {
6597
9219
  setTexture(null);
6598
9220
  return;
@@ -6631,7 +9253,7 @@ function useEquirectTexture(url, anisotropy, generateMipmaps, onLoad, onError) {
6631
9253
  active = false;
6632
9254
  };
6633
9255
  }, [anisotropy, generateMipmaps, url]);
6634
- useEffect19(
9256
+ useEffect20(
6635
9257
  () => () => {
6636
9258
  texture?.dispose();
6637
9259
  },
@@ -6670,11 +9292,11 @@ function Sphere({
6670
9292
  onPreviewError
6671
9293
  );
6672
9294
  const displayTexture = texture ?? previewTexture;
6673
- const readyRef = useRef19(false);
6674
- useEffect19(() => {
9295
+ const readyRef = useRef20(false);
9296
+ useEffect20(() => {
6675
9297
  readyRef.current = false;
6676
9298
  }, [resolvedPreviewUrl, src]);
6677
- useEffect19(() => {
9299
+ useEffect20(() => {
6678
9300
  if (!displayTexture || readyRef.current) {
6679
9301
  return;
6680
9302
  }
@@ -6687,7 +9309,7 @@ function Sphere({
6687
9309
  return /* @__PURE__ */ jsxs9(
6688
9310
  "mesh",
6689
9311
  {
6690
- rotation: [0, MathUtils4.degToRad(90 + yawOffset), 0],
9312
+ rotation: [0, MathUtils5.degToRad(90 + yawOffset), 0],
6691
9313
  visible,
6692
9314
  children: [
6693
9315
  /* @__PURE__ */ jsx15("sphereGeometry", { args: [DEFAULT_PANORAMA_RADIUS, 128, 64] }),
@@ -6708,18 +9330,18 @@ function Sphere({
6708
9330
  import { useThree as useThree14 } from "@react-three/fiber";
6709
9331
  import {
6710
9332
  useCallback as useCallback9,
6711
- useContext as useContext19,
6712
- useEffect as useEffect20,
9333
+ useContext as useContext20,
9334
+ useEffect as useEffect21,
6713
9335
  useLayoutEffect as useLayoutEffect3,
6714
9336
  useMemo as useMemo13,
6715
- useRef as useRef20,
9337
+ useRef as useRef21,
6716
9338
  useState as useState9
6717
9339
  } from "react";
6718
9340
  import {
6719
9341
  BackSide as BackSide3,
6720
9342
  LinearFilter as LinearFilter2,
6721
9343
  LinearMipmapLinearFilter as LinearMipmapLinearFilter2,
6722
- MathUtils as MathUtils5,
9344
+ MathUtils as MathUtils6,
6723
9345
  RepeatWrapping as RepeatWrapping2,
6724
9346
  SRGBColorSpace as SRGBColorSpace2,
6725
9347
  TextureLoader as TextureLoader2,
@@ -6811,9 +9433,9 @@ function applyEquirectangularLayout(texture, anisotropy) {
6811
9433
  function usePosterTexture(poster, onError) {
6812
9434
  const gl = useThree14((state) => state.gl);
6813
9435
  const [texture, setTexture] = useState9(null);
6814
- const onErrorRef = useRef20(onError);
9436
+ const onErrorRef = useRef21(onError);
6815
9437
  onErrorRef.current = onError;
6816
- useEffect20(() => {
9438
+ useEffect21(() => {
6817
9439
  let active = true;
6818
9440
  setTexture(null);
6819
9441
  if (!poster) {
@@ -6850,7 +9472,7 @@ function usePosterTexture(poster, onError) {
6850
9472
  active = false;
6851
9473
  };
6852
9474
  }, [gl, poster]);
6853
- useEffect20(
9475
+ useEffect21(
6854
9476
  () => () => {
6855
9477
  texture?.dispose();
6856
9478
  },
@@ -6908,8 +9530,8 @@ function PanoVideo({
6908
9530
  onTrackChange
6909
9531
  }) {
6910
9532
  const gl = useThree14((state) => state.gl);
6911
- const host = useContext19(PanoVideoHostContext);
6912
- const overlay = useContext19(PanoChromeOverlayContext);
9533
+ const host = useContext20(PanoVideoHostContext);
9534
+ const overlay = useContext20(PanoChromeOverlayContext);
6913
9535
  const variants = useMemo13(
6914
9536
  () => resolvePanoVideoVariants({ poster, src, variants: variantsProp }),
6915
9537
  [poster, src, variantsProp]
@@ -6929,17 +9551,17 @@ function PanoVideo({
6929
9551
  () => captionsEnabled ? defaultPanoVideoTrackId(tracks) : null
6930
9552
  );
6931
9553
  const [ready, setReady] = useState9(false);
6932
- const autoPlayRef = useRef20(autoPlay);
9554
+ const autoPlayRef = useRef21(autoPlay);
6933
9555
  autoPlayRef.current = autoPlay;
6934
- const blockedRef = useRef20(false);
6935
- const captionAppearanceOverrideRef = useRef20(
9556
+ const blockedRef = useRef21(false);
9557
+ const captionAppearanceOverrideRef = useRef21(
6936
9558
  {}
6937
9559
  );
6938
- const mediaCapabilitiesRef = useRef20({
9560
+ const mediaCapabilitiesRef = useRef21({
6939
9561
  volumeAdjustable: true,
6940
9562
  playbackRates: [...DEFAULT_PANO_VIDEO_PLAYBACK_RATES]
6941
9563
  });
6942
- const storeRef = useRef20(null);
9564
+ const storeRef = useRef21(null);
6943
9565
  if (!storeRef.current) {
6944
9566
  storeRef.current = {
6945
9567
  snapshot: {
@@ -6949,7 +9571,7 @@ function PanoVideo({
6949
9571
  listeners: /* @__PURE__ */ new Set()
6950
9572
  };
6951
9573
  }
6952
- const actionsRef = useRef20({
9574
+ const actionsRef = useRef21({
6953
9575
  play: async () => {
6954
9576
  },
6955
9577
  pause: () => {
@@ -6969,12 +9591,12 @@ function PanoVideo({
6969
9591
  setCaptionAppearance: (_appearance) => {
6970
9592
  }
6971
9593
  });
6972
- const onLoadRef = useRef20(onLoad);
6973
- const onErrorRef = useRef20(onError);
6974
- const onPlaybackStateChangeRef = useRef20(onPlaybackStateChange);
6975
- const onEndedRef = useRef20(onEnded);
6976
- const onVariantChangeRef = useRef20(onVariantChange);
6977
- 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);
6978
9600
  onLoadRef.current = onLoad;
6979
9601
  onErrorRef.current = onError;
6980
9602
  onPlaybackStateChangeRef.current = onPlaybackStateChange;
@@ -6998,7 +9620,7 @@ function PanoVideo({
6998
9620
  texture.generateMipmaps = false;
6999
9621
  return { video, texture };
7000
9622
  }, []);
7001
- useEffect20(
9623
+ useEffect21(
7002
9624
  () => () => {
7003
9625
  if (!resource) {
7004
9626
  return;
@@ -7013,13 +9635,13 @@ function PanoVideo({
7013
9635
  },
7014
9636
  [resource]
7015
9637
  );
7016
- useEffect20(() => {
9638
+ useEffect21(() => {
7017
9639
  if (!resource) {
7018
9640
  return;
7019
9641
  }
7020
9642
  resource.texture.anisotropy = gl.capabilities.getMaxAnisotropy();
7021
9643
  }, [gl, resource]);
7022
- useEffect20(() => {
9644
+ useEffect21(() => {
7023
9645
  if (!resource || !overlay?.overlayElement) {
7024
9646
  return;
7025
9647
  }
@@ -7172,10 +9794,10 @@ function PanoVideo({
7172
9794
  };
7173
9795
  emitSnapshot();
7174
9796
  }, [emitSnapshot, playbackRates, resource]);
7175
- useEffect20(() => {
9797
+ useEffect21(() => {
7176
9798
  emitSnapshot();
7177
9799
  }, [emitSnapshot]);
7178
- useEffect20(() => {
9800
+ useEffect21(() => {
7179
9801
  if (!resource || !activeVariant || !mediaKey) {
7180
9802
  return;
7181
9803
  }
@@ -7232,7 +9854,7 @@ function PanoVideo({
7232
9854
  video.removeEventListener("error", handleError);
7233
9855
  };
7234
9856
  }, [mediaKey, resource]);
7235
- useEffect20(() => {
9857
+ useEffect21(() => {
7236
9858
  if (!resource) {
7237
9859
  return;
7238
9860
  }
@@ -7322,7 +9944,7 @@ function PanoVideo({
7322
9944
  }
7323
9945
  };
7324
9946
  }, [emitSnapshot, resource]);
7325
- useEffect20(() => {
9947
+ useEffect21(() => {
7326
9948
  if (!resource) {
7327
9949
  return;
7328
9950
  }
@@ -7335,7 +9957,7 @@ function PanoVideo({
7335
9957
  video.playsInline = playsInline;
7336
9958
  video.preload = preload;
7337
9959
  }, [loop, muted, playsInline, preload, resource, volume]);
7338
- useEffect20(() => {
9960
+ useEffect21(() => {
7339
9961
  if (!resource) {
7340
9962
  return;
7341
9963
  }
@@ -7385,7 +10007,7 @@ function PanoVideo({
7385
10007
  video.removeEventListener("ratechange", handleVolume);
7386
10008
  };
7387
10009
  }, [emitSnapshot, resource]);
7388
- useEffect20(() => {
10010
+ useEffect21(() => {
7389
10011
  if (!resource) {
7390
10012
  return;
7391
10013
  }
@@ -7420,7 +10042,7 @@ function PanoVideo({
7420
10042
  video.textTracks.removeEventListener("change", applyModes);
7421
10043
  };
7422
10044
  }, [emitSnapshot, resource, trackId, tracks]);
7423
- useEffect20(() => {
10045
+ useEffect21(() => {
7424
10046
  if (!captionsEnabled) {
7425
10047
  setTrackId(null);
7426
10048
  return;
@@ -7435,7 +10057,7 @@ function PanoVideo({
7435
10057
  activeTexture ? /* @__PURE__ */ jsxs10(
7436
10058
  "mesh",
7437
10059
  {
7438
- rotation: [0, MathUtils5.degToRad(90 + yawOffset), 0],
10060
+ rotation: [0, MathUtils6.degToRad(90 + yawOffset), 0],
7439
10061
  visible,
7440
10062
  children: [
7441
10063
  /* @__PURE__ */ jsx16("sphereGeometry", { args: [DEFAULT_PANORAMA_RADIUS, 128, 64] }),
@@ -7459,10 +10081,10 @@ import { useFrame as useFrame12, useThree as useThree19 } from "@react-three/fib
7459
10081
  import {
7460
10082
  Fragment as Fragment6,
7461
10083
  useCallback as useCallback10,
7462
- useContext as useContext21,
7463
- useEffect as useEffect25,
10084
+ useContext as useContext22,
10085
+ useEffect as useEffect26,
7464
10086
  useMemo as useMemo18,
7465
- useRef as useRef24,
10087
+ useRef as useRef25,
7466
10088
  useState as useState11
7467
10089
  } from "react";
7468
10090
  import {
@@ -7519,7 +10141,7 @@ function isSnapshotTransition(preset) {
7519
10141
 
7520
10142
  // src/scene-transitions/particle-overlay.tsx
7521
10143
  import { useFrame as useFrame9, useThree as useThree15 } from "@react-three/fiber";
7522
- 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";
7523
10145
  import {
7524
10146
  DoubleSide as DoubleSide2,
7525
10147
  InstancedBufferAttribute,
@@ -7527,7 +10149,7 @@ import {
7527
10149
  PlaneGeometry as PlaneGeometry3,
7528
10150
  ShaderMaterial as ShaderMaterial2,
7529
10151
  Vector2 as Vector24,
7530
- Vector3 as Vector38
10152
+ Vector3 as Vector39
7531
10153
  } from "three";
7532
10154
 
7533
10155
  // src/scene-transitions/glsl.ts
@@ -7659,10 +10281,10 @@ function ParticleOverlay({
7659
10281
  onFinish
7660
10282
  }) {
7661
10283
  const { camera } = useThree15();
7662
- const meshRef = useRef21(null);
7663
- const startRef = useRef21(null);
7664
- const finishedRef = useRef21(false);
7665
- 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());
7666
10288
  const geometry = useMemo14(() => createParticleGeometry(), []);
7667
10289
  const material = useMemo14(
7668
10290
  () => new ShaderMaterial2({
@@ -7680,9 +10302,9 @@ function ParticleOverlay({
7680
10302
  }),
7681
10303
  [snapshot.texture]
7682
10304
  );
7683
- useEffect21(() => () => geometry.dispose(), [geometry]);
7684
- useEffect21(() => () => material.dispose(), [material]);
7685
- useEffect21(() => {
10305
+ useEffect22(() => () => geometry.dispose(), [geometry]);
10306
+ useEffect22(() => () => material.dispose(), [material]);
10307
+ useEffect22(() => {
7686
10308
  startRef.current = null;
7687
10309
  finishedRef.current = false;
7688
10310
  material.uniforms.progress.value = 0;
@@ -7718,8 +10340,8 @@ function ParticleOverlay({
7718
10340
 
7719
10341
  // src/scene-transitions/snapshot-overlay.tsx
7720
10342
  import { useFrame as useFrame10, useThree as useThree16 } from "@react-three/fiber";
7721
- import { useEffect as useEffect22, useMemo as useMemo15, useRef as useRef22 } from "react";
7722
- 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";
7723
10345
 
7724
10346
  // src/scene-transitions/snapshot-shaders.ts
7725
10347
  import { DoubleSide as DoubleSide3, ShaderMaterial as ShaderMaterial3, Vector2 as Vector25 } from "three";
@@ -8007,18 +10629,18 @@ function SnapshotOverlay({
8007
10629
  onFinish
8008
10630
  }) {
8009
10631
  const { camera, gl } = useThree16();
8010
- const meshRef = useRef22(null);
8011
- const startRef = useRef22(null);
8012
- const finishedRef = useRef22(false);
8013
- 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());
8014
10636
  const material = useMemo15(() => {
8015
10637
  if (!isSnapshotTransition(transition.preset)) {
8016
10638
  return null;
8017
10639
  }
8018
10640
  return createSnapshotMaterial(transition.preset, snapshot.texture);
8019
10641
  }, [snapshot.texture, transition.preset]);
8020
- useEffect22(() => () => material?.dispose(), [material]);
8021
- useEffect22(() => {
10642
+ useEffect23(() => () => material?.dispose(), [material]);
10643
+ useEffect23(() => {
8022
10644
  startRef.current = null;
8023
10645
  finishedRef.current = false;
8024
10646
  if (material) {
@@ -8102,8 +10724,8 @@ function TransitionOverlay(props) {
8102
10724
  import { useThree as useThree17 } from "@react-three/fiber";
8103
10725
  import {
8104
10726
  createContext as createContext11,
8105
- useContext as useContext20,
8106
- useEffect as useEffect23,
10727
+ useContext as useContext21,
10728
+ useEffect as useEffect24,
8107
10729
  useMemo as useMemo16
8108
10730
  } from "react";
8109
10731
 
@@ -8354,23 +10976,23 @@ function TileTextureManagerProvider({
8354
10976
  }),
8355
10977
  [anisotropy, maxConcurrentLoads, maxTextureMemoryMb]
8356
10978
  );
8357
- useEffect23(() => {
10979
+ useEffect24(() => {
8358
10980
  manager.resume();
8359
10981
  return () => manager.dispose();
8360
10982
  }, [manager]);
8361
10983
  return /* @__PURE__ */ jsx20(TileTextureManagerContext.Provider, { value: manager, children });
8362
10984
  }
8363
10985
  function useSharedTileTextureManager() {
8364
- return useContext20(TileTextureManagerContext);
10986
+ return useContext21(TileTextureManagerContext);
8365
10987
  }
8366
10988
 
8367
10989
  // src/tile/tile.tsx
8368
10990
  import { useFrame as useFrame11, useThree as useThree18 } from "@react-three/fiber";
8369
10991
  import {
8370
10992
  memo,
8371
- useEffect as useEffect24,
10993
+ useEffect as useEffect25,
8372
10994
  useMemo as useMemo17,
8373
- useRef as useRef23,
10995
+ useRef as useRef24,
8374
10996
  useState as useState10
8375
10997
  } from "react";
8376
10998
  import {
@@ -8382,7 +11004,7 @@ import {
8382
11004
  PerspectiveCamera as PerspectiveCamera4,
8383
11005
  SRGBColorSpace as SRGBColorSpace4,
8384
11006
  TextureLoader as TextureLoader4,
8385
- Vector3 as Vector311
11007
+ Vector3 as Vector312
8386
11008
  } from "three";
8387
11009
 
8388
11010
  // src/tile/face-layout.ts
@@ -8390,7 +11012,7 @@ import {
8390
11012
  Box3,
8391
11013
  Euler as Euler3,
8392
11014
  Quaternion as Quaternion2,
8393
- Vector3 as Vector310
11015
+ Vector3 as Vector311
8394
11016
  } from "three";
8395
11017
  var CUBE_FACES = ["f", "r", "b", "l", "u", "d"];
8396
11018
  var PREVIEW_FACE_ORDER = ["l", "f", "r", "b", "u", "d"];
@@ -8454,12 +11076,12 @@ function getTileBoundingBox(address, radius = CUBE_RADIUS) {
8454
11076
  const halfWidth = local.width / 2;
8455
11077
  const halfHeight = local.height / 2;
8456
11078
  const quaternion = getFaceQuaternion(address.face);
8457
- const position = new Vector310(...transform.position);
11079
+ const position = new Vector311(...transform.position);
8458
11080
  const corners = [
8459
- new Vector310(local.x - halfWidth, local.y - halfHeight, 0),
8460
- new Vector310(local.x + halfWidth, local.y - halfHeight, 0),
8461
- new Vector310(local.x - halfWidth, local.y + halfHeight, 0),
8462
- 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)
8463
11085
  ];
8464
11086
  for (const corner of corners) {
8465
11087
  corner.applyQuaternion(quaternion).add(position);
@@ -8577,9 +11199,9 @@ var PREVIEW_RADIUS = CUBE_RADIUS + 0.05;
8577
11199
  var SHARED_TILE_GEOMETRY = new PlaneGeometry4(1, 1);
8578
11200
  function usePreviewTexture(url, anisotropy, onError) {
8579
11201
  const [texture, setTexture] = useState10(null);
8580
- const onErrorRef = useRef23(onError);
11202
+ const onErrorRef = useRef24(onError);
8581
11203
  onErrorRef.current = onError;
8582
- useEffect24(() => {
11204
+ useEffect25(() => {
8583
11205
  if (!url) {
8584
11206
  setTexture(null);
8585
11207
  return;
@@ -8616,7 +11238,7 @@ function usePreviewTexture(url, anisotropy, onError) {
8616
11238
  active = false;
8617
11239
  };
8618
11240
  }, [anisotropy, url]);
8619
- useEffect24(
11241
+ useEffect25(
8620
11242
  () => () => {
8621
11243
  texture?.dispose();
8622
11244
  },
@@ -8647,7 +11269,7 @@ function PreviewFace({
8647
11269
  uv.needsUpdate = true;
8648
11270
  return nextGeometry;
8649
11271
  }, [face, faceOrder]);
8650
- useEffect24(
11272
+ useEffect25(
8651
11273
  () => () => {
8652
11274
  geometry.dispose();
8653
11275
  },
@@ -8695,7 +11317,7 @@ function useManagedTexture(manager, key, url, address) {
8695
11317
  snapshot: manager.getSnapshot(key)
8696
11318
  }));
8697
11319
  const snapshot = managedState.manager === manager && managedState.key === key && managedState.url === url ? managedState.snapshot : manager.getSnapshot(key);
8698
- useEffect24(
11320
+ useEffect25(
8699
11321
  () => manager.acquire(key, url, address, (nextSnapshot) => {
8700
11322
  setManagedState({
8701
11323
  manager,
@@ -8846,8 +11468,8 @@ function parentAddresses(child, parentLevel, parentFaceSize, tileSize) {
8846
11468
  return addresses;
8847
11469
  }
8848
11470
  function centerFacingAddress(candidates, camera) {
8849
- const direction = camera.getWorldDirection(new Vector311());
8850
- const center = new Vector311();
11471
+ const direction = camera.getWorldDirection(new Vector312());
11472
+ const center = new Vector312();
8851
11473
  let bestCandidate = candidates[0];
8852
11474
  let bestAlignment = -Infinity;
8853
11475
  for (const candidate of candidates) {
@@ -8930,9 +11552,9 @@ function Tile({
8930
11552
  onPreviewError
8931
11553
  );
8932
11554
  const sharedManager = useSharedTileTextureManager();
8933
- const progressRef = useRef23(onLoadProgress);
8934
- const errorRef = useRef23(onTileError);
8935
- const levelChangeRef = useRef23(onLevelChange);
11555
+ const progressRef = useRef24(onLoadProgress);
11556
+ const errorRef = useRef24(onTileError);
11557
+ const levelChangeRef = useRef24(onLevelChange);
8936
11558
  progressRef.current = onLoadProgress;
8937
11559
  errorRef.current = onTileError;
8938
11560
  levelChangeRef.current = onLevelChange;
@@ -8957,7 +11579,7 @@ function Tile({
8957
11579
  ]
8958
11580
  );
8959
11581
  const manager = sharedManager ?? ownedManager;
8960
- useEffect24(() => {
11582
+ useEffect25(() => {
8961
11583
  manager.resume();
8962
11584
  return () => {
8963
11585
  if (manager === ownedManager) {
@@ -8967,11 +11589,11 @@ function Tile({
8967
11589
  queueMicrotask(() => manager.releaseUnused());
8968
11590
  };
8969
11591
  }, [manager, ownedManager]);
8970
- const readyRef = useRef23(false);
8971
- useEffect24(() => {
11592
+ const readyRef = useRef24(false);
11593
+ useEffect25(() => {
8972
11594
  readyRef.current = false;
8973
11595
  }, [effectivePreviewUrl]);
8974
- useEffect24(() => {
11596
+ useEffect25(() => {
8975
11597
  if (!previewTexture || readyRef.current) {
8976
11598
  return;
8977
11599
  }
@@ -8987,23 +11609,23 @@ function Tile({
8987
11609
  [baseUrl, resolveTileUrl, template]
8988
11610
  );
8989
11611
  const [layers, setLayers] = useState10([]);
8990
- const layerTokenRef = useRef23("");
8991
- const currentLevelRef = useRef23(1);
8992
- const lastUpdateAtRef = useRef23(-Infinity);
8993
- const visibilityDirtyRef = useRef23(true);
8994
- const lastVisibilityQuaternionRef = useRef23(camera.quaternion.clone());
8995
- const lastVisibilityFovRef = useRef23(Number.NaN);
8996
- const lastViewportRef = useRef23({ width: 0, height: 0, dpr: 0 });
8997
- const frustumRef = useRef23(new Frustum());
8998
- const projectionMatrixRef = useRef23(new Matrix4());
8999
- const visibilityCameraRef = useRef23(new PerspectiveCamera4());
9000
- 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(() => {
9001
11623
  currentLevelRef.current = 1;
9002
11624
  layerTokenRef.current = "";
9003
11625
  visibilityDirtyRef.current = true;
9004
11626
  setLayers([]);
9005
11627
  }, [manager, multiresToken]);
9006
- useEffect24(() => {
11628
+ useEffect25(() => {
9007
11629
  if (loadMode !== "preview") {
9008
11630
  return;
9009
11631
  }
@@ -9154,9 +11776,9 @@ function SnapshotCapture({
9154
11776
  onCaptured
9155
11777
  }) {
9156
11778
  const { camera, gl, scene, size } = useThree19();
9157
- const capturedRequestRef = useRef24(0);
9158
- const renderTargetRef = useRef24(null);
9159
- useEffect25(
11779
+ const capturedRequestRef = useRef25(0);
11780
+ const renderTargetRef = useRef25(null);
11781
+ useEffect26(
9160
11782
  () => () => {
9161
11783
  renderTargetRef.current?.dispose();
9162
11784
  renderTargetRef.current = null;
@@ -9211,7 +11833,7 @@ function ScenesController({
9211
11833
  onTransitionError,
9212
11834
  snapshotMaxPixels = 3686400
9213
11835
  }) {
9214
- const controlsRef = useContext21(PanoramaViewContext);
11836
+ const controlsRef = useContext22(PanoramaViewContext);
9215
11837
  const manager = useSharedTileTextureManager();
9216
11838
  const transition = useMemo18(
9217
11839
  () => resolveTransition(transitionInput),
@@ -9234,13 +11856,13 @@ function ScenesController({
9234
11856
  const [transitionRunId, setTransitionRunId] = useState11(0);
9235
11857
  const [snapshot, setSnapshot] = useState11(null);
9236
11858
  const [recoveryKey, setRecoveryKey] = useState11(0);
9237
- const requestedSceneIdRef = useRef24(activeSceneId);
9238
- const captureReasonRef = useRef24("start");
9239
- const interactionReleaseRef = useRef24(null);
9240
- const slotsRef = useRef24(slots);
9241
- const phaseRef = useRef24(phase);
9242
- const liveSlotRef = useRef24(liveSlot);
9243
- 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);
9244
11866
  slotsRef.current = slots;
9245
11867
  phaseRef.current = phase;
9246
11868
  liveSlotRef.current = liveSlot;
@@ -9262,7 +11884,7 @@ function ScenesController({
9262
11884
  setPendingSlot(nextSlot);
9263
11885
  setPhase("preloading");
9264
11886
  }, []);
9265
- useEffect25(() => {
11887
+ useEffect26(() => {
9266
11888
  const requested = sceneMap.get(activeSceneId);
9267
11889
  if (!requested) {
9268
11890
  reportError(activeSceneId, new Error(`Unknown panorama scene: ${activeSceneId}`));
@@ -9364,12 +11986,12 @@ function ScenesController({
9364
11986
  });
9365
11987
  }
9366
11988
  }, [onTransitionEnd, pendingSlot, releaseInteraction, snapshot, transition.preset]);
9367
- useEffect25(() => () => {
11989
+ useEffect26(() => () => {
9368
11990
  releaseInteraction();
9369
11991
  snapshot?.dispose();
9370
11992
  }, [releaseInteraction, snapshot]);
9371
11993
  const { gl } = useThree19();
9372
- useEffect25(() => {
11994
+ useEffect26(() => {
9373
11995
  const canvas = gl.domElement;
9374
11996
  const onContextLost = (event) => {
9375
11997
  event.preventDefault();
@@ -9452,7 +12074,7 @@ function Scenes({
9452
12074
 
9453
12075
  // src/hotspot/image-hotspot.tsx
9454
12076
  import { useThree as useThree21 } from "@react-three/fiber";
9455
- 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";
9456
12078
  import {
9457
12079
  ClampToEdgeWrapping as ClampToEdgeWrapping3,
9458
12080
  LinearFilter as LinearFilter6,
@@ -9464,35 +12086,35 @@ import {
9464
12086
  // src/hotspot/hotspot-anchor.tsx
9465
12087
  import { useFrame as useFrame13, useThree as useThree20 } from "@react-three/fiber";
9466
12088
  import {
9467
- useContext as useContext23,
9468
- useEffect as useEffect27,
12089
+ useContext as useContext24,
12090
+ useEffect as useEffect28,
9469
12091
  useLayoutEffect as useLayoutEffect4,
9470
12092
  useMemo as useMemo20,
9471
- useRef as useRef25,
12093
+ useRef as useRef26,
9472
12094
  useState as useState13
9473
12095
  } from "react";
9474
12096
  import {
9475
12097
  Box3 as Box33,
9476
12098
  EdgesGeometry,
9477
- MathUtils as MathUtils6,
12099
+ MathUtils as MathUtils7,
9478
12100
  Matrix4 as Matrix42,
9479
12101
  Plane,
9480
12102
  PlaneGeometry as PlaneGeometry5,
9481
12103
  PerspectiveCamera as PerspectiveCamera5,
9482
12104
  Quaternion as Quaternion3,
9483
12105
  Ray,
9484
- Vector3 as Vector312
12106
+ Vector3 as Vector313
9485
12107
  } from "three";
9486
12108
 
9487
12109
  // src/hotspot/hotspot-tooltip.tsx
9488
- 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";
9489
12111
 
9490
12112
  // src/webvr/stereo-html.tsx
9491
12113
  import { Html } from "@react-three/drei";
9492
- import { useContext as useContext22, useSyncExternalStore as useSyncExternalStore6 } from "react";
12114
+ import { useContext as useContext23, useSyncExternalStore as useSyncExternalStore6 } from "react";
9493
12115
  import { Fragment as Fragment7, jsx as jsx23, jsxs as jsxs14 } from "react/jsx-runtime";
9494
12116
  function useFallbackStereoView() {
9495
- const runtime = useContext22(WebVRRuntimeContext);
12117
+ const runtime = useContext23(WebVRRuntimeContext);
9496
12118
  const host = runtime?.host ?? null;
9497
12119
  const fallback = useSyncExternalStore6(
9498
12120
  (onStoreChange) => host ? subscribeWebVRHost(host, onStoreChange) : () => void 0,
@@ -9609,7 +12231,7 @@ function HotspotTooltip({
9609
12231
  appearance
9610
12232
  }) {
9611
12233
  const [imageFailed, setImageFailed] = useState12(false);
9612
- useEffect26(() => {
12234
+ useEffect27(() => {
9613
12235
  setImageFailed(false);
9614
12236
  }, [content.image]);
9615
12237
  const showImage = Boolean(content.image) && !imageFailed;
@@ -9667,28 +12289,28 @@ var DEFAULT_REFERENCE_FOV = 75;
9667
12289
  var MIN_ANGULAR_SIZE = 0.01;
9668
12290
  var MAX_ANGULAR_SIZE = 179;
9669
12291
  var DRAG_EPSILON_DEGREES = 1e-3;
9670
- var LOCAL_FORWARD = new Vector312(0, 0, 1);
12292
+ var LOCAL_FORWARD = new Vector313(0, 0, 1);
9671
12293
  var TOOLTIP_WORLD_BOX = new Box33();
9672
12294
  var TOOLTIP_LOCAL_BOX = new Box33();
9673
- var TOOLTIP_CORNER = new Vector312();
12295
+ var TOOLTIP_CORNER = new Vector313();
9674
12296
  var TOOLTIP_INVERSE = new Matrix42();
9675
- var TOOLTIP_WORLD_CORNER = new Vector312();
9676
- var TOOLTIP_PROJECTED = new Vector312();
9677
- var TOOLTIP_RAY_ORIGIN = new Vector312();
9678
- var TOOLTIP_RAY_FAR = new Vector312();
9679
- 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();
9680
12302
  var TOOLTIP_RAY = new Ray();
9681
12303
  var TOOLTIP_PLANE = new Plane();
9682
- var TOOLTIP_INTERSECTION = new Vector312();
9683
- var TOOLTIP_PLANE_NORMAL = new Vector312();
9684
- 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();
9685
12307
  var HOTSPOT_MODE_RENDERING = {
9686
12308
  surface: { orientation: "surface", placement: "surface" },
9687
12309
  billboard: { orientation: "billboard", placement: "floating" }
9688
12310
  };
9689
12311
  function angularSizeToWorldSize(size, radius) {
9690
- const safeSize = Number.isFinite(size) ? MathUtils6.clamp(Math.abs(size), MIN_ANGULAR_SIZE, MAX_ANGULAR_SIZE) : MIN_ANGULAR_SIZE;
9691
- 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);
9692
12314
  }
9693
12315
  function resolveScale(scale) {
9694
12316
  return Number.isFinite(scale) && scale > 0 ? scale : 1;
@@ -9701,7 +12323,7 @@ function resolveDistance(placement, distance, width, height) {
9701
12323
  if (!Number.isFinite(distance)) {
9702
12324
  return DEFAULT_FLOATING_DISTANCE;
9703
12325
  }
9704
- return MathUtils6.clamp(Math.abs(distance), 0.1, maximumDistance);
12326
+ return MathUtils7.clamp(Math.abs(distance), 0.1, maximumDistance);
9705
12327
  }
9706
12328
  function applyHotspotTransform(group, camera, orientation2, surfaceQuaternion3, rotation, scaleMode, referenceFov, useAngularScale, worldWidth, worldHeight) {
9707
12329
  if (orientation2 === "billboard") {
@@ -9709,7 +12331,7 @@ function applyHotspotTransform(group, camera, orientation2, surfaceQuaternion3,
9709
12331
  } else {
9710
12332
  group.quaternion.copy(surfaceQuaternion3);
9711
12333
  }
9712
- group.rotateOnAxis(LOCAL_FORWARD, MathUtils6.degToRad(-rotation));
12334
+ group.rotateOnAxis(LOCAL_FORWARD, MathUtils7.degToRad(-rotation));
9713
12335
  const scaleFactor = scaleMode === "fixed" && camera instanceof PerspectiveCamera5 ? fixedScaleFactor(camera.fov, referenceFov) : 1;
9714
12336
  group.scale.set(
9715
12337
  (useAngularScale ? worldWidth : 1) * scaleFactor,
@@ -9719,33 +12341,33 @@ function applyHotspotTransform(group, camera, orientation2, surfaceQuaternion3,
9719
12341
  group.updateMatrixWorld();
9720
12342
  }
9721
12343
  function maximumHotspotDistance(width, height) {
9722
- const safeWidth = MathUtils6.clamp(
12344
+ const safeWidth = MathUtils7.clamp(
9723
12345
  Math.abs(Number.isFinite(width) ? width : MIN_ANGULAR_SIZE),
9724
12346
  MIN_ANGULAR_SIZE,
9725
12347
  MAX_ANGULAR_SIZE
9726
12348
  );
9727
- const safeHeight = MathUtils6.clamp(
12349
+ const safeHeight = MathUtils7.clamp(
9728
12350
  Math.abs(Number.isFinite(height) ? height : MIN_ANGULAR_SIZE),
9729
12351
  MIN_ANGULAR_SIZE,
9730
12352
  MAX_ANGULAR_SIZE
9731
12353
  );
9732
12354
  const cornerFactor = Math.hypot(
9733
12355
  1,
9734
- Math.tan(MathUtils6.degToRad(safeWidth) / 2),
9735
- Math.tan(MathUtils6.degToRad(safeHeight) / 2)
12356
+ Math.tan(MathUtils7.degToRad(safeWidth) / 2),
12357
+ Math.tan(MathUtils7.degToRad(safeHeight) / 2)
9736
12358
  );
9737
12359
  return (PANORAMA_RADIUS - PANORAMA_SURFACE_INSET) / cornerFactor;
9738
12360
  }
9739
12361
  function fixedScaleFactor(cameraFov, referenceFov) {
9740
- const safeReferenceFov = MathUtils6.clamp(referenceFov, 1, 179);
9741
- 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);
9742
12364
  }
9743
12365
  function createSurfaceQuaternion(position) {
9744
12366
  const outward = panoPositionToVector3(position).normalize();
9745
12367
  const inward = outward.clone().negate();
9746
- const pitch = MathUtils6.degToRad(position.pitch);
9747
- const yaw = MathUtils6.degToRad(position.yaw);
9748
- const localUp = new Vector312(
12368
+ const pitch = MathUtils7.degToRad(position.pitch);
12369
+ const yaw = MathUtils7.degToRad(position.yaw);
12370
+ const localUp = new Vector313(
9749
12371
  -Math.sin(pitch) * Math.sin(yaw),
9750
12372
  Math.cos(pitch),
9751
12373
  Math.sin(pitch) * Math.cos(yaw)
@@ -9765,7 +12387,7 @@ function makeInteractionEvent(id, position, event) {
9765
12387
  function angularDistance(a, b) {
9766
12388
  const aVector = panoPositionToVector3(a);
9767
12389
  const bVector = panoPositionToVector3(b);
9768
- return MathUtils6.radToDeg(aVector.angleTo(bVector));
12390
+ return MathUtils7.radToDeg(aVector.angleTo(bVector));
9769
12391
  }
9770
12392
  function isTooltipOpen(trigger, hovered, focused, pinned) {
9771
12393
  switch (trigger) {
@@ -9996,14 +12618,14 @@ function HotspotAnchor({
9996
12618
  onPositionChange,
9997
12619
  onDragEnd
9998
12620
  }) {
9999
- const controlsRef = useContext23(PanoramaViewContext);
10000
- const eventBus = useContext23(PanoEventBusContext);
12621
+ const controlsRef = useContext24(PanoramaViewContext);
12622
+ const eventBus = useContext24(PanoEventBusContext);
10001
12623
  const cursorApi = usePanoCursor();
10002
12624
  const { camera, size } = useThree20();
10003
- const groupRef = useRef25(null);
10004
- const tooltipAnchorRef = useRef25(null);
10005
- const dragStateRef = useRef25(null);
10006
- const suppressNextClickRef = useRef25(false);
12625
+ const groupRef = useRef26(null);
12626
+ const tooltipAnchorRef = useRef26(null);
12627
+ const dragStateRef = useRef26(null);
12628
+ const suppressNextClickRef = useRef26(false);
10007
12629
  const [hovered, setHovered] = useState13(false);
10008
12630
  const [dragging, setDragging] = useState13(false);
10009
12631
  const [pinned, setPinned] = useState13(false);
@@ -10060,14 +12682,14 @@ function HotspotAnchor({
10060
12682
  });
10061
12683
  const tooltipOpen = visible && tooltipContent !== null && isTooltipOpen(tooltipTrigger, hovered, focused, pinned);
10062
12684
  const cursorClaimId = hotspotCursorClaimId(id);
10063
- useEffect27(
12685
+ useEffect28(
10064
12686
  () => () => {
10065
12687
  dragStateRef.current?.releaseInteractionLock();
10066
12688
  dragStateRef.current = null;
10067
12689
  },
10068
12690
  []
10069
12691
  );
10070
- useEffect27(() => {
12692
+ useEffect28(() => {
10071
12693
  if (!cursorApi) {
10072
12694
  return;
10073
12695
  }
@@ -10089,14 +12711,14 @@ function HotspotAnchor({
10089
12711
  hovered,
10090
12712
  visible
10091
12713
  ]);
10092
- useEffect27(
12714
+ useEffect28(
10093
12715
  () => () => {
10094
12716
  cursorApi?.release(cursorClaimId);
10095
12717
  },
10096
12718
  [cursorApi, cursorClaimId]
10097
12719
  );
10098
- useEffect27(() => () => focusGeometry.dispose(), [focusGeometry]);
10099
- useEffect27(() => {
12720
+ useEffect28(() => () => focusGeometry.dispose(), [focusGeometry]);
12721
+ useEffect28(() => {
10100
12722
  if (tooltipTrigger !== "click") {
10101
12723
  setPinned(false);
10102
12724
  return;
@@ -10105,12 +12727,12 @@ function HotspotAnchor({
10105
12727
  setPinned(false);
10106
12728
  });
10107
12729
  }, [eventBus, tooltipTrigger]);
10108
- useEffect27(() => {
12730
+ useEffect28(() => {
10109
12731
  if (tooltipTrigger !== "hover") {
10110
12732
  setHovered(false);
10111
12733
  }
10112
12734
  }, [tooltipTrigger]);
10113
- useEffect27(() => {
12735
+ useEffect28(() => {
10114
12736
  if (acceptsPointer) {
10115
12737
  return;
10116
12738
  }
@@ -10455,11 +13077,11 @@ import { jsx as jsx27 } from "react/jsx-runtime";
10455
13077
  function useHotspotImageTexture(src, onLoad, onError) {
10456
13078
  const gl = useThree21((state) => state.gl);
10457
13079
  const [texture, setTexture] = useState14(null);
10458
- const onLoadRef = useRef26(onLoad);
10459
- const onErrorRef = useRef26(onError);
13080
+ const onLoadRef = useRef27(onLoad);
13081
+ const onErrorRef = useRef27(onError);
10460
13082
  onLoadRef.current = onLoad;
10461
13083
  onErrorRef.current = onError;
10462
- useEffect28(() => {
13084
+ useEffect29(() => {
10463
13085
  let active = true;
10464
13086
  setTexture(null);
10465
13087
  if (!src) {
@@ -10497,7 +13119,7 @@ function useHotspotImageTexture(src, onLoad, onError) {
10497
13119
  active = false;
10498
13120
  };
10499
13121
  }, [gl, src]);
10500
- useEffect28(
13122
+ useEffect29(
10501
13123
  () => () => {
10502
13124
  texture?.dispose();
10503
13125
  },
@@ -10519,7 +13141,7 @@ function ImageHotspot({
10519
13141
  }
10520
13142
 
10521
13143
  // src/hotspot/polygon-hotspot.tsx
10522
- 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";
10523
13145
  import {
10524
13146
  BufferGeometry,
10525
13147
  DoubleSide as DoubleSide5,
@@ -10528,20 +13150,20 @@ import {
10528
13150
  Quaternion as Quaternion4,
10529
13151
  ShapeUtils,
10530
13152
  Vector2 as Vector27,
10531
- Vector3 as Vector314
13153
+ Vector3 as Vector315
10532
13154
  } from "three";
10533
13155
 
10534
13156
  // src/hotspot/hotspot-stroke-line.tsx
10535
13157
  import { Line } from "@react-three/drei";
10536
13158
  import { useFrame as useFrame14, useThree as useThree22 } from "@react-three/fiber";
10537
- import { useLayoutEffect as useLayoutEffect5, useRef as useRef27 } from "react";
13159
+ import { useLayoutEffect as useLayoutEffect5, useRef as useRef28 } from "react";
10538
13160
  import {
10539
- MathUtils as MathUtils7,
13161
+ MathUtils as MathUtils8,
10540
13162
  PerspectiveCamera as PerspectiveCamera6,
10541
- Vector3 as Vector313
13163
+ Vector3 as Vector314
10542
13164
  } from "three";
10543
13165
  import { jsx as jsx28 } from "react/jsx-runtime";
10544
- var LINE_WORLD_POSITION = new Vector313();
13166
+ var LINE_WORLD_POSITION = new Vector314();
10545
13167
  function applyScreenSpaceDashScale(object, camera, viewportHeight) {
10546
13168
  const material = object?.material;
10547
13169
  if (!object || typeof material?.dashScale !== "number") {
@@ -10550,7 +13172,7 @@ function applyScreenSpaceDashScale(object, camera, viewportHeight) {
10550
13172
  object.getWorldPosition(LINE_WORLD_POSITION);
10551
13173
  const depth = Math.max(camera.position.distanceTo(LINE_WORLD_POSITION), 1);
10552
13174
  const fov = camera instanceof PerspectiveCamera6 ? camera.fov : 75;
10553
- 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);
10554
13176
  }
10555
13177
  function resolveDash(dashSize, gapSize) {
10556
13178
  if (dashSize === void 0 || !Number.isFinite(dashSize) || dashSize <= 0) {
@@ -10571,7 +13193,7 @@ function HotspotStrokeLine({
10571
13193
  dashSize,
10572
13194
  gapSize
10573
13195
  }) {
10574
- const lineRef = useRef27(null);
13196
+ const lineRef = useRef28(null);
10575
13197
  const { camera, size } = useThree22();
10576
13198
  const dash = resolveDash(dashSize, gapSize);
10577
13199
  useLayoutEffect5(() => {
@@ -10680,7 +13302,7 @@ function polygonContainsDirection(vertices, direction) {
10680
13302
  }
10681
13303
  function fitsHemisphere(vertices) {
10682
13304
  const directions = vertices.map((vertex) => panoPositionToVector3(vertex).normalize());
10683
- const candidates = [new Vector314()];
13305
+ const candidates = [new Vector315()];
10684
13306
  for (const direction of directions) {
10685
13307
  candidates[0].add(direction);
10686
13308
  candidates.push(direction.clone());
@@ -10704,7 +13326,7 @@ function validatePolygonVertices(vertices) {
10704
13326
  if (hasSelfIntersection(unwrapped)) {
10705
13327
  issues.push({ code: "self_intersection", message: "Polygon edges cannot cross." });
10706
13328
  }
10707
- 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))) {
10708
13330
  issues.push({ code: "contains_pole", message: "Polygons cannot contain a panorama pole." });
10709
13331
  }
10710
13332
  if (!fitsHemisphere(normalized)) {
@@ -10715,7 +13337,7 @@ function validatePolygonVertices(vertices) {
10715
13337
  function polygonCenter(vertices) {
10716
13338
  const sum = vertices.reduce(
10717
13339
  (total, vertex) => total.add(panoPositionToVector3(vertex).normalize()),
10718
- new Vector314()
13340
+ new Vector315()
10719
13341
  );
10720
13342
  return sum.lengthSq() > 1e-8 ? vector3ToPanoPosition(sum) : normalizePanoPosition(vertices[0]);
10721
13343
  }
@@ -10724,7 +13346,7 @@ function surfaceQuaternion(position) {
10724
13346
  const inward = outward.clone().negate();
10725
13347
  const pitch = position.pitch * Math.PI / 180;
10726
13348
  const yaw = position.yaw * Math.PI / 180;
10727
- const localUp = new Vector314(
13349
+ const localUp = new Vector315(
10728
13350
  -Math.sin(pitch) * Math.sin(yaw),
10729
13351
  Math.cos(pitch),
10730
13352
  Math.sin(pitch) * Math.cos(yaw)
@@ -10737,7 +13359,7 @@ function makeWorldToLocal(center) {
10737
13359
  return new Matrix43().compose(
10738
13360
  panoPositionToVector3(center, POLYGON_RADIUS),
10739
13361
  surfaceQuaternion(center),
10740
- new Vector314(1, 1, 1)
13362
+ new Vector315(1, 1, 1)
10741
13363
  ).invert();
10742
13364
  }
10743
13365
  function projectedPoint(a, b, c, weightB, weightC, radius, worldToLocal) {
@@ -10876,12 +13498,12 @@ function PolygonHotspot({
10876
13498
  [center, valid, vertices]
10877
13499
  );
10878
13500
  const resolvedStrokeOpacity = Math.max(0, Math.min(strokeOpacity, 1));
10879
- const startVerticesRef = useRef28(null);
13501
+ const startVerticesRef = useRef29(null);
10880
13502
  const issuesKey = issues.map((issue) => issue.code).join(",");
10881
- useEffect29(() => {
13503
+ useEffect30(() => {
10882
13504
  if (!valid) onInvalid?.(issues);
10883
13505
  }, [issues, issuesKey, onInvalid, valid]);
10884
- useEffect29(() => () => fillGeometry?.dispose(), [fillGeometry]);
13506
+ useEffect30(() => () => fillGeometry?.dispose(), [fillGeometry]);
10885
13507
  if (!valid || !center || !fillGeometry || !strokePoints || strokePoints.length < 2) {
10886
13508
  return null;
10887
13509
  }
@@ -10961,12 +13583,12 @@ function PolygonHotspot({
10961
13583
  }
10962
13584
 
10963
13585
  // src/hotspot/polyline-hotspot.tsx
10964
- 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";
10965
13587
  import {
10966
- MathUtils as MathUtils8,
13588
+ MathUtils as MathUtils9,
10967
13589
  Matrix4 as Matrix44,
10968
13590
  Quaternion as Quaternion5,
10969
- Vector3 as Vector315
13591
+ Vector3 as Vector316
10970
13592
  } from "three";
10971
13593
  import { jsx as jsx30 } from "react/jsx-runtime";
10972
13594
  var POLYLINE_RADIUS = 990;
@@ -10993,16 +13615,16 @@ function unwrapVertices(vertices) {
10993
13615
  function polylineCenter(vertices) {
10994
13616
  const sum = vertices.reduce(
10995
13617
  (total, vertex) => total.add(panoPositionToVector3(vertex).normalize()),
10996
- new Vector315()
13618
+ new Vector316()
10997
13619
  );
10998
13620
  return sum.lengthSq() > 1e-8 ? vector3ToPanoPosition(sum) : normalizePanoPosition(vertices[0]);
10999
13621
  }
11000
13622
  function surfaceQuaternion2(position) {
11001
13623
  const outward = panoPositionToVector3(position).normalize();
11002
13624
  const inward = outward.clone().negate();
11003
- const pitch = MathUtils8.degToRad(position.pitch);
11004
- const yaw = MathUtils8.degToRad(position.yaw);
11005
- const localUp = new Vector315(
13625
+ const pitch = MathUtils9.degToRad(position.pitch);
13626
+ const yaw = MathUtils9.degToRad(position.yaw);
13627
+ const localUp = new Vector316(
11006
13628
  -Math.sin(pitch) * Math.sin(yaw),
11007
13629
  Math.cos(pitch),
11008
13630
  Math.sin(pitch) * Math.cos(yaw)
@@ -11015,7 +13637,7 @@ function makeWorldToLocal2(center) {
11015
13637
  return new Matrix44().compose(
11016
13638
  panoPositionToVector3(center, POLYLINE_RADIUS),
11017
13639
  surfaceQuaternion2(center),
11018
- new Vector315(1, 1, 1)
13640
+ new Vector316(1, 1, 1)
11019
13641
  ).invert();
11020
13642
  }
11021
13643
  function subdivisionSteps(vertices) {
@@ -11030,7 +13652,7 @@ function subdivisionSteps(vertices) {
11030
13652
  }
11031
13653
  return Math.min(
11032
13654
  8,
11033
- Math.max(1, Math.ceil(MathUtils8.radToDeg(maxAngle) / MAX_SEGMENT_DEGREES))
13655
+ Math.max(1, Math.ceil(MathUtils9.radToDeg(maxAngle) / MAX_SEGMENT_DEGREES))
11034
13656
  );
11035
13657
  }
11036
13658
  function makeLinePositions(vertices, center) {
@@ -11093,8 +13715,8 @@ function PolylineHotspot({
11093
13715
  [center, valid, vertices]
11094
13716
  );
11095
13717
  const opacity = Math.max(0, Math.min(strokeOpacity, 1));
11096
- const startVerticesRef = useRef29(null);
11097
- useEffect30(() => {
13718
+ const startVerticesRef = useRef30(null);
13719
+ useEffect31(() => {
11098
13720
  if (!valid) onInvalid?.(issues);
11099
13721
  }, [issues, onInvalid, valid]);
11100
13722
  if (!valid || !center || !linePoints || linePoints.length < 2) return null;
@@ -11160,7 +13782,7 @@ function PolylineHotspot({
11160
13782
  }
11161
13783
 
11162
13784
  // src/hotspot/graphic-hotspot.tsx
11163
- 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";
11164
13786
  import {
11165
13787
  CanvasTexture,
11166
13788
  ClampToEdgeWrapping as ClampToEdgeWrapping4,
@@ -11358,11 +13980,11 @@ function createGraphicTexture(graphic, aspectWidth, aspectHeight) {
11358
13980
  }
11359
13981
  function useGraphicTexture(graphic, aspectWidth, aspectHeight, onLoad, onError) {
11360
13982
  const [texture, setTexture] = useState15(null);
11361
- const onLoadRef = useRef30(onLoad);
11362
- const onErrorRef = useRef30(onError);
13983
+ const onLoadRef = useRef31(onLoad);
13984
+ const onErrorRef = useRef31(onError);
11363
13985
  onLoadRef.current = onLoad;
11364
13986
  onErrorRef.current = onError;
11365
- useEffect31(() => {
13987
+ useEffect32(() => {
11366
13988
  let nextTexture = null;
11367
13989
  try {
11368
13990
  nextTexture = createGraphicTexture(graphic, aspectWidth, aspectHeight);
@@ -11401,7 +14023,7 @@ function GraphicHotspot(props) {
11401
14023
 
11402
14024
  // src/hotspot/sequence-hotspot.tsx
11403
14025
  import { useFrame as useFrame15, useThree as useThree23 } from "@react-three/fiber";
11404
- 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";
11405
14027
  import {
11406
14028
  ClampToEdgeWrapping as ClampToEdgeWrapping5,
11407
14029
  LinearFilter as LinearFilter8,
@@ -11425,11 +14047,11 @@ function useSpriteTexture({
11425
14047
  }) {
11426
14048
  const gl = useThree23((state) => state.gl);
11427
14049
  const [texture, setTexture] = useState16(null);
11428
- const onErrorRef = useRef31(onError);
11429
- const onLoadProgressRef = useRef31(onLoadProgress);
14050
+ const onErrorRef = useRef32(onError);
14051
+ const onLoadProgressRef = useRef32(onLoadProgress);
11430
14052
  onErrorRef.current = onError;
11431
14053
  onLoadProgressRef.current = onLoadProgress;
11432
- useEffect32(() => {
14054
+ useEffect33(() => {
11433
14055
  let active = true;
11434
14056
  setTexture(null);
11435
14057
  if (!src) {
@@ -11470,7 +14092,7 @@ function useSpriteTexture({
11470
14092
  active = false;
11471
14093
  };
11472
14094
  }, [gl, id, src]);
11473
- useEffect32(
14095
+ useEffect33(
11474
14096
  () => () => {
11475
14097
  texture?.dispose();
11476
14098
  },
@@ -11500,23 +14122,23 @@ function SequenceHotspot({
11500
14122
  const frameCount = resolveFrameCount(requestedFrameCount);
11501
14123
  const safeFps = resolveFps(fps);
11502
14124
  const [frameIndex, setFrameIndex] = useState16(0);
11503
- const elapsedRef = useRef31(0);
11504
- const frameIndexRef = useRef31(0);
11505
- const endedRef = useRef31(false);
11506
- const lastPlaybackStateRef = useRef31(null);
11507
- const onFrameChangeRef = useRef31(onFrameChange);
11508
- const onPlaybackStateChangeRef = useRef31(onPlaybackStateChange);
11509
- 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);
11510
14132
  onFrameChangeRef.current = onFrameChange;
11511
14133
  onPlaybackStateChangeRef.current = onPlaybackStateChange;
11512
14134
  onEndedRef.current = onEnded;
11513
- useEffect32(() => {
14135
+ useEffect33(() => {
11514
14136
  elapsedRef.current = 0;
11515
14137
  frameIndexRef.current = 0;
11516
14138
  endedRef.current = false;
11517
14139
  setFrameIndex(0);
11518
14140
  }, [frameCount, frameDirection, src]);
11519
- useEffect32(() => {
14141
+ useEffect33(() => {
11520
14142
  if (!texture) {
11521
14143
  return;
11522
14144
  }
@@ -11530,13 +14152,13 @@ function SequenceHotspot({
11530
14152
  );
11531
14153
  texture.needsUpdate = true;
11532
14154
  }, [frameCount, frameDirection, frameIndex, texture]);
11533
- useEffect32(() => {
14155
+ useEffect33(() => {
11534
14156
  if (!texture) {
11535
14157
  return;
11536
14158
  }
11537
14159
  onFrameChangeRef.current?.({ id, index: 0, src });
11538
14160
  }, [id, src, texture]);
11539
- useEffect32(() => {
14161
+ useEffect33(() => {
11540
14162
  if (!texture) {
11541
14163
  return;
11542
14164
  }
@@ -11590,7 +14212,7 @@ function SequenceHotspot({
11590
14212
 
11591
14213
  // src/hotspot/video-hotspot.tsx
11592
14214
  import { useThree as useThree24 } from "@react-three/fiber";
11593
- 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";
11594
14216
  import {
11595
14217
  ClampToEdgeWrapping as ClampToEdgeWrapping6,
11596
14218
  LinearFilter as LinearFilter9,
@@ -11609,9 +14231,9 @@ function clampVolume2(volume) {
11609
14231
  function usePosterTexture2(id, poster, onError) {
11610
14232
  const gl = useThree24((state) => state.gl);
11611
14233
  const [texture, setTexture] = useState17(null);
11612
- const onErrorRef = useRef32(onError);
14234
+ const onErrorRef = useRef33(onError);
11613
14235
  onErrorRef.current = onError;
11614
- useEffect33(() => {
14236
+ useEffect34(() => {
11615
14237
  let active = true;
11616
14238
  setTexture(null);
11617
14239
  if (!poster) {
@@ -11648,7 +14270,7 @@ function usePosterTexture2(id, poster, onError) {
11648
14270
  active = false;
11649
14271
  };
11650
14272
  }, [gl, id, poster]);
11651
- useEffect33(
14273
+ useEffect34(
11652
14274
  () => () => {
11653
14275
  texture?.dispose();
11654
14276
  },
@@ -11667,13 +14289,13 @@ function useVideoResource({
11667
14289
  src
11668
14290
  }) {
11669
14291
  const [resource, setResource] = useState17(null);
11670
- const onEndedRef = useRef32(onEnded);
11671
- const onErrorRef = useRef32(onError);
11672
- const onPlaybackStateChangeRef = useRef32(onPlaybackStateChange);
14292
+ const onEndedRef = useRef33(onEnded);
14293
+ const onErrorRef = useRef33(onError);
14294
+ const onPlaybackStateChangeRef = useRef33(onPlaybackStateChange);
11673
14295
  onEndedRef.current = onEnded;
11674
14296
  onErrorRef.current = onError;
11675
14297
  onPlaybackStateChangeRef.current = onPlaybackStateChange;
11676
- useEffect33(() => {
14298
+ useEffect34(() => {
11677
14299
  if (!src) {
11678
14300
  setResource(null);
11679
14301
  return;
@@ -11774,11 +14396,11 @@ function VideoHotspot({
11774
14396
  src
11775
14397
  });
11776
14398
  const posterTexture = usePosterTexture2(id, poster, onError);
11777
- const onPlaybackErrorRef = useRef32(onPlaybackError);
11778
- const onPlaybackStateChangeRef = useRef32(onPlaybackStateChange);
14399
+ const onPlaybackErrorRef = useRef33(onPlaybackError);
14400
+ const onPlaybackStateChangeRef = useRef33(onPlaybackStateChange);
11779
14401
  onPlaybackErrorRef.current = onPlaybackError;
11780
14402
  onPlaybackStateChangeRef.current = onPlaybackStateChange;
11781
- useEffect33(() => {
14403
+ useEffect34(() => {
11782
14404
  if (!resource) {
11783
14405
  return;
11784
14406
  }
@@ -11788,7 +14410,7 @@ function VideoHotspot({
11788
14410
  resource.video.playsInline = playsInline;
11789
14411
  resource.video.preload = preload;
11790
14412
  }, [loop, muted, playsInline, preload, resource, volume]);
11791
- useEffect33(() => {
14413
+ useEffect34(() => {
11792
14414
  if (!resource) {
11793
14415
  return;
11794
14416
  }
@@ -11814,16 +14436,314 @@ function VideoHotspot({
11814
14436
  return /* @__PURE__ */ jsx33(HotspotAnchor, { ...anchorProps, id, height, width, children: /* @__PURE__ */ jsx33(HotspotPlane, { map: activeTexture, opacity }) });
11815
14437
  }
11816
14438
 
11817
- // src/hotspot/text-hotspot.tsx
11818
- 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";
11819
14442
  import {
11820
14443
  CanvasTexture as CanvasTexture2,
11821
14444
  ClampToEdgeWrapping as ClampToEdgeWrapping7,
11822
14445
  LinearFilter as LinearFilter10,
11823
14446
  LinearMipmapLinearFilter as LinearMipmapLinearFilter7,
11824
- SRGBColorSpace as SRGBColorSpace9
14447
+ SRGBColorSpace as SRGBColorSpace9,
14448
+ TextureLoader as TextureLoader8
11825
14449
  } from "three";
11826
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";
11827
14747
  var TEXT_TEXTURE_LONG_SIDE = 1024;
11828
14748
  var DEFAULT_FONT_FAMILY = "system-ui, sans-serif";
11829
14749
  var DEFAULT_FONT_SIZE = 96;
@@ -12032,23 +14952,23 @@ function createTextTexture(text, width, height, style) {
12032
14952
  throw new Error("Canvas 2D is unavailable for this text hotspot.");
12033
14953
  }
12034
14954
  drawTextHotspot(context, canvasWidth, canvasHeight, text, style);
12035
- const texture = new CanvasTexture2(canvas);
12036
- texture.colorSpace = SRGBColorSpace9;
12037
- texture.wrapS = ClampToEdgeWrapping7;
12038
- texture.wrapT = ClampToEdgeWrapping7;
12039
- texture.magFilter = LinearFilter10;
12040
- 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;
12041
14961
  texture.generateMipmaps = true;
12042
14962
  texture.needsUpdate = true;
12043
14963
  return texture;
12044
14964
  }
12045
14965
  function useTextTexture(text, width, height, style, onLoad, onError) {
12046
- const [texture, setTexture] = useState18(null);
12047
- const onLoadRef = useRef33(onLoad);
12048
- const onErrorRef = useRef33(onError);
14966
+ const [texture, setTexture] = useState19(null);
14967
+ const onLoadRef = useRef35(onLoad);
14968
+ const onErrorRef = useRef35(onError);
12049
14969
  onLoadRef.current = onLoad;
12050
14970
  onErrorRef.current = onError;
12051
- useEffect34(() => {
14971
+ useEffect36(() => {
12052
14972
  let cancelled = false;
12053
14973
  let nextTexture = null;
12054
14974
  const run = async () => {
@@ -12141,13 +15061,13 @@ function TextHotspot({
12141
15061
  whiteSpace
12142
15062
  };
12143
15063
  const texture = useTextTexture(text, width, height, style, onLoad, onError);
12144
- 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 }) });
12145
15065
  }
12146
15066
 
12147
15067
  // src/hotspot/iframe-hotspot.tsx
12148
15068
  import { Html as Html2 } from "@react-three/drei";
12149
15069
  import { DoubleSide as DoubleSide6 } from "three";
12150
- import { jsx as jsx35, jsxs as jsxs19 } from "react/jsx-runtime";
15070
+ import { jsx as jsx36, jsxs as jsxs19 } from "react/jsx-runtime";
12151
15071
  var IFRAME_LONG_SIDE = 800;
12152
15072
  var CSS3D_DISTANCE_FACTOR = 400;
12153
15073
  var DEFAULT_SANDBOX = "allow-scripts allow-popups allow-forms";
@@ -12214,8 +15134,8 @@ function IframeHotspot({
12214
15134
  width,
12215
15135
  children: [
12216
15136
  /* @__PURE__ */ jsxs19("mesh", { children: [
12217
- /* @__PURE__ */ jsx35("planeGeometry", { args: [1, 1] }),
12218
- /* @__PURE__ */ jsx35(
15137
+ /* @__PURE__ */ jsx36("planeGeometry", { args: [1, 1] }),
15138
+ /* @__PURE__ */ jsx36(
12219
15139
  "meshBasicMaterial",
12220
15140
  {
12221
15141
  depthWrite: false,
@@ -12226,7 +15146,7 @@ function IframeHotspot({
12226
15146
  }
12227
15147
  )
12228
15148
  ] }),
12229
- /* @__PURE__ */ jsx35(
15149
+ /* @__PURE__ */ jsx36(
12230
15150
  Html2,
12231
15151
  {
12232
15152
  distanceFactor: CSS3D_DISTANCE_FACTOR,
@@ -12241,7 +15161,7 @@ function IframeHotspot({
12241
15161
  },
12242
15162
  transform: true,
12243
15163
  zIndexRange: [10, 0],
12244
- children: /* @__PURE__ */ jsx35(
15164
+ children: /* @__PURE__ */ jsx36(
12245
15165
  "iframe",
12246
15166
  {
12247
15167
  allow,
@@ -12262,7 +15182,9 @@ function IframeHotspot({
12262
15182
  );
12263
15183
  }
12264
15184
  export {
15185
+ AudioHotspot,
12265
15186
  AutoRotate,
15187
+ BackgroundAudio,
12266
15188
  DEFAULT_HOTSPOT_TOOLTIP_APPEARANCE,
12267
15189
  DEFAULT_HOTSPOT_TOOLTIP_OFFSET,
12268
15190
  DEFAULT_PANO_CURSORS,
@@ -12313,4 +15235,28 @@ export {
12313
15235
  validatePolylineVertices,
12314
15236
  vector3ToPanoPosition
12315
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
+ */
12316
15262
  //# sourceMappingURL=index.mjs.map