@ericchen1990/pano-view 3.2.3 → 3.4.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
@@ -9716,8 +9716,8 @@ function usePanoViewer() {
9716
9716
  }
9717
9717
 
9718
9718
  // src/sphere-tile/sphere-tile.tsx
9719
- import { useFrame as useFrame9, useThree as useThree13 } from "@react-three/fiber";
9720
- import { memo, useCallback as useCallback9, useEffect as useEffect22, useMemo as useMemo14, useRef as useRef23, useState as useState10 } from "react";
9719
+ import { useFrame as useFrame9, useThree as useThree14 } from "@react-three/fiber";
9720
+ import { memo, useCallback as useCallback9, useEffect as useEffect23, useMemo as useMemo15, useRef as useRef23, useState as useState10 } from "react";
9721
9721
  import { BackSide as BackSide2, Frustum, Matrix4 as Matrix42, PerspectiveCamera as PerspectiveCamera3 } from "three";
9722
9722
 
9723
9723
  // src/asset-url.ts
@@ -9988,6 +9988,27 @@ function PanoBasicMaterial({
9988
9988
  );
9989
9989
  }
9990
9990
 
9991
+ // src/scene-detail.tsx
9992
+ import { createContext as createContext15, useContext as useContext21 } from "react";
9993
+ var SceneDetailContext = createContext15(null);
9994
+ function useSceneDetailReporter() {
9995
+ return useContext21(SceneDetailContext);
9996
+ }
9997
+ function viewTilesAreDrawable(textures) {
9998
+ return textures.length > 0 && textures.every((texture) => texture != null);
9999
+ }
10000
+ function publishSceneDetail(reporter, lastToken, ready) {
10001
+ if (!reporter) {
10002
+ return;
10003
+ }
10004
+ const token = `${reporter.generation}:${ready ? 1 : 0}`;
10005
+ if (lastToken.current === token) {
10006
+ return;
10007
+ }
10008
+ lastToken.current = token;
10009
+ reporter.report(ready);
10010
+ }
10011
+
9991
10012
  // src/tile/texture-manager.ts
