@ericchen1990/pano-view 3.1.2 → 3.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.mjs CHANGED
@@ -2311,6 +2311,9 @@ function isMediaActivationEvent(event) {
2311
2311
  return false;
2312
2312
  }
2313
2313
  }
2314
+ function isAutoplayPolicyError(error) {
2315
+ return typeof error === "object" && error !== null && "name" in error && error.name === "NotAllowedError";
2316
+ }
2314
2317
 
2315
2318
  // src/audio/howl.ts
2316
2319
  import_howler.Howler.autoUnlock = true;
@@ -3742,7 +3745,9 @@ var DEFAULT_PANO_FILTER_INTENSITY = 1;
3742
3745
  var DEFAULT_PANO_FILTER_SNAPSHOT = {
3743
3746
  preset: "none",
3744
3747
  intensity: DEFAULT_PANO_FILTER_INTENSITY,
3745
- enabled: true
3748
+ enabled: true,
3749
+ colorMatrix: null,
3750
+ colorMatrixScope: "panorama"
3746
3751
  };
3747
3752
  function clampPanoFilterIntensity(value) {
3748
3753
  if (!Number.isFinite(value)) {
@@ -3751,15 +3756,17 @@ function clampPanoFilterIntensity(value) {
3751
3756
  return Math.max(0, Math.min(value, 1));
3752
3757
  }
3753
3758
  function resolvePanoFilterSnapshot(input) {
3759
+ if (input.colorMatrix && (input.colorMatrix.length !== 20 || input.colorMatrix.some((value) => !Number.isFinite(value)))) {
3760
+ throw new Error("colorMatrix must contain 20 finite numbers");
3761
+ }
3754
3762
  return {
3763
+ colorMatrix: input.colorMatrix ? [...input.colorMatrix] : null,
3764
+ colorMatrixScope: input.colorMatrixScope ?? "panorama",
3755
3765
  preset: input.preset ?? "none",
3756
3766
  intensity: clampPanoFilterIntensity(input.intensity),
3757
3767
  enabled: input.enabled !== false
3758
3768
  };
3759
3769
  }
3760
- function isPanoFilterActive(snapshot) {
3761
- return snapshot.enabled && snapshot.preset !== "none";
3762
- }
3763
3770
 
3764
3771
  // src/pano-filter/host.ts
3765
3772
  var PanoFilterHostContext = createContext7(null);
@@ -3856,7 +3863,7 @@ function hasPanoMediaActivationIntent(host) {
3856
3863
  return host.intents.size > 0;
3857
3864
  }
3858
3865
  function needsMediaGesture() {
3859
- if (typeof navigator !== "undefined" && navigator.userActivation?.hasBeenActive) {
3866
+ if (typeof navigator !== "undefined" && navigator.userActivation?.isActive) {
3860
3867
  return false;
3861
3868
  }
3862
3869
  if (import_howler2.Howler.ctx?.state === "running") {
@@ -7189,10 +7196,6 @@ var PanoViewer = forwardRef2(
7189
7196
  if (!shouldActivateMedia) {
7190
7197
  return;
7191
7198
  }
7192
- if (!needsMediaGesture()) {
7193
- void activateMedia();
7194
- return;
7195
- }
7196
7199
  let cancelled = false;
7197
7200
  let activating = false;
7198
7201
  const removeListeners = () => {
@@ -7200,32 +7203,69 @@ var PanoViewer = forwardRef2(
7200
7203
  window.removeEventListener("pointerup", handleGesture, true);
7201
7204
  window.removeEventListener("keydown", handleGesture, true);
7202
7205
  };
7203
- const handleGesture = (event) => {
7204
- if (!isMediaActivationEvent(event) || activating || cancelled) {
7206
+ const completeIfUnlocked = (requestedVideo, videoOk) => {
7207
+ if (cancelled || !isPanoAudioUnlocked()) {
7208
+ return;
7209
+ }
7210
+ if (requestedVideo && videoHost.controller && !videoOk) {
7211
+ return;
7212
+ }
7213
+ removeListeners();
7214
+ setMediaActivated(true);
7215
+ };
7216
+ const tryActivate = () => {
7217
+ if (activating || cancelled) {
7205
7218
  return;
7206
7219
  }
7207
7220
  activating = true;
7221
+ let videoPlay;
7222
+ const controls2 = {
7223
+ resumeAudio: mediaActivationControls.resumeAudio,
7224
+ playVideo: (options) => {
7225
+ const result = mediaActivationControls.playVideo(options);
7226
+ videoPlay = result;
7227
+ return result;
7228
+ },
7229
+ playBackgroundAudio: mediaActivationControls.playBackgroundAudio
7230
+ };
7208
7231
  try {
7209
- const resume = runMediaActivation();
7210
- void resume.then(() => {
7211
- if (cancelled || !isPanoAudioUnlocked()) {
7212
- return;
7232
+ const resume = controls2.resumeAudio();
7233
+ mediaActivationOptions?.onActivate?.(controls2);
7234
+ const requestedVideo = videoPlay !== void 0;
7235
+ void Promise.all([resume, videoPlay ?? Promise.resolve(true)]).then(
7236
+ ([, videoOk]) => {
7237
+ completeIfUnlocked(requestedVideo, videoOk);
7238
+ },
7239
+ () => {
7240
+ completeIfUnlocked(requestedVideo, false);
7213
7241
  }
7214
- removeListeners();
7215
- setMediaActivated(true);
7216
- });
7242
+ );
7217
7243
  } finally {
7218
7244
  activating = false;
7219
7245
  }
7220
7246
  };
7247
+ const handleGesture = (event) => {
7248
+ if (!isMediaActivationEvent(event)) {
7249
+ return;
7250
+ }
7251
+ tryActivate();
7252
+ };
7221
7253
  window.addEventListener("pointerdown", handleGesture, { capture: true });
7222
7254
  window.addEventListener("pointerup", handleGesture, { capture: true });
7223
7255
  window.addEventListener("keydown", handleGesture, { capture: true });
7256
+ if (!needsMediaGesture()) {
7257
+ tryActivate();
7258
+ }
7224
7259
  return () => {
7225
7260
  cancelled = true;
7226
7261
  removeListeners();
7227
7262
  };
7228
- }, [activateMedia, runMediaActivation, shouldActivateMedia]);
7263
+ }, [
7264
+ mediaActivationControls,
7265
+ mediaActivationOptions,
7266
+ shouldActivateMedia,
7267
+ videoHost
7268
+ ]);
7229
7269
  const fallbackViewRef = useRef13(DEFAULT_VIEW);
7230
7270
  const normalizedMinFov = Math.max(1, Math.min(minFov, maxFov - 1));
7231
7271
  const normalizedMaxFov = Math.min(
@@ -8004,15 +8044,23 @@ import { useContext as useContext17, useEffect as useEffect15, useMemo as useMem
8004
8044
  function PanoFilter({
8005
8045
  preset = "none",
8006
8046
  intensity,
8007
- enabled = true
8047
+ enabled = true,
8048
+ colorMatrix,
8049
+ colorMatrixScope
8008
8050
  }) {
8009
8051
  const host = useContext17(PanoFilterHostContext);
8010
8052
  if (!host) {
8011
8053
  throw new Error("<PanoFilter> must be rendered inside <PanoViewer>.");
8012
8054
  }
8013
8055
  const snapshot = useMemo9(
8014
- () => resolvePanoFilterSnapshot({ preset, intensity, enabled }),
8015
- [enabled, intensity, preset]
8056
+ () => resolvePanoFilterSnapshot({
8057
+ preset,
8058
+ intensity,
8059
+ enabled,
8060
+ colorMatrix,
8061
+ colorMatrixScope
8062
+ }),
8063
+ [enabled, intensity, preset, colorMatrix, colorMatrixScope]
8016
8064
  );
8017
8065
  useEffect15(() => {
8018
8066
  claimPanoFilter(host);
@@ -9666,18 +9714,10 @@ function usePanoViewer() {
9666
9714
  return useMemo12(() => ({ ref, ...handle }), [handle]);
9667
9715
  }
9668
9716
 
9669
- // src/sphere.tsx
9670
- import { useThree as useThree13 } from "@react-three/fiber";
9671
- import { useEffect as useEffect21, useMemo as useMemo14, useRef as useRef22, useState as useState9 } from "react";
9672
- import {
9673
- BackSide as BackSide2,
9674
- LinearFilter,
9675
- LinearMipmapLinearFilter,
9676
- MathUtils as MathUtils5,
9677
- RepeatWrapping,
9678
- SRGBColorSpace,
9679
- TextureLoader
9680
- } from "three";
9717
+ // src/sphere-tile/sphere-tile.tsx
9718
+ import { useFrame as useFrame9, useThree as useThree13 } from "@react-three/fiber";
9719
+ import { memo, useCallback as useCallback9, useEffect as useEffect22, useMemo as useMemo14, useRef as useRef23, useState as useState10 } from "react";
9720
+ import { BackSide as BackSide2, Frustum, Matrix4 as Matrix42, PerspectiveCamera as PerspectiveCamera3 } from "three";
9681
9721
 
9682
9722
  // src/asset-url.ts
9683
9723
  function isAbsoluteAssetUrl(url) {
@@ -9702,6 +9742,10 @@ function resolveUrlAgainstFile(fileUrl, path) {
9702
9742
 
9703
9743
  // src/pano-filter/pano-basic-material.tsx
9704
9744
  import { useLayoutEffect as useLayoutEffect2, useMemo as useMemo13, useRef as useRef21 } from "react";
9745
+ import {
9746
+ Matrix4,
9747
+ Vector4 as Vector42
9748
+ } from "three";
9705
9749
 
9706
9750
  // src/pano-filter/shaders.ts
9707
9751
  var GLSL_FILTER_COMMON = `
@@ -9850,212 +9894,944 @@ ${applyPanoFilterFunction(panoFilterBody(preset))}`
9850
9894
  diffuseColor.rgb = mix(diffuseColor.rgb, applyPanoFilter(diffuseColor.rgb), clamp(uPanoFilterIntensity, 0.0, 1.0));`
9851
9895
  );
9852
9896
  }
9897
+ function injectPanoColorMatrixShader(shader) {
9898
+ shader.fragmentShader = shader.fragmentShader.replace(
9899
+ "#include <common>",
9900
+ `#include <common>
9901
+ uniform mat4 uPanoColorMatrix;
9902
+ uniform vec4 uPanoColorOffset;
9903
+ uniform float uPanoColorMatrixIntensity;`
9904
+ ).replace(
9905
+ "#include <colorspace_fragment>",
9906
+ `#include <colorspace_fragment>
9907
+ gl_FragColor = mix(gl_FragColor, clamp(uPanoColorMatrix * gl_FragColor + uPanoColorOffset, 0.0, 1.0), uPanoColorMatrixIntensity);`
9908
+ );
9909
+ }
9853
9910
 
9854
9911
  // src/pano-filter/pano-basic-material.tsx
9855
9912
  import { jsx as jsx14 } from "react/jsx-runtime";
9913
+ function matrixUniforms(matrix) {
9914
+ return {
9915
+ matrix: new Matrix4().set(
9916
+ matrix[0],
9917
+ matrix[1],
9918
+ matrix[2],
9919
+ matrix[3],
9920
+ matrix[5],
9921
+ matrix[6],
9922
+ matrix[7],
9923
+ matrix[8],
9924
+ matrix[10],
9925
+ matrix[11],
9926
+ matrix[12],
9927
+ matrix[13],
9928
+ matrix[15],
9929
+ matrix[16],
9930
+ matrix[17],
9931
+ matrix[18]
9932
+ ),
9933
+ offset: new Vector42(matrix[4], matrix[9], matrix[14], matrix[19])
9934
+ };
9935
+ }
9856
9936
  function PanoBasicMaterial({
9857
- map,
9858
- side,
9859
- depthTest,
9860
- depthWrite,
9861
- toneMapped = false
9937
+ target = "panorama",
9938
+ ...props
9862
9939
  }) {
9863
9940
  const snapshot = usePanoFilterSnapshot();
9864
- const materialRef = useRef21(null);
9865
- const intensityRef = useRef21(snapshot.intensity);
9866
- const intensityUniformRef = useRef21(null);
9867
- intensityRef.current = snapshot.intensity;
9868
- const active = isPanoFilterActive(snapshot);
9869
- const preset = snapshot.preset;
9941
+ const preset = snapshot.enabled && target === "panorama" ? snapshot.preset : "none";
9942
+ const matrix = snapshot.enabled && (target === "panorama" || snapshot.colorMatrixScope === "all") ? snapshot.colorMatrix : null;
9943
+ const hasMatrix = matrix !== null;
9944
+ const currentRef = useRef21({ matrix, intensity: snapshot.intensity });
9945
+ currentRef.current = { matrix, intensity: snapshot.intensity };
9946
+ const shaderRef = useRef21(null);
9870
9947
  const onBeforeCompile = useMemo13(() => {
9871
- if (!active || preset === "none") {
9872
- return void 0;
9873
- }
9874
9948
  const compile = (shader) => {
9875
- injectPanoFilterShader(shader, preset);
9876
- const intensityUniform = shader.uniforms.uPanoFilterIntensity;
9877
- intensityUniform.value = intensityRef.current;
9878
- intensityUniformRef.current = intensityUniform;
9879
- const material = materialRef.current;
9880
- if (material) {
9881
- material.userData.uPanoFilterIntensity = intensityUniform;
9949
+ shaderRef.current = shader;
9950
+ if (preset !== "none") {
9951
+ injectPanoFilterShader(shader, preset);
9952
+ shader.uniforms.uPanoFilterIntensity.value = currentRef.current.intensity;
9953
+ }
9954
+ if (hasMatrix && currentRef.current.matrix) {
9955
+ injectPanoColorMatrixShader(shader);
9956
+ const values = matrixUniforms(currentRef.current.matrix);
9957
+ shader.uniforms.uPanoColorMatrix = { value: values.matrix };
9958
+ shader.uniforms.uPanoColorOffset = { value: values.offset };
9959
+ shader.uniforms.uPanoColorMatrixIntensity = {
9960
+ value: currentRef.current.intensity
9961
+ };
9882
9962
  }
9883
9963
  };
9884
- compile.toString = () => `pano-filter:${preset}`;
9964
+ compile.toString = () => `pano-filter:${preset}:matrix:${hasMatrix}`;
9885
9965
  return compile;
9886
- }, [active, preset]);
9887
- useLayoutEffect2(() => {
9888
- if (!active) {
9889
- intensityUniformRef.current = null;
9890
- }
9891
- const material = materialRef.current;
9892
- if (!material) {
9893
- return;
9894
- }
9895
- material.needsUpdate = true;
9896
- }, [active, preset]);
9966
+ }, [preset, hasMatrix]);
9897
9967
  useLayoutEffect2(() => {
9898
- if (intensityUniformRef.current) {
9899
- intensityUniformRef.current.value = snapshot.intensity;
9900
- }
9901
- }, [snapshot.intensity]);
9968
+ const shader = shaderRef.current;
9969
+ if (!shader) return;
9970
+ if (shader.uniforms.uPanoFilterIntensity)
9971
+ shader.uniforms.uPanoFilterIntensity.value = snapshot.intensity;
9972
+ if (shader.uniforms.uPanoColorMatrix && matrix) {
9973
+ const values = matrixUniforms(matrix);
9974
+ shader.uniforms.uPanoColorMatrix.value = values.matrix;
9975
+ shader.uniforms.uPanoColorOffset.value = values.offset;
9976
+ shader.uniforms.uPanoColorMatrixIntensity.value = snapshot.intensity;
9977
+ }
9978
+ }, [matrix, snapshot.intensity]);
9902
9979
  return /* @__PURE__ */ jsx14(
9903
9980
  "meshBasicMaterial",
9904
9981
  {
9905
- ref: materialRef,
9906
- depthTest,
9907
- depthWrite,
9908
- map,
9909
- onBeforeCompile,
9910
- side,
9911
- toneMapped
9982
+ toneMapped: false,
9983
+ ...props,
9984
+ onBeforeCompile
9912
9985
  },
9913
- active ? preset : "none"
9986
+ `${preset}:${hasMatrix}`
9914
9987
  );
9915
9988
  }
9916
9989
 
9917
- // src/sphere.tsx
9918
- import { jsx as jsx15, jsxs as jsxs9 } from "react/jsx-runtime";
9919
- function useEquirectTexture(url, anisotropy, generateMipmaps, onLoad, onError) {
9920
- const [texture, setTexture] = useState9(null);
9921
- const onLoadRef = useRef22(onLoad);
9922
- const onErrorRef = useRef22(onError);
9923
- onLoadRef.current = onLoad;
9924
- onErrorRef.current = onError;
9925
- useEffect21(() => {
9926
- if (!url) {
9927
- setTexture(null);
9928
- return;
9990
+ // src/tile/texture-manager.ts
9991
+ import {
9992
+ ClampToEdgeWrapping,
9993
+ LinearFilter,
9994
+ SRGBColorSpace,
9995
+ TextureLoader
9996
+ } from "three";
9997
+ var EMPTY_TEXTURE_SNAPSHOT = {
9998
+ status: "idle",
9999
+ texture: null,
10000
+ error: null
10001
+ };
10002
+ var TileTextureManager = class {
10003
+ constructor(options) {
10004
+ this.loader = new TextureLoader();
10005
+ this.entries = /* @__PURE__ */ new Map();
10006
+ this.queue = [];
10007
+ this.activeLoads = 0;
10008
+ this.totalBytes = 0;
10009
+ this.requested = 0;
10010
+ this.loaded = 0;
10011
+ this.failed = 0;
10012
+ this.disposed = false;
10013
+ this.generation = 0;
10014
+ this.options = options;
10015
+ }
10016
+ resume() {
10017
+ this.disposed = false;
10018
+ this.drain();
10019
+ }
10020
+ getSnapshot(key) {
10021
+ const entry = this.entries.get(key);
10022
+ return entry ? this.snapshot(entry) : EMPTY_TEXTURE_SNAPSHOT;
10023
+ }
10024
+ acquire(key, url, address, listener) {
10025
+ let entry = this.entries.get(key);
10026
+ if (!entry) {
10027
+ entry = {
10028
+ key,
10029
+ url,
10030
+ address,
10031
+ status: "idle",
10032
+ texture: null,
10033
+ error: null,
10034
+ refs: 0,
10035
+ listeners: /* @__PURE__ */ new Set(),
10036
+ lastUsed: performance.now(),
10037
+ bytes: 0
10038
+ };
10039
+ this.entries.set(key, entry);
9929
10040
  }
9930
- let active = true;
9931
- const loader = new TextureLoader();
9932
- setTexture(null);
9933
- loader.load(
9934
- url,
9935
- (loadedTexture) => {
9936
- if (!active) {
9937
- loadedTexture.dispose();
9938
- return;
9939
- }
9940
- loadedTexture.colorSpace = SRGBColorSpace;
9941
- loadedTexture.wrapS = RepeatWrapping;
9942
- loadedTexture.repeat.x = -1;
9943
- loadedTexture.offset.x = 1;
9944
- loadedTexture.anisotropy = anisotropy;
9945
- loadedTexture.magFilter = LinearFilter;
9946
- loadedTexture.minFilter = generateMipmaps ? LinearMipmapLinearFilter : LinearFilter;
9947
- loadedTexture.generateMipmaps = generateMipmaps;
9948
- loadedTexture.needsUpdate = true;
9949
- setTexture(loadedTexture);
9950
- onLoadRef.current?.(loadedTexture);
9951
- },
9952
- void 0,
9953
- (error) => {
9954
- if (active) {
9955
- setTexture(null);
9956
- onErrorRef.current?.(error);
10041
+ entry.refs += 1;
10042
+ entry.lastUsed = performance.now();
10043
+ entry.listeners.add(listener);
10044
+ listener(this.snapshot(entry));
10045
+ if (entry.status === "idle") {
10046
+ entry.status = "queued";
10047
+ this.queue.push(entry);
10048
+ this.requested += 1;
10049
+ this.emitProgress();
10050
+ this.drain();
10051
+ }
10052
+ return () => {
10053
+ entry.listeners.delete(listener);
10054
+ entry.refs = Math.max(0, entry.refs - 1);
10055
+ entry.lastUsed = performance.now();
10056
+ if (entry.refs === 0 && entry.status === "queued") {
10057
+ const queueIndex = this.queue.indexOf(entry);
10058
+ if (queueIndex >= 0) {
10059
+ this.queue.splice(queueIndex, 1);
9957
10060
  }
10061
+ entry.status = "idle";
10062
+ this.entries.delete(entry.key);
10063
+ this.requested = Math.max(0, this.requested - 1);
10064
+ this.emitProgress();
10065
+ this.drain();
10066
+ return;
9958
10067
  }
9959
- );
9960
- return () => {
9961
- active = false;
10068
+ this.evict();
9962
10069
  };
9963
- }, [anisotropy, generateMipmaps, url]);
9964
- useEffect21(
9965
- () => () => {
9966
- texture?.dispose();
9967
- },
9968
- [texture]
9969
- );
9970
- return texture;
9971
- }
9972
- function Sphere({
9973
- src,
9974
- previewUrl,
9975
- yawOffset = 0,
9976
- onReady,
9977
- onLoad,
9978
- onError,
9979
- onPreviewError,
9980
- visible = true
9981
- }) {
9982
- const gl = useThree13((state) => state.gl);
9983
- const anisotropy = gl.capabilities.getMaxAnisotropy();
9984
- const resolvedPreviewUrl = useMemo14(
9985
- () => resolveUrlAgainstFile(src, previewUrl),
9986
- [previewUrl, src]
9987
- );
9988
- const texture = useEquirectTexture(
9989
- src,
9990
- anisotropy,
9991
- true,
9992
- onLoad,
9993
- onError
9994
- );
9995
- const previewTexture = useEquirectTexture(
9996
- texture ? null : resolvedPreviewUrl,
9997
- anisotropy,
9998
- false,
9999
- void 0,
10000
- onPreviewError
10001
- );
10002
- const displayTexture = texture ?? previewTexture;
10003
- const readyRef = useRef22(false);
10004
- useEffect21(() => {
10005
- readyRef.current = false;
10006
- }, [resolvedPreviewUrl, src]);
10007
- useEffect21(() => {
10008
- if (!displayTexture || readyRef.current) {
10009
- return;
10070
+ }
10071
+ dispose() {
10072
+ this.disposed = true;
10073
+ this.generation += 1;
10074
+ this.queue.length = 0;
10075
+ for (const entry of this.entries.values()) {
10076
+ entry.texture?.dispose();
10077
+ entry.listeners.clear();
10010
10078
  }
10011
- readyRef.current = true;
10012
- onReady?.();
10013
- }, [displayTexture, onReady]);
10014
- if (!displayTexture) {
10015
- return null;
10079
+ this.entries.clear();
10080
+ this.totalBytes = 0;
10016
10081
  }
10017
- return /* @__PURE__ */ jsxs9(
10018
- "mesh",
10019
- {
10020
- rotation: [0, MathUtils5.degToRad(90 + yawOffset), 0],
10021
- visible,
10022
- children: [
10023
- /* @__PURE__ */ jsx15("sphereGeometry", { args: [DEFAULT_PANORAMA_RADIUS, 128, 64] }),
10024
- /* @__PURE__ */ jsx15(
10025
- PanoBasicMaterial,
10026
- {
10027
- map: displayTexture,
10028
- side: BackSide2,
10029
- toneMapped: false
10030
- }
10031
- )
10032
- ]
10082
+ /**
10083
+ * Releases textures that are no longer rendered by any Tile instance.
10084
+ * Scene transitions call this after the outgoing panorama has been
10085
+ * snapshotted, so the incoming scene never competes with stale GPU tiles.
10086
+ */
10087
+ releaseUnused() {
10088
+ for (const entry of Array.from(this.entries.values())) {
10089
+ if (entry.refs > 0) {
10090
+ continue;
10091
+ }
10092
+ entry.texture?.dispose();
10093
+ this.totalBytes -= entry.bytes;
10094
+ this.entries.delete(entry.key);
10033
10095
  }
10034
- );
10096
+ this.totalBytes = Math.max(0, this.totalBytes);
10097
+ }
10098
+ snapshot(entry) {
10099
+ return {
10100
+ status: entry.status,
10101
+ texture: entry.texture,
10102
+ error: entry.error
10103
+ };
10104
+ }
10105
+ notify(entry) {
10106
+ const snapshot = this.snapshot(entry);
10107
+ for (const listener of entry.listeners) {
10108
+ listener(snapshot);
10109
+ }
10110
+ }
10111
+ emitProgress() {
10112
+ this.options.onProgress?.({
10113
+ requested: this.requested,
10114
+ loaded: this.loaded,
10115
+ failed: this.failed,
10116
+ active: this.activeLoads,
10117
+ queued: this.queue.length
10118
+ });
10119
+ }
10120
+ drain() {
10121
+ while (!this.disposed && this.activeLoads < this.options.concurrency && this.queue.length > 0) {
10122
+ const entry = this.queue.shift();
10123
+ if (entry.refs === 0) {
10124
+ entry.status = "idle";
10125
+ this.entries.delete(entry.key);
10126
+ this.requested = Math.max(0, this.requested - 1);
10127
+ continue;
10128
+ }
10129
+ entry.status = "loading";
10130
+ this.activeLoads += 1;
10131
+ this.notify(entry);
10132
+ this.emitProgress();
10133
+ void this.loadAndFinish(entry);
10134
+ }
10135
+ }
10136
+ async load(entry, generation) {
10137
+ let lastError = null;
10138
+ for (let attempt = 0; attempt <= this.options.retryCount; attempt += 1) {
10139
+ if (this.disposed || generation !== this.generation) return;
10140
+ try {
10141
+ const texture = await this.loader.loadAsync(entry.url);
10142
+ if (this.disposed || generation !== this.generation) {
10143
+ texture.dispose();
10144
+ return;
10145
+ }
10146
+ this.configureTexture(texture);
10147
+ entry.texture = texture;
10148
+ entry.status = "loaded";
10149
+ entry.error = null;
10150
+ entry.bytes = entry.address.width * entry.address.height * 4;
10151
+ entry.lastUsed = performance.now();
10152
+ this.totalBytes += entry.bytes;
10153
+ this.loaded += 1;
10154
+ this.notify(entry);
10155
+ return;
10156
+ } catch (error) {
10157
+ lastError = error;
10158
+ }
10159
+ }
10160
+ if (!this.disposed && generation === this.generation) {
10161
+ entry.status = "error";
10162
+ entry.error = lastError;
10163
+ this.failed += 1;
10164
+ this.notify(entry);
10165
+ this.options.onError?.({
10166
+ address: entry.address,
10167
+ url: entry.url,
10168
+ error: lastError
10169
+ });
10170
+ }
10171
+ }
10172
+ configureTexture(texture) {
10173
+ texture.colorSpace = SRGBColorSpace;
10174
+ texture.wrapS = ClampToEdgeWrapping;
10175
+ texture.wrapT = ClampToEdgeWrapping;
10176
+ texture.magFilter = LinearFilter;
10177
+ texture.minFilter = LinearFilter;
10178
+ texture.generateMipmaps = false;
10179
+ texture.anisotropy = Math.min(4, this.options.anisotropy);
10180
+ texture.needsUpdate = true;
10181
+ }
10182
+ evict() {
10183
+ if (this.totalBytes <= this.options.maxBytes) {
10184
+ return;
10185
+ }
10186
+ const candidates = Array.from(this.entries.values()).filter((entry) => entry.refs === 0 && entry.texture).sort((a, b) => a.lastUsed - b.lastUsed);
10187
+ for (const entry of candidates) {
10188
+ if (this.totalBytes <= this.options.maxBytes) {
10189
+ break;
10190
+ }
10191
+ entry.texture?.dispose();
10192
+ this.totalBytes -= entry.bytes;
10193
+ this.entries.delete(entry.key);
10194
+ }
10195
+ this.totalBytes = Math.max(0, this.totalBytes);
10196
+ }
10197
+ finishLoad(generation) {
10198
+ this.activeLoads = Math.max(0, this.activeLoads - 1);
10199
+ if (!this.disposed && generation === this.generation) {
10200
+ this.emitProgress();
10201
+ this.evict();
10202
+ }
10203
+ if (!this.disposed) {
10204
+ this.drain();
10205
+ }
10206
+ }
10207
+ async loadAndFinish(entry) {
10208
+ const generation = this.generation;
10209
+ try {
10210
+ await this.load(entry, generation);
10211
+ } finally {
10212
+ this.finishLoad(generation);
10213
+ }
10214
+ }
10215
+ };
10216
+
10217
+ // src/tile/texture-hooks.ts
10218
+ import { useEffect as useEffect21, useRef as useRef22, useState as useState9 } from "react";
10219
+ import {
10220
+ ClampToEdgeWrapping as ClampToEdgeWrapping2,
10221
+ LinearFilter as LinearFilter2,
10222
+ SRGBColorSpace as SRGBColorSpace2,
10223
+ TextureLoader as TextureLoader2
10224
+ } from "three";
10225
+ function usePreviewTexture(url, anisotropy, onError) {
10226
+ const [texture, setTexture] = useState9(null);
10227
+ const onErrorRef = useRef22(onError);
10228
+ onErrorRef.current = onError;
10229
+ useEffect21(() => {
10230
+ if (!url) {
10231
+ setTexture(null);
10232
+ return;
10233
+ }
10234
+ let active = true;
10235
+ const loader = new TextureLoader2();
10236
+ setTexture(null);
10237
+ loader.load(
10238
+ url,
10239
+ (loadedTexture) => {
10240
+ if (!active) {
10241
+ loadedTexture.dispose();
10242
+ return;
10243
+ }
10244
+ loadedTexture.colorSpace = SRGBColorSpace2;
10245
+ loadedTexture.wrapS = ClampToEdgeWrapping2;
10246
+ loadedTexture.wrapT = ClampToEdgeWrapping2;
10247
+ loadedTexture.magFilter = LinearFilter2;
10248
+ loadedTexture.minFilter = LinearFilter2;
10249
+ loadedTexture.generateMipmaps = false;
10250
+ loadedTexture.anisotropy = Math.min(4, anisotropy);
10251
+ loadedTexture.needsUpdate = true;
10252
+ setTexture(loadedTexture);
10253
+ },
10254
+ void 0,
10255
+ (error) => {
10256
+ if (active) {
10257
+ setTexture(null);
10258
+ onErrorRef.current?.(error);
10259
+ }
10260
+ }
10261
+ );
10262
+ return () => {
10263
+ active = false;
10264
+ };
10265
+ }, [anisotropy, url]);
10266
+ useEffect21(
10267
+ () => () => {
10268
+ texture?.dispose();
10269
+ },
10270
+ [texture]
10271
+ );
10272
+ return texture;
10273
+ }
10274
+ function useManagedTexture(manager, key, url, address) {
10275
+ const [managedState, setManagedState] = useState9(() => ({
10276
+ manager,
10277
+ key,
10278
+ url,
10279
+ snapshot: manager.getSnapshot(key)
10280
+ }));
10281
+ const snapshot = managedState.manager === manager && managedState.key === key && managedState.url === url ? managedState.snapshot : manager.getSnapshot(key);
10282
+ useEffect21(
10283
+ () => manager.acquire(key, url, address, (nextSnapshot) => {
10284
+ setManagedState({
10285
+ manager,
10286
+ key,
10287
+ url,
10288
+ snapshot: nextSnapshot
10289
+ });
10290
+ }),
10291
+ [key, manager, url]
10292
+ );
10293
+ return snapshot;
10035
10294
  }
10036
10295
 
10037
- // src/video/pano-video.tsx
10296
+ // src/sphere-tile/layout.ts
10297
+ import {
10298
+ Box3,
10299
+ BufferGeometry,
10300
+ Float32BufferAttribute,
10301
+ MathUtils as MathUtils5,
10302
+ Vector3 as Vector38
10303
+ } from "three";
10304
+ function positiveInteger(value, name) {
10305
+ if (!Number.isSafeInteger(value) || value <= 0) {
10306
+ throw new Error(`${name} must be a positive safe integer`);
10307
+ }
10308
+ return value;
10309
+ }
10310
+ function parseSphereMultires(input) {
10311
+ const parts = typeof input === "string" ? input.split(",").map((part) => part.trim()) : null;
10312
+ const tileSize = positiveInteger(
10313
+ parts ? Number(parts[0]) : input.tileSize,
10314
+ "tileSize"
10315
+ );
10316
+ const levels = parts ? parts.slice(1).map((part) => {
10317
+ const match = /^(\d+)\s*x\s*(\d+)$/i.exec(part);
10318
+ if (!match)
10319
+ throw new Error("sphere multires levels must use widthxheight");
10320
+ return { width: Number(match[1]), height: Number(match[2]) };
10321
+ }) : input.levels.map((level) => ({ ...level }));
10322
+ if (levels.length === 0)
10323
+ throw new Error("sphere multires needs at least one level");
10324
+ levels.forEach((level, index) => {
10325
+ positiveInteger(level.width, "level width");
10326
+ positiveInteger(level.height, "level height");
10327
+ if (Math.abs(level.width - level.height * 2) > 2)
10328
+ throw new Error("sphere levels must be full 2:1 equirectangular images");
10329
+ const previous = levels[index - 1];
10330
+ if (previous && (level.width <= previous.width || level.height <= previous.height)) {
10331
+ throw new Error("sphere multires dimensions must be strictly ascending");
10332
+ }
10333
+ });
10334
+ return { tileSize, levels };
10335
+ }
10336
+ function resolveSphereTemplateUrl(template, address, indexBase = 1) {
10337
+ return template.replace(/%l/g, String(address.level + indexBase)).replace(
10338
+ /%(0*)([hxucvywr])/g,
10339
+ (_match, zeroes, placeholder) => String(
10340
+ ("hxuc".includes(placeholder) ? address.col : address.row) + indexBase
10341
+ ).padStart(zeroes.length + 1, "0")
10342
+ );
10343
+ }
10344
+ function sphereTileKey(address) {
10345
+ return `${address.level}/${address.row}/${address.col}`;
10346
+ }
10347
+ function sphereTileAddresses(size, level, tileSize) {
10348
+ const addresses = [];
10349
+ for (let row = 0; row < Math.ceil(size.height / tileSize); row++) {
10350
+ for (let col = 0; col < Math.ceil(size.width / tileSize); col++) {
10351
+ addresses.push({
10352
+ level,
10353
+ col,
10354
+ row,
10355
+ imageWidth: size.width,
10356
+ imageHeight: size.height,
10357
+ tileSize,
10358
+ width: Math.min(tileSize, size.width - col * tileSize),
10359
+ height: Math.min(tileSize, size.height - row * tileSize)
10360
+ });
10361
+ }
10362
+ }
10363
+ return addresses;
10364
+ }
10365
+ function sphereTileRange(address) {
10366
+ return {
10367
+ left: address.col * address.tileSize / address.imageWidth,
10368
+ right: (address.col * address.tileSize + address.width) / address.imageWidth,
10369
+ top: address.row * address.tileSize / address.imageHeight,
10370
+ bottom: (address.row * address.tileSize + address.height) / address.imageHeight
10371
+ };
10372
+ }
10373
+ function spherePoint(u, v, yawOffset = 0, radius = DEFAULT_PANORAMA_RADIUS) {
10374
+ const yaw = (u - 0.5) * Math.PI * 2 + MathUtils5.degToRad(yawOffset);
10375
+ const pitch = (0.5 - v) * Math.PI;
10376
+ return new Vector38(
10377
+ Math.sin(yaw) * Math.cos(pitch) * radius,
10378
+ Math.sin(pitch) * radius,
10379
+ -Math.cos(yaw) * Math.cos(pitch) * radius
10380
+ );
10381
+ }
10382
+ function sphereTileBounds(address, yawOffset) {
10383
+ const { left, right, top, bottom } = sphereTileRange(address);
10384
+ const us = [left, right];
10385
+ for (let i = -4; i <= 8; i++) {
10386
+ const u = 0.5 + (i * 90 - yawOffset % 360) / 360;
10387
+ if (u > left && u < right) us.push(u);
10388
+ }
10389
+ const vs = top < 0.5 && bottom > 0.5 ? [top, 0.5, bottom] : [top, bottom];
10390
+ return new Box3().setFromPoints(
10391
+ us.flatMap((u) => vs.map((v) => spherePoint(u, v, yawOffset)))
10392
+ );
10393
+ }
10394
+ function sphereTileGeometry(address, yawOffset, radius = DEFAULT_PANORAMA_RADIUS) {
10395
+ const { left, right, top, bottom } = sphereTileRange(address);
10396
+ const columns = Math.max(2, Math.ceil((right - left) * 360 / 3));
10397
+ const rows = Math.max(2, Math.ceil((bottom - top) * 180 / 3));
10398
+ const positions = [], uvs = [], indices = [];
10399
+ for (let row = 0; row <= rows; row++) {
10400
+ for (let col = 0; col <= columns; col++) {
10401
+ const u = col / columns, v = row / rows;
10402
+ const point = spherePoint(
10403
+ left + (right - left) * u,
10404
+ top + (bottom - top) * v,
10405
+ yawOffset,
10406
+ radius
10407
+ );
10408
+ positions.push(point.x, point.y, point.z);
10409
+ uvs.push(u, 1 - v);
10410
+ if (row < rows && col < columns) {
10411
+ const a = row * (columns + 1) + col, b = a + 1, c = a + columns + 1, d = c + 1;
10412
+ indices.push(a, b, c, b, d, c);
10413
+ }
10414
+ }
10415
+ }
10416
+ const geometry = new BufferGeometry();
10417
+ geometry.setAttribute("position", new Float32BufferAttribute(positions, 3));
10418
+ geometry.setAttribute("uv", new Float32BufferAttribute(uvs, 2));
10419
+ geometry.setIndex(indices);
10420
+ geometry.computeBoundingSphere();
10421
+ return geometry;
10422
+ }
10423
+ function preferredSphereLevel(levels, height, dpr, verticalFov) {
10424
+ const needed = height * dpr * 180 / Math.max(1, verticalFov);
10425
+ const index = levels.findIndex((level) => level.height >= needed);
10426
+ return index < 0 ? levels.length - 1 : index;
10427
+ }
10428
+
10429
+ // src/sphere-tile/sphere-tile.tsx
10430
+ import { jsx as jsx15, jsxs as jsxs9 } from "react/jsx-runtime";
10431
+ function SpherePatch({
10432
+ address,
10433
+ texture,
10434
+ yawOffset,
10435
+ preview = false
10436
+ }) {
10437
+ const geometry = useMemo14(
10438
+ () => sphereTileGeometry(
10439
+ address,
10440
+ yawOffset,
10441
+ DEFAULT_PANORAMA_RADIUS + (preview ? 0.05 : 0)
10442
+ ),
10443
+ [address, yawOffset, preview]
10444
+ );
10445
+ useEffect22(() => () => geometry.dispose(), [geometry]);
10446
+ return /* @__PURE__ */ jsx15(
10447
+ "mesh",
10448
+ {
10449
+ geometry,
10450
+ renderOrder: preview ? -1e3 : -900 + address.level,
10451
+ children: /* @__PURE__ */ jsx15(
10452
+ PanoBasicMaterial,
10453
+ {
10454
+ map: texture,
10455
+ side: BackSide2,
10456
+ depthTest: false,
10457
+ depthWrite: false,
10458
+ toneMapped: false
10459
+ }
10460
+ )
10461
+ }
10462
+ );
10463
+ }
10464
+ var ManagedPatch = memo(function ManagedPatch2({
10465
+ address,
10466
+ manager,
10467
+ resolveUrl,
10468
+ yawOffset,
10469
+ ready
10470
+ }) {
10471
+ const url = resolveUrl(address);
10472
+ const snapshot = useManagedTexture(
10473
+ manager,
10474
+ `${url}\0${sphereTileKey(address)}`,
10475
+ url,
10476
+ address
10477
+ );
10478
+ useEffect22(() => {
10479
+ if (snapshot.texture) ready();
10480
+ }, [snapshot.texture, ready]);
10481
+ return snapshot.texture ? /* @__PURE__ */ jsx15(
10482
+ SpherePatch,
10483
+ {
10484
+ address,
10485
+ texture: snapshot.texture,
10486
+ yawOffset
10487
+ }
10488
+ ) : null;
10489
+ });
10490
+ function SphereTileSource({
10491
+ config,
10492
+ baseUrl,
10493
+ previewUrl,
10494
+ urlTemplate = "tiles/%l/%h_%v.webp",
10495
+ indexBase = 1,
10496
+ resolveTileUrl,
10497
+ yawOffset = 0,
10498
+ maxTextureMemoryMb = 128,
10499
+ maxConcurrentLoads = 4,
10500
+ retryCount = 1,
10501
+ loadMode = "full",
10502
+ visible = true,
10503
+ onReady,
10504
+ onPreviewError,
10505
+ onLoadProgress,
10506
+ onTileError,
10507
+ onLevelChange
10508
+ }) {
10509
+ const { camera, gl, size } = useThree13();
10510
+ const anisotropy = gl.capabilities.getMaxAnisotropy();
10511
+ const preview = usePreviewTexture(
10512
+ resolveAssetUrl(baseUrl, previewUrl),
10513
+ anisotropy,
10514
+ onPreviewError
10515
+ );
10516
+ const callbacks = useRef23({
10517
+ onReady,
10518
+ onLoadProgress,
10519
+ onTileError,
10520
+ onLevelChange
10521
+ });
10522
+ callbacks.current = { onReady, onLoadProgress, onTileError, onLevelChange };
10523
+ const budget = Math.max(
10524
+ 1,
10525
+ Number.isFinite(maxTextureMemoryMb) ? maxTextureMemoryMb : 128
10526
+ ) * 1024 * 1024;
10527
+ const manager = useMemo14(
10528
+ () => new TileTextureManager({
10529
+ anisotropy,
10530
+ maxBytes: budget,
10531
+ concurrency: Math.max(
10532
+ 1,
10533
+ Math.floor(
10534
+ Number.isFinite(maxConcurrentLoads) ? maxConcurrentLoads : 4
10535
+ )
10536
+ ),
10537
+ retryCount: Math.max(
10538
+ 0,
10539
+ Math.floor(Number.isFinite(retryCount) ? retryCount : 1)
10540
+ ),
10541
+ onProgress: (progress) => callbacks.current.onLoadProgress?.(progress),
10542
+ onError: (error) => callbacks.current.onTileError?.(error)
10543
+ }),
10544
+ [anisotropy, budget, maxConcurrentLoads, retryCount]
10545
+ );
10546
+ const readyRef = useRef23(false);
10547
+ const ready = useCallback9(() => {
10548
+ if (!readyRef.current) {
10549
+ readyRef.current = true;
10550
+ callbacks.current.onReady?.();
10551
+ }
10552
+ }, []);
10553
+ useEffect22(() => {
10554
+ if (preview) ready();
10555
+ }, [preview, ready]);
10556
+ useEffect22(() => {
10557
+ manager.resume();
10558
+ return () => manager.dispose();
10559
+ }, [manager]);
10560
+ const resolveUrl = useMemo14(
10561
+ () => (address) => resolveAssetUrl(
10562
+ baseUrl,
10563
+ resolveTileUrl ? resolveTileUrl(address) : resolveSphereTemplateUrl(urlTemplate, address, indexBase)
10564
+ ),
10565
+ [baseUrl, resolveTileUrl, urlTemplate, indexBase]
10566
+ );
10567
+ const candidates = useMemo14(
10568
+ () => config.levels.map(
10569
+ (level, index) => sphereTileAddresses(level, index, config.tileSize).map((address) => ({
10570
+ address,
10571
+ bounds: sphereTileBounds(address, yawOffset)
10572
+ }))
10573
+ ),
10574
+ [config, yawOffset]
10575
+ );
10576
+ const previewAddress = useMemo14(
10577
+ () => sphereTileAddresses({ width: 2, height: 1 }, 0, 2)[0],
10578
+ []
10579
+ );
10580
+ const [layers, setLayers] = useState10([]);
10581
+ const scratch = useMemo14(
10582
+ () => ({
10583
+ camera: new PerspectiveCamera3(),
10584
+ frustum: new Frustum(),
10585
+ matrix: new Matrix42(),
10586
+ quaternion: camera.quaternion.clone(),
10587
+ fov: NaN,
10588
+ width: 0,
10589
+ height: 0,
10590
+ dpr: 0,
10591
+ time: -Infinity,
10592
+ token: "",
10593
+ level: -1,
10594
+ loadMode: "",
10595
+ manager: null
10596
+ }),
10597
+ [camera, candidates]
10598
+ );
10599
+ useFrame9(() => {
10600
+ if (!(camera instanceof PerspectiveCamera3)) return;
10601
+ const now = performance.now(), dpr = gl.getPixelRatio();
10602
+ const reset = scratch.manager !== manager || scratch.loadMode !== loadMode;
10603
+ 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))
10604
+ return;
10605
+ scratch.time = now;
10606
+ scratch.fov = camera.fov;
10607
+ scratch.width = size.width;
10608
+ scratch.height = size.height;
10609
+ scratch.dpr = dpr;
10610
+ scratch.quaternion.copy(camera.quaternion);
10611
+ scratch.manager = manager;
10612
+ scratch.loadMode = loadMode;
10613
+ scratch.camera.copy(camera, false);
10614
+ scratch.camera.fov = Math.min(179, camera.fov + 8);
10615
+ scratch.camera.updateProjectionMatrix();
10616
+ scratch.camera.updateMatrixWorld();
10617
+ scratch.matrix.multiplyMatrices(
10618
+ scratch.camera.projectionMatrix,
10619
+ scratch.camera.matrixWorldInverse
10620
+ );
10621
+ scratch.frustum.setFromProjectionMatrix(scratch.matrix);
10622
+ let level = loadMode === "preview" ? -1 : loadMode === "base" ? 0 : preferredSphereLevel(config.levels, size.height, dpr, camera.fov);
10623
+ const next = [];
10624
+ let residentBytes = 0;
10625
+ for (let index = 0; index <= level; index++) {
10626
+ const addresses = candidates[index].filter(
10627
+ ({ bounds }) => scratch.frustum.intersectsBox(bounds)
10628
+ ).map(({ address }) => address);
10629
+ const bytes = addresses.reduce(
10630
+ (total, address) => total + address.width * address.height * 4,
10631
+ 0
10632
+ );
10633
+ if (residentBytes + bytes > budget) {
10634
+ level = index - 1;
10635
+ break;
10636
+ }
10637
+ residentBytes += bytes;
10638
+ next.push({ level: index, addresses });
10639
+ }
10640
+ if (level !== scratch.level) {
10641
+ scratch.level = level;
10642
+ if (level >= 0) callbacks.current.onLevelChange?.(level);
10643
+ }
10644
+ const token = next.map((layer) => layer.addresses.map(sphereTileKey).join(",")).join(";");
10645
+ if (token !== scratch.token || reset) {
10646
+ scratch.token = token;
10647
+ setLayers(next);
10648
+ }
10649
+ });
10650
+ return /* @__PURE__ */ jsxs9("group", { visible, children: [
10651
+ preview ? /* @__PURE__ */ jsx15(
10652
+ SpherePatch,
10653
+ {
10654
+ address: previewAddress,
10655
+ texture: preview,
10656
+ yawOffset,
10657
+ preview: true
10658
+ }
10659
+ ) : null,
10660
+ loadMode !== "preview" ? layers.flatMap(
10661
+ (layer) => layer.addresses.map((address) => /* @__PURE__ */ jsx15(
10662
+ ManagedPatch,
10663
+ {
10664
+ address,
10665
+ manager,
10666
+ resolveUrl,
10667
+ yawOffset,
10668
+ ready
10669
+ },
10670
+ sphereTileKey(address)
10671
+ ))
10672
+ ) : null
10673
+ ] });
10674
+ }
10675
+ function SphereTile({ multires, ...props }) {
10676
+ const token = typeof multires === "string" ? multires : JSON.stringify(multires);
10677
+ const config = useMemo14(() => parseSphereMultires(multires), [token]);
10678
+ const sourceKey = `${props.baseUrl}\0${token}\0${props.previewUrl}\0${props.urlTemplate ?? ""}\0${props.indexBase ?? 1}`;
10679
+ return /* @__PURE__ */ jsx15(SphereTileSource, { ...props, config }, sourceKey);
10680
+ }
10681
+
10682
+ // src/sphere.tsx
10038
10683
  import { useThree as useThree14 } from "@react-three/fiber";
10684
+ import { useEffect as useEffect23, useMemo as useMemo15, useRef as useRef24, useState as useState11 } from "react";
10685
+ import {
10686
+ BackSide as BackSide3,
10687
+ LinearFilter as LinearFilter3,
10688
+ LinearMipmapLinearFilter,
10689
+ MathUtils as MathUtils6,
10690
+ RepeatWrapping,
10691
+ SRGBColorSpace as SRGBColorSpace3,
10692
+ TextureLoader as TextureLoader3
10693
+ } from "three";
10694
+ import { jsx as jsx16, jsxs as jsxs10 } from "react/jsx-runtime";
10695
+ function useEquirectTexture(url, anisotropy, generateMipmaps, onLoad, onError) {
10696
+ const [texture, setTexture] = useState11(null);
10697
+ const onLoadRef = useRef24(onLoad);
10698
+ const onErrorRef = useRef24(onError);
10699
+ onLoadRef.current = onLoad;
10700
+ onErrorRef.current = onError;
10701
+ useEffect23(() => {
10702
+ if (!url) {
10703
+ setTexture(null);
10704
+ return;
10705
+ }
10706
+ let active = true;
10707
+ const loader = new TextureLoader3();
10708
+ setTexture(null);
10709
+ loader.load(
10710
+ url,
10711
+ (loadedTexture) => {
10712
+ if (!active) {
10713
+ loadedTexture.dispose();
10714
+ return;
10715
+ }
10716
+ loadedTexture.colorSpace = SRGBColorSpace3;
10717
+ loadedTexture.wrapS = RepeatWrapping;
10718
+ loadedTexture.repeat.x = -1;
10719
+ loadedTexture.offset.x = 1;
10720
+ loadedTexture.anisotropy = anisotropy;
10721
+ loadedTexture.magFilter = LinearFilter3;
10722
+ loadedTexture.minFilter = generateMipmaps ? LinearMipmapLinearFilter : LinearFilter3;
10723
+ loadedTexture.generateMipmaps = generateMipmaps;
10724
+ loadedTexture.needsUpdate = true;
10725
+ setTexture(loadedTexture);
10726
+ onLoadRef.current?.(loadedTexture);
10727
+ },
10728
+ void 0,
10729
+ (error) => {
10730
+ if (active) {
10731
+ setTexture(null);
10732
+ onErrorRef.current?.(error);
10733
+ }
10734
+ }
10735
+ );
10736
+ return () => {
10737
+ active = false;
10738
+ };
10739
+ }, [anisotropy, generateMipmaps, url]);
10740
+ useEffect23(
10741
+ () => () => {
10742
+ texture?.dispose();
10743
+ },
10744
+ [texture]
10745
+ );
10746
+ return texture;
10747
+ }
10748
+ function Sphere({
10749
+ src,
10750
+ previewUrl,
10751
+ yawOffset = 0,
10752
+ onReady,
10753
+ onLoad,
10754
+ onError,
10755
+ onPreviewError,
10756
+ visible = true
10757
+ }) {
10758
+ const gl = useThree14((state) => state.gl);
10759
+ const anisotropy = gl.capabilities.getMaxAnisotropy();
10760
+ const resolvedPreviewUrl = useMemo15(
10761
+ () => resolveUrlAgainstFile(src, previewUrl),
10762
+ [previewUrl, src]
10763
+ );
10764
+ const texture = useEquirectTexture(
10765
+ src,
10766
+ anisotropy,
10767
+ true,
10768
+ onLoad,
10769
+ onError
10770
+ );
10771
+ const previewTexture = useEquirectTexture(
10772
+ texture ? null : resolvedPreviewUrl,
10773
+ anisotropy,
10774
+ false,
10775
+ void 0,
10776
+ onPreviewError
10777
+ );
10778
+ const displayTexture = texture ?? previewTexture;
10779
+ const readyRef = useRef24(false);
10780
+ useEffect23(() => {
10781
+ readyRef.current = false;
10782
+ }, [resolvedPreviewUrl, src]);
10783
+ useEffect23(() => {
10784
+ if (!displayTexture || readyRef.current) {
10785
+ return;
10786
+ }
10787
+ readyRef.current = true;
10788
+ onReady?.();
10789
+ }, [displayTexture, onReady]);
10790
+ if (!displayTexture) {
10791
+ return null;
10792
+ }
10793
+ return /* @__PURE__ */ jsxs10(
10794
+ "mesh",
10795
+ {
10796
+ rotation: [0, MathUtils6.degToRad(90 + yawOffset), 0],
10797
+ visible,
10798
+ children: [
10799
+ /* @__PURE__ */ jsx16("sphereGeometry", { args: [DEFAULT_PANORAMA_RADIUS, 128, 64] }),
10800
+ /* @__PURE__ */ jsx16(
10801
+ PanoBasicMaterial,
10802
+ {
10803
+ map: displayTexture,
10804
+ side: BackSide3,
10805
+ toneMapped: false
10806
+ }
10807
+ )
10808
+ ]
10809
+ }
10810
+ );
10811
+ }
10812
+
10813
+ // src/video/pano-video.tsx
10814
+ import { useThree as useThree15 } from "@react-three/fiber";
10039
10815
  import {
10040
- useCallback as useCallback9,
10816
+ useCallback as useCallback10,
10041
10817
  useContext as useContext21,
10042
- useEffect as useEffect22,
10818
+ useEffect as useEffect24,
10043
10819
  useLayoutEffect as useLayoutEffect3,
10044
- useMemo as useMemo15,
10045
- useRef as useRef23,
10046
- useState as useState10
10820
+ useMemo as useMemo16,
10821
+ useRef as useRef25,
10822
+ useState as useState12
10047
10823
  } from "react";
10048
10824
  import {
10049
- BackSide as BackSide3,
10050
- LinearFilter as LinearFilter2,
10825
+ BackSide as BackSide4,
10826
+ LinearFilter as LinearFilter4,
10051
10827
  LinearMipmapLinearFilter as LinearMipmapLinearFilter2,
10052
- MathUtils as MathUtils6,
10828
+ MathUtils as MathUtils7,
10053
10829
  RepeatWrapping as RepeatWrapping2,
10054
- SRGBColorSpace as SRGBColorSpace2,
10055
- TextureLoader as TextureLoader2,
10830
+ SRGBColorSpace as SRGBColorSpace4,
10831
+ TextureLoader as TextureLoader4,
10056
10832
  VideoTexture
10057
10833
  } from "three";
10058
- import { Fragment as Fragment5, jsx as jsx16, jsxs as jsxs10 } from "react/jsx-runtime";
10834
+ import { Fragment as Fragment5, jsx as jsx17, jsxs as jsxs11 } from "react/jsx-runtime";
10059
10835
  var EMPTY_TRACKS = [];
10060
10836
  var EMPTY_RATES = DEFAULT_PANO_VIDEO_PLAYBACK_RATES;
10061
10837
  function createEmptySnapshot() {
@@ -10131,7 +10907,7 @@ function findTextTrack(video, tracks, trackId) {
10131
10907
  return list.length > 0 ? list[0] : null;
10132
10908
  }
10133
10909
  function applyEquirectangularLayout(texture, anisotropy) {
10134
- texture.colorSpace = SRGBColorSpace2;
10910
+ texture.colorSpace = SRGBColorSpace4;
10135
10911
  texture.wrapS = RepeatWrapping2;
10136
10912
  texture.repeat.x = -1;
10137
10913
  texture.offset.x = 1;
@@ -10139,11 +10915,11 @@ function applyEquirectangularLayout(texture, anisotropy) {
10139
10915
  texture.needsUpdate = true;
10140
10916
  }
10141
10917
  function usePosterTexture(poster, onError) {
10142
- const gl = useThree14((state) => state.gl);
10143
- const [texture, setTexture] = useState10(null);
10144
- const onErrorRef = useRef23(onError);
10918
+ const gl = useThree15((state) => state.gl);
10919
+ const [texture, setTexture] = useState12(null);
10920
+ const onErrorRef = useRef25(onError);
10145
10921
  onErrorRef.current = onError;
10146
- useEffect22(() => {
10922
+ useEffect24(() => {
10147
10923
  let active = true;
10148
10924
  setTexture(null);
10149
10925
  if (!poster) {
@@ -10151,7 +10927,7 @@ function usePosterTexture(poster, onError) {
10151
10927
  active = false;
10152
10928
  };
10153
10929
  }
10154
- const loader = new TextureLoader2();
10930
+ const loader = new TextureLoader4();
10155
10931
  loader.load(
10156
10932
  poster,
10157
10933
  (loadedTexture) => {
@@ -10164,7 +10940,7 @@ function usePosterTexture(poster, onError) {
10164
10940
  gl.capabilities.getMaxAnisotropy()
10165
10941
  );
10166
10942
  loadedTexture.wrapT = RepeatWrapping2;
10167
- loadedTexture.magFilter = LinearFilter2;
10943
+ loadedTexture.magFilter = LinearFilter4;
10168
10944
  loadedTexture.minFilter = LinearMipmapLinearFilter2;
10169
10945
  loadedTexture.generateMipmaps = true;
10170
10946
  setTexture(loadedTexture);
@@ -10180,7 +10956,7 @@ function usePosterTexture(poster, onError) {
10180
10956
  active = false;
10181
10957
  };
10182
10958
  }, [gl, poster]);
10183
- useEffect22(
10959
+ useEffect24(
10184
10960
  () => () => {
10185
10961
  texture?.dispose();
10186
10962
  },
@@ -10238,39 +11014,39 @@ function PanoVideo({
10238
11014
  onTrackChange
10239
11015
  }) {
10240
11016
  usePanoMediaActivationIntent(autoPlay);
10241
- const gl = useThree14((state) => state.gl);
11017
+ const gl = useThree15((state) => state.gl);
10242
11018
  const host = useContext21(PanoVideoHostContext);
10243
11019
  const overlay = useContext21(PanoChromeOverlayContext);
10244
- const variants = useMemo15(
11020
+ const variants = useMemo16(
10245
11021
  () => resolvePanoVideoVariants({ poster, src, variants: variantsProp }),
10246
11022
  [poster, src, variantsProp]
10247
11023
  );
10248
11024
  const tracks = tracksProp ?? EMPTY_TRACKS;
10249
11025
  const captionsEnabled = captions !== false;
10250
- const captionAppearance = useMemo15(
11026
+ const captionAppearance = useMemo16(
10251
11027
  () => resolvePanoVideoCaptionAppearance(
10252
11028
  typeof captions === "object" ? captions : void 0
10253
11029
  ),
10254
11030
  [captions]
10255
11031
  );
10256
- const [variantId, setVariantId] = useState10(
11032
+ const [variantId, setVariantId] = useState12(
10257
11033
  () => resolvePanoVideoVariantId(variants, defaultVariantId)
10258
11034
  );
10259
- const [trackId, setTrackId] = useState10(
11035
+ const [trackId, setTrackId] = useState12(
10260
11036
  () => captionsEnabled ? defaultPanoVideoTrackId(tracks) : null
10261
11037
  );
10262
- const [ready, setReady] = useState10(false);
10263
- const autoPlayRef = useRef23(autoPlay);
11038
+ const [ready, setReady] = useState12(false);
11039
+ const autoPlayRef = useRef25(autoPlay);
10264
11040
  autoPlayRef.current = autoPlay;
10265
- const blockedRef = useRef23(false);
10266
- const captionAppearanceOverrideRef = useRef23(
11041
+ const blockedRef = useRef25(false);
11042
+ const captionAppearanceOverrideRef = useRef25(
10267
11043
  {}
10268
11044
  );
10269
- const mediaCapabilitiesRef = useRef23({
11045
+ const mediaCapabilitiesRef = useRef25({
10270
11046
  volumeAdjustable: true,
10271
11047
  playbackRates: [...DEFAULT_PANO_VIDEO_PLAYBACK_RATES]
10272
11048
  });
10273
- const storeRef = useRef23(null);
11049
+ const storeRef = useRef25(null);
10274
11050
  if (!storeRef.current) {
10275
11051
  storeRef.current = {
10276
11052
  snapshot: {
@@ -10280,7 +11056,7 @@ function PanoVideo({
10280
11056
  listeners: /* @__PURE__ */ new Set()
10281
11057
  };
10282
11058
  }
10283
- const actionsRef = useRef23({
11059
+ const actionsRef = useRef25({
10284
11060
  play: async () => {
10285
11061
  },
10286
11062
  pause: () => {
@@ -10300,19 +11076,19 @@ function PanoVideo({
10300
11076
  setCaptionAppearance: (_appearance) => {
10301
11077
  }
10302
11078
  });
10303
- const onLoadRef = useRef23(onLoad);
10304
- const onErrorRef = useRef23(onError);
10305
- const onPlaybackStateChangeRef = useRef23(onPlaybackStateChange);
10306
- const onEndedRef = useRef23(onEnded);
10307
- const onVariantChangeRef = useRef23(onVariantChange);
10308
- const onTrackChangeRef = useRef23(onTrackChange);
11079
+ const onLoadRef = useRef25(onLoad);
11080
+ const onErrorRef = useRef25(onError);
11081
+ const onPlaybackStateChangeRef = useRef25(onPlaybackStateChange);
11082
+ const onEndedRef = useRef25(onEnded);
11083
+ const onVariantChangeRef = useRef25(onVariantChange);
11084
+ const onTrackChangeRef = useRef25(onTrackChange);
10309
11085
  onLoadRef.current = onLoad;
10310
11086
  onErrorRef.current = onError;
10311
11087
  onPlaybackStateChangeRef.current = onPlaybackStateChange;
10312
11088
  onEndedRef.current = onEnded;
10313
11089
  onVariantChangeRef.current = onVariantChange;
10314
11090
  onTrackChangeRef.current = onTrackChange;
10315
- const resource = useMemo15(() => {
11091
+ const resource = useMemo16(() => {
10316
11092
  if (typeof document === "undefined") {
10317
11093
  return null;
10318
11094
  }
@@ -10324,12 +11100,12 @@ function PanoVideo({
10324
11100
  video.preload = "metadata";
10325
11101
  const texture = new VideoTexture(video);
10326
11102
  applyEquirectangularLayout(texture, 1);
10327
- texture.magFilter = LinearFilter2;
10328
- texture.minFilter = LinearFilter2;
11103
+ texture.magFilter = LinearFilter4;
11104
+ texture.minFilter = LinearFilter4;
10329
11105
  texture.generateMipmaps = false;
10330
11106
  return { video, texture };
10331
11107
  }, []);
10332
- useEffect22(
11108
+ useEffect24(
10333
11109
  () => () => {
10334
11110
  if (!resource) {
10335
11111
  return;
@@ -10344,13 +11120,13 @@ function PanoVideo({
10344
11120
  },
10345
11121
  [resource]
10346
11122
  );
10347
- useEffect22(() => {
11123
+ useEffect24(() => {
10348
11124
  if (!resource) {
10349
11125
  return;
10350
11126
  }
10351
11127
  resource.texture.anisotropy = gl.capabilities.getMaxAnisotropy();
10352
11128
  }, [gl, resource]);
10353
- useEffect22(() => {
11129
+ useEffect24(() => {
10354
11130
  if (!resource || !overlay?.overlayElement) {
10355
11131
  return;
10356
11132
  }
@@ -10373,7 +11149,7 @@ function PanoVideo({
10373
11149
  activeVariant?.poster ?? poster,
10374
11150
  onError
10375
11151
  );
10376
- const emitSnapshot = useCallback9(
11152
+ const emitSnapshot = useCallback10(
10377
11153
  (patch) => {
10378
11154
  const store = storeRef.current;
10379
11155
  const video = resource?.video;
@@ -10425,7 +11201,7 @@ function PanoVideo({
10425
11201
  captionAppearance
10426
11202
  ]
10427
11203
  );
10428
- const controller = useMemo15(
11204
+ const controller = useMemo16(
10429
11205
  () => ({
10430
11206
  subscribe: (onStoreChange) => {
10431
11207
  const store = storeRef.current;
@@ -10503,10 +11279,10 @@ function PanoVideo({
10503
11279
  };
10504
11280
  emitSnapshot();
10505
11281
  }, [emitSnapshot, playbackRates, resource]);
10506
- useEffect22(() => {
11282
+ useEffect24(() => {
10507
11283
  emitSnapshot();
10508
11284
  }, [emitSnapshot]);
10509
- useEffect22(() => {
11285
+ useEffect24(() => {
10510
11286
  if (!resource || !activeVariant || !mediaKey) {
10511
11287
  return;
10512
11288
  }
@@ -10563,7 +11339,7 @@ function PanoVideo({
10563
11339
  video.removeEventListener("error", handleError);
10564
11340
  };
10565
11341
  }, [mediaKey, resource]);
10566
- useEffect22(() => {
11342
+ useEffect24(() => {
10567
11343
  if (!resource) {
10568
11344
  return;
10569
11345
  }
@@ -10574,8 +11350,10 @@ function PanoVideo({
10574
11350
  try {
10575
11351
  await video.play();
10576
11352
  } catch (error) {
10577
- blockedRef.current = true;
10578
- onPlaybackStateChangeRef.current?.("blocked");
11353
+ if (isAutoplayPolicyError(error)) {
11354
+ blockedRef.current = true;
11355
+ onPlaybackStateChangeRef.current?.("blocked");
11356
+ }
10579
11357
  onErrorRef.current?.({ source: "video", error });
10580
11358
  emitSnapshot();
10581
11359
  }
@@ -10653,7 +11431,7 @@ function PanoVideo({
10653
11431
  }
10654
11432
  };
10655
11433
  }, [emitSnapshot, resource]);
10656
- useEffect22(() => {
11434
+ useEffect24(() => {
10657
11435
  if (!resource) {
10658
11436
  return;
10659
11437
  }
@@ -10673,7 +11451,7 @@ function PanoVideo({
10673
11451
  }
10674
11452
  video.preload = preload;
10675
11453
  }, [loop, muted, playsInline, preload, resource, volume]);
10676
- useEffect22(() => {
11454
+ useEffect24(() => {
10677
11455
  if (!resource) {
10678
11456
  return;
10679
11457
  }
@@ -10723,7 +11501,7 @@ function PanoVideo({
10723
11501
  video.removeEventListener("ratechange", handleVolume);
10724
11502
  };
10725
11503
  }, [emitSnapshot, resource]);
10726
- useEffect22(() => {
11504
+ useEffect24(() => {
10727
11505
  if (!resource) {
10728
11506
  return;
10729
11507
  }
@@ -10758,7 +11536,7 @@ function PanoVideo({
10758
11536
  video.textTracks.removeEventListener("change", applyModes);
10759
11537
  };
10760
11538
  }, [emitSnapshot, resource, trackId, tracks]);
10761
- useEffect22(() => {
11539
+ useEffect24(() => {
10762
11540
  if (!captionsEnabled) {
10763
11541
  setTrackId(null);
10764
11542
  return;
@@ -10769,39 +11547,39 @@ function PanoVideo({
10769
11547
  if (variants.length === 0) {
10770
11548
  return null;
10771
11549
  }
10772
- return /* @__PURE__ */ jsxs10(Fragment5, { children: [
10773
- activeTexture ? /* @__PURE__ */ jsxs10(
11550
+ return /* @__PURE__ */ jsxs11(Fragment5, { children: [
11551
+ activeTexture ? /* @__PURE__ */ jsxs11(
10774
11552
  "mesh",
10775
11553
  {
10776
- rotation: [0, MathUtils6.degToRad(90 + yawOffset), 0],
11554
+ rotation: [0, MathUtils7.degToRad(90 + yawOffset), 0],
10777
11555
  visible,
10778
11556
  children: [
10779
- /* @__PURE__ */ jsx16("sphereGeometry", { args: [DEFAULT_PANORAMA_RADIUS, 128, 64] }),
10780
- /* @__PURE__ */ jsx16(
11557
+ /* @__PURE__ */ jsx17("sphereGeometry", { args: [DEFAULT_PANORAMA_RADIUS, 128, 64] }),
11558
+ /* @__PURE__ */ jsx17(
10781
11559
  PanoBasicMaterial,
10782
11560
  {
10783
11561
  map: activeTexture,
10784
- side: BackSide3,
11562
+ side: BackSide4,
10785
11563
  toneMapped: false
10786
11564
  }
10787
11565
  )
10788
11566
  ]
10789
11567
  }
10790
11568
  ) : null,
10791
- captionsEnabled ? /* @__PURE__ */ jsx16(PanoVideoCaptions, { appearance: typeof captions === "object" ? captions : void 0 }) : null
11569
+ captionsEnabled ? /* @__PURE__ */ jsx17(PanoVideoCaptions, { appearance: typeof captions === "object" ? captions : void 0 }) : null
10792
11570
  ] });
10793
11571
  }
10794
11572
 
10795
11573
  // src/scenes.tsx
10796
- import { useFrame as useFrame12, useThree as useThree19 } from "@react-three/fiber";
11574
+ import { useFrame as useFrame13, useThree as useThree20 } from "@react-three/fiber";
10797
11575
  import {
10798
11576
  Fragment as Fragment6,
10799
- useCallback as useCallback10,
11577
+ useCallback as useCallback11,
10800
11578
  useContext as useContext23,
10801
- useEffect as useEffect27,
10802
- useMemo as useMemo20,
10803
- useRef as useRef27,
10804
- useState as useState12
11579
+ useEffect as useEffect29,
11580
+ useMemo as useMemo21,
11581
+ useRef as useRef29,
11582
+ useState as useState14
10805
11583
  } from "react";
10806
11584
  import {
10807
11585
  LinearSRGBColorSpace,
@@ -10856,8 +11634,8 @@ function isSnapshotTransition(preset) {
10856
11634
  }
10857
11635
 
10858
11636
  // src/scene-transitions/particle-overlay.tsx
10859
- import { useFrame as useFrame9, useThree as useThree15 } from "@react-three/fiber";
10860
- import { useEffect as useEffect23, useMemo as useMemo16, useRef as useRef24 } from "react";
11637
+ import { useFrame as useFrame10, useThree as useThree16 } from "@react-three/fiber";
11638
+ import { useEffect as useEffect25, useMemo as useMemo17, useRef as useRef26 } from "react";
10861
11639
  import {
10862
11640
  DoubleSide as DoubleSide2,
10863
11641
  InstancedBufferAttribute,
@@ -10865,7 +11643,7 @@ import {
10865
11643
  PlaneGeometry as PlaneGeometry3,
10866
11644
  ShaderMaterial as ShaderMaterial2,
10867
11645
  Vector2 as Vector24,
10868
- Vector3 as Vector39
11646
+ Vector3 as Vector310
10869
11647
  } from "three";
10870
11648
 
10871
11649
  // src/scene-transitions/glsl.ts
@@ -10920,7 +11698,7 @@ function overlayProgress(elapsedTime, duration, startTime) {
10920
11698
  }
10921
11699
 
10922
11700
  // src/scene-transitions/particle-overlay.tsx
10923
- import { jsx as jsx17 } from "react/jsx-runtime";
11701
+ import { jsx as jsx18 } from "react/jsx-runtime";
10924
11702
  var PARTICLE_GRID = 48;
10925
11703
  var PARTICLE_COUNT = PARTICLE_GRID * PARTICLE_GRID;
10926
11704
  var PARTICLE_VERTEX_SHADER = `
@@ -10996,13 +11774,13 @@ function ParticleOverlay({
10996
11774
  runId,
10997
11775
  onFinish
10998
11776
  }) {
10999
- const { camera } = useThree15();
11000
- const meshRef = useRef24(null);
11001
- const startRef = useRef24(null);
11002
- const finishedRef = useRef24(false);
11003
- const directionRef = useRef24(new Vector39());
11004
- const geometry = useMemo16(() => createParticleGeometry(), []);
11005
- const material = useMemo16(
11777
+ const { camera } = useThree16();
11778
+ const meshRef = useRef26(null);
11779
+ const startRef = useRef26(null);
11780
+ const finishedRef = useRef26(false);
11781
+ const directionRef = useRef26(new Vector310());
11782
+ const geometry = useMemo17(() => createParticleGeometry(), []);
11783
+ const material = useMemo17(
11006
11784
  () => new ShaderMaterial2({
11007
11785
  transparent: true,
11008
11786
  depthTest: false,
@@ -11018,14 +11796,14 @@ function ParticleOverlay({
11018
11796
  }),
11019
11797
  [snapshot.texture]
11020
11798
  );
11021
- useEffect23(() => () => geometry.dispose(), [geometry]);
11022
- useEffect23(() => () => material.dispose(), [material]);
11023
- useEffect23(() => {
11799
+ useEffect25(() => () => geometry.dispose(), [geometry]);
11800
+ useEffect25(() => () => material.dispose(), [material]);
11801
+ useEffect25(() => {
11024
11802
  startRef.current = null;
11025
11803
  finishedRef.current = false;
11026
11804
  material.uniforms.progress.value = 0;
11027
11805
  }, [material, runId]);
11028
- useFrame9((state) => {
11806
+ useFrame10((state) => {
11029
11807
  const mesh = meshRef.current;
11030
11808
  if (!mesh || !isPerspectiveCamera(camera)) {
11031
11809
  return;
@@ -11042,7 +11820,7 @@ function ParticleOverlay({
11042
11820
  onFinish();
11043
11821
  }
11044
11822
  });
11045
- return /* @__PURE__ */ jsx17(
11823
+ return /* @__PURE__ */ jsx18(
11046
11824
  "mesh",
11047
11825
  {
11048
11826
  ref: meshRef,
@@ -11055,9 +11833,9 @@ function ParticleOverlay({
11055
11833
  }
11056
11834
 
11057
11835
  // src/scene-transitions/snapshot-overlay.tsx
11058
- import { useFrame as useFrame10, useThree as useThree16 } from "@react-three/fiber";
11059
- import { useEffect as useEffect24, useMemo as useMemo17, useRef as useRef25 } from "react";
11060
- import { Vector3 as Vector310 } from "three";
11836
+ import { useFrame as useFrame11, useThree as useThree17 } from "@react-three/fiber";
11837
+ import { useEffect as useEffect26, useMemo as useMemo18, useRef as useRef27 } from "react";
11838
+ import { Vector3 as Vector311 } from "three";
11061
11839
 
11062
11840
  // src/scene-transitions/snapshot-shaders.ts
11063
11841
  import { DoubleSide as DoubleSide3, ShaderMaterial as ShaderMaterial3, Vector2 as Vector25 } from "three";
@@ -11336,7 +12114,7 @@ function createSnapshotMaterial(preset, texture) {
11336
12114
  }
11337
12115
 
11338
12116
  // src/scene-transitions/snapshot-overlay.tsx
11339
- import { jsx as jsx18, jsxs as jsxs11 } from "react/jsx-runtime";
12117
+ import { jsx as jsx19, jsxs as jsxs12 } from "react/jsx-runtime";
11340
12118
  function SnapshotOverlay({
11341
12119
  snapshot,
11342
12120
  transition,
@@ -11344,26 +12122,26 @@ function SnapshotOverlay({
11344
12122
  runId,
11345
12123
  onFinish
11346
12124
  }) {
11347
- const { camera, gl } = useThree16();
11348
- const meshRef = useRef25(null);
11349
- const startRef = useRef25(null);
11350
- const finishedRef = useRef25(false);
11351
- const directionRef = useRef25(new Vector310());
11352
- const material = useMemo17(() => {
12125
+ const { camera, gl } = useThree17();
12126
+ const meshRef = useRef27(null);
12127
+ const startRef = useRef27(null);
12128
+ const finishedRef = useRef27(false);
12129
+ const directionRef = useRef27(new Vector311());
12130
+ const material = useMemo18(() => {
11353
12131
  if (!isSnapshotTransition(transition.preset)) {
11354
12132
  return null;
11355
12133
  }
11356
12134
  return createSnapshotMaterial(transition.preset, snapshot.texture);
11357
12135
  }, [snapshot.texture, transition.preset]);
11358
- useEffect24(() => () => material?.dispose(), [material]);
11359
- useEffect24(() => {
12136
+ useEffect26(() => () => material?.dispose(), [material]);
12137
+ useEffect26(() => {
11360
12138
  startRef.current = null;
11361
12139
  finishedRef.current = false;
11362
12140
  if (material) {
11363
12141
  material.uniforms.progress.value = 0;
11364
12142
  }
11365
12143
  }, [material, runId]);
11366
- useFrame10((state) => {
12144
+ useFrame11((state) => {
11367
12145
  const mesh = meshRef.current;
11368
12146
  if (!mesh || !material || !isPerspectiveCamera(camera)) {
11369
12147
  return;
@@ -11385,21 +12163,21 @@ function SnapshotOverlay({
11385
12163
  if (!material) {
11386
12164
  return null;
11387
12165
  }
11388
- return /* @__PURE__ */ jsxs11("mesh", { ref: meshRef, renderOrder: OVERLAY_RENDER_ORDER, frustumCulled: false, children: [
11389
- /* @__PURE__ */ jsx18("primitive", { attach: "geometry", object: FULLSCREEN_PLANE }),
11390
- /* @__PURE__ */ jsx18("primitive", { attach: "material", object: material })
12166
+ return /* @__PURE__ */ jsxs12("mesh", { ref: meshRef, renderOrder: OVERLAY_RENDER_ORDER, frustumCulled: false, children: [
12167
+ /* @__PURE__ */ jsx19("primitive", { attach: "geometry", object: FULLSCREEN_PLANE }),
12168
+ /* @__PURE__ */ jsx19("primitive", { attach: "material", object: material })
11391
12169
  ] });
11392
12170
  }
11393
12171
 
11394
12172
  // src/scene-transitions/transition-overlay.tsx
11395
- import { jsx as jsx19 } from "react/jsx-runtime";
12173
+ import { jsx as jsx20 } from "react/jsx-runtime";
11396
12174
  function TransitionOverlay(props) {
11397
12175
  const { preset } = props.transition;
11398
12176
  switch (preset) {
11399
12177
  case "none":
11400
12178
  return null;
11401
12179
  case "particles":
11402
- return /* @__PURE__ */ jsx19(ParticleOverlay, { ...props });
12180
+ return /* @__PURE__ */ jsx20(ParticleOverlay, { ...props });
11403
12181
  case "crossfade":
11404
12182
  case "zoom":
11405
12183
  case "blackout":
@@ -11427,7 +12205,7 @@ function TransitionOverlay(props) {
11427
12205
  case "zoomBlur":
11428
12206
  case "hexDissolve":
11429
12207
  case "filmBurn":
11430
- return /* @__PURE__ */ jsx19(SnapshotOverlay, { ...props });
12208
+ return /* @__PURE__ */ jsx20(SnapshotOverlay, { ...props });
11431
12209
  default: {
11432
12210
  const exhaustive = preset;
11433
12211
  void exhaustive;
@@ -11437,242 +12215,14 @@ function TransitionOverlay(props) {
11437
12215
  }
11438
12216
 
11439
12217
  // src/tile/texture-manager-context.tsx
11440
- import { useThree as useThree17 } from "@react-three/fiber";
12218
+ import { useThree as useThree18 } from "@react-three/fiber";
11441
12219
  import {
11442
12220
  createContext as createContext15,
11443
12221
  useContext as useContext22,
11444
- useEffect as useEffect25,
11445
- useMemo as useMemo18
12222
+ useEffect as useEffect27,
12223
+ useMemo as useMemo19
11446
12224
  } from "react";
11447
-
11448
- // src/tile/texture-manager.ts
11449
- import {
11450
- ClampToEdgeWrapping,
11451
- LinearFilter as LinearFilter3,
11452
- SRGBColorSpace as SRGBColorSpace3,
11453
- TextureLoader as TextureLoader3
11454
- } from "three";
11455
- var EMPTY_TEXTURE_SNAPSHOT = {
11456
- status: "idle",
11457
- texture: null,
11458
- error: null
11459
- };
11460
- var TileTextureManager = class {
11461
- constructor(options) {
11462
- this.loader = new TextureLoader3();
11463
- this.entries = /* @__PURE__ */ new Map();
11464
- this.queue = [];
11465
- this.activeLoads = 0;
11466
- this.totalBytes = 0;
11467
- this.requested = 0;
11468
- this.loaded = 0;
11469
- this.failed = 0;
11470
- this.disposed = false;
11471
- this.generation = 0;
11472
- this.options = options;
11473
- }
11474
- resume() {
11475
- this.disposed = false;
11476
- this.drain();
11477
- }
11478
- getSnapshot(key) {
11479
- const entry = this.entries.get(key);
11480
- return entry ? this.snapshot(entry) : EMPTY_TEXTURE_SNAPSHOT;
11481
- }
11482
- acquire(key, url, address, listener) {
11483
- let entry = this.entries.get(key);
11484
- if (!entry) {
11485
- entry = {
11486
- key,
11487
- url,
11488
- address,
11489
- status: "idle",
11490
- texture: null,
11491
- error: null,
11492
- refs: 0,
11493
- listeners: /* @__PURE__ */ new Set(),
11494
- lastUsed: performance.now(),
11495
- bytes: 0
11496
- };
11497
- this.entries.set(key, entry);
11498
- }
11499
- entry.refs += 1;
11500
- entry.lastUsed = performance.now();
11501
- entry.listeners.add(listener);
11502
- listener(this.snapshot(entry));
11503
- if (entry.status === "idle") {
11504
- entry.status = "queued";
11505
- this.queue.push(entry);
11506
- this.requested += 1;
11507
- this.emitProgress();
11508
- this.drain();
11509
- }
11510
- return () => {
11511
- entry.listeners.delete(listener);
11512
- entry.refs = Math.max(0, entry.refs - 1);
11513
- entry.lastUsed = performance.now();
11514
- if (entry.refs === 0 && entry.status === "queued") {
11515
- const queueIndex = this.queue.indexOf(entry);
11516
- if (queueIndex >= 0) {
11517
- this.queue.splice(queueIndex, 1);
11518
- }
11519
- entry.status = "idle";
11520
- this.entries.delete(entry.key);
11521
- this.requested = Math.max(0, this.requested - 1);
11522
- this.emitProgress();
11523
- this.drain();
11524
- return;
11525
- }
11526
- this.evict();
11527
- };
11528
- }
11529
- dispose() {
11530
- this.disposed = true;
11531
- this.generation += 1;
11532
- this.queue.length = 0;
11533
- for (const entry of this.entries.values()) {
11534
- entry.texture?.dispose();
11535
- entry.listeners.clear();
11536
- }
11537
- this.entries.clear();
11538
- this.totalBytes = 0;
11539
- }
11540
- /**
11541
- * Releases textures that are no longer rendered by any Tile instance.
11542
- * Scene transitions call this after the outgoing panorama has been
11543
- * snapshotted, so the incoming scene never competes with stale GPU tiles.
11544
- */
11545
- releaseUnused() {
11546
- for (const entry of Array.from(this.entries.values())) {
11547
- if (entry.refs > 0) {
11548
- continue;
11549
- }
11550
- entry.texture?.dispose();
11551
- this.totalBytes -= entry.bytes;
11552
- this.entries.delete(entry.key);
11553
- }
11554
- this.totalBytes = Math.max(0, this.totalBytes);
11555
- }
11556
- snapshot(entry) {
11557
- return {
11558
- status: entry.status,
11559
- texture: entry.texture,
11560
- error: entry.error
11561
- };
11562
- }
11563
- notify(entry) {
11564
- const snapshot = this.snapshot(entry);
11565
- for (const listener of entry.listeners) {
11566
- listener(snapshot);
11567
- }
11568
- }
11569
- emitProgress() {
11570
- this.options.onProgress?.({
11571
- requested: this.requested,
11572
- loaded: this.loaded,
11573
- failed: this.failed,
11574
- active: this.activeLoads,
11575
- queued: this.queue.length
11576
- });
11577
- }
11578
- drain() {
11579
- while (!this.disposed && this.activeLoads < this.options.concurrency && this.queue.length > 0) {
11580
- const entry = this.queue.shift();
11581
- if (entry.refs === 0) {
11582
- entry.status = "idle";
11583
- this.entries.delete(entry.key);
11584
- this.requested = Math.max(0, this.requested - 1);
11585
- continue;
11586
- }
11587
- entry.status = "loading";
11588
- this.activeLoads += 1;
11589
- this.notify(entry);
11590
- this.emitProgress();
11591
- void this.loadAndFinish(entry);
11592
- }
11593
- }
11594
- async load(entry, generation) {
11595
- let lastError = null;
11596
- for (let attempt = 0; attempt <= this.options.retryCount; attempt += 1) {
11597
- try {
11598
- const texture = await this.loader.loadAsync(entry.url);
11599
- if (this.disposed || generation !== this.generation) {
11600
- texture.dispose();
11601
- return;
11602
- }
11603
- this.configureTexture(texture);
11604
- entry.texture = texture;
11605
- entry.status = "loaded";
11606
- entry.error = null;
11607
- entry.bytes = entry.address.width * entry.address.height * 4;
11608
- entry.lastUsed = performance.now();
11609
- this.totalBytes += entry.bytes;
11610
- this.loaded += 1;
11611
- this.notify(entry);
11612
- return;
11613
- } catch (error) {
11614
- lastError = error;
11615
- }
11616
- }
11617
- if (!this.disposed && generation === this.generation) {
11618
- entry.status = "error";
11619
- entry.error = lastError;
11620
- this.failed += 1;
11621
- this.notify(entry);
11622
- this.options.onError?.({
11623
- address: entry.address,
11624
- url: entry.url,
11625
- error: lastError
11626
- });
11627
- }
11628
- }
11629
- configureTexture(texture) {
11630
- texture.colorSpace = SRGBColorSpace3;
11631
- texture.wrapS = ClampToEdgeWrapping;
11632
- texture.wrapT = ClampToEdgeWrapping;
11633
- texture.magFilter = LinearFilter3;
11634
- texture.minFilter = LinearFilter3;
11635
- texture.generateMipmaps = false;
11636
- texture.anisotropy = Math.min(4, this.options.anisotropy);
11637
- texture.needsUpdate = true;
11638
- }
11639
- evict() {
11640
- if (this.totalBytes <= this.options.maxBytes) {
11641
- return;
11642
- }
11643
- const candidates = Array.from(this.entries.values()).filter((entry) => entry.refs === 0 && entry.texture).sort((a, b) => a.lastUsed - b.lastUsed);
11644
- for (const entry of candidates) {
11645
- if (this.totalBytes <= this.options.maxBytes) {
11646
- break;
11647
- }
11648
- entry.texture?.dispose();
11649
- this.totalBytes -= entry.bytes;
11650
- this.entries.delete(entry.key);
11651
- }
11652
- this.totalBytes = Math.max(0, this.totalBytes);
11653
- }
11654
- finishLoad(generation) {
11655
- this.activeLoads = Math.max(0, this.activeLoads - 1);
11656
- if (!this.disposed && generation === this.generation) {
11657
- this.emitProgress();
11658
- this.evict();
11659
- }
11660
- if (!this.disposed) {
11661
- this.drain();
11662
- }
11663
- }
11664
- async loadAndFinish(entry) {
11665
- const generation = this.generation;
11666
- try {
11667
- await this.load(entry, generation);
11668
- } finally {
11669
- this.finishLoad(generation);
11670
- }
11671
- }
11672
- };
11673
-
11674
- // src/tile/texture-manager-context.tsx
11675
- import { jsx as jsx20 } from "react/jsx-runtime";
12225
+ import { jsx as jsx21 } from "react/jsx-runtime";
11676
12226
  var TileTextureManagerContext = createContext15(
11677
12227
  null
11678
12228
  );
@@ -11681,9 +12231,9 @@ function TileTextureManagerProvider({
11681
12231
  maxTextureMemoryMb = 128,
11682
12232
  maxConcurrentLoads = 4
11683
12233
  }) {
11684
- const gl = useThree17((state) => state.gl);
12234
+ const gl = useThree18((state) => state.gl);
11685
12235
  const anisotropy = gl.capabilities.getMaxAnisotropy();
11686
- const manager = useMemo18(
12236
+ const manager = useMemo19(
11687
12237
  () => new TileTextureManager({
11688
12238
  anisotropy,
11689
12239
  maxBytes: Math.max(1, maxTextureMemoryMb) * 1024 * 1024,
@@ -11692,43 +12242,33 @@ function TileTextureManagerProvider({
11692
12242
  }),
11693
12243
  [anisotropy, maxConcurrentLoads, maxTextureMemoryMb]
11694
12244
  );
11695
- useEffect25(() => {
12245
+ useEffect27(() => {
11696
12246
  manager.resume();
11697
12247
  return () => manager.dispose();
11698
12248
  }, [manager]);
11699
- return /* @__PURE__ */ jsx20(TileTextureManagerContext.Provider, { value: manager, children });
12249
+ return /* @__PURE__ */ jsx21(TileTextureManagerContext.Provider, { value: manager, children });
11700
12250
  }
11701
12251
  function useSharedTileTextureManager() {
11702
12252
  return useContext22(TileTextureManagerContext);
11703
12253
  }
11704
12254
 
11705
12255
  // src/tile/tile.tsx
11706
- import { useFrame as useFrame11, useThree as useThree18 } from "@react-three/fiber";
11707
- import {
11708
- memo,
11709
- useEffect as useEffect26,
11710
- useMemo as useMemo19,
11711
- useRef as useRef26,
11712
- useState as useState11
11713
- } from "react";
12256
+ import { useFrame as useFrame12, useThree as useThree19 } from "@react-three/fiber";
12257
+ import { memo as memo2, useEffect as useEffect28, useMemo as useMemo20, useRef as useRef28, useState as useState13 } from "react";
11714
12258
  import {
11715
- ClampToEdgeWrapping as ClampToEdgeWrapping2,
11716
- Frustum,
11717
- LinearFilter as LinearFilter4,
11718
- Matrix4,
12259
+ Frustum as Frustum2,
12260
+ Matrix4 as Matrix43,
11719
12261
  PlaneGeometry as PlaneGeometry4,
11720
- PerspectiveCamera as PerspectiveCamera4,
11721
- SRGBColorSpace as SRGBColorSpace4,
11722
- TextureLoader as TextureLoader4,
11723
- Vector3 as Vector312
12262
+ PerspectiveCamera as PerspectiveCamera5,
12263
+ Vector3 as Vector313
11724
12264
  } from "three";
11725
12265
 
11726
12266
  // src/tile/face-layout.ts
11727
12267
  import {
11728
- Box3,
12268
+ Box3 as Box32,
11729
12269
  Euler as Euler3,
11730
12270
  Quaternion as Quaternion2,
11731
- Vector3 as Vector311
12271
+ Vector3 as Vector312
11732
12272
  } from "three";
11733
12273
  var CUBE_FACES = ["f", "r", "b", "l", "u", "d"];
11734
12274
  var PREVIEW_FACE_ORDER = ["l", "f", "r", "b", "u", "d"];
@@ -11792,17 +12332,17 @@ function getTileBoundingBox(address, radius = CUBE_RADIUS) {
11792
12332
  const halfWidth = local.width / 2;
11793
12333
  const halfHeight = local.height / 2;
11794
12334
  const quaternion = getFaceQuaternion(address.face);
11795
- const position = new Vector311(...transform.position);
12335
+ const position = new Vector312(...transform.position);
11796
12336
  const corners = [
11797
- new Vector311(local.x - halfWidth, local.y - halfHeight, 0),
11798
- new Vector311(local.x + halfWidth, local.y - halfHeight, 0),
11799
- new Vector311(local.x - halfWidth, local.y + halfHeight, 0),
11800
- new Vector311(local.x + halfWidth, local.y + halfHeight, 0)
12337
+ new Vector312(local.x - halfWidth, local.y - halfHeight, 0),
12338
+ new Vector312(local.x + halfWidth, local.y - halfHeight, 0),
12339
+ new Vector312(local.x - halfWidth, local.y + halfHeight, 0),
12340
+ new Vector312(local.x + halfWidth, local.y + halfHeight, 0)
11801
12341
  ];
11802
12342
  for (const corner of corners) {
11803
12343
  corner.applyQuaternion(quaternion).add(position);
11804
12344
  }
11805
- return new Box3().setFromPoints(corners);
12345
+ return new Box32().setFromPoints(corners);
11806
12346
  }
11807
12347
  function makeTileAddress(face, level, faceSize, tileSize, col, row) {
11808
12348
  const left = (col - 1) * tileSize;
@@ -11849,7 +12389,7 @@ function previewAtlasVRange(face, faceOrder = PREVIEW_FACE_ORDER) {
11849
12389
  }
11850
12390
 
11851
12391
  // src/tile/multires.ts
11852
- function positiveInteger(value, name) {
12392
+ function positiveInteger2(value, name) {
11853
12393
  if (!Number.isFinite(value) || value <= 0 || !Number.isInteger(value)) {
11854
12394
  throw new Error(`${name} must be a positive integer, received ${String(value)}`);
11855
12395
  }
@@ -11865,13 +12405,13 @@ function ascendingLevels(levels) {
11865
12405
  }
11866
12406
  function parseMultires(multires) {
11867
12407
  if (typeof multires !== "string") {
11868
- const tileSize2 = positiveInteger(multires.tileSize, "multires.tileSize");
12408
+ const tileSize2 = positiveInteger2(multires.tileSize, "multires.tileSize");
11869
12409
  if (multires.levels.length === 0) {
11870
12410
  throw new Error("multires.levels must contain at least one face size");
11871
12411
  }
11872
12412
  const levels2 = ascendingLevels(
11873
12413
  multires.levels.map(
11874
- (level, index) => positiveInteger(level, `multires.levels[${index}]`)
12414
+ (level, index) => positiveInteger2(level, `multires.levels[${index}]`)
11875
12415
  )
11876
12416
  );
11877
12417
  return { tileSize: tileSize2, levels: levels2 };
@@ -11882,10 +12422,10 @@ function parseMultires(multires) {
11882
12422
  "multires must contain a tile size followed by at least one face size"
11883
12423
  );
11884
12424
  }
11885
- const tileSize = positiveInteger(values[0], "multires tile size");
12425
+ const tileSize = positiveInteger2(values[0], "multires tile size");
11886
12426
  const levels = ascendingLevels(
11887
12427
  values.slice(1).map(
11888
- (level, index) => positiveInteger(level, `multires level ${index + 1}`)
12428
+ (level, index) => positiveInteger2(level, `multires level ${index + 1}`)
11889
12429
  )
11890
12430
  );
11891
12431
  return { tileSize, levels };
@@ -11905,7 +12445,7 @@ function resolveTemplateUrl(template, address) {
11905
12445
  }
11906
12446
 
11907
12447
  // src/tile/tile.tsx
11908
- import { jsx as jsx21, jsxs as jsxs12 } from "react/jsx-runtime";
12448
+ import { jsx as jsx22, jsxs as jsxs13 } from "react/jsx-runtime";
11909
12449
  var MAX_LOD_UPDATE_INTERVAL_MS = 100;
11910
12450
  var FAST_ROTATION_THRESHOLD_RADIANS = Math.PI / 180;
11911
12451
  var FAST_FOV_THRESHOLD_DEGREES = 0.5;
@@ -11913,61 +12453,12 @@ var VIEW_CHANGE_EPSILON = 1e-4;
11913
12453
  var VISIBILITY_FOV_PADDING_DEGREES = 8;
11914
12454
  var PREVIEW_RADIUS = CUBE_RADIUS + 0.05;
11915
12455
  var SHARED_TILE_GEOMETRY = new PlaneGeometry4(1, 1);
11916
- function usePreviewTexture(url, anisotropy, onError) {
11917
- const [texture, setTexture] = useState11(null);
11918
- const onErrorRef = useRef26(onError);
11919
- onErrorRef.current = onError;
11920
- useEffect26(() => {
11921
- if (!url) {
11922
- setTexture(null);
11923
- return;
11924
- }
11925
- let active = true;
11926
- const loader = new TextureLoader4();
11927
- setTexture(null);
11928
- loader.load(
11929
- url,
11930
- (loadedTexture) => {
11931
- if (!active) {
11932
- loadedTexture.dispose();
11933
- return;
11934
- }
11935
- loadedTexture.colorSpace = SRGBColorSpace4;
11936
- loadedTexture.wrapS = ClampToEdgeWrapping2;
11937
- loadedTexture.wrapT = ClampToEdgeWrapping2;
11938
- loadedTexture.magFilter = LinearFilter4;
11939
- loadedTexture.minFilter = LinearFilter4;
11940
- loadedTexture.generateMipmaps = false;
11941
- loadedTexture.anisotropy = Math.min(4, anisotropy);
11942
- loadedTexture.needsUpdate = true;
11943
- setTexture(loadedTexture);
11944
- },
11945
- void 0,
11946
- (error) => {
11947
- if (active) {
11948
- setTexture(null);
11949
- onErrorRef.current?.(error);
11950
- }
11951
- }
11952
- );
11953
- return () => {
11954
- active = false;
11955
- };
11956
- }, [anisotropy, url]);
11957
- useEffect26(
11958
- () => () => {
11959
- texture?.dispose();
11960
- },
11961
- [texture]
11962
- );
11963
- return texture;
11964
- }
11965
12456
  function PreviewFace({
11966
12457
  face,
11967
12458
  texture,
11968
12459
  faceOrder
11969
12460
  }) {
11970
- const geometry = useMemo19(() => {
12461
+ const geometry = useMemo20(() => {
11971
12462
  const nextGeometry = new PlaneGeometry4(
11972
12463
  PREVIEW_RADIUS * 2,
11973
12464
  PREVIEW_RADIUS * 2
@@ -11977,29 +12468,26 @@ function PreviewFace({
11977
12468
  const inset = scale / 512;
11978
12469
  for (let index = 0; index < uv.count; index += 1) {
11979
12470
  const sourceV = uv.getY(index);
11980
- uv.setY(
11981
- index,
11982
- offset + inset + sourceV * Math.max(0, scale - inset * 2)
11983
- );
12471
+ uv.setY(index, offset + inset + sourceV * Math.max(0, scale - inset * 2));
11984
12472
  }
11985
12473
  uv.needsUpdate = true;
11986
12474
  return nextGeometry;
11987
12475
  }, [face, faceOrder]);
11988
- useEffect26(
12476
+ useEffect28(
11989
12477
  () => () => {
11990
12478
  geometry.dispose();
11991
12479
  },
11992
12480
  [geometry]
11993
12481
  );
11994
12482
  const transform = getFaceTransform(face, PREVIEW_RADIUS);
11995
- return /* @__PURE__ */ jsx21(
12483
+ return /* @__PURE__ */ jsx22(
11996
12484
  "mesh",
11997
12485
  {
11998
12486
  geometry,
11999
12487
  position: transform.position,
12000
12488
  renderOrder: -100,
12001
12489
  rotation: transform.rotation,
12002
- children: /* @__PURE__ */ jsx21(
12490
+ children: /* @__PURE__ */ jsx22(
12003
12491
  PanoBasicMaterial,
12004
12492
  {
12005
12493
  depthTest: false,
@@ -12015,7 +12503,7 @@ function PreviewCube({
12015
12503
  texture,
12016
12504
  faceOrder
12017
12505
  }) {
12018
- return CUBE_FACES.map((face) => /* @__PURE__ */ jsx21(
12506
+ return CUBE_FACES.map((face) => /* @__PURE__ */ jsx22(
12019
12507
  PreviewFace,
12020
12508
  {
12021
12509
  face,
@@ -12025,28 +12513,7 @@ function PreviewCube({
12025
12513
  face
12026
12514
  ));
12027
12515
  }
12028
- function useManagedTexture(manager, key, url, address) {
12029
- const [managedState, setManagedState] = useState11(() => ({
12030
- manager,
12031
- key,
12032
- url,
12033
- snapshot: manager.getSnapshot(key)
12034
- }));
12035
- const snapshot = managedState.manager === manager && managedState.key === key && managedState.url === url ? managedState.snapshot : manager.getSnapshot(key);
12036
- useEffect26(
12037
- () => manager.acquire(key, url, address, (nextSnapshot) => {
12038
- setManagedState({
12039
- manager,
12040
- key,
12041
- url,
12042
- snapshot: nextSnapshot
12043
- });
12044
- }),
12045
- [key, manager, url]
12046
- );
12047
- return snapshot;
12048
- }
12049
- var TileMesh = memo(function TileMesh2({
12516
+ var TileMesh = memo2(function TileMesh2({
12050
12517
  address,
12051
12518
  manager,
12052
12519
  renderOrder,
@@ -12060,14 +12527,14 @@ var TileMesh = memo(function TileMesh2({
12060
12527
  if (!snapshot.texture) {
12061
12528
  return null;
12062
12529
  }
12063
- return /* @__PURE__ */ jsx21("group", { position: transform.position, rotation: transform.rotation, children: /* @__PURE__ */ jsx21(
12530
+ return /* @__PURE__ */ jsx22("group", { position: transform.position, rotation: transform.rotation, children: /* @__PURE__ */ jsx22(
12064
12531
  "mesh",
12065
12532
  {
12066
12533
  geometry: SHARED_TILE_GEOMETRY,
12067
12534
  position: [layout.x, layout.y, 0],
12068
12535
  renderOrder,
12069
12536
  scale: [layout.width, layout.height, 1],
12070
- children: /* @__PURE__ */ jsx21(
12537
+ children: /* @__PURE__ */ jsx22(
12071
12538
  PanoBasicMaterial,
12072
12539
  {
12073
12540
  depthTest: false,
@@ -12079,12 +12546,12 @@ var TileMesh = memo(function TileMesh2({
12079
12546
  }
12080
12547
  ) });
12081
12548
  });
12082
- var TileLayerMeshes = memo(function TileLayerMeshes2({
12549
+ var TileLayerMeshes = memo2(function TileLayerMeshes2({
12083
12550
  layer,
12084
12551
  manager,
12085
12552
  resolveUrl
12086
12553
  }) {
12087
- return layer.addresses.map((address) => /* @__PURE__ */ jsx21(
12554
+ return layer.addresses.map((address) => /* @__PURE__ */ jsx22(
12088
12555
  TileMesh,
12089
12556
  {
12090
12557
  address,
@@ -12184,8 +12651,8 @@ function parentAddresses(child, parentLevel, parentFaceSize, tileSize) {
12184
12651
  return addresses;
12185
12652
  }
12186
12653
  function centerFacingAddress(candidates, camera) {
12187
- const direction = camera.getWorldDirection(new Vector312());
12188
- const center = new Vector312();
12654
+ const direction = camera.getWorldDirection(new Vector313());
12655
+ const center = new Vector313();
12189
12656
  let bestCandidate = candidates[0];
12190
12657
  let bestAlignment = -Infinity;
12191
12658
  for (const candidate of candidates) {
@@ -12230,9 +12697,7 @@ function buildLayers(targetLevel, levels, tileSize, frustum, camera, candidatesB
12230
12697
  }));
12231
12698
  }
12232
12699
  function layerToken(layers) {
12233
- return layers.map(
12234
- (layer) => `${layer.level}:${layer.addresses.map(tileKey).join(",")}`
12235
- ).join("|");
12700
+ return layers.map((layer) => `${layer.level}:${layer.addresses.map(tileKey).join(",")}`).join("|");
12236
12701
  }
12237
12702
  function Tile({
12238
12703
  baseUrl,
@@ -12252,11 +12717,11 @@ function Tile({
12252
12717
  onTileError,
12253
12718
  onLevelChange
12254
12719
  }) {
12255
- const { camera, gl, size } = useThree18();
12256
- const multiresConfig = useMemo19(() => parseMultires(multires), [multires]);
12720
+ const { camera, gl, size } = useThree19();
12721
+ const multiresConfig = useMemo20(() => parseMultires(multires), [multires]);
12257
12722
  const { levels, tileSize } = multiresConfig;
12258
12723
  const multiresToken = `${tileSize}:${levels.join(",")}`;
12259
- const candidatesByLevel = useMemo19(
12724
+ const candidatesByLevel = useMemo20(
12260
12725
  () => buildTileCandidates(levels, tileSize),
12261
12726
  [levels, tileSize]
12262
12727
  );
@@ -12268,13 +12733,13 @@ function Tile({
12268
12733
  onPreviewError
12269
12734
  );
12270
12735
  const sharedManager = useSharedTileTextureManager();
12271
- const progressRef = useRef26(onLoadProgress);
12272
- const errorRef = useRef26(onTileError);
12273
- const levelChangeRef = useRef26(onLevelChange);
12736
+ const progressRef = useRef28(onLoadProgress);
12737
+ const errorRef = useRef28(onTileError);
12738
+ const levelChangeRef = useRef28(onLevelChange);
12274
12739
  progressRef.current = onLoadProgress;
12275
12740
  errorRef.current = onTileError;
12276
12741
  levelChangeRef.current = onLevelChange;
12277
- const ownedManager = useMemo19(
12742
+ const ownedManager = useMemo20(
12278
12743
  () => new TileTextureManager({
12279
12744
  anisotropy,
12280
12745
  maxBytes: Math.max(1, maxTextureMemoryMb) * 1024 * 1024,
@@ -12295,7 +12760,7 @@ function Tile({
12295
12760
  ]
12296
12761
  );
12297
12762
  const manager = sharedManager ?? ownedManager;
12298
- useEffect26(() => {
12763
+ useEffect28(() => {
12299
12764
  manager.resume();
12300
12765
  return () => {
12301
12766
  if (manager === ownedManager) {
@@ -12305,11 +12770,11 @@ function Tile({
12305
12770
  queueMicrotask(() => manager.releaseUnused());
12306
12771
  };
12307
12772
  }, [manager, ownedManager]);
12308
- const readyRef = useRef26(false);
12309
- useEffect26(() => {
12773
+ const readyRef = useRef28(false);
12774
+ useEffect28(() => {
12310
12775
  readyRef.current = false;
12311
12776
  }, [effectivePreviewUrl]);
12312
- useEffect26(() => {
12777
+ useEffect28(() => {
12313
12778
  if (!previewTexture || readyRef.current) {
12314
12779
  return;
12315
12780
  }
@@ -12317,31 +12782,31 @@ function Tile({
12317
12782
  onReady?.();
12318
12783
  }, [onReady, previewTexture]);
12319
12784
  const template = urlTemplate ?? buildDefaultTileUrlTemplate();
12320
- const resolveUrl = useMemo19(
12785
+ const resolveUrl = useMemo20(
12321
12786
  () => (address) => {
12322
12787
  const relativePath = resolveTileUrl ? resolveTileUrl(address) : resolveTemplateUrl(template, address);
12323
12788
  return resolveRelativeTileUrl(baseUrl, relativePath);
12324
12789
  },
12325
12790
  [baseUrl, resolveTileUrl, template]
12326
12791
  );
12327
- const [layers, setLayers] = useState11([]);
12328
- const layerTokenRef = useRef26("");
12329
- const currentLevelRef = useRef26(1);
12330
- const lastUpdateAtRef = useRef26(-Infinity);
12331
- const visibilityDirtyRef = useRef26(true);
12332
- const lastVisibilityQuaternionRef = useRef26(camera.quaternion.clone());
12333
- const lastVisibilityFovRef = useRef26(Number.NaN);
12334
- const lastViewportRef = useRef26({ width: 0, height: 0, dpr: 0 });
12335
- const frustumRef = useRef26(new Frustum());
12336
- const projectionMatrixRef = useRef26(new Matrix4());
12337
- const visibilityCameraRef = useRef26(new PerspectiveCamera4());
12338
- useEffect26(() => {
12792
+ const [layers, setLayers] = useState13([]);
12793
+ const layerTokenRef = useRef28("");
12794
+ const currentLevelRef = useRef28(1);
12795
+ const lastUpdateAtRef = useRef28(-Infinity);
12796
+ const visibilityDirtyRef = useRef28(true);
12797
+ const lastVisibilityQuaternionRef = useRef28(camera.quaternion.clone());
12798
+ const lastVisibilityFovRef = useRef28(Number.NaN);
12799
+ const lastViewportRef = useRef28({ width: 0, height: 0, dpr: 0 });
12800
+ const frustumRef = useRef28(new Frustum2());
12801
+ const projectionMatrixRef = useRef28(new Matrix43());
12802
+ const visibilityCameraRef = useRef28(new PerspectiveCamera5());
12803
+ useEffect28(() => {
12339
12804
  currentLevelRef.current = 1;
12340
12805
  layerTokenRef.current = "";
12341
12806
  visibilityDirtyRef.current = true;
12342
12807
  setLayers([]);
12343
12808
  }, [manager, multiresToken]);
12344
- useEffect26(() => {
12809
+ useEffect28(() => {
12345
12810
  if (loadMode !== "preview") {
12346
12811
  return;
12347
12812
  }
@@ -12355,11 +12820,11 @@ function Tile({
12355
12820
  setLayers(nextLayers);
12356
12821
  }
12357
12822
  };
12358
- useFrame11(() => {
12823
+ useFrame12(() => {
12359
12824
  if (loadMode === "preview") {
12360
12825
  return;
12361
12826
  }
12362
- if (!(camera instanceof PerspectiveCamera4)) {
12827
+ if (!(camera instanceof PerspectiveCamera5)) {
12363
12828
  return;
12364
12829
  }
12365
12830
  const now = performance.now();
@@ -12421,15 +12886,9 @@ function Tile({
12421
12886
  };
12422
12887
  commitLayers(nextLayers);
12423
12888
  });
12424
- return /* @__PURE__ */ jsxs12("group", { visible, children: [
12425
- previewTexture ? /* @__PURE__ */ jsx21(
12426
- PreviewCube,
12427
- {
12428
- texture: previewTexture,
12429
- faceOrder: previewFaceOrder
12430
- }
12431
- ) : null,
12432
- layers.map((layer) => /* @__PURE__ */ jsx21(
12889
+ return /* @__PURE__ */ jsxs13("group", { visible, children: [
12890
+ previewTexture ? /* @__PURE__ */ jsx22(PreviewCube, { texture: previewTexture, faceOrder: previewFaceOrder }) : null,
12891
+ layers.map((layer) => /* @__PURE__ */ jsx22(
12433
12892
  TileLayerMeshes,
12434
12893
  {
12435
12894
  layer,
@@ -12442,7 +12901,7 @@ function Tile({
12442
12901
  }
12443
12902
 
12444
12903
  // src/scenes.tsx
12445
- import { jsx as jsx22, jsxs as jsxs13 } from "react/jsx-runtime";
12904
+ import { jsx as jsx23, jsxs as jsxs14 } from "react/jsx-runtime";
12446
12905
  function SceneSource({
12447
12906
  scene,
12448
12907
  visible,
@@ -12455,7 +12914,7 @@ function SceneSource({
12455
12914
  }
12456
12915
  switch (scene.type) {
12457
12916
  case "sphere":
12458
- return /* @__PURE__ */ jsx22(
12917
+ return /* @__PURE__ */ jsx23(
12459
12918
  Sphere,
12460
12919
  {
12461
12920
  src: scene.src,
@@ -12468,7 +12927,7 @@ function SceneSource({
12468
12927
  );
12469
12928
  case "tile": {
12470
12929
  const { id: _id, type: _type, ...tileProps } = scene;
12471
- return /* @__PURE__ */ jsx22(
12930
+ return /* @__PURE__ */ jsx23(
12472
12931
  Tile,
12473
12932
  {
12474
12933
  ...tileProps,
@@ -12491,17 +12950,17 @@ function SnapshotCapture({
12491
12950
  maxPixels,
12492
12951
  onCaptured
12493
12952
  }) {
12494
- const { camera, gl, scene, size } = useThree19();
12495
- const capturedRequestRef = useRef27(0);
12496
- const renderTargetRef = useRef27(null);
12497
- useEffect27(
12953
+ const { camera, gl, scene, size } = useThree20();
12954
+ const capturedRequestRef = useRef29(0);
12955
+ const renderTargetRef = useRef29(null);
12956
+ useEffect29(
12498
12957
  () => () => {
12499
12958
  renderTargetRef.current?.dispose();
12500
12959
  renderTargetRef.current = null;
12501
12960
  },
12502
12961
  []
12503
12962
  );
12504
- useFrame12(() => {
12963
+ useFrame13(() => {
12505
12964
  if (requestId === 0 || requestId === capturedRequestRef.current) {
12506
12965
  return;
12507
12966
  }
@@ -12552,48 +13011,48 @@ function ScenesController({
12552
13011
  }) {
12553
13012
  const controlsRef = useContext23(PanoramaViewContext);
12554
13013
  const manager = useSharedTileTextureManager();
12555
- const transition = useMemo20(
13014
+ const transition = useMemo21(
12556
13015
  () => resolveTransition(transitionInput),
12557
13016
  [transitionInput]
12558
13017
  );
12559
- const sceneMap = useMemo20(
13018
+ const sceneMap = useMemo21(
12560
13019
  () => new Map(scenes.map((scene) => [scene.id, scene])),
12561
13020
  [scenes]
12562
13021
  );
12563
13022
  const initialScene = sceneMap.get(activeSceneId) ?? null;
12564
- const [slots, setSlots] = useState12([
13023
+ const [slots, setSlots] = useState14([
12565
13024
  initialScene,
12566
13025
  null
12567
13026
  ]);
12568
- const [activeSlot, setActiveSlot] = useState12(0);
12569
- const [liveSlot, setLiveSlot] = useState12(0);
12570
- const [pendingSlot, setPendingSlot] = useState12(null);
12571
- const [phase, setPhase] = useState12(initialScene ? "idle" : "preloading");
12572
- const [captureRequestId, setCaptureRequestId] = useState12(0);
12573
- const [transitionRunId, setTransitionRunId] = useState12(0);
12574
- const [snapshot, setSnapshot] = useState12(null);
12575
- const [recoveryKey, setRecoveryKey] = useState12(0);
12576
- const requestedSceneIdRef = useRef27(activeSceneId);
12577
- const captureReasonRef = useRef27("start");
12578
- const interactionReleaseRef = useRef27(null);
12579
- const slotsRef = useRef27(slots);
12580
- const phaseRef = useRef27(phase);
12581
- const liveSlotRef = useRef27(liveSlot);
12582
- const transitionFromRef = useRef27(initialScene);
13027
+ const [activeSlot, setActiveSlot] = useState14(0);
13028
+ const [liveSlot, setLiveSlot] = useState14(0);
13029
+ const [pendingSlot, setPendingSlot] = useState14(null);
13030
+ const [phase, setPhase] = useState14(initialScene ? "idle" : "preloading");
13031
+ const [captureRequestId, setCaptureRequestId] = useState14(0);
13032
+ const [transitionRunId, setTransitionRunId] = useState14(0);
13033
+ const [snapshot, setSnapshot] = useState14(null);
13034
+ const [recoveryKey, setRecoveryKey] = useState14(0);
13035
+ const requestedSceneIdRef = useRef29(activeSceneId);
13036
+ const captureReasonRef = useRef29("start");
13037
+ const interactionReleaseRef = useRef29(null);
13038
+ const slotsRef = useRef29(slots);
13039
+ const phaseRef = useRef29(phase);
13040
+ const liveSlotRef = useRef29(liveSlot);
13041
+ const transitionFromRef = useRef29(initialScene);
12583
13042
  slotsRef.current = slots;
12584
13043
  phaseRef.current = phase;
12585
13044
  if (externalPhaseRef) {
12586
13045
  externalPhaseRef.current = phase;
12587
13046
  }
12588
13047
  liveSlotRef.current = liveSlot;
12589
- const releaseInteraction = useCallback10(() => {
13048
+ const releaseInteraction = useCallback11(() => {
12590
13049
  interactionReleaseRef.current?.();
12591
13050
  interactionReleaseRef.current = null;
12592
13051
  }, []);
12593
- const reportError = useCallback10((sceneId, error) => {
13052
+ const reportError = useCallback11((sceneId, error) => {
12594
13053
  onTransitionError?.({ sceneId, error });
12595
13054
  }, [onTransitionError]);
12596
- const startPreload = useCallback10((scene) => {
13055
+ const startPreload = useCallback11((scene) => {
12597
13056
  const nextSlot = 1 - liveSlotRef.current;
12598
13057
  requestedSceneIdRef.current = scene.id;
12599
13058
  setSlots((current) => {
@@ -12604,7 +13063,7 @@ function ScenesController({
12604
13063
  setPendingSlot(nextSlot);
12605
13064
  setPhase("preloading");
12606
13065
  }, []);
12607
- useEffect27(() => {
13066
+ useEffect29(() => {
12608
13067
  const requested = sceneMap.get(activeSceneId);
12609
13068
  if (!requested) {
12610
13069
  reportError(activeSceneId, new Error(`Unknown panorama scene: ${activeSceneId}`));
@@ -12628,7 +13087,7 @@ function ScenesController({
12628
13087
  }
12629
13088
  startPreload(requested);
12630
13089
  }, [activeSceneId, pendingSlot, reportError, sceneMap, startPreload]);
12631
- const handleReady = useCallback10((slot) => {
13090
+ const handleReady = useCallback11((slot) => {
12632
13091
  if (slot !== pendingSlot || phaseRef.current !== "preloading") {
12633
13092
  return;
12634
13093
  }
@@ -12659,7 +13118,7 @@ function ScenesController({
12659
13118
  setPhase("capturing");
12660
13119
  setCaptureRequestId((current) => current + 1);
12661
13120
  }, [controlsRef, onTransitionEnd, pendingSlot, transition.preset]);
12662
- const handleCaptured = useCallback10((nextSnapshot) => {
13121
+ const handleCaptured = useCallback11((nextSnapshot) => {
12663
13122
  setSnapshot((current) => {
12664
13123
  current?.dispose();
12665
13124
  return nextSnapshot;
@@ -12681,7 +13140,7 @@ function ScenesController({
12681
13140
  setPhase("transitioning");
12682
13141
  setTransitionRunId((current) => current + 1);
12683
13142
  }, [manager, pendingSlot, sceneMap, startPreload]);
12684
- const finishTransition = useCallback10(() => {
13143
+ const finishTransition = useCallback11(() => {
12685
13144
  const nextSlot = pendingSlot;
12686
13145
  const previousScene = transitionFromRef.current;
12687
13146
  const nextScene = nextSlot === null ? null : slotsRef.current[nextSlot];
@@ -12706,12 +13165,12 @@ function ScenesController({
12706
13165
  });
12707
13166
  }
12708
13167
  }, [onTransitionEnd, pendingSlot, releaseInteraction, snapshot, transition.preset]);
12709
- useEffect27(() => () => {
13168
+ useEffect29(() => () => {
12710
13169
  releaseInteraction();
12711
13170
  snapshot?.dispose();
12712
13171
  }, [releaseInteraction, snapshot]);
12713
- const { gl } = useThree19();
12714
- useEffect27(() => {
13172
+ const { gl } = useThree20();
13173
+ useEffect29(() => {
12715
13174
  const canvas = gl.domElement;
12716
13175
  const onContextLost = (event) => {
12717
13176
  event.preventDefault();
@@ -12735,8 +13194,8 @@ function ScenesController({
12735
13194
  }, [gl, manager, releaseInteraction, snapshot]);
12736
13195
  const renderedScene = slots[liveSlot];
12737
13196
  const snapshotVisible = snapshot !== null && (phase === "transitioning" || phase === "recapturing" || phase === "preloading");
12738
- return /* @__PURE__ */ jsxs13(Fragment6, { children: [
12739
- /* @__PURE__ */ jsx22(
13197
+ return /* @__PURE__ */ jsxs14(Fragment6, { children: [
13198
+ /* @__PURE__ */ jsx23(
12740
13199
  SnapshotCapture,
12741
13200
  {
12742
13201
  requestId: captureRequestId,
@@ -12748,7 +13207,7 @@ function ScenesController({
12748
13207
  const source = slots[slot];
12749
13208
  const isLive = slot === liveSlot;
12750
13209
  const isPending = slot === pendingSlot;
12751
- return /* @__PURE__ */ jsx22(
13210
+ return /* @__PURE__ */ jsx23(
12752
13211
  SceneSource,
12753
13212
  {
12754
13213
  scene: source,
@@ -12764,7 +13223,7 @@ function ScenesController({
12764
13223
  `${slot}:${source?.id ?? "empty"}:${recoveryKey}`
12765
13224
  );
12766
13225
  }),
12767
- snapshotVisible ? /* @__PURE__ */ jsx22(
13226
+ snapshotVisible ? /* @__PURE__ */ jsx23(
12768
13227
  TransitionOverlay,
12769
13228
  {
12770
13229
  snapshot,
@@ -12787,11 +13246,11 @@ function Scenes({
12787
13246
  ...rest
12788
13247
  }) {
12789
13248
  const isControlled = controlledId !== void 0;
12790
- const [internalId, setInternalId] = useState12(
13249
+ const [internalId, setInternalId] = useState14(
12791
13250
  () => controlledId ?? defaultActiveSceneId ?? scenes[0]?.id ?? ""
12792
13251
  );
12793
13252
  const resolvedId = isControlled ? controlledId : internalId;
12794
- const requestSceneChange = useCallback10(
13253
+ const requestSceneChange = useCallback11(
12795
13254
  (id) => {
12796
13255
  if (isControlled) {
12797
13256
  onActiveSceneIdChange?.(id);
@@ -12801,13 +13260,13 @@ function Scenes({
12801
13260
  },
12802
13261
  [isControlled, onActiveSceneIdChange]
12803
13262
  );
12804
- const scenesRef = useRef27(scenes);
13263
+ const scenesRef = useRef29(scenes);
12805
13264
  scenesRef.current = scenes;
12806
- const resolvedIdRef = useRef27(resolvedId);
13265
+ const resolvedIdRef = useRef29(resolvedId);
12807
13266
  resolvedIdRef.current = resolvedId;
12808
13267
  const host = useContext23(ScenesHostContext);
12809
- const phaseRef = useRef27("idle");
12810
- useEffect27(() => {
13268
+ const phaseRef = useRef29("idle");
13269
+ useEffect29(() => {
12811
13270
  if (!host) {
12812
13271
  return;
12813
13272
  }
@@ -12857,12 +13316,12 @@ function Scenes({
12857
13316
  }
12858
13317
  };
12859
13318
  }, [host, requestSceneChange]);
12860
- return /* @__PURE__ */ jsx22(
13319
+ return /* @__PURE__ */ jsx23(
12861
13320
  TileTextureManagerProvider,
12862
13321
  {
12863
13322
  maxTextureMemoryMb,
12864
13323
  maxConcurrentLoads: maxConcurrentTileLoads,
12865
- children: /* @__PURE__ */ jsx22(
13324
+ children: /* @__PURE__ */ jsx23(
12866
13325
  ScenesController,
12867
13326
  {
12868
13327
  ...rest,
@@ -12876,8 +13335,8 @@ function Scenes({
12876
13335
  }
12877
13336
 
12878
13337
  // src/hotspot/image-hotspot.tsx
12879
- import { useThree as useThree21 } from "@react-three/fiber";
12880
- import { useEffect as useEffect30, useRef as useRef29, useState as useState15 } from "react";
13338
+ import { useThree as useThree22 } from "@react-three/fiber";
13339
+ import { useEffect as useEffect32, useRef as useRef31, useState as useState17 } from "react";
12881
13340
  import {
12882
13341
  ClampToEdgeWrapping as ClampToEdgeWrapping3,
12883
13342
  LinearFilter as LinearFilter6,
@@ -12887,35 +13346,35 @@ import {
12887
13346
  } from "three";
12888
13347
 
12889
13348
  // src/hotspot/hotspot-anchor.tsx
12890
- import { useFrame as useFrame13, useThree as useThree20 } from "@react-three/fiber";
13349
+ import { useFrame as useFrame14, useThree as useThree21 } from "@react-three/fiber";
12891
13350
  import {
12892
13351
  useContext as useContext25,
12893
- useEffect as useEffect29,
13352
+ useEffect as useEffect31,
12894
13353
  useLayoutEffect as useLayoutEffect4,
12895
- useMemo as useMemo22,
12896
- useRef as useRef28,
12897
- useState as useState14
13354
+ useMemo as useMemo23,
13355
+ useRef as useRef30,
13356
+ useState as useState16
12898
13357
  } from "react";
12899
13358
  import {
12900
- Box3 as Box33,
13359
+ Box3 as Box34,
12901
13360
  EdgesGeometry,
12902
- MathUtils as MathUtils7,
12903
- Matrix4 as Matrix42,
13361
+ MathUtils as MathUtils8,
13362
+ Matrix4 as Matrix44,
12904
13363
  Plane,
12905
13364
  PlaneGeometry as PlaneGeometry5,
12906
- PerspectiveCamera as PerspectiveCamera5,
13365
+ PerspectiveCamera as PerspectiveCamera6,
12907
13366
  Quaternion as Quaternion3,
12908
13367
  Ray,
12909
- Vector3 as Vector313
13368
+ Vector3 as Vector314
12910
13369
  } from "three";
12911
13370
 
12912
13371
  // src/hotspot/hotspot-tooltip.tsx
12913
- import { useEffect as useEffect28, useMemo as useMemo21, useState as useState13 } from "react";
13372
+ import { useEffect as useEffect30, useMemo as useMemo22, useState as useState15 } from "react";
12914
13373
 
12915
13374
  // src/webvr/stereo-html.tsx
12916
13375
  import { Html } from "@react-three/drei";
12917
13376
  import { useContext as useContext24, useSyncExternalStore as useSyncExternalStore7 } from "react";
12918
- import { Fragment as Fragment7, jsx as jsx23, jsxs as jsxs14 } from "react/jsx-runtime";
13377
+ import { Fragment as Fragment7, jsx as jsx24, jsxs as jsxs15 } from "react/jsx-runtime";
12919
13378
  function useFallbackStereoView() {
12920
13379
  const runtime = useContext24(WebVRRuntimeContext);
12921
13380
  const host = runtime?.host ?? null;
@@ -12940,10 +13399,10 @@ function stereoCalculatePosition(eye, stereoView) {
12940
13399
  function PanoHtml({ children, ...htmlProps }) {
12941
13400
  const stereoView = useFallbackStereoView();
12942
13401
  if (!stereoView) {
12943
- return /* @__PURE__ */ jsx23(Html, { ...htmlProps, children });
13402
+ return /* @__PURE__ */ jsx24(Html, { ...htmlProps, children });
12944
13403
  }
12945
- return /* @__PURE__ */ jsxs14(Fragment7, { children: [
12946
- /* @__PURE__ */ jsx23(
13404
+ return /* @__PURE__ */ jsxs15(Fragment7, { children: [
13405
+ /* @__PURE__ */ jsx24(
12947
13406
  Html,
12948
13407
  {
12949
13408
  ...htmlProps,
@@ -12951,7 +13410,7 @@ function PanoHtml({ children, ...htmlProps }) {
12951
13410
  children
12952
13411
  }
12953
13412
  ),
12954
- /* @__PURE__ */ jsx23(
13413
+ /* @__PURE__ */ jsx24(
12955
13414
  Html,
12956
13415
  {
12957
13416
  ...htmlProps,
@@ -12964,7 +13423,7 @@ function PanoHtml({ children, ...htmlProps }) {
12964
13423
  }
12965
13424
 
12966
13425
  // src/hotspot/hotspot-tooltip.tsx
12967
- import { jsx as jsx24, jsxs as jsxs15 } from "react/jsx-runtime";
13426
+ import { jsx as jsx25, jsxs as jsxs16 } from "react/jsx-runtime";
12968
13427
  var DEFAULT_HOTSPOT_TOOLTIP_OFFSET = 12;
12969
13428
  var DEFAULT_HOTSPOT_TOOLTIP_APPEARANCE = {
12970
13429
  background: "rgba(22, 22, 22, 0.72)",
@@ -12973,7 +13432,10 @@ var DEFAULT_HOTSPOT_TOOLTIP_APPEARANCE = {
12973
13432
  borderRadius: 8,
12974
13433
  shadow: "0 8px 24px rgba(0, 0, 0, 0.35)",
12975
13434
  padding: 8,
12976
- fontSize: 12
13435
+ fontSize: 12,
13436
+ fontFamily: "inherit",
13437
+ lineHeight: 1.4,
13438
+ letterSpacing: "normal"
12977
13439
  };
12978
13440
  var WRAPPER_STYLE = {
12979
13441
  pointerEvents: "none"
@@ -13033,16 +13495,16 @@ function HotspotTooltip({
13033
13495
  offset = DEFAULT_HOTSPOT_TOOLTIP_OFFSET,
13034
13496
  appearance
13035
13497
  }) {
13036
- const [imageFailed, setImageFailed] = useState13(false);
13037
- useEffect28(() => {
13498
+ const [imageFailed, setImageFailed] = useState15(false);
13499
+ useEffect30(() => {
13038
13500
  setImageFailed(false);
13039
13501
  }, [content.image]);
13040
13502
  const showImage = Boolean(content.image) && !imageFailed;
13041
- const resolvedAppearance = useMemo21(
13503
+ const resolvedAppearance = useMemo22(
13042
13504
  () => resolveHotspotTooltipAppearance(appearance),
13043
13505
  [appearance]
13044
13506
  );
13045
- const bubbleStyle = useMemo21(
13507
+ const bubbleStyle = useMemo22(
13046
13508
  () => ({
13047
13509
  background: resolvedAppearance.background,
13048
13510
  border: resolvedAppearance.border,
@@ -13050,6 +13512,9 @@ function HotspotTooltip({
13050
13512
  boxShadow: resolvedAppearance.shadow,
13051
13513
  color: resolvedAppearance.color,
13052
13514
  fontSize: toCssLength(resolvedAppearance.fontSize),
13515
+ fontFamily: resolvedAppearance.fontFamily,
13516
+ lineHeight: resolvedAppearance.lineHeight,
13517
+ letterSpacing: resolvedAppearance.letterSpacing,
13053
13518
  padding: toCssLength(resolvedAppearance.padding),
13054
13519
  transform: tooltipBubbleTransform(
13055
13520
  placement,
@@ -13061,30 +13526,33 @@ function HotspotTooltip({
13061
13526
  if (!showImage && !content.text) {
13062
13527
  return null;
13063
13528
  }
13064
- return /* @__PURE__ */ jsx24(PanoHtml, { pointerEvents: "none", style: WRAPPER_STYLE, zIndexRange: [20, 10], children: /* @__PURE__ */ jsxs15(
13065
- "div",
13066
- {
13067
- className: "pano-hotspot-tooltip",
13068
- role: "tooltip",
13069
- style: bubbleStyle,
13070
- children: [
13071
- showImage ? /* @__PURE__ */ jsx24(
13072
- "img",
13073
- {
13074
- alt: content.imageAlt ?? content.text ?? "",
13075
- className: "pano-hotspot-tooltip-image",
13076
- onError: () => setImageFailed(true),
13077
- src: content.image
13078
- }
13079
- ) : null,
13080
- content.text ? /* @__PURE__ */ jsx24("p", { className: "pano-hotspot-tooltip-text", children: content.text }) : null
13081
- ]
13082
- }
13083
- ) });
13529
+ 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: [
13530
+ showImage ? /* @__PURE__ */ jsx25(
13531
+ "img",
13532
+ {
13533
+ alt: content.imageAlt ?? content.text ?? "",
13534
+ className: "pano-hotspot-tooltip-image",
13535
+ onError: () => setImageFailed(true),
13536
+ src: content.image
13537
+ }
13538
+ ) : null,
13539
+ content.text ? /* @__PURE__ */ jsx25(
13540
+ "p",
13541
+ {
13542
+ className: "pano-hotspot-tooltip-text",
13543
+ style: {
13544
+ lineHeight: "inherit",
13545
+ letterSpacing: "inherit",
13546
+ fontFamily: "inherit"
13547
+ },
13548
+ children: content.text
13549
+ }
13550
+ ) : null
13551
+ ] }) });
13084
13552
  }
13085
13553
 
13086
13554
  // src/hotspot/hotspot-anchor.tsx
13087
- import { jsx as jsx25, jsxs as jsxs16 } from "react/jsx-runtime";
13555
+ import { jsx as jsx26, jsxs as jsxs17 } from "react/jsx-runtime";
13088
13556
  var DEFAULT_FLOATING_DISTANCE = 10;
13089
13557
  var PANORAMA_RADIUS = DEFAULT_PANORAMA_RADIUS;
13090
13558
  var PANORAMA_SURFACE_INSET = 4;
@@ -13092,28 +13560,28 @@ var DEFAULT_REFERENCE_FOV = 75;
13092
13560
  var MIN_ANGULAR_SIZE = 0.01;
13093
13561
  var MAX_ANGULAR_SIZE = 179;
13094
13562
  var DRAG_EPSILON_DEGREES = 1e-3;
13095
- var LOCAL_FORWARD = new Vector313(0, 0, 1);
13096
- var TOOLTIP_WORLD_BOX = new Box33();
13097
- var TOOLTIP_LOCAL_BOX = new Box33();
13098
- var TOOLTIP_CORNER = new Vector313();
13099
- var TOOLTIP_INVERSE = new Matrix42();
13100
- var TOOLTIP_WORLD_CORNER = new Vector313();
13101
- var TOOLTIP_PROJECTED = new Vector313();
13102
- var TOOLTIP_RAY_ORIGIN = new Vector313();
13103
- var TOOLTIP_RAY_FAR = new Vector313();
13104
- var TOOLTIP_RAY_DIRECTION = new Vector313();
13563
+ var LOCAL_FORWARD = new Vector314(0, 0, 1);
13564
+ var TOOLTIP_WORLD_BOX = new Box34();
13565
+ var TOOLTIP_LOCAL_BOX = new Box34();
13566
+ var TOOLTIP_CORNER = new Vector314();
13567
+ var TOOLTIP_INVERSE = new Matrix44();
13568
+ var TOOLTIP_WORLD_CORNER = new Vector314();
13569
+ var TOOLTIP_PROJECTED = new Vector314();
13570
+ var TOOLTIP_RAY_ORIGIN = new Vector314();
13571
+ var TOOLTIP_RAY_FAR = new Vector314();
13572
+ var TOOLTIP_RAY_DIRECTION = new Vector314();
13105
13573
  var TOOLTIP_RAY = new Ray();
13106
13574
  var TOOLTIP_PLANE = new Plane();
13107
- var TOOLTIP_INTERSECTION = new Vector313();
13108
- var TOOLTIP_PLANE_NORMAL = new Vector313();
13109
- var TOOLTIP_PLANE_POINT = new Vector313();
13575
+ var TOOLTIP_INTERSECTION = new Vector314();
13576
+ var TOOLTIP_PLANE_NORMAL = new Vector314();
13577
+ var TOOLTIP_PLANE_POINT = new Vector314();
13110
13578
  var HOTSPOT_MODE_RENDERING = {
13111
13579
  surface: { orientation: "surface", placement: "surface" },
13112
13580
  billboard: { orientation: "billboard", placement: "floating" }
13113
13581
  };
13114
13582
  function angularSizeToWorldSize(size, radius) {
13115
- const safeSize = Number.isFinite(size) ? MathUtils7.clamp(Math.abs(size), MIN_ANGULAR_SIZE, MAX_ANGULAR_SIZE) : MIN_ANGULAR_SIZE;
13116
- return 2 * radius * Math.tan(MathUtils7.degToRad(safeSize) / 2);
13583
+ const safeSize = Number.isFinite(size) ? MathUtils8.clamp(Math.abs(size), MIN_ANGULAR_SIZE, MAX_ANGULAR_SIZE) : MIN_ANGULAR_SIZE;
13584
+ return 2 * radius * Math.tan(MathUtils8.degToRad(safeSize) / 2);
13117
13585
  }
13118
13586
  function resolveScale(scale) {
13119
13587
  return Number.isFinite(scale) && scale > 0 ? scale : 1;
@@ -13126,7 +13594,7 @@ function resolveDistance(placement, distance, width, height) {
13126
13594
  if (!Number.isFinite(distance)) {
13127
13595
  return DEFAULT_FLOATING_DISTANCE;
13128
13596
  }
13129
- return MathUtils7.clamp(Math.abs(distance), 0.1, maximumDistance);
13597
+ return MathUtils8.clamp(Math.abs(distance), 0.1, maximumDistance);
13130
13598
  }
13131
13599
  function applyHotspotTransform(group, camera, orientation2, surfaceQuaternion3, rotation, scaleMode, referenceFov, useAngularScale, worldWidth, worldHeight) {
13132
13600
  if (orientation2 === "billboard") {
@@ -13134,8 +13602,8 @@ function applyHotspotTransform(group, camera, orientation2, surfaceQuaternion3,
13134
13602
  } else {
13135
13603
  group.quaternion.copy(surfaceQuaternion3);
13136
13604
  }
13137
- group.rotateOnAxis(LOCAL_FORWARD, MathUtils7.degToRad(-rotation));
13138
- const scaleFactor = scaleMode === "fixed" && camera instanceof PerspectiveCamera5 ? fixedScaleFactor(camera.fov, referenceFov) : 1;
13605
+ group.rotateOnAxis(LOCAL_FORWARD, MathUtils8.degToRad(-rotation));
13606
+ const scaleFactor = scaleMode === "fixed" && camera instanceof PerspectiveCamera6 ? fixedScaleFactor(camera.fov, referenceFov) : 1;
13139
13607
  group.scale.set(
13140
13608
  (useAngularScale ? worldWidth : 1) * scaleFactor,
13141
13609
  (useAngularScale ? worldHeight : 1) * scaleFactor,
@@ -13144,39 +13612,39 @@ function applyHotspotTransform(group, camera, orientation2, surfaceQuaternion3,
13144
13612
  group.updateMatrixWorld();
13145
13613
  }
13146
13614
  function maximumHotspotDistance(width, height) {
13147
- const safeWidth = MathUtils7.clamp(
13615
+ const safeWidth = MathUtils8.clamp(
13148
13616
  Math.abs(Number.isFinite(width) ? width : MIN_ANGULAR_SIZE),
13149
13617
  MIN_ANGULAR_SIZE,
13150
13618
  MAX_ANGULAR_SIZE
13151
13619
  );
13152
- const safeHeight = MathUtils7.clamp(
13620
+ const safeHeight = MathUtils8.clamp(
13153
13621
  Math.abs(Number.isFinite(height) ? height : MIN_ANGULAR_SIZE),
13154
13622
  MIN_ANGULAR_SIZE,
13155
13623
  MAX_ANGULAR_SIZE
13156
13624
  );
13157
13625
  const cornerFactor = Math.hypot(
13158
13626
  1,
13159
- Math.tan(MathUtils7.degToRad(safeWidth) / 2),
13160
- Math.tan(MathUtils7.degToRad(safeHeight) / 2)
13627
+ Math.tan(MathUtils8.degToRad(safeWidth) / 2),
13628
+ Math.tan(MathUtils8.degToRad(safeHeight) / 2)
13161
13629
  );
13162
13630
  return (PANORAMA_RADIUS - PANORAMA_SURFACE_INSET) / cornerFactor;
13163
13631
  }
13164
13632
  function fixedScaleFactor(cameraFov, referenceFov) {
13165
- const safeReferenceFov = MathUtils7.clamp(referenceFov, 1, 179);
13166
- return Math.tan(MathUtils7.degToRad(cameraFov) / 2) / Math.tan(MathUtils7.degToRad(safeReferenceFov) / 2);
13633
+ const safeReferenceFov = MathUtils8.clamp(referenceFov, 1, 179);
13634
+ return Math.tan(MathUtils8.degToRad(cameraFov) / 2) / Math.tan(MathUtils8.degToRad(safeReferenceFov) / 2);
13167
13635
  }
13168
13636
  function createSurfaceQuaternion(position) {
13169
13637
  const outward = panoPositionToVector3(position).normalize();
13170
13638
  const inward = outward.clone().negate();
13171
- const pitch = MathUtils7.degToRad(position.pitch);
13172
- const yaw = MathUtils7.degToRad(position.yaw);
13173
- const localUp = new Vector313(
13639
+ const pitch = MathUtils8.degToRad(position.pitch);
13640
+ const yaw = MathUtils8.degToRad(position.yaw);
13641
+ const localUp = new Vector314(
13174
13642
  -Math.sin(pitch) * Math.sin(yaw),
13175
13643
  Math.cos(pitch),
13176
13644
  Math.sin(pitch) * Math.cos(yaw)
13177
13645
  ).normalize();
13178
13646
  const localRight = localUp.clone().cross(inward).normalize();
13179
- const basis = new Matrix42().makeBasis(localRight, localUp, inward);
13647
+ const basis = new Matrix44().makeBasis(localRight, localUp, inward);
13180
13648
  return new Quaternion3().setFromRotationMatrix(basis);
13181
13649
  }
13182
13650
  function makeInteractionEvent(id, position, event) {
@@ -13190,7 +13658,7 @@ function makeInteractionEvent(id, position, event) {
13190
13658
  function angularDistance(a, b) {
13191
13659
  const aVector = panoPositionToVector3(a);
13192
13660
  const bVector = panoPositionToVector3(b);
13193
- return MathUtils7.radToDeg(aVector.angleTo(bVector));
13661
+ return MathUtils8.radToDeg(aVector.angleTo(bVector));
13194
13662
  }
13195
13663
  function isTooltipOpen(trigger, hovered, focused, pinned) {
13196
13664
  switch (trigger) {
@@ -13425,20 +13893,20 @@ function HotspotAnchor({
13425
13893
  const hotspotTargetRegistry = useContext25(HotspotTargetRegistryContext);
13426
13894
  const eventBus = useContext25(PanoEventBusContext);
13427
13895
  const cursorApi = usePanoCursor();
13428
- const { camera, size } = useThree20();
13429
- const groupRef = useRef28(null);
13430
- const tooltipAnchorRef = useRef28(null);
13431
- const dragStateRef = useRef28(null);
13432
- const suppressNextClickRef = useRef28(false);
13433
- const [hovered, setHovered] = useState14(false);
13434
- const [dragging, setDragging] = useState14(false);
13435
- const [pinned, setPinned] = useState14(false);
13436
- const tooltipContent = useMemo22(
13896
+ const { camera, size } = useThree21();
13897
+ const groupRef = useRef30(null);
13898
+ const tooltipAnchorRef = useRef30(null);
13899
+ const dragStateRef = useRef30(null);
13900
+ const suppressNextClickRef = useRef30(false);
13901
+ const [hovered, setHovered] = useState16(false);
13902
+ const [dragging, setDragging] = useState16(false);
13903
+ const [pinned, setPinned] = useState16(false);
13904
+ const tooltipContent = useMemo23(
13437
13905
  () => resolveHotspotTooltipContent(tooltip),
13438
13906
  [tooltip]
13439
13907
  );
13440
13908
  const normalizedPosition = normalizePanoPosition(position);
13441
- useEffect29(() => {
13909
+ useEffect31(() => {
13442
13910
  if (!hotspotTargetRegistry) {
13443
13911
  return;
13444
13912
  }
@@ -13455,17 +13923,17 @@ function HotspotAnchor({
13455
13923
  scaledWidth,
13456
13924
  scaledHeight
13457
13925
  );
13458
- const worldPosition = useMemo22(
13926
+ const worldPosition = useMemo23(
13459
13927
  () => panoPositionToVector3(normalizedPosition, resolvedDistance),
13460
13928
  [normalizedPosition.pitch, normalizedPosition.yaw, resolvedDistance]
13461
13929
  );
13462
- const surfaceQuaternion3 = useMemo22(
13930
+ const surfaceQuaternion3 = useMemo23(
13463
13931
  () => createSurfaceQuaternion(normalizedPosition),
13464
13932
  [normalizedPosition.pitch, normalizedPosition.yaw]
13465
13933
  );
13466
13934
  const worldWidth = angularSizeToWorldSize(scaledWidth, resolvedDistance);
13467
13935
  const worldHeight = angularSizeToWorldSize(scaledHeight, resolvedDistance);
13468
- const focusGeometry = useMemo22(() => {
13936
+ const focusGeometry = useMemo23(() => {
13469
13937
  const planeGeometry = new PlaneGeometry5(1, 1);
13470
13938
  const geometry = new EdgesGeometry(planeGeometry);
13471
13939
  planeGeometry.dispose();
@@ -13492,14 +13960,14 @@ function HotspotAnchor({
13492
13960
  });
13493
13961
  const tooltipOpen = visible && tooltipContent !== null && isTooltipOpen(tooltipTrigger, hovered, focused, pinned);
13494
13962
  const cursorClaimId = hotspotCursorClaimId(id);
13495
- useEffect29(
13963
+ useEffect31(
13496
13964
  () => () => {
13497
13965
  dragStateRef.current?.releaseInteractionLock();
13498
13966
  dragStateRef.current = null;
13499
13967
  },
13500
13968
  []
13501
13969
  );
13502
- useEffect29(() => {
13970
+ useEffect31(() => {
13503
13971
  if (!cursorApi) {
13504
13972
  return;
13505
13973
  }
@@ -13521,14 +13989,14 @@ function HotspotAnchor({
13521
13989
  hovered,
13522
13990
  visible
13523
13991
  ]);
13524
- useEffect29(
13992
+ useEffect31(
13525
13993
  () => () => {
13526
13994
  cursorApi?.release(cursorClaimId);
13527
13995
  },
13528
13996
  [cursorApi, cursorClaimId]
13529
13997
  );
13530
- useEffect29(() => () => focusGeometry.dispose(), [focusGeometry]);
13531
- useEffect29(() => {
13998
+ useEffect31(() => () => focusGeometry.dispose(), [focusGeometry]);
13999
+ useEffect31(() => {
13532
14000
  if (tooltipTrigger !== "click") {
13533
14001
  setPinned(false);
13534
14002
  return;
@@ -13537,12 +14005,12 @@ function HotspotAnchor({
13537
14005
  setPinned(false);
13538
14006
  });
13539
14007
  }, [eventBus, tooltipTrigger]);
13540
- useEffect29(() => {
14008
+ useEffect31(() => {
13541
14009
  if (tooltipTrigger !== "hover") {
13542
14010
  setHovered(false);
13543
14011
  }
13544
14012
  }, [tooltipTrigger]);
13545
- useEffect29(() => {
14013
+ useEffect31(() => {
13546
14014
  if (acceptsPointer) {
13547
14015
  return;
13548
14016
  }
@@ -13596,7 +14064,7 @@ function HotspotAnchor({
13596
14064
  worldHeight,
13597
14065
  worldWidth
13598
14066
  ]);
13599
- useFrame13((state) => {
14067
+ useFrame14((state) => {
13600
14068
  const group = groupRef.current;
13601
14069
  if (!group) {
13602
14070
  return;
@@ -13654,7 +14122,7 @@ function HotspotAnchor({
13654
14122
  setHovered(true);
13655
14123
  }
13656
14124
  };
13657
- return /* @__PURE__ */ jsxs16(
14125
+ return /* @__PURE__ */ jsxs17(
13658
14126
  "group",
13659
14127
  {
13660
14128
  ref: groupRef,
@@ -13731,18 +14199,18 @@ function HotspotAnchor({
13731
14199
  } : void 0,
13732
14200
  onPointerUp: acceptsPointer ? (event) => releasePointer(event, true) : void 0,
13733
14201
  children: [
13734
- focused ? focusContent ?? /* @__PURE__ */ jsx25(
14202
+ focused ? focusContent ?? /* @__PURE__ */ jsx26(
13735
14203
  "lineSegments",
13736
14204
  {
13737
14205
  geometry: focusGeometry,
13738
14206
  position: [0, 0, 0.01],
13739
14207
  renderOrder: renderOrder + 1,
13740
14208
  scale: [1.12, 1.12, 1],
13741
- children: /* @__PURE__ */ jsx25("lineBasicMaterial", { color: "#f5fbfc", depthTest: false })
14209
+ children: /* @__PURE__ */ jsx26("lineBasicMaterial", { color: "#f5fbfc", depthTest: false })
13742
14210
  }
13743
14211
  ) : null,
13744
14212
  children,
13745
- tooltipOpen && tooltipContent ? /* @__PURE__ */ jsx25("group", { ref: tooltipAnchorRef, children: /* @__PURE__ */ jsx25(
14213
+ tooltipOpen && tooltipContent ? /* @__PURE__ */ jsx26("group", { ref: tooltipAnchorRef, children: /* @__PURE__ */ jsx26(
13746
14214
  HotspotTooltip,
13747
14215
  {
13748
14216
  appearance: tooltipAppearance,
@@ -13763,7 +14231,7 @@ import {
13763
14231
  MeshBasicMaterial,
13764
14232
  Vector2 as Vector26
13765
14233
  } from "three";
13766
- import { jsx as jsx26, jsxs as jsxs17 } from "react/jsx-runtime";
14234
+ import { jsx as jsx27, jsxs as jsxs18 } from "react/jsx-runtime";
13767
14235
  var HOTSPOT_ALPHA_CUTOFF = 0.05;
13768
14236
  var SAMPLE_UV = new Vector26();
13769
14237
  var RAYCAST_HITS = [];
@@ -13865,11 +14333,12 @@ function HotspotPlane({
13865
14333
  map,
13866
14334
  opacity
13867
14335
  }) {
13868
- return /* @__PURE__ */ jsxs17("mesh", { raycast: hotspotPlaneRaycast, children: [
13869
- /* @__PURE__ */ jsx26("planeGeometry", { args: [1, 1] }),
13870
- /* @__PURE__ */ jsx26(
13871
- "meshBasicMaterial",
14336
+ return /* @__PURE__ */ jsxs18("mesh", { raycast: hotspotPlaneRaycast, children: [
14337
+ /* @__PURE__ */ jsx27("planeGeometry", { args: [1, 1] }),
14338
+ /* @__PURE__ */ jsx27(
14339
+ PanoBasicMaterial,
13872
14340
  {
14341
+ target: "hotspot",
13873
14342
  alphaTest: HOTSPOT_ALPHA_CUTOFF,
13874
14343
  alphaToCoverage: true,
13875
14344
  map,
@@ -13883,15 +14352,15 @@ function HotspotPlane({
13883
14352
  }
13884
14353
 
13885
14354
  // src/hotspot/image-hotspot.tsx
13886
- import { jsx as jsx27 } from "react/jsx-runtime";
14355
+ import { jsx as jsx28 } from "react/jsx-runtime";
13887
14356
  function useHotspotImageTexture(src, onLoad, onError) {
13888
- const gl = useThree21((state) => state.gl);
13889
- const [texture, setTexture] = useState15(null);
13890
- const onLoadRef = useRef29(onLoad);
13891
- const onErrorRef = useRef29(onError);
14357
+ const gl = useThree22((state) => state.gl);
14358
+ const [texture, setTexture] = useState17(null);
14359
+ const onLoadRef = useRef31(onLoad);
14360
+ const onErrorRef = useRef31(onError);
13892
14361
  onLoadRef.current = onLoad;
13893
14362
  onErrorRef.current = onError;
13894
- useEffect30(() => {
14363
+ useEffect32(() => {
13895
14364
  let active = true;
13896
14365
  setTexture(null);
13897
14366
  if (!src) {
@@ -13929,7 +14398,7 @@ function useHotspotImageTexture(src, onLoad, onError) {
13929
14398
  active = false;
13930
14399
  };
13931
14400
  }, [gl, src]);
13932
- useEffect30(
14401
+ useEffect32(
13933
14402
  () => () => {
13934
14403
  texture?.dispose();
13935
14404
  },
@@ -13947,33 +14416,33 @@ function ImageHotspot({
13947
14416
  ...anchorProps
13948
14417
  }) {
13949
14418
  const texture = useHotspotImageTexture(src, onLoad, onError);
13950
- return /* @__PURE__ */ jsx27(HotspotAnchor, { ...anchorProps, height, width, children: /* @__PURE__ */ jsx27(HotspotPlane, { map: texture, opacity }) });
14419
+ return /* @__PURE__ */ jsx28(HotspotAnchor, { ...anchorProps, height, width, children: /* @__PURE__ */ jsx28(HotspotPlane, { map: texture, opacity }) });
13951
14420
  }
13952
14421
 
13953
14422
  // src/hotspot/polygon-hotspot.tsx
13954
- import { useEffect as useEffect31, useMemo as useMemo23, useRef as useRef31 } from "react";
14423
+ import { useEffect as useEffect33, useMemo as useMemo24, useRef as useRef33 } from "react";
13955
14424
  import {
13956
- BufferGeometry,
14425
+ BufferGeometry as BufferGeometry2,
13957
14426
  DoubleSide as DoubleSide5,
13958
- Float32BufferAttribute,
13959
- Matrix4 as Matrix43,
14427
+ Float32BufferAttribute as Float32BufferAttribute2,
14428
+ Matrix4 as Matrix45,
13960
14429
  Quaternion as Quaternion4,
13961
14430
  ShapeUtils,
13962
14431
  Vector2 as Vector27,
13963
- Vector3 as Vector315
14432
+ Vector3 as Vector316
13964
14433
  } from "three";
13965
14434
 
13966
14435
  // src/hotspot/hotspot-stroke-line.tsx
13967
14436
  import { Line } from "@react-three/drei";
13968
- import { useFrame as useFrame14, useThree as useThree22 } from "@react-three/fiber";
13969
- import { useLayoutEffect as useLayoutEffect5, useRef as useRef30 } from "react";
14437
+ import { useFrame as useFrame15, useThree as useThree23 } from "@react-three/fiber";
14438
+ import { useLayoutEffect as useLayoutEffect5, useRef as useRef32 } from "react";
13970
14439
  import {
13971
- MathUtils as MathUtils8,
13972
- PerspectiveCamera as PerspectiveCamera6,
13973
- Vector3 as Vector314
14440
+ MathUtils as MathUtils9,
14441
+ PerspectiveCamera as PerspectiveCamera7,
14442
+ Vector3 as Vector315
13974
14443
  } from "three";
13975
- import { jsx as jsx28 } from "react/jsx-runtime";
13976
- var LINE_WORLD_POSITION = new Vector314();
14444
+ import { jsx as jsx29 } from "react/jsx-runtime";
14445
+ var LINE_WORLD_POSITION = new Vector315();
13977
14446
  function applyScreenSpaceDashScale(object, camera, viewportHeight) {
13978
14447
  const material = object?.material;
13979
14448
  if (!object || typeof material?.dashScale !== "number") {
@@ -13981,8 +14450,8 @@ function applyScreenSpaceDashScale(object, camera, viewportHeight) {
13981
14450
  }
13982
14451
  object.getWorldPosition(LINE_WORLD_POSITION);
13983
14452
  const depth = Math.max(camera.position.distanceTo(LINE_WORLD_POSITION), 1);
13984
- const fov = camera instanceof PerspectiveCamera6 ? camera.fov : 75;
13985
- material.dashScale = viewportHeight / (2 * Math.tan(MathUtils8.degToRad(fov) * 0.5) * depth);
14453
+ const fov = camera instanceof PerspectiveCamera7 ? camera.fov : 75;
14454
+ material.dashScale = viewportHeight / (2 * Math.tan(MathUtils9.degToRad(fov) * 0.5) * depth);
13986
14455
  }
13987
14456
  function resolveDash(dashSize, gapSize) {
13988
14457
  if (dashSize === void 0 || !Number.isFinite(dashSize) || dashSize <= 0) {
@@ -14003,8 +14472,8 @@ function HotspotStrokeLine({
14003
14472
  dashSize,
14004
14473
  gapSize
14005
14474
  }) {
14006
- const lineRef = useRef30(null);
14007
- const { camera, size } = useThree22();
14475
+ const lineRef = useRef32(null);
14476
+ const { camera, size } = useThree23();
14008
14477
  const dash = resolveDash(dashSize, gapSize);
14009
14478
  useLayoutEffect5(() => {
14010
14479
  if (!dash.dashed) {
@@ -14012,13 +14481,13 @@ function HotspotStrokeLine({
14012
14481
  }
14013
14482
  applyScreenSpaceDashScale(lineRef.current, camera, size.height);
14014
14483
  }, [camera, dash.dashed, dash.dashSize, dash.gapSize, size.height]);
14015
- useFrame14((state) => {
14484
+ useFrame15((state) => {
14016
14485
  if (!dash.dashed) {
14017
14486
  return;
14018
14487
  }
14019
14488
  applyScreenSpaceDashScale(lineRef.current, state.camera, state.size.height);
14020
14489
  });
14021
- return /* @__PURE__ */ jsx28(
14490
+ return /* @__PURE__ */ jsx29(
14022
14491
  Line,
14023
14492
  {
14024
14493
  ref: lineRef,
@@ -14040,7 +14509,7 @@ function HotspotStrokeLine({
14040
14509
  }
14041
14510
 
14042
14511
  // src/hotspot/polygon-hotspot.tsx
14043
- import { jsx as jsx29, jsxs as jsxs18 } from "react/jsx-runtime";
14512
+ import { jsx as jsx30, jsxs as jsxs19 } from "react/jsx-runtime";
14044
14513
  var POLYGON_RADIUS = 990;
14045
14514
  var MAX_FILL_SEGMENT_DEGREES = 7;
14046
14515
  function cloneVertices(vertices) {
@@ -14112,7 +14581,7 @@ function polygonContainsDirection(vertices, direction) {
14112
14581
  }
14113
14582
  function fitsHemisphere(vertices) {
14114
14583
  const directions = vertices.map((vertex) => panoPositionToVector3(vertex).normalize());
14115
- const candidates = [new Vector315()];
14584
+ const candidates = [new Vector316()];
14116
14585
  for (const direction of directions) {
14117
14586
  candidates[0].add(direction);
14118
14587
  candidates.push(direction.clone());
@@ -14136,7 +14605,7 @@ function validatePolygonVertices(vertices) {
14136
14605
  if (hasSelfIntersection(unwrapped)) {
14137
14606
  issues.push({ code: "self_intersection", message: "Polygon edges cannot cross." });
14138
14607
  }
14139
- if (polygonContainsDirection(normalized, new Vector315(0, 1, 0)) || polygonContainsDirection(normalized, new Vector315(0, -1, 0))) {
14608
+ if (polygonContainsDirection(normalized, new Vector316(0, 1, 0)) || polygonContainsDirection(normalized, new Vector316(0, -1, 0))) {
14140
14609
  issues.push({ code: "contains_pole", message: "Polygons cannot contain a panorama pole." });
14141
14610
  }
14142
14611
  if (!fitsHemisphere(normalized)) {
@@ -14147,7 +14616,7 @@ function validatePolygonVertices(vertices) {
14147
14616
  function polygonCenter(vertices) {
14148
14617
  const sum = vertices.reduce(
14149
14618
  (total, vertex) => total.add(panoPositionToVector3(vertex).normalize()),
14150
- new Vector315()
14619
+ new Vector316()
14151
14620
  );
14152
14621
  return sum.lengthSq() > 1e-8 ? vector3ToPanoPosition(sum) : normalizePanoPosition(vertices[0]);
14153
14622
  }
@@ -14156,20 +14625,20 @@ function surfaceQuaternion(position) {
14156
14625
  const inward = outward.clone().negate();
14157
14626
  const pitch = position.pitch * Math.PI / 180;
14158
14627
  const yaw = position.yaw * Math.PI / 180;
14159
- const localUp = new Vector315(
14628
+ const localUp = new Vector316(
14160
14629
  -Math.sin(pitch) * Math.sin(yaw),
14161
14630
  Math.cos(pitch),
14162
14631
  Math.sin(pitch) * Math.cos(yaw)
14163
14632
  ).normalize();
14164
14633
  return new Quaternion4().setFromRotationMatrix(
14165
- new Matrix43().makeBasis(localUp.clone().cross(inward).normalize(), localUp, inward)
14634
+ new Matrix45().makeBasis(localUp.clone().cross(inward).normalize(), localUp, inward)
14166
14635
  );
14167
14636
  }
14168
14637
  function makeWorldToLocal(center) {
14169
- return new Matrix43().compose(
14638
+ return new Matrix45().compose(
14170
14639
  panoPositionToVector3(center, POLYGON_RADIUS),
14171
14640
  surfaceQuaternion(center),
14172
- new Vector315(1, 1, 1)
14641
+ new Vector316(1, 1, 1)
14173
14642
  ).invert();
14174
14643
  }
14175
14644
  function projectedPoint(a, b, c, weightB, weightC, radius, worldToLocal) {
@@ -14241,7 +14710,7 @@ function makeFillGeometry(vertices, center) {
14241
14710
  steps
14242
14711
  );
14243
14712
  }
14244
- return new BufferGeometry().setAttribute("position", new Float32BufferAttribute(positions, 3)).setIndex(indices);
14713
+ return new BufferGeometry2().setAttribute("position", new Float32BufferAttribute2(positions, 3)).setIndex(indices);
14245
14714
  }
14246
14715
  function makeStrokePositions(vertices, center) {
14247
14716
  const points = [];
@@ -14296,24 +14765,24 @@ function PolygonHotspot({
14296
14765
  onInvalid,
14297
14766
  ...anchorProps
14298
14767
  }) {
14299
- const issues = useMemo23(() => validatePolygonVertices(vertices), [vertices]);
14768
+ const issues = useMemo24(() => validatePolygonVertices(vertices), [vertices]);
14300
14769
  const valid = issues.length === 0;
14301
- const center = useMemo23(() => valid ? polygonCenter(vertices) : null, [valid, vertices]);
14302
- const fillGeometry = useMemo23(
14770
+ const center = useMemo24(() => valid ? polygonCenter(vertices) : null, [valid, vertices]);
14771
+ const fillGeometry = useMemo24(
14303
14772
  () => valid && center ? makeFillGeometry(vertices, center) : null,
14304
14773
  [center, valid, vertices]
14305
14774
  );
14306
- const strokePoints = useMemo23(
14775
+ const strokePoints = useMemo24(
14307
14776
  () => valid && center ? makeStrokePositions(vertices, center) : null,
14308
14777
  [center, valid, vertices]
14309
14778
  );
14310
14779
  const resolvedStrokeOpacity = Math.max(0, Math.min(strokeOpacity, 1));
14311
- const startVerticesRef = useRef31(null);
14780
+ const startVerticesRef = useRef33(null);
14312
14781
  const issuesKey = issues.map((issue) => issue.code).join(",");
14313
- useEffect31(() => {
14782
+ useEffect33(() => {
14314
14783
  if (!valid) onInvalid?.(issues);
14315
14784
  }, [issues, issuesKey, onInvalid, valid]);
14316
- useEffect31(() => () => fillGeometry?.dispose(), [fillGeometry]);
14785
+ useEffect33(() => () => fillGeometry?.dispose(), [fillGeometry]);
14317
14786
  if (!valid || !center || !fillGeometry || !strokePoints || strokePoints.length < 2) {
14318
14787
  return null;
14319
14788
  }
@@ -14328,7 +14797,7 @@ function PolygonHotspot({
14328
14797
  startPosition: event.startPosition
14329
14798
  });
14330
14799
  };
14331
- return /* @__PURE__ */ jsxs18(
14800
+ return /* @__PURE__ */ jsxs19(
14332
14801
  HotspotAnchor,
14333
14802
  {
14334
14803
  ...anchorProps,
@@ -14343,7 +14812,7 @@ function PolygonHotspot({
14343
14812
  draggable,
14344
14813
  interactive,
14345
14814
  useAngularScale: false,
14346
- focusContent: /* @__PURE__ */ jsx29(
14815
+ focusContent: /* @__PURE__ */ jsx30(
14347
14816
  HotspotStrokeLine,
14348
14817
  {
14349
14818
  color: "#75cbd3",
@@ -14365,7 +14834,7 @@ function PolygonHotspot({
14365
14834
  startVerticesRef.current = null;
14366
14835
  },
14367
14836
  children: [
14368
- /* @__PURE__ */ jsx29("mesh", { geometry: fillGeometry, renderOrder, children: /* @__PURE__ */ jsx29(
14837
+ /* @__PURE__ */ jsx30("mesh", { geometry: fillGeometry, renderOrder, children: /* @__PURE__ */ jsx30(
14369
14838
  "meshBasicMaterial",
14370
14839
  {
14371
14840
  color: fill,
@@ -14375,7 +14844,7 @@ function PolygonHotspot({
14375
14844
  transparent: true
14376
14845
  }
14377
14846
  ) }),
14378
- /* @__PURE__ */ jsx29(
14847
+ /* @__PURE__ */ jsx30(
14379
14848
  HotspotStrokeLine,
14380
14849
  {
14381
14850
  color: stroke,
@@ -14393,14 +14862,14 @@ function PolygonHotspot({
14393
14862
  }
14394
14863
 
14395
14864
  // src/hotspot/polyline-hotspot.tsx
14396
- import { useEffect as useEffect32, useMemo as useMemo24, useRef as useRef32 } from "react";
14865
+ import { useEffect as useEffect34, useMemo as useMemo25, useRef as useRef34 } from "react";
14397
14866
  import {
14398
- MathUtils as MathUtils9,
14399
- Matrix4 as Matrix44,
14867
+ MathUtils as MathUtils10,
14868
+ Matrix4 as Matrix46,
14400
14869
  Quaternion as Quaternion5,
14401
- Vector3 as Vector316
14870
+ Vector3 as Vector317
14402
14871
  } from "three";
14403
- import { jsx as jsx30 } from "react/jsx-runtime";
14872
+ import { jsx as jsx31 } from "react/jsx-runtime";
14404
14873
  var POLYLINE_RADIUS = 990;
14405
14874
  var MAX_SEGMENT_DEGREES = 7;
14406
14875
  function cloneVertices2(vertices) {
@@ -14425,29 +14894,29 @@ function unwrapVertices(vertices) {
14425
14894
  function polylineCenter(vertices) {
14426
14895
  const sum = vertices.reduce(
14427
14896
  (total, vertex) => total.add(panoPositionToVector3(vertex).normalize()),
14428
- new Vector316()
14897
+ new Vector317()
14429
14898
  );
14430
14899
  return sum.lengthSq() > 1e-8 ? vector3ToPanoPosition(sum) : normalizePanoPosition(vertices[0]);
14431
14900
  }
14432
14901
  function surfaceQuaternion2(position) {
14433
14902
  const outward = panoPositionToVector3(position).normalize();
14434
14903
  const inward = outward.clone().negate();
14435
- const pitch = MathUtils9.degToRad(position.pitch);
14436
- const yaw = MathUtils9.degToRad(position.yaw);
14437
- const localUp = new Vector316(
14904
+ const pitch = MathUtils10.degToRad(position.pitch);
14905
+ const yaw = MathUtils10.degToRad(position.yaw);
14906
+ const localUp = new Vector317(
14438
14907
  -Math.sin(pitch) * Math.sin(yaw),
14439
14908
  Math.cos(pitch),
14440
14909
  Math.sin(pitch) * Math.cos(yaw)
14441
14910
  ).normalize();
14442
14911
  return new Quaternion5().setFromRotationMatrix(
14443
- new Matrix44().makeBasis(localUp.clone().cross(inward).normalize(), localUp, inward)
14912
+ new Matrix46().makeBasis(localUp.clone().cross(inward).normalize(), localUp, inward)
14444
14913
  );
14445
14914
  }
14446
14915
  function makeWorldToLocal2(center) {
14447
- return new Matrix44().compose(
14916
+ return new Matrix46().compose(
14448
14917
  panoPositionToVector3(center, POLYLINE_RADIUS),
14449
14918
  surfaceQuaternion2(center),
14450
- new Vector316(1, 1, 1)
14919
+ new Vector317(1, 1, 1)
14451
14920
  ).invert();
14452
14921
  }
14453
14922
  function subdivisionSteps(vertices) {
@@ -14462,7 +14931,7 @@ function subdivisionSteps(vertices) {
14462
14931
  }
14463
14932
  return Math.min(
14464
14933
  8,
14465
- Math.max(1, Math.ceil(MathUtils9.radToDeg(maxAngle) / MAX_SEGMENT_DEGREES))
14934
+ Math.max(1, Math.ceil(MathUtils10.radToDeg(maxAngle) / MAX_SEGMENT_DEGREES))
14466
14935
  );
14467
14936
  }
14468
14937
  function makeLinePositions(vertices, center) {
@@ -14517,16 +14986,16 @@ function PolylineHotspot({
14517
14986
  onInvalid,
14518
14987
  ...anchorProps
14519
14988
  }) {
14520
- const issues = useMemo24(() => validatePolylineVertices(vertices), [vertices]);
14989
+ const issues = useMemo25(() => validatePolylineVertices(vertices), [vertices]);
14521
14990
  const valid = issues.length === 0;
14522
- const center = useMemo24(() => valid ? polylineCenter(vertices) : null, [valid, vertices]);
14523
- const linePoints = useMemo24(
14991
+ const center = useMemo25(() => valid ? polylineCenter(vertices) : null, [valid, vertices]);
14992
+ const linePoints = useMemo25(
14524
14993
  () => valid && center ? makeLinePositions(vertices, center) : null,
14525
14994
  [center, valid, vertices]
14526
14995
  );
14527
14996
  const opacity = Math.max(0, Math.min(strokeOpacity, 1));
14528
- const startVerticesRef = useRef32(null);
14529
- useEffect32(() => {
14997
+ const startVerticesRef = useRef34(null);
14998
+ useEffect34(() => {
14530
14999
  if (!valid) onInvalid?.(issues);
14531
15000
  }, [issues, onInvalid, valid]);
14532
15001
  if (!valid || !center || !linePoints || linePoints.length < 2) return null;
@@ -14540,7 +15009,7 @@ function PolylineHotspot({
14540
15009
  startPosition: event.startPosition
14541
15010
  });
14542
15011
  };
14543
- return /* @__PURE__ */ jsx30(
15012
+ return /* @__PURE__ */ jsx31(
14544
15013
  HotspotAnchor,
14545
15014
  {
14546
15015
  ...anchorProps,
@@ -14554,7 +15023,7 @@ function PolylineHotspot({
14554
15023
  renderOrder,
14555
15024
  draggable,
14556
15025
  useAngularScale: false,
14557
- focusContent: /* @__PURE__ */ jsx30(
15026
+ focusContent: /* @__PURE__ */ jsx31(
14558
15027
  HotspotStrokeLine,
14559
15028
  {
14560
15029
  color: "#75cbd3",
@@ -14575,7 +15044,7 @@ function PolylineHotspot({
14575
15044
  emitVerticesChange(event, onDragEnd);
14576
15045
  startVerticesRef.current = null;
14577
15046
  },
14578
- children: /* @__PURE__ */ jsx30(
15047
+ children: /* @__PURE__ */ jsx31(
14579
15048
  HotspotStrokeLine,
14580
15049
  {
14581
15050
  color: stroke,
@@ -14592,7 +15061,7 @@ function PolylineHotspot({
14592
15061
  }
14593
15062
 
14594
15063
  // src/hotspot/graphic-hotspot.tsx
14595
- import { useEffect as useEffect33, useRef as useRef33, useState as useState16 } from "react";
15064
+ import { useEffect as useEffect35, useRef as useRef35, useState as useState18 } from "react";
14596
15065
  import {
14597
15066
  CanvasTexture,
14598
15067
  ClampToEdgeWrapping as ClampToEdgeWrapping4,
@@ -14600,7 +15069,7 @@ import {
14600
15069
  LinearMipmapLinearFilter as LinearMipmapLinearFilter4,
14601
15070
  SRGBColorSpace as SRGBColorSpace6
14602
15071
  } from "three";
14603
- import { jsx as jsx31 } from "react/jsx-runtime";
15072
+ import { jsx as jsx32 } from "react/jsx-runtime";
14604
15073
  var GRAPHIC_TEXTURE_SIZE = 512;
14605
15074
  function resolveStrokeWidth(value) {
14606
15075
  return Number.isFinite(value) ? Math.max(value, 0) : 8;
@@ -14789,12 +15258,12 @@ function createGraphicTexture(graphic, aspectWidth, aspectHeight) {
14789
15258
  return texture;
14790
15259
  }
14791
15260
  function useGraphicTexture(graphic, aspectWidth, aspectHeight, onLoad, onError) {
14792
- const [texture, setTexture] = useState16(null);
14793
- const onLoadRef = useRef33(onLoad);
14794
- const onErrorRef = useRef33(onError);
15261
+ const [texture, setTexture] = useState18(null);
15262
+ const onLoadRef = useRef35(onLoad);
15263
+ const onErrorRef = useRef35(onError);
14795
15264
  onLoadRef.current = onLoad;
14796
15265
  onErrorRef.current = onError;
14797
- useEffect33(() => {
15266
+ useEffect35(() => {
14798
15267
  let nextTexture = null;
14799
15268
  try {
14800
15269
  nextTexture = createGraphicTexture(graphic, aspectWidth, aspectHeight);
@@ -14820,20 +15289,20 @@ function CanvasGraphicHotspot({
14820
15289
  ...anchorProps
14821
15290
  }) {
14822
15291
  const texture = useGraphicTexture(graphic, width, height, onLoad, onError);
14823
- return /* @__PURE__ */ jsx31(HotspotAnchor, { ...anchorProps, height, width, children: /* @__PURE__ */ jsx31(HotspotPlane, { map: texture, opacity }) });
15292
+ return /* @__PURE__ */ jsx32(HotspotAnchor, { ...anchorProps, height, width, children: /* @__PURE__ */ jsx32(HotspotPlane, { map: texture, opacity }) });
14824
15293
  }
14825
15294
  function GraphicHotspot(props) {
14826
15295
  const { graphic, ...restProps } = props;
14827
15296
  if (graphic.kind === "svg") {
14828
15297
  const imageProps = restProps;
14829
- return /* @__PURE__ */ jsx31(ImageHotspot, { ...imageProps, src: graphic.src });
15298
+ return /* @__PURE__ */ jsx32(ImageHotspot, { ...imageProps, src: graphic.src });
14830
15299
  }
14831
- return /* @__PURE__ */ jsx31(CanvasGraphicHotspot, { ...restProps, graphic });
15300
+ return /* @__PURE__ */ jsx32(CanvasGraphicHotspot, { ...restProps, graphic });
14832
15301
  }
14833
15302
 
14834
15303
  // src/hotspot/sequence-hotspot.tsx
14835
- import { useFrame as useFrame15, useThree as useThree23 } from "@react-three/fiber";
14836
- import { useEffect as useEffect34, useRef as useRef34, useState as useState17 } from "react";
15304
+ import { useFrame as useFrame16, useThree as useThree24 } from "@react-three/fiber";
15305
+ import { useEffect as useEffect36, useRef as useRef36, useState as useState19 } from "react";
14837
15306
  import {
14838
15307
  ClampToEdgeWrapping as ClampToEdgeWrapping5,
14839
15308
  LinearFilter as LinearFilter8,
@@ -14841,7 +15310,7 @@ import {
14841
15310
  SRGBColorSpace as SRGBColorSpace7,
14842
15311
  TextureLoader as TextureLoader6
14843
15312
  } from "three";
14844
- import { jsx as jsx32 } from "react/jsx-runtime";
15313
+ import { jsx as jsx33 } from "react/jsx-runtime";
14845
15314
  var DEFAULT_SEQUENCE_FPS = 12;
14846
15315
  function resolveFps(value) {
14847
15316
  return Number.isFinite(value) && value > 0 ? value : DEFAULT_SEQUENCE_FPS;
@@ -14855,13 +15324,13 @@ function useSpriteTexture({
14855
15324
  onError,
14856
15325
  onLoadProgress
14857
15326
  }) {
14858
- const gl = useThree23((state) => state.gl);
14859
- const [texture, setTexture] = useState17(null);
14860
- const onErrorRef = useRef34(onError);
14861
- const onLoadProgressRef = useRef34(onLoadProgress);
15327
+ const gl = useThree24((state) => state.gl);
15328
+ const [texture, setTexture] = useState19(null);
15329
+ const onErrorRef = useRef36(onError);
15330
+ const onLoadProgressRef = useRef36(onLoadProgress);
14862
15331
  onErrorRef.current = onError;
14863
15332
  onLoadProgressRef.current = onLoadProgress;
14864
- useEffect34(() => {
15333
+ useEffect36(() => {
14865
15334
  let active = true;
14866
15335
  setTexture(null);
14867
15336
  if (!src) {
@@ -14902,7 +15371,7 @@ function useSpriteTexture({
14902
15371
  active = false;
14903
15372
  };
14904
15373
  }, [gl, id, src]);
14905
- useEffect34(
15374
+ useEffect36(
14906
15375
  () => () => {
14907
15376
  texture?.dispose();
14908
15377
  },
@@ -14931,24 +15400,24 @@ function SequenceHotspot({
14931
15400
  const texture = useSpriteTexture({ id, src, onError, onLoadProgress });
14932
15401
  const frameCount = resolveFrameCount(requestedFrameCount);
14933
15402
  const safeFps = resolveFps(fps);
14934
- const [frameIndex, setFrameIndex] = useState17(0);
14935
- const elapsedRef = useRef34(0);
14936
- const frameIndexRef = useRef34(0);
14937
- const endedRef = useRef34(false);
14938
- const lastPlaybackStateRef = useRef34(null);
14939
- const onFrameChangeRef = useRef34(onFrameChange);
14940
- const onPlaybackStateChangeRef = useRef34(onPlaybackStateChange);
14941
- const onEndedRef = useRef34(onEnded);
15403
+ const [frameIndex, setFrameIndex] = useState19(0);
15404
+ const elapsedRef = useRef36(0);
15405
+ const frameIndexRef = useRef36(0);
15406
+ const endedRef = useRef36(false);
15407
+ const lastPlaybackStateRef = useRef36(null);
15408
+ const onFrameChangeRef = useRef36(onFrameChange);
15409
+ const onPlaybackStateChangeRef = useRef36(onPlaybackStateChange);
15410
+ const onEndedRef = useRef36(onEnded);
14942
15411
  onFrameChangeRef.current = onFrameChange;
14943
15412
  onPlaybackStateChangeRef.current = onPlaybackStateChange;
14944
15413
  onEndedRef.current = onEnded;
14945
- useEffect34(() => {
15414
+ useEffect36(() => {
14946
15415
  elapsedRef.current = 0;
14947
15416
  frameIndexRef.current = 0;
14948
15417
  endedRef.current = false;
14949
15418
  setFrameIndex(0);
14950
15419
  }, [frameCount, frameDirection, src]);
14951
- useEffect34(() => {
15420
+ useEffect36(() => {
14952
15421
  if (!texture) {
14953
15422
  return;
14954
15423
  }
@@ -14962,13 +15431,13 @@ function SequenceHotspot({
14962
15431
  );
14963
15432
  texture.needsUpdate = true;
14964
15433
  }, [frameCount, frameDirection, frameIndex, texture]);
14965
- useEffect34(() => {
15434
+ useEffect36(() => {
14966
15435
  if (!texture) {
14967
15436
  return;
14968
15437
  }
14969
15438
  onFrameChangeRef.current?.({ id, index: 0, src });
14970
15439
  }, [id, src, texture]);
14971
- useEffect34(() => {
15440
+ useEffect36(() => {
14972
15441
  if (!texture) {
14973
15442
  return;
14974
15443
  }
@@ -14987,7 +15456,7 @@ function SequenceHotspot({
14987
15456
  onPlaybackStateChangeRef.current?.(nextState);
14988
15457
  }
14989
15458
  }, [playing, texture]);
14990
- useFrame15((_, deltaSeconds) => {
15459
+ useFrame16((_, deltaSeconds) => {
14991
15460
  if (!texture || !playing || endedRef.current) {
14992
15461
  return;
14993
15462
  }
@@ -15017,12 +15486,12 @@ function SequenceHotspot({
15017
15486
  onFrameChangeRef.current?.({ id, index: nextIndex, src });
15018
15487
  }
15019
15488
  });
15020
- return /* @__PURE__ */ jsx32(HotspotAnchor, { ...anchorProps, id, height, width, children: /* @__PURE__ */ jsx32(HotspotPlane, { map: texture, opacity }) });
15489
+ return /* @__PURE__ */ jsx33(HotspotAnchor, { ...anchorProps, id, height, width, children: /* @__PURE__ */ jsx33(HotspotPlane, { map: texture, opacity }) });
15021
15490
  }
15022
15491
 
15023
15492
  // src/hotspot/video-hotspot.tsx
15024
- import { useThree as useThree24 } from "@react-three/fiber";
15025
- import { useEffect as useEffect35, useRef as useRef35, useState as useState18 } from "react";
15493
+ import { useThree as useThree25 } from "@react-three/fiber";
15494
+ import { useEffect as useEffect37, useRef as useRef37, useState as useState20 } from "react";
15026
15495
  import {
15027
15496
  ClampToEdgeWrapping as ClampToEdgeWrapping6,
15028
15497
  LinearFilter as LinearFilter9,
@@ -15031,7 +15500,7 @@ import {
15031
15500
  TextureLoader as TextureLoader7,
15032
15501
  VideoTexture as VideoTexture2
15033
15502
  } from "three";
15034
- import { jsx as jsx33 } from "react/jsx-runtime";
15503
+ import { jsx as jsx34 } from "react/jsx-runtime";
15035
15504
  function clampVolume2(volume) {
15036
15505
  if (!Number.isFinite(volume)) {
15037
15506
  return 1;
@@ -15039,11 +15508,11 @@ function clampVolume2(volume) {
15039
15508
  return Math.max(0, Math.min(volume, 1));
15040
15509
  }
15041
15510
  function usePosterTexture2(id, poster, onError) {
15042
- const gl = useThree24((state) => state.gl);
15043
- const [texture, setTexture] = useState18(null);
15044
- const onErrorRef = useRef35(onError);
15511
+ const gl = useThree25((state) => state.gl);
15512
+ const [texture, setTexture] = useState20(null);
15513
+ const onErrorRef = useRef37(onError);
15045
15514
  onErrorRef.current = onError;
15046
- useEffect35(() => {
15515
+ useEffect37(() => {
15047
15516
  let active = true;
15048
15517
  setTexture(null);
15049
15518
  if (!poster) {
@@ -15080,7 +15549,7 @@ function usePosterTexture2(id, poster, onError) {
15080
15549
  active = false;
15081
15550
  };
15082
15551
  }, [gl, id, poster]);
15083
- useEffect35(
15552
+ useEffect37(
15084
15553
  () => () => {
15085
15554
  texture?.dispose();
15086
15555
  },
@@ -15098,14 +15567,14 @@ function useVideoResource({
15098
15567
  poster,
15099
15568
  src
15100
15569
  }) {
15101
- const [resource, setResource] = useState18(null);
15102
- const onEndedRef = useRef35(onEnded);
15103
- const onErrorRef = useRef35(onError);
15104
- const onPlaybackStateChangeRef = useRef35(onPlaybackStateChange);
15570
+ const [resource, setResource] = useState20(null);
15571
+ const onEndedRef = useRef37(onEnded);
15572
+ const onErrorRef = useRef37(onError);
15573
+ const onPlaybackStateChangeRef = useRef37(onPlaybackStateChange);
15105
15574
  onEndedRef.current = onEnded;
15106
15575
  onErrorRef.current = onError;
15107
15576
  onPlaybackStateChangeRef.current = onPlaybackStateChange;
15108
- useEffect35(() => {
15577
+ useEffect37(() => {
15109
15578
  if (!src) {
15110
15579
  setResource(null);
15111
15580
  return;
@@ -15212,11 +15681,11 @@ function VideoHotspot({
15212
15681
  src
15213
15682
  });
15214
15683
  const posterTexture = usePosterTexture2(id, poster, onError);
15215
- const onPlaybackErrorRef = useRef35(onPlaybackError);
15216
- const onPlaybackStateChangeRef = useRef35(onPlaybackStateChange);
15684
+ const onPlaybackErrorRef = useRef37(onPlaybackError);
15685
+ const onPlaybackStateChangeRef = useRef37(onPlaybackStateChange);
15217
15686
  onPlaybackErrorRef.current = onPlaybackError;
15218
15687
  onPlaybackStateChangeRef.current = onPlaybackStateChange;
15219
- useEffect35(() => {
15688
+ useEffect37(() => {
15220
15689
  if (!resource) {
15221
15690
  return;
15222
15691
  }
@@ -15233,7 +15702,7 @@ function VideoHotspot({
15233
15702
  }
15234
15703
  resource.video.preload = preload;
15235
15704
  }, [loop, muted, playsInline, preload, resource, volume]);
15236
- useEffect35(() => {
15705
+ useEffect37(() => {
15237
15706
  if (!resource) {
15238
15707
  return;
15239
15708
  }
@@ -15256,12 +15725,12 @@ function VideoHotspot({
15256
15725
  };
15257
15726
  }, [playing, resource]);
15258
15727
  const activeTexture = resource?.ready ? resource.texture : posterTexture;
15259
- return /* @__PURE__ */ jsx33(HotspotAnchor, { ...anchorProps, id, height, width, children: /* @__PURE__ */ jsx33(HotspotPlane, { map: activeTexture, opacity }) });
15728
+ return /* @__PURE__ */ jsx34(HotspotAnchor, { ...anchorProps, id, height, width, children: /* @__PURE__ */ jsx34(HotspotPlane, { map: activeTexture, opacity }) });
15260
15729
  }
15261
15730
 
15262
15731
  // src/hotspot/audio-hotspot.tsx
15263
- import { useFrame as useFrame16, useThree as useThree25 } from "@react-three/fiber";
15264
- import { useEffect as useEffect36, useRef as useRef36, useState as useState19 } from "react";
15732
+ import { useFrame as useFrame17, useThree as useThree26 } from "@react-three/fiber";
15733
+ import { useEffect as useEffect38, useRef as useRef38, useState as useState21 } from "react";
15265
15734
  import {
15266
15735
  CanvasTexture as CanvasTexture2,
15267
15736
  ClampToEdgeWrapping as ClampToEdgeWrapping7,
@@ -15270,7 +15739,7 @@ import {
15270
15739
  SRGBColorSpace as SRGBColorSpace9,
15271
15740
  TextureLoader as TextureLoader8
15272
15741
  } from "three";
15273
- import { jsx as jsx34 } from "react/jsx-runtime";
15742
+ import { jsx as jsx35 } from "react/jsx-runtime";
15274
15743
  var SPEAKER_TEXTURE_SIZE = 512;
15275
15744
  function paintSpeakerBody(context, center) {
15276
15745
  context.fillStyle = "#f5fbfc";
@@ -15334,8 +15803,8 @@ function createSpeakerTexture(state) {
15334
15803
  return texture;
15335
15804
  }
15336
15805
  function useSpeakerTextures(enabled) {
15337
- const [textures, setTextures] = useState19({ playing: null, stopped: null });
15338
- useEffect36(() => {
15806
+ const [textures, setTextures] = useState21({ playing: null, stopped: null });
15807
+ useEffect38(() => {
15339
15808
  if (!enabled) {
15340
15809
  setTextures({ playing: null, stopped: null });
15341
15810
  return;
@@ -15351,11 +15820,11 @@ function useSpeakerTextures(enabled) {
15351
15820
  return textures;
15352
15821
  }
15353
15822
  function useIconTexture(icon, enabled, onError, id) {
15354
- const gl = useThree25((state) => state.gl);
15355
- const [texture, setTexture] = useState19(null);
15356
- const onErrorRef = useRef36(onError);
15823
+ const gl = useThree26((state) => state.gl);
15824
+ const [texture, setTexture] = useState21(null);
15825
+ const onErrorRef = useRef38(onError);
15357
15826
  onErrorRef.current = onError;
15358
- useEffect36(() => {
15827
+ useEffect38(() => {
15359
15828
  let active = true;
15360
15829
  setTexture(null);
15361
15830
  if (!enabled || !icon) {
@@ -15392,7 +15861,7 @@ function useIconTexture(icon, enabled, onError, id) {
15392
15861
  active = false;
15393
15862
  };
15394
15863
  }, [enabled, gl, icon, id]);
15395
- useEffect36(
15864
+ useEffect38(
15396
15865
  () => () => {
15397
15866
  texture?.dispose();
15398
15867
  },
@@ -15411,13 +15880,13 @@ function useAudioHowl({
15411
15880
  playing,
15412
15881
  src
15413
15882
  }) {
15414
- const [howl, setHowl] = useState19(null);
15415
- const playingRef = useRef36(playing);
15416
- const loopRef = useRef36(loop ?? false);
15417
- const onEndedRef = useRef36(onEnded);
15418
- const onErrorRef = useRef36(onError);
15419
- const onPlaybackErrorRef = useRef36(onPlaybackError);
15420
- const onPlaybackStateChangeRef = useRef36(onPlaybackStateChange);
15883
+ const [howl, setHowl] = useState21(null);
15884
+ const playingRef = useRef38(playing);
15885
+ const loopRef = useRef38(loop ?? false);
15886
+ const onEndedRef = useRef38(onEnded);
15887
+ const onErrorRef = useRef38(onError);
15888
+ const onPlaybackErrorRef = useRef38(onPlaybackError);
15889
+ const onPlaybackStateChangeRef = useRef38(onPlaybackStateChange);
15421
15890
  playingRef.current = playing;
15422
15891
  loopRef.current = loop ?? false;
15423
15892
  onEndedRef.current = onEnded;
@@ -15425,7 +15894,7 @@ function useAudioHowl({
15425
15894
  onPlaybackErrorRef.current = onPlaybackError;
15426
15895
  onPlaybackStateChangeRef.current = onPlaybackStateChange;
15427
15896
  const sourcesKey = sourceList(src).join("\0");
15428
- useEffect36(() => {
15897
+ useEffect38(() => {
15429
15898
  const sources = sourcesKey.length > 0 ? sourcesKey.split("\0") : [];
15430
15899
  if (sources.length === 0) {
15431
15900
  setHowl(null);
@@ -15462,7 +15931,7 @@ function useAudioHowl({
15462
15931
  handle.dispose();
15463
15932
  };
15464
15933
  }, [crossOrigin, id, sourcesKey]);
15465
- useEffect36(() => {
15934
+ useEffect38(() => {
15466
15935
  howl?.loop(loop ?? false);
15467
15936
  }, [howl, loop]);
15468
15937
  return howl;
@@ -15490,7 +15959,7 @@ function AudioHotspot({
15490
15959
  ...anchorProps
15491
15960
  }) {
15492
15961
  usePanoMediaActivationIntent(playing);
15493
- const camera = useThree25((state) => state.camera);
15962
+ const camera = useThree26((state) => state.camera);
15494
15963
  const howl = useAudioHowl({
15495
15964
  crossOrigin,
15496
15965
  id,
@@ -15506,15 +15975,15 @@ function AudioHotspot({
15506
15975
  const stoppedIconTexture = useIconTexture(icon, marker, onError, id);
15507
15976
  const playingIconTexture = useIconTexture(playingIcon, marker, onError, id);
15508
15977
  const markerTexture = playing ? playingIconTexture ?? stoppedIconTexture ?? speakerTextures.playing : stoppedIconTexture ?? speakerTextures.stopped;
15509
- const playingRef = useRef36(playing);
15978
+ const playingRef = useRef38(playing);
15510
15979
  playingRef.current = playing;
15511
- const mutedRef = useRef36(muted);
15512
- const volumeRef = useRef36(volume);
15513
- const rangeRef = useRef36(range);
15980
+ const mutedRef = useRef38(muted);
15981
+ const volumeRef = useRef38(volume);
15982
+ const rangeRef = useRef38(range);
15514
15983
  mutedRef.current = muted;
15515
15984
  volumeRef.current = volume;
15516
15985
  rangeRef.current = range;
15517
- useEffect36(() => {
15986
+ useEffect38(() => {
15518
15987
  if (!howl) {
15519
15988
  return;
15520
15989
  }
@@ -15524,7 +15993,7 @@ function AudioHotspot({
15524
15993
  }
15525
15994
  howl.play();
15526
15995
  }, [howl, playing]);
15527
- useEffect36(() => {
15996
+ useEffect38(() => {
15528
15997
  if (!howl || !pauseWhenHidden) {
15529
15998
  return;
15530
15999
  }
@@ -15542,7 +16011,7 @@ function AudioHotspot({
15542
16011
  document.removeEventListener("visibilitychange", handleVisibility);
15543
16012
  };
15544
16013
  }, [howl, pauseWhenHidden]);
15545
- useFrame16(() => {
16014
+ useFrame17(() => {
15546
16015
  if (!howl) {
15547
16016
  return;
15548
16017
  }
@@ -15555,11 +16024,11 @@ function AudioHotspot({
15555
16024
  howl.mute(mutedRef.current);
15556
16025
  howl.volume(clampAudioVolume(volumeRef.current) * spatial.gain);
15557
16026
  });
15558
- return /* @__PURE__ */ jsx34(HotspotAnchor, { ...anchorProps, id, height, width, children: marker ? /* @__PURE__ */ jsx34(HotspotPlane, { map: markerTexture, opacity }) : null });
16027
+ return /* @__PURE__ */ jsx35(HotspotAnchor, { ...anchorProps, id, height, width, children: marker ? /* @__PURE__ */ jsx35(HotspotPlane, { map: markerTexture, opacity }) : null });
15559
16028
  }
15560
16029
 
15561
16030
  // src/hotspot/text-hotspot.tsx
15562
- import { useEffect as useEffect37, useRef as useRef37, useState as useState20 } from "react";
16031
+ import { useEffect as useEffect39, useRef as useRef39, useState as useState22 } from "react";
15563
16032
  import {
15564
16033
  CanvasTexture as CanvasTexture3,
15565
16034
  ClampToEdgeWrapping as ClampToEdgeWrapping8,
@@ -15567,7 +16036,7 @@ import {
15567
16036
  LinearMipmapLinearFilter as LinearMipmapLinearFilter8,
15568
16037
  SRGBColorSpace as SRGBColorSpace10
15569
16038
  } from "three";
15570
- import { jsx as jsx35 } from "react/jsx-runtime";
16039
+ import { jsx as jsx36 } from "react/jsx-runtime";
15571
16040
  var TEXT_TEXTURE_LONG_SIDE = 1024;
15572
16041
  var DEFAULT_FONT_FAMILY = "system-ui, sans-serif";
15573
16042
  var DEFAULT_FONT_SIZE = 96;
@@ -15787,12 +16256,12 @@ function createTextTexture(text, width, height, style) {
15787
16256
  return texture;
15788
16257
  }
15789
16258
  function useTextTexture(text, width, height, style, onLoad, onError) {
15790
- const [texture, setTexture] = useState20(null);
15791
- const onLoadRef = useRef37(onLoad);
15792
- const onErrorRef = useRef37(onError);
16259
+ const [texture, setTexture] = useState22(null);
16260
+ const onLoadRef = useRef39(onLoad);
16261
+ const onErrorRef = useRef39(onError);
15793
16262
  onLoadRef.current = onLoad;
15794
16263
  onErrorRef.current = onError;
15795
- useEffect37(() => {
16264
+ useEffect39(() => {
15796
16265
  let cancelled = false;
15797
16266
  let nextTexture = null;
15798
16267
  const run = async () => {
@@ -15885,13 +16354,13 @@ function TextHotspot({
15885
16354
  whiteSpace
15886
16355
  };
15887
16356
  const texture = useTextTexture(text, width, height, style, onLoad, onError);
15888
- return /* @__PURE__ */ jsx35(HotspotAnchor, { ...anchorProps, height, width, children: /* @__PURE__ */ jsx35(HotspotPlane, { map: texture, opacity }) });
16357
+ return /* @__PURE__ */ jsx36(HotspotAnchor, { ...anchorProps, height, width, children: /* @__PURE__ */ jsx36(HotspotPlane, { map: texture, opacity }) });
15889
16358
  }
15890
16359
 
15891
16360
  // src/hotspot/iframe-hotspot.tsx
15892
16361
  import { Html as Html2 } from "@react-three/drei";
15893
16362
  import { DoubleSide as DoubleSide6 } from "three";
15894
- import { jsx as jsx36, jsxs as jsxs19 } from "react/jsx-runtime";
16363
+ import { jsx as jsx37, jsxs as jsxs20 } from "react/jsx-runtime";
15895
16364
  var IFRAME_LONG_SIDE = 800;
15896
16365
  var CSS3D_DISTANCE_FACTOR = 400;
15897
16366
  var DEFAULT_SANDBOX = "allow-scripts allow-popups allow-forms";
@@ -15948,7 +16417,7 @@ function IframeHotspot({
15948
16417
  interactive,
15949
16418
  pointerEvents
15950
16419
  );
15951
- return /* @__PURE__ */ jsxs19(
16420
+ return /* @__PURE__ */ jsxs20(
15952
16421
  HotspotAnchor,
15953
16422
  {
15954
16423
  ...anchorProps,
@@ -15957,9 +16426,9 @@ function IframeHotspot({
15957
16426
  pointerEvents,
15958
16427
  width,
15959
16428
  children: [
15960
- /* @__PURE__ */ jsxs19("mesh", { children: [
15961
- /* @__PURE__ */ jsx36("planeGeometry", { args: [1, 1] }),
15962
- /* @__PURE__ */ jsx36(
16429
+ /* @__PURE__ */ jsxs20("mesh", { children: [
16430
+ /* @__PURE__ */ jsx37("planeGeometry", { args: [1, 1] }),
16431
+ /* @__PURE__ */ jsx37(
15963
16432
  "meshBasicMaterial",
15964
16433
  {
15965
16434
  depthWrite: false,
@@ -15970,7 +16439,7 @@ function IframeHotspot({
15970
16439
  }
15971
16440
  )
15972
16441
  ] }),
15973
- /* @__PURE__ */ jsx36(
16442
+ /* @__PURE__ */ jsx37(
15974
16443
  Html2,
15975
16444
  {
15976
16445
  distanceFactor: CSS3D_DISTANCE_FACTOR,
@@ -15985,7 +16454,7 @@ function IframeHotspot({
15985
16454
  },
15986
16455
  transform: true,
15987
16456
  zIndexRange: [10, 0],
15988
- children: /* @__PURE__ */ jsx36(
16457
+ children: /* @__PURE__ */ jsx37(
15989
16458
  "iframe",
15990
16459
  {
15991
16460
  allow,
@@ -16037,6 +16506,7 @@ export {
16037
16506
  Scenes,
16038
16507
  SequenceHotspot,
16039
16508
  Sphere,
16509
+ SphereTile,
16040
16510
  TextHotspot,
16041
16511
  Tile,
16042
16512
  TouchControls,