@ericchen1990/pano-view 3.3.0 → 3.4.1

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
@@ -3404,7 +3404,9 @@ function KeyboardControls({
3404
3404
  return;
3405
3405
  }
3406
3406
  const previousTabIndex = element.getAttribute("tabindex");
3407
+ const previousOutline = element.style.outline;
3407
3408
  element.tabIndex = 0;
3409
+ element.style.outline = "none";
3408
3410
  const syncKeyboardActive = () => {
3409
3411
  let continuous = false;
3410
3412
  for (const action of pressedRef.current) {
@@ -3488,6 +3490,7 @@ function KeyboardControls({
3488
3490
  } else {
3489
3491
  element.setAttribute("tabindex", previousTabIndex);
3490
3492
  }
3493
+ element.style.outline = previousOutline;
3491
3494
  clearPressed();
3492
3495
  };
3493
3496
  }, [controlsRef, enabled, gl, keyMap]);
@@ -9988,6 +9991,27 @@ function PanoBasicMaterial({
9988
9991
  );
9989
9992
  }
9990
9993
 
9994
+ // src/scene-detail.tsx
9995
+ import { createContext as createContext15, useContext as useContext21 } from "react";
9996
+ var SceneDetailContext = createContext15(null);
9997
+ function useSceneDetailReporter() {
9998
+ return useContext21(SceneDetailContext);
9999
+ }
10000
+ function viewTilesAreDrawable(textures) {
10001
+ return textures.length > 0 && textures.every((texture) => texture != null);
10002
+ }
10003
+ function publishSceneDetail(reporter, lastToken, ready) {
10004
+ if (!reporter) {
10005
+ return;
10006
+ }
10007
+ const token = `${reporter.generation}:${ready ? 1 : 0}`;
10008
+ if (lastToken.current === token) {
10009
+ return;
10010
+ }
10011
+ lastToken.current = token;
10012
+ reporter.report(ready);
10013
+ }
10014
+
9991
10015
  // src/tile/texture-manager.ts
9992
10016
  import {
9993
10017
  ClampToEdgeWrapping,
@@ -10221,13 +10245,13 @@ var TileTextureManager = class {
10221
10245
  // src/tile/texture-manager-context.tsx
10222
10246
  import { useThree as useThree13 } from "@react-three/fiber";
10223
10247
  import {
10224
- createContext as createContext15,
10225
- useContext as useContext21,
10248
+ createContext as createContext16,
10249
+ useContext as useContext22,
10226
10250
  useEffect as useEffect21,
10227
10251
  useMemo as useMemo14
10228
10252
  } from "react";
10229
10253
  import { jsx as jsx15 } from "react/jsx-runtime";
10230
- var TileTextureManagerContext = createContext15(null);
10254
+ var TileTextureManagerContext = createContext16(null);
10231
10255
  function TileTextureManagerProvider({
10232
10256
  children,
10233
10257
  maxTextureMemoryMb = 128,
@@ -10251,7 +10275,7 @@ function TileTextureManagerProvider({
10251
10275
  return /* @__PURE__ */ jsx15(TileTextureManagerContext.Provider, { value: manager, children });
10252
10276
  }
10253
10277
  function useSharedTileTextureManager() {
10254
- return useContext21(TileTextureManagerContext);
10278
+ return useContext22(TileTextureManagerContext);
10255
10279
  }
10256
10280
 
10257
10281
  // src/tile/texture-hooks.ts
@@ -10468,6 +10492,15 @@ function preferredSphereLevel(levels, height, dpr, verticalFov) {
10468
10492
 
10469
10493
  // src/sphere-tile/sphere-tile.tsx
10470
10494
  import { jsx as jsx16, jsxs as jsxs9 } from "react/jsx-runtime";
10495
+ function sphereTileViewShouldRefresh(input) {
10496
+ if (input.loadModeChanged || input.managerChanged) {
10497
+ return true;
10498
+ }
10499
+ if (input.elapsedMs < 100 || input.viewUnchanged) {
10500
+ return false;
10501
+ }
10502
+ return true;
10503
+ }
10471
10504
  function SpherePatch({
10472
10505
  address,
10473
10506
  texture,
@@ -10627,6 +10660,11 @@ function SphereTileSource({
10627
10660
  []
10628
10661
  );
10629
10662
  const [layers, setLayers] = useState10([]);
10663
+ const detailReporter = useSceneDetailReporter();
10664
+ const detailReporterRef = useRef23(detailReporter);
10665
+ detailReporterRef.current = detailReporter;
10666
+ const detailTokenRef = useRef23("");
10667
+ const targetKeysRef = useRef23([]);
10630
10668
  const scratch = useMemo15(
10631
10669
  () => ({
10632
10670
  camera: new PerspectiveCamera3(),
@@ -10648,53 +10686,72 @@ function SphereTileSource({
10648
10686
  useFrame9(() => {
10649
10687
  if (!(camera instanceof PerspectiveCamera3)) return;
10650
10688
  const now = performance.now(), dpr = gl.getPixelRatio();
10651
- const reset = scratch.manager !== manager || scratch.loadMode !== loadMode;
10652
- 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))
10653
- return;
10654
- scratch.time = now;
10655
- scratch.fov = camera.fov;
10656
- scratch.width = size.width;
10657
- scratch.height = size.height;
10658
- scratch.dpr = dpr;
10659
- scratch.quaternion.copy(camera.quaternion);
10660
- scratch.manager = manager;
10661
- scratch.loadMode = loadMode;
10662
- scratch.camera.copy(camera, false);
10663
- scratch.camera.fov = Math.min(179, camera.fov + 8);
10664
- scratch.camera.updateProjectionMatrix();
10665
- scratch.camera.updateMatrixWorld();
10666
- scratch.matrix.multiplyMatrices(
10667
- scratch.camera.projectionMatrix,
10668
- scratch.camera.matrixWorldInverse
10669
- );
10670
- scratch.frustum.setFromProjectionMatrix(scratch.matrix);
10671
- let level = loadMode === "preview" ? -1 : loadMode === "base" ? 0 : preferredSphereLevel(config.levels, size.height, dpr, camera.fov);
10672
- const next = [];
10673
- let residentBytes = 0;
10674
- for (let index = 0; index <= level; index++) {
10675
- const addresses = candidates[index].filter(
10676
- ({ bounds }) => scratch.frustum.intersectsBox(bounds)
10677
- ).map(({ address }) => address);
10678
- const bytes = addresses.reduce(
10679
- (total, address) => total + address.width * address.height * 4,
10680
- 0
10689
+ const managerChanged = scratch.manager !== manager;
10690
+ const loadModeChanged = scratch.loadMode !== loadMode;
10691
+ const viewUnchanged = scratch.fov === camera.fov && scratch.width === size.width && scratch.height === size.height && scratch.dpr === dpr && scratch.quaternion.angleTo(camera.quaternion) < 1e-4;
10692
+ if (sphereTileViewShouldRefresh({
10693
+ loadModeChanged,
10694
+ managerChanged,
10695
+ elapsedMs: now - scratch.time,
10696
+ viewUnchanged
10697
+ })) {
10698
+ const reset = managerChanged || loadModeChanged;
10699
+ scratch.time = now;
10700
+ scratch.fov = camera.fov;
10701
+ scratch.width = size.width;
10702
+ scratch.height = size.height;
10703
+ scratch.dpr = dpr;
10704
+ scratch.quaternion.copy(camera.quaternion);
10705
+ scratch.manager = manager;
10706
+ scratch.loadMode = loadMode;
10707
+ scratch.camera.copy(camera, false);
10708
+ scratch.camera.fov = Math.min(179, camera.fov + 8);
10709
+ scratch.camera.updateProjectionMatrix();
10710
+ scratch.camera.updateMatrixWorld();
10711
+ scratch.matrix.multiplyMatrices(
10712
+ scratch.camera.projectionMatrix,
10713
+ scratch.camera.matrixWorldInverse
10681
10714
  );
10682
- if (residentBytes + bytes > budget) {
10683
- level = index - 1;
10684
- break;
10715
+ scratch.frustum.setFromProjectionMatrix(scratch.matrix);
10716
+ let level = loadMode === "preview" ? -1 : loadMode === "base" ? 0 : preferredSphereLevel(config.levels, size.height, dpr, camera.fov);
10717
+ const next = [];
10718
+ let residentBytes = 0;
10719
+ for (let index = 0; index <= level; index++) {
10720
+ const addresses = candidates[index].filter(
10721
+ ({ bounds }) => scratch.frustum.intersectsBox(bounds)
10722
+ ).map(({ address }) => address);
10723
+ const bytes = addresses.reduce(
10724
+ (total, address) => total + address.width * address.height * 4,
10725
+ 0
10726
+ );
10727
+ if (residentBytes + bytes > budget) {
10728
+ level = index - 1;
10729
+ break;
10730
+ }
10731
+ residentBytes += bytes;
10732
+ next.push({ level: index, addresses });
10733
+ }
10734
+ const targetLayer = loadMode === "full" ? next[next.length - 1] : void 0;
10735
+ targetKeysRef.current = targetLayer ? targetLayer.addresses.map(
10736
+ (address) => `${resolveUrl(address)}\0${sphereTileKey(address)}`
10737
+ ) : [];
10738
+ if (level !== scratch.level) {
10739
+ scratch.level = level;
10740
+ if (level >= 0) callbacks.current.onLevelChange?.(level);
10741
+ }
10742
+ const token = next.map((layer) => layer.addresses.map(sphereTileKey).join(",")).join(";");
10743
+ if (token !== scratch.token || reset) {
10744
+ scratch.token = token;
10745
+ setLayers(next);
10685
10746
  }
10686
- residentBytes += bytes;
10687
- next.push({ level: index, addresses });
10688
- }
10689
- if (level !== scratch.level) {
10690
- scratch.level = level;
10691
- if (level >= 0) callbacks.current.onLevelChange?.(level);
10692
- }
10693
- const token = next.map((layer) => layer.addresses.map(sphereTileKey).join(",")).join(";");
10694
- if (token !== scratch.token || reset) {
10695
- scratch.token = token;
10696
- setLayers(next);
10697
10747
  }
10748
+ publishSceneDetail(
10749
+ detailReporterRef.current,
10750
+ detailTokenRef,
10751
+ loadMode === "full" && viewTilesAreDrawable(
10752
+ targetKeysRef.current.map((key) => manager.getSnapshot(key).texture)
10753
+ )
10754
+ );
10698
10755
  });
10699
10756
  return /* @__PURE__ */ jsxs9("group", { visible, children: [
10700
10757
  preview ? /* @__PURE__ */ jsx16(
@@ -10826,9 +10883,19 @@ function Sphere({
10826
10883
  );
10827
10884
  const displayTexture = texture ?? previewTexture;
10828
10885
  const readyRef = useRef24(false);
10886
+ const detailReporter = useSceneDetailReporter();
10829
10887
  useEffect24(() => {
10830
10888
  readyRef.current = false;
10831
10889
  }, [resolvedPreviewUrl, src]);
10890
+ useEffect24(() => {
10891
+ if (!detailReporter) {
10892
+ return;
10893
+ }
10894
+ detailReporter.report(texture != null);
10895
+ return () => {
10896
+ detailReporter.report(false);
10897
+ };
10898
+ }, [detailReporter, texture]);
10832
10899
  useEffect24(() => {
10833
10900
  if (!displayTexture || readyRef.current) {
10834
10901
  return;
@@ -10863,7 +10930,7 @@ function Sphere({
10863
10930
  import { useThree as useThree16 } from "@react-three/fiber";
10864
10931
  import {
10865
10932
  useCallback as useCallback10,
10866
- useContext as useContext22,
10933
+ useContext as useContext23,
10867
10934
  useEffect as useEffect25,
10868
10935
  useLayoutEffect as useLayoutEffect3,
10869
10936
  useMemo as useMemo17,
@@ -11064,8 +11131,8 @@ function PanoVideo({
11064
11131
  }) {
11065
11132
  usePanoMediaActivationIntent(autoPlay);
11066
11133
  const gl = useThree16((state) => state.gl);
11067
- const host = useContext22(PanoVideoHostContext);
11068
- const overlay = useContext22(PanoChromeOverlayContext);
11134
+ const host = useContext23(PanoVideoHostContext);
11135
+ const overlay = useContext23(PanoChromeOverlayContext);
11069
11136
  const variants = useMemo17(
11070
11137
  () => resolvePanoVideoVariants({ poster, src, variants: variantsProp }),
11071
11138
  [poster, src, variantsProp]
@@ -11620,14 +11687,14 @@ function PanoVideo({
11620
11687
  }
11621
11688
 
11622
11689
  // src/scenes.tsx
11623
- import { useFrame as useFrame13, useThree as useThree20 } from "@react-three/fiber";
11690
+ import { useFrame as useFrame14, useThree as useThree21 } from "@react-three/fiber";
11624
11691
  import {
11625
11692
  Fragment as Fragment6,
11626
11693
  useCallback as useCallback11,
11627
- useContext as useContext23,
11628
- useEffect as useEffect29,
11629
- useMemo as useMemo21,
11630
- useRef as useRef29,
11694
+ useContext as useContext24,
11695
+ useEffect as useEffect30,
11696
+ useMemo as useMemo22,
11697
+ useRef as useRef30,
11631
11698
  useState as useState14
11632
11699
  } from "react";
11633
11700
  import {
@@ -11682,18 +11749,34 @@ function isSnapshotTransition(preset) {
11682
11749
  return preset !== "none" && preset !== "particles";
11683
11750
  }
11684
11751
 
11685
- // src/scene-transitions/particle-overlay.tsx
11752
+ // src/scene-transitions/snapshot-hold.tsx
11686
11753
  import { useFrame as useFrame10, useThree as useThree17 } from "@react-three/fiber";
11687
11754
  import { useEffect as useEffect26, useMemo as useMemo18, useRef as useRef26 } from "react";
11688
- import {
11689
- DoubleSide as DoubleSide2,
11690
- InstancedBufferAttribute,
11691
- InstancedBufferGeometry,
11692
- PlaneGeometry as PlaneGeometry3,
11693
- ShaderMaterial as ShaderMaterial2,
11694
- Vector2 as Vector24,
11695
- Vector3 as Vector310
11696
- } from "three";
11755
+ import { Vector3 as Vector310 } from "three";
11756
+
11757
+ // src/scene-transitions/overlay-utils.ts
11758
+ import { PlaneGeometry as PlaneGeometry2 } from "three";
11759
+ var OVERLAY_RENDER_ORDER = 1e4;
11760
+ var FULLSCREEN_PLANE = new PlaneGeometry2(1, 1);
11761
+ function isPerspectiveCamera(camera) {
11762
+ return camera.isPerspectiveCamera === true;
11763
+ }
11764
+ function placeFullscreenOverlay(mesh, camera, direction) {
11765
+ const distance = Math.max(camera.near * 1.1, 0.11);
11766
+ camera.getWorldDirection(direction);
11767
+ mesh.position.copy(camera.position).addScaledVector(direction, distance);
11768
+ mesh.quaternion.copy(camera.quaternion);
11769
+ const height = 2 * distance * Math.tan(camera.fov * Math.PI / 360);
11770
+ mesh.scale.set(height * camera.aspect, height, 1);
11771
+ }
11772
+ function overlayProgress(elapsedTime, duration, startTime) {
11773
+ const started = startTime ?? elapsedTime;
11774
+ const progress = duration === 0 ? 1 : Math.min(1, (elapsedTime - started) / duration);
11775
+ return { startTime: started, progress };
11776
+ }
11777
+
11778
+ // src/scene-transitions/snapshot-shaders.ts
11779
+ import { DoubleSide as DoubleSide2, ShaderMaterial as ShaderMaterial2, Vector2 as Vector24 } from "three";
11697
11780
 
11698
11781
  // src/scene-transitions/glsl.ts
11699
11782
  var GLSL_COMMON = `
@@ -11725,169 +11808,7 @@ float fbm(vec2 p) {
11725
11808
  }
11726
11809
  `;
11727
11810
 
11728
- // src/scene-transitions/overlay-utils.ts
11729
- import { PlaneGeometry as PlaneGeometry2 } from "three";
11730
- var OVERLAY_RENDER_ORDER = 1e4;
11731
- var FULLSCREEN_PLANE = new PlaneGeometry2(1, 1);
11732
- function isPerspectiveCamera(camera) {
11733
- return camera.isPerspectiveCamera === true;
11734
- }
11735
- function placeFullscreenOverlay(mesh, camera, direction) {
11736
- const distance = Math.max(camera.near * 1.1, 0.11);
11737
- camera.getWorldDirection(direction);
11738
- mesh.position.copy(camera.position).addScaledVector(direction, distance);
11739
- mesh.quaternion.copy(camera.quaternion);
11740
- const height = 2 * distance * Math.tan(camera.fov * Math.PI / 360);
11741
- mesh.scale.set(height * camera.aspect, height, 1);
11742
- }
11743
- function overlayProgress(elapsedTime, duration, startTime) {
11744
- const started = startTime ?? elapsedTime;
11745
- const progress = duration === 0 ? 1 : Math.min(1, (elapsedTime - started) / duration);
11746
- return { startTime: started, progress };
11747
- }
11748
-
11749
- // src/scene-transitions/particle-overlay.tsx
11750
- import { jsx as jsx19 } from "react/jsx-runtime";
11751
- var PARTICLE_GRID = 48;
11752
- var PARTICLE_COUNT = PARTICLE_GRID * PARTICLE_GRID;
11753
- var PARTICLE_VERTEX_SHADER = `
11754
- attribute float instanceIndex;
11755
- uniform float progress;
11756
- uniform vec2 grid;
11757
- varying vec2 vUv;
11758
- varying float vAlpha;
11759
- ${GLSL_COMMON}
11760
-
11761
- void main() {
11762
- float id = instanceIndex;
11763
- float gx = mod(id, grid.x);
11764
- float gy = floor(id / grid.x);
11765
- vec2 cell = vec2(gx, gy);
11766
- float h = hash(cell);
11767
- float h2 = hash(cell + 19.2);
11768
- float h3 = hash(cell + 7.7);
11769
- vec2 randomDir = normalize(vec2(h, h2) * 2.0 - 1.0 + 1e-5);
11770
- vec2 fromCenter = (cell + 0.5) / grid - 0.5 + 1e-5;
11771
- vec2 dir = normalize(mix(randomDir, normalize(fromCenter), 0.65));
11772
- float delay = h3 * 0.28;
11773
- float lt = clamp((progress - delay) / max(1.0 - delay, 0.001), 0.0, 1.0);
11774
- float explode = lt * lt;
11775
- float scale = mix(1.0, 0.18, explode);
11776
- float angle = (h * 2.0 - 1.0) * explode * 4.2;
11777
- float ca = cos(angle);
11778
- float sa = sin(angle);
11779
- vec2 cellSize = 1.0 / grid;
11780
- vec2 local = position.xy * cellSize * scale;
11781
- vec2 rotated = vec2(local.x * ca - local.y * sa, local.x * sa + local.y * ca);
11782
- vec2 planeCenter = (cell + 0.5) / grid - 0.5;
11783
- vec2 exploded = planeCenter + dir * explode * 0.9;
11784
- vec3 pos = vec3(exploded + rotated, -explode * 0.14);
11785
- vUv = (cell + uv) / grid;
11786
- vAlpha = 1.0 - explode;
11787
- gl_Position = projectionMatrix * modelViewMatrix * vec4(pos, 1.0);
11788
- }
11789
- `;
11790
- var PARTICLE_FRAGMENT_SHADER = `
11791
- uniform sampler2D map;
11792
- varying vec2 vUv;
11793
- varying float vAlpha;
11794
-
11795
- void main() {
11796
- vec4 old = texture2D(map, vUv);
11797
- old.rgb *= 1.0 + 0.22 * (1.0 - vAlpha);
11798
- gl_FragColor = vec4(old.rgb, old.a * vAlpha);
11799
- #include <colorspace_fragment>
11800
- }
11801
- `;
11802
- function createParticleGeometry() {
11803
- const quad = new PlaneGeometry3(1, 1);
11804
- const geometry = new InstancedBufferGeometry();
11805
- if (quad.index) {
11806
- geometry.setIndex(quad.index.clone());
11807
- }
11808
- geometry.setAttribute("position", quad.attributes.position.clone());
11809
- geometry.setAttribute("uv", quad.attributes.uv.clone());
11810
- const indexes = new Float32Array(PARTICLE_COUNT);
11811
- for (let i = 0; i < PARTICLE_COUNT; i += 1) {
11812
- indexes[i] = i;
11813
- }
11814
- geometry.setAttribute("instanceIndex", new InstancedBufferAttribute(indexes, 1));
11815
- geometry.instanceCount = PARTICLE_COUNT;
11816
- quad.dispose();
11817
- return geometry;
11818
- }
11819
- function ParticleOverlay({
11820
- snapshot,
11821
- transition,
11822
- running,
11823
- runId,
11824
- onFinish
11825
- }) {
11826
- const { camera } = useThree17();
11827
- const meshRef = useRef26(null);
11828
- const startRef = useRef26(null);
11829
- const finishedRef = useRef26(false);
11830
- const directionRef = useRef26(new Vector310());
11831
- const geometry = useMemo18(() => createParticleGeometry(), []);
11832
- const material = useMemo18(
11833
- () => new ShaderMaterial2({
11834
- transparent: true,
11835
- depthTest: false,
11836
- depthWrite: false,
11837
- side: DoubleSide2,
11838
- uniforms: {
11839
- map: { value: snapshot.texture },
11840
- progress: { value: 0 },
11841
- grid: { value: new Vector24(PARTICLE_GRID, PARTICLE_GRID) }
11842
- },
11843
- vertexShader: PARTICLE_VERTEX_SHADER,
11844
- fragmentShader: PARTICLE_FRAGMENT_SHADER
11845
- }),
11846
- [snapshot.texture]
11847
- );
11848
- useEffect26(() => () => geometry.dispose(), [geometry]);
11849
- useEffect26(() => () => material.dispose(), [material]);
11850
- useEffect26(() => {
11851
- startRef.current = null;
11852
- finishedRef.current = false;
11853
- material.uniforms.progress.value = 0;
11854
- }, [material, runId]);
11855
- useFrame10((state) => {
11856
- const mesh = meshRef.current;
11857
- if (!mesh || !isPerspectiveCamera(camera)) {
11858
- return;
11859
- }
11860
- placeFullscreenOverlay(mesh, camera, directionRef.current);
11861
- if (!running || finishedRef.current) {
11862
- return;
11863
- }
11864
- const next = overlayProgress(state.clock.elapsedTime, transition.duration, startRef.current);
11865
- startRef.current = next.startTime;
11866
- material.uniforms.progress.value = next.progress;
11867
- if (next.progress === 1) {
11868
- finishedRef.current = true;
11869
- onFinish();
11870
- }
11871
- });
11872
- return /* @__PURE__ */ jsx19(
11873
- "mesh",
11874
- {
11875
- ref: meshRef,
11876
- frustumCulled: false,
11877
- geometry,
11878
- material,
11879
- renderOrder: OVERLAY_RENDER_ORDER
11880
- }
11881
- );
11882
- }
11883
-
11884
- // src/scene-transitions/snapshot-overlay.tsx
11885
- import { useFrame as useFrame11, useThree as useThree18 } from "@react-three/fiber";
11886
- import { useEffect as useEffect27, useMemo as useMemo19, useRef as useRef27 } from "react";
11887
- import { Vector3 as Vector311 } from "three";
11888
-
11889
11811
  // src/scene-transitions/snapshot-shaders.ts
11890
- import { DoubleSide as DoubleSide3, ShaderMaterial as ShaderMaterial3, Vector2 as Vector25 } from "three";
11891
11812
  var SNAPSHOT_VERTEX_SHADER = `
11892
11813
  varying vec2 vUv;
11893
11814
  void main() {
@@ -12147,50 +12068,285 @@ var SNAPSHOT_FRAGMENT_SHADERS = {
12147
12068
  `)
12148
12069
  };
12149
12070
  function createSnapshotMaterial(preset, texture) {
12150
- return new ShaderMaterial3({
12071
+ return new ShaderMaterial2({
12151
12072
  transparent: true,
12152
12073
  depthTest: false,
12153
12074
  depthWrite: false,
12154
- side: DoubleSide3,
12075
+ side: DoubleSide2,
12155
12076
  uniforms: {
12156
12077
  map: { value: texture },
12157
12078
  progress: { value: 0 },
12158
- resolution: { value: new Vector25(1, 1) }
12079
+ resolution: { value: new Vector24(1, 1) }
12159
12080
  },
12160
12081
  vertexShader: SNAPSHOT_VERTEX_SHADER,
12161
12082
  fragmentShader: SNAPSHOT_FRAGMENT_SHADERS[preset]
12162
12083
  });
12163
12084
  }
12164
12085
 
12165
- // src/scene-transitions/snapshot-overlay.tsx
12166
- import { jsx as jsx20, jsxs as jsxs12 } from "react/jsx-runtime";
12167
- function SnapshotOverlay({
12086
+ // src/scene-transitions/snapshot-hold.tsx
12087
+ import { jsx as jsx19, jsxs as jsxs12 } from "react/jsx-runtime";
12088
+ function SnapshotHold({ snapshot }) {
12089
+ const { camera, gl } = useThree17();
12090
+ const meshRef = useRef26(null);
12091
+ const directionRef = useRef26(new Vector310());
12092
+ const material = useMemo18(
12093
+ () => createSnapshotMaterial("crossfade", snapshot.texture),
12094
+ [snapshot.texture]
12095
+ );
12096
+ useEffect26(() => () => material.dispose(), [material]);
12097
+ useFrame10(() => {
12098
+ const mesh = meshRef.current;
12099
+ if (!mesh || !isPerspectiveCamera(camera)) {
12100
+ return;
12101
+ }
12102
+ placeFullscreenOverlay(mesh, camera, directionRef.current);
12103
+ const context = gl.getContext();
12104
+ material.uniforms.resolution.value.set(
12105
+ context.drawingBufferWidth,
12106
+ context.drawingBufferHeight
12107
+ );
12108
+ material.uniforms.progress.value = 0;
12109
+ });
12110
+ return /* @__PURE__ */ jsxs12("mesh", { frustumCulled: false, ref: meshRef, renderOrder: OVERLAY_RENDER_ORDER, children: [
12111
+ /* @__PURE__ */ jsx19("primitive", { attach: "geometry", object: FULLSCREEN_PLANE }),
12112
+ /* @__PURE__ */ jsx19("primitive", { attach: "material", object: material })
12113
+ ] });
12114
+ }
12115
+
12116
+ // src/scene-transition-policy.ts
12117
+ function pendingSceneUsesBaseLayer(phase, isPending) {
12118
+ return isPending && (phase === "preloading" || phase === "capturing");
12119
+ }
12120
+ function normalizeTransitionWaitMs(value) {
12121
+ if (typeof value !== "number" || !Number.isFinite(value) || value <= 0) {
12122
+ return 0;
12123
+ }
12124
+ return value;
12125
+ }
12126
+ function planDetailHold(input) {
12127
+ if (input.waitMs <= 0) {
12128
+ return null;
12129
+ }
12130
+ return {
12131
+ generation: input.generation,
12132
+ sceneId: input.sceneId,
12133
+ deadline: input.now + input.waitMs
12134
+ };
12135
+ }
12136
+ function acceptDetailWait(wait, signal) {
12137
+ if (!wait) {
12138
+ return { wait: null, start: false };
12139
+ }
12140
+ switch (signal.kind) {
12141
+ case "ready":
12142
+ if (signal.generation !== wait.generation || signal.sceneId !== wait.sceneId) {
12143
+ return { wait, start: false };
12144
+ }
12145
+ return { wait: null, start: true };
12146
+ case "timeout":
12147
+ if (signal.generation !== wait.generation || signal.now < wait.deadline) {
12148
+ return { wait, start: false };
12149
+ }
12150
+ return { wait: null, start: true };
12151
+ case "cancel":
12152
+ if (signal.generation !== wait.generation) {
12153
+ return { wait, start: false };
12154
+ }
12155
+ return { wait: null, start: false };
12156
+ default: {
12157
+ const exhaustive = signal;
12158
+ return exhaustive;
12159
+ }
12160
+ }
12161
+ }
12162
+ function phaseAfterSnapshot(preset, hold) {
12163
+ if (hold) {
12164
+ return "awaitingDetail";
12165
+ }
12166
+ if (preset === "none") {
12167
+ return "idle";
12168
+ }
12169
+ return "transitioning";
12170
+ }
12171
+
12172
+ // src/scene-transitions/particle-overlay.tsx
12173
+ import { useFrame as useFrame11, useThree as useThree18 } from "@react-three/fiber";
12174
+ import { useEffect as useEffect27, useMemo as useMemo19, useRef as useRef27 } from "react";
12175
+ import {
12176
+ DoubleSide as DoubleSide3,
12177
+ InstancedBufferAttribute,
12178
+ InstancedBufferGeometry,
12179
+ PlaneGeometry as PlaneGeometry3,
12180
+ ShaderMaterial as ShaderMaterial3,
12181
+ Vector2 as Vector25,
12182
+ Vector3 as Vector311
12183
+ } from "three";
12184
+ import { jsx as jsx20 } from "react/jsx-runtime";
12185
+ var PARTICLE_GRID = 48;
12186
+ var PARTICLE_COUNT = PARTICLE_GRID * PARTICLE_GRID;
12187
+ var PARTICLE_VERTEX_SHADER = `
12188
+ attribute float instanceIndex;
12189
+ uniform float progress;
12190
+ uniform vec2 grid;
12191
+ varying vec2 vUv;
12192
+ varying float vAlpha;
12193
+ ${GLSL_COMMON}
12194
+
12195
+ void main() {
12196
+ float id = instanceIndex;
12197
+ float gx = mod(id, grid.x);
12198
+ float gy = floor(id / grid.x);
12199
+ vec2 cell = vec2(gx, gy);
12200
+ float h = hash(cell);
12201
+ float h2 = hash(cell + 19.2);
12202
+ float h3 = hash(cell + 7.7);
12203
+ vec2 randomDir = normalize(vec2(h, h2) * 2.0 - 1.0 + 1e-5);
12204
+ vec2 fromCenter = (cell + 0.5) / grid - 0.5 + 1e-5;
12205
+ vec2 dir = normalize(mix(randomDir, normalize(fromCenter), 0.65));
12206
+ float delay = h3 * 0.28;
12207
+ float lt = clamp((progress - delay) / max(1.0 - delay, 0.001), 0.0, 1.0);
12208
+ float explode = lt * lt;
12209
+ float scale = mix(1.0, 0.18, explode);
12210
+ float angle = (h * 2.0 - 1.0) * explode * 4.2;
12211
+ float ca = cos(angle);
12212
+ float sa = sin(angle);
12213
+ vec2 cellSize = 1.0 / grid;
12214
+ vec2 local = position.xy * cellSize * scale;
12215
+ vec2 rotated = vec2(local.x * ca - local.y * sa, local.x * sa + local.y * ca);
12216
+ vec2 planeCenter = (cell + 0.5) / grid - 0.5;
12217
+ vec2 exploded = planeCenter + dir * explode * 0.9;
12218
+ vec3 pos = vec3(exploded + rotated, -explode * 0.14);
12219
+ vUv = (cell + uv) / grid;
12220
+ vAlpha = 1.0 - explode;
12221
+ gl_Position = projectionMatrix * modelViewMatrix * vec4(pos, 1.0);
12222
+ }
12223
+ `;
12224
+ var PARTICLE_FRAGMENT_SHADER = `
12225
+ uniform sampler2D map;
12226
+ varying vec2 vUv;
12227
+ varying float vAlpha;
12228
+
12229
+ void main() {
12230
+ vec4 old = texture2D(map, vUv);
12231
+ old.rgb *= 1.0 + 0.22 * (1.0 - vAlpha);
12232
+ gl_FragColor = vec4(old.rgb, old.a * vAlpha);
12233
+ #include <colorspace_fragment>
12234
+ }
12235
+ `;
12236
+ function createParticleGeometry() {
12237
+ const quad = new PlaneGeometry3(1, 1);
12238
+ const geometry = new InstancedBufferGeometry();
12239
+ if (quad.index) {
12240
+ geometry.setIndex(quad.index.clone());
12241
+ }
12242
+ geometry.setAttribute("position", quad.attributes.position.clone());
12243
+ geometry.setAttribute("uv", quad.attributes.uv.clone());
12244
+ const indexes = new Float32Array(PARTICLE_COUNT);
12245
+ for (let i = 0; i < PARTICLE_COUNT; i += 1) {
12246
+ indexes[i] = i;
12247
+ }
12248
+ geometry.setAttribute("instanceIndex", new InstancedBufferAttribute(indexes, 1));
12249
+ geometry.instanceCount = PARTICLE_COUNT;
12250
+ quad.dispose();
12251
+ return geometry;
12252
+ }
12253
+ function ParticleOverlay({
12168
12254
  snapshot,
12169
12255
  transition,
12170
12256
  running,
12171
12257
  runId,
12172
12258
  onFinish
12173
12259
  }) {
12174
- const { camera, gl } = useThree18();
12260
+ const { camera } = useThree18();
12175
12261
  const meshRef = useRef27(null);
12176
12262
  const startRef = useRef27(null);
12177
12263
  const finishedRef = useRef27(false);
12178
12264
  const directionRef = useRef27(new Vector311());
12179
- const material = useMemo19(() => {
12265
+ const geometry = useMemo19(() => createParticleGeometry(), []);
12266
+ const material = useMemo19(
12267
+ () => new ShaderMaterial3({
12268
+ transparent: true,
12269
+ depthTest: false,
12270
+ depthWrite: false,
12271
+ side: DoubleSide3,
12272
+ uniforms: {
12273
+ map: { value: snapshot.texture },
12274
+ progress: { value: 0 },
12275
+ grid: { value: new Vector25(PARTICLE_GRID, PARTICLE_GRID) }
12276
+ },
12277
+ vertexShader: PARTICLE_VERTEX_SHADER,
12278
+ fragmentShader: PARTICLE_FRAGMENT_SHADER
12279
+ }),
12280
+ [snapshot.texture]
12281
+ );
12282
+ useEffect27(() => () => geometry.dispose(), [geometry]);
12283
+ useEffect27(() => () => material.dispose(), [material]);
12284
+ useEffect27(() => {
12285
+ startRef.current = null;
12286
+ finishedRef.current = false;
12287
+ material.uniforms.progress.value = 0;
12288
+ }, [material, runId]);
12289
+ useFrame11((state) => {
12290
+ const mesh = meshRef.current;
12291
+ if (!mesh || !isPerspectiveCamera(camera)) {
12292
+ return;
12293
+ }
12294
+ placeFullscreenOverlay(mesh, camera, directionRef.current);
12295
+ if (!running || finishedRef.current) {
12296
+ return;
12297
+ }
12298
+ const next = overlayProgress(state.clock.elapsedTime, transition.duration, startRef.current);
12299
+ startRef.current = next.startTime;
12300
+ material.uniforms.progress.value = next.progress;
12301
+ if (next.progress === 1) {
12302
+ finishedRef.current = true;
12303
+ onFinish();
12304
+ }
12305
+ });
12306
+ return /* @__PURE__ */ jsx20(
12307
+ "mesh",
12308
+ {
12309
+ ref: meshRef,
12310
+ frustumCulled: false,
12311
+ geometry,
12312
+ material,
12313
+ renderOrder: OVERLAY_RENDER_ORDER
12314
+ }
12315
+ );
12316
+ }
12317
+
12318
+ // src/scene-transitions/snapshot-overlay.tsx
12319
+ import { useFrame as useFrame12, useThree as useThree19 } from "@react-three/fiber";
12320
+ import { useEffect as useEffect28, useMemo as useMemo20, useRef as useRef28 } from "react";
12321
+ import { Vector3 as Vector312 } from "three";
12322
+ import { jsx as jsx21, jsxs as jsxs13 } from "react/jsx-runtime";
12323
+ function SnapshotOverlay({
12324
+ snapshot,
12325
+ transition,
12326
+ running,
12327
+ runId,
12328
+ onFinish
12329
+ }) {
12330
+ const { camera, gl } = useThree19();
12331
+ const meshRef = useRef28(null);
12332
+ const startRef = useRef28(null);
12333
+ const finishedRef = useRef28(false);
12334
+ const directionRef = useRef28(new Vector312());
12335
+ const material = useMemo20(() => {
12180
12336
  if (!isSnapshotTransition(transition.preset)) {
12181
12337
  return null;
12182
12338
  }
12183
12339
  return createSnapshotMaterial(transition.preset, snapshot.texture);
12184
12340
  }, [snapshot.texture, transition.preset]);
12185
- useEffect27(() => () => material?.dispose(), [material]);
12186
- useEffect27(() => {
12341
+ useEffect28(() => () => material?.dispose(), [material]);
12342
+ useEffect28(() => {
12187
12343
  startRef.current = null;
12188
12344
  finishedRef.current = false;
12189
12345
  if (material) {
12190
12346
  material.uniforms.progress.value = 0;
12191
12347
  }
12192
12348
  }, [material, runId]);
12193
- useFrame11((state) => {
12349
+ useFrame12((state) => {
12194
12350
  const mesh = meshRef.current;
12195
12351
  if (!mesh || !material || !isPerspectiveCamera(camera)) {
12196
12352
  return;
@@ -12212,21 +12368,21 @@ function SnapshotOverlay({
12212
12368
  if (!material) {
12213
12369
  return null;
12214
12370
  }
12215
- return /* @__PURE__ */ jsxs12("mesh", { ref: meshRef, renderOrder: OVERLAY_RENDER_ORDER, frustumCulled: false, children: [
12216
- /* @__PURE__ */ jsx20("primitive", { attach: "geometry", object: FULLSCREEN_PLANE }),
12217
- /* @__PURE__ */ jsx20("primitive", { attach: "material", object: material })
12371
+ return /* @__PURE__ */ jsxs13("mesh", { ref: meshRef, renderOrder: OVERLAY_RENDER_ORDER, frustumCulled: false, children: [
12372
+ /* @__PURE__ */ jsx21("primitive", { attach: "geometry", object: FULLSCREEN_PLANE }),
12373
+ /* @__PURE__ */ jsx21("primitive", { attach: "material", object: material })
12218
12374
  ] });
12219
12375
  }
12220
12376
 
12221
12377
  // src/scene-transitions/transition-overlay.tsx
12222
- import { jsx as jsx21 } from "react/jsx-runtime";
12378
+ import { jsx as jsx22 } from "react/jsx-runtime";
12223
12379
  function TransitionOverlay(props) {
12224
12380
  const { preset } = props.transition;
12225
12381
  switch (preset) {
12226
12382
  case "none":
12227
12383
  return null;
12228
12384
  case "particles":
12229
- return /* @__PURE__ */ jsx21(ParticleOverlay, { ...props });
12385
+ return /* @__PURE__ */ jsx22(ParticleOverlay, { ...props });
12230
12386
  case "crossfade":
12231
12387
  case "zoom":
12232
12388
  case "blackout":
@@ -12254,7 +12410,7 @@ function TransitionOverlay(props) {
12254
12410
  case "zoomBlur":
12255
12411
  case "hexDissolve":
12256
12412
  case "filmBurn":
12257
- return /* @__PURE__ */ jsx21(SnapshotOverlay, { ...props });
12413
+ return /* @__PURE__ */ jsx22(SnapshotOverlay, { ...props });
12258
12414
  default: {
12259
12415
  const exhaustive = preset;
12260
12416
  void exhaustive;
@@ -12264,14 +12420,14 @@ function TransitionOverlay(props) {
12264
12420
  }
12265
12421
 
12266
12422
  // src/tile/tile.tsx
12267
- import { useFrame as useFrame12, useThree as useThree19 } from "@react-three/fiber";
12268
- import { memo as memo2, useEffect as useEffect28, useMemo as useMemo20, useRef as useRef28, useState as useState13 } from "react";
12423
+ import { useFrame as useFrame13, useThree as useThree20 } from "@react-three/fiber";
12424
+ import { memo as memo2, useEffect as useEffect29, useMemo as useMemo21, useRef as useRef29, useState as useState13 } from "react";
12269
12425
  import {
12270
12426
  Frustum as Frustum2,
12271
12427
  Matrix4 as Matrix43,
12272
12428
  PlaneGeometry as PlaneGeometry4,
12273
12429
  PerspectiveCamera as PerspectiveCamera5,
12274
- Vector3 as Vector313
12430
+ Vector3 as Vector314
12275
12431
  } from "three";
12276
12432
 
12277
12433
  // src/tile/face-layout.ts
@@ -12279,7 +12435,7 @@ import {
12279
12435
  Box3 as Box32,
12280
12436
  Euler as Euler3,
12281
12437
  Quaternion as Quaternion2,
12282
- Vector3 as Vector312
12438
+ Vector3 as Vector313
12283
12439
  } from "three";
12284
12440
  var CUBE_FACES = ["f", "r", "b", "l", "u", "d"];
12285
12441
  var PREVIEW_FACE_ORDER = ["l", "f", "r", "b", "u", "d"];
@@ -12343,12 +12499,12 @@ function getTileBoundingBox(address, radius = CUBE_RADIUS) {
12343
12499
  const halfWidth = local.width / 2;
12344
12500
  const halfHeight = local.height / 2;
12345
12501
  const quaternion = getFaceQuaternion(address.face);
12346
- const position = new Vector312(...transform.position);
12502
+ const position = new Vector313(...transform.position);
12347
12503
  const corners = [
12348
- new Vector312(local.x - halfWidth, local.y - halfHeight, 0),
12349
- new Vector312(local.x + halfWidth, local.y - halfHeight, 0),
12350
- new Vector312(local.x - halfWidth, local.y + halfHeight, 0),
12351
- new Vector312(local.x + halfWidth, local.y + halfHeight, 0)
12504
+ new Vector313(local.x - halfWidth, local.y - halfHeight, 0),
12505
+ new Vector313(local.x + halfWidth, local.y - halfHeight, 0),
12506
+ new Vector313(local.x - halfWidth, local.y + halfHeight, 0),
12507
+ new Vector313(local.x + halfWidth, local.y + halfHeight, 0)
12352
12508
  ];
12353
12509
  for (const corner of corners) {
12354
12510
  corner.applyQuaternion(quaternion).add(position);
@@ -12456,11 +12612,27 @@ function resolveTemplateUrl(template, address) {
12456
12612
  }
12457
12613
 
12458
12614
  // src/tile/tile.tsx
12459
- import { jsx as jsx22, jsxs as jsxs13 } from "react/jsx-runtime";
12615
+ import { jsx as jsx23, jsxs as jsxs14 } from "react/jsx-runtime";
12460
12616
  var MAX_LOD_UPDATE_INTERVAL_MS = 100;
12461
12617
  var FAST_ROTATION_THRESHOLD_RADIANS = Math.PI / 180;
12462
12618
  var FAST_FOV_THRESHOLD_DEGREES = 0.5;
12463
12619
  var VIEW_CHANGE_EPSILON = 1e-4;
12620
+ function decideTileLodUpdate(input) {
12621
+ if (input.loadMode === "preview") {
12622
+ return false;
12623
+ }
12624
+ const loadModeChanged = input.loadMode !== input.trackedLoadMode;
12625
+ const viewChanged = input.visibilityDirty || loadModeChanged || input.viewportChanged || input.rotationDelta > VIEW_CHANGE_EPSILON || input.fovDelta > VIEW_CHANGE_EPSILON;
12626
+ if (!viewChanged) {
12627
+ return false;
12628
+ }
12629
+ const movingQuickly = input.rotationDelta >= FAST_ROTATION_THRESHOLD_RADIANS || input.fovDelta >= FAST_FOV_THRESHOLD_DEGREES;
12630
+ const immediate = input.visibilityDirty || loadModeChanged || input.viewportChanged || movingQuickly;
12631
+ if (!immediate && input.now - input.lastUpdateAt < MAX_LOD_UPDATE_INTERVAL_MS) {
12632
+ return false;
12633
+ }
12634
+ return true;
12635
+ }
12464
12636
  var VISIBILITY_FOV_PADDING_DEGREES = 8;
12465
12637
  var PREVIEW_RADIUS = CUBE_RADIUS + 0.05;
12466
12638
  var SHARED_TILE_GEOMETRY = new PlaneGeometry4(1, 1);
@@ -12469,7 +12641,7 @@ function PreviewFace({
12469
12641
  texture,
12470
12642
  faceOrder
12471
12643
  }) {
12472
- const geometry = useMemo20(() => {
12644
+ const geometry = useMemo21(() => {
12473
12645
  const nextGeometry = new PlaneGeometry4(
12474
12646
  PREVIEW_RADIUS * 2,
12475
12647
  PREVIEW_RADIUS * 2
@@ -12484,21 +12656,21 @@ function PreviewFace({
12484
12656
  uv.needsUpdate = true;
12485
12657
  return nextGeometry;
12486
12658
  }, [face, faceOrder]);
12487
- useEffect28(
12659
+ useEffect29(
12488
12660
  () => () => {
12489
12661
  geometry.dispose();
12490
12662
  },
12491
12663
  [geometry]
12492
12664
  );
12493
12665
  const transform = getFaceTransform(face, PREVIEW_RADIUS);
12494
- return /* @__PURE__ */ jsx22(
12666
+ return /* @__PURE__ */ jsx23(
12495
12667
  "mesh",
12496
12668
  {
12497
12669
  geometry,
12498
12670
  position: transform.position,
12499
12671
  renderOrder: -100,
12500
12672
  rotation: transform.rotation,
12501
- children: /* @__PURE__ */ jsx22(
12673
+ children: /* @__PURE__ */ jsx23(
12502
12674
  PanoBasicMaterial,
12503
12675
  {
12504
12676
  depthTest: false,
@@ -12514,7 +12686,7 @@ function PreviewCube({
12514
12686
  texture,
12515
12687
  faceOrder
12516
12688
  }) {
12517
- return CUBE_FACES.map((face) => /* @__PURE__ */ jsx22(
12689
+ return CUBE_FACES.map((face) => /* @__PURE__ */ jsx23(
12518
12690
  PreviewFace,
12519
12691
  {
12520
12692
  face,
@@ -12538,14 +12710,14 @@ var TileMesh = memo2(function TileMesh2({
12538
12710
  if (!snapshot.texture) {
12539
12711
  return null;
12540
12712
  }
12541
- return /* @__PURE__ */ jsx22("group", { position: transform.position, rotation: transform.rotation, children: /* @__PURE__ */ jsx22(
12713
+ return /* @__PURE__ */ jsx23("group", { position: transform.position, rotation: transform.rotation, children: /* @__PURE__ */ jsx23(
12542
12714
  "mesh",
12543
12715
  {
12544
12716
  geometry: SHARED_TILE_GEOMETRY,
12545
12717
  position: [layout.x, layout.y, 0],
12546
12718
  renderOrder,
12547
12719
  scale: [layout.width, layout.height, 1],
12548
- children: /* @__PURE__ */ jsx22(
12720
+ children: /* @__PURE__ */ jsx23(
12549
12721
  PanoBasicMaterial,
12550
12722
  {
12551
12723
  depthTest: false,
@@ -12562,7 +12734,7 @@ var TileLayerMeshes = memo2(function TileLayerMeshes2({
12562
12734
  manager,
12563
12735
  resolveUrl
12564
12736
  }) {
12565
- return layer.addresses.map((address) => /* @__PURE__ */ jsx22(
12737
+ return layer.addresses.map((address) => /* @__PURE__ */ jsx23(
12566
12738
  TileMesh,
12567
12739
  {
12568
12740
  address,
@@ -12662,8 +12834,8 @@ function parentAddresses(child, parentLevel, parentFaceSize, tileSize) {
12662
12834
  return addresses;
12663
12835
  }
12664
12836
  function centerFacingAddress(candidates, camera) {
12665
- const direction = camera.getWorldDirection(new Vector313());
12666
- const center = new Vector313();
12837
+ const direction = camera.getWorldDirection(new Vector314());
12838
+ const center = new Vector314();
12667
12839
  let bestCandidate = candidates[0];
12668
12840
  let bestAlignment = -Infinity;
12669
12841
  for (const candidate of candidates) {
@@ -12728,11 +12900,11 @@ function Tile({
12728
12900
  onTileError,
12729
12901
  onLevelChange
12730
12902
  }) {
12731
- const { camera, gl, size } = useThree19();
12732
- const multiresConfig = useMemo20(() => parseMultires(multires), [multires]);
12903
+ const { camera, gl, size } = useThree20();
12904
+ const multiresConfig = useMemo21(() => parseMultires(multires), [multires]);
12733
12905
  const { levels, tileSize } = multiresConfig;
12734
12906
  const multiresToken = `${tileSize}:${levels.join(",")}`;
12735
- const candidatesByLevel = useMemo20(
12907
+ const candidatesByLevel = useMemo21(
12736
12908
  () => buildTileCandidates(levels, tileSize),
12737
12909
  [levels, tileSize]
12738
12910
  );
@@ -12744,13 +12916,13 @@ function Tile({
12744
12916
  onPreviewError
12745
12917
  );
12746
12918
  const sharedManager = useSharedTileTextureManager();
12747
- const progressRef = useRef28(onLoadProgress);
12748
- const errorRef = useRef28(onTileError);
12749
- const levelChangeRef = useRef28(onLevelChange);
12919
+ const progressRef = useRef29(onLoadProgress);
12920
+ const errorRef = useRef29(onTileError);
12921
+ const levelChangeRef = useRef29(onLevelChange);
12750
12922
  progressRef.current = onLoadProgress;
12751
12923
  errorRef.current = onTileError;
12752
12924
  levelChangeRef.current = onLevelChange;
12753
- const ownedManager = useMemo20(
12925
+ const ownedManager = useMemo21(
12754
12926
  () => new TileTextureManager({
12755
12927
  anisotropy,
12756
12928
  maxBytes: Math.max(1, maxTextureMemoryMb) * 1024 * 1024,
@@ -12771,7 +12943,7 @@ function Tile({
12771
12943
  ]
12772
12944
  );
12773
12945
  const manager = sharedManager ?? ownedManager;
12774
- useEffect28(() => {
12946
+ useEffect29(() => {
12775
12947
  manager.resume();
12776
12948
  return () => {
12777
12949
  if (manager === ownedManager) {
@@ -12781,11 +12953,11 @@ function Tile({
12781
12953
  queueMicrotask(() => manager.releaseUnused());
12782
12954
  };
12783
12955
  }, [manager, ownedManager]);
12784
- const readyRef = useRef28(false);
12785
- useEffect28(() => {
12956
+ const readyRef = useRef29(false);
12957
+ useEffect29(() => {
12786
12958
  readyRef.current = false;
12787
12959
  }, [effectivePreviewUrl]);
12788
- useEffect28(() => {
12960
+ useEffect29(() => {
12789
12961
  if (!previewTexture || readyRef.current) {
12790
12962
  return;
12791
12963
  }
@@ -12793,7 +12965,7 @@ function Tile({
12793
12965
  onReady?.();
12794
12966
  }, [onReady, previewTexture]);
12795
12967
  const template = urlTemplate ?? buildDefaultTileUrlTemplate();
12796
- const resolveUrl = useMemo20(
12968
+ const resolveUrl = useMemo21(
12797
12969
  () => (address) => {
12798
12970
  const relativePath = resolveTileUrl ? resolveTileUrl(address) : resolveTemplateUrl(template, address);
12799
12971
  return resolveRelativeTileUrl(baseUrl, relativePath);
@@ -12801,23 +12973,29 @@ function Tile({
12801
12973
  [baseUrl, resolveTileUrl, template]
12802
12974
  );
12803
12975
  const [layers, setLayers] = useState13([]);
12804
- const layerTokenRef = useRef28("");
12805
- const currentLevelRef = useRef28(1);
12806
- const lastUpdateAtRef = useRef28(-Infinity);
12807
- const visibilityDirtyRef = useRef28(true);
12808
- const lastVisibilityQuaternionRef = useRef28(camera.quaternion.clone());
12809
- const lastVisibilityFovRef = useRef28(Number.NaN);
12810
- const lastViewportRef = useRef28({ width: 0, height: 0, dpr: 0 });
12811
- const frustumRef = useRef28(new Frustum2());
12812
- const projectionMatrixRef = useRef28(new Matrix43());
12813
- const visibilityCameraRef = useRef28(new PerspectiveCamera5());
12814
- useEffect28(() => {
12976
+ const layerTokenRef = useRef29("");
12977
+ const currentLevelRef = useRef29(1);
12978
+ const lastUpdateAtRef = useRef29(-Infinity);
12979
+ const visibilityDirtyRef = useRef29(true);
12980
+ const lastVisibilityQuaternionRef = useRef29(camera.quaternion.clone());
12981
+ const lastVisibilityFovRef = useRef29(Number.NaN);
12982
+ const lastViewportRef = useRef29({ width: 0, height: 0, dpr: 0 });
12983
+ const frustumRef = useRef29(new Frustum2());
12984
+ const projectionMatrixRef = useRef29(new Matrix43());
12985
+ const visibilityCameraRef = useRef29(new PerspectiveCamera5());
12986
+ const trackedLoadModeRef = useRef29(loadMode);
12987
+ const targetKeysRef = useRef29([]);
12988
+ const detailTokenRef = useRef29("");
12989
+ const detailReporter = useSceneDetailReporter();
12990
+ const detailReporterRef = useRef29(detailReporter);
12991
+ detailReporterRef.current = detailReporter;
12992
+ useEffect29(() => {
12815
12993
  currentLevelRef.current = 1;
12816
12994
  layerTokenRef.current = "";
12817
12995
  visibilityDirtyRef.current = true;
12818
12996
  setLayers([]);
12819
12997
  }, [manager, multiresToken]);
12820
- useEffect28(() => {
12998
+ useEffect29(() => {
12821
12999
  if (loadMode !== "preview") {
12822
13000
  return;
12823
13001
  }
@@ -12831,11 +13009,14 @@ function Tile({
12831
13009
  setLayers(nextLayers);
12832
13010
  }
12833
13011
  };
12834
- useFrame12(() => {
12835
- if (loadMode === "preview") {
13012
+ useFrame13(() => {
13013
+ if (!(camera instanceof PerspectiveCamera5)) {
12836
13014
  return;
12837
13015
  }
12838
- if (!(camera instanceof PerspectiveCamera5)) {
13016
+ if (loadMode === "preview") {
13017
+ trackedLoadModeRef.current = "preview";
13018
+ targetKeysRef.current = [];
13019
+ publishSceneDetail(detailReporterRef.current, detailTokenRef, false);
12839
13020
  return;
12840
13021
  }
12841
13022
  const now = performance.now();
@@ -12843,63 +13024,78 @@ function Tile({
12843
13024
  const rotationDelta = lastVisibilityQuaternionRef.current.angleTo(
12844
13025
  camera.quaternion
12845
13026
  );
12846
- const fovDelta = Number.isFinite(lastVisibilityFovRef.current) ? Math.abs(camera.fov - lastVisibilityFovRef.current) : Infinity;
12847
- const lastViewport = lastViewportRef.current;
12848
- const viewportChanged = lastViewport.width !== size.width || lastViewport.height !== size.height || lastViewport.dpr !== pixelRatio;
12849
- const viewChanged = visibilityDirtyRef.current || viewportChanged || rotationDelta > VIEW_CHANGE_EPSILON || fovDelta > VIEW_CHANGE_EPSILON;
12850
- const movingQuickly = rotationDelta >= FAST_ROTATION_THRESHOLD_RADIANS || fovDelta >= FAST_FOV_THRESHOLD_DEGREES;
12851
- if (!viewChanged) {
12852
- return;
12853
- }
12854
- const needsImmediateUpdate = visibilityDirtyRef.current || viewportChanged || movingQuickly;
12855
- if (!needsImmediateUpdate && now - lastUpdateAtRef.current < MAX_LOD_UPDATE_INTERVAL_MS) {
12856
- return;
12857
- }
12858
- lastUpdateAtRef.current = now;
12859
- const targetLevel = loadMode === "base" ? 1 : getPreferredLevel(
12860
- levels,
12861
- size.height,
12862
- pixelRatio,
12863
- camera.fov,
12864
- currentLevelRef.current
12865
- );
12866
- if (targetLevel !== currentLevelRef.current) {
12867
- currentLevelRef.current = targetLevel;
12868
- levelChangeRef.current?.(targetLevel);
12869
- }
12870
- const visibilityCamera = visibilityCameraRef.current;
12871
- visibilityCamera.copy(camera, false);
12872
- visibilityCamera.fov = Math.min(
12873
- 179,
12874
- camera.fov + VISIBILITY_FOV_PADDING_DEGREES
12875
- );
12876
- visibilityCamera.aspect = camera.aspect;
12877
- updateVisibilityFrustum(
12878
- visibilityCamera,
12879
- projectionMatrixRef.current,
12880
- frustumRef.current
12881
- );
12882
- const nextLayers = buildLayers(
12883
- targetLevel,
12884
- levels,
12885
- tileSize,
12886
- frustumRef.current,
12887
- camera,
12888
- candidatesByLevel
13027
+ const fovDelta = Number.isFinite(lastVisibilityFovRef.current) ? Math.abs(camera.fov - lastVisibilityFovRef.current) : Infinity;
13028
+ const lastViewport = lastViewportRef.current;
13029
+ const viewportChanged = lastViewport.width !== size.width || lastViewport.height !== size.height || lastViewport.dpr !== pixelRatio;
13030
+ const updateLod = decideTileLodUpdate({
13031
+ loadMode,
13032
+ trackedLoadMode: trackedLoadModeRef.current,
13033
+ now,
13034
+ lastUpdateAt: lastUpdateAtRef.current,
13035
+ visibilityDirty: visibilityDirtyRef.current,
13036
+ viewportChanged,
13037
+ rotationDelta,
13038
+ fovDelta
13039
+ });
13040
+ if (updateLod) {
13041
+ trackedLoadModeRef.current = loadMode;
13042
+ lastUpdateAtRef.current = now;
13043
+ const targetLevel = loadMode === "base" ? 1 : getPreferredLevel(
13044
+ levels,
13045
+ size.height,
13046
+ pixelRatio,
13047
+ camera.fov,
13048
+ currentLevelRef.current
13049
+ );
13050
+ if (targetLevel !== currentLevelRef.current) {
13051
+ currentLevelRef.current = targetLevel;
13052
+ levelChangeRef.current?.(targetLevel);
13053
+ }
13054
+ const visibilityCamera = visibilityCameraRef.current;
13055
+ visibilityCamera.copy(camera, false);
13056
+ visibilityCamera.fov = Math.min(
13057
+ 179,
13058
+ camera.fov + VISIBILITY_FOV_PADDING_DEGREES
13059
+ );
13060
+ visibilityCamera.aspect = camera.aspect;
13061
+ updateVisibilityFrustum(
13062
+ visibilityCamera,
13063
+ projectionMatrixRef.current,
13064
+ frustumRef.current
13065
+ );
13066
+ const nextLayers = buildLayers(
13067
+ targetLevel,
13068
+ levels,
13069
+ tileSize,
13070
+ frustumRef.current,
13071
+ camera,
13072
+ candidatesByLevel
13073
+ );
13074
+ visibilityDirtyRef.current = false;
13075
+ lastVisibilityQuaternionRef.current.copy(camera.quaternion);
13076
+ lastVisibilityFovRef.current = camera.fov;
13077
+ lastViewportRef.current = {
13078
+ width: size.width,
13079
+ height: size.height,
13080
+ dpr: pixelRatio
13081
+ };
13082
+ const targetLayer = nextLayers.find((layer) => layer.level === targetLevel);
13083
+ targetKeysRef.current = loadMode === "full" ? (targetLayer?.addresses ?? []).map(
13084
+ (address) => `${resolveUrl(address)}\0${tileKey(address)}`
13085
+ ) : [];
13086
+ commitLayers(nextLayers);
13087
+ }
13088
+ publishSceneDetail(
13089
+ detailReporterRef.current,
13090
+ detailTokenRef,
13091
+ loadMode === "full" && viewTilesAreDrawable(
13092
+ targetKeysRef.current.map((key) => manager.getSnapshot(key).texture)
13093
+ )
12889
13094
  );
12890
- visibilityDirtyRef.current = false;
12891
- lastVisibilityQuaternionRef.current.copy(camera.quaternion);
12892
- lastVisibilityFovRef.current = camera.fov;
12893
- lastViewportRef.current = {
12894
- width: size.width,
12895
- height: size.height,
12896
- dpr: pixelRatio
12897
- };
12898
- commitLayers(nextLayers);
12899
13095
  });
12900
- return /* @__PURE__ */ jsxs13("group", { visible, children: [
12901
- previewTexture ? /* @__PURE__ */ jsx22(PreviewCube, { texture: previewTexture, faceOrder: previewFaceOrder }) : null,
12902
- layers.map((layer) => /* @__PURE__ */ jsx22(
13096
+ return /* @__PURE__ */ jsxs14("group", { visible, children: [
13097
+ previewTexture ? /* @__PURE__ */ jsx23(PreviewCube, { texture: previewTexture, faceOrder: previewFaceOrder }) : null,
13098
+ layers.map((layer) => /* @__PURE__ */ jsx23(
12903
13099
  TileLayerMeshes,
12904
13100
  {
12905
13101
  layer,
@@ -12912,7 +13108,7 @@ function Tile({
12912
13108
  }
12913
13109
 
12914
13110
  // src/scenes.tsx
12915
- import { jsx as jsx23, jsxs as jsxs14 } from "react/jsx-runtime";
13111
+ import { jsx as jsx24, jsxs as jsxs15 } from "react/jsx-runtime";
12916
13112
  function SceneSource({
12917
13113
  scene,
12918
13114
  visible,
@@ -12925,7 +13121,7 @@ function SceneSource({
12925
13121
  }
12926
13122
  switch (scene.type) {
12927
13123
  case "sphere":
12928
- return /* @__PURE__ */ jsx23(
13124
+ return /* @__PURE__ */ jsx24(
12929
13125
  Sphere,
12930
13126
  {
12931
13127
  src: scene.src,
@@ -12938,7 +13134,7 @@ function SceneSource({
12938
13134
  );
12939
13135
  case "tile": {
12940
13136
  const { id: _id, type: _type, ...tileProps } = scene;
12941
- return /* @__PURE__ */ jsx23(
13137
+ return /* @__PURE__ */ jsx24(
12942
13138
  Tile,
12943
13139
  {
12944
13140
  ...tileProps,
@@ -12951,7 +13147,7 @@ function SceneSource({
12951
13147
  }
12952
13148
  case "sphereTile": {
12953
13149
  const { id: _id, type: _type, ...tileProps } = scene;
12954
- return /* @__PURE__ */ jsx23(
13150
+ return /* @__PURE__ */ jsx24(
12955
13151
  SphereTile,
12956
13152
  {
12957
13153
  ...tileProps,
@@ -12974,17 +13170,17 @@ function SnapshotCapture({
12974
13170
  maxPixels,
12975
13171
  onCaptured
12976
13172
  }) {
12977
- const { camera, gl, scene, size } = useThree20();
12978
- const capturedRequestRef = useRef29(0);
12979
- const renderTargetRef = useRef29(null);
12980
- useEffect29(
13173
+ const { camera, gl, scene, size } = useThree21();
13174
+ const capturedRequestRef = useRef30(0);
13175
+ const renderTargetRef = useRef30(null);
13176
+ useEffect30(
12981
13177
  () => () => {
12982
13178
  renderTargetRef.current?.dispose();
12983
13179
  renderTargetRef.current = null;
12984
13180
  },
12985
13181
  []
12986
13182
  );
12987
- useFrame13(() => {
13183
+ useFrame14(() => {
12988
13184
  if (requestId === 0 || requestId === capturedRequestRef.current) {
12989
13185
  return;
12990
13186
  }
@@ -13032,15 +13228,16 @@ function ScenesController({
13032
13228
  onTransitionEnd,
13033
13229
  onTransitionError,
13034
13230
  snapshotMaxPixels = 3686400,
13231
+ transitionWaitForDetailMs,
13035
13232
  phaseRef: externalPhaseRef
13036
13233
  }) {
13037
- const controlsRef = useContext23(PanoramaViewContext);
13234
+ const controlsRef = useContext24(PanoramaViewContext);
13038
13235
  const manager = useSharedTileTextureManager();
13039
- const transition = useMemo21(
13236
+ const transition = useMemo22(
13040
13237
  () => resolveTransition(transitionInput),
13041
13238
  [transitionInput]
13042
13239
  );
13043
- const sceneMap = useMemo21(
13240
+ const sceneMap = useMemo22(
13044
13241
  () => new Map(scenes.map((scene) => [scene.id, scene])),
13045
13242
  [scenes]
13046
13243
  );
@@ -13057,14 +13254,21 @@ function ScenesController({
13057
13254
  const [transitionRunId, setTransitionRunId] = useState14(0);
13058
13255
  const [snapshot, setSnapshot] = useState14(null);
13059
13256
  const [recoveryKey, setRecoveryKey] = useState14(0);
13060
- const requestedSceneIdRef = useRef29(activeSceneId);
13061
- const captureReasonRef = useRef29("start");
13062
- const interactionReleaseRef = useRef29(null);
13063
- const slotsRef = useRef29(slots);
13064
- const phaseRef = useRef29(phase);
13065
- const liveSlotRef = useRef29(liveSlot);
13066
- const transitionFromRef = useRef29(initialScene);
13067
- const readySceneRef = useRef29(null);
13257
+ const requestedSceneIdRef = useRef30(activeSceneId);
13258
+ const captureReasonRef = useRef30("start");
13259
+ const interactionReleaseRef = useRef30(null);
13260
+ const slotsRef = useRef30(slots);
13261
+ const phaseRef = useRef30(phase);
13262
+ const liveSlotRef = useRef30(liveSlot);
13263
+ const transitionFromRef = useRef30(initialScene);
13264
+ const readySceneRef = useRef30(null);
13265
+ const waitRef = useRef30(null);
13266
+ const waitTimerRef = useRef30(null);
13267
+ const detailGenerationRef = useRef30(0);
13268
+ const [detailGeneration, setDetailGeneration] = useState14(0);
13269
+ const mountedRef = useRef30(true);
13270
+ const waitForDetailMsRef = useRef30(0);
13271
+ waitForDetailMsRef.current = normalizeTransitionWaitMs(transitionWaitForDetailMs);
13068
13272
  slotsRef.current = slots;
13069
13273
  phaseRef.current = phase;
13070
13274
  if (externalPhaseRef) {
@@ -13078,7 +13282,36 @@ function ScenesController({
13078
13282
  const reportError = useCallback11((sceneId, error) => {
13079
13283
  onTransitionError?.({ sceneId, error });
13080
13284
  }, [onTransitionError]);
13285
+ const clearDetailWait = useCallback11((bumpGeneration) => {
13286
+ if (waitTimerRef.current !== null) {
13287
+ clearTimeout(waitTimerRef.current);
13288
+ waitTimerRef.current = null;
13289
+ }
13290
+ const generation = waitRef.current?.generation;
13291
+ if (generation === void 0) {
13292
+ waitRef.current = null;
13293
+ } else {
13294
+ waitRef.current = acceptDetailWait(waitRef.current, {
13295
+ kind: "cancel",
13296
+ generation
13297
+ }).wait;
13298
+ }
13299
+ if (!bumpGeneration || !mountedRef.current) {
13300
+ return;
13301
+ }
13302
+ const nextGeneration = detailGenerationRef.current + 1;
13303
+ detailGenerationRef.current = nextGeneration;
13304
+ setDetailGeneration(nextGeneration);
13305
+ }, []);
13306
+ useEffect30(() => {
13307
+ mountedRef.current = true;
13308
+ return () => {
13309
+ mountedRef.current = false;
13310
+ clearDetailWait(false);
13311
+ };
13312
+ }, [clearDetailWait]);
13081
13313
  const startPreload = useCallback11((scene) => {
13314
+ clearDetailWait(true);
13082
13315
  const nextSlot = 1 - liveSlotRef.current;
13083
13316
  requestedSceneIdRef.current = scene.id;
13084
13317
  setSlots((current) => {
@@ -13088,8 +13321,8 @@ function ScenesController({
13088
13321
  });
13089
13322
  setPendingSlot(nextSlot);
13090
13323
  setPhase("preloading");
13091
- }, []);
13092
- useEffect29(() => {
13324
+ }, [clearDetailWait]);
13325
+ useEffect30(() => {
13093
13326
  const requested = sceneMap.get(activeSceneId);
13094
13327
  if (!requested) {
13095
13328
  reportError(activeSceneId, new Error(`Unknown panorama scene: ${activeSceneId}`));
@@ -13104,16 +13337,17 @@ function ScenesController({
13104
13337
  requestedSceneIdRef.current = requested.id;
13105
13338
  return;
13106
13339
  }
13107
- if (phaseRef.current === "transitioning" || phaseRef.current === "capturing") {
13340
+ if (phaseRef.current === "transitioning" || phaseRef.current === "capturing" || phaseRef.current === "awaitingDetail") {
13108
13341
  if (requestedSceneIdRef.current === requested.id) return;
13109
13342
  requestedSceneIdRef.current = requested.id;
13110
13343
  captureReasonRef.current = "interrupt";
13344
+ clearDetailWait(true);
13111
13345
  setPhase("recapturing");
13112
13346
  setCaptureRequestId((current) => current + 1);
13113
13347
  return;
13114
13348
  }
13115
13349
  startPreload(requested);
13116
- }, [activeSceneId, pendingSlot, reportError, sceneMap, startPreload]);
13350
+ }, [activeSceneId, clearDetailWait, pendingSlot, reportError, sceneMap, startPreload]);
13117
13351
  const notifySceneReady = useCallback11((scene) => {
13118
13352
  if (!scene || readySceneRef.current === scene) return;
13119
13353
  readySceneRef.current = scene;
@@ -13127,7 +13361,7 @@ function ScenesController({
13127
13361
  if (slot !== pendingSlot || phaseRef.current !== "preloading") {
13128
13362
  return;
13129
13363
  }
13130
- if (transition.preset === "none") {
13364
+ if (transition.preset === "none" && waitForDetailMsRef.current === 0) {
13131
13365
  const previousScene = slotsRef.current[liveSlotRef.current];
13132
13366
  const nextScene = slotsRef.current[slot];
13133
13367
  setSlots((current) => {
@@ -13155,29 +13389,6 @@ function ScenesController({
13155
13389
  setPhase("capturing");
13156
13390
  setCaptureRequestId((current) => current + 1);
13157
13391
  }, [controlsRef, notifySceneReady, onTransitionEnd, pendingSlot, transition.preset]);
13158
- const handleCaptured = useCallback11((nextSnapshot) => {
13159
- setSnapshot((current) => {
13160
- current?.dispose();
13161
- return nextSnapshot;
13162
- });
13163
- if (captureReasonRef.current === "interrupt") {
13164
- startPreload(sceneMap.get(requestedSceneIdRef.current));
13165
- return;
13166
- }
13167
- const sourceSlot = liveSlotRef.current;
13168
- setSlots((current) => {
13169
- const next = [...current];
13170
- next[sourceSlot] = null;
13171
- return next;
13172
- });
13173
- manager?.releaseUnused();
13174
- if (pendingSlot !== null) {
13175
- notifySceneReady(slotsRef.current[pendingSlot]);
13176
- setLiveSlot(pendingSlot);
13177
- }
13178
- setPhase("transitioning");
13179
- setTransitionRunId((current) => current + 1);
13180
- }, [manager, notifySceneReady, pendingSlot, sceneMap, startPreload]);
13181
13392
  const finishTransition = useCallback11(() => {
13182
13393
  const nextSlot = pendingSlot;
13183
13394
  const previousScene = transitionFromRef.current;
@@ -13203,16 +13414,142 @@ function ScenesController({
13203
13414
  });
13204
13415
  }
13205
13416
  }, [onTransitionEnd, pendingSlot, releaseInteraction, snapshot, transition.preset]);
13206
- useEffect29(() => () => {
13417
+ const finishTransitionRef = useRef30(finishTransition);
13418
+ finishTransitionRef.current = finishTransition;
13419
+ const transitionRef = useRef30(transition);
13420
+ transitionRef.current = transition;
13421
+ const consumeDetailSignal = useCallback11((signal) => {
13422
+ const decision = acceptDetailWait(waitRef.current, signal);
13423
+ waitRef.current = decision.wait;
13424
+ if (!decision.start) {
13425
+ return;
13426
+ }
13427
+ if (waitTimerRef.current !== null) {
13428
+ clearTimeout(waitTimerRef.current);
13429
+ waitTimerRef.current = null;
13430
+ }
13431
+ if (!mountedRef.current) {
13432
+ return;
13433
+ }
13434
+ if (transitionRef.current.preset === "none") {
13435
+ finishTransitionRef.current();
13436
+ return;
13437
+ }
13438
+ setPhase("transitioning");
13439
+ setTransitionRunId((current) => current + 1);
13440
+ }, []);
13441
+ const handleCaptured = useCallback11((nextSnapshot) => {
13442
+ if (captureReasonRef.current === "interrupt") {
13443
+ setSnapshot((current) => {
13444
+ current?.dispose();
13445
+ return nextSnapshot;
13446
+ });
13447
+ startPreload(sceneMap.get(requestedSceneIdRef.current));
13448
+ return;
13449
+ }
13450
+ const sourceSlot = liveSlotRef.current;
13451
+ const incoming = pendingSlot === null ? null : slotsRef.current[pendingSlot];
13452
+ setSlots((current) => {
13453
+ const next = [...current];
13454
+ next[sourceSlot] = null;
13455
+ return next;
13456
+ });
13457
+ manager?.releaseUnused();
13458
+ if (pendingSlot !== null && incoming) {
13459
+ notifySceneReady(incoming);
13460
+ setLiveSlot(pendingSlot);
13461
+ }
13462
+ if (waitTimerRef.current !== null) {
13463
+ clearTimeout(waitTimerRef.current);
13464
+ waitTimerRef.current = null;
13465
+ }
13466
+ waitRef.current = null;
13467
+ let hold = null;
13468
+ if (incoming && waitForDetailMsRef.current > 0) {
13469
+ const now = performance.now();
13470
+ const generation = detailGenerationRef.current + 1;
13471
+ detailGenerationRef.current = generation;
13472
+ hold = planDetailHold({
13473
+ waitMs: waitForDetailMsRef.current,
13474
+ now,
13475
+ generation,
13476
+ sceneId: incoming.id
13477
+ });
13478
+ if (hold) {
13479
+ const deadline = hold.deadline;
13480
+ waitRef.current = hold;
13481
+ setDetailGeneration(generation);
13482
+ waitTimerRef.current = setTimeout(() => {
13483
+ consumeDetailSignal({
13484
+ kind: "timeout",
13485
+ generation,
13486
+ now: deadline
13487
+ });
13488
+ }, Math.max(0, deadline - performance.now()));
13489
+ }
13490
+ }
13491
+ const nextPhase = phaseAfterSnapshot(transition.preset, hold);
13492
+ if (nextPhase === "awaitingDetail") {
13493
+ setSnapshot((current) => {
13494
+ current?.dispose();
13495
+ return nextSnapshot;
13496
+ });
13497
+ setPhase("awaitingDetail");
13498
+ return;
13499
+ }
13500
+ if (nextPhase === "idle") {
13501
+ nextSnapshot.dispose();
13502
+ setSnapshot((current) => {
13503
+ current?.dispose();
13504
+ return null;
13505
+ });
13506
+ if (pendingSlot !== null) {
13507
+ setActiveSlot(pendingSlot);
13508
+ }
13509
+ setPendingSlot(null);
13510
+ setPhase("idle");
13511
+ releaseInteraction();
13512
+ const previousScene = transitionFromRef.current;
13513
+ if (previousScene && incoming) {
13514
+ onTransitionEnd?.({
13515
+ previousSceneId: previousScene.id,
13516
+ sceneId: incoming.id,
13517
+ preset: "none"
13518
+ });
13519
+ }
13520
+ return;
13521
+ }
13522
+ setSnapshot((current) => {
13523
+ current?.dispose();
13524
+ return nextSnapshot;
13525
+ });
13526
+ setPhase("transitioning");
13527
+ setTransitionRunId((current) => current + 1);
13528
+ }, [
13529
+ consumeDetailSignal,
13530
+ manager,
13531
+ notifySceneReady,
13532
+ onTransitionEnd,
13533
+ pendingSlot,
13534
+ releaseInteraction,
13535
+ sceneMap,
13536
+ startPreload,
13537
+ transition.preset
13538
+ ]);
13539
+ const snapshotRef = useRef30(snapshot);
13540
+ snapshotRef.current = snapshot;
13541
+ useEffect30(() => () => {
13207
13542
  releaseInteraction();
13208
- snapshot?.dispose();
13209
- }, [releaseInteraction, snapshot]);
13210
- const { gl } = useThree20();
13211
- useEffect29(() => {
13543
+ snapshotRef.current?.dispose();
13544
+ snapshotRef.current = null;
13545
+ }, [releaseInteraction]);
13546
+ const { gl } = useThree21();
13547
+ useEffect30(() => {
13212
13548
  const canvas = gl.domElement;
13213
13549
  const onContextLost = (event) => {
13214
13550
  event.preventDefault();
13215
13551
  releaseInteraction();
13552
+ clearDetailWait(true);
13216
13553
  manager?.dispose();
13217
13554
  snapshot?.dispose();
13218
13555
  setSnapshot(null);
@@ -13230,11 +13567,30 @@ function ScenesController({
13230
13567
  canvas.removeEventListener("webglcontextlost", onContextLost);
13231
13568
  canvas.removeEventListener("webglcontextrestored", onContextRestored);
13232
13569
  };
13233
- }, [gl, manager, releaseInteraction, snapshot]);
13570
+ }, [clearDetailWait, gl, manager, releaseInteraction, snapshot]);
13234
13571
  const renderedScene = slots[liveSlot];
13235
13572
  const snapshotVisible = snapshot !== null && (phase === "transitioning" || phase === "recapturing" || phase === "preloading");
13236
- return /* @__PURE__ */ jsxs14(Fragment6, { children: [
13237
- /* @__PURE__ */ jsx23(
13573
+ const slotSceneKey = `${slots[0]?.id ?? ""}
13574
+ ${slots[1]?.id ?? ""}`;
13575
+ const detailReporters = useMemo22(() => {
13576
+ const [firstSceneId = "", secondSceneId = ""] = slotSceneKey.split("\n");
13577
+ const sceneIds = [firstSceneId, secondSceneId];
13578
+ return sceneIds.map((sceneId) => ({
13579
+ generation: detailGeneration,
13580
+ report: (ready) => {
13581
+ if (!ready || sceneId === "") {
13582
+ return;
13583
+ }
13584
+ consumeDetailSignal({
13585
+ kind: "ready",
13586
+ generation: detailGeneration,
13587
+ sceneId
13588
+ });
13589
+ }
13590
+ }));
13591
+ }, [consumeDetailSignal, detailGeneration, slotSceneKey]);
13592
+ return /* @__PURE__ */ jsxs15(Fragment6, { children: [
13593
+ /* @__PURE__ */ jsx24(
13238
13594
  SnapshotCapture,
13239
13595
  {
13240
13596
  requestId: captureRequestId,
@@ -13246,23 +13602,30 @@ function ScenesController({
13246
13602
  const source = slots[slot];
13247
13603
  const isLive = slot === liveSlot;
13248
13604
  const isPending = slot === pendingSlot;
13249
- return /* @__PURE__ */ jsx23(
13250
- SceneSource,
13605
+ return /* @__PURE__ */ jsx24(
13606
+ SceneDetailContext.Provider,
13251
13607
  {
13252
- scene: source,
13253
- visible: isLive,
13254
- baseOnly: isPending && phase !== "idle",
13255
- onReady: () => handleReady(slot),
13256
- onError: (error) => {
13257
- if (source) {
13258
- reportError(source.id, error);
13608
+ value: detailReporters[slot],
13609
+ children: /* @__PURE__ */ jsx24(
13610
+ SceneSource,
13611
+ {
13612
+ scene: source,
13613
+ visible: isLive,
13614
+ baseOnly: pendingSceneUsesBaseLayer(phase, isPending),
13615
+ onReady: () => handleReady(slot),
13616
+ onError: (error) => {
13617
+ if (source) {
13618
+ reportError(source.id, error);
13619
+ }
13620
+ }
13259
13621
  }
13260
- }
13622
+ )
13261
13623
  },
13262
13624
  `${slot}:${source?.id ?? "empty"}:${recoveryKey}`
13263
13625
  );
13264
13626
  }),
13265
- snapshotVisible ? /* @__PURE__ */ jsx23(
13627
+ snapshot !== null && phase === "awaitingDetail" ? /* @__PURE__ */ jsx24(SnapshotHold, { snapshot }) : null,
13628
+ snapshotVisible ? /* @__PURE__ */ jsx24(
13266
13629
  TransitionOverlay,
13267
13630
  {
13268
13631
  snapshot,
@@ -13299,13 +13662,13 @@ function Scenes({
13299
13662
  },
13300
13663
  [isControlled, onActiveSceneIdChange]
13301
13664
  );
13302
- const scenesRef = useRef29(scenes);
13665
+ const scenesRef = useRef30(scenes);
13303
13666
  scenesRef.current = scenes;
13304
- const resolvedIdRef = useRef29(resolvedId);
13667
+ const resolvedIdRef = useRef30(resolvedId);
13305
13668
  resolvedIdRef.current = resolvedId;
13306
- const host = useContext23(ScenesHostContext);
13307
- const phaseRef = useRef29("idle");
13308
- useEffect29(() => {
13669
+ const host = useContext24(ScenesHostContext);
13670
+ const phaseRef = useRef30("idle");
13671
+ useEffect30(() => {
13309
13672
  if (!host) {
13310
13673
  return;
13311
13674
  }
@@ -13355,12 +13718,12 @@ function Scenes({
13355
13718
  }
13356
13719
  };
13357
13720
  }, [host, requestSceneChange]);
13358
- return /* @__PURE__ */ jsx23(
13721
+ return /* @__PURE__ */ jsx24(
13359
13722
  TileTextureManagerProvider,
13360
13723
  {
13361
13724
  maxTextureMemoryMb,
13362
13725
  maxConcurrentLoads: maxConcurrentTileLoads,
13363
- children: /* @__PURE__ */ jsx23(
13726
+ children: /* @__PURE__ */ jsx24(
13364
13727
  ScenesController,
13365
13728
  {
13366
13729
  ...rest,
@@ -13374,8 +13737,8 @@ function Scenes({
13374
13737
  }
13375
13738
 
13376
13739
  // src/hotspot/image-hotspot.tsx
13377
- import { useThree as useThree23 } from "@react-three/fiber";
13378
- import { useEffect as useEffect32, useRef as useRef32, useState as useState17 } from "react";
13740
+ import { useThree as useThree24 } from "@react-three/fiber";
13741
+ import { useEffect as useEffect33, useRef as useRef33, useState as useState17 } from "react";
13379
13742
  import {
13380
13743
  ClampToEdgeWrapping as ClampToEdgeWrapping3,
13381
13744
  LinearFilter as LinearFilter6,
@@ -13385,13 +13748,13 @@ import {
13385
13748
  } from "three";
13386
13749
 
13387
13750
  // src/hotspot/hotspot-anchor.tsx
13388
- import { useFrame as useFrame15, useThree as useThree22 } from "@react-three/fiber";
13751
+ import { useFrame as useFrame16, useThree as useThree23 } from "@react-three/fiber";
13389
13752
  import {
13390
- useContext as useContext25,
13391
- useEffect as useEffect31,
13753
+ useContext as useContext26,
13754
+ useEffect as useEffect32,
13392
13755
  useLayoutEffect as useLayoutEffect5,
13393
- useMemo as useMemo23,
13394
- useRef as useRef31,
13756
+ useMemo as useMemo24,
13757
+ useRef as useRef32,
13395
13758
  useState as useState16
13396
13759
  } from "react";
13397
13760
  import {
@@ -13403,25 +13766,25 @@ import {
13403
13766
  PlaneGeometry as PlaneGeometry5,
13404
13767
  Quaternion as Quaternion4,
13405
13768
  Ray,
13406
- Vector3 as Vector316
13769
+ Vector3 as Vector317
13407
13770
  } from "three";
13408
13771
 
13409
13772
  // src/hotspot/hotspot-tooltip.tsx
13410
- import { useEffect as useEffect30, useMemo as useMemo22, useState as useState15 } from "react";
13773
+ import { useEffect as useEffect31, useMemo as useMemo23, useState as useState15 } from "react";
13411
13774
 
13412
13775
  // src/webvr/stereo-html.tsx
13413
- import { useFrame as useFrame14, useThree as useThree21 } from "@react-three/fiber";
13776
+ import { useFrame as useFrame15, useThree as useThree22 } from "@react-three/fiber";
13414
13777
  import {
13415
- useContext as useContext24,
13778
+ useContext as useContext25,
13416
13779
  useLayoutEffect as useLayoutEffect4,
13417
- useRef as useRef30,
13780
+ useRef as useRef31,
13418
13781
  useSyncExternalStore as useSyncExternalStore7
13419
13782
  } from "react";
13420
13783
  import { createRoot } from "react-dom/client";
13421
- import { Vector3 as Vector314 } from "three";
13422
- import { Fragment as Fragment7, jsx as jsx24, jsxs as jsxs15 } from "react/jsx-runtime";
13784
+ import { Vector3 as Vector315 } from "three";
13785
+ import { Fragment as Fragment7, jsx as jsx25, jsxs as jsxs16 } from "react/jsx-runtime";
13423
13786
  function useFallbackStereoView() {
13424
- const runtime = useContext24(WebVRRuntimeContext);
13787
+ const runtime = useContext25(WebVRRuntimeContext);
13425
13788
  const host = runtime?.host ?? null;
13426
13789
  const fallback = useSyncExternalStore7(
13427
13790
  (onStoreChange) => host ? subscribeWebVRHost(host, onStoreChange) : () => void 0,
@@ -13438,10 +13801,10 @@ function ProjectedHtml({
13438
13801
  stereoView,
13439
13802
  eye
13440
13803
  }) {
13441
- const { camera, gl, events, size } = useThree21();
13442
- const group = useRef30(null);
13443
- const overlay = useRef30(null);
13444
- const scratch = useRef30(new Vector314());
13804
+ const { camera, gl, events, size } = useThree22();
13805
+ const group = useRef31(null);
13806
+ const overlay = useRef31(null);
13807
+ const scratch = useRef31(new Vector315());
13445
13808
  const target = events.connected || gl.domElement.parentElement;
13446
13809
  const updatePosition = () => {
13447
13810
  const anchor = group.current;
@@ -13489,7 +13852,7 @@ function ProjectedHtml({
13489
13852
  }, [target]);
13490
13853
  useLayoutEffect4(() => {
13491
13854
  overlay.current?.root.render(
13492
- /* @__PURE__ */ jsx24(
13855
+ /* @__PURE__ */ jsx25(
13493
13856
  "div",
13494
13857
  {
13495
13858
  "aria-hidden": eye === "right" || void 0,
@@ -13500,19 +13863,19 @@ function ProjectedHtml({
13500
13863
  );
13501
13864
  updatePosition();
13502
13865
  });
13503
- useFrame14(updatePosition);
13504
- return /* @__PURE__ */ jsx24("group", { ref: group });
13866
+ useFrame15(updatePosition);
13867
+ return /* @__PURE__ */ jsx25("group", { ref: group });
13505
13868
  }
13506
13869
  function PanoHtml(props) {
13507
13870
  const stereoView = useFallbackStereoView();
13508
- return stereoView ? /* @__PURE__ */ jsxs15(Fragment7, { children: [
13509
- /* @__PURE__ */ jsx24(ProjectedHtml, { ...props, stereoView, eye: "left" }),
13510
- /* @__PURE__ */ jsx24(ProjectedHtml, { ...props, stereoView, eye: "right" })
13511
- ] }) : /* @__PURE__ */ jsx24(ProjectedHtml, { ...props });
13871
+ return stereoView ? /* @__PURE__ */ jsxs16(Fragment7, { children: [
13872
+ /* @__PURE__ */ jsx25(ProjectedHtml, { ...props, stereoView, eye: "left" }),
13873
+ /* @__PURE__ */ jsx25(ProjectedHtml, { ...props, stereoView, eye: "right" })
13874
+ ] }) : /* @__PURE__ */ jsx25(ProjectedHtml, { ...props });
13512
13875
  }
13513
13876
 
13514
13877
  // src/hotspot/hotspot-tooltip.tsx
13515
- import { jsx as jsx25, jsxs as jsxs16 } from "react/jsx-runtime";
13878
+ import { jsx as jsx26, jsxs as jsxs17 } from "react/jsx-runtime";
13516
13879
  var DEFAULT_HOTSPOT_TOOLTIP_OFFSET = 12;
13517
13880
  var DEFAULT_HOTSPOT_TOOLTIP_APPEARANCE = {
13518
13881
  background: "rgba(22, 22, 22, 0.72)",
@@ -13585,15 +13948,15 @@ function HotspotTooltip({
13585
13948
  appearance
13586
13949
  }) {
13587
13950
  const [imageFailed, setImageFailed] = useState15(false);
13588
- useEffect30(() => {
13951
+ useEffect31(() => {
13589
13952
  setImageFailed(false);
13590
13953
  }, [content.image]);
13591
13954
  const showImage = Boolean(content.image) && !imageFailed;
13592
- const resolvedAppearance = useMemo22(
13955
+ const resolvedAppearance = useMemo23(
13593
13956
  () => resolveHotspotTooltipAppearance(appearance),
13594
13957
  [appearance]
13595
13958
  );
13596
- const bubbleStyle = useMemo22(
13959
+ const bubbleStyle = useMemo23(
13597
13960
  () => ({
13598
13961
  background: resolvedAppearance.background,
13599
13962
  border: resolvedAppearance.border,
@@ -13615,8 +13978,8 @@ function HotspotTooltip({
13615
13978
  if (!showImage && !content.text) {
13616
13979
  return null;
13617
13980
  }
13618
- 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: [
13619
- showImage ? /* @__PURE__ */ jsx25(
13981
+ 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: [
13982
+ showImage ? /* @__PURE__ */ jsx26(
13620
13983
  "img",
13621
13984
  {
13622
13985
  alt: content.imageAlt ?? content.text ?? "",
@@ -13625,7 +13988,7 @@ function HotspotTooltip({
13625
13988
  src: content.image
13626
13989
  }
13627
13990
  ) : null,
13628
- content.text ? /* @__PURE__ */ jsx25(
13991
+ content.text ? /* @__PURE__ */ jsx26(
13629
13992
  "p",
13630
13993
  {
13631
13994
  className: "pano-hotspot-tooltip-text",
@@ -13644,10 +14007,10 @@ function HotspotTooltip({
13644
14007
  import {
13645
14008
  MathUtils as MathUtils8,
13646
14009
  PerspectiveCamera as PerspectiveCamera6,
13647
- Vector3 as Vector315
14010
+ Vector3 as Vector316
13648
14011
  } from "three";
13649
- var LOCAL_FORWARD = new Vector315(0, 0, 1);
13650
- var CAMERA_POSITION = new Vector315();
14012
+ var LOCAL_FORWARD = new Vector316(0, 0, 1);
14013
+ var CAMERA_POSITION = new Vector316();
13651
14014
  function applyHotspotTransform(group, camera, orientation2, surfaceQuaternion3, rotation, scaleMode, referenceFov, useAngularScale, worldWidth, worldHeight, distance) {
13652
14015
  if (orientation2 === "billboard") {
13653
14016
  group.quaternion.copy(camera.quaternion);
@@ -13676,7 +14039,7 @@ function fixedScaleFactor(cameraFov, referenceFov) {
13676
14039
  }
13677
14040
 
13678
14041
  // src/hotspot/hotspot-anchor.tsx
13679
- import { jsx as jsx26, jsxs as jsxs17 } from "react/jsx-runtime";
14042
+ import { jsx as jsx27, jsxs as jsxs18 } from "react/jsx-runtime";
13680
14043
  var DEFAULT_FLOATING_DISTANCE = 10;
13681
14044
  var PANORAMA_RADIUS = DEFAULT_PANORAMA_RADIUS;
13682
14045
  var PANORAMA_SURFACE_INSET = 4;
@@ -13686,18 +14049,18 @@ var MAX_ANGULAR_SIZE = 179;
13686
14049
  var DRAG_EPSILON_DEGREES = 1e-3;
13687
14050
  var TOOLTIP_WORLD_BOX = new Box34();
13688
14051
  var TOOLTIP_LOCAL_BOX = new Box34();
13689
- var TOOLTIP_CORNER = new Vector316();
14052
+ var TOOLTIP_CORNER = new Vector317();
13690
14053
  var TOOLTIP_INVERSE = new Matrix44();
13691
- var TOOLTIP_WORLD_CORNER = new Vector316();
13692
- var TOOLTIP_PROJECTED = new Vector316();
13693
- var TOOLTIP_RAY_ORIGIN = new Vector316();
13694
- var TOOLTIP_RAY_FAR = new Vector316();
13695
- var TOOLTIP_RAY_DIRECTION = new Vector316();
14054
+ var TOOLTIP_WORLD_CORNER = new Vector317();
14055
+ var TOOLTIP_PROJECTED = new Vector317();
14056
+ var TOOLTIP_RAY_ORIGIN = new Vector317();
14057
+ var TOOLTIP_RAY_FAR = new Vector317();
14058
+ var TOOLTIP_RAY_DIRECTION = new Vector317();
13696
14059
  var TOOLTIP_RAY = new Ray();
13697
14060
  var TOOLTIP_PLANE = new Plane();
13698
- var TOOLTIP_INTERSECTION = new Vector316();
13699
- var TOOLTIP_PLANE_NORMAL = new Vector316();
13700
- var TOOLTIP_PLANE_POINT = new Vector316();
14061
+ var TOOLTIP_INTERSECTION = new Vector317();
14062
+ var TOOLTIP_PLANE_NORMAL = new Vector317();
14063
+ var TOOLTIP_PLANE_POINT = new Vector317();
13701
14064
  var HOTSPOT_MODE_RENDERING = {
13702
14065
  surface: { orientation: "surface", placement: "surface" },
13703
14066
  billboard: { orientation: "billboard", placement: "floating" }
@@ -13742,7 +14105,7 @@ function createSurfaceQuaternion(position) {
13742
14105
  const inward = outward.clone().negate();
13743
14106
  const pitch = MathUtils9.degToRad(position.pitch);
13744
14107
  const yaw = MathUtils9.degToRad(position.yaw);
13745
- const localUp = new Vector316(
14108
+ const localUp = new Vector317(
13746
14109
  -Math.sin(pitch) * Math.sin(yaw),
13747
14110
  Math.cos(pitch),
13748
14111
  Math.sin(pitch) * Math.cos(yaw)
@@ -13993,24 +14356,24 @@ function HotspotAnchor({
13993
14356
  onPositionChange,
13994
14357
  onDragEnd
13995
14358
  }) {
13996
- const controlsRef = useContext25(PanoramaViewContext);
13997
- const hotspotTargetRegistry = useContext25(HotspotTargetRegistryContext);
13998
- const eventBus = useContext25(PanoEventBusContext);
14359
+ const controlsRef = useContext26(PanoramaViewContext);
14360
+ const hotspotTargetRegistry = useContext26(HotspotTargetRegistryContext);
14361
+ const eventBus = useContext26(PanoEventBusContext);
13999
14362
  const cursorApi = usePanoCursor();
14000
- const { camera, size } = useThree22();
14001
- const groupRef = useRef31(null);
14002
- const tooltipAnchorRef = useRef31(null);
14003
- const dragStateRef = useRef31(null);
14004
- const suppressNextClickRef = useRef31(false);
14363
+ const { camera, size } = useThree23();
14364
+ const groupRef = useRef32(null);
14365
+ const tooltipAnchorRef = useRef32(null);
14366
+ const dragStateRef = useRef32(null);
14367
+ const suppressNextClickRef = useRef32(false);
14005
14368
  const [hovered, setHovered] = useState16(false);
14006
14369
  const [dragging, setDragging] = useState16(false);
14007
14370
  const [pinned, setPinned] = useState16(false);
14008
- const tooltipContent = useMemo23(
14371
+ const tooltipContent = useMemo24(
14009
14372
  () => resolveHotspotTooltipContent(tooltip),
14010
14373
  [tooltip]
14011
14374
  );
14012
14375
  const normalizedPosition = normalizePanoPosition(position);
14013
- useEffect31(() => {
14376
+ useEffect32(() => {
14014
14377
  if (!hotspotTargetRegistry) {
14015
14378
  return;
14016
14379
  }
@@ -14027,17 +14390,17 @@ function HotspotAnchor({
14027
14390
  scaledWidth,
14028
14391
  scaledHeight
14029
14392
  );
14030
- const worldPosition = useMemo23(
14393
+ const worldPosition = useMemo24(
14031
14394
  () => panoPositionToVector3(normalizedPosition, resolvedDistance),
14032
14395
  [normalizedPosition.pitch, normalizedPosition.yaw, resolvedDistance]
14033
14396
  );
14034
- const surfaceQuaternion3 = useMemo23(
14397
+ const surfaceQuaternion3 = useMemo24(
14035
14398
  () => createSurfaceQuaternion(normalizedPosition),
14036
14399
  [normalizedPosition.pitch, normalizedPosition.yaw]
14037
14400
  );
14038
14401
  const worldWidth = angularSizeToWorldSize(scaledWidth, resolvedDistance);
14039
14402
  const worldHeight = angularSizeToWorldSize(scaledHeight, resolvedDistance);
14040
- const focusGeometry = useMemo23(() => {
14403
+ const focusGeometry = useMemo24(() => {
14041
14404
  const planeGeometry = new PlaneGeometry5(1, 1);
14042
14405
  const geometry = new EdgesGeometry(planeGeometry);
14043
14406
  planeGeometry.dispose();
@@ -14064,14 +14427,14 @@ function HotspotAnchor({
14064
14427
  });
14065
14428
  const tooltipOpen = visible && tooltipContent !== null && isTooltipOpen(tooltipTrigger, hovered, focused, pinned);
14066
14429
  const cursorClaimId = hotspotCursorClaimId(id);
14067
- useEffect31(
14430
+ useEffect32(
14068
14431
  () => () => {
14069
14432
  dragStateRef.current?.releaseInteractionLock();
14070
14433
  dragStateRef.current = null;
14071
14434
  },
14072
14435
  []
14073
14436
  );
14074
- useEffect31(() => {
14437
+ useEffect32(() => {
14075
14438
  if (!cursorApi) {
14076
14439
  return;
14077
14440
  }
@@ -14093,14 +14456,14 @@ function HotspotAnchor({
14093
14456
  hovered,
14094
14457
  visible
14095
14458
  ]);
14096
- useEffect31(
14459
+ useEffect32(
14097
14460
  () => () => {
14098
14461
  cursorApi?.release(cursorClaimId);
14099
14462
  },
14100
14463
  [cursorApi, cursorClaimId]
14101
14464
  );
14102
- useEffect31(() => () => focusGeometry.dispose(), [focusGeometry]);
14103
- useEffect31(() => {
14465
+ useEffect32(() => () => focusGeometry.dispose(), [focusGeometry]);
14466
+ useEffect32(() => {
14104
14467
  if (tooltipTrigger !== "click") {
14105
14468
  setPinned(false);
14106
14469
  return;
@@ -14109,12 +14472,12 @@ function HotspotAnchor({
14109
14472
  setPinned(false);
14110
14473
  });
14111
14474
  }, [eventBus, tooltipTrigger]);
14112
- useEffect31(() => {
14475
+ useEffect32(() => {
14113
14476
  if (tooltipTrigger !== "hover") {
14114
14477
  setHovered(false);
14115
14478
  }
14116
14479
  }, [tooltipTrigger]);
14117
- useEffect31(() => {
14480
+ useEffect32(() => {
14118
14481
  if (acceptsPointer) {
14119
14482
  return;
14120
14483
  }
@@ -14170,7 +14533,7 @@ function HotspotAnchor({
14170
14533
  worldHeight,
14171
14534
  worldWidth
14172
14535
  ]);
14173
- useFrame15((state) => {
14536
+ useFrame16((state) => {
14174
14537
  const group = groupRef.current;
14175
14538
  if (!group) {
14176
14539
  return;
@@ -14229,7 +14592,7 @@ function HotspotAnchor({
14229
14592
  setHovered(true);
14230
14593
  }
14231
14594
  };
14232
- return /* @__PURE__ */ jsxs17(
14595
+ return /* @__PURE__ */ jsxs18(
14233
14596
  "group",
14234
14597
  {
14235
14598
  ref: groupRef,
@@ -14306,18 +14669,18 @@ function HotspotAnchor({
14306
14669
  } : void 0,
14307
14670
  onPointerUp: acceptsPointer ? (event) => releasePointer(event, true) : void 0,
14308
14671
  children: [
14309
- focused ? focusContent ?? /* @__PURE__ */ jsx26(
14672
+ focused ? focusContent ?? /* @__PURE__ */ jsx27(
14310
14673
  "lineSegments",
14311
14674
  {
14312
14675
  geometry: focusGeometry,
14313
14676
  position: [0, 0, 0.01],
14314
14677
  renderOrder: renderOrder + 1,
14315
14678
  scale: [1.12, 1.12, 1],
14316
- children: /* @__PURE__ */ jsx26("lineBasicMaterial", { color: "#f5fbfc", depthTest: false })
14679
+ children: /* @__PURE__ */ jsx27("lineBasicMaterial", { color: "#f5fbfc", depthTest: false })
14317
14680
  }
14318
14681
  ) : null,
14319
14682
  children,
14320
- tooltipOpen && tooltipContent ? /* @__PURE__ */ jsx26("group", { ref: tooltipAnchorRef, children: /* @__PURE__ */ jsx26(
14683
+ tooltipOpen && tooltipContent ? /* @__PURE__ */ jsx27("group", { ref: tooltipAnchorRef, children: /* @__PURE__ */ jsx27(
14321
14684
  HotspotTooltip,
14322
14685
  {
14323
14686
  appearance: tooltipAppearance,
@@ -14334,11 +14697,11 @@ function HotspotAnchor({
14334
14697
  // src/hotspot/hotspot-plane.tsx
14335
14698
  import {
14336
14699
  DoubleSide as DoubleSide4,
14337
- Mesh as Mesh5,
14700
+ Mesh as Mesh6,
14338
14701
  MeshBasicMaterial,
14339
14702
  Vector2 as Vector26
14340
14703
  } from "three";
14341
- import { jsx as jsx27, jsxs as jsxs18 } from "react/jsx-runtime";
14704
+ import { jsx as jsx28, jsxs as jsxs19 } from "react/jsx-runtime";
14342
14705
  var HOTSPOT_ALPHA_CUTOFF = 0.05;
14343
14706
  var SAMPLE_UV = new Vector26();
14344
14707
  var RAYCAST_HITS = [];
@@ -14415,7 +14778,7 @@ function sampleTextureAlpha(texture, u, v) {
14415
14778
  function hotspotPlaneRaycast(raycaster, intersects2) {
14416
14779
  const material = Array.isArray(this.material) ? this.material[0] : this.material;
14417
14780
  if (!(material instanceof MeshBasicMaterial)) {
14418
- Mesh5.prototype.raycast.call(this, raycaster, intersects2);
14781
+ Mesh6.prototype.raycast.call(this, raycaster, intersects2);
14419
14782
  return;
14420
14783
  }
14421
14784
  const cutoff = Math.max(material.alphaTest, HOTSPOT_ALPHA_CUTOFF);
@@ -14423,7 +14786,7 @@ function hotspotPlaneRaycast(raycaster, intersects2) {
14423
14786
  return;
14424
14787
  }
14425
14788
  RAYCAST_HITS.length = 0;
14426
- Mesh5.prototype.raycast.call(this, raycaster, RAYCAST_HITS);
14789
+ Mesh6.prototype.raycast.call(this, raycaster, RAYCAST_HITS);
14427
14790
  const map = material.map;
14428
14791
  for (const hit of RAYCAST_HITS) {
14429
14792
  if (!map || !hit.uv) {
@@ -14440,9 +14803,9 @@ function HotspotPlane({
14440
14803
  map,
14441
14804
  opacity
14442
14805
  }) {
14443
- return /* @__PURE__ */ jsxs18("mesh", { raycast: hotspotPlaneRaycast, children: [
14444
- /* @__PURE__ */ jsx27("planeGeometry", { args: [1, 1] }),
14445
- /* @__PURE__ */ jsx27(
14806
+ return /* @__PURE__ */ jsxs19("mesh", { raycast: hotspotPlaneRaycast, children: [
14807
+ /* @__PURE__ */ jsx28("planeGeometry", { args: [1, 1] }),
14808
+ /* @__PURE__ */ jsx28(
14446
14809
  PanoBasicMaterial,
14447
14810
  {
14448
14811
  target: "hotspot",
@@ -14458,15 +14821,15 @@ function HotspotPlane({
14458
14821
  }
14459
14822
 
14460
14823
  // src/hotspot/image-hotspot.tsx
14461
- import { jsx as jsx28 } from "react/jsx-runtime";
14824
+ import { jsx as jsx29 } from "react/jsx-runtime";
14462
14825
  function useHotspotImageTexture(src, onLoad, onError) {
14463
- const gl = useThree23((state) => state.gl);
14826
+ const gl = useThree24((state) => state.gl);
14464
14827
  const [texture, setTexture] = useState17(null);
14465
- const onLoadRef = useRef32(onLoad);
14466
- const onErrorRef = useRef32(onError);
14828
+ const onLoadRef = useRef33(onLoad);
14829
+ const onErrorRef = useRef33(onError);
14467
14830
  onLoadRef.current = onLoad;
14468
14831
  onErrorRef.current = onError;
14469
- useEffect32(() => {
14832
+ useEffect33(() => {
14470
14833
  let active = true;
14471
14834
  setTexture(null);
14472
14835
  if (!src) {
@@ -14504,7 +14867,7 @@ function useHotspotImageTexture(src, onLoad, onError) {
14504
14867
  active = false;
14505
14868
  };
14506
14869
  }, [gl, src]);
14507
- useEffect32(
14870
+ useEffect33(
14508
14871
  () => () => {
14509
14872
  texture?.dispose();
14510
14873
  },
@@ -14522,11 +14885,11 @@ function ImageHotspot({
14522
14885
  ...anchorProps
14523
14886
  }) {
14524
14887
  const texture = useHotspotImageTexture(src, onLoad, onError);
14525
- return /* @__PURE__ */ jsx28(HotspotAnchor, { ...anchorProps, height, width, children: /* @__PURE__ */ jsx28(HotspotPlane, { map: texture, opacity }) });
14888
+ return /* @__PURE__ */ jsx29(HotspotAnchor, { ...anchorProps, height, width, children: /* @__PURE__ */ jsx29(HotspotPlane, { map: texture, opacity }) });
14526
14889
  }
14527
14890
 
14528
14891
  // src/hotspot/polygon-hotspot.tsx
14529
- import { useEffect as useEffect33, useMemo as useMemo24, useRef as useRef34 } from "react";
14892
+ import { useEffect as useEffect34, useMemo as useMemo25, useRef as useRef35 } from "react";
14530
14893
  import {
14531
14894
  BufferGeometry as BufferGeometry2,
14532
14895
  DoubleSide as DoubleSide5,
@@ -14535,20 +14898,20 @@ import {
14535
14898
  Quaternion as Quaternion5,
14536
14899
  ShapeUtils,
14537
14900
  Vector2 as Vector27,
14538
- Vector3 as Vector318
14901
+ Vector3 as Vector319
14539
14902
  } from "three";
14540
14903
 
14541
14904
  // src/hotspot/hotspot-stroke-line.tsx
14542
14905
  import { Line } from "@react-three/drei";
14543
- import { useFrame as useFrame16, useThree as useThree24 } from "@react-three/fiber";
14544
- import { useLayoutEffect as useLayoutEffect6, useRef as useRef33 } from "react";
14906
+ import { useFrame as useFrame17, useThree as useThree25 } from "@react-three/fiber";
14907
+ import { useLayoutEffect as useLayoutEffect6, useRef as useRef34 } from "react";
14545
14908
  import {
14546
14909
  MathUtils as MathUtils10,
14547
14910
  PerspectiveCamera as PerspectiveCamera7,
14548
- Vector3 as Vector317
14911
+ Vector3 as Vector318
14549
14912
  } from "three";
14550
- import { jsx as jsx29 } from "react/jsx-runtime";
14551
- var LINE_WORLD_POSITION = new Vector317();
14913
+ import { jsx as jsx30 } from "react/jsx-runtime";
14914
+ var LINE_WORLD_POSITION = new Vector318();
14552
14915
  function applyScreenSpaceDashScale(object, camera, viewportHeight) {
14553
14916
  const material = object?.material;
14554
14917
  if (!object || typeof material?.dashScale !== "number") {
@@ -14578,8 +14941,8 @@ function HotspotStrokeLine({
14578
14941
  dashSize,
14579
14942
  gapSize
14580
14943
  }) {
14581
- const lineRef = useRef33(null);
14582
- const { camera, size } = useThree24();
14944
+ const lineRef = useRef34(null);
14945
+ const { camera, size } = useThree25();
14583
14946
  const dash = resolveDash(dashSize, gapSize);
14584
14947
  useLayoutEffect6(() => {
14585
14948
  if (!dash.dashed) {
@@ -14587,13 +14950,13 @@ function HotspotStrokeLine({
14587
14950
  }
14588
14951
  applyScreenSpaceDashScale(lineRef.current, camera, size.height);
14589
14952
  }, [camera, dash.dashed, dash.dashSize, dash.gapSize, size.height]);
14590
- useFrame16((state) => {
14953
+ useFrame17((state) => {
14591
14954
  if (!dash.dashed) {
14592
14955
  return;
14593
14956
  }
14594
14957
  applyScreenSpaceDashScale(lineRef.current, state.camera, state.size.height);
14595
14958
  });
14596
- return /* @__PURE__ */ jsx29(
14959
+ return /* @__PURE__ */ jsx30(
14597
14960
  Line,
14598
14961
  {
14599
14962
  ref: lineRef,
@@ -14615,7 +14978,7 @@ function HotspotStrokeLine({
14615
14978
  }
14616
14979
 
14617
14980
  // src/hotspot/polygon-hotspot.tsx
14618
- import { jsx as jsx30, jsxs as jsxs19 } from "react/jsx-runtime";
14981
+ import { jsx as jsx31, jsxs as jsxs20 } from "react/jsx-runtime";
14619
14982
  var POLYGON_RADIUS = 990;
14620
14983
  var MAX_FILL_SEGMENT_DEGREES = 7;
14621
14984
  function cloneVertices(vertices) {
@@ -14687,7 +15050,7 @@ function polygonContainsDirection(vertices, direction) {
14687
15050
  }
14688
15051
  function fitsHemisphere(vertices) {
14689
15052
  const directions = vertices.map((vertex) => panoPositionToVector3(vertex).normalize());
14690
- const candidates = [new Vector318()];
15053
+ const candidates = [new Vector319()];
14691
15054
  for (const direction of directions) {
14692
15055
  candidates[0].add(direction);
14693
15056
  candidates.push(direction.clone());
@@ -14711,7 +15074,7 @@ function validatePolygonVertices(vertices) {
14711
15074
  if (hasSelfIntersection(unwrapped)) {
14712
15075
  issues.push({ code: "self_intersection", message: "Polygon edges cannot cross." });
14713
15076
  }
14714
- if (polygonContainsDirection(normalized, new Vector318(0, 1, 0)) || polygonContainsDirection(normalized, new Vector318(0, -1, 0))) {
15077
+ if (polygonContainsDirection(normalized, new Vector319(0, 1, 0)) || polygonContainsDirection(normalized, new Vector319(0, -1, 0))) {
14715
15078
  issues.push({ code: "contains_pole", message: "Polygons cannot contain a panorama pole." });
14716
15079
  }
14717
15080
  if (!fitsHemisphere(normalized)) {
@@ -14722,7 +15085,7 @@ function validatePolygonVertices(vertices) {
14722
15085
  function polygonCenter(vertices) {
14723
15086
  const sum = vertices.reduce(
14724
15087
  (total, vertex) => total.add(panoPositionToVector3(vertex).normalize()),
14725
- new Vector318()
15088
+ new Vector319()
14726
15089
  );
14727
15090
  return sum.lengthSq() > 1e-8 ? vector3ToPanoPosition(sum) : normalizePanoPosition(vertices[0]);
14728
15091
  }
@@ -14731,7 +15094,7 @@ function surfaceQuaternion(position) {
14731
15094
  const inward = outward.clone().negate();
14732
15095
  const pitch = position.pitch * Math.PI / 180;
14733
15096
  const yaw = position.yaw * Math.PI / 180;
14734
- const localUp = new Vector318(
15097
+ const localUp = new Vector319(
14735
15098
  -Math.sin(pitch) * Math.sin(yaw),
14736
15099
  Math.cos(pitch),
14737
15100
  Math.sin(pitch) * Math.cos(yaw)
@@ -14744,7 +15107,7 @@ function makeWorldToLocal(center) {
14744
15107
  return new Matrix45().compose(
14745
15108
  panoPositionToVector3(center, POLYGON_RADIUS),
14746
15109
  surfaceQuaternion(center),
14747
- new Vector318(1, 1, 1)
15110
+ new Vector319(1, 1, 1)
14748
15111
  ).invert();
14749
15112
  }
14750
15113
  function projectedPoint(a, b, c, weightB, weightC, radius, worldToLocal) {
@@ -14871,24 +15234,24 @@ function PolygonHotspot({
14871
15234
  onInvalid,
14872
15235
  ...anchorProps
14873
15236
  }) {
14874
- const issues = useMemo24(() => validatePolygonVertices(vertices), [vertices]);
15237
+ const issues = useMemo25(() => validatePolygonVertices(vertices), [vertices]);
14875
15238
  const valid = issues.length === 0;
14876
- const center = useMemo24(() => valid ? polygonCenter(vertices) : null, [valid, vertices]);
14877
- const fillGeometry = useMemo24(
15239
+ const center = useMemo25(() => valid ? polygonCenter(vertices) : null, [valid, vertices]);
15240
+ const fillGeometry = useMemo25(
14878
15241
  () => valid && center ? makeFillGeometry(vertices, center) : null,
14879
15242
  [center, valid, vertices]
14880
15243
  );
14881
- const strokePoints = useMemo24(
15244
+ const strokePoints = useMemo25(
14882
15245
  () => valid && center ? makeStrokePositions(vertices, center) : null,
14883
15246
  [center, valid, vertices]
14884
15247
  );
14885
15248
  const resolvedStrokeOpacity = Math.max(0, Math.min(strokeOpacity, 1));
14886
- const startVerticesRef = useRef34(null);
15249
+ const startVerticesRef = useRef35(null);
14887
15250
  const issuesKey = issues.map((issue) => issue.code).join(",");
14888
- useEffect33(() => {
15251
+ useEffect34(() => {
14889
15252
  if (!valid) onInvalid?.(issues);
14890
15253
  }, [issues, issuesKey, onInvalid, valid]);
14891
- useEffect33(() => () => fillGeometry?.dispose(), [fillGeometry]);
15254
+ useEffect34(() => () => fillGeometry?.dispose(), [fillGeometry]);
14892
15255
  if (!valid || !center || !fillGeometry || !strokePoints || strokePoints.length < 2) {
14893
15256
  return null;
14894
15257
  }
@@ -14903,7 +15266,7 @@ function PolygonHotspot({
14903
15266
  startPosition: event.startPosition
14904
15267
  });
14905
15268
  };
14906
- return /* @__PURE__ */ jsxs19(
15269
+ return /* @__PURE__ */ jsxs20(
14907
15270
  HotspotAnchor,
14908
15271
  {
14909
15272
  ...anchorProps,
@@ -14918,7 +15281,7 @@ function PolygonHotspot({
14918
15281
  draggable,
14919
15282
  interactive,
14920
15283
  useAngularScale: false,
14921
- focusContent: /* @__PURE__ */ jsx30(
15284
+ focusContent: /* @__PURE__ */ jsx31(
14922
15285
  HotspotStrokeLine,
14923
15286
  {
14924
15287
  color: "#75cbd3",
@@ -14940,7 +15303,7 @@ function PolygonHotspot({
14940
15303
  startVerticesRef.current = null;
14941
15304
  },
14942
15305
  children: [
14943
- /* @__PURE__ */ jsx30("mesh", { geometry: fillGeometry, renderOrder, children: /* @__PURE__ */ jsx30(
15306
+ /* @__PURE__ */ jsx31("mesh", { geometry: fillGeometry, renderOrder, children: /* @__PURE__ */ jsx31(
14944
15307
  "meshBasicMaterial",
14945
15308
  {
14946
15309
  color: fill,
@@ -14950,7 +15313,7 @@ function PolygonHotspot({
14950
15313
  transparent: true
14951
15314
  }
14952
15315
  ) }),
14953
- /* @__PURE__ */ jsx30(
15316
+ /* @__PURE__ */ jsx31(
14954
15317
  HotspotStrokeLine,
14955
15318
  {
14956
15319
  color: stroke,
@@ -14968,14 +15331,14 @@ function PolygonHotspot({
14968
15331
  }
14969
15332
 
14970
15333
  // src/hotspot/polyline-hotspot.tsx
14971
- import { useEffect as useEffect34, useMemo as useMemo25, useRef as useRef35 } from "react";
15334
+ import { useEffect as useEffect35, useMemo as useMemo26, useRef as useRef36 } from "react";
14972
15335
  import {
14973
15336
  MathUtils as MathUtils11,
14974
15337
  Matrix4 as Matrix46,
14975
15338
  Quaternion as Quaternion6,
14976
- Vector3 as Vector319
15339
+ Vector3 as Vector320
14977
15340
  } from "three";
14978
- import { jsx as jsx31 } from "react/jsx-runtime";
15341
+ import { jsx as jsx32 } from "react/jsx-runtime";
14979
15342
  var POLYLINE_RADIUS = 990;
14980
15343
  var MAX_SEGMENT_DEGREES = 7;
14981
15344
  function cloneVertices2(vertices) {
@@ -15000,7 +15363,7 @@ function unwrapVertices(vertices) {
15000
15363
  function polylineCenter(vertices) {
15001
15364
  const sum = vertices.reduce(
15002
15365
  (total, vertex) => total.add(panoPositionToVector3(vertex).normalize()),
15003
- new Vector319()
15366
+ new Vector320()
15004
15367
  );
15005
15368
  return sum.lengthSq() > 1e-8 ? vector3ToPanoPosition(sum) : normalizePanoPosition(vertices[0]);
15006
15369
  }
@@ -15009,7 +15372,7 @@ function surfaceQuaternion2(position) {
15009
15372
  const inward = outward.clone().negate();
15010
15373
  const pitch = MathUtils11.degToRad(position.pitch);
15011
15374
  const yaw = MathUtils11.degToRad(position.yaw);
15012
- const localUp = new Vector319(
15375
+ const localUp = new Vector320(
15013
15376
  -Math.sin(pitch) * Math.sin(yaw),
15014
15377
  Math.cos(pitch),
15015
15378
  Math.sin(pitch) * Math.cos(yaw)
@@ -15022,7 +15385,7 @@ function makeWorldToLocal2(center) {
15022
15385
  return new Matrix46().compose(
15023
15386
  panoPositionToVector3(center, POLYLINE_RADIUS),
15024
15387
  surfaceQuaternion2(center),
15025
- new Vector319(1, 1, 1)
15388
+ new Vector320(1, 1, 1)
15026
15389
  ).invert();
15027
15390
  }
15028
15391
  function subdivisionSteps(vertices) {
@@ -15092,16 +15455,16 @@ function PolylineHotspot({
15092
15455
  onInvalid,
15093
15456
  ...anchorProps
15094
15457
  }) {
15095
- const issues = useMemo25(() => validatePolylineVertices(vertices), [vertices]);
15458
+ const issues = useMemo26(() => validatePolylineVertices(vertices), [vertices]);
15096
15459
  const valid = issues.length === 0;
15097
- const center = useMemo25(() => valid ? polylineCenter(vertices) : null, [valid, vertices]);
15098
- const linePoints = useMemo25(
15460
+ const center = useMemo26(() => valid ? polylineCenter(vertices) : null, [valid, vertices]);
15461
+ const linePoints = useMemo26(
15099
15462
  () => valid && center ? makeLinePositions(vertices, center) : null,
15100
15463
  [center, valid, vertices]
15101
15464
  );
15102
15465
  const opacity = Math.max(0, Math.min(strokeOpacity, 1));
15103
- const startVerticesRef = useRef35(null);
15104
- useEffect34(() => {
15466
+ const startVerticesRef = useRef36(null);
15467
+ useEffect35(() => {
15105
15468
  if (!valid) onInvalid?.(issues);
15106
15469
  }, [issues, onInvalid, valid]);
15107
15470
  if (!valid || !center || !linePoints || linePoints.length < 2) return null;
@@ -15115,7 +15478,7 @@ function PolylineHotspot({
15115
15478
  startPosition: event.startPosition
15116
15479
  });
15117
15480
  };
15118
- return /* @__PURE__ */ jsx31(
15481
+ return /* @__PURE__ */ jsx32(
15119
15482
  HotspotAnchor,
15120
15483
  {
15121
15484
  ...anchorProps,
@@ -15129,7 +15492,7 @@ function PolylineHotspot({
15129
15492
  renderOrder,
15130
15493
  draggable,
15131
15494
  useAngularScale: false,
15132
- focusContent: /* @__PURE__ */ jsx31(
15495
+ focusContent: /* @__PURE__ */ jsx32(
15133
15496
  HotspotStrokeLine,
15134
15497
  {
15135
15498
  color: "#75cbd3",
@@ -15150,7 +15513,7 @@ function PolylineHotspot({
15150
15513
  emitVerticesChange(event, onDragEnd);
15151
15514
  startVerticesRef.current = null;
15152
15515
  },
15153
- children: /* @__PURE__ */ jsx31(
15516
+ children: /* @__PURE__ */ jsx32(
15154
15517
  HotspotStrokeLine,
15155
15518
  {
15156
15519
  color: stroke,
@@ -15167,7 +15530,7 @@ function PolylineHotspot({
15167
15530
  }
15168
15531
 
15169
15532
  // src/hotspot/graphic-hotspot.tsx
15170
- import { useEffect as useEffect35, useRef as useRef36, useState as useState18 } from "react";
15533
+ import { useEffect as useEffect36, useRef as useRef37, useState as useState18 } from "react";
15171
15534
  import {
15172
15535
  CanvasTexture,
15173
15536
  ClampToEdgeWrapping as ClampToEdgeWrapping4,
@@ -15175,7 +15538,7 @@ import {
15175
15538
  LinearMipmapLinearFilter as LinearMipmapLinearFilter4,
15176
15539
  SRGBColorSpace as SRGBColorSpace6
15177
15540
  } from "three";
15178
- import { jsx as jsx32 } from "react/jsx-runtime";
15541
+ import { jsx as jsx33 } from "react/jsx-runtime";
15179
15542
  var GRAPHIC_TEXTURE_SIZE = 512;
15180
15543
  function resolveStrokeWidth(value) {
15181
15544
  return Number.isFinite(value) ? Math.max(value, 0) : 8;
@@ -15365,11 +15728,11 @@ function createGraphicTexture(graphic, aspectWidth, aspectHeight) {
15365
15728
  }
15366
15729
  function useGraphicTexture(graphic, aspectWidth, aspectHeight, onLoad, onError) {
15367
15730
  const [texture, setTexture] = useState18(null);
15368
- const onLoadRef = useRef36(onLoad);
15369
- const onErrorRef = useRef36(onError);
15731
+ const onLoadRef = useRef37(onLoad);
15732
+ const onErrorRef = useRef37(onError);
15370
15733
  onLoadRef.current = onLoad;
15371
15734
  onErrorRef.current = onError;
15372
- useEffect35(() => {
15735
+ useEffect36(() => {
15373
15736
  let nextTexture = null;
15374
15737
  try {
15375
15738
  nextTexture = createGraphicTexture(graphic, aspectWidth, aspectHeight);
@@ -15395,20 +15758,20 @@ function CanvasGraphicHotspot({
15395
15758
  ...anchorProps
15396
15759
  }) {
15397
15760
  const texture = useGraphicTexture(graphic, width, height, onLoad, onError);
15398
- return /* @__PURE__ */ jsx32(HotspotAnchor, { ...anchorProps, height, width, children: /* @__PURE__ */ jsx32(HotspotPlane, { map: texture, opacity }) });
15761
+ return /* @__PURE__ */ jsx33(HotspotAnchor, { ...anchorProps, height, width, children: /* @__PURE__ */ jsx33(HotspotPlane, { map: texture, opacity }) });
15399
15762
  }
15400
15763
  function GraphicHotspot(props) {
15401
15764
  const { graphic, ...restProps } = props;
15402
15765
  if (graphic.kind === "svg") {
15403
15766
  const imageProps = restProps;
15404
- return /* @__PURE__ */ jsx32(ImageHotspot, { ...imageProps, src: graphic.src });
15767
+ return /* @__PURE__ */ jsx33(ImageHotspot, { ...imageProps, src: graphic.src });
15405
15768
  }
15406
- return /* @__PURE__ */ jsx32(CanvasGraphicHotspot, { ...restProps, graphic });
15769
+ return /* @__PURE__ */ jsx33(CanvasGraphicHotspot, { ...restProps, graphic });
15407
15770
  }
15408
15771
 
15409
15772
  // src/hotspot/sequence-hotspot.tsx
15410
- import { useFrame as useFrame17, useThree as useThree25 } from "@react-three/fiber";
15411
- import { useEffect as useEffect36, useRef as useRef37, useState as useState19 } from "react";
15773
+ import { useFrame as useFrame18, useThree as useThree26 } from "@react-three/fiber";
15774
+ import { useEffect as useEffect37, useRef as useRef38, useState as useState19 } from "react";
15412
15775
  import {
15413
15776
  ClampToEdgeWrapping as ClampToEdgeWrapping5,
15414
15777
  LinearFilter as LinearFilter8,
@@ -15416,7 +15779,7 @@ import {
15416
15779
  SRGBColorSpace as SRGBColorSpace7,
15417
15780
  TextureLoader as TextureLoader6
15418
15781
  } from "three";
15419
- import { jsx as jsx33 } from "react/jsx-runtime";
15782
+ import { jsx as jsx34 } from "react/jsx-runtime";
15420
15783
  var DEFAULT_SEQUENCE_FPS = 12;
15421
15784
  function resolveFps(value) {
15422
15785
  return Number.isFinite(value) && value > 0 ? value : DEFAULT_SEQUENCE_FPS;
@@ -15430,13 +15793,13 @@ function useSpriteTexture({
15430
15793
  onError,
15431
15794
  onLoadProgress
15432
15795
  }) {
15433
- const gl = useThree25((state) => state.gl);
15796
+ const gl = useThree26((state) => state.gl);
15434
15797
  const [texture, setTexture] = useState19(null);
15435
- const onErrorRef = useRef37(onError);
15436
- const onLoadProgressRef = useRef37(onLoadProgress);
15798
+ const onErrorRef = useRef38(onError);
15799
+ const onLoadProgressRef = useRef38(onLoadProgress);
15437
15800
  onErrorRef.current = onError;
15438
15801
  onLoadProgressRef.current = onLoadProgress;
15439
- useEffect36(() => {
15802
+ useEffect37(() => {
15440
15803
  let active = true;
15441
15804
  setTexture(null);
15442
15805
  if (!src) {
@@ -15477,7 +15840,7 @@ function useSpriteTexture({
15477
15840
  active = false;
15478
15841
  };
15479
15842
  }, [gl, id, src]);
15480
- useEffect36(
15843
+ useEffect37(
15481
15844
  () => () => {
15482
15845
  texture?.dispose();
15483
15846
  },
@@ -15507,23 +15870,23 @@ function SequenceHotspot({
15507
15870
  const frameCount = resolveFrameCount(requestedFrameCount);
15508
15871
  const safeFps = resolveFps(fps);
15509
15872
  const [frameIndex, setFrameIndex] = useState19(0);
15510
- const elapsedRef = useRef37(0);
15511
- const frameIndexRef = useRef37(0);
15512
- const endedRef = useRef37(false);
15513
- const lastPlaybackStateRef = useRef37(null);
15514
- const onFrameChangeRef = useRef37(onFrameChange);
15515
- const onPlaybackStateChangeRef = useRef37(onPlaybackStateChange);
15516
- const onEndedRef = useRef37(onEnded);
15873
+ const elapsedRef = useRef38(0);
15874
+ const frameIndexRef = useRef38(0);
15875
+ const endedRef = useRef38(false);
15876
+ const lastPlaybackStateRef = useRef38(null);
15877
+ const onFrameChangeRef = useRef38(onFrameChange);
15878
+ const onPlaybackStateChangeRef = useRef38(onPlaybackStateChange);
15879
+ const onEndedRef = useRef38(onEnded);
15517
15880
  onFrameChangeRef.current = onFrameChange;
15518
15881
  onPlaybackStateChangeRef.current = onPlaybackStateChange;
15519
15882
  onEndedRef.current = onEnded;
15520
- useEffect36(() => {
15883
+ useEffect37(() => {
15521
15884
  elapsedRef.current = 0;
15522
15885
  frameIndexRef.current = 0;
15523
15886
  endedRef.current = false;
15524
15887
  setFrameIndex(0);
15525
15888
  }, [frameCount, frameDirection, src]);
15526
- useEffect36(() => {
15889
+ useEffect37(() => {
15527
15890
  if (!texture) {
15528
15891
  return;
15529
15892
  }
@@ -15537,13 +15900,13 @@ function SequenceHotspot({
15537
15900
  );
15538
15901
  texture.needsUpdate = true;
15539
15902
  }, [frameCount, frameDirection, frameIndex, texture]);
15540
- useEffect36(() => {
15903
+ useEffect37(() => {
15541
15904
  if (!texture) {
15542
15905
  return;
15543
15906
  }
15544
15907
  onFrameChangeRef.current?.({ id, index: 0, src });
15545
15908
  }, [id, src, texture]);
15546
- useEffect36(() => {
15909
+ useEffect37(() => {
15547
15910
  if (!texture) {
15548
15911
  return;
15549
15912
  }
@@ -15562,7 +15925,7 @@ function SequenceHotspot({
15562
15925
  onPlaybackStateChangeRef.current?.(nextState);
15563
15926
  }
15564
15927
  }, [playing, texture]);
15565
- useFrame17((_, deltaSeconds) => {
15928
+ useFrame18((_, deltaSeconds) => {
15566
15929
  if (!texture || !playing || endedRef.current) {
15567
15930
  return;
15568
15931
  }
@@ -15592,12 +15955,12 @@ function SequenceHotspot({
15592
15955
  onFrameChangeRef.current?.({ id, index: nextIndex, src });
15593
15956
  }
15594
15957
  });
15595
- return /* @__PURE__ */ jsx33(HotspotAnchor, { ...anchorProps, id, height, width, children: /* @__PURE__ */ jsx33(HotspotPlane, { map: texture, opacity }) });
15958
+ return /* @__PURE__ */ jsx34(HotspotAnchor, { ...anchorProps, id, height, width, children: /* @__PURE__ */ jsx34(HotspotPlane, { map: texture, opacity }) });
15596
15959
  }
15597
15960
 
15598
15961
  // src/hotspot/video-hotspot.tsx
15599
- import { useThree as useThree26 } from "@react-three/fiber";
15600
- import { useEffect as useEffect37, useRef as useRef38, useState as useState20 } from "react";
15962
+ import { useThree as useThree27 } from "@react-three/fiber";
15963
+ import { useEffect as useEffect38, useRef as useRef39, useState as useState20 } from "react";
15601
15964
  import {
15602
15965
  ClampToEdgeWrapping as ClampToEdgeWrapping6,
15603
15966
  LinearFilter as LinearFilter9,
@@ -15606,7 +15969,7 @@ import {
15606
15969
  TextureLoader as TextureLoader7,
15607
15970
  VideoTexture as VideoTexture2
15608
15971
  } from "three";
15609
- import { jsx as jsx34 } from "react/jsx-runtime";
15972
+ import { jsx as jsx35 } from "react/jsx-runtime";
15610
15973
  function clampVolume2(volume) {
15611
15974
  if (!Number.isFinite(volume)) {
15612
15975
  return 1;
@@ -15614,11 +15977,11 @@ function clampVolume2(volume) {
15614
15977
  return Math.max(0, Math.min(volume, 1));
15615
15978
  }
15616
15979
  function usePosterTexture2(id, poster, onError) {
15617
- const gl = useThree26((state) => state.gl);
15980
+ const gl = useThree27((state) => state.gl);
15618
15981
  const [texture, setTexture] = useState20(null);
15619
- const onErrorRef = useRef38(onError);
15982
+ const onErrorRef = useRef39(onError);
15620
15983
  onErrorRef.current = onError;
15621
- useEffect37(() => {
15984
+ useEffect38(() => {
15622
15985
  let active = true;
15623
15986
  setTexture(null);
15624
15987
  if (!poster) {
@@ -15655,7 +16018,7 @@ function usePosterTexture2(id, poster, onError) {
15655
16018
  active = false;
15656
16019
  };
15657
16020
  }, [gl, id, poster]);
15658
- useEffect37(
16021
+ useEffect38(
15659
16022
  () => () => {
15660
16023
  texture?.dispose();
15661
16024
  },
@@ -15674,13 +16037,13 @@ function useVideoResource({
15674
16037
  src
15675
16038
  }) {
15676
16039
  const [resource, setResource] = useState20(null);
15677
- const onEndedRef = useRef38(onEnded);
15678
- const onErrorRef = useRef38(onError);
15679
- const onPlaybackStateChangeRef = useRef38(onPlaybackStateChange);
16040
+ const onEndedRef = useRef39(onEnded);
16041
+ const onErrorRef = useRef39(onError);
16042
+ const onPlaybackStateChangeRef = useRef39(onPlaybackStateChange);
15680
16043
  onEndedRef.current = onEnded;
15681
16044
  onErrorRef.current = onError;
15682
16045
  onPlaybackStateChangeRef.current = onPlaybackStateChange;
15683
- useEffect37(() => {
16046
+ useEffect38(() => {
15684
16047
  if (!src) {
15685
16048
  setResource(null);
15686
16049
  return;
@@ -15787,11 +16150,11 @@ function VideoHotspot({
15787
16150
  src
15788
16151
  });
15789
16152
  const posterTexture = usePosterTexture2(id, poster, onError);
15790
- const onPlaybackErrorRef = useRef38(onPlaybackError);
15791
- const onPlaybackStateChangeRef = useRef38(onPlaybackStateChange);
16153
+ const onPlaybackErrorRef = useRef39(onPlaybackError);
16154
+ const onPlaybackStateChangeRef = useRef39(onPlaybackStateChange);
15792
16155
  onPlaybackErrorRef.current = onPlaybackError;
15793
16156
  onPlaybackStateChangeRef.current = onPlaybackStateChange;
15794
- useEffect37(() => {
16157
+ useEffect38(() => {
15795
16158
  if (!resource) {
15796
16159
  return;
15797
16160
  }
@@ -15808,7 +16171,7 @@ function VideoHotspot({
15808
16171
  }
15809
16172
  resource.video.preload = preload;
15810
16173
  }, [loop, muted, playsInline, preload, resource, volume]);
15811
- useEffect37(() => {
16174
+ useEffect38(() => {
15812
16175
  if (!resource) {
15813
16176
  return;
15814
16177
  }
@@ -15831,12 +16194,12 @@ function VideoHotspot({
15831
16194
  };
15832
16195
  }, [playing, resource]);
15833
16196
  const activeTexture = resource?.ready ? resource.texture : posterTexture;
15834
- return /* @__PURE__ */ jsx34(HotspotAnchor, { ...anchorProps, id, height, width, children: /* @__PURE__ */ jsx34(HotspotPlane, { map: activeTexture, opacity }) });
16197
+ return /* @__PURE__ */ jsx35(HotspotAnchor, { ...anchorProps, id, height, width, children: /* @__PURE__ */ jsx35(HotspotPlane, { map: activeTexture, opacity }) });
15835
16198
  }
15836
16199
 
15837
16200
  // src/hotspot/audio-hotspot.tsx
15838
- import { useFrame as useFrame18, useThree as useThree27 } from "@react-three/fiber";
15839
- import { useEffect as useEffect38, useRef as useRef39, useState as useState21 } from "react";
16201
+ import { useFrame as useFrame19, useThree as useThree28 } from "@react-three/fiber";
16202
+ import { useEffect as useEffect39, useRef as useRef40, useState as useState21 } from "react";
15840
16203
  import {
15841
16204
  CanvasTexture as CanvasTexture2,
15842
16205
  ClampToEdgeWrapping as ClampToEdgeWrapping7,
@@ -15845,7 +16208,7 @@ import {
15845
16208
  SRGBColorSpace as SRGBColorSpace9,
15846
16209
  TextureLoader as TextureLoader8
15847
16210
  } from "three";
15848
- import { jsx as jsx35 } from "react/jsx-runtime";
16211
+ import { jsx as jsx36 } from "react/jsx-runtime";
15849
16212
  var SPEAKER_TEXTURE_SIZE = 512;
15850
16213
  function paintSpeakerBody(context, center) {
15851
16214
  context.fillStyle = "#f5fbfc";
@@ -15910,7 +16273,7 @@ function createSpeakerTexture(state) {
15910
16273
  }
15911
16274
  function useSpeakerTextures(enabled) {
15912
16275
  const [textures, setTextures] = useState21({ playing: null, stopped: null });
15913
- useEffect38(() => {
16276
+ useEffect39(() => {
15914
16277
  if (!enabled) {
15915
16278
  setTextures({ playing: null, stopped: null });
15916
16279
  return;
@@ -15926,11 +16289,11 @@ function useSpeakerTextures(enabled) {
15926
16289
  return textures;
15927
16290
  }
15928
16291
  function useIconTexture(icon, enabled, onError, id) {
15929
- const gl = useThree27((state) => state.gl);
16292
+ const gl = useThree28((state) => state.gl);
15930
16293
  const [texture, setTexture] = useState21(null);
15931
- const onErrorRef = useRef39(onError);
16294
+ const onErrorRef = useRef40(onError);
15932
16295
  onErrorRef.current = onError;
15933
- useEffect38(() => {
16296
+ useEffect39(() => {
15934
16297
  let active = true;
15935
16298
  setTexture(null);
15936
16299
  if (!enabled || !icon) {
@@ -15967,7 +16330,7 @@ function useIconTexture(icon, enabled, onError, id) {
15967
16330
  active = false;
15968
16331
  };
15969
16332
  }, [enabled, gl, icon, id]);
15970
- useEffect38(
16333
+ useEffect39(
15971
16334
  () => () => {
15972
16335
  texture?.dispose();
15973
16336
  },
@@ -15987,12 +16350,12 @@ function useAudioHowl({
15987
16350
  src
15988
16351
  }) {
15989
16352
  const [howl, setHowl] = useState21(null);
15990
- const playingRef = useRef39(playing);
15991
- const loopRef = useRef39(loop ?? false);
15992
- const onEndedRef = useRef39(onEnded);
15993
- const onErrorRef = useRef39(onError);
15994
- const onPlaybackErrorRef = useRef39(onPlaybackError);
15995
- const onPlaybackStateChangeRef = useRef39(onPlaybackStateChange);
16353
+ const playingRef = useRef40(playing);
16354
+ const loopRef = useRef40(loop ?? false);
16355
+ const onEndedRef = useRef40(onEnded);
16356
+ const onErrorRef = useRef40(onError);
16357
+ const onPlaybackErrorRef = useRef40(onPlaybackError);
16358
+ const onPlaybackStateChangeRef = useRef40(onPlaybackStateChange);
15996
16359
  playingRef.current = playing;
15997
16360
  loopRef.current = loop ?? false;
15998
16361
  onEndedRef.current = onEnded;
@@ -16000,7 +16363,7 @@ function useAudioHowl({
16000
16363
  onPlaybackErrorRef.current = onPlaybackError;
16001
16364
  onPlaybackStateChangeRef.current = onPlaybackStateChange;
16002
16365
  const sourcesKey = sourceList(src).join("\0");
16003
- useEffect38(() => {
16366
+ useEffect39(() => {
16004
16367
  const sources = sourcesKey.length > 0 ? sourcesKey.split("\0") : [];
16005
16368
  if (sources.length === 0) {
16006
16369
  setHowl(null);
@@ -16037,7 +16400,7 @@ function useAudioHowl({
16037
16400
  handle.dispose();
16038
16401
  };
16039
16402
  }, [crossOrigin, id, sourcesKey]);
16040
- useEffect38(() => {
16403
+ useEffect39(() => {
16041
16404
  howl?.loop(loop ?? false);
16042
16405
  }, [howl, loop]);
16043
16406
  return howl;
@@ -16065,7 +16428,7 @@ function AudioHotspot({
16065
16428
  ...anchorProps
16066
16429
  }) {
16067
16430
  usePanoMediaActivationIntent(playing);
16068
- const camera = useThree27((state) => state.camera);
16431
+ const camera = useThree28((state) => state.camera);
16069
16432
  const howl = useAudioHowl({
16070
16433
  crossOrigin,
16071
16434
  id,
@@ -16081,15 +16444,15 @@ function AudioHotspot({
16081
16444
  const stoppedIconTexture = useIconTexture(icon, marker, onError, id);
16082
16445
  const playingIconTexture = useIconTexture(playingIcon, marker, onError, id);
16083
16446
  const markerTexture = playing ? playingIconTexture ?? stoppedIconTexture ?? speakerTextures.playing : stoppedIconTexture ?? speakerTextures.stopped;
16084
- const playingRef = useRef39(playing);
16447
+ const playingRef = useRef40(playing);
16085
16448
  playingRef.current = playing;
16086
- const mutedRef = useRef39(muted);
16087
- const volumeRef = useRef39(volume);
16088
- const rangeRef = useRef39(range);
16449
+ const mutedRef = useRef40(muted);
16450
+ const volumeRef = useRef40(volume);
16451
+ const rangeRef = useRef40(range);
16089
16452
  mutedRef.current = muted;
16090
16453
  volumeRef.current = volume;
16091
16454
  rangeRef.current = range;
16092
- useEffect38(() => {
16455
+ useEffect39(() => {
16093
16456
  if (!howl) {
16094
16457
  return;
16095
16458
  }
@@ -16099,7 +16462,7 @@ function AudioHotspot({
16099
16462
  }
16100
16463
  howl.play();
16101
16464
  }, [howl, playing]);
16102
- useEffect38(() => {
16465
+ useEffect39(() => {
16103
16466
  if (!howl || !pauseWhenHidden) {
16104
16467
  return;
16105
16468
  }
@@ -16117,7 +16480,7 @@ function AudioHotspot({
16117
16480
  document.removeEventListener("visibilitychange", handleVisibility);
16118
16481
  };
16119
16482
  }, [howl, pauseWhenHidden]);
16120
- useFrame18(() => {
16483
+ useFrame19(() => {
16121
16484
  if (!howl) {
16122
16485
  return;
16123
16486
  }
@@ -16130,11 +16493,11 @@ function AudioHotspot({
16130
16493
  howl.mute(mutedRef.current);
16131
16494
  howl.volume(clampAudioVolume(volumeRef.current) * spatial.gain);
16132
16495
  });
16133
- return /* @__PURE__ */ jsx35(HotspotAnchor, { ...anchorProps, id, height, width, children: marker ? /* @__PURE__ */ jsx35(HotspotPlane, { map: markerTexture, opacity }) : null });
16496
+ return /* @__PURE__ */ jsx36(HotspotAnchor, { ...anchorProps, id, height, width, children: marker ? /* @__PURE__ */ jsx36(HotspotPlane, { map: markerTexture, opacity }) : null });
16134
16497
  }
16135
16498
 
16136
16499
  // src/hotspot/text-hotspot.tsx
16137
- import { useEffect as useEffect39, useRef as useRef40, useState as useState22 } from "react";
16500
+ import { useEffect as useEffect40, useRef as useRef41, useState as useState22 } from "react";
16138
16501
  import {
16139
16502
  CanvasTexture as CanvasTexture3,
16140
16503
  ClampToEdgeWrapping as ClampToEdgeWrapping8,
@@ -16142,7 +16505,7 @@ import {
16142
16505
  LinearMipmapLinearFilter as LinearMipmapLinearFilter8,
16143
16506
  SRGBColorSpace as SRGBColorSpace10
16144
16507
  } from "three";
16145
- import { jsx as jsx36 } from "react/jsx-runtime";
16508
+ import { jsx as jsx37 } from "react/jsx-runtime";
16146
16509
  var TEXT_TEXTURE_LONG_SIDE = 1024;
16147
16510
  var DEFAULT_FONT_FAMILY = "system-ui, sans-serif";
16148
16511
  var DEFAULT_FONT_SIZE = 96;
@@ -16363,11 +16726,11 @@ function createTextTexture(text, width, height, style) {
16363
16726
  }
16364
16727
  function useTextTexture(text, width, height, style, onLoad, onError) {
16365
16728
  const [texture, setTexture] = useState22(null);
16366
- const onLoadRef = useRef40(onLoad);
16367
- const onErrorRef = useRef40(onError);
16729
+ const onLoadRef = useRef41(onLoad);
16730
+ const onErrorRef = useRef41(onError);
16368
16731
  onLoadRef.current = onLoad;
16369
16732
  onErrorRef.current = onError;
16370
- useEffect39(() => {
16733
+ useEffect40(() => {
16371
16734
  let cancelled = false;
16372
16735
  let nextTexture = null;
16373
16736
  const run = async () => {
@@ -16460,13 +16823,13 @@ function TextHotspot({
16460
16823
  whiteSpace
16461
16824
  };
16462
16825
  const texture = useTextTexture(text, width, height, style, onLoad, onError);
16463
- return /* @__PURE__ */ jsx36(HotspotAnchor, { ...anchorProps, height, width, children: /* @__PURE__ */ jsx36(HotspotPlane, { map: texture, opacity }) });
16826
+ return /* @__PURE__ */ jsx37(HotspotAnchor, { ...anchorProps, height, width, children: /* @__PURE__ */ jsx37(HotspotPlane, { map: texture, opacity }) });
16464
16827
  }
16465
16828
 
16466
16829
  // src/hotspot/iframe-hotspot.tsx
16467
16830
  import { Html } from "@react-three/drei";
16468
16831
  import { DoubleSide as DoubleSide6 } from "three";
16469
- import { jsx as jsx37, jsxs as jsxs20 } from "react/jsx-runtime";
16832
+ import { jsx as jsx38, jsxs as jsxs21 } from "react/jsx-runtime";
16470
16833
  var IFRAME_LONG_SIDE = 800;
16471
16834
  var CSS3D_DISTANCE_FACTOR = 400;
16472
16835
  var DEFAULT_SANDBOX = "allow-scripts allow-popups allow-forms";
@@ -16523,7 +16886,7 @@ function IframeHotspot({
16523
16886
  interactive,
16524
16887
  pointerEvents
16525
16888
  );
16526
- return /* @__PURE__ */ jsxs20(
16889
+ return /* @__PURE__ */ jsxs21(
16527
16890
  HotspotAnchor,
16528
16891
  {
16529
16892
  ...anchorProps,
@@ -16532,9 +16895,9 @@ function IframeHotspot({
16532
16895
  pointerEvents,
16533
16896
  width,
16534
16897
  children: [
16535
- /* @__PURE__ */ jsxs20("mesh", { children: [
16536
- /* @__PURE__ */ jsx37("planeGeometry", { args: [1, 1] }),
16537
- /* @__PURE__ */ jsx37(
16898
+ /* @__PURE__ */ jsxs21("mesh", { children: [
16899
+ /* @__PURE__ */ jsx38("planeGeometry", { args: [1, 1] }),
16900
+ /* @__PURE__ */ jsx38(
16538
16901
  "meshBasicMaterial",
16539
16902
  {
16540
16903
  depthWrite: false,
@@ -16545,7 +16908,7 @@ function IframeHotspot({
16545
16908
  }
16546
16909
  )
16547
16910
  ] }),
16548
- /* @__PURE__ */ jsx37(
16911
+ /* @__PURE__ */ jsx38(
16549
16912
  Html,
16550
16913
  {
16551
16914
  distanceFactor: CSS3D_DISTANCE_FACTOR,
@@ -16560,7 +16923,7 @@ function IframeHotspot({
16560
16923
  },
16561
16924
  transform: true,
16562
16925
  zIndexRange: [10, 0],
16563
- children: /* @__PURE__ */ jsx37(
16926
+ children: /* @__PURE__ */ jsx38(
16564
16927
  "iframe",
16565
16928
  {
16566
16929
  allow,