9992
10013
  import {
9993
10014
  ClampToEdgeWrapping,
@@ -10014,6 +10035,9 @@ var TileTextureManager = class {
10014
10035
  this.generation = 0;
10015
10036
  this.options = options;
10016
10037
  }
10038
+ get memoryBudgetBytes() {
10039
+ return this.options.maxBytes;
10040
+ }
10017
10041
  resume() {
10018
10042
  this.disposed = false;
10019
10043
  this.drain();
@@ -10081,7 +10105,7 @@ var TileTextureManager = class {
10081
10105
  this.totalBytes = 0;
10082
10106
  }
10083
10107
  /**
10084
- * Releases textures that are no longer rendered by any Tile instance.
10108
+ * Releases textures that are no longer rendered by any tile source.
10085
10109
  * Scene transitions call this after the outgoing panorama has been
10086
10110
  * snapshotted, so the incoming scene never competes with stale GPU tiles.
10087
10111
  */
@@ -10215,8 +10239,44 @@ var TileTextureManager = class {
10215
10239
  }
10216
10240
  };
10217
10241
 
10242
+ // src/tile/texture-manager-context.tsx
10243
+ import { useThree as useThree13 } from "@react-three/fiber";
10244
+ import {
10245
+ createContext as createContext16,
10246
+ useContext as useContext22,
10247
+ useEffect as useEffect21,
10248
+ useMemo as useMemo14
10249
+ } from "react";
10250
+ import { jsx as jsx15 } from "react/jsx-runtime";
10251
+ var TileTextureManagerContext = createContext16(null);
10252
+ function TileTextureManagerProvider({
10253
+ children,
10254
+ maxTextureMemoryMb = 128,
10255
+ maxConcurrentLoads = 4
10256
+ }) {
10257
+ const gl = useThree13((state) => state.gl);
10258
+ const anisotropy = gl.capabilities.getMaxAnisotropy();
10259
+ const manager = useMemo14(
10260
+ () => new TileTextureManager({
10261
+ anisotropy,
10262
+ maxBytes: Math.max(1, maxTextureMemoryMb) * 1024 * 1024,
10263
+ concurrency: Math.max(1, Math.floor(maxConcurrentLoads)),
10264
+ retryCount: 1
10265
+ }),
10266
+ [anisotropy, maxConcurrentLoads, maxTextureMemoryMb]
10267
+ );
10268
+ useEffect21(() => {
10269
+ manager.resume();
10270
+ return () => manager.dispose();
10271
+ }, [manager]);
10272
+ return /* @__PURE__ */ jsx15(TileTextureManagerContext.Provider, { value: manager, children });
10273
+ }
10274
+ function useSharedTileTextureManager() {
10275
+ return useContext22(TileTextureManagerContext);
10276
+ }
10277
+
10218
10278
  // src/tile/texture-hooks.ts
10219
- import { useEffect as useEffect21, useRef as useRef22, useState as useState9 } from "react";
10279
+ import { useEffect as useEffect22, useRef as useRef22, useState as useState9 } from "react";
10220
10280
  import {
10221
10281
  ClampToEdgeWrapping as ClampToEdgeWrapping2,
10222
10282
  LinearFilter as LinearFilter2,
@@ -10227,7 +10287,7 @@ function usePreviewTexture(url, anisotropy, onError) {
10227
10287
  const [texture, setTexture] = useState9(null);
10228
10288
  const onErrorRef = useRef22(onError);
10229
10289
  onErrorRef.current = onError;
10230
- useEffect21(() => {
10290
+ useEffect22(() => {
10231
10291
  if (!url) {
10232
10292
  setTexture(null);
10233
10293
  return;
@@ -10264,7 +10324,7 @@ function usePreviewTexture(url, anisotropy, onError) {
10264
10324
  active = false;
10265
10325
  };
10266
10326
  }, [anisotropy, url]);
10267
- useEffect21(
10327
+ useEffect22(
10268
10328
  () => () => {
10269
10329
  texture?.dispose();
10270
10330
  },
@@ -10280,7 +10340,7 @@ function useManagedTexture(manager, key, url, address) {
10280
10340
  snapshot: manager.getSnapshot(key)
10281
10341
  }));
10282
10342
  const snapshot = managedState.manager === manager && managedState.key === key && managedState.url === url ? managedState.snapshot : manager.getSnapshot(key);
10283
- useEffect21(
10343
+ useEffect22(
10284
10344
  () => manager.acquire(key, url, address, (nextSnapshot) => {
10285
10345
  setManagedState({
10286
10346
  manager,
@@ -10428,14 +10488,23 @@ function preferredSphereLevel(levels, height, dpr, verticalFov) {
10428
10488
  }
10429
10489
 
10430
10490
  // src/sphere-tile/sphere-tile.tsx
10431
- import { jsx as jsx15, jsxs as jsxs9 } from "react/jsx-runtime";
10491
+ import { jsx as jsx16, jsxs as jsxs9 } from "react/jsx-runtime";
10492
+ function sphereTileViewShouldRefresh(input) {
10493
+ if (input.loadModeChanged || input.managerChanged) {
10494
+ return true;
10495
+ }
10496
+ if (input.elapsedMs < 100 || input.viewUnchanged) {
10497
+ return false;
10498
+ }
10499
+ return true;
10500
+ }
10432
10501
  function SpherePatch({
10433
10502
  address,
10434
10503
  texture,
10435
10504
  yawOffset,
10436
10505
  preview = false
10437
10506
  }) {
10438
- const geometry = useMemo14(
10507
+ const geometry = useMemo15(
10439
10508
  () => sphereTileGeometry(
10440
10509
  address,
10441
10510
  yawOffset,
@@ -10443,13 +10512,13 @@ function SpherePatch({
10443
10512
  ),
10444
10513
  [address, yawOffset, preview]
10445
10514
  );
10446
- useEffect22(() => () => geometry.dispose(), [geometry]);
10447
- return /* @__PURE__ */ jsx15(
10515
+ useEffect23(() => () => geometry.dispose(), [geometry]);
10516
+ return /* @__PURE__ */ jsx16(
10448
10517
  "mesh",
10449
10518
  {
10450
10519
  geometry,
10451
10520
  renderOrder: preview ? -1e3 : -900 + address.level,
10452
- children: /* @__PURE__ */ jsx15(
10521
+ children: /* @__PURE__ */ jsx16(
10453
10522
  PanoBasicMaterial,
10454
10523
  {
10455
10524
  map: texture,
@@ -10476,10 +10545,10 @@ var ManagedPatch = memo(function ManagedPatch2({
10476
10545
  url,
10477
10546
  address
10478
10547
  );
10479
- useEffect22(() => {
10548
+ useEffect23(() => {
10480
10549
  if (snapshot.texture) ready();
10481
10550
  }, [snapshot.texture, ready]);
10482
- return snapshot.texture ? /* @__PURE__ */ jsx15(
10551
+ return snapshot.texture ? /* @__PURE__ */ jsx16(
10483
10552
  SpherePatch,
10484
10553
  {
10485
10554
  address,
@@ -10507,7 +10576,7 @@ function SphereTileSource({
10507
10576
  onTileError,
10508
10577
  onLevelChange
10509
10578
  }) {
10510
- const { camera, gl, size } = useThree13();
10579
+ const { camera, gl, size } = useThree14();
10511
10580
  const anisotropy = gl.capabilities.getMaxAnisotropy();
10512
10581
  const preview = usePreviewTexture(
10513
10582
  resolveAssetUrl(baseUrl, previewUrl),
@@ -10521,14 +10590,15 @@ function SphereTileSource({
10521
10590
  onLevelChange
10522
10591
  });
10523
10592
  callbacks.current = { onReady, onLoadProgress, onTileError, onLevelChange };
10524
- const budget = Math.max(
10593
+ const sharedManager = useSharedTileTextureManager();
10594
+ const ownedBudget = Math.max(
10525
10595
  1,
10526
10596
  Number.isFinite(maxTextureMemoryMb) ? maxTextureMemoryMb : 128
10527
10597
  ) * 1024 * 1024;
10528
- const manager = useMemo14(
10598
+ const ownedManager = useMemo15(
10529
10599
  () => new TileTextureManager({
10530
10600
  anisotropy,
10531
- maxBytes: budget,
10601
+ maxBytes: ownedBudget,
10532
10602
  concurrency: Math.max(
10533
10603
  1,
10534
10604
  Math.floor(
@@ -10542,8 +10612,10 @@ function SphereTileSource({
10542
10612
  onProgress: (progress) => callbacks.current.onLoadProgress?.(progress),
10543
10613
  onError: (error) => callbacks.current.onTileError?.(error)
10544
10614
  }),
10545
- [anisotropy, budget, maxConcurrentLoads, retryCount]
10615
+ [anisotropy, ownedBudget, maxConcurrentLoads, retryCount]
10546
10616
  );
10617
+ const manager = sharedManager ?? ownedManager;
10618
+ const budget = manager.memoryBudgetBytes;
10547
10619
  const readyRef = useRef23(false);
10548
10620
  const ready = useCallback9(() => {
10549
10621
  if (!readyRef.current) {
@@ -10551,21 +10623,27 @@ function SphereTileSource({
10551
10623
  callbacks.current.onReady?.();
10552
10624
  }
10553
10625
  }, []);
10554
- useEffect22(() => {
10626
+ useEffect23(() => {
10555
10627
  if (preview) ready();
10556
10628
  }, [preview, ready]);
10557
- useEffect22(() => {
10629
+ useEffect23(() => {
10558
10630
  manager.resume();
10559
- return () => manager.dispose();
10560
- }, [manager]);
10561
- const resolveUrl = useMemo14(
10631
+ return () => {
10632
+ if (manager === ownedManager) {
10633
+ manager.dispose();
10634
+ return;
10635
+ }
10636
+ queueMicrotask(() => manager.releaseUnused());
10637
+ };
10638
+ }, [manager, ownedManager]);
10639
+ const resolveUrl = useMemo15(
10562
10640
  () => (address) => resolveAssetUrl(
10563
10641
  baseUrl,
10564
10642
  resolveTileUrl ? resolveTileUrl(address) : resolveSphereTemplateUrl(urlTemplate, address, indexBase)
10565
10643
  ),
10566
10644
  [baseUrl, resolveTileUrl, urlTemplate, indexBase]
10567
10645
  );
10568
- const candidates = useMemo14(
10646
+ const candidates = useMemo15(
10569
10647
  () => config.levels.map(
10570
10648
  (level, index) => sphereTileAddresses(level, index, config.tileSize).map((address) => ({
10571
10649
  address,
@@ -10574,12 +10652,17 @@ function SphereTileSource({
10574
10652
  ),
10575
10653
  [config, yawOffset]
10576
10654
  );
10577
- const previewAddress = useMemo14(
10655
+ const previewAddress = useMemo15(
10578
10656
  () => sphereTileAddresses({ width: 2, height: 1 }, 0, 2)[0],
10579
10657
  []
10580
10658
  );
10581
10659
  const [layers, setLayers] = useState10([]);
10582
- const scratch = useMemo14(
10660
+ const detailReporter = useSceneDetailReporter();
10661
+ const detailReporterRef = useRef23(detailReporter);
10662
+ detailReporterRef.current = detailReporter;
10663
+ const detailTokenRef = useRef23("");
10664
+ const targetKeysRef = useRef23([]);
10665
+ const scratch = useMemo15(
10583
10666
  () => ({
10584
10667
  camera: new PerspectiveCamera3(),
10585
10668
  frustum: new Frustum(),
@@ -10600,56 +10683,75 @@ function SphereTileSource({
10600
10683
  useFrame9(() => {
10601
10684
  if (!(camera instanceof PerspectiveCamera3)) return;
10602
10685
  const now = performance.now(), dpr = gl.getPixelRatio();
10603
- const reset = scratch.manager !== manager || scratch.loadMode !== loadMode;
10604
- if (!reset && (now - scratch.time < 100 || scratch.fov === camera.fov && scratch.width === size.width && scratch.height === size.height && scratch.dpr === dpr && scratch.quaternion.angleTo(camera.quaternion) < 1e-4))
10605
- return;
10606
- scratch.time = now;
10607
- scratch.fov = camera.fov;
10608
- scratch.width = size.width;
10609
- scratch.height = size.height;
10610
- scratch.dpr = dpr;
10611
- scratch.quaternion.copy(camera.quaternion);
10612
- scratch.manager = manager;
10613
- scratch.loadMode = loadMode;
10614
- scratch.camera.copy(camera, false);
10615
- scratch.camera.fov = Math.min(179, camera.fov + 8);
10616
- scratch.camera.updateProjectionMatrix();
10617
- scratch.camera.updateMatrixWorld();
10618
- scratch.matrix.multiplyMatrices(
10619
- scratch.camera.projectionMatrix,
10620
- scratch.camera.matrixWorldInverse
10621
- );
10622
- scratch.frustum.setFromProjectionMatrix(scratch.matrix);
10623
- let level = loadMode === "preview" ? -1 : loadMode === "base" ? 0 : preferredSphereLevel(config.levels, size.height, dpr, camera.fov);
10624
- const next = [];
10625
- let residentBytes = 0;
10626
- for (let index = 0; index <= level; index++) {
10627
- const addresses = candidates[index].filter(
10628
- ({ bounds }) => scratch.frustum.intersectsBox(bounds)
10629
- ).map(({ address }) => address);
10630
- const bytes = addresses.reduce(
10631
- (total, address) => total + address.width * address.height * 4,
10632
- 0
10686
+ const managerChanged = scratch.manager !== manager;
10687
+ const loadModeChanged = scratch.loadMode !== loadMode;
10688
+ const viewUnchanged = scratch.fov === camera.fov && scratch.width === size.width && scratch.height === size.height && scratch.dpr === dpr && scratch.quaternion.angleTo(camera.quaternion) < 1e-4;
10689
+ if (sphereTileViewShouldRefresh({
10690
+ loadModeChanged,
10691
+ managerChanged,
10692
+ elapsedMs: now - scratch.time,
10693
+ viewUnchanged
10694
+ })) {
10695
+ const reset = managerChanged || loadModeChanged;
10696
+ scratch.time = now;
10697
+ scratch.fov = camera.fov;
10698
+ scratch.width = size.width;
10699
+ scratch.height = size.height;
10700
+ scratch.dpr = dpr;
10701
+ scratch.quaternion.copy(camera.quaternion);
10702
+ scratch.manager = manager;
10703
+ scratch.loadMode = loadMode;
10704
+ scratch.camera.copy(camera, false);
10705
+ scratch.camera.fov = Math.min(179, camera.fov + 8);
10706
+ scratch.camera.updateProjectionMatrix();
10707
+ scratch.camera.updateMatrixWorld();
10708
+ scratch.matrix.multiplyMatrices(
10709
+ scratch.camera.projectionMatrix,
10710
+ scratch.camera.matrixWorldInverse
10633
10711
  );
10634
- if (residentBytes + bytes > budget) {
10635
- level = index - 1;
10636
- break;
10712
+ scratch.frustum.setFromProjectionMatrix(scratch.matrix);
10713
+ let level = loadMode === "preview" ? -1 : loadMode === "base" ? 0 : preferredSphereLevel(config.levels, size.height, dpr, camera.fov);
10714
+ const next = [];
10715
+ let residentBytes = 0;
10716
+ for (let index = 0; index <= level; index++) {
10717
+ const addresses = candidates[index].filter(
10718
+ ({ bounds }) => scratch.frustum.intersectsBox(bounds)
10719
+ ).map(({ address }) => address);
10720
+ const bytes = addresses.reduce(
10721
+ (total, address) => total + address.width * address.height * 4,
10722
+ 0
10723
+ );
10724
+ if (residentBytes + bytes > budget) {
10725
+ level = index - 1;
10726
+ break;
10727
+ }
10728
+ residentBytes += bytes;
10729
+ next.push({ level: index, addresses });
10730
+ }
10731
+ const targetLayer = loadMode === "full" ? next[next.length - 1] : void 0;
10732
+ targetKeysRef.current = targetLayer ? targetLayer.addresses.map(
10733
+ (address) => `${resolveUrl(address)}\0${sphereTileKey(address)}`
10734
+ ) : [];
10735
+ if (level !== scratch.level) {
10736
+ scratch.level = level;
10737
+ if (level >= 0) callbacks.current.onLevelChange?.(level);
10738
+ }
10739
+ const token = next.map((layer) => layer.addresses.map(sphereTileKey).join(",")).join(";");
10740
+ if (token !== scratch.token || reset) {
10741
+ scratch.token = token;
10742
+ setLayers(next);
10637
10743
  }
10638
- residentBytes += bytes;
10639
- next.push({ level: index, addresses });
10640
- }
10641
- if (level !== scratch.level) {
10642
- scratch.level = level;
10643
- if (level >= 0) callbacks.current.onLevelChange?.(level);
10644
- }
10645
- const token = next.map((layer) => layer.addresses.map(sphereTileKey).join(",")).join(";");
10646
- if (token !== scratch.token || reset) {
10647
- scratch.token = token;
10648
- setLayers(next);
10649
10744
  }
10745
+ publishSceneDetail(
10746
+ detailReporterRef.current,
10747
+ detailTokenRef,
10748
+ loadMode === "full" && viewTilesAreDrawable(
10749
+ targetKeysRef.current.map((key) => manager.getSnapshot(key).texture)
10750
+ )
10751
+ );
10650
10752
  });
10651
10753
  return /* @__PURE__ */ jsxs9("group", { visible, children: [
10652
- preview ? /* @__PURE__ */ jsx15(
10754
+ preview ? /* @__PURE__ */ jsx16(
10653
10755
  SpherePatch,
10654
10756
  {
10655
10757
  address: previewAddress,
@@ -10659,7 +10761,7 @@ function SphereTileSource({
10659
10761
  }
10660
10762
  ) : null,
10661
10763
  loadMode !== "preview" ? layers.flatMap(
10662
- (layer) => layer.addresses.map((address) => /* @__PURE__ */ jsx15(
10764
+ (layer) => layer.addresses.map((address) => /* @__PURE__ */ jsx16(
10663
10765
  ManagedPatch,
10664
10766
  {
10665
10767
  address,
@@ -10675,14 +10777,14 @@ function SphereTileSource({
10675
10777
  }
10676
10778
  function SphereTile({ multires, ...props }) {
10677
10779
  const token = typeof multires === "string" ? multires : JSON.stringify(multires);
10678
- const config = useMemo14(() => parseSphereMultires(multires), [token]);
10780
+ const config = useMemo15(() => parseSphereMultires(multires), [token]);
10679
10781
  const sourceKey = `${props.baseUrl}\0${token}\0${props.previewUrl}\0${props.urlTemplate ?? ""}\0${props.indexBase ?? 1}`;
10680
- return /* @__PURE__ */ jsx15(SphereTileSource, { ...props, config }, sourceKey);
10782
+ return /* @__PURE__ */ jsx16(SphereTileSource, { ...props, config }, sourceKey);
10681
10783
  }
10682
10784
 
10683
10785
  // src/sphere.tsx
10684
- import { useThree as useThree14 } from "@react-three/fiber";
10685
- import { useEffect as useEffect23, useMemo as useMemo15, useRef as useRef24, useState as useState11 } from "react";
10786
+ import { useThree as useThree15 } from "@react-three/fiber";
10787
+ import { useEffect as useEffect24, useMemo as useMemo16, useRef as useRef24, useState as useState11 } from "react";
10686
10788
  import {
10687
10789
  BackSide as BackSide3,
10688
10790
  LinearFilter as LinearFilter3,
@@ -10692,14 +10794,14 @@ import {
10692
10794
  SRGBColorSpace as SRGBColorSpace3,
10693
10795
  TextureLoader as TextureLoader3
10694
10796
  } from "three";
10695
- import { jsx as jsx16, jsxs as jsxs10 } from "react/jsx-runtime";
10797
+ import { jsx as jsx17, jsxs as jsxs10 } from "react/jsx-runtime";
10696
10798
  function useEquirectTexture(url, anisotropy, generateMipmaps, onLoad, onError) {
10697
10799
  const [texture, setTexture] = useState11(null);
10698
10800
  const onLoadRef = useRef24(onLoad);
10699
10801
  const onErrorRef = useRef24(onError);
10700
10802
  onLoadRef.current = onLoad;
10701
10803
  onErrorRef.current = onError;
10702
- useEffect23(() => {
10804
+ useEffect24(() => {
10703
10805
  if (!url) {
10704
10806
  setTexture(null);
10705
10807
  return;
@@ -10738,7 +10840,7 @@ function useEquirectTexture(url, anisotropy, generateMipmaps, onLoad, onError) {
10738
10840
  active = false;
10739
10841
  };
10740
10842
  }, [anisotropy, generateMipmaps, url]);
10741
- useEffect23(
10843
+ useEffect24(
10742
10844
  () => () => {
10743
10845
  texture?.dispose();
10744
10846
  },
@@ -10756,9 +10858,9 @@ function Sphere({
10756
10858
  onPreviewError,
10757
10859
  visible = true
10758
10860
  }) {
10759
- const gl = useThree14((state) => state.gl);
10861
+ const gl = useThree15((state) => state.gl);
10760
10862
  const anisotropy = gl.capabilities.getMaxAnisotropy();
10761
- const resolvedPreviewUrl = useMemo15(
10863
+ const resolvedPreviewUrl = useMemo16(
10762
10864
  () => resolveUrlAgainstFile(src, previewUrl),
10763
10865
  [previewUrl, src]
10764
10866
  );
@@ -10778,10 +10880,20 @@ function Sphere({
10778
10880
  );
10779
10881
  const displayTexture = texture ?? previewTexture;
10780
10882
  const readyRef = useRef24(false);
10781
- useEffect23(() => {
10883
+ const detailReporter = useSceneDetailReporter();
10884
+ useEffect24(() => {
10782
10885
  readyRef.current = false;
10783
10886
  }, [resolvedPreviewUrl, src]);
10784
- useEffect23(() => {
10887
+ useEffect24(() => {
10888
+ if (!detailReporter) {
10889
+ return;
10890
+ }
10891
+ detailReporter.report(texture != null);
10892
+ return () => {
10893
+ detailReporter.report(false);
10894
+ };
10895
+ }, [detailReporter, texture]);
10896
+ useEffect24(() => {
10785
10897
  if (!displayTexture || readyRef.current) {
10786
10898
  return;
10787
10899
  }
@@ -10797,8 +10909,8 @@ function Sphere({
10797
10909
  rotation: [0, MathUtils6.degToRad(90 + yawOffset), 0],
10798
10910
  visible,
10799
10911
  children: [
10800
- /* @__PURE__ */ jsx16("sphereGeometry", { args: [DEFAULT_PANORAMA_RADIUS, 128, 64] }),
10801
- /* @__PURE__ */ jsx16(
10912
+ /* @__PURE__ */ jsx17("sphereGeometry", { args: [DEFAULT_PANORAMA_RADIUS, 128, 64] }),
10913
+ /* @__PURE__ */ jsx17(
10802
10914
  PanoBasicMaterial,
10803
10915
  {
10804
10916
  map: displayTexture,
@@ -10812,13 +10924,13 @@ function Sphere({
10812
10924
  }
10813
10925
 
10814
10926
  // src/video/pano-video.tsx
10815
- import { useThree as useThree15 } from "@react-three/fiber";
10927
+ import { useThree as useThree16 } from "@react-three/fiber";
10816
10928
  import {
10817
10929
  useCallback as useCallback10,
10818
- useContext as useContext21,
10819
- useEffect as useEffect24,
10930
+ useContext as useContext23,
10931
+ useEffect as useEffect25,
10820
10932
  useLayoutEffect as useLayoutEffect3,
10821
- useMemo as useMemo16,
10933
+ useMemo as useMemo17,
10822
10934
  useRef as useRef25,
10823
10935
  useState as useState12
10824
10936
  } from "react";
@@ -10832,7 +10944,7 @@ import {
10832
10944
  TextureLoader as TextureLoader4,
10833
10945
  VideoTexture
10834
10946
  } from "three";
10835
- import { Fragment as Fragment5, jsx as jsx17, jsxs as jsxs11 } from "react/jsx-runtime";
10947
+ import { Fragment as Fragment5, jsx as jsx18, jsxs as jsxs11 } from "react/jsx-runtime";
10836
10948
  var EMPTY_TRACKS = [];
10837
10949
  var EMPTY_RATES = DEFAULT_PANO_VIDEO_PLAYBACK_RATES;
10838
10950
  function createEmptySnapshot() {
@@ -10916,11 +11028,11 @@ function applyEquirectangularLayout(texture, anisotropy) {
10916
11028
  texture.needsUpdate = true;
10917
11029
  }
10918
11030
  function usePosterTexture(poster, onError) {
10919
- const gl = useThree15((state) => state.gl);
11031
+ const gl = useThree16((state) => state.gl);
10920
11032
  const [texture, setTexture] = useState12(null);
10921
11033
  const onErrorRef = useRef25(onError);
10922
11034
  onErrorRef.current = onError;
10923
- useEffect24(() => {
11035
+ useEffect25(() => {
10924
11036
  let active = true;
10925
11037
  setTexture(null);
10926
11038
  if (!poster) {
@@ -10957,7 +11069,7 @@ function usePosterTexture(poster, onError) {
10957
11069
  active = false;
10958
11070
  };
10959
11071
  }, [gl, poster]);
10960
- useEffect24(
11072
+ useEffect25(
10961
11073
  () => () => {
10962
11074
  texture?.dispose();
10963
11075
  },
@@ -11015,16 +11127,16 @@ function PanoVideo({
11015
11127
  onTrackChange
11016
11128
  }) {
11017
11129
  usePanoMediaActivationIntent(autoPlay);
11018
- const gl = useThree15((state) => state.gl);
11019
- const host = useContext21(PanoVideoHostContext);
11020
- const overlay = useContext21(PanoChromeOverlayContext);
11021
- const variants = useMemo16(
11130
+ const gl = useThree16((state) => state.gl);
11131
+ const host = useContext23(PanoVideoHostContext);
11132
+ const overlay = useContext23(PanoChromeOverlayContext);
11133
+ const variants = useMemo17(
11022
11134
  () => resolvePanoVideoVariants({ poster, src, variants: variantsProp }),
11023
11135
  [poster, src, variantsProp]
11024
11136
  );
11025
11137
  const tracks = tracksProp ?? EMPTY_TRACKS;
11026
11138
  const captionsEnabled = captions !== false;
11027
- const captionAppearance = useMemo16(
11139
+ const captionAppearance = useMemo17(
11028
11140
  () => resolvePanoVideoCaptionAppearance(
11029
11141
  typeof captions === "object" ? captions : void 0
11030
11142
  ),
@@ -11089,7 +11201,7 @@ function PanoVideo({
11089
11201
  onEndedRef.current = onEnded;
11090
11202
  onVariantChangeRef.current = onVariantChange;
11091
11203
  onTrackChangeRef.current = onTrackChange;
11092
- const resource = useMemo16(() => {
11204
+ const resource = useMemo17(() => {
11093
11205
  if (typeof document === "undefined") {
11094
11206
  return null;
11095
11207
  }
@@ -11106,7 +11218,7 @@ function PanoVideo({
11106
11218
  texture.generateMipmaps = false;
11107
11219
  return { video, texture };
11108
11220
  }, []);
11109
- useEffect24(
11221
+ useEffect25(
11110
11222
  () => () => {
11111
11223
  if (!resource) {
11112
11224
  return;
@@ -11121,13 +11233,13 @@ function PanoVideo({
11121
11233
  },
11122
11234
  [resource]
11123
11235
  );
11124
- useEffect24(() => {
11236
+ useEffect25(() => {
11125
11237
  if (!resource) {
11126
11238
  return;
11127
11239
  }
11128
11240
  resource.texture.anisotropy = gl.capabilities.getMaxAnisotropy();
11129
11241
  }, [gl, resource]);
11130
- useEffect24(() => {
11242
+ useEffect25(() => {
11131
11243
  if (!resource || !overlay?.overlayElement) {
11132
11244
  return;
11133
11245
  }
@@ -11202,7 +11314,7 @@ function PanoVideo({
11202
11314
  captionAppearance
11203
11315
  ]
11204
11316
  );
11205
- const controller = useMemo16(
11317
+ const controller = useMemo17(
11206
11318
  () => ({
11207
11319
  subscribe: (onStoreChange) => {
11208
11320
  const store = storeRef.current;
@@ -11280,10 +11392,10 @@ function PanoVideo({
11280
11392
  };
11281
11393
  emitSnapshot();
11282
11394
  }, [emitSnapshot, playbackRates, resource]);
11283
- useEffect24(() => {
11395
+ useEffect25(() => {
11284
11396
  emitSnapshot();
11285
11397
  }, [emitSnapshot]);
11286
- useEffect24(() => {
11398
+ useEffect25(() => {
11287
11399
  if (!resource || !activeVariant || !mediaKey) {
11288
11400
  return;
11289
11401
  }
@@ -11340,7 +11452,7 @@ function PanoVideo({
11340
11452
  video.removeEventListener("error", handleError);
11341
11453
  };
11342
11454
  }, [mediaKey, resource]);
11343
- useEffect24(() => {
11455
+ useEffect25(() => {
11344
11456
  if (!resource) {
11345
11457
  return;
11346
11458
  }
@@ -11432,7 +11544,7 @@ function PanoVideo({
11432
11544
  }
11433
11545
  };
11434
11546
  }, [emitSnapshot, resource]);
11435
- useEffect24(() => {
11547
+ useEffect25(() => {
11436
11548
  if (!resource) {
11437
11549
  return;
11438
11550
  }
@@ -11452,7 +11564,7 @@ function PanoVideo({
11452
11564
  }
11453
11565
  video.preload = preload;
11454
11566
  }, [loop, muted, playsInline, preload, resource, volume]);
11455
- useEffect24(() => {
11567
+ useEffect25(() => {
11456
11568
  if (!resource) {
11457
11569
  return;
11458
11570
  }
@@ -11502,7 +11614,7 @@ function PanoVideo({
11502
11614
  video.removeEventListener("ratechange", handleVolume);
11503
11615
  };
11504
11616
  }, [emitSnapshot, resource]);
11505
- useEffect24(() => {
11617
+ useEffect25(() => {
11506
11618
  if (!resource) {
11507
11619
  return;
11508
11620
  }
@@ -11537,7 +11649,7 @@ function PanoVideo({
11537
11649
  video.textTracks.removeEventListener("change", applyModes);
11538
11650
  };
11539
11651
  }, [emitSnapshot, resource, trackId, tracks]);
11540
- useEffect24(() => {
11652
+ useEffect25(() => {
11541
11653
  if (!captionsEnabled) {
11542
11654
  setTrackId(null);
11543
11655
  return;
@@ -11555,8 +11667,8 @@ function PanoVideo({
11555
11667
  rotation: [0, MathUtils7.degToRad(90 + yawOffset), 0],
11556
11668
  visible,
11557
11669
  children: [
11558
- /* @__PURE__ */ jsx17("sphereGeometry", { args: [DEFAULT_PANORAMA_RADIUS, 128, 64] }),
11559
- /* @__PURE__ */ jsx17(
11670
+ /* @__PURE__ */ jsx18("sphereGeometry", { args: [DEFAULT_PANORAMA_RADIUS, 128, 64] }),
11671
+ /* @__PURE__ */ jsx18(
11560
11672
  PanoBasicMaterial,
11561
11673
  {
11562
11674
  map: activeTexture,
@@ -11567,19 +11679,19 @@ function PanoVideo({
11567
11679
  ]
11568
11680
  }
11569
11681
  ) : null,
11570
- captionsEnabled ? /* @__PURE__ */ jsx17(PanoVideoCaptions, { appearance: typeof captions === "object" ? captions : void 0 }) : null
11682
+ captionsEnabled ? /* @__PURE__ */ jsx18(PanoVideoCaptions, { appearance: typeof captions === "object" ? captions : void 0 }) : null
11571
11683
  ] });
11572
11684
  }
11573
11685
 
11574
11686
  // src/scenes.tsx
11575
- import { useFrame as useFrame13, useThree as useThree20 } from "@react-three/fiber";
11687
+ import { useFrame as useFrame14, useThree as useThree21 } from "@react-three/fiber";
11576
11688
  import {
11577
11689
  Fragment as Fragment6,
11578
11690
  useCallback as useCallback11,
11579
- useContext as useContext23,
11580
- useEffect as useEffect29,
11581
- useMemo as useMemo21,
11582
- useRef as useRef29,
11691
+ useContext as useContext24,
11692
+ useEffect as useEffect30,
11693
+ useMemo as useMemo22,
11694
+ useRef as useRef30,
11583
11695
  useState as useState14
11584
11696
  } from "react";
11585
11697
  import {
@@ -11634,18 +11746,34 @@ function isSnapshotTransition(preset) {
11634
11746
  return preset !== "none" && preset !== "particles";
11635
11747
  }
11636
11748
 
11637
- // src/scene-transitions/particle-overlay.tsx
11638
- import { useFrame as useFrame10, useThree as useThree16 } from "@react-three/fiber";
11639
- import { useEffect as useEffect25, useMemo as useMemo17, useRef as useRef26 } from "react";
11640
- import {
11641
- DoubleSide as DoubleSide2,
11642
- InstancedBufferAttribute,
11643
- InstancedBufferGeometry,
11644
- PlaneGeometry as PlaneGeometry3,
11645
- ShaderMaterial as ShaderMaterial2,
11646
- Vector2 as Vector24,
11647
- Vector3 as Vector310
11648
- } from "three";
11749
+ // src/scene-transitions/snapshot-hold.tsx
11750
+ import { useFrame as useFrame10, useThree as useThree17 } from "@react-three/fiber";
11751
+ import { useEffect as useEffect26, useMemo as useMemo18, useRef as useRef26 } from "react";
11752
+ import { Vector3 as Vector310 } from "three";
11753
+
11754
+ // src/scene-transitions/overlay-utils.ts
11755
+ import { PlaneGeometry as PlaneGeometry2 } from "three";
11756
+ var OVERLAY_RENDER_ORDER = 1e4;
11757
+ var FULLSCREEN_PLANE = new PlaneGeometry2(1, 1);
11758
+ function isPerspectiveCamera(camera) {
11759
+ return camera.isPerspectiveCamera === true;
11760
+ }
11761
+ function placeFullscreenOverlay(mesh, camera, direction) {
11762
+ const distance = Math.max(camera.near * 1.1, 0.11);
11763
+ camera.getWorldDirection(direction);
11764
+ mesh.position.copy(camera.position).addScaledVector(direction, distance);
11765
+ mesh.quaternion.copy(camera.quaternion);
11766
+ const height = 2 * distance * Math.tan(camera.fov * Math.PI / 360);
11767
+ mesh.scale.set(height * camera.aspect, height, 1);
11768
+ }
11769
+ function overlayProgress(elapsedTime, duration, startTime) {
11770
+ const started = startTime ?? elapsedTime;
11771
+ const progress = duration === 0 ? 1 : Math.min(1, (elapsedTime - started) / duration);
11772
+ return { startTime: started, progress };
11773
+ }
11774
+
11775
+ // src/scene-transitions/snapshot-shaders.ts
11776
+ import { DoubleSide as DoubleSide2, ShaderMaterial as ShaderMaterial2, Vector2 as Vector24 } from "three";
11649
11777
 
11650
11778
  // src/scene-transitions/glsl.ts
11651
11779
  var GLSL_COMMON = `
@@ -11677,186 +11805,24 @@ float fbm(vec2 p) {
11677
11805
  }
11678
11806
  `;
11679
11807
 
11680
- // src/scene-transitions/overlay-utils.ts
11681
- import { PlaneGeometry as PlaneGeometry2 } from "three";
11682
- var OVERLAY_RENDER_ORDER = 1e4;
11683
- var FULLSCREEN_PLANE = new PlaneGeometry2(1, 1);
11684
- function isPerspectiveCamera(camera) {
11685
- return camera.isPerspectiveCamera === true;
11686
- }
11687
- function placeFullscreenOverlay(mesh, camera, direction) {
11688
- const distance = Math.max(camera.near * 1.1, 0.11);
11689
- camera.getWorldDirection(direction);
11690
- mesh.position.copy(camera.position).addScaledVector(direction, distance);
11691
- mesh.quaternion.copy(camera.quaternion);
11692
- const height = 2 * distance * Math.tan(camera.fov * Math.PI / 360);
11693
- mesh.scale.set(height * camera.aspect, height, 1);
11694
- }
11695
- function overlayProgress(elapsedTime, duration, startTime) {
11696
- const started = startTime ?? elapsedTime;
11697
- const progress = duration === 0 ? 1 : Math.min(1, (elapsedTime - started) / duration);
11698
- return { startTime: started, progress };
11699
- }
11700
-
11701
- // src/scene-transitions/particle-overlay.tsx
11702
- import { jsx as jsx18 } from "react/jsx-runtime";
11703
- var PARTICLE_GRID = 48;
11704
- var PARTICLE_COUNT = PARTICLE_GRID * PARTICLE_GRID;
11705
- var PARTICLE_VERTEX_SHADER = `
11706
- attribute float instanceIndex;
11707
- uniform float progress;
11708
- uniform vec2 grid;
11808
+ // src/scene-transitions/snapshot-shaders.ts
11809
+ var SNAPSHOT_VERTEX_SHADER = `
11709
11810
  varying vec2 vUv;
11710
- varying float vAlpha;
11711
- ${GLSL_COMMON}
11712
-
11713
11811
  void main() {
11714
- float id = instanceIndex;
11715
- float gx = mod(id, grid.x);
11716
- float gy = floor(id / grid.x);
11717
- vec2 cell = vec2(gx, gy);
11718
- float h = hash(cell);
11719
- float h2 = hash(cell + 19.2);
11720
- float h3 = hash(cell + 7.7);
11721
- vec2 randomDir = normalize(vec2(h, h2) * 2.0 - 1.0 + 1e-5);
11722
- vec2 fromCenter = (cell + 0.5) / grid - 0.5 + 1e-5;
11723
- vec2 dir = normalize(mix(randomDir, normalize(fromCenter), 0.65));
11724
- float delay = h3 * 0.28;
11725
- float lt = clamp((progress - delay) / max(1.0 - delay, 0.001), 0.0, 1.0);
11726
- float explode = lt * lt;
11727
- float scale = mix(1.0, 0.18, explode);
11728
- float angle = (h * 2.0 - 1.0) * explode * 4.2;
11729
- float ca = cos(angle);
11730
- float sa = sin(angle);
11731
- vec2 cellSize = 1.0 / grid;
11732
- vec2 local = position.xy * cellSize * scale;
11733
- vec2 rotated = vec2(local.x * ca - local.y * sa, local.x * sa + local.y * ca);
11734
- vec2 planeCenter = (cell + 0.5) / grid - 0.5;
11735
- vec2 exploded = planeCenter + dir * explode * 0.9;
11736
- vec3 pos = vec3(exploded + rotated, -explode * 0.14);
11737
- vUv = (cell + uv) / grid;
11738
- vAlpha = 1.0 - explode;
11739
- gl_Position = projectionMatrix * modelViewMatrix * vec4(pos, 1.0);
11812
+ vUv = uv;
11813
+ gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
11740
11814
  }
11741
11815
  `;
11742
- var PARTICLE_FRAGMENT_SHADER = `
11743
- uniform sampler2D map;
11744
- varying vec2 vUv;
11745
- varying float vAlpha;
11816
+ var HEADER = `
11817
+ uniform sampler2D map;
11818
+ uniform float progress;
11819
+ uniform vec2 resolution;
11820
+ varying vec2 vUv;
11821
+ ${GLSL_COMMON}
11746
11822
 
11747
- void main() {
11748
- vec4 old = texture2D(map, vUv);
11749
- old.rgb *= 1.0 + 0.22 * (1.0 - vAlpha);
11750
- gl_FragColor = vec4(old.rgb, old.a * vAlpha);
11751
- #include <colorspace_fragment>
11752
- }
11753
- `;
11754
- function createParticleGeometry() {
11755
- const quad = new PlaneGeometry3(1, 1);
11756
- const geometry = new InstancedBufferGeometry();
11757
- if (quad.index) {
11758
- geometry.setIndex(quad.index.clone());
11759
- }
11760
- geometry.setAttribute("position", quad.attributes.position.clone());
11761
- geometry.setAttribute("uv", quad.attributes.uv.clone());
11762
- const indexes = new Float32Array(PARTICLE_COUNT);
11763
- for (let i = 0; i < PARTICLE_COUNT; i += 1) {
11764
- indexes[i] = i;
11765
- }
11766
- geometry.setAttribute("instanceIndex", new InstancedBufferAttribute(indexes, 1));
11767
- geometry.instanceCount = PARTICLE_COUNT;
11768
- quad.dispose();
11769
- return geometry;
11770
- }
11771
- function ParticleOverlay({
11772
- snapshot,
11773
- transition,
11774
- running,
11775
- runId,
11776
- onFinish
11777
- }) {
11778
- const { camera } = useThree16();
11779
- const meshRef = useRef26(null);
11780
- const startRef = useRef26(null);
11781
- const finishedRef = useRef26(false);
11782
- const directionRef = useRef26(new Vector310());
11783
- const geometry = useMemo17(() => createParticleGeometry(), []);
11784
- const material = useMemo17(
11785
- () => new ShaderMaterial2({
11786
- transparent: true,
11787
- depthTest: false,
11788
- depthWrite: false,
11789
- side: DoubleSide2,
11790
- uniforms: {
11791
- map: { value: snapshot.texture },
11792
- progress: { value: 0 },
11793
- grid: { value: new Vector24(PARTICLE_GRID, PARTICLE_GRID) }
11794
- },
11795
- vertexShader: PARTICLE_VERTEX_SHADER,
11796
- fragmentShader: PARTICLE_FRAGMENT_SHADER
11797
- }),
11798
- [snapshot.texture]
11799
- );
11800
- useEffect25(() => () => geometry.dispose(), [geometry]);
11801
- useEffect25(() => () => material.dispose(), [material]);
11802
- useEffect25(() => {
11803
- startRef.current = null;
11804
- finishedRef.current = false;
11805
- material.uniforms.progress.value = 0;
11806
- }, [material, runId]);
11807
- useFrame10((state) => {
11808
- const mesh = meshRef.current;
11809
- if (!mesh || !isPerspectiveCamera(camera)) {
11810
- return;
11811
- }
11812
- placeFullscreenOverlay(mesh, camera, directionRef.current);
11813
- if (!running || finishedRef.current) {
11814
- return;
11815
- }
11816
- const next = overlayProgress(state.clock.elapsedTime, transition.duration, startRef.current);
11817
- startRef.current = next.startTime;
11818
- material.uniforms.progress.value = next.progress;
11819
- if (next.progress === 1) {
11820
- finishedRef.current = true;
11821
- onFinish();
11822
- }
11823
- });
11824
- return /* @__PURE__ */ jsx18(
11825
- "mesh",
11826
- {
11827
- ref: meshRef,
11828
- frustumCulled: false,
11829
- geometry,
11830
- material,
11831
- renderOrder: OVERLAY_RENDER_ORDER
11832
- }
11833
- );
11834
- }
11835
-
11836
- // src/scene-transitions/snapshot-overlay.tsx
11837
- import { useFrame as useFrame11, useThree as useThree17 } from "@react-three/fiber";
11838
- import { useEffect as useEffect26, useMemo as useMemo18, useRef as useRef27 } from "react";
11839
- import { Vector3 as Vector311 } from "three";
11840
-
11841
- // src/scene-transitions/snapshot-shaders.ts
11842
- import { DoubleSide as DoubleSide3, ShaderMaterial as ShaderMaterial3, Vector2 as Vector25 } from "three";
11843
- var SNAPSHOT_VERTEX_SHADER = `
11844
- varying vec2 vUv;
11845
- void main() {
11846
- vUv = uv;
11847
- gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
11848
- }
11849
- `;
11850
- var HEADER = `
11851
- uniform sampler2D map;
11852
- uniform float progress;
11853
- uniform vec2 resolution;
11854
- varying vec2 vUv;
11855
- ${GLSL_COMMON}
11856
-
11857
- vec2 aspectGrid(float rows) {
11858
- float aspect = resolution.x / max(resolution.y, 1.0);
11859
- return vec2(max(8.0, floor(rows * aspect)), rows);
11823
+ vec2 aspectGrid(float rows) {
11824
+ float aspect = resolution.x / max(resolution.y, 1.0);
11825
+ return vec2(max(8.0, floor(rows * aspect)), rows);
11860
11826
  }
11861
11827
 
11862
11828
  vec2 gridCellId() {
@@ -12099,50 +12065,285 @@ var SNAPSHOT_FRAGMENT_SHADERS = {
12099
12065
  `)
12100
12066
  };
12101
12067
  function createSnapshotMaterial(preset, texture) {
12102
- return new ShaderMaterial3({
12068
+ return new ShaderMaterial2({
12103
12069
  transparent: true,
12104
12070
  depthTest: false,
12105
12071
  depthWrite: false,
12106
- side: DoubleSide3,
12072
+ side: DoubleSide2,
12107
12073
  uniforms: {
12108
12074
  map: { value: texture },
12109
12075
  progress: { value: 0 },
12110
- resolution: { value: new Vector25(1, 1) }
12076
+ resolution: { value: new Vector24(1, 1) }
12111
12077
  },
12112
12078
  vertexShader: SNAPSHOT_VERTEX_SHADER,
12113
12079
  fragmentShader: SNAPSHOT_FRAGMENT_SHADERS[preset]
12114
12080
  });
12115
12081
  }
12116
12082
 
12117
- // src/scene-transitions/snapshot-overlay.tsx
12083
+ // src/scene-transitions/snapshot-hold.tsx
12118
12084
  import { jsx as jsx19, jsxs as jsxs12 } from "react/jsx-runtime";
12119
- function SnapshotOverlay({
12085
+ function SnapshotHold({ snapshot }) {
12086
+ const { camera, gl } = useThree17();
12087
+ const meshRef = useRef26(null);
12088
+ const directionRef = useRef26(new Vector310());
12089
+ const material = useMemo18(
12090
+ () => createSnapshotMaterial("crossfade", snapshot.texture),
12091
+ [snapshot.texture]
12092
+ );
12093
+ useEffect26(() => () => material.dispose(), [material]);
12094
+ useFrame10(() => {
12095
+ const mesh = meshRef.current;
12096
+ if (!mesh || !isPerspectiveCamera(camera)) {
12097
+ return;
12098
+ }
12099
+ placeFullscreenOverlay(mesh, camera, directionRef.current);
12100
+ const context = gl.getContext();
12101
+ material.uniforms.resolution.value.set(
12102
+ context.drawingBufferWidth,
12103
+ context.drawingBufferHeight
12104
+ );
12105
+ material.uniforms.progress.value = 0;
12106
+ });
12107
+ return /* @__PURE__ */ jsxs12("mesh", { frustumCulled: false, ref: meshRef, renderOrder: OVERLAY_RENDER_ORDER, children: [
12108
+ /* @__PURE__ */ jsx19("primitive", { attach: "geometry", object: FULLSCREEN_PLANE }),
12109
+ /* @__PURE__ */ jsx19("primitive", { attach: "material", object: material })
12110
+ ] });
12111
+ }
12112
+
12113
+ // src/scene-transition-policy.ts
12114
+ function pendingSceneUsesBaseLayer(phase, isPending) {
12115
+ return isPending && (phase === "preloading" || phase === "capturing");
12116
+ }
12117
+ function normalizeTransitionWaitMs(value) {
12118
+ if (typeof value !== "number" || !Number.isFinite(value) || value <= 0) {
12119
+ return 0;
12120
+ }
12121
+ return value;
12122
+ }
12123
+ function planDetailHold(input) {
12124
+ if (input.waitMs <= 0) {
12125
+ return null;
12126
+ }
12127
+ return {
12128
+ generation: input.generation,
12129
+ sceneId: input.sceneId,
12130
+ deadline: input.now + input.waitMs
12131
+ };
12132
+ }
12133
+ function acceptDetailWait(wait, signal) {
12134
+ if (!wait) {
12135
+ return { wait: null, start: false };
12136
+ }
12137
+ switch (signal.kind) {
12138
+ case "ready":
12139
+ if (signal.generation !== wait.generation || signal.sceneId !== wait.sceneId) {
12140
+ return { wait, start: false };
12141
+ }
12142
+ return { wait: null, start: true };
12143
+ case "timeout":
12144
+ if (signal.generation !== wait.generation || signal.now < wait.deadline) {
12145
+ return { wait, start: false };
12146
+ }
12147
+ return { wait: null, start: true };
12148
+ case "cancel":
12149
+ if (signal.generation !== wait.generation) {
12150
+ return { wait, start: false };
12151
+ }
12152
+ return { wait: null, start: false };
12153
+ default: {
12154
+ const exhaustive = signal;
12155
+ return exhaustive;
12156
+ }
12157
+ }
12158
+ }
12159
+ function phaseAfterSnapshot(preset, hold) {
12160
+ if (hold) {
12161
+ return "awaitingDetail";
12162
+ }
12163
+ if (preset === "none") {
12164
+ return "idle";
12165
+ }
12166
+ return "transitioning";
12167
+ }
12168
+
12169
+ // src/scene-transitions/particle-overlay.tsx
12170
+ import { useFrame as useFrame11, useThree as useThree18 } from "@react-three/fiber";
12171
+ import { useEffect as useEffect27, useMemo as useMemo19, useRef as useRef27 } from "react";
12172
+ import {
12173
+ DoubleSide as DoubleSide3,
12174
+ InstancedBufferAttribute,
12175
+ InstancedBufferGeometry,
12176
+ PlaneGeometry as PlaneGeometry3,
12177
+ ShaderMaterial as ShaderMaterial3,
12178
+ Vector2 as Vector25,
12179
+ Vector3 as Vector311
12180
+ } from "three";
12181
+ import { jsx as jsx20 } from "react/jsx-runtime";
12182
+ var PARTICLE_GRID = 48;
12183
+ var PARTICLE_COUNT = PARTICLE_GRID * PARTICLE_GRID;
12184
+ var PARTICLE_VERTEX_SHADER = `
12185
+ attribute float instanceIndex;
12186
+ uniform float progress;
12187
+ uniform vec2 grid;
12188
+ varying vec2 vUv;
12189
+ varying float vAlpha;
12190
+ ${GLSL_COMMON}
12191
+
12192
+ void main() {
12193
+ float id = instanceIndex;
12194
+ float gx = mod(id, grid.x);
12195
+ float gy = floor(id / grid.x);
12196
+ vec2 cell = vec2(gx, gy);
12197
+ float h = hash(cell);
12198
+ float h2 = hash(cell + 19.2);
12199
+ float h3 = hash(cell + 7.7);
12200
+ vec2 randomDir = normalize(vec2(h, h2) * 2.0 - 1.0 + 1e-5);
12201
+ vec2 fromCenter = (cell + 0.5) / grid - 0.5 + 1e-5;
12202
+ vec2 dir = normalize(mix(randomDir, normalize(fromCenter), 0.65));
12203
+ float delay = h3 * 0.28;
12204
+ float lt = clamp((progress - delay) / max(1.0 - delay, 0.001), 0.0, 1.0);
12205
+ float explode = lt * lt;
12206
+ float scale = mix(1.0, 0.18, explode);
12207
+ float angle = (h * 2.0 - 1.0) * explode * 4.2;
12208
+ float ca = cos(angle);
12209
+ float sa = sin(angle);
12210
+ vec2 cellSize = 1.0 / grid;
12211
+ vec2 local = position.xy * cellSize * scale;
12212
+ vec2 rotated = vec2(local.x * ca - local.y * sa, local.x * sa + local.y * ca);
12213
+ vec2 planeCenter = (cell + 0.5) / grid - 0.5;
12214
+ vec2 exploded = planeCenter + dir * explode * 0.9;
12215
+ vec3 pos = vec3(exploded + rotated, -explode * 0.14);
12216
+ vUv = (cell + uv) / grid;
12217
+ vAlpha = 1.0 - explode;
12218
+ gl_Position = projectionMatrix * modelViewMatrix * vec4(pos, 1.0);
12219
+ }
12220
+ `;
12221
+ var PARTICLE_FRAGMENT_SHADER = `
12222
+ uniform sampler2D map;
12223
+ varying vec2 vUv;
12224
+ varying float vAlpha;
12225
+
12226
+ void main() {
12227
+ vec4 old = texture2D(map, vUv);
12228
+ old.rgb *= 1.0 + 0.22 * (1.0 - vAlpha);
12229
+ gl_FragColor = vec4(old.rgb, old.a * vAlpha);
12230
+ #include <colorspace_fragment>
12231
+ }
12232
+ `;
12233
+ function createParticleGeometry() {
12234
+ const quad = new PlaneGeometry3(1, 1);
12235
+ const geometry = new InstancedBufferGeometry();
12236
+ if (quad.index) {
12237
+ geometry.setIndex(quad.index.clone());
12238
+ }
12239
+ geometry.setAttribute("position", quad.attributes.position.clone());
12240
+ geometry.setAttribute("uv", quad.attributes.uv.clone());
12241
+ const indexes = new Float32Array(PARTICLE_COUNT);
12242
+ for (let i = 0; i < PARTICLE_COUNT; i += 1) {
12243
+ indexes[i] = i;
12244
+ }
12245
+ geometry.setAttribute("instanceIndex", new InstancedBufferAttribute(indexes, 1));
12246
+ geometry.instanceCount = PARTICLE_COUNT;
12247
+ quad.dispose();
12248
+ return geometry;
12249
+ }
12250
+ function ParticleOverlay({
12120
12251
  snapshot,
12121
12252
  transition,
12122
12253
  running,
12123
12254
  runId,
12124
12255
  onFinish
12125
12256
  }) {
12126
- const { camera, gl } = useThree17();
12257
+ const { camera } = useThree18();
12127
12258
  const meshRef = useRef27(null);
12128
12259
  const startRef = useRef27(null);
12129
12260
  const finishedRef = useRef27(false);
12130
12261
  const directionRef = useRef27(new Vector311());
12131
- const material = useMemo18(() => {
12262
+ const geometry = useMemo19(() => createParticleGeometry(), []);
12263
+ const material = useMemo19(
12264
+ () => new ShaderMaterial3({
12265
+ transparent: true,
12266
+ depthTest: false,
12267
+ depthWrite: false,
12268
+ side: DoubleSide3,
12269
+ uniforms: {
12270
+ map: { value: snapshot.texture },
12271
+ progress: { value: 0 },
12272
+ grid: { value: new Vector25(PARTICLE_GRID, PARTICLE_GRID) }
12273
+ },
12274
+ vertexShader: PARTICLE_VERTEX_SHADER,
12275
+ fragmentShader: PARTICLE_FRAGMENT_SHADER
12276
+ }),
12277
+ [snapshot.texture]
12278
+ );
12279
+ useEffect27(() => () => geometry.dispose(), [geometry]);
12280
+ useEffect27(() => () => material.dispose(), [material]);
12281
+ useEffect27(() => {
12282
+ startRef.current = null;
12283
+ finishedRef.current = false;
12284
+ material.uniforms.progress.value = 0;
12285
+ }, [material, runId]);
12286
+ useFrame11((state) => {
12287
+ const mesh = meshRef.current;
12288
+ if (!mesh || !isPerspectiveCamera(camera)) {
12289
+ return;
12290
+ }
12291
+ placeFullscreenOverlay(mesh, camera, directionRef.current);
12292
+ if (!running || finishedRef.current) {
12293
+ return;
12294
+ }
12295
+ const next = overlayProgress(state.clock.elapsedTime, transition.duration, startRef.current);
12296
+ startRef.current = next.startTime;
12297
+ material.uniforms.progress.value = next.progress;
12298
+ if (next.progress === 1) {
12299
+ finishedRef.current = true;
12300
+ onFinish();
12301
+ }
12302
+ });
12303
+ return /* @__PURE__ */ jsx20(
12304
+ "mesh",
12305
+ {
12306
+ ref: meshRef,
12307
+ frustumCulled: false,
12308
+ geometry,
12309
+ material,
12310
+ renderOrder: OVERLAY_RENDER_ORDER
12311
+ }
12312
+ );
12313
+ }
12314
+
12315
+ // src/scene-transitions/snapshot-overlay.tsx
12316
+ import { useFrame as useFrame12, useThree as useThree19 } from "@react-three/fiber";
12317
+ import { useEffect as useEffect28, useMemo as useMemo20, useRef as useRef28 } from "react";
12318
+ import { Vector3 as Vector312 } from "three";
12319
+ import { jsx as jsx21, jsxs as jsxs13 } from "react/jsx-runtime";
12320
+ function SnapshotOverlay({
12321
+ snapshot,
12322
+ transition,
12323
+ running,
12324
+ runId,
12325
+ onFinish
12326
+ }) {
12327
+ const { camera, gl } = useThree19();
12328
+ const meshRef = useRef28(null);
12329
+ const startRef = useRef28(null);
12330
+ const finishedRef = useRef28(false);
12331
+ const directionRef = useRef28(new Vector312());
12332
+ const material = useMemo20(() => {
12132
12333
  if (!isSnapshotTransition(transition.preset)) {
12133
12334
  return null;
12134
12335
  }
12135
12336
  return createSnapshotMaterial(transition.preset, snapshot.texture);
12136
12337
  }, [snapshot.texture, transition.preset]);
12137
- useEffect26(() => () => material?.dispose(), [material]);
12138
- useEffect26(() => {
12338
+ useEffect28(() => () => material?.dispose(), [material]);
12339
+ useEffect28(() => {
12139
12340
  startRef.current = null;
12140
12341
  finishedRef.current = false;
12141
12342
  if (material) {
12142
12343
  material.uniforms.progress.value = 0;
12143
12344
  }
12144
12345
  }, [material, runId]);
12145
- useFrame11((state) => {
12346
+ useFrame12((state) => {
12146
12347
  const mesh = meshRef.current;
12147
12348
  if (!mesh || !material || !isPerspectiveCamera(camera)) {
12148
12349
  return;
@@ -12164,21 +12365,21 @@ function SnapshotOverlay({
12164
12365
  if (!material) {
12165
12366
  return null;
12166
12367
  }
12167
- return /* @__PURE__ */ jsxs12("mesh", { ref: meshRef, renderOrder: OVERLAY_RENDER_ORDER, frustumCulled: false, children: [
12168
- /* @__PURE__ */ jsx19("primitive", { attach: "geometry", object: FULLSCREEN_PLANE }),
12169
- /* @__PURE__ */ jsx19("primitive", { attach: "material", object: material })
12368
+ return /* @__PURE__ */ jsxs13("mesh", { ref: meshRef, renderOrder: OVERLAY_RENDER_ORDER, frustumCulled: false, children: [
12369
+ /* @__PURE__ */ jsx21("primitive", { attach: "geometry", object: FULLSCREEN_PLANE }),
12370
+ /* @__PURE__ */ jsx21("primitive", { attach: "material", object: material })
12170
12371
  ] });
12171
12372
  }
12172
12373
 
12173
12374
  // src/scene-transitions/transition-overlay.tsx
12174
- import { jsx as jsx20 } from "react/jsx-runtime";
12375
+ import { jsx as jsx22 } from "react/jsx-runtime";
12175
12376
  function TransitionOverlay(props) {
12176
12377
  const { preset } = props.transition;
12177
12378
  switch (preset) {
12178
12379
  case "none":
12179
12380
  return null;
12180
12381
  case "particles":
12181
- return /* @__PURE__ */ jsx20(ParticleOverlay, { ...props });
12382
+ return /* @__PURE__ */ jsx22(ParticleOverlay, { ...props });
12182
12383
  case "crossfade":
12183
12384
  case "zoom":
12184
12385
  case "blackout":
@@ -12206,7 +12407,7 @@ function TransitionOverlay(props) {
12206
12407
  case "zoomBlur":
12207
12408
  case "hexDissolve":
12208
12409
  case "filmBurn":
12209
- return /* @__PURE__ */ jsx20(SnapshotOverlay, { ...props });
12410
+ return /* @__PURE__ */ jsx22(SnapshotOverlay, { ...props });
12210
12411
  default: {
12211
12412
  const exhaustive = preset;
12212
12413
  void exhaustive;
@@ -12215,53 +12416,15 @@ function TransitionOverlay(props) {
12215
12416
  }
12216
12417
  }
12217
12418
 
12218
- // src/tile/texture-manager-context.tsx
12219
- import { useThree as useThree18 } from "@react-three/fiber";
12220
- import {
12221
- createContext as createContext15,
12222
- useContext as useContext22,
12223
- useEffect as useEffect27,
12224
- useMemo as useMemo19
12225
- } from "react";
12226
- import { jsx as jsx21 } from "react/jsx-runtime";
12227
- var TileTextureManagerContext = createContext15(
12228
- null
12229
- );
12230
- function TileTextureManagerProvider({
12231
- children,
12232
- maxTextureMemoryMb = 128,
12233
- maxConcurrentLoads = 4
12234
- }) {
12235
- const gl = useThree18((state) => state.gl);
12236
- const anisotropy = gl.capabilities.getMaxAnisotropy();
12237
- const manager = useMemo19(
12238
- () => new TileTextureManager({
12239
- anisotropy,
12240
- maxBytes: Math.max(1, maxTextureMemoryMb) * 1024 * 1024,
12241
- concurrency: Math.max(1, Math.floor(maxConcurrentLoads)),
12242
- retryCount: 1
12243
- }),
12244
- [anisotropy, maxConcurrentLoads, maxTextureMemoryMb]
12245
- );
12246
- useEffect27(() => {
12247
- manager.resume();
12248
- return () => manager.dispose();
12249
- }, [manager]);
12250
- return /* @__PURE__ */ jsx21(TileTextureManagerContext.Provider, { value: manager, children });
12251
- }
12252
- function useSharedTileTextureManager() {
12253
- return useContext22(TileTextureManagerContext);
12254
- }
12255
-
12256
12419
  // src/tile/tile.tsx
12257
- import { useFrame as useFrame12, useThree as useThree19 } from "@react-three/fiber";
12258
- import { memo as memo2, useEffect as useEffect28, useMemo as useMemo20, useRef as useRef28, useState as useState13 } from "react";
12420
+ import { useFrame as useFrame13, useThree as useThree20 } from "@react-three/fiber";
12421
+ import { memo as memo2, useEffect as useEffect29, useMemo as useMemo21, useRef as useRef29, useState as useState13 } from "react";
12259
12422
  import {
12260
12423
  Frustum as Frustum2,
12261
12424
  Matrix4 as Matrix43,
12262
12425
  PlaneGeometry as PlaneGeometry4,
12263
12426
  PerspectiveCamera as PerspectiveCamera5,
12264
- Vector3 as Vector313
12427
+ Vector3 as Vector314
12265
12428
  } from "three";
12266
12429
 
12267
12430
  // src/tile/face-layout.ts
@@ -12269,7 +12432,7 @@ import {
12269
12432
  Box3 as Box32,
12270
12433
  Euler as Euler3,
12271
12434
  Quaternion as Quaternion2,
12272
- Vector3 as Vector312
12435
+ Vector3 as Vector313
12273
12436
  } from "three";
12274
12437
  var CUBE_FACES = ["f", "r", "b", "l", "u", "d"];
12275
12438
  var PREVIEW_FACE_ORDER = ["l", "f", "r", "b", "u", "d"];
@@ -12333,12 +12496,12 @@ function getTileBoundingBox(address, radius = CUBE_RADIUS) {
12333
12496
  const halfWidth = local.width / 2;
12334
12497
  const halfHeight = local.height / 2;
12335
12498
  const quaternion = getFaceQuaternion(address.face);
12336
- const position = new Vector312(...transform.position);
12499
+ const position = new Vector313(...transform.position);
12337
12500
  const corners = [
12338
- new Vector312(local.x - halfWidth, local.y - halfHeight, 0),
12339
- new Vector312(local.x + halfWidth, local.y - halfHeight, 0),
12340
- new Vector312(local.x - halfWidth, local.y + halfHeight, 0),
12341
- new Vector312(local.x + halfWidth, local.y + halfHeight, 0)
12501
+ new Vector313(local.x - halfWidth, local.y - halfHeight, 0),
12502
+ new Vector313(local.x + halfWidth, local.y - halfHeight, 0),
12503
+ new Vector313(local.x - halfWidth, local.y + halfHeight, 0),
12504
+ new Vector313(local.x + halfWidth, local.y + halfHeight, 0)
12342
12505
  ];
12343
12506
  for (const corner of corners) {
12344
12507
  corner.applyQuaternion(quaternion).add(position);
@@ -12446,11 +12609,27 @@ function resolveTemplateUrl(template, address) {
12446
12609
  }
12447
12610
 
12448
12611
  // src/tile/tile.tsx
12449
- import { jsx as jsx22, jsxs as jsxs13 } from "react/jsx-runtime";
12612
+ import { jsx as jsx23, jsxs as jsxs14 } from "react/jsx-runtime";
12450
12613
  var MAX_LOD_UPDATE_INTERVAL_MS = 100;
12451
12614
  var FAST_ROTATION_THRESHOLD_RADIANS = Math.PI / 180;
12452
12615
  var FAST_FOV_THRESHOLD_DEGREES = 0.5;
12453
12616
  var VIEW_CHANGE_EPSILON = 1e-4;
12617
+ function decideTileLodUpdate(input) {
12618
+ if (input.loadMode === "preview") {
12619
+ return false;
12620
+ }
12621
+ const loadModeChanged = input.loadMode !== input.trackedLoadMode;
12622
+ const viewChanged = input.visibilityDirty || loadModeChanged || input.viewportChanged || input.rotationDelta > VIEW_CHANGE_EPSILON || input.fovDelta > VIEW_CHANGE_EPSILON;
12623
+ if (!viewChanged) {
12624
+ return false;
12625
+ }
12626
+ const movingQuickly = input.rotationDelta >= FAST_ROTATION_THRESHOLD_RADIANS || input.fovDelta >= FAST_FOV_THRESHOLD_DEGREES;
12627
+ const immediate = input.visibilityDirty || loadModeChanged || input.viewportChanged || movingQuickly;
12628
+ if (!immediate && input.now - input.lastUpdateAt < MAX_LOD_UPDATE_INTERVAL_MS) {
12629
+ return false;
12630
+ }
12631
+ return true;
12632
+ }
12454
12633
  var VISIBILITY_FOV_PADDING_DEGREES = 8;
12455
12634
  var PREVIEW_RADIUS = CUBE_RADIUS + 0.05;
12456
12635
  var SHARED_TILE_GEOMETRY = new PlaneGeometry4(1, 1);
@@ -12459,7 +12638,7 @@ function PreviewFace({
12459
12638
  texture,
12460
12639
  faceOrder
12461
12640
  }) {
12462
- const geometry = useMemo20(() => {
12641
+ const geometry = useMemo21(() => {
12463
12642
  const nextGeometry = new PlaneGeometry4(
12464
12643
  PREVIEW_RADIUS * 2,
12465
12644
  PREVIEW_RADIUS * 2
@@ -12474,21 +12653,21 @@ function PreviewFace({
12474
12653
  uv.needsUpdate = true;
12475
12654
  return nextGeometry;
12476
12655
  }, [face, faceOrder]);
12477
- useEffect28(
12656
+ useEffect29(
12478
12657
  () => () => {
12479
12658
  geometry.dispose();
12480
12659
  },
12481
12660
  [geometry]
12482
12661
  );
12483
12662
  const transform = getFaceTransform(face, PREVIEW_RADIUS);
12484
- return /* @__PURE__ */ jsx22(
12663
+ return /* @__PURE__ */ jsx23(
12485
12664
  "mesh",
12486
12665
  {
12487
12666
  geometry,
12488
12667
  position: transform.position,
12489
12668
  renderOrder: -100,
12490
12669
  rotation: transform.rotation,
12491
- children: /* @__PURE__ */ jsx22(
12670
+ children: /* @__PURE__ */ jsx23(
12492
12671
  PanoBasicMaterial,
12493
12672
  {
12494
12673
  depthTest: false,
@@ -12504,7 +12683,7 @@ function PreviewCube({
12504
12683
  texture,
12505
12684
  faceOrder
12506
12685
  }) {
12507
- return CUBE_FACES.map((face) => /* @__PURE__ */ jsx22(
12686
+ return CUBE_FACES.map((face) => /* @__PURE__ */ jsx23(
12508
12687
  PreviewFace,
12509
12688
  {
12510
12689
  face,
@@ -12528,14 +12707,14 @@ var TileMesh = memo2(function TileMesh2({
12528
12707
  if (!snapshot.texture) {
12529
12708
  return null;
12530
12709
  }
12531
- return /* @__PURE__ */ jsx22("group", { position: transform.position, rotation: transform.rotation, children: /* @__PURE__ */ jsx22(
12710
+ return /* @__PURE__ */ jsx23("group", { position: transform.position, rotation: transform.rotation, children: /* @__PURE__ */ jsx23(
12532
12711
  "mesh",
12533
12712
  {
12534
12713
  geometry: SHARED_TILE_GEOMETRY,
12535
12714
  position: [layout.x, layout.y, 0],
12536
12715
  renderOrder,
12537
12716
  scale: [layout.width, layout.height, 1],
12538
- children: /* @__PURE__ */ jsx22(
12717
+ children: /* @__PURE__ */ jsx23(
12539
12718
  PanoBasicMaterial,
12540
12719
  {
12541
12720
  depthTest: false,
@@ -12552,7 +12731,7 @@ var TileLayerMeshes = memo2(function TileLayerMeshes2({
12552
12731
  manager,
12553
12732
  resolveUrl
12554
12733
  }) {
12555
- return layer.addresses.map((address) => /* @__PURE__ */ jsx22(
12734
+ return layer.addresses.map((address) => /* @__PURE__ */ jsx23(
12556
12735
  TileMesh,
12557
12736
  {
12558
12737
  address,
@@ -12652,8 +12831,8 @@ function parentAddresses(child, parentLevel, parentFaceSize, tileSize) {
12652
12831
  return addresses;
12653
12832
  }
12654
12833
  function centerFacingAddress(candidates, camera) {
12655
- const direction = camera.getWorldDirection(new Vector313());
12656
- const center = new Vector313();
12834
+ const direction = camera.getWorldDirection(new Vector314());
12835
+ const center = new Vector314();
12657
12836
  let bestCandidate = candidates[0];
12658
12837
  let bestAlignment = -Infinity;
12659
12838
  for (const candidate of candidates) {
@@ -12718,11 +12897,11 @@ function Tile({
12718
12897
  onTileError,
12719
12898
  onLevelChange
12720
12899
  }) {
12721
- const { camera, gl, size } = useThree19();
12722
- const multiresConfig = useMemo20(() => parseMultires(multires), [multires]);
12900
+ const { camera, gl, size } = useThree20();
12901
+ const multiresConfig = useMemo21(() => parseMultires(multires), [multires]);
12723
12902
  const { levels, tileSize } = multiresConfig;
12724
12903
  const multiresToken = `${tileSize}:${levels.join(",")}`;
12725
- const candidatesByLevel = useMemo20(
12904
+ const candidatesByLevel = useMemo21(
12726
12905
  () => buildTileCandidates(levels, tileSize),
12727
12906
  [levels, tileSize]
12728
12907
  );
@@ -12734,13 +12913,13 @@ function Tile({
12734
12913
  onPreviewError
12735
12914
  );
12736
12915
  const sharedManager = useSharedTileTextureManager();
12737
- const progressRef = useRef28(onLoadProgress);
12738
- const errorRef = useRef28(onTileError);
12739
- const levelChangeRef = useRef28(onLevelChange);
12916
+ const progressRef = useRef29(onLoadProgress);
12917
+ const errorRef = useRef29(onTileError);
12918
+ const levelChangeRef = useRef29(onLevelChange);
12740
12919
  progressRef.current = onLoadProgress;
12741
12920
  errorRef.current = onTileError;
12742
12921
  levelChangeRef.current = onLevelChange;
12743
- const ownedManager = useMemo20(
12922
+ const ownedManager = useMemo21(
12744
12923
  () => new TileTextureManager({
12745
12924
  anisotropy,
12746
12925
  maxBytes: Math.max(1, maxTextureMemoryMb) * 1024 * 1024,
@@ -12761,7 +12940,7 @@ function Tile({
12761
12940
  ]
12762
12941
  );
12763
12942
  const manager = sharedManager ?? ownedManager;
12764
- useEffect28(() => {
12943
+ useEffect29(() => {
12765
12944
  manager.resume();
12766
12945
  return () => {
12767
12946
  if (manager === ownedManager) {
@@ -12771,11 +12950,11 @@ function Tile({
12771
12950
  queueMicrotask(() => manager.releaseUnused());
12772
12951
  };
12773
12952
  }, [manager, ownedManager]);
12774
- const readyRef = useRef28(false);
12775
- useEffect28(() => {
12953
+ const readyRef = useRef29(false);
12954
+ useEffect29(() => {
12776
12955
  readyRef.current = false;
12777
12956
  }, [effectivePreviewUrl]);
12778
- useEffect28(() => {
12957
+ useEffect29(() => {
12779
12958
  if (!previewTexture || readyRef.current) {
12780
12959
  return;
12781
12960
  }
@@ -12783,7 +12962,7 @@ function Tile({
12783
12962
  onReady?.();
12784
12963
  }, [onReady, previewTexture]);
12785
12964
  const template = urlTemplate ?? buildDefaultTileUrlTemplate();
12786
- const resolveUrl = useMemo20(
12965
+ const resolveUrl = useMemo21(
12787
12966
  () => (address) => {
12788
12967
  const relativePath = resolveTileUrl ? resolveTileUrl(address) : resolveTemplateUrl(template, address);
12789
12968
  return resolveRelativeTileUrl(baseUrl, relativePath);
@@ -12791,23 +12970,29 @@ function Tile({
12791
12970
  [baseUrl, resolveTileUrl, template]
12792
12971
  );
12793
12972
  const [layers, setLayers] = useState13([]);
12794
- const layerTokenRef = useRef28("");
12795
- const currentLevelRef = useRef28(1);
12796
- const lastUpdateAtRef = useRef28(-Infinity);
12797
- const visibilityDirtyRef = useRef28(true);
12798
- const lastVisibilityQuaternionRef = useRef28(camera.quaternion.clone());
12799
- const lastVisibilityFovRef = useRef28(Number.NaN);
12800
- const lastViewportRef = useRef28({ width: 0, height: 0, dpr: 0 });
12801
- const frustumRef = useRef28(new Frustum2());
12802
- const projectionMatrixRef = useRef28(new Matrix43());
12803
- const visibilityCameraRef = useRef28(new PerspectiveCamera5());
12804
- useEffect28(() => {
12973
+ const layerTokenRef = useRef29("");
12974
+ const currentLevelRef = useRef29(1);
12975
+ const lastUpdateAtRef = useRef29(-Infinity);
12976
+ const visibilityDirtyRef = useRef29(true);
12977
+ const lastVisibilityQuaternionRef = useRef29(camera.quaternion.clone());
12978
+ const lastVisibilityFovRef = useRef29(Number.NaN);
12979
+ const lastViewportRef = useRef29({ width: 0, height: 0, dpr: 0 });
12980
+ const frustumRef = useRef29(new Frustum2());
12981
+ const projectionMatrixRef = useRef29(new Matrix43());
12982
+ const visibilityCameraRef = useRef29(new PerspectiveCamera5());
12983
+ const trackedLoadModeRef = useRef29(loadMode);
12984
+ const targetKeysRef = useRef29([]);
12985
+ const detailTokenRef = useRef29("");
12986
+ const detailReporter = useSceneDetailReporter();
12987
+ const detailReporterRef = useRef29(detailReporter);
12988
+ detailReporterRef.current = detailReporter;
12989
+ useEffect29(() => {
12805
12990
  currentLevelRef.current = 1;
12806
12991
  layerTokenRef.current = "";
12807
12992
  visibilityDirtyRef.current = true;
12808
12993
  setLayers([]);
12809
12994
  }, [manager, multiresToken]);
12810
- useEffect28(() => {
12995
+ useEffect29(() => {
12811
12996
  if (loadMode !== "preview") {
12812
12997
  return;
12813
12998
  }
@@ -12821,11 +13006,14 @@ function Tile({
12821
13006
  setLayers(nextLayers);
12822
13007
  }
12823
13008
  };
12824
- useFrame12(() => {
12825
- if (loadMode === "preview") {
13009
+ useFrame13(() => {
13010
+ if (!(camera instanceof PerspectiveCamera5)) {
12826
13011
  return;
12827
13012
  }
12828
- if (!(camera instanceof PerspectiveCamera5)) {
13013
+ if (loadMode === "preview") {
13014
+ trackedLoadModeRef.current = "preview";
13015
+ targetKeysRef.current = [];
13016
+ publishSceneDetail(detailReporterRef.current, detailTokenRef, false);
12829
13017
  return;
12830
13018
  }
12831
13019
  const now = performance.now();
@@ -12836,60 +13024,75 @@ function Tile({
12836
13024
  const fovDelta = Number.isFinite(lastVisibilityFovRef.current) ? Math.abs(camera.fov - lastVisibilityFovRef.current) : Infinity;
12837
13025
  const lastViewport = lastViewportRef.current;
12838
13026
  const viewportChanged = lastViewport.width !== size.width || lastViewport.height !== size.height || lastViewport.dpr !== pixelRatio;
12839
- const viewChanged = visibilityDirtyRef.current || viewportChanged || rotationDelta > VIEW_CHANGE_EPSILON || fovDelta > VIEW_CHANGE_EPSILON;
12840
- const movingQuickly = rotationDelta >= FAST_ROTATION_THRESHOLD_RADIANS || fovDelta >= FAST_FOV_THRESHOLD_DEGREES;
12841
- if (!viewChanged) {
12842
- return;
12843
- }
12844
- const needsImmediateUpdate = visibilityDirtyRef.current || viewportChanged || movingQuickly;
12845
- if (!needsImmediateUpdate && now - lastUpdateAtRef.current < MAX_LOD_UPDATE_INTERVAL_MS) {
12846
- return;
12847
- }
12848
- lastUpdateAtRef.current = now;
12849
- const targetLevel = loadMode === "base" ? 1 : getPreferredLevel(
12850
- levels,
12851
- size.height,
12852
- pixelRatio,
12853
- camera.fov,
12854
- currentLevelRef.current
12855
- );
12856
- if (targetLevel !== currentLevelRef.current) {
12857
- currentLevelRef.current = targetLevel;
12858
- levelChangeRef.current?.(targetLevel);
12859
- }
12860
- const visibilityCamera = visibilityCameraRef.current;
12861
- visibilityCamera.copy(camera, false);
12862
- visibilityCamera.fov = Math.min(
12863
- 179,
12864
- camera.fov + VISIBILITY_FOV_PADDING_DEGREES
12865
- );
12866
- visibilityCamera.aspect = camera.aspect;
12867
- updateVisibilityFrustum(
12868
- visibilityCamera,
12869
- projectionMatrixRef.current,
12870
- frustumRef.current
12871
- );
12872
- const nextLayers = buildLayers(
12873
- targetLevel,
12874
- levels,
12875
- tileSize,
12876
- frustumRef.current,
12877
- camera,
12878
- candidatesByLevel
13027
+ const updateLod = decideTileLodUpdate({
13028
+ loadMode,
13029
+ trackedLoadMode: trackedLoadModeRef.current,
13030
+ now,
13031
+ lastUpdateAt: lastUpdateAtRef.current,
13032
+ visibilityDirty: visibilityDirtyRef.current,
13033
+ viewportChanged,
13034
+ rotationDelta,
13035
+ fovDelta
13036
+ });
13037
+ if (updateLod) {
13038
+ trackedLoadModeRef.current = loadMode;
13039
+ lastUpdateAtRef.current = now;
13040
+ const targetLevel = loadMode === "base" ? 1 : getPreferredLevel(
13041
+ levels,
13042
+ size.height,
13043
+ pixelRatio,
13044
+ camera.fov,
13045
+ currentLevelRef.current
13046
+ );
13047
+ if (targetLevel !== currentLevelRef.current) {
13048
+ currentLevelRef.current = targetLevel;
13049
+ levelChangeRef.current?.(targetLevel);
13050
+ }
13051
+ const visibilityCamera = visibilityCameraRef.current;
13052
+ visibilityCamera.copy(camera, false);
13053
+ visibilityCamera.fov = Math.min(
13054
+ 179,
13055
+ camera.fov + VISIBILITY_FOV_PADDING_DEGREES
13056
+ );
13057
+ visibilityCamera.aspect = camera.aspect;
13058
+ updateVisibilityFrustum(
13059
+ visibilityCamera,
13060
+ projectionMatrixRef.current,
13061
+ frustumRef.current
13062
+ );
13063
+ const nextLayers = buildLayers(
13064
+ targetLevel,
13065
+ levels,
13066
+ tileSize,
13067
+ frustumRef.current,
13068
+ camera,
13069
+ candidatesByLevel
13070
+ );
13071
+ visibilityDirtyRef.current = false;
13072
+ lastVisibilityQuaternionRef.current.copy(camera.quaternion);
13073
+ lastVisibilityFovRef.current = camera.fov;
13074
+ lastViewportRef.current = {
13075
+ width: size.width,
13076
+ height: size.height,
13077
+ dpr: pixelRatio
13078
+ };
13079
+ const targetLayer = nextLayers.find((layer) => layer.level === targetLevel);
13080
+ targetKeysRef.current = loadMode === "full" ? (targetLayer?.addresses ?? []).map(
13081
+ (address) => `${resolveUrl(address)}\0${tileKey(address)}`
13082
+ ) : [];
13083
+ commitLayers(nextLayers);
13084
+ }
13085
+ publishSceneDetail(
13086
+ detailReporterRef.current,
13087
+ detailTokenRef,
13088
+ loadMode === "full" && viewTilesAreDrawable(
13089
+ targetKeysRef.current.map((key) => manager.getSnapshot(key).texture)
13090
+ )
12879
13091
  );
12880
- visibilityDirtyRef.current = false;
12881
- lastVisibilityQuaternionRef.current.copy(camera.quaternion);
12882
- lastVisibilityFovRef.current = camera.fov;
12883
- lastViewportRef.current = {
12884
- width: size.width,
12885
- height: size.height,
12886
- dpr: pixelRatio
12887
- };
12888
- commitLayers(nextLayers);
12889
13092
  });
12890
- return /* @__PURE__ */ jsxs13("group", { visible, children: [
12891
- previewTexture ? /* @__PURE__ */ jsx22(PreviewCube, { texture: previewTexture, faceOrder: previewFaceOrder }) : null,
12892
- layers.map((layer) => /* @__PURE__ */ jsx22(
13093
+ return /* @__PURE__ */ jsxs14("group", { visible, children: [
13094
+ previewTexture ? /* @__PURE__ */ jsx23(PreviewCube, { texture: previewTexture, faceOrder: previewFaceOrder }) : null,
13095
+ layers.map((layer) => /* @__PURE__ */ jsx23(
12893
13096
  TileLayerMeshes,
12894
13097
  {
12895
13098
  layer,
@@ -12902,7 +13105,7 @@ function Tile({
12902
13105
  }
12903
13106
 
12904
13107
  // src/scenes.tsx
12905
- import { jsx as jsx23, jsxs as jsxs14 } from "react/jsx-runtime";
13108
+ import { jsx as jsx24, jsxs as jsxs15 } from "react/jsx-runtime";
12906
13109
  function SceneSource({
12907
13110
  scene,
12908
13111
  visible,
@@ -12915,7 +13118,7 @@ function SceneSource({
12915
13118
  }
12916
13119
  switch (scene.type) {
12917
13120
  case "sphere":
12918
- return /* @__PURE__ */ jsx23(
13121
+ return /* @__PURE__ */ jsx24(
12919
13122
  Sphere,
12920
13123
  {
12921
13124
  src: scene.src,
@@ -12928,7 +13131,7 @@ function SceneSource({
12928
13131
  );
12929
13132
  case "tile": {
12930
13133
  const { id: _id, type: _type, ...tileProps } = scene;
12931
- return /* @__PURE__ */ jsx23(
13134
+ return /* @__PURE__ */ jsx24(
12932
13135
  Tile,
12933
13136
  {
12934
13137
  ...tileProps,
@@ -12939,6 +13142,19 @@ function SceneSource({
12939
13142
  }
12940
13143
  );
12941
13144
  }
13145
+ case "sphereTile": {
13146
+ const { id: _id, type: _type, ...tileProps } = scene;
13147
+ return /* @__PURE__ */ jsx24(
13148
+ SphereTile,
13149
+ {
13150
+ ...tileProps,
13151
+ visible,
13152
+ loadMode: baseOnly ? "base" : "full",
13153
+ onReady,
13154
+ onPreviewError: onError
13155
+ }
13156
+ );
13157
+ }
12942
13158
  default: {
12943
13159
  const exhaustive = scene;
12944
13160
  void exhaustive;
@@ -12951,17 +13167,17 @@ function SnapshotCapture({
12951
13167
  maxPixels,
12952
13168
  onCaptured
12953
13169
  }) {
12954
- const { camera, gl, scene, size } = useThree20();
12955
- const capturedRequestRef = useRef29(0);
12956
- const renderTargetRef = useRef29(null);
12957
- useEffect29(
13170
+ const { camera, gl, scene, size } = useThree21();
13171
+ const capturedRequestRef = useRef30(0);
13172
+ const renderTargetRef = useRef30(null);
13173
+ useEffect30(
12958
13174
  () => () => {
12959
13175
  renderTargetRef.current?.dispose();
12960
13176
  renderTargetRef.current = null;
12961
13177
  },
12962
13178
  []
12963
13179
  );
12964
- useFrame13(() => {
13180
+ useFrame14(() => {
12965
13181
  if (requestId === 0 || requestId === capturedRequestRef.current) {
12966
13182
  return;
12967
13183
  }
@@ -13005,18 +13221,20 @@ function ScenesController({
13005
13221
  activeSceneId,
13006
13222
  transition: transitionInput,
13007
13223
  renderHotspots,
13224
+ onSceneReady,
13008
13225
  onTransitionEnd,
13009
13226
  onTransitionError,
13010
13227
  snapshotMaxPixels = 3686400,
13228
+ transitionWaitForDetailMs,
13011
13229
  phaseRef: externalPhaseRef
13012
13230
  }) {
13013
- const controlsRef = useContext23(PanoramaViewContext);
13231
+ const controlsRef = useContext24(PanoramaViewContext);
13014
13232
  const manager = useSharedTileTextureManager();
13015
- const transition = useMemo21(
13233
+ const transition = useMemo22(
13016
13234
  () => resolveTransition(transitionInput),
13017
13235
  [transitionInput]
13018
13236
  );
13019
- const sceneMap = useMemo21(
13237
+ const sceneMap = useMemo22(
13020
13238
  () => new Map(scenes.map((scene) => [scene.id, scene])),
13021
13239
  [scenes]
13022
13240
  );
@@ -13033,13 +13251,21 @@ function ScenesController({
13033
13251
  const [transitionRunId, setTransitionRunId] = useState14(0);
13034
13252
  const [snapshot, setSnapshot] = useState14(null);
13035
13253
  const [recoveryKey, setRecoveryKey] = useState14(0);
13036
- const requestedSceneIdRef = useRef29(activeSceneId);
13037
- const captureReasonRef = useRef29("start");
13038
- const interactionReleaseRef = useRef29(null);
13039
- const slotsRef = useRef29(slots);
13040
- const phaseRef = useRef29(phase);
13041
- const liveSlotRef = useRef29(liveSlot);
13042
- const transitionFromRef = useRef29(initialScene);
13254
+ const requestedSceneIdRef = useRef30(activeSceneId);
13255
+ const captureReasonRef = useRef30("start");
13256
+ const interactionReleaseRef = useRef30(null);
13257
+ const slotsRef = useRef30(slots);
13258
+ const phaseRef = useRef30(phase);
13259
+ const liveSlotRef = useRef30(liveSlot);
13260
+ const transitionFromRef = useRef30(initialScene);
13261
+ const readySceneRef = useRef30(null);
13262
+ const waitRef = useRef30(null);
13263
+ const waitTimerRef = useRef30(null);
13264
+ const detailGenerationRef = useRef30(0);
13265
+ const [detailGeneration, setDetailGeneration] = useState14(0);
13266
+ const mountedRef = useRef30(true);
13267
+ const waitForDetailMsRef = useRef30(0);
13268
+ waitForDetailMsRef.current = normalizeTransitionWaitMs(transitionWaitForDetailMs);
13043
13269
  slotsRef.current = slots;
13044
13270
  phaseRef.current = phase;
13045
13271
  if (externalPhaseRef) {
@@ -13053,7 +13279,36 @@ function ScenesController({
13053
13279
  const reportError = useCallback11((sceneId, error) => {
13054
13280
  onTransitionError?.({ sceneId, error });
13055
13281
  }, [onTransitionError]);
13282
+ const clearDetailWait = useCallback11((bumpGeneration) => {
13283
+ if (waitTimerRef.current !== null) {
13284
+ clearTimeout(waitTimerRef.current);
13285
+ waitTimerRef.current = null;
13286
+ }
13287
+ const generation = waitRef.current?.generation;
13288
+ if (generation === void 0) {
13289
+ waitRef.current = null;
13290
+ } else {
13291
+ waitRef.current = acceptDetailWait(waitRef.current, {
13292
+ kind: "cancel",
13293
+ generation
13294
+ }).wait;
13295
+ }
13296
+ if (!bumpGeneration || !mountedRef.current) {
13297
+ return;
13298
+ }
13299
+ const nextGeneration = detailGenerationRef.current + 1;
13300
+ detailGenerationRef.current = nextGeneration;
13301
+ setDetailGeneration(nextGeneration);
13302
+ }, []);
13303
+ useEffect30(() => {
13304
+ mountedRef.current = true;
13305
+ return () => {
13306
+ mountedRef.current = false;
13307
+ clearDetailWait(false);
13308
+ };
13309
+ }, [clearDetailWait]);
13056
13310
  const startPreload = useCallback11((scene) => {
13311
+ clearDetailWait(true);
13057
13312
  const nextSlot = 1 - liveSlotRef.current;
13058
13313
  requestedSceneIdRef.current = scene.id;
13059
13314
  setSlots((current) => {
@@ -13063,8 +13318,8 @@ function ScenesController({
13063
13318
  });
13064
13319
  setPendingSlot(nextSlot);
13065
13320
  setPhase("preloading");
13066
- }, []);
13067
- useEffect29(() => {
13321
+ }, [clearDetailWait]);
13322
+ useEffect30(() => {
13068
13323
  const requested = sceneMap.get(activeSceneId);
13069
13324
  if (!requested) {
13070
13325
  reportError(activeSceneId, new Error(`Unknown panorama scene: ${activeSceneId}`));
@@ -13079,20 +13334,31 @@ function ScenesController({
13079
13334
  requestedSceneIdRef.current = requested.id;
13080
13335
  return;
13081
13336
  }
13082
- if (phaseRef.current === "transitioning" || phaseRef.current === "capturing") {
13337
+ if (phaseRef.current === "transitioning" || phaseRef.current === "capturing" || phaseRef.current === "awaitingDetail") {
13338
+ if (requestedSceneIdRef.current === requested.id) return;
13083
13339
  requestedSceneIdRef.current = requested.id;
13084
13340
  captureReasonRef.current = "interrupt";
13341
+ clearDetailWait(true);
13085
13342
  setPhase("recapturing");
13086
13343
  setCaptureRequestId((current) => current + 1);
13087
13344
  return;
13088
13345
  }
13089
13346
  startPreload(requested);
13090
- }, [activeSceneId, pendingSlot, reportError, sceneMap, startPreload]);
13347
+ }, [activeSceneId, clearDetailWait, pendingSlot, reportError, sceneMap, startPreload]);
13348
+ const notifySceneReady = useCallback11((scene) => {
13349
+ if (!scene || readySceneRef.current === scene) return;
13350
+ readySceneRef.current = scene;
13351
+ onSceneReady?.(scene.id);
13352
+ }, [onSceneReady]);
13091
13353
  const handleReady = useCallback11((slot) => {
13354
+ if (slot === liveSlotRef.current && pendingSlot === null && phaseRef.current === "idle") {
13355
+ notifySceneReady(slotsRef.current[slot]);
13356
+ return;
13357
+ }
13092
13358
  if (slot !== pendingSlot || phaseRef.current !== "preloading") {
13093
13359
  return;
13094
13360
  }
13095
- if (transition.preset === "none") {
13361
+ if (transition.preset === "none" && waitForDetailMsRef.current === 0) {
13096
13362
  const previousScene = slotsRef.current[liveSlotRef.current];
13097
13363
  const nextScene = slotsRef.current[slot];
13098
13364
  setSlots((current) => {
@@ -13104,6 +13370,7 @@ function ScenesController({
13104
13370
  setActiveSlot(slot);
13105
13371
  setPendingSlot(null);
13106
13372
  setPhase("idle");
13373
+ notifySceneReady(nextScene);
13107
13374
  if (previousScene && nextScene) {
13108
13375
  onTransitionEnd?.({
13109
13376
  previousSceneId: previousScene.id,
@@ -13118,29 +13385,7 @@ function ScenesController({
13118
13385
  captureReasonRef.current = "start";
13119
13386
  setPhase("capturing");
13120
13387
  setCaptureRequestId((current) => current + 1);
13121
- }, [controlsRef, onTransitionEnd, pendingSlot, transition.preset]);
13122
- const handleCaptured = useCallback11((nextSnapshot) => {
13123
- setSnapshot((current) => {
13124
- current?.dispose();
13125
- return nextSnapshot;
13126
- });
13127
- if (captureReasonRef.current === "interrupt") {
13128
- startPreload(sceneMap.get(requestedSceneIdRef.current));
13129
- return;
13130
- }
13131
- const sourceSlot = liveSlotRef.current;
13132
- setSlots((current) => {
13133
- const next = [...current];
13134
- next[sourceSlot] = null;
13135
- return next;
13136
- });
13137
- manager?.releaseUnused();
13138
- if (pendingSlot !== null) {
13139
- setLiveSlot(pendingSlot);
13140
- }
13141
- setPhase("transitioning");
13142
- setTransitionRunId((current) => current + 1);
13143
- }, [manager, pendingSlot, sceneMap, startPreload]);
13388
+ }, [controlsRef, notifySceneReady, onTransitionEnd, pendingSlot, transition.preset]);
13144
13389
  const finishTransition = useCallback11(() => {
13145
13390
  const nextSlot = pendingSlot;
13146
13391
  const previousScene = transitionFromRef.current;
@@ -13166,16 +13411,142 @@ function ScenesController({
13166
13411
  });
13167
13412
  }
13168
13413
  }, [onTransitionEnd, pendingSlot, releaseInteraction, snapshot, transition.preset]);
13169
- useEffect29(() => () => {
13414
+ const finishTransitionRef = useRef30(finishTransition);
13415
+ finishTransitionRef.current = finishTransition;
13416
+ const transitionRef = useRef30(transition);
13417
+ transitionRef.current = transition;
13418
+ const consumeDetailSignal = useCallback11((signal) => {
13419
+ const decision = acceptDetailWait(waitRef.current, signal);
13420
+ waitRef.current = decision.wait;
13421
+ if (!decision.start) {
13422
+ return;
13423
+ }
13424
+ if (waitTimerRef.current !== null) {
13425
+ clearTimeout(waitTimerRef.current);
13426
+ waitTimerRef.current = null;
13427
+ }
13428
+ if (!mountedRef.current) {
13429
+ return;
13430
+ }
13431
+ if (transitionRef.current.preset === "none") {
13432
+ finishTransitionRef.current();
13433
+ return;
13434
+ }
13435
+ setPhase("transitioning");
13436
+ setTransitionRunId((current) => current + 1);
13437
+ }, []);
13438
+ const handleCaptured = useCallback11((nextSnapshot) => {
13439
+ if (captureReasonRef.current === "interrupt") {
13440
+ setSnapshot((current) => {
13441
+ current?.dispose();
13442
+ return nextSnapshot;
13443
+ });
13444
+ startPreload(sceneMap.get(requestedSceneIdRef.current));
13445
+ return;
13446
+ }
13447
+ const sourceSlot = liveSlotRef.current;
13448
+ const incoming = pendingSlot === null ? null : slotsRef.current[pendingSlot];
13449
+ setSlots((current) => {
13450
+ const next = [...current];
13451
+ next[sourceSlot] = null;
13452
+ return next;
13453
+ });
13454
+ manager?.releaseUnused();
13455
+ if (pendingSlot !== null && incoming) {
13456
+ notifySceneReady(incoming);
13457
+ setLiveSlot(pendingSlot);
13458
+ }
13459
+ if (waitTimerRef.current !== null) {
13460
+ clearTimeout(waitTimerRef.current);
13461
+ waitTimerRef.current = null;
13462
+ }
13463
+ waitRef.current = null;
13464
+ let hold = null;
13465
+ if (incoming && waitForDetailMsRef.current > 0) {
13466
+ const now = performance.now();
13467
+ const generation = detailGenerationRef.current + 1;
13468
+ detailGenerationRef.current = generation;
13469
+ hold = planDetailHold({
13470
+ waitMs: waitForDetailMsRef.current,
13471
+ now,
13472
+ generation,
13473
+ sceneId: incoming.id
13474
+ });
13475
+ if (hold) {
13476
+ const deadline = hold.deadline;
13477
+ waitRef.current = hold;
13478
+ setDetailGeneration(generation);
13479
+ waitTimerRef.current = setTimeout(() => {
13480
+ consumeDetailSignal({
13481
+ kind: "timeout",
13482
+ generation,
13483
+ now: deadline
13484
+ });
13485
+ }, Math.max(0, deadline - performance.now()));
13486
+ }
13487
+ }
13488
+ const nextPhase = phaseAfterSnapshot(transition.preset, hold);
13489
+ if (nextPhase === "awaitingDetail") {
13490
+ setSnapshot((current) => {
13491
+ current?.dispose();
13492
+ return nextSnapshot;
13493
+ });
13494
+ setPhase("awaitingDetail");
13495
+ return;
13496
+ }
13497
+ if (nextPhase === "idle") {
13498
+ nextSnapshot.dispose();
13499
+ setSnapshot((current) => {
13500
+ current?.dispose();
13501
+ return null;
13502
+ });
13503
+ if (pendingSlot !== null) {
13504
+ setActiveSlot(pendingSlot);
13505
+ }
13506
+ setPendingSlot(null);
13507
+ setPhase("idle");
13508
+ releaseInteraction();
13509
+ const previousScene = transitionFromRef.current;
13510
+ if (previousScene && incoming) {
13511
+ onTransitionEnd?.({
13512
+ previousSceneId: previousScene.id,
13513
+ sceneId: incoming.id,
13514
+ preset: "none"
13515
+ });
13516
+ }
13517
+ return;
13518
+ }
13519
+ setSnapshot((current) => {
13520
+ current?.dispose();
13521
+ return nextSnapshot;
13522
+ });
13523
+ setPhase("transitioning");
13524
+ setTransitionRunId((current) => current + 1);
13525
+ }, [
13526
+ consumeDetailSignal,
13527
+ manager,
13528
+ notifySceneReady,
13529
+ onTransitionEnd,
13530
+ pendingSlot,
13531
+ releaseInteraction,
13532
+ sceneMap,
13533
+ startPreload,
13534
+ transition.preset
13535
+ ]);
13536
+ const snapshotRef = useRef30(snapshot);
13537
+ snapshotRef.current = snapshot;
13538
+ useEffect30(() => () => {
13170
13539
  releaseInteraction();
13171
- snapshot?.dispose();
13172
- }, [releaseInteraction, snapshot]);
13173
- const { gl } = useThree20();
13174
- useEffect29(() => {
13540
+ snapshotRef.current?.dispose();
13541
+ snapshotRef.current = null;
13542
+ }, [releaseInteraction]);
13543
+ const { gl } = useThree21();
13544
+ useEffect30(() => {
13175
13545
  const canvas = gl.domElement;
13176
13546
  const onContextLost = (event) => {
13177
13547
  event.preventDefault();
13178
13548
  releaseInteraction();
13549
+ clearDetailWait(true);
13179
13550
  manager?.dispose();
13180
13551
  snapshot?.dispose();
13181
13552
  setSnapshot(null);
@@ -13183,6 +13554,7 @@ function ScenesController({
13183
13554
  setPhase("idle");
13184
13555
  };
13185
13556
  const onContextRestored = () => {
13557
+ readySceneRef.current = null;
13186
13558
  manager?.resume();
13187
13559
  setRecoveryKey((current) => current + 1);
13188
13560
  };
@@ -13192,11 +13564,30 @@ function ScenesController({
13192
13564
  canvas.removeEventListener("webglcontextlost", onContextLost);
13193
13565
  canvas.removeEventListener("webglcontextrestored", onContextRestored);
13194
13566
  };
13195
- }, [gl, manager, releaseInteraction, snapshot]);
13567
+ }, [clearDetailWait, gl, manager, releaseInteraction, snapshot]);
13196
13568
  const renderedScene = slots[liveSlot];
13197
13569
  const snapshotVisible = snapshot !== null && (phase === "transitioning" || phase === "recapturing" || phase === "preloading");
13198
- return /* @__PURE__ */ jsxs14(Fragment6, { children: [
13199
- /* @__PURE__ */ jsx23(
13570
+ const slotSceneKey = `${slots[0]?.id ?? ""}
13571
+ ${slots[1]?.id ?? ""}`;
13572
+ const detailReporters = useMemo22(() => {
13573
+ const [firstSceneId = "", secondSceneId = ""] = slotSceneKey.split("\n");
13574
+ const sceneIds = [firstSceneId, secondSceneId];
13575
+ return sceneIds.map((sceneId) => ({
13576
+ generation: detailGeneration,
13577
+ report: (ready) => {
13578
+ if (!ready || sceneId === "") {
13579
+ return;
13580
+ }
13581
+ consumeDetailSignal({
13582
+ kind: "ready",
13583
+ generation: detailGeneration,
13584
+ sceneId
13585
+ });
13586
+ }
13587
+ }));
13588
+ }, [consumeDetailSignal, detailGeneration, slotSceneKey]);
13589
+ return /* @__PURE__ */ jsxs15(Fragment6, { children: [
13590
+ /* @__PURE__ */ jsx24(
13200
13591
  SnapshotCapture,
13201
13592
  {
13202
13593
  requestId: captureRequestId,
@@ -13208,23 +13599,30 @@ function ScenesController({
13208
13599
  const source = slots[slot];
13209
13600
  const isLive = slot === liveSlot;
13210
13601
  const isPending = slot === pendingSlot;
13211
- return /* @__PURE__ */ jsx23(
13212
- SceneSource,
13602
+ return /* @__PURE__ */ jsx24(
13603
+ SceneDetailContext.Provider,
13213
13604
  {
13214
- scene: source,
13215
- visible: isLive,
13216
- baseOnly: isPending && phase !== "idle",
13217
- onReady: () => handleReady(slot),
13218
- onError: (error) => {
13219
- if (source) {
13220
- reportError(source.id, error);
13605
+ value: detailReporters[slot],
13606
+ children: /* @__PURE__ */ jsx24(
13607
+ SceneSource,
13608
+ {
13609
+ scene: source,
13610
+ visible: isLive,
13611
+ baseOnly: pendingSceneUsesBaseLayer(phase, isPending),
13612
+ onReady: () => handleReady(slot),
13613
+ onError: (error) => {
13614
+ if (source) {
13615
+ reportError(source.id, error);
13616
+ }
13617
+ }
13221
13618
  }
13222
- }
13619
+ )
13223
13620
  },
13224
13621
  `${slot}:${source?.id ?? "empty"}:${recoveryKey}`
13225
13622
  );
13226
13623
  }),
13227
- snapshotVisible ? /* @__PURE__ */ jsx23(
13624
+ snapshot !== null && phase === "awaitingDetail" ? /* @__PURE__ */ jsx24(SnapshotHold, { snapshot }) : null,
13625
+ snapshotVisible ? /* @__PURE__ */ jsx24(
13228
13626
  TransitionOverlay,
13229
13627
  {
13230
13628
  snapshot,
@@ -13261,13 +13659,13 @@ function Scenes({
13261
13659
  },
13262
13660
  [isControlled, onActiveSceneIdChange]
13263
13661
  );
13264
- const scenesRef = useRef29(scenes);
13662
+ const scenesRef = useRef30(scenes);
13265
13663
  scenesRef.current = scenes;
13266
- const resolvedIdRef = useRef29(resolvedId);
13664
+ const resolvedIdRef = useRef30(resolvedId);
13267
13665
  resolvedIdRef.current = resolvedId;
13268
- const host = useContext23(ScenesHostContext);
13269
- const phaseRef = useRef29("idle");
13270
- useEffect29(() => {
13666
+ const host = useContext24(ScenesHostContext);
13667
+ const phaseRef = useRef30("idle");
13668
+ useEffect30(() => {
13271
13669
  if (!host) {
13272
13670
  return;
13273
13671
  }
@@ -13317,12 +13715,12 @@ function Scenes({
13317
13715
  }
13318
13716
  };
13319
13717
  }, [host, requestSceneChange]);
13320
- return /* @__PURE__ */ jsx23(
13718
+ return /* @__PURE__ */ jsx24(
13321
13719
  TileTextureManagerProvider,
13322
13720
  {
13323
13721
  maxTextureMemoryMb,
13324
13722
  maxConcurrentLoads: maxConcurrentTileLoads,
13325
- children: /* @__PURE__ */ jsx23(
13723
+ children: /* @__PURE__ */ jsx24(
13326
13724
  ScenesController,
13327
13725
  {
13328
13726
  ...rest,
@@ -13336,8 +13734,8 @@ function Scenes({
13336
13734
  }
13337
13735
 
13338
13736
  // src/hotspot/image-hotspot.tsx
13339
- import { useThree as useThree23 } from "@react-three/fiber";
13340
- import { useEffect as useEffect32, useRef as useRef32, useState as useState17 } from "react";
13737
+ import { useThree as useThree24 } from "@react-three/fiber";
13738
+ import { useEffect as useEffect33, useRef as useRef33, useState as useState17 } from "react";
13341
13739
  import {
13342
13740
  ClampToEdgeWrapping as ClampToEdgeWrapping3,
13343
13741
  LinearFilter as LinearFilter6,
@@ -13347,13 +13745,13 @@ import {
13347
13745
  } from "three";
13348
13746
 
13349
13747
  // src/hotspot/hotspot-anchor.tsx
13350
- import { useFrame as useFrame15, useThree as useThree22 } from "@react-three/fiber";
13748
+ import { useFrame as useFrame16, useThree as useThree23 } from "@react-three/fiber";
13351
13749
  import {
13352
- useContext as useContext25,
13353
- useEffect as useEffect31,
13750
+ useContext as useContext26,
13751
+ useEffect as useEffect32,
13354
13752
  useLayoutEffect as useLayoutEffect5,
13355
- useMemo as useMemo23,
13356
- useRef as useRef31,
13753
+ useMemo as useMemo24,
13754
+ useRef as useRef32,
13357
13755
  useState as useState16
13358
13756
  } from "react";
13359
13757
  import {
@@ -13365,25 +13763,25 @@ import {
13365
13763
  PlaneGeometry as PlaneGeometry5,
13366
13764
  Quaternion as Quaternion4,
13367
13765
  Ray,
13368
- Vector3 as Vector316
13766
+ Vector3 as Vector317
13369
13767
  } from "three";
13370
13768
 
13371
13769
  // src/hotspot/hotspot-tooltip.tsx
13372
- import { useEffect as useEffect30, useMemo as useMemo22, useState as useState15 } from "react";
13770
+ import { useEffect as useEffect31, useMemo as useMemo23, useState as useState15 } from "react";
13373
13771
 
13374
13772
  // src/webvr/stereo-html.tsx
13375
- import { useFrame as useFrame14, useThree as useThree21 } from "@react-three/fiber";
13773
+ import { useFrame as useFrame15, useThree as useThree22 } from "@react-three/fiber";
13376
13774
  import {
13377
- useContext as useContext24,
13775
+ useContext as useContext25,
13378
13776
  useLayoutEffect as useLayoutEffect4,
13379
- useRef as useRef30,
13777
+ useRef as useRef31,
13380
13778
  useSyncExternalStore as useSyncExternalStore7
13381
13779
  } from "react";
13382
13780
  import { createRoot } from "react-dom/client";
13383
- import { Vector3 as Vector314 } from "three";
13384
- import { Fragment as Fragment7, jsx as jsx24, jsxs as jsxs15 } from "react/jsx-runtime";
13781
+ import { Vector3 as Vector315 } from "three";
13782
+ import { Fragment as Fragment7, jsx as jsx25, jsxs as jsxs16 } from "react/jsx-runtime";
13385
13783
  function useFallbackStereoView() {
13386
- const runtime = useContext24(WebVRRuntimeContext);
13784
+ const runtime = useContext25(WebVRRuntimeContext);
13387
13785
  const host = runtime?.host ?? null;
13388
13786
  const fallback = useSyncExternalStore7(
13389
13787
  (onStoreChange) => host ? subscribeWebVRHost(host, onStoreChange) : () => void 0,
@@ -13400,10 +13798,10 @@ function ProjectedHtml({
13400
13798
  stereoView,
13401
13799
  eye
13402
13800
  }) {
13403
- const { camera, gl, events, size } = useThree21();
13404
- const group = useRef30(null);
13405
- const overlay = useRef30(null);
13406
- const scratch = useRef30(new Vector314());
13801
+ const { camera, gl, events, size } = useThree22();
13802
+ const group = useRef31(null);
13803
+ const overlay = useRef31(null);
13804
+ const scratch = useRef31(new Vector315());
13407
13805
  const target = events.connected || gl.domElement.parentElement;
13408
13806
  const updatePosition = () => {
13409
13807
  const anchor = group.current;
@@ -13451,7 +13849,7 @@ function ProjectedHtml({
13451
13849
  }, [target]);
13452
13850
  useLayoutEffect4(() => {
13453
13851
  overlay.current?.root.render(
13454
- /* @__PURE__ */ jsx24(
13852
+ /* @__PURE__ */ jsx25(
13455
13853
  "div",
13456
13854
  {
13457
13855
  "aria-hidden": eye === "right" || void 0,
@@ -13462,19 +13860,19 @@ function ProjectedHtml({
13462
13860
  );
13463
13861
  updatePosition();
13464
13862
  });
13465
- useFrame14(updatePosition);
13466
- return /* @__PURE__ */ jsx24("group", { ref: group });
13863
+ useFrame15(updatePosition);
13864
+ return /* @__PURE__ */ jsx25("group", { ref: group });
13467
13865
  }
13468
13866
  function PanoHtml(props) {
13469
13867
  const stereoView = useFallbackStereoView();
13470
- return stereoView ? /* @__PURE__ */ jsxs15(Fragment7, { children: [
13471
- /* @__PURE__ */ jsx24(ProjectedHtml, { ...props, stereoView, eye: "left" }),
13472
- /* @__PURE__ */ jsx24(ProjectedHtml, { ...props, stereoView, eye: "right" })
13473
- ] }) : /* @__PURE__ */ jsx24(ProjectedHtml, { ...props });
13868
+ return stereoView ? /* @__PURE__ */ jsxs16(Fragment7, { children: [
13869
+ /* @__PURE__ */ jsx25(ProjectedHtml, { ...props, stereoView, eye: "left" }),
13870
+ /* @__PURE__ */ jsx25(ProjectedHtml, { ...props, stereoView, eye: "right" })
13871
+ ] }) : /* @__PURE__ */ jsx25(ProjectedHtml, { ...props });
13474
13872
  }
13475
13873
 
13476
13874
  // src/hotspot/hotspot-tooltip.tsx
13477
- import { jsx as jsx25, jsxs as jsxs16 } from "react/jsx-runtime";
13875
+ import { jsx as jsx26, jsxs as jsxs17 } from "react/jsx-runtime";
13478
13876
  var DEFAULT_HOTSPOT_TOOLTIP_OFFSET = 12;
13479
13877
  var DEFAULT_HOTSPOT_TOOLTIP_APPEARANCE = {
13480
13878
  background: "rgba(22, 22, 22, 0.72)",
@@ -13547,15 +13945,15 @@ function HotspotTooltip({
13547
13945
  appearance
13548
13946
  }) {
13549
13947
  const [imageFailed, setImageFailed] = useState15(false);
13550
- useEffect30(() => {
13948
+ useEffect31(() => {
13551
13949
  setImageFailed(false);
13552
13950
  }, [content.image]);
13553
13951
  const showImage = Boolean(content.image) && !imageFailed;
13554
- const resolvedAppearance = useMemo22(
13952
+ const resolvedAppearance = useMemo23(
13555
13953
  () => resolveHotspotTooltipAppearance(appearance),
13556
13954
  [appearance]
13557
13955
  );
13558
- const bubbleStyle = useMemo22(
13956
+ const bubbleStyle = useMemo23(
13559
13957
  () => ({
13560
13958
  background: resolvedAppearance.background,
13561
13959
  border: resolvedAppearance.border,
@@ -13577,8 +13975,8 @@ function HotspotTooltip({
13577
13975
  if (!showImage && !content.text) {
13578
13976
  return null;
13579
13977
  }
13580
- return /* @__PURE__ */ jsx25(PanoHtml, { pointerEvents: "none", style: WRAPPER_STYLE, zIndexRange: [20, 10], children: /* @__PURE__ */ jsxs16("div", { className: "pano-hotspot-tooltip", role: "tooltip", style: bubbleStyle, children: [
13581
- showImage ? /* @__PURE__ */ jsx25(
13978
+ return /* @__PURE__ */ jsx26(PanoHtml, { pointerEvents: "none", style: WRAPPER_STYLE, zIndexRange: [20, 10], children: /* @__PURE__ */ jsxs17("div", { className: "pano-hotspot-tooltip", role: "tooltip", style: bubbleStyle, children: [
13979
+ showImage ? /* @__PURE__ */ jsx26(
13582
13980
  "img",
13583
13981
  {
13584
13982
  alt: content.imageAlt ?? content.text ?? "",
@@ -13587,7 +13985,7 @@ function HotspotTooltip({
13587
13985
  src: content.image
13588
13986
  }
13589
13987
  ) : null,
13590
- content.text ? /* @__PURE__ */ jsx25(
13988
+ content.text ? /* @__PURE__ */ jsx26(
13591
13989
  "p",
13592
13990
  {
13593
13991
  className: "pano-hotspot-tooltip-text",
@@ -13606,10 +14004,10 @@ function HotspotTooltip({
13606
14004
  import {
13607
14005
  MathUtils as MathUtils8,
13608
14006
  PerspectiveCamera as PerspectiveCamera6,
13609
- Vector3 as Vector315
14007
+ Vector3 as Vector316
13610
14008
  } from "three";
13611
- var LOCAL_FORWARD = new Vector315(0, 0, 1);
13612
- var CAMERA_POSITION = new Vector315();
14009
+ var LOCAL_FORWARD = new Vector316(0, 0, 1);
14010
+ var CAMERA_POSITION = new Vector316();
13613
14011
  function applyHotspotTransform(group, camera, orientation2, surfaceQuaternion3, rotation, scaleMode, referenceFov, useAngularScale, worldWidth, worldHeight, distance) {
13614
14012
  if (orientation2 === "billboard") {
13615
14013
  group.quaternion.copy(camera.quaternion);
@@ -13638,7 +14036,7 @@ function fixedScaleFactor(cameraFov, referenceFov) {
13638
14036
  }
13639
14037
 
13640
14038
  // src/hotspot/hotspot-anchor.tsx
13641
- import { jsx as jsx26, jsxs as jsxs17 } from "react/jsx-runtime";
14039
+ import { jsx as jsx27, jsxs as jsxs18 } from "react/jsx-runtime";
13642
14040
  var DEFAULT_FLOATING_DISTANCE = 10;
13643
14041
  var PANORAMA_RADIUS = DEFAULT_PANORAMA_RADIUS;
13644
14042
  var PANORAMA_SURFACE_INSET = 4;
@@ -13648,18 +14046,18 @@ var MAX_ANGULAR_SIZE = 179;
13648
14046
  var DRAG_EPSILON_DEGREES = 1e-3;
13649
14047
  var TOOLTIP_WORLD_BOX = new Box34();
13650
14048
  var TOOLTIP_LOCAL_BOX = new Box34();
13651
- var TOOLTIP_CORNER = new Vector316();
14049
+ var TOOLTIP_CORNER = new Vector317();
13652
14050
  var TOOLTIP_INVERSE = new Matrix44();
13653
- var TOOLTIP_WORLD_CORNER = new Vector316();
13654
- var TOOLTIP_PROJECTED = new Vector316();
13655
- var TOOLTIP_RAY_ORIGIN = new Vector316();
13656
- var TOOLTIP_RAY_FAR = new Vector316();
13657
- var TOOLTIP_RAY_DIRECTION = new Vector316();
14051
+ var TOOLTIP_WORLD_CORNER = new Vector317();
14052
+ var TOOLTIP_PROJECTED = new Vector317();
14053
+ var TOOLTIP_RAY_ORIGIN = new Vector317();
14054
+ var TOOLTIP_RAY_FAR = new Vector317();
14055
+ var TOOLTIP_RAY_DIRECTION = new Vector317();
13658
14056
  var TOOLTIP_RAY = new Ray();
13659
14057
  var TOOLTIP_PLANE = new Plane();
13660
- var TOOLTIP_INTERSECTION = new Vector316();
13661
- var TOOLTIP_PLANE_NORMAL = new Vector316();
13662
- var TOOLTIP_PLANE_POINT = new Vector316();
14058
+ var TOOLTIP_INTERSECTION = new Vector317();
14059
+ var TOOLTIP_PLANE_NORMAL = new Vector317();
14060
+ var TOOLTIP_PLANE_POINT = new Vector317();
13663
14061
  var HOTSPOT_MODE_RENDERING = {
13664
14062
  surface: { orientation: "surface", placement: "surface" },
13665
14063
  billboard: { orientation: "billboard", placement: "floating" }
@@ -13704,7 +14102,7 @@ function createSurfaceQuaternion(position) {
13704
14102
  const inward = outward.clone().negate();
13705
14103
  const pitch = MathUtils9.degToRad(position.pitch);
13706
14104
  const yaw = MathUtils9.degToRad(position.yaw);
13707
- const localUp = new Vector316(
14105
+ const localUp = new Vector317(
13708
14106
  -Math.sin(pitch) * Math.sin(yaw),
13709
14107
  Math.cos(pitch),
13710
14108
  Math.sin(pitch) * Math.cos(yaw)
@@ -13955,24 +14353,24 @@ function HotspotAnchor({
13955
14353
  onPositionChange,
13956
14354
  onDragEnd
13957
14355
  }) {
13958
- const controlsRef = useContext25(PanoramaViewContext);
13959
- const hotspotTargetRegistry = useContext25(HotspotTargetRegistryContext);
13960
- const eventBus = useContext25(PanoEventBusContext);
14356
+ const controlsRef = useContext26(PanoramaViewContext);
14357
+ const hotspotTargetRegistry = useContext26(HotspotTargetRegistryContext);
14358
+ const eventBus = useContext26(PanoEventBusContext);
13961
14359
  const cursorApi = usePanoCursor();
13962
- const { camera, size } = useThree22();
13963
- const groupRef = useRef31(null);
13964
- const tooltipAnchorRef = useRef31(null);
13965
- const dragStateRef = useRef31(null);
13966
- const suppressNextClickRef = useRef31(false);
14360
+ const { camera, size } = useThree23();
14361
+ const groupRef = useRef32(null);
14362
+ const tooltipAnchorRef = useRef32(null);
14363
+ const dragStateRef = useRef32(null);
14364
+ const suppressNextClickRef = useRef32(false);
13967
14365
  const [hovered, setHovered] = useState16(false);
13968
14366
  const [dragging, setDragging] = useState16(false);
13969
14367
  const [pinned, setPinned] = useState16(false);
13970
- const tooltipContent = useMemo23(
14368
+ const tooltipContent = useMemo24(
13971
14369
  () => resolveHotspotTooltipContent(tooltip),
13972
14370
  [tooltip]
13973
14371
  );
13974
14372
  const normalizedPosition = normalizePanoPosition(position);
13975
- useEffect31(() => {
14373
+ useEffect32(() => {
13976
14374
  if (!hotspotTargetRegistry) {
13977
14375
  return;
13978
14376
  }
@@ -13989,17 +14387,17 @@ function HotspotAnchor({
13989
14387
  scaledWidth,
13990
14388
  scaledHeight
13991
14389
  );
13992
- const worldPosition = useMemo23(
14390
+ const worldPosition = useMemo24(
13993
14391
  () => panoPositionToVector3(normalizedPosition, resolvedDistance),
13994
14392
  [normalizedPosition.pitch, normalizedPosition.yaw, resolvedDistance]
13995
14393
  );
13996
- const surfaceQuaternion3 = useMemo23(
14394
+ const surfaceQuaternion3 = useMemo24(
13997
14395
  () => createSurfaceQuaternion(normalizedPosition),
13998
14396
  [normalizedPosition.pitch, normalizedPosition.yaw]
13999
14397
  );
14000
14398
  const worldWidth = angularSizeToWorldSize(scaledWidth, resolvedDistance);
14001
14399
  const worldHeight = angularSizeToWorldSize(scaledHeight, resolvedDistance);
14002
- const focusGeometry = useMemo23(() => {
14400
+ const focusGeometry = useMemo24(() => {
14003
14401
  const planeGeometry = new PlaneGeometry5(1, 1);
14004
14402
  const geometry = new EdgesGeometry(planeGeometry);
14005
14403
  planeGeometry.dispose();
@@ -14026,14 +14424,14 @@ function HotspotAnchor({
14026
14424
  });
14027
14425
  const tooltipOpen = visible && tooltipContent !== null && isTooltipOpen(tooltipTrigger, hovered, focused, pinned);
14028
14426
  const cursorClaimId = hotspotCursorClaimId(id);
14029
- useEffect31(
14427
+ useEffect32(
14030
14428
  () => () => {
14031
14429
  dragStateRef.current?.releaseInteractionLock();
14032
14430
  dragStateRef.current = null;
14033
14431
  },
14034
14432
  []
14035
14433
  );
14036
- useEffect31(() => {
14434
+ useEffect32(() => {
14037
14435
  if (!cursorApi) {
14038
14436
  return;
14039
14437
  }
@@ -14055,14 +14453,14 @@ function HotspotAnchor({
14055
14453
  hovered,
14056
14454
  visible
14057
14455
  ]);
14058
- useEffect31(
14456
+ useEffect32(
14059
14457
  () => () => {
14060
14458
  cursorApi?.release(cursorClaimId);
14061
14459
  },
14062
14460
  [cursorApi, cursorClaimId]
14063
14461
  );
14064
- useEffect31(() => () => focusGeometry.dispose(), [focusGeometry]);
14065
- useEffect31(() => {
14462
+ useEffect32(() => () => focusGeometry.dispose(), [focusGeometry]);
14463
+ useEffect32(() => {
14066
14464
  if (tooltipTrigger !== "click") {
14067
14465
  setPinned(false);
14068
14466
  return;
@@ -14071,12 +14469,12 @@ function HotspotAnchor({
14071
14469
  setPinned(false);
14072
14470
  });
14073
14471
  }, [eventBus, tooltipTrigger]);
14074
- useEffect31(() => {
14472
+ useEffect32(() => {
14075
14473
  if (tooltipTrigger !== "hover") {
14076
14474
  setHovered(false);
14077
14475
  }
14078
14476
  }, [tooltipTrigger]);
14079
- useEffect31(() => {
14477
+ useEffect32(() => {
14080
14478
  if (acceptsPointer) {
14081
14479
  return;
14082
14480
  }
@@ -14132,7 +14530,7 @@ function HotspotAnchor({
14132
14530
  worldHeight,
14133
14531
  worldWidth
14134
14532
  ]);
14135
- useFrame15((state) => {
14533
+ useFrame16((state) => {
14136
14534
  const group = groupRef.current;
14137
14535
  if (!group) {
14138
14536
  return;
@@ -14191,7 +14589,7 @@ function HotspotAnchor({
14191
14589
  setHovered(true);
14192
14590
  }
14193
14591
  };
14194
- return /* @__PURE__ */ jsxs17(
14592
+ return /* @__PURE__ */ jsxs18(
14195
14593
  "group",
14196
14594
  {
14197
14595
  ref: groupRef,
@@ -14268,18 +14666,18 @@ function HotspotAnchor({
14268
14666
  } : void 0,
14269
14667
  onPointerUp: acceptsPointer ? (event) => releasePointer(event, true) : void 0,
14270
14668
  children: [
14271
- focused ? focusContent ?? /* @__PURE__ */ jsx26(
14669
+ focused ? focusContent ?? /* @__PURE__ */ jsx27(
14272
14670
  "lineSegments",
14273
14671
  {
14274
14672
  geometry: focusGeometry,
14275
14673
  position: [0, 0, 0.01],
14276
14674
  renderOrder: renderOrder + 1,
14277
14675
  scale: [1.12, 1.12, 1],
14278
- children: /* @__PURE__ */ jsx26("lineBasicMaterial", { color: "#f5fbfc", depthTest: false })
14676
+ children: /* @__PURE__ */ jsx27("lineBasicMaterial", { color: "#f5fbfc", depthTest: false })
14279
14677
  }
14280
14678
  ) : null,
14281
14679
  children,
14282
- tooltipOpen && tooltipContent ? /* @__PURE__ */ jsx26("group", { ref: tooltipAnchorRef, children: /* @__PURE__ */ jsx26(
14680
+ tooltipOpen && tooltipContent ? /* @__PURE__ */ jsx27("group", { ref: tooltipAnchorRef, children: /* @__PURE__ */ jsx27(
14283
14681
  HotspotTooltip,
14284
14682
  {
14285
14683
  appearance: tooltipAppearance,
@@ -14296,11 +14694,11 @@ function HotspotAnchor({
14296
14694
  // src/hotspot/hotspot-plane.tsx
14297
14695
  import {
14298
14696
  DoubleSide as DoubleSide4,
14299
- Mesh as Mesh5,
14697
+ Mesh as Mesh6,
14300
14698
  MeshBasicMaterial,
14301
14699
  Vector2 as Vector26
14302
14700
  } from "three";
14303
- import { jsx as jsx27, jsxs as jsxs18 } from "react/jsx-runtime";
14701
+ import { jsx as jsx28, jsxs as jsxs19 } from "react/jsx-runtime";
14304
14702
  var HOTSPOT_ALPHA_CUTOFF = 0.05;
14305
14703
  var SAMPLE_UV = new Vector26();
14306
14704
  var RAYCAST_HITS = [];
@@ -14377,7 +14775,7 @@ function sampleTextureAlpha(texture, u, v) {
14377
14775
  function hotspotPlaneRaycast(raycaster, intersects2) {
14378
14776
  const material = Array.isArray(this.material) ? this.material[0] : this.material;
14379
14777
  if (!(material instanceof MeshBasicMaterial)) {
14380
- Mesh5.prototype.raycast.call(this, raycaster, intersects2);
14778
+ Mesh6.prototype.raycast.call(this, raycaster, intersects2);
14381
14779
  return;
14382
14780
  }
14383
14781
  const cutoff = Math.max(material.alphaTest, HOTSPOT_ALPHA_CUTOFF);
@@ -14385,7 +14783,7 @@ function hotspotPlaneRaycast(raycaster, intersects2) {
14385
14783
  return;
14386
14784
  }
14387
14785
  RAYCAST_HITS.length = 0;
14388
- Mesh5.prototype.raycast.call(this, raycaster, RAYCAST_HITS);
14786
+ Mesh6.prototype.raycast.call(this, raycaster, RAYCAST_HITS);
14389
14787
  const map = material.map;
14390
14788
  for (const hit of RAYCAST_HITS) {
14391
14789
  if (!map || !hit.uv) {
@@ -14402,9 +14800,9 @@ function HotspotPlane({
14402
14800
  map,
14403
14801
  opacity
14404
14802
  }) {
14405
- return /* @__PURE__ */ jsxs18("mesh", { raycast: hotspotPlaneRaycast, children: [
14406
- /* @__PURE__ */ jsx27("planeGeometry", { args: [1, 1] }),
14407
- /* @__PURE__ */ jsx27(
14803
+ return /* @__PURE__ */ jsxs19("mesh", { raycast: hotspotPlaneRaycast, children: [
14804
+ /* @__PURE__ */ jsx28("planeGeometry", { args: [1, 1] }),
14805
+ /* @__PURE__ */ jsx28(
14408
14806
  PanoBasicMaterial,
14409
14807
  {
14410
14808
  target: "hotspot",
@@ -14420,15 +14818,15 @@ function HotspotPlane({
14420
14818
  }
14421
14819
 
14422
14820
  // src/hotspot/image-hotspot.tsx
14423
- import { jsx as jsx28 } from "react/jsx-runtime";
14821
+ import { jsx as jsx29 } from "react/jsx-runtime";
14424
14822
  function useHotspotImageTexture(src, onLoad, onError) {
14425
- const gl = useThree23((state) => state.gl);
14823
+ const gl = useThree24((state) => state.gl);
14426
14824
  const [texture, setTexture] = useState17(null);
14427
- const onLoadRef = useRef32(onLoad);
14428
- const onErrorRef = useRef32(onError);
14825
+ const onLoadRef = useRef33(onLoad);
14826
+ const onErrorRef = useRef33(onError);
14429
14827
  onLoadRef.current = onLoad;
14430
14828
  onErrorRef.current = onError;
14431
- useEffect32(() => {
14829
+ useEffect33(() => {
14432
14830
  let active = true;
14433
14831
  setTexture(null);
14434
14832
  if (!src) {
@@ -14466,7 +14864,7 @@ function useHotspotImageTexture(src, onLoad, onError) {
14466
14864
  active = false;
14467
14865
  };
14468
14866
  }, [gl, src]);
14469
- useEffect32(
14867
+ useEffect33(
14470
14868
  () => () => {
14471
14869
  texture?.dispose();
14472
14870
  },
@@ -14484,11 +14882,11 @@ function ImageHotspot({
14484
14882
  ...anchorProps
14485
14883
  }) {
14486
14884
  const texture = useHotspotImageTexture(src, onLoad, onError);
14487
- return /* @__PURE__ */ jsx28(HotspotAnchor, { ...anchorProps, height, width, children: /* @__PURE__ */ jsx28(HotspotPlane, { map: texture, opacity }) });
14885
+ return /* @__PURE__ */ jsx29(HotspotAnchor, { ...anchorProps, height, width, children: /* @__PURE__ */ jsx29(HotspotPlane, { map: texture, opacity }) });
14488
14886
  }
14489
14887
 
14490
14888
  // src/hotspot/polygon-hotspot.tsx
14491
- import { useEffect as useEffect33, useMemo as useMemo24, useRef as useRef34 } from "react";
14889
+ import { useEffect as useEffect34, useMemo as useMemo25, useRef as useRef35 } from "react";
14492
14890
  import {
14493
14891
  BufferGeometry as BufferGeometry2,
14494
14892
  DoubleSide as DoubleSide5,
@@ -14497,20 +14895,20 @@ import {
14497
14895
  Quaternion as Quaternion5,
14498
14896
  ShapeUtils,
14499
14897
  Vector2 as Vector27,
14500
- Vector3 as Vector318
14898
+ Vector3 as Vector319
14501
14899
  } from "three";
14502
14900
 
14503
14901
  // src/hotspot/hotspot-stroke-line.tsx
14504
14902
  import { Line } from "@react-three/drei";
14505
- import { useFrame as useFrame16, useThree as useThree24 } from "@react-three/fiber";
14506
- import { useLayoutEffect as useLayoutEffect6, useRef as useRef33 } from "react";
14903
+ import { useFrame as useFrame17, useThree as useThree25 } from "@react-three/fiber";
14904
+ import { useLayoutEffect as useLayoutEffect6, useRef as useRef34 } from "react";
14507
14905
  import {
14508
14906
  MathUtils as MathUtils10,
14509
14907
  PerspectiveCamera as PerspectiveCamera7,
14510
- Vector3 as Vector317
14908
+ Vector3 as Vector318
14511
14909
  } from "three";
14512
- import { jsx as jsx29 } from "react/jsx-runtime";
14513
- var LINE_WORLD_POSITION = new Vector317();
14910
+ import { jsx as jsx30 } from "react/jsx-runtime";
14911
+ var LINE_WORLD_POSITION = new Vector318();
14514
14912
  function applyScreenSpaceDashScale(object, camera, viewportHeight) {
14515
14913
  const material = object?.material;
14516
14914
  if (!object || typeof material?.dashScale !== "number") {
@@ -14540,8 +14938,8 @@ function HotspotStrokeLine({
14540
14938
  dashSize,
14541
14939
  gapSize
14542
14940
  }) {
14543
- const lineRef = useRef33(null);
14544
- const { camera, size } = useThree24();
14941
+ const lineRef = useRef34(null);
14942
+ const { camera, size } = useThree25();
14545
14943
  const dash = resolveDash(dashSize, gapSize);
14546
14944
  useLayoutEffect6(() => {
14547
14945
  if (!dash.dashed) {
@@ -14549,13 +14947,13 @@ function HotspotStrokeLine({
14549
14947
  }
14550
14948
  applyScreenSpaceDashScale(lineRef.current, camera, size.height);
14551
14949
  }, [camera, dash.dashed, dash.dashSize, dash.gapSize, size.height]);
14552
- useFrame16((state) => {
14950
+ useFrame17((state) => {
14553
14951
  if (!dash.dashed) {
14554
14952
  return;
14555
14953
  }
14556
14954
  applyScreenSpaceDashScale(lineRef.current, state.camera, state.size.height);
14557
14955
  });
14558
- return /* @__PURE__ */ jsx29(
14956
+ return /* @__PURE__ */ jsx30(
14559
14957
  Line,
14560
14958
  {
14561
14959
  ref: lineRef,
@@ -14577,7 +14975,7 @@ function HotspotStrokeLine({
14577
14975
  }
14578
14976
 
14579
14977
  // src/hotspot/polygon-hotspot.tsx
14580
- import { jsx as jsx30, jsxs as jsxs19 } from "react/jsx-runtime";
14978
+ import { jsx as jsx31, jsxs as jsxs20 } from "react/jsx-runtime";
14581
14979
  var POLYGON_RADIUS = 990;
14582
14980
  var MAX_FILL_SEGMENT_DEGREES = 7;
14583
14981
  function cloneVertices(vertices) {
@@ -14649,7 +15047,7 @@ function polygonContainsDirection(vertices, direction) {
14649
15047
  }
14650
15048
  function fitsHemisphere(vertices) {
14651
15049
  const directions = vertices.map((vertex) => panoPositionToVector3(vertex).normalize());
14652
- const candidates = [new Vector318()];
15050
+ const candidates = [new Vector319()];
14653
15051
  for (const direction of directions) {
14654
15052
  candidates[0].add(direction);
14655
15053
  candidates.push(direction.clone());
@@ -14673,7 +15071,7 @@ function validatePolygonVertices(vertices) {
14673
15071
  if (hasSelfIntersection(unwrapped)) {
14674
15072
  issues.push({ code: "self_intersection", message: "Polygon edges cannot cross." });
14675
15073
  }
14676
- if (polygonContainsDirection(normalized, new Vector318(0, 1, 0)) || polygonContainsDirection(normalized, new Vector318(0, -1, 0))) {
15074
+ if (polygonContainsDirection(normalized, new Vector319(0, 1, 0)) || polygonContainsDirection(normalized, new Vector319(0, -1, 0))) {
14677
15075
  issues.push({ code: "contains_pole", message: "Polygons cannot contain a panorama pole." });
14678
15076
  }
14679
15077
  if (!fitsHemisphere(normalized)) {
@@ -14684,7 +15082,7 @@ function validatePolygonVertices(vertices) {
14684
15082
  function polygonCenter(vertices) {
14685
15083
  const sum = vertices.reduce(
14686
15084
  (total, vertex) => total.add(panoPositionToVector3(vertex).normalize()),
14687
- new Vector318()
15085
+ new Vector319()
14688
15086
  );
14689
15087
  return sum.lengthSq() > 1e-8 ? vector3ToPanoPosition(sum) : normalizePanoPosition(vertices[0]);
14690
15088
  }
@@ -14693,7 +15091,7 @@ function surfaceQuaternion(position) {
14693
15091
  const inward = outward.clone().negate();
14694
15092
  const pitch = position.pitch * Math.PI / 180;
14695
15093
  const yaw = position.yaw * Math.PI / 180;
14696
- const localUp = new Vector318(
15094
+ const localUp = new Vector319(
14697
15095
  -Math.sin(pitch) * Math.sin(yaw),
14698
15096
  Math.cos(pitch),
14699
15097
  Math.sin(pitch) * Math.cos(yaw)
@@ -14706,7 +15104,7 @@ function makeWorldToLocal(center) {
14706
15104
  return new Matrix45().compose(
14707
15105
  panoPositionToVector3(center, POLYGON_RADIUS),
14708
15106
  surfaceQuaternion(center),
14709
- new Vector318(1, 1, 1)
15107
+ new Vector319(1, 1, 1)
14710
15108
  ).invert();
14711
15109
  }
14712
15110
  function projectedPoint(a, b, c, weightB, weightC, radius, worldToLocal) {
@@ -14833,24 +15231,24 @@ function PolygonHotspot({
14833
15231
  onInvalid,
14834
15232
  ...anchorProps
14835
15233
  }) {
14836
- const issues = useMemo24(() => validatePolygonVertices(vertices), [vertices]);
15234
+ const issues = useMemo25(() => validatePolygonVertices(vertices), [vertices]);
14837
15235
  const valid = issues.length === 0;
14838
- const center = useMemo24(() => valid ? polygonCenter(vertices) : null, [valid, vertices]);
14839
- const fillGeometry = useMemo24(
15236
+ const center = useMemo25(() => valid ? polygonCenter(vertices) : null, [valid, vertices]);
15237
+ const fillGeometry = useMemo25(
14840
15238
  () => valid && center ? makeFillGeometry(vertices, center) : null,
14841
15239
  [center, valid, vertices]
14842
15240
  );
14843
- const strokePoints = useMemo24(
15241
+ const strokePoints = useMemo25(
14844
15242
  () => valid && center ? makeStrokePositions(vertices, center) : null,
14845
15243
  [center, valid, vertices]
14846
15244
  );
14847
15245
  const resolvedStrokeOpacity = Math.max(0, Math.min(strokeOpacity, 1));
14848
- const startVerticesRef = useRef34(null);
15246
+ const startVerticesRef = useRef35(null);
14849
15247
  const issuesKey = issues.map((issue) => issue.code).join(",");
14850
- useEffect33(() => {
15248
+ useEffect34(() => {
14851
15249
  if (!valid) onInvalid?.(issues);
14852
15250
  }, [issues, issuesKey, onInvalid, valid]);
14853
- useEffect33(() => () => fillGeometry?.dispose(), [fillGeometry]);
15251
+ useEffect34(() => () => fillGeometry?.dispose(), [fillGeometry]);
14854
15252
  if (!valid || !center || !fillGeometry || !strokePoints || strokePoints.length < 2) {
14855
15253
  return null;
14856
15254
  }
@@ -14865,7 +15263,7 @@ function PolygonHotspot({
14865
15263
  startPosition: event.startPosition
14866
15264
  });
14867
15265
  };
14868
- return /* @__PURE__ */ jsxs19(
15266
+ return /* @__PURE__ */ jsxs20(
14869
15267
  HotspotAnchor,
14870
15268
  {
14871
15269
  ...anchorProps,
@@ -14880,7 +15278,7 @@ function PolygonHotspot({
14880
15278
  draggable,
14881
15279
  interactive,
14882
15280
  useAngularScale: false,
14883
- focusContent: /* @__PURE__ */ jsx30(
15281
+ focusContent: /* @__PURE__ */ jsx31(
14884
15282
  HotspotStrokeLine,
14885
15283
  {
14886
15284
  color: "#75cbd3",
@@ -14902,7 +15300,7 @@ function PolygonHotspot({
14902
15300
  startVerticesRef.current = null;
14903
15301
  },
14904
15302
  children: [
14905
- /* @__PURE__ */ jsx30("mesh", { geometry: fillGeometry, renderOrder, children: /* @__PURE__ */ jsx30(
15303
+ /* @__PURE__ */ jsx31("mesh", { geometry: fillGeometry, renderOrder, children: /* @__PURE__ */ jsx31(
14906
15304
  "meshBasicMaterial",
14907
15305
  {
14908
15306
  color: fill,
@@ -14912,7 +15310,7 @@ function PolygonHotspot({
14912
15310
  transparent: true
14913
15311
  }
14914
15312
  ) }),
14915
- /* @__PURE__ */ jsx30(
15313
+ /* @__PURE__ */ jsx31(
14916
15314
  HotspotStrokeLine,
14917
15315
  {
14918
15316
  color: stroke,
@@ -14930,14 +15328,14 @@ function PolygonHotspot({
14930
15328
  }
14931
15329
 
14932
15330
  // src/hotspot/polyline-hotspot.tsx
14933
- import { useEffect as useEffect34, useMemo as useMemo25, useRef as useRef35 } from "react";
15331
+ import { useEffect as useEffect35, useMemo as useMemo26, useRef as useRef36 } from "react";
14934
15332
  import {
14935
15333
  MathUtils as MathUtils11,
14936
15334
  Matrix4 as Matrix46,
14937
15335
  Quaternion as Quaternion6,
14938
- Vector3 as Vector319
15336
+ Vector3 as Vector320
14939
15337
  } from "three";
14940
- import { jsx as jsx31 } from "react/jsx-runtime";
15338
+ import { jsx as jsx32 } from "react/jsx-runtime";
14941
15339
  var POLYLINE_RADIUS = 990;
14942
15340
  var MAX_SEGMENT_DEGREES = 7;
14943
15341
  function cloneVertices2(vertices) {
@@ -14962,7 +15360,7 @@ function unwrapVertices(vertices) {
14962
15360
  function polylineCenter(vertices) {
14963
15361
  const sum = vertices.reduce(
14964
15362
  (total, vertex) => total.add(panoPositionToVector3(vertex).normalize()),
14965
- new Vector319()
15363
+ new Vector320()
14966
15364
  );
14967
15365
  return sum.lengthSq() > 1e-8 ? vector3ToPanoPosition(sum) : normalizePanoPosition(vertices[0]);
14968
15366
  }
@@ -14971,7 +15369,7 @@ function surfaceQuaternion2(position) {
14971
15369
  const inward = outward.clone().negate();
14972
15370
  const pitch = MathUtils11.degToRad(position.pitch);
14973
15371
  const yaw = MathUtils11.degToRad(position.yaw);
14974
- const localUp = new Vector319(
15372
+ const localUp = new Vector320(
14975
15373
  -Math.sin(pitch) * Math.sin(yaw),
14976
15374
  Math.cos(pitch),
14977
15375
  Math.sin(pitch) * Math.cos(yaw)
@@ -14984,7 +15382,7 @@ function makeWorldToLocal2(center) {
14984
15382
  return new Matrix46().compose(
14985
15383
  panoPositionToVector3(center, POLYLINE_RADIUS),
14986
15384
  surfaceQuaternion2(center),
14987
- new Vector319(1, 1, 1)
15385
+ new Vector320(1, 1, 1)
14988
15386
  ).invert();
14989
15387
  }
14990
15388
  function subdivisionSteps(vertices) {
@@ -15054,16 +15452,16 @@ function PolylineHotspot({
15054
15452
  onInvalid,
15055
15453
  ...anchorProps
15056
15454
  }) {
15057
- const issues = useMemo25(() => validatePolylineVertices(vertices), [vertices]);
15455
+ const issues = useMemo26(() => validatePolylineVertices(vertices), [vertices]);
15058
15456
  const valid = issues.length === 0;
15059
- const center = useMemo25(() => valid ? polylineCenter(vertices) : null, [valid, vertices]);
15060
- const linePoints = useMemo25(
15457
+ const center = useMemo26(() => valid ? polylineCenter(vertices) : null, [valid, vertices]);
15458
+ const linePoints = useMemo26(
15061
15459
  () => valid && center ? makeLinePositions(vertices, center) : null,
15062
15460
  [center, valid, vertices]
15063
15461
  );
15064
15462
  const opacity = Math.max(0, Math.min(strokeOpacity, 1));
15065
- const startVerticesRef = useRef35(null);
15066
- useEffect34(() => {
15463
+ const startVerticesRef = useRef36(null);
15464
+ useEffect35(() => {
15067
15465
  if (!valid) onInvalid?.(issues);
15068
15466
  }, [issues, onInvalid, valid]);
15069
15467
  if (!valid || !center || !linePoints || linePoints.length < 2) return null;
@@ -15077,7 +15475,7 @@ function PolylineHotspot({
15077
15475
  startPosition: event.startPosition
15078
15476
  });
15079
15477
  };
15080
- return /* @__PURE__ */ jsx31(
15478
+ return /* @__PURE__ */ jsx32(
15081
15479
  HotspotAnchor,
15082
15480
  {
15083
15481
  ...anchorProps,
@@ -15091,7 +15489,7 @@ function PolylineHotspot({
15091
15489
  renderOrder,
15092
15490
  draggable,
15093
15491
  useAngularScale: false,
15094
- focusContent: /* @__PURE__ */ jsx31(
15492
+ focusContent: /* @__PURE__ */ jsx32(
15095
15493
  HotspotStrokeLine,
15096
15494
  {
15097
15495
  color: "#75cbd3",
@@ -15112,7 +15510,7 @@ function PolylineHotspot({
15112
15510
  emitVerticesChange(event, onDragEnd);
15113
15511
  startVerticesRef.current = null;
15114
15512
  },
15115
- children: /* @__PURE__ */ jsx31(
15513
+ children: /* @__PURE__ */ jsx32(
15116
15514
  HotspotStrokeLine,
15117
15515
  {
15118
15516
  color: stroke,
@@ -15129,7 +15527,7 @@ function PolylineHotspot({
15129
15527
  }
15130
15528
 
15131
15529
  // src/hotspot/graphic-hotspot.tsx
15132
- import { useEffect as useEffect35, useRef as useRef36, useState as useState18 } from "react";
15530
+ import { useEffect as useEffect36, useRef as useRef37, useState as useState18 } from "react";
15133
15531
  import {
15134
15532
  CanvasTexture,
15135
15533
  ClampToEdgeWrapping as ClampToEdgeWrapping4,
@@ -15137,7 +15535,7 @@ import {
15137
15535
  LinearMipmapLinearFilter as LinearMipmapLinearFilter4,
15138
15536
  SRGBColorSpace as SRGBColorSpace6
15139
15537
  } from "three";
15140
- import { jsx as jsx32 } from "react/jsx-runtime";
15538
+ import { jsx as jsx33 } from "react/jsx-runtime";
15141
15539
  var GRAPHIC_TEXTURE_SIZE = 512;
15142
15540
  function resolveStrokeWidth(value) {
15143
15541
  return Number.isFinite(value) ? Math.max(value, 0) : 8;
@@ -15327,11 +15725,11 @@ function createGraphicTexture(graphic, aspectWidth, aspectHeight) {
15327
15725
  }
15328
15726
  function useGraphicTexture(graphic, aspectWidth, aspectHeight, onLoad, onError) {
15329
15727
  const [texture, setTexture] = useState18(null);
15330
- const onLoadRef = useRef36(onLoad);
15331
- const onErrorRef = useRef36(onError);
15728
+ const onLoadRef = useRef37(onLoad);
15729
+ const onErrorRef = useRef37(onError);
15332
15730
  onLoadRef.current = onLoad;
15333
15731
  onErrorRef.current = onError;
15334
- useEffect35(() => {
15732
+ useEffect36(() => {
15335
15733
  let nextTexture = null;
15336
15734
  try {
15337
15735
  nextTexture = createGraphicTexture(graphic, aspectWidth, aspectHeight);
@@ -15357,20 +15755,20 @@ function CanvasGraphicHotspot({
15357
15755
  ...anchorProps
15358
15756
  }) {
15359
15757
  const texture = useGraphicTexture(graphic, width, height, onLoad, onError);
15360
- return /* @__PURE__ */ jsx32(HotspotAnchor, { ...anchorProps, height, width, children: /* @__PURE__ */ jsx32(HotspotPlane, { map: texture, opacity }) });
15758
+ return /* @__PURE__ */ jsx33(HotspotAnchor, { ...anchorProps, height, width, children: /* @__PURE__ */ jsx33(HotspotPlane, { map: texture, opacity }) });
15361
15759
  }
15362
15760
  function GraphicHotspot(props) {
15363
15761
  const { graphic, ...restProps } = props;
15364
15762
  if (graphic.kind === "svg") {
15365
15763
  const imageProps = restProps;
15366
- return /* @__PURE__ */ jsx32(ImageHotspot, { ...imageProps, src: graphic.src });
15764
+ return /* @__PURE__ */ jsx33(ImageHotspot, { ...imageProps, src: graphic.src });
15367
15765
  }
15368
- return /* @__PURE__ */ jsx32(CanvasGraphicHotspot, { ...restProps, graphic });
15766
+ return /* @__PURE__ */ jsx33(CanvasGraphicHotspot, { ...restProps, graphic });
15369
15767
  }
15370
15768
 
15371
15769
  // src/hotspot/sequence-hotspot.tsx
15372
- import { useFrame as useFrame17, useThree as useThree25 } from "@react-three/fiber";
15373
- import { useEffect as useEffect36, useRef as useRef37, useState as useState19 } from "react";
15770
+ import { useFrame as useFrame18, useThree as useThree26 } from "@react-three/fiber";
15771
+ import { useEffect as useEffect37, useRef as useRef38, useState as useState19 } from "react";
15374
15772
  import {
15375
15773
  ClampToEdgeWrapping as ClampToEdgeWrapping5,
15376
15774
  LinearFilter as LinearFilter8,
@@ -15378,7 +15776,7 @@ import {
15378
15776
  SRGBColorSpace as SRGBColorSpace7,
15379
15777
  TextureLoader as TextureLoader6
15380
15778
  } from "three";
15381
- import { jsx as jsx33 } from "react/jsx-runtime";
15779
+ import { jsx as jsx34 } from "react/jsx-runtime";
15382
15780
  var DEFAULT_SEQUENCE_FPS = 12;
15383
15781
  function resolveFps(value) {
15384
15782
  return Number.isFinite(value) && value > 0 ? value : DEFAULT_SEQUENCE_FPS;
@@ -15392,13 +15790,13 @@ function useSpriteTexture({
15392
15790
  onError,
15393
15791
  onLoadProgress
15394
15792
  }) {
15395
- const gl = useThree25((state) => state.gl);
15793
+ const gl = useThree26((state) => state.gl);
15396
15794
  const [texture, setTexture] = useState19(null);
15397
- const onErrorRef = useRef37(onError);
15398
- const onLoadProgressRef = useRef37(onLoadProgress);
15795
+ const onErrorRef = useRef38(onError);
15796
+ const onLoadProgressRef = useRef38(onLoadProgress);
15399
15797
  onErrorRef.current = onError;
15400
15798
  onLoadProgressRef.current = onLoadProgress;
15401
- useEffect36(() => {
15799
+ useEffect37(() => {
15402
15800
  let active = true;
15403
15801
  setTexture(null);
15404
15802
  if (!src) {
@@ -15439,7 +15837,7 @@ function useSpriteTexture({
15439
15837
  active = false;
15440
15838
  };
15441
15839
  }, [gl, id, src]);
15442
- useEffect36(
15840
+ useEffect37(
15443
15841
  () => () => {
15444
15842
  texture?.dispose();
15445
15843
  },
@@ -15469,23 +15867,23 @@ function SequenceHotspot({
15469
15867
  const frameCount = resolveFrameCount(requestedFrameCount);
15470
15868
  const safeFps = resolveFps(fps);
15471
15869
  const [frameIndex, setFrameIndex] = useState19(0);
15472
- const elapsedRef = useRef37(0);
15473
- const frameIndexRef = useRef37(0);
15474
- const endedRef = useRef37(false);
15475
- const lastPlaybackStateRef = useRef37(null);
15476
- const onFrameChangeRef = useRef37(onFrameChange);
15477
- const onPlaybackStateChangeRef = useRef37(onPlaybackStateChange);
15478
- const onEndedRef = useRef37(onEnded);
15870
+ const elapsedRef = useRef38(0);
15871
+ const frameIndexRef = useRef38(0);
15872
+ const endedRef = useRef38(false);
15873
+ const lastPlaybackStateRef = useRef38(null);
15874
+ const onFrameChangeRef = useRef38(onFrameChange);
15875
+ const onPlaybackStateChangeRef = useRef38(onPlaybackStateChange);
15876
+ const onEndedRef = useRef38(onEnded);
15479
15877
  onFrameChangeRef.current = onFrameChange;
15480
15878
  onPlaybackStateChangeRef.current = onPlaybackStateChange;
15481
15879
  onEndedRef.current = onEnded;
15482
- useEffect36(() => {
15880
+ useEffect37(() => {
15483
15881
  elapsedRef.current = 0;
15484
15882
  frameIndexRef.current = 0;
15485
15883
  endedRef.current = false;
15486
15884
  setFrameIndex(0);
15487
15885
  }, [frameCount, frameDirection, src]);
15488
- useEffect36(() => {
15886
+ useEffect37(() => {
15489
15887
  if (!texture) {
15490
15888
  return;
15491
15889
  }
@@ -15499,13 +15897,13 @@ function SequenceHotspot({
15499
15897
  );
15500
15898
  texture.needsUpdate = true;
15501
15899
  }, [frameCount, frameDirection, frameIndex, texture]);
15502
- useEffect36(() => {
15900
+ useEffect37(() => {
15503
15901
  if (!texture) {
15504
15902
  return;
15505
15903
  }
15506
15904
  onFrameChangeRef.current?.({ id, index: 0, src });
15507
15905
  }, [id, src, texture]);
15508
- useEffect36(() => {
15906
+ useEffect37(() => {
15509
15907
  if (!texture) {
15510
15908
  return;
15511
15909
  }
@@ -15524,7 +15922,7 @@ function SequenceHotspot({
15524
15922
  onPlaybackStateChangeRef.current?.(nextState);
15525
15923
  }
15526
15924
  }, [playing, texture]);
15527
- useFrame17((_, deltaSeconds) => {
15925
+ useFrame18((_, deltaSeconds) => {
15528
15926
  if (!texture || !playing || endedRef.current) {
15529
15927
  return;
15530
15928
  }
@@ -15554,12 +15952,12 @@ function SequenceHotspot({
15554
15952
  onFrameChangeRef.current?.({ id, index: nextIndex, src });
15555
15953
  }
15556
15954
  });
15557
- return /* @__PURE__ */ jsx33(HotspotAnchor, { ...anchorProps, id, height, width, children: /* @__PURE__ */ jsx33(HotspotPlane, { map: texture, opacity }) });
15955
+ return /* @__PURE__ */ jsx34(HotspotAnchor, { ...anchorProps, id, height, width, children: /* @__PURE__ */ jsx34(HotspotPlane, { map: texture, opacity }) });
15558
15956
  }
15559
15957
 
15560
15958
  // src/hotspot/video-hotspot.tsx
15561
- import { useThree as useThree26 } from "@react-three/fiber";
15562
- import { useEffect as useEffect37, useRef as useRef38, useState as useState20 } from "react";
15959
+ import { useThree as useThree27 } from "@react-three/fiber";
15960
+ import { useEffect as useEffect38, useRef as useRef39, useState as useState20 } from "react";
15563
15961
  import {
15564
15962
  ClampToEdgeWrapping as ClampToEdgeWrapping6,
15565
15963
  LinearFilter as LinearFilter9,
@@ -15568,7 +15966,7 @@ import {
15568
15966
  TextureLoader as TextureLoader7,
15569
15967
  VideoTexture as VideoTexture2
15570
15968
  } from "three";
15571
- import { jsx as jsx34 } from "react/jsx-runtime";
15969
+ import { jsx as jsx35 } from "react/jsx-runtime";
15572
15970
  function clampVolume2(volume) {
15573
15971
  if (!Number.isFinite(volume)) {
15574
15972
  return 1;
@@ -15576,11 +15974,11 @@ function clampVolume2(volume) {
15576
15974
  return Math.max(0, Math.min(volume, 1));
15577
15975
  }
15578
15976
  function usePosterTexture2(id, poster, onError) {
15579
- const gl = useThree26((state) => state.gl);
15977
+ const gl = useThree27((state) => state.gl);
15580
15978
  const [texture, setTexture] = useState20(null);
15581
- const onErrorRef = useRef38(onError);
15979
+ const onErrorRef = useRef39(onError);
15582
15980
  onErrorRef.current = onError;
15583
- useEffect37(() => {
15981
+ useEffect38(() => {
15584
15982
  let active = true;
15585
15983
  setTexture(null);
15586
15984
  if (!poster) {
@@ -15617,7 +16015,7 @@ function usePosterTexture2(id, poster, onError) {
15617
16015
  active = false;
15618
16016
  };
15619
16017
  }, [gl, id, poster]);
15620
- useEffect37(
16018
+ useEffect38(
15621
16019
  () => () => {
15622
16020
  texture?.dispose();
15623
16021
  },
@@ -15636,13 +16034,13 @@ function useVideoResource({
15636
16034
  src
15637
16035
  }) {
15638
16036
  const [resource, setResource] = useState20(null);
15639
- const onEndedRef = useRef38(onEnded);
15640
- const onErrorRef = useRef38(onError);
15641
- const onPlaybackStateChangeRef = useRef38(onPlaybackStateChange);
16037
+ const onEndedRef = useRef39(onEnded);
16038
+ const onErrorRef = useRef39(onError);
16039
+ const onPlaybackStateChangeRef = useRef39(onPlaybackStateChange);
15642
16040
  onEndedRef.current = onEnded;
15643
16041
  onErrorRef.current = onError;
15644
16042
  onPlaybackStateChangeRef.current = onPlaybackStateChange;
15645
- useEffect37(() => {
16043
+ useEffect38(() => {
15646
16044
  if (!src) {
15647
16045
  setResource(null);
15648
16046
  return;
@@ -15749,11 +16147,11 @@ function VideoHotspot({
15749
16147
  src
15750
16148
  });
15751
16149
  const posterTexture = usePosterTexture2(id, poster, onError);
15752
- const onPlaybackErrorRef = useRef38(onPlaybackError);
15753
- const onPlaybackStateChangeRef = useRef38(onPlaybackStateChange);
16150
+ const onPlaybackErrorRef = useRef39(onPlaybackError);
16151
+ const onPlaybackStateChangeRef = useRef39(onPlaybackStateChange);
15754
16152
  onPlaybackErrorRef.current = onPlaybackError;
15755
16153
  onPlaybackStateChangeRef.current = onPlaybackStateChange;
15756
- useEffect37(() => {
16154
+ useEffect38(() => {
15757
16155
  if (!resource) {
15758
16156
  return;
15759
16157
  }
@@ -15770,7 +16168,7 @@ function VideoHotspot({
15770
16168
  }
15771
16169
  resource.video.preload = preload;
15772
16170
  }, [loop, muted, playsInline, preload, resource, volume]);
15773
- useEffect37(() => {
16171
+ useEffect38(() => {
15774
16172
  if (!resource) {
15775
16173
  return;
15776
16174
  }
@@ -15793,12 +16191,12 @@ function VideoHotspot({
15793
16191
  };
15794
16192
  }, [playing, resource]);
15795
16193
  const activeTexture = resource?.ready ? resource.texture : posterTexture;
15796
- return /* @__PURE__ */ jsx34(HotspotAnchor, { ...anchorProps, id, height, width, children: /* @__PURE__ */ jsx34(HotspotPlane, { map: activeTexture, opacity }) });
16194
+ return /* @__PURE__ */ jsx35(HotspotAnchor, { ...anchorProps, id, height, width, children: /* @__PURE__ */ jsx35(HotspotPlane, { map: activeTexture, opacity }) });
15797
16195
  }
15798
16196
 
15799
16197
  // src/hotspot/audio-hotspot.tsx
15800
- import { useFrame as useFrame18, useThree as useThree27 } from "@react-three/fiber";
15801
- import { useEffect as useEffect38, useRef as useRef39, useState as useState21 } from "react";
16198
+ import { useFrame as useFrame19, useThree as useThree28 } from "@react-three/fiber";
16199
+ import { useEffect as useEffect39, useRef as useRef40, useState as useState21 } from "react";
15802
16200
  import {
15803
16201
  CanvasTexture as CanvasTexture2,
15804
16202
  ClampToEdgeWrapping as ClampToEdgeWrapping7,
@@ -15807,7 +16205,7 @@ import {
15807
16205
  SRGBColorSpace as SRGBColorSpace9,
15808
16206
  TextureLoader as TextureLoader8
15809
16207
  } from "three";
15810
- import { jsx as jsx35 } from "react/jsx-runtime";
16208
+ import { jsx as jsx36 } from "react/jsx-runtime";
15811
16209
  var SPEAKER_TEXTURE_SIZE = 512;
15812
16210
  function paintSpeakerBody(context, center) {
15813
16211
  context.fillStyle = "#f5fbfc";
@@ -15872,7 +16270,7 @@ function createSpeakerTexture(state) {
15872
16270
  }
15873
16271
  function useSpeakerTextures(enabled) {
15874
16272
  const [textures, setTextures] = useState21({ playing: null, stopped: null });
15875
- useEffect38(() => {
16273
+ useEffect39(() => {
15876
16274
  if (!enabled) {
15877
16275
  setTextures({ playing: null, stopped: null });
15878
16276
  return;
@@ -15888,11 +16286,11 @@ function useSpeakerTextures(enabled) {
15888
16286
  return textures;
15889
16287
  }
15890
16288
  function useIconTexture(icon, enabled, onError, id) {
15891
- const gl = useThree27((state) => state.gl);
16289
+ const gl = useThree28((state) => state.gl);
15892
16290
  const [texture, setTexture] = useState21(null);
15893
- const onErrorRef = useRef39(onError);
16291
+ const onErrorRef = useRef40(onError);
15894
16292
  onErrorRef.current = onError;
15895
- useEffect38(() => {
16293
+ useEffect39(() => {
15896
16294
  let active = true;
15897
16295
  setTexture(null);
15898
16296
  if (!enabled || !icon) {
@@ -15929,7 +16327,7 @@ function useIconTexture(icon, enabled, onError, id) {
15929
16327
  active = false;
15930
16328
  };
15931
16329
  }, [enabled, gl, icon, id]);
15932
- useEffect38(
16330
+ useEffect39(
15933
16331
  () => () => {
15934
16332
  texture?.dispose();
15935
16333
  },
@@ -15949,12 +16347,12 @@ function useAudioHowl({
15949
16347
  src
15950
16348
  }) {
15951
16349
  const [howl, setHowl] = useState21(null);
15952
- const playingRef = useRef39(playing);
15953
- const loopRef = useRef39(loop ?? false);
15954
- const onEndedRef = useRef39(onEnded);
15955
- const onErrorRef = useRef39(onError);
15956
- const onPlaybackErrorRef = useRef39(onPlaybackError);
15957
- const onPlaybackStateChangeRef = useRef39(onPlaybackStateChange);
16350
+ const playingRef = useRef40(playing);
16351
+ const loopRef = useRef40(loop ?? false);
16352
+ const onEndedRef = useRef40(onEnded);
16353
+ const onErrorRef = useRef40(onError);
16354
+ const onPlaybackErrorRef = useRef40(onPlaybackError);
16355
+ const onPlaybackStateChangeRef = useRef40(onPlaybackStateChange);
15958
16356
  playingRef.current = playing;
15959
16357
  loopRef.current = loop ?? false;
15960
16358
  onEndedRef.current = onEnded;
@@ -15962,7 +16360,7 @@ function useAudioHowl({
15962
16360
  onPlaybackErrorRef.current = onPlaybackError;
15963
16361
  onPlaybackStateChangeRef.current = onPlaybackStateChange;
15964
16362
  const sourcesKey = sourceList(src).join("\0");
15965
- useEffect38(() => {
16363
+ useEffect39(() => {
15966
16364
  const sources = sourcesKey.length > 0 ? sourcesKey.split("\0") : [];
15967
16365
  if (sources.length === 0) {
15968
16366
  setHowl(null);
@@ -15999,7 +16397,7 @@ function useAudioHowl({
15999
16397
  handle.dispose();
16000
16398
  };
16001
16399
  }, [crossOrigin, id, sourcesKey]);
16002
- useEffect38(() => {
16400
+ useEffect39(() => {
16003
16401
  howl?.loop(loop ?? false);
16004
16402
  }, [howl, loop]);
16005
16403
  return howl;
@@ -16027,7 +16425,7 @@ function AudioHotspot({
16027
16425
  ...anchorProps
16028
16426
  }) {
16029
16427
  usePanoMediaActivationIntent(playing);
16030
- const camera = useThree27((state) => state.camera);
16428
+ const camera = useThree28((state) => state.camera);
16031
16429
  const howl = useAudioHowl({
16032
16430
  crossOrigin,
16033
16431
  id,
@@ -16043,15 +16441,15 @@ function AudioHotspot({
16043
16441
  const stoppedIconTexture = useIconTexture(icon, marker, onError, id);
16044
16442
  const playingIconTexture = useIconTexture(playingIcon, marker, onError, id);
16045
16443
  const markerTexture = playing ? playingIconTexture ?? stoppedIconTexture ?? speakerTextures.playing : stoppedIconTexture ?? speakerTextures.stopped;
16046
- const playingRef = useRef39(playing);
16444
+ const playingRef = useRef40(playing);
16047
16445
  playingRef.current = playing;
16048
- const mutedRef = useRef39(muted);
16049
- const volumeRef = useRef39(volume);
16050
- const rangeRef = useRef39(range);
16446
+ const mutedRef = useRef40(muted);
16447
+ const volumeRef = useRef40(volume);
16448
+ const rangeRef = useRef40(range);
16051
16449
  mutedRef.current = muted;
16052
16450
  volumeRef.current = volume;
16053
16451
  rangeRef.current = range;
16054
- useEffect38(() => {
16452
+ useEffect39(() => {
16055
16453
  if (!howl) {
16056
16454
  return;
16057
16455
  }
@@ -16061,7 +16459,7 @@ function AudioHotspot({
16061
16459
  }
16062
16460
  howl.play();
16063
16461
  }, [howl, playing]);
16064
- useEffect38(() => {
16462
+ useEffect39(() => {
16065
16463
  if (!howl || !pauseWhenHidden) {
16066
16464
  return;
16067
16465
  }
@@ -16079,7 +16477,7 @@ function AudioHotspot({
16079
16477
  document.removeEventListener("visibilitychange", handleVisibility);
16080
16478
  };
16081
16479
  }, [howl, pauseWhenHidden]);
16082
- useFrame18(() => {
16480
+ useFrame19(() => {
16083
16481
  if (!howl) {
16084
16482
  return;
16085
16483
  }
@@ -16092,11 +16490,11 @@ function AudioHotspot({
16092
16490
  howl.mute(mutedRef.current);
16093
16491
  howl.volume(clampAudioVolume(volumeRef.current) * spatial.gain);
16094
16492
  });
16095
- return /* @__PURE__ */ jsx35(HotspotAnchor, { ...anchorProps, id, height, width, children: marker ? /* @__PURE__ */ jsx35(HotspotPlane, { map: markerTexture, opacity }) : null });
16493
+ return /* @__PURE__ */ jsx36(HotspotAnchor, { ...anchorProps, id, height, width, children: marker ? /* @__PURE__ */ jsx36(HotspotPlane, { map: markerTexture, opacity }) : null });
16096
16494
  }
16097
16495
 
16098
16496
  // src/hotspot/text-hotspot.tsx
16099
- import { useEffect as useEffect39, useRef as useRef40, useState as useState22 } from "react";
16497
+ import { useEffect as useEffect40, useRef as useRef41, useState as useState22 } from "react";
16100
16498
  import {
16101
16499
  CanvasTexture as CanvasTexture3,
16102
16500
  ClampToEdgeWrapping as ClampToEdgeWrapping8,
@@ -16104,7 +16502,7 @@ import {
16104
16502
  LinearMipmapLinearFilter as LinearMipmapLinearFilter8,
16105
16503
  SRGBColorSpace as SRGBColorSpace10
16106
16504
  } from "three";
16107
- import { jsx as jsx36 } from "react/jsx-runtime";
16505
+ import { jsx as jsx37 } from "react/jsx-runtime";
16108
16506
  var TEXT_TEXTURE_LONG_SIDE = 1024;
16109
16507
  var DEFAULT_FONT_FAMILY = "system-ui, sans-serif";
16110
16508
  var DEFAULT_FONT_SIZE = 96;
@@ -16325,11 +16723,11 @@ function createTextTexture(text, width, height, style) {
16325
16723
  }
16326
16724
  function useTextTexture(text, width, height, style, onLoad, onError) {
16327
16725
  const [texture, setTexture] = useState22(null);
16328
- const onLoadRef = useRef40(onLoad);
16329
- const onErrorRef = useRef40(onError);
16726
+ const onLoadRef = useRef41(onLoad);
16727
+ const onErrorRef = useRef41(onError);
16330
16728
  onLoadRef.current = onLoad;
16331
16729
  onErrorRef.current = onError;
16332
- useEffect39(() => {
16730
+ useEffect40(() => {
16333
16731
  let cancelled = false;
16334
16732
  let nextTexture = null;
16335
16733
  const run = async () => {
@@ -16422,13 +16820,13 @@ function TextHotspot({
16422
16820
  whiteSpace
16423
16821
  };
16424
16822
  const texture = useTextTexture(text, width, height, style, onLoad, onError);
16425
- return /* @__PURE__ */ jsx36(HotspotAnchor, { ...anchorProps, height, width, children: /* @__PURE__ */ jsx36(HotspotPlane, { map: texture, opacity }) });
16823
+ return /* @__PURE__ */ jsx37(HotspotAnchor, { ...anchorProps, height, width, children: /* @__PURE__ */ jsx37(HotspotPlane, { map: texture, opacity }) });
16426
16824
  }
16427
16825
 
16428
16826
  // src/hotspot/iframe-hotspot.tsx
16429
16827
  import { Html } from "@react-three/drei";
16430
16828
  import { DoubleSide as DoubleSide6 } from "three";
16431
- import { jsx as jsx37, jsxs as jsxs20 } from "react/jsx-runtime";
16829
+ import { jsx as jsx38, jsxs as jsxs21 } from "react/jsx-runtime";
16432
16830
  var IFRAME_LONG_SIDE = 800;
16433
16831
  var CSS3D_DISTANCE_FACTOR = 400;
16434
16832
  var DEFAULT_SANDBOX = "allow-scripts allow-popups allow-forms";
@@ -16485,7 +16883,7 @@ function IframeHotspot({
16485
16883
  interactive,
16486
16884
  pointerEvents
16487
16885
  );
16488
- return /* @__PURE__ */ jsxs20(
16886
+ return /* @__PURE__ */ jsxs21(
16489
16887
  HotspotAnchor,
16490
16888
  {
16491
16889
  ...anchorProps,
@@ -16494,9 +16892,9 @@ function IframeHotspot({
16494
16892
  pointerEvents,
16495
16893
  width,
16496
16894
  children: [
16497
- /* @__PURE__ */ jsxs20("mesh", { children: [
16498
- /* @__PURE__ */ jsx37("planeGeometry", { args: [1, 1] }),
16499
- /* @__PURE__ */ jsx37(
16895
+ /* @__PURE__ */ jsxs21("mesh", { children: [
16896
+ /* @__PURE__ */ jsx38("planeGeometry", { args: [1, 1] }),
16897
+ /* @__PURE__ */ jsx38(
16500
16898
  "meshBasicMaterial",
16501
16899
  {
16502
16900
  depthWrite: false,
@@ -16507,7 +16905,7 @@ function IframeHotspot({
16507
16905
  }
16508
16906
  )
16509
16907
  ] }),
16510
- /* @__PURE__ */ jsx37(
16908
+ /* @__PURE__ */ jsx38(
16511
16909
  Html,
16512
16910
  {
16513
16911
  distanceFactor: CSS3D_DISTANCE_FACTOR,
@@ -16522,7 +16920,7 @@ function IframeHotspot({
16522
16920
  },
16523
16921
  transform: true,
16524
16922
  zIndexRange: [10, 0],
16525
- children: /* @__PURE__ */ jsx37(
16923
+ children: /* @__PURE__ */ jsx38(
16526
16924
  "iframe",
16527
16925
  {
16528
16926
  allow,