@ericchen1990/pano-view 3.3.0 → 3.4.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -3446,7 +3446,9 @@ function KeyboardControls({
3446
3446
  return;
3447
3447
  }
3448
3448
  const previousTabIndex = element.getAttribute("tabindex");
3449
+ const previousOutline = element.style.outline;
3449
3450
  element.tabIndex = 0;
3451
+ element.style.outline = "none";
3450
3452
  const syncKeyboardActive = () => {
3451
3453
  let continuous = false;
3452
3454
  for (const action of pressedRef.current) {
@@ -3530,6 +3532,7 @@ function KeyboardControls({
3530
3532
  } else {
3531
3533
  element.setAttribute("tabindex", previousTabIndex);
3532
3534
  }
3535
+ element.style.outline = previousOutline;
3533
3536
  clearPressed();
3534
3537
  };
3535
3538
  }, [controlsRef, enabled, gl, keyMap]);
@@ -9700,7 +9703,7 @@ function usePanoViewer() {
9700
9703
 
9701
9704
  // src/sphere-tile/sphere-tile.tsx
9702
9705
  var import_fiber16 = require("@react-three/fiber");
9703
- var import_react39 = require("react");
9706
+ var import_react40 = require("react");
9704
9707
  var import_three14 = require("three");
9705
9708
 
9706
9709
  // src/asset-url.ts
@@ -9968,6 +9971,27 @@ function PanoBasicMaterial({
9968
9971
  );
9969
9972
  }
9970
9973
 
9974
+ // src/scene-detail.tsx
9975
+ var import_react37 = require("react");
9976
+ var SceneDetailContext = (0, import_react37.createContext)(null);
9977
+ function useSceneDetailReporter() {
9978
+ return (0, import_react37.useContext)(SceneDetailContext);
9979
+ }
9980
+ function viewTilesAreDrawable(textures) {
9981
+ return textures.length > 0 && textures.every((texture) => texture != null);
9982
+ }
9983
+ function publishSceneDetail(reporter, lastToken, ready) {
9984
+ if (!reporter) {
9985
+ return;
9986
+ }
9987
+ const token = `${reporter.generation}:${ready ? 1 : 0}`;
9988
+ if (lastToken.current === token) {
9989
+ return;
9990
+ }
9991
+ lastToken.current = token;
9992
+ reporter.report(ready);
9993
+ }
9994
+
9971
9995
  // src/tile/texture-manager.ts
9972
9996
  var import_three11 = require("three");
9973
9997
  var EMPTY_TEXTURE_SNAPSHOT = {
@@ -10195,9 +10219,9 @@ var TileTextureManager = class {
10195
10219
 
10196
10220
  // src/tile/texture-manager-context.tsx
10197
10221
  var import_fiber15 = require("@react-three/fiber");
10198
- var import_react37 = require("react");
10222
+ var import_react38 = require("react");
10199
10223
  var import_jsx_runtime15 = require("react/jsx-runtime");
10200
- var TileTextureManagerContext = (0, import_react37.createContext)(null);
10224
+ var TileTextureManagerContext = (0, import_react38.createContext)(null);
10201
10225
  function TileTextureManagerProvider({
10202
10226
  children,
10203
10227
  maxTextureMemoryMb = 128,
@@ -10205,7 +10229,7 @@ function TileTextureManagerProvider({
10205
10229
  }) {
10206
10230
  const gl = (0, import_fiber15.useThree)((state) => state.gl);
10207
10231
  const anisotropy = gl.capabilities.getMaxAnisotropy();
10208
- const manager = (0, import_react37.useMemo)(
10232
+ const manager = (0, import_react38.useMemo)(
10209
10233
  () => new TileTextureManager({
10210
10234
  anisotropy,
10211
10235
  maxBytes: Math.max(1, maxTextureMemoryMb) * 1024 * 1024,
@@ -10214,24 +10238,24 @@ function TileTextureManagerProvider({
10214
10238
  }),
10215
10239
  [anisotropy, maxConcurrentLoads, maxTextureMemoryMb]
10216
10240
  );
10217
- (0, import_react37.useEffect)(() => {
10241
+ (0, import_react38.useEffect)(() => {
10218
10242
  manager.resume();
10219
10243
  return () => manager.dispose();
10220
10244
  }, [manager]);
10221
10245
  return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(TileTextureManagerContext.Provider, { value: manager, children });
10222
10246
  }
10223
10247
  function useSharedTileTextureManager() {
10224
- return (0, import_react37.useContext)(TileTextureManagerContext);
10248
+ return (0, import_react38.useContext)(TileTextureManagerContext);
10225
10249
  }
10226
10250
 
10227
10251
  // src/tile/texture-hooks.ts
10228
- var import_react38 = require("react");
10252
+ var import_react39 = require("react");
10229
10253
  var import_three12 = require("three");
10230
10254
  function usePreviewTexture(url, anisotropy, onError) {
10231
- const [texture, setTexture] = (0, import_react38.useState)(null);
10232
- const onErrorRef = (0, import_react38.useRef)(onError);
10255
+ const [texture, setTexture] = (0, import_react39.useState)(null);
10256
+ const onErrorRef = (0, import_react39.useRef)(onError);
10233
10257
  onErrorRef.current = onError;
10234
- (0, import_react38.useEffect)(() => {
10258
+ (0, import_react39.useEffect)(() => {
10235
10259
  if (!url) {
10236
10260
  setTexture(null);
10237
10261
  return;
@@ -10268,7 +10292,7 @@ function usePreviewTexture(url, anisotropy, onError) {
10268
10292
  active = false;
10269
10293
  };
10270
10294
  }, [anisotropy, url]);
10271
- (0, import_react38.useEffect)(
10295
+ (0, import_react39.useEffect)(
10272
10296
  () => () => {
10273
10297
  texture?.dispose();
10274
10298
  },
@@ -10277,14 +10301,14 @@ function usePreviewTexture(url, anisotropy, onError) {
10277
10301
  return texture;
10278
10302
  }
10279
10303
  function useManagedTexture(manager, key, url, address) {
10280
- const [managedState, setManagedState] = (0, import_react38.useState)(() => ({
10304
+ const [managedState, setManagedState] = (0, import_react39.useState)(() => ({
10281
10305
  manager,
10282
10306
  key,
10283
10307
  url,
10284
10308
  snapshot: manager.getSnapshot(key)
10285
10309
  }));
10286
10310
  const snapshot = managedState.manager === manager && managedState.key === key && managedState.url === url ? managedState.snapshot : manager.getSnapshot(key);
10287
- (0, import_react38.useEffect)(
10311
+ (0, import_react39.useEffect)(
10288
10312
  () => manager.acquire(key, url, address, (nextSnapshot) => {
10289
10313
  setManagedState({
10290
10314
  manager,
@@ -10427,13 +10451,22 @@ function preferredSphereLevel(levels, height, dpr, verticalFov) {
10427
10451
 
10428
10452
  // src/sphere-tile/sphere-tile.tsx
10429
10453
  var import_jsx_runtime16 = require("react/jsx-runtime");
10454
+ function sphereTileViewShouldRefresh(input) {
10455
+ if (input.loadModeChanged || input.managerChanged) {
10456
+ return true;
10457
+ }
10458
+ if (input.elapsedMs < 100 || input.viewUnchanged) {
10459
+ return false;
10460
+ }
10461
+ return true;
10462
+ }
10430
10463
  function SpherePatch({
10431
10464
  address,
10432
10465
  texture,
10433
10466
  yawOffset,
10434
10467
  preview = false
10435
10468
  }) {
10436
- const geometry = (0, import_react39.useMemo)(
10469
+ const geometry = (0, import_react40.useMemo)(
10437
10470
  () => sphereTileGeometry(
10438
10471
  address,
10439
10472
  yawOffset,
@@ -10441,7 +10474,7 @@ function SpherePatch({
10441
10474
  ),
10442
10475
  [address, yawOffset, preview]
10443
10476
  );
10444
- (0, import_react39.useEffect)(() => () => geometry.dispose(), [geometry]);
10477
+ (0, import_react40.useEffect)(() => () => geometry.dispose(), [geometry]);
10445
10478
  return /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
10446
10479
  "mesh",
10447
10480
  {
@@ -10460,7 +10493,7 @@ function SpherePatch({
10460
10493
  }
10461
10494
  );
10462
10495
  }
10463
- var ManagedPatch = (0, import_react39.memo)(function ManagedPatch2({
10496
+ var ManagedPatch = (0, import_react40.memo)(function ManagedPatch2({
10464
10497
  address,
10465
10498
  manager,
10466
10499
  resolveUrl,
@@ -10474,7 +10507,7 @@ var ManagedPatch = (0, import_react39.memo)(function ManagedPatch2({
10474
10507
  url,
10475
10508
  address
10476
10509
  );
10477
- (0, import_react39.useEffect)(() => {
10510
+ (0, import_react40.useEffect)(() => {
10478
10511
  if (snapshot.texture) ready();
10479
10512
  }, [snapshot.texture, ready]);
10480
10513
  return snapshot.texture ? /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
@@ -10512,7 +10545,7 @@ function SphereTileSource({
10512
10545
  anisotropy,
10513
10546
  onPreviewError
10514
10547
  );
10515
- const callbacks = (0, import_react39.useRef)({
10548
+ const callbacks = (0, import_react40.useRef)({
10516
10549
  onReady,
10517
10550
  onLoadProgress,
10518
10551
  onTileError,
@@ -10524,7 +10557,7 @@ function SphereTileSource({
10524
10557
  1,
10525
10558
  Number.isFinite(maxTextureMemoryMb) ? maxTextureMemoryMb : 128
10526
10559
  ) * 1024 * 1024;
10527
- const ownedManager = (0, import_react39.useMemo)(
10560
+ const ownedManager = (0, import_react40.useMemo)(
10528
10561
  () => new TileTextureManager({
10529
10562
  anisotropy,
10530
10563
  maxBytes: ownedBudget,
@@ -10545,17 +10578,17 @@ function SphereTileSource({
10545
10578
  );
10546
10579
  const manager = sharedManager ?? ownedManager;
10547
10580
  const budget = manager.memoryBudgetBytes;
10548
- const readyRef = (0, import_react39.useRef)(false);
10549
- const ready = (0, import_react39.useCallback)(() => {
10581
+ const readyRef = (0, import_react40.useRef)(false);
10582
+ const ready = (0, import_react40.useCallback)(() => {
10550
10583
  if (!readyRef.current) {
10551
10584
  readyRef.current = true;
10552
10585
  callbacks.current.onReady?.();
10553
10586
  }
10554
10587
  }, []);
10555
- (0, import_react39.useEffect)(() => {
10588
+ (0, import_react40.useEffect)(() => {
10556
10589
  if (preview) ready();
10557
10590
  }, [preview, ready]);
10558
- (0, import_react39.useEffect)(() => {
10591
+ (0, import_react40.useEffect)(() => {
10559
10592
  manager.resume();
10560
10593
  return () => {
10561
10594
  if (manager === ownedManager) {
@@ -10565,14 +10598,14 @@ function SphereTileSource({
10565
10598
  queueMicrotask(() => manager.releaseUnused());
10566
10599
  };
10567
10600
  }, [manager, ownedManager]);
10568
- const resolveUrl = (0, import_react39.useMemo)(
10601
+ const resolveUrl = (0, import_react40.useMemo)(
10569
10602
  () => (address) => resolveAssetUrl(
10570
10603
  baseUrl,
10571
10604
  resolveTileUrl ? resolveTileUrl(address) : resolveSphereTemplateUrl(urlTemplate, address, indexBase)
10572
10605
  ),
10573
10606
  [baseUrl, resolveTileUrl, urlTemplate, indexBase]
10574
10607
  );
10575
- const candidates = (0, import_react39.useMemo)(
10608
+ const candidates = (0, import_react40.useMemo)(
10576
10609
  () => config.levels.map(
10577
10610
  (level, index) => sphereTileAddresses(level, index, config.tileSize).map((address) => ({
10578
10611
  address,
@@ -10581,12 +10614,17 @@ function SphereTileSource({
10581
10614
  ),
10582
10615
  [config, yawOffset]
10583
10616
  );
10584
- const previewAddress = (0, import_react39.useMemo)(
10617
+ const previewAddress = (0, import_react40.useMemo)(
10585
10618
  () => sphereTileAddresses({ width: 2, height: 1 }, 0, 2)[0],
10586
10619
  []
10587
10620
  );
10588
- const [layers, setLayers] = (0, import_react39.useState)([]);
10589
- const scratch = (0, import_react39.useMemo)(
10621
+ const [layers, setLayers] = (0, import_react40.useState)([]);
10622
+ const detailReporter = useSceneDetailReporter();
10623
+ const detailReporterRef = (0, import_react40.useRef)(detailReporter);
10624
+ detailReporterRef.current = detailReporter;
10625
+ const detailTokenRef = (0, import_react40.useRef)("");
10626
+ const targetKeysRef = (0, import_react40.useRef)([]);
10627
+ const scratch = (0, import_react40.useMemo)(
10590
10628
  () => ({
10591
10629
  camera: new import_three14.PerspectiveCamera(),
10592
10630
  frustum: new import_three14.Frustum(),
@@ -10607,53 +10645,72 @@ function SphereTileSource({
10607
10645
  (0, import_fiber16.useFrame)(() => {
10608
10646
  if (!(camera instanceof import_three14.PerspectiveCamera)) return;
10609
10647
  const now = performance.now(), dpr = gl.getPixelRatio();
10610
- const reset = scratch.manager !== manager || scratch.loadMode !== loadMode;
10611
- 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))
10612
- return;
10613
- scratch.time = now;
10614
- scratch.fov = camera.fov;
10615
- scratch.width = size.width;
10616
- scratch.height = size.height;
10617
- scratch.dpr = dpr;
10618
- scratch.quaternion.copy(camera.quaternion);
10619
- scratch.manager = manager;
10620
- scratch.loadMode = loadMode;
10621
- scratch.camera.copy(camera, false);
10622
- scratch.camera.fov = Math.min(179, camera.fov + 8);
10623
- scratch.camera.updateProjectionMatrix();
10624
- scratch.camera.updateMatrixWorld();
10625
- scratch.matrix.multiplyMatrices(
10626
- scratch.camera.projectionMatrix,
10627
- scratch.camera.matrixWorldInverse
10628
- );
10629
- scratch.frustum.setFromProjectionMatrix(scratch.matrix);
10630
- let level = loadMode === "preview" ? -1 : loadMode === "base" ? 0 : preferredSphereLevel(config.levels, size.height, dpr, camera.fov);
10631
- const next = [];
10632
- let residentBytes = 0;
10633
- for (let index = 0; index <= level; index++) {
10634
- const addresses = candidates[index].filter(
10635
- ({ bounds }) => scratch.frustum.intersectsBox(bounds)
10636
- ).map(({ address }) => address);
10637
- const bytes = addresses.reduce(
10638
- (total, address) => total + address.width * address.height * 4,
10639
- 0
10648
+ const managerChanged = scratch.manager !== manager;
10649
+ const loadModeChanged = scratch.loadMode !== loadMode;
10650
+ const viewUnchanged = scratch.fov === camera.fov && scratch.width === size.width && scratch.height === size.height && scratch.dpr === dpr && scratch.quaternion.angleTo(camera.quaternion) < 1e-4;
10651
+ if (sphereTileViewShouldRefresh({
10652
+ loadModeChanged,
10653
+ managerChanged,
10654
+ elapsedMs: now - scratch.time,
10655
+ viewUnchanged
10656
+ })) {
10657
+ const reset = managerChanged || loadModeChanged;
10658
+ scratch.time = now;
10659
+ scratch.fov = camera.fov;
10660
+ scratch.width = size.width;
10661
+ scratch.height = size.height;
10662
+ scratch.dpr = dpr;
10663
+ scratch.quaternion.copy(camera.quaternion);
10664
+ scratch.manager = manager;
10665
+ scratch.loadMode = loadMode;
10666
+ scratch.camera.copy(camera, false);
10667
+ scratch.camera.fov = Math.min(179, camera.fov + 8);
10668
+ scratch.camera.updateProjectionMatrix();
10669
+ scratch.camera.updateMatrixWorld();
10670
+ scratch.matrix.multiplyMatrices(
10671
+ scratch.camera.projectionMatrix,
10672
+ scratch.camera.matrixWorldInverse
10640
10673
  );
10641
- if (residentBytes + bytes > budget) {
10642
- level = index - 1;
10643
- break;
10674
+ scratch.frustum.setFromProjectionMatrix(scratch.matrix);
10675
+ let level = loadMode === "preview" ? -1 : loadMode === "base" ? 0 : preferredSphereLevel(config.levels, size.height, dpr, camera.fov);
10676
+ const next = [];
10677
+ let residentBytes = 0;
10678
+ for (let index = 0; index <= level; index++) {
10679
+ const addresses = candidates[index].filter(
10680
+ ({ bounds }) => scratch.frustum.intersectsBox(bounds)
10681
+ ).map(({ address }) => address);
10682
+ const bytes = addresses.reduce(
10683
+ (total, address) => total + address.width * address.height * 4,
10684
+ 0
10685
+ );
10686
+ if (residentBytes + bytes > budget) {
10687
+ level = index - 1;
10688
+ break;
10689
+ }
10690
+ residentBytes += bytes;
10691
+ next.push({ level: index, addresses });
10692
+ }
10693
+ const targetLayer = loadMode === "full" ? next[next.length - 1] : void 0;
10694
+ targetKeysRef.current = targetLayer ? targetLayer.addresses.map(
10695
+ (address) => `${resolveUrl(address)}\0${sphereTileKey(address)}`
10696
+ ) : [];
10697
+ if (level !== scratch.level) {
10698
+ scratch.level = level;
10699
+ if (level >= 0) callbacks.current.onLevelChange?.(level);
10700
+ }
10701
+ const token = next.map((layer) => layer.addresses.map(sphereTileKey).join(",")).join(";");
10702
+ if (token !== scratch.token || reset) {
10703
+ scratch.token = token;
10704
+ setLayers(next);
10644
10705
  }
10645
- residentBytes += bytes;
10646
- next.push({ level: index, addresses });
10647
- }
10648
- if (level !== scratch.level) {
10649
- scratch.level = level;
10650
- if (level >= 0) callbacks.current.onLevelChange?.(level);
10651
- }
10652
- const token = next.map((layer) => layer.addresses.map(sphereTileKey).join(",")).join(";");
10653
- if (token !== scratch.token || reset) {
10654
- scratch.token = token;
10655
- setLayers(next);
10656
10706
  }
10707
+ publishSceneDetail(
10708
+ detailReporterRef.current,
10709
+ detailTokenRef,
10710
+ loadMode === "full" && viewTilesAreDrawable(
10711
+ targetKeysRef.current.map((key) => manager.getSnapshot(key).texture)
10712
+ )
10713
+ );
10657
10714
  });
10658
10715
  return /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("group", { visible, children: [
10659
10716
  preview ? /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
@@ -10682,23 +10739,23 @@ function SphereTileSource({
10682
10739
  }
10683
10740
  function SphereTile({ multires, ...props }) {
10684
10741
  const token = typeof multires === "string" ? multires : JSON.stringify(multires);
10685
- const config = (0, import_react39.useMemo)(() => parseSphereMultires(multires), [token]);
10742
+ const config = (0, import_react40.useMemo)(() => parseSphereMultires(multires), [token]);
10686
10743
  const sourceKey = `${props.baseUrl}\0${token}\0${props.previewUrl}\0${props.urlTemplate ?? ""}\0${props.indexBase ?? 1}`;
10687
10744
  return /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(SphereTileSource, { ...props, config }, sourceKey);
10688
10745
  }
10689
10746
 
10690
10747
  // src/sphere.tsx
10691
10748
  var import_fiber17 = require("@react-three/fiber");
10692
- var import_react40 = require("react");
10749
+ var import_react41 = require("react");
10693
10750
  var import_three15 = require("three");
10694
10751
  var import_jsx_runtime17 = require("react/jsx-runtime");
10695
10752
  function useEquirectTexture(url, anisotropy, generateMipmaps, onLoad, onError) {
10696
- const [texture, setTexture] = (0, import_react40.useState)(null);
10697
- const onLoadRef = (0, import_react40.useRef)(onLoad);
10698
- const onErrorRef = (0, import_react40.useRef)(onError);
10753
+ const [texture, setTexture] = (0, import_react41.useState)(null);
10754
+ const onLoadRef = (0, import_react41.useRef)(onLoad);
10755
+ const onErrorRef = (0, import_react41.useRef)(onError);
10699
10756
  onLoadRef.current = onLoad;
10700
10757
  onErrorRef.current = onError;
10701
- (0, import_react40.useEffect)(() => {
10758
+ (0, import_react41.useEffect)(() => {
10702
10759
  if (!url) {
10703
10760
  setTexture(null);
10704
10761
  return;
@@ -10737,7 +10794,7 @@ function useEquirectTexture(url, anisotropy, generateMipmaps, onLoad, onError) {
10737
10794
  active = false;
10738
10795
  };
10739
10796
  }, [anisotropy, generateMipmaps, url]);
10740
- (0, import_react40.useEffect)(
10797
+ (0, import_react41.useEffect)(
10741
10798
  () => () => {
10742
10799
  texture?.dispose();
10743
10800
  },
@@ -10757,7 +10814,7 @@ function Sphere({
10757
10814
  }) {
10758
10815
  const gl = (0, import_fiber17.useThree)((state) => state.gl);
10759
10816
  const anisotropy = gl.capabilities.getMaxAnisotropy();
10760
- const resolvedPreviewUrl = (0, import_react40.useMemo)(
10817
+ const resolvedPreviewUrl = (0, import_react41.useMemo)(
10761
10818
  () => resolveUrlAgainstFile(src, previewUrl),
10762
10819
  [previewUrl, src]
10763
10820
  );
@@ -10776,11 +10833,21 @@ function Sphere({
10776
10833
  onPreviewError
10777
10834
  );
10778
10835
  const displayTexture = texture ?? previewTexture;
10779
- const readyRef = (0, import_react40.useRef)(false);
10780
- (0, import_react40.useEffect)(() => {
10836
+ const readyRef = (0, import_react41.useRef)(false);
10837
+ const detailReporter = useSceneDetailReporter();
10838
+ (0, import_react41.useEffect)(() => {
10781
10839
  readyRef.current = false;
10782
10840
  }, [resolvedPreviewUrl, src]);
10783
- (0, import_react40.useEffect)(() => {
10841
+ (0, import_react41.useEffect)(() => {
10842
+ if (!detailReporter) {
10843
+ return;
10844
+ }
10845
+ detailReporter.report(texture != null);
10846
+ return () => {
10847
+ detailReporter.report(false);
10848
+ };
10849
+ }, [detailReporter, texture]);
10850
+ (0, import_react41.useEffect)(() => {
10784
10851
  if (!displayTexture || readyRef.current) {
10785
10852
  return;
10786
10853
  }
@@ -10812,7 +10879,7 @@ function Sphere({
10812
10879
 
10813
10880
  // src/video/pano-video.tsx
10814
10881
  var import_fiber18 = require("@react-three/fiber");
10815
- var import_react41 = require("react");
10882
+ var import_react42 = require("react");
10816
10883
  var import_three16 = require("three");
10817
10884
  var import_jsx_runtime18 = require("react/jsx-runtime");
10818
10885
  var EMPTY_TRACKS = [];
@@ -10899,10 +10966,10 @@ function applyEquirectangularLayout(texture, anisotropy) {
10899
10966
  }
10900
10967
  function usePosterTexture(poster, onError) {
10901
10968
  const gl = (0, import_fiber18.useThree)((state) => state.gl);
10902
- const [texture, setTexture] = (0, import_react41.useState)(null);
10903
- const onErrorRef = (0, import_react41.useRef)(onError);
10969
+ const [texture, setTexture] = (0, import_react42.useState)(null);
10970
+ const onErrorRef = (0, import_react42.useRef)(onError);
10904
10971
  onErrorRef.current = onError;
10905
- (0, import_react41.useEffect)(() => {
10972
+ (0, import_react42.useEffect)(() => {
10906
10973
  let active = true;
10907
10974
  setTexture(null);
10908
10975
  if (!poster) {
@@ -10939,7 +11006,7 @@ function usePosterTexture(poster, onError) {
10939
11006
  active = false;
10940
11007
  };
10941
11008
  }, [gl, poster]);
10942
- (0, import_react41.useEffect)(
11009
+ (0, import_react42.useEffect)(
10943
11010
  () => () => {
10944
11011
  texture?.dispose();
10945
11012
  },
@@ -10998,38 +11065,38 @@ function PanoVideo({
10998
11065
  }) {
10999
11066
  usePanoMediaActivationIntent(autoPlay);
11000
11067
  const gl = (0, import_fiber18.useThree)((state) => state.gl);
11001
- const host = (0, import_react41.useContext)(PanoVideoHostContext);
11002
- const overlay = (0, import_react41.useContext)(PanoChromeOverlayContext);
11003
- const variants = (0, import_react41.useMemo)(
11068
+ const host = (0, import_react42.useContext)(PanoVideoHostContext);
11069
+ const overlay = (0, import_react42.useContext)(PanoChromeOverlayContext);
11070
+ const variants = (0, import_react42.useMemo)(
11004
11071
  () => resolvePanoVideoVariants({ poster, src, variants: variantsProp }),
11005
11072
  [poster, src, variantsProp]
11006
11073
  );
11007
11074
  const tracks = tracksProp ?? EMPTY_TRACKS;
11008
11075
  const captionsEnabled = captions !== false;
11009
- const captionAppearance = (0, import_react41.useMemo)(
11076
+ const captionAppearance = (0, import_react42.useMemo)(
11010
11077
  () => resolvePanoVideoCaptionAppearance(
11011
11078
  typeof captions === "object" ? captions : void 0
11012
11079
  ),
11013
11080
  [captions]
11014
11081
  );
11015
- const [variantId, setVariantId] = (0, import_react41.useState)(
11082
+ const [variantId, setVariantId] = (0, import_react42.useState)(
11016
11083
  () => resolvePanoVideoVariantId(variants, defaultVariantId)
11017
11084
  );
11018
- const [trackId, setTrackId] = (0, import_react41.useState)(
11085
+ const [trackId, setTrackId] = (0, import_react42.useState)(
11019
11086
  () => captionsEnabled ? defaultPanoVideoTrackId(tracks) : null
11020
11087
  );
11021
- const [ready, setReady] = (0, import_react41.useState)(false);
11022
- const autoPlayRef = (0, import_react41.useRef)(autoPlay);
11088
+ const [ready, setReady] = (0, import_react42.useState)(false);
11089
+ const autoPlayRef = (0, import_react42.useRef)(autoPlay);
11023
11090
  autoPlayRef.current = autoPlay;
11024
- const blockedRef = (0, import_react41.useRef)(false);
11025
- const captionAppearanceOverrideRef = (0, import_react41.useRef)(
11091
+ const blockedRef = (0, import_react42.useRef)(false);
11092
+ const captionAppearanceOverrideRef = (0, import_react42.useRef)(
11026
11093
  {}
11027
11094
  );
11028
- const mediaCapabilitiesRef = (0, import_react41.useRef)({
11095
+ const mediaCapabilitiesRef = (0, import_react42.useRef)({
11029
11096
  volumeAdjustable: true,
11030
11097
  playbackRates: [...DEFAULT_PANO_VIDEO_PLAYBACK_RATES]
11031
11098
  });
11032
- const storeRef = (0, import_react41.useRef)(null);
11099
+ const storeRef = (0, import_react42.useRef)(null);
11033
11100
  if (!storeRef.current) {
11034
11101
  storeRef.current = {
11035
11102
  snapshot: {
@@ -11039,7 +11106,7 @@ function PanoVideo({
11039
11106
  listeners: /* @__PURE__ */ new Set()
11040
11107
  };
11041
11108
  }
11042
- const actionsRef = (0, import_react41.useRef)({
11109
+ const actionsRef = (0, import_react42.useRef)({
11043
11110
  play: async () => {
11044
11111
  },
11045
11112
  pause: () => {
@@ -11059,19 +11126,19 @@ function PanoVideo({
11059
11126
  setCaptionAppearance: (_appearance) => {
11060
11127
  }
11061
11128
  });
11062
- const onLoadRef = (0, import_react41.useRef)(onLoad);
11063
- const onErrorRef = (0, import_react41.useRef)(onError);
11064
- const onPlaybackStateChangeRef = (0, import_react41.useRef)(onPlaybackStateChange);
11065
- const onEndedRef = (0, import_react41.useRef)(onEnded);
11066
- const onVariantChangeRef = (0, import_react41.useRef)(onVariantChange);
11067
- const onTrackChangeRef = (0, import_react41.useRef)(onTrackChange);
11129
+ const onLoadRef = (0, import_react42.useRef)(onLoad);
11130
+ const onErrorRef = (0, import_react42.useRef)(onError);
11131
+ const onPlaybackStateChangeRef = (0, import_react42.useRef)(onPlaybackStateChange);
11132
+ const onEndedRef = (0, import_react42.useRef)(onEnded);
11133
+ const onVariantChangeRef = (0, import_react42.useRef)(onVariantChange);
11134
+ const onTrackChangeRef = (0, import_react42.useRef)(onTrackChange);
11068
11135
  onLoadRef.current = onLoad;
11069
11136
  onErrorRef.current = onError;
11070
11137
  onPlaybackStateChangeRef.current = onPlaybackStateChange;
11071
11138
  onEndedRef.current = onEnded;
11072
11139
  onVariantChangeRef.current = onVariantChange;
11073
11140
  onTrackChangeRef.current = onTrackChange;
11074
- const resource = (0, import_react41.useMemo)(() => {
11141
+ const resource = (0, import_react42.useMemo)(() => {
11075
11142
  if (typeof document === "undefined") {
11076
11143
  return null;
11077
11144
  }
@@ -11088,7 +11155,7 @@ function PanoVideo({
11088
11155
  texture.generateMipmaps = false;
11089
11156
  return { video, texture };
11090
11157
  }, []);
11091
- (0, import_react41.useEffect)(
11158
+ (0, import_react42.useEffect)(
11092
11159
  () => () => {
11093
11160
  if (!resource) {
11094
11161
  return;
@@ -11103,13 +11170,13 @@ function PanoVideo({
11103
11170
  },
11104
11171
  [resource]
11105
11172
  );
11106
- (0, import_react41.useEffect)(() => {
11173
+ (0, import_react42.useEffect)(() => {
11107
11174
  if (!resource) {
11108
11175
  return;
11109
11176
  }
11110
11177
  resource.texture.anisotropy = gl.capabilities.getMaxAnisotropy();
11111
11178
  }, [gl, resource]);
11112
- (0, import_react41.useEffect)(() => {
11179
+ (0, import_react42.useEffect)(() => {
11113
11180
  if (!resource || !overlay?.overlayElement) {
11114
11181
  return;
11115
11182
  }
@@ -11132,7 +11199,7 @@ function PanoVideo({
11132
11199
  activeVariant?.poster ?? poster,
11133
11200
  onError
11134
11201
  );
11135
- const emitSnapshot = (0, import_react41.useCallback)(
11202
+ const emitSnapshot = (0, import_react42.useCallback)(
11136
11203
  (patch) => {
11137
11204
  const store = storeRef.current;
11138
11205
  const video = resource?.video;
@@ -11184,7 +11251,7 @@ function PanoVideo({
11184
11251
  captionAppearance
11185
11252
  ]
11186
11253
  );
11187
- const controller = (0, import_react41.useMemo)(
11254
+ const controller = (0, import_react42.useMemo)(
11188
11255
  () => ({
11189
11256
  subscribe: (onStoreChange) => {
11190
11257
  const store = storeRef.current;
@@ -11236,7 +11303,7 @@ function PanoVideo({
11236
11303
  }),
11237
11304
  []
11238
11305
  );
11239
- (0, import_react41.useLayoutEffect)(() => {
11306
+ (0, import_react42.useLayoutEffect)(() => {
11240
11307
  if (!host || variants.length === 0) {
11241
11308
  return;
11242
11309
  }
@@ -11249,7 +11316,7 @@ function PanoVideo({
11249
11316
  notifyPanoVideoHost(host);
11250
11317
  };
11251
11318
  }, [captionsEnabled, controller, controls, host, variants.length]);
11252
- (0, import_react41.useLayoutEffect)(() => {
11319
+ (0, import_react42.useLayoutEffect)(() => {
11253
11320
  if (!resource) {
11254
11321
  return;
11255
11322
  }
@@ -11262,10 +11329,10 @@ function PanoVideo({
11262
11329
  };
11263
11330
  emitSnapshot();
11264
11331
  }, [emitSnapshot, playbackRates, resource]);
11265
- (0, import_react41.useEffect)(() => {
11332
+ (0, import_react42.useEffect)(() => {
11266
11333
  emitSnapshot();
11267
11334
  }, [emitSnapshot]);
11268
- (0, import_react41.useEffect)(() => {
11335
+ (0, import_react42.useEffect)(() => {
11269
11336
  if (!resource || !activeVariant || !mediaKey) {
11270
11337
  return;
11271
11338
  }
@@ -11322,7 +11389,7 @@ function PanoVideo({
11322
11389
  video.removeEventListener("error", handleError);
11323
11390
  };
11324
11391
  }, [mediaKey, resource]);
11325
- (0, import_react41.useEffect)(() => {
11392
+ (0, import_react42.useEffect)(() => {
11326
11393
  if (!resource) {
11327
11394
  return;
11328
11395
  }
@@ -11414,7 +11481,7 @@ function PanoVideo({
11414
11481
  }
11415
11482
  };
11416
11483
  }, [emitSnapshot, resource]);
11417
- (0, import_react41.useEffect)(() => {
11484
+ (0, import_react42.useEffect)(() => {
11418
11485
  if (!resource) {
11419
11486
  return;
11420
11487
  }
@@ -11434,7 +11501,7 @@ function PanoVideo({
11434
11501
  }
11435
11502
  video.preload = preload;
11436
11503
  }, [loop, muted, playsInline, preload, resource, volume]);
11437
- (0, import_react41.useEffect)(() => {
11504
+ (0, import_react42.useEffect)(() => {
11438
11505
  if (!resource) {
11439
11506
  return;
11440
11507
  }
@@ -11484,7 +11551,7 @@ function PanoVideo({
11484
11551
  video.removeEventListener("ratechange", handleVolume);
11485
11552
  };
11486
11553
  }, [emitSnapshot, resource]);
11487
- (0, import_react41.useEffect)(() => {
11554
+ (0, import_react42.useEffect)(() => {
11488
11555
  if (!resource) {
11489
11556
  return;
11490
11557
  }
@@ -11519,7 +11586,7 @@ function PanoVideo({
11519
11586
  video.textTracks.removeEventListener("change", applyModes);
11520
11587
  };
11521
11588
  }, [emitSnapshot, resource, trackId, tracks]);
11522
- (0, import_react41.useEffect)(() => {
11589
+ (0, import_react42.useEffect)(() => {
11523
11590
  if (!captionsEnabled) {
11524
11591
  setTrackId(null);
11525
11592
  return;
@@ -11554,9 +11621,9 @@ function PanoVideo({
11554
11621
  }
11555
11622
 
11556
11623
  // src/scenes.tsx
11557
- var import_fiber22 = require("@react-three/fiber");
11558
- var import_react45 = require("react");
11559
- var import_three23 = require("three");
11624
+ var import_fiber23 = require("@react-three/fiber");
11625
+ var import_react47 = require("react");
11626
+ var import_three24 = require("three");
11560
11627
 
11561
11628
  // src/scene-transitions/presets.ts
11562
11629
  var TRANSITION_DEFAULTS = {
@@ -11604,9 +11671,33 @@ function isSnapshotTransition(preset) {
11604
11671
  return preset !== "none" && preset !== "particles";
11605
11672
  }
11606
11673
 
11607
- // src/scene-transitions/particle-overlay.tsx
11674
+ // src/scene-transitions/snapshot-hold.tsx
11608
11675
  var import_fiber19 = require("@react-three/fiber");
11609
- var import_react42 = require("react");
11676
+ var import_react43 = require("react");
11677
+ var import_three19 = require("three");
11678
+
11679
+ // src/scene-transitions/overlay-utils.ts
11680
+ var import_three17 = require("three");
11681
+ var OVERLAY_RENDER_ORDER = 1e4;
11682
+ var FULLSCREEN_PLANE = new import_three17.PlaneGeometry(1, 1);
11683
+ function isPerspectiveCamera(camera) {
11684
+ return camera.isPerspectiveCamera === true;
11685
+ }
11686
+ function placeFullscreenOverlay(mesh, camera, direction) {
11687
+ const distance = Math.max(camera.near * 1.1, 0.11);
11688
+ camera.getWorldDirection(direction);
11689
+ mesh.position.copy(camera.position).addScaledVector(direction, distance);
11690
+ mesh.quaternion.copy(camera.quaternion);
11691
+ const height = 2 * distance * Math.tan(camera.fov * Math.PI / 360);
11692
+ mesh.scale.set(height * camera.aspect, height, 1);
11693
+ }
11694
+ function overlayProgress(elapsedTime, duration, startTime) {
11695
+ const started = startTime ?? elapsedTime;
11696
+ const progress = duration === 0 ? 1 : Math.min(1, (elapsedTime - started) / duration);
11697
+ return { startTime: started, progress };
11698
+ }
11699
+
11700
+ // src/scene-transitions/snapshot-shaders.ts
11610
11701
  var import_three18 = require("three");
11611
11702
 
11612
11703
  // src/scene-transitions/glsl.ts
@@ -11639,227 +11730,65 @@ float fbm(vec2 p) {
11639
11730
  }
11640
11731
  `;
11641
11732
 
11642
- // src/scene-transitions/overlay-utils.ts
11643
- var import_three17 = require("three");
11644
- var OVERLAY_RENDER_ORDER = 1e4;
11645
- var FULLSCREEN_PLANE = new import_three17.PlaneGeometry(1, 1);
11646
- function isPerspectiveCamera(camera) {
11647
- return camera.isPerspectiveCamera === true;
11733
+ // src/scene-transitions/snapshot-shaders.ts
11734
+ var SNAPSHOT_VERTEX_SHADER = `
11735
+ varying vec2 vUv;
11736
+ void main() {
11737
+ vUv = uv;
11738
+ gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
11739
+ }
11740
+ `;
11741
+ var HEADER = `
11742
+ uniform sampler2D map;
11743
+ uniform float progress;
11744
+ uniform vec2 resolution;
11745
+ varying vec2 vUv;
11746
+ ${GLSL_COMMON}
11747
+
11748
+ vec2 aspectGrid(float rows) {
11749
+ float aspect = resolution.x / max(resolution.y, 1.0);
11750
+ return vec2(max(8.0, floor(rows * aspect)), rows);
11648
11751
  }
11649
- function placeFullscreenOverlay(mesh, camera, direction) {
11650
- const distance = Math.max(camera.near * 1.1, 0.11);
11651
- camera.getWorldDirection(direction);
11652
- mesh.position.copy(camera.position).addScaledVector(direction, distance);
11653
- mesh.quaternion.copy(camera.quaternion);
11654
- const height = 2 * distance * Math.tan(camera.fov * Math.PI / 360);
11655
- mesh.scale.set(height * camera.aspect, height, 1);
11752
+
11753
+ vec2 gridCellId() {
11754
+ return floor(vUv * aspectGrid(16.0));
11656
11755
  }
11657
- function overlayProgress(elapsedTime, duration, startTime) {
11658
- const started = startTime ?? elapsedTime;
11659
- const progress = duration === 0 ? 1 : Math.min(1, (elapsedTime - started) / duration);
11660
- return { startTime: started, progress };
11756
+
11757
+ vec2 gridCellUv() {
11758
+ vec2 cells = aspectGrid(16.0);
11759
+ return (floor(vUv * cells) + 0.5) / cells;
11661
11760
  }
11662
11761
 
11663
- // src/scene-transitions/particle-overlay.tsx
11664
- var import_jsx_runtime19 = require("react/jsx-runtime");
11665
- var PARTICLE_GRID = 48;
11666
- var PARTICLE_COUNT = PARTICLE_GRID * PARTICLE_GRID;
11667
- var PARTICLE_VERTEX_SHADER = `
11668
- attribute float instanceIndex;
11669
- uniform float progress;
11670
- uniform vec2 grid;
11671
- varying vec2 vUv;
11672
- varying float vAlpha;
11673
- ${GLSL_COMMON}
11762
+ float gridWipeAlpha(float spatialOrder, float t) {
11763
+ vec2 cells = aspectGrid(16.0);
11764
+ vec2 id = floor(vUv * cells);
11765
+ vec2 local = fract(vUv * cells);
11766
+ float order = mix(clamp(spatialOrder, 0.0, 1.0), hash(id), 0.12);
11767
+ float disappear = smoothstep(order, order + 0.16, t);
11768
+ float sc = mix(1.0, 0.18, disappear);
11769
+ vec2 scaled = 0.5 + (local - 0.5) / max(sc, 0.001);
11770
+ float inside = step(0.0, scaled.x) * step(scaled.x, 1.0) * step(0.0, scaled.y) * step(scaled.y, 1.0);
11771
+ return inside * (1.0 - disappear);
11772
+ }
11674
11773
 
11675
- void main() {
11676
- float id = instanceIndex;
11677
- float gx = mod(id, grid.x);
11678
- float gy = floor(id / grid.x);
11679
- vec2 cell = vec2(gx, gy);
11680
- float h = hash(cell);
11681
- float h2 = hash(cell + 19.2);
11682
- float h3 = hash(cell + 7.7);
11683
- vec2 randomDir = normalize(vec2(h, h2) * 2.0 - 1.0 + 1e-5);
11684
- vec2 fromCenter = (cell + 0.5) / grid - 0.5 + 1e-5;
11685
- vec2 dir = normalize(mix(randomDir, normalize(fromCenter), 0.65));
11686
- float delay = h3 * 0.28;
11687
- float lt = clamp((progress - delay) / max(1.0 - delay, 0.001), 0.0, 1.0);
11688
- float explode = lt * lt;
11689
- float scale = mix(1.0, 0.18, explode);
11690
- float angle = (h * 2.0 - 1.0) * explode * 4.2;
11691
- float ca = cos(angle);
11692
- float sa = sin(angle);
11693
- vec2 cellSize = 1.0 / grid;
11694
- vec2 local = position.xy * cellSize * scale;
11695
- vec2 rotated = vec2(local.x * ca - local.y * sa, local.x * sa + local.y * ca);
11696
- vec2 planeCenter = (cell + 0.5) / grid - 0.5;
11697
- vec2 exploded = planeCenter + dir * explode * 0.9;
11698
- vec3 pos = vec3(exploded + rotated, -explode * 0.14);
11699
- vUv = (cell + uv) / grid;
11700
- vAlpha = 1.0 - explode;
11701
- gl_Position = projectionMatrix * modelViewMatrix * vec4(pos, 1.0);
11702
- }
11703
- `;
11704
- var PARTICLE_FRAGMENT_SHADER = `
11705
- uniform sampler2D map;
11706
- varying vec2 vUv;
11707
- varying float vAlpha;
11774
+ float hexRound(float x) {
11775
+ return floor(x + 0.5);
11776
+ }
11708
11777
 
11709
- void main() {
11710
- vec4 old = texture2D(map, vUv);
11711
- old.rgb *= 1.0 + 0.22 * (1.0 - vAlpha);
11712
- gl_FragColor = vec4(old.rgb, old.a * vAlpha);
11713
- #include <colorspace_fragment>
11714
- }
11715
- `;
11716
- function createParticleGeometry() {
11717
- const quad = new import_three18.PlaneGeometry(1, 1);
11718
- const geometry = new import_three18.InstancedBufferGeometry();
11719
- if (quad.index) {
11720
- geometry.setIndex(quad.index.clone());
11721
- }
11722
- geometry.setAttribute("position", quad.attributes.position.clone());
11723
- geometry.setAttribute("uv", quad.attributes.uv.clone());
11724
- const indexes = new Float32Array(PARTICLE_COUNT);
11725
- for (let i = 0; i < PARTICLE_COUNT; i += 1) {
11726
- indexes[i] = i;
11778
+ vec2 hexCellId(vec2 uv) {
11779
+ float aspect = resolution.x / max(resolution.y, 1.0);
11780
+ vec2 p = (uv - 0.5) * vec2(aspect, 1.0) * 12.0;
11781
+ float q = 1.1547005 * p.x;
11782
+ float r = -0.5773503 * p.x + p.y;
11783
+ vec3 cube = vec3(q, -q - r, r);
11784
+ vec3 rounded = vec3(hexRound(cube.x), hexRound(cube.y), hexRound(cube.z));
11785
+ vec3 diff = abs(rounded - cube);
11786
+ if (diff.x > diff.y && diff.x > diff.z) {
11787
+ rounded.x = -rounded.y - rounded.z;
11788
+ } else if (diff.y > diff.z) {
11789
+ rounded.y = -rounded.x - rounded.z;
11727
11790
  }
11728
- geometry.setAttribute("instanceIndex", new import_three18.InstancedBufferAttribute(indexes, 1));
11729
- geometry.instanceCount = PARTICLE_COUNT;
11730
- quad.dispose();
11731
- return geometry;
11732
- }
11733
- function ParticleOverlay({
11734
- snapshot,
11735
- transition,
11736
- running,
11737
- runId,
11738
- onFinish
11739
- }) {
11740
- const { camera } = (0, import_fiber19.useThree)();
11741
- const meshRef = (0, import_react42.useRef)(null);
11742
- const startRef = (0, import_react42.useRef)(null);
11743
- const finishedRef = (0, import_react42.useRef)(false);
11744
- const directionRef = (0, import_react42.useRef)(new import_three18.Vector3());
11745
- const geometry = (0, import_react42.useMemo)(() => createParticleGeometry(), []);
11746
- const material = (0, import_react42.useMemo)(
11747
- () => new import_three18.ShaderMaterial({
11748
- transparent: true,
11749
- depthTest: false,
11750
- depthWrite: false,
11751
- side: import_three18.DoubleSide,
11752
- uniforms: {
11753
- map: { value: snapshot.texture },
11754
- progress: { value: 0 },
11755
- grid: { value: new import_three18.Vector2(PARTICLE_GRID, PARTICLE_GRID) }
11756
- },
11757
- vertexShader: PARTICLE_VERTEX_SHADER,
11758
- fragmentShader: PARTICLE_FRAGMENT_SHADER
11759
- }),
11760
- [snapshot.texture]
11761
- );
11762
- (0, import_react42.useEffect)(() => () => geometry.dispose(), [geometry]);
11763
- (0, import_react42.useEffect)(() => () => material.dispose(), [material]);
11764
- (0, import_react42.useEffect)(() => {
11765
- startRef.current = null;
11766
- finishedRef.current = false;
11767
- material.uniforms.progress.value = 0;
11768
- }, [material, runId]);
11769
- (0, import_fiber19.useFrame)((state) => {
11770
- const mesh = meshRef.current;
11771
- if (!mesh || !isPerspectiveCamera(camera)) {
11772
- return;
11773
- }
11774
- placeFullscreenOverlay(mesh, camera, directionRef.current);
11775
- if (!running || finishedRef.current) {
11776
- return;
11777
- }
11778
- const next = overlayProgress(state.clock.elapsedTime, transition.duration, startRef.current);
11779
- startRef.current = next.startTime;
11780
- material.uniforms.progress.value = next.progress;
11781
- if (next.progress === 1) {
11782
- finishedRef.current = true;
11783
- onFinish();
11784
- }
11785
- });
11786
- return /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
11787
- "mesh",
11788
- {
11789
- ref: meshRef,
11790
- frustumCulled: false,
11791
- geometry,
11792
- material,
11793
- renderOrder: OVERLAY_RENDER_ORDER
11794
- }
11795
- );
11796
- }
11797
-
11798
- // src/scene-transitions/snapshot-overlay.tsx
11799
- var import_fiber20 = require("@react-three/fiber");
11800
- var import_react43 = require("react");
11801
- var import_three20 = require("three");
11802
-
11803
- // src/scene-transitions/snapshot-shaders.ts
11804
- var import_three19 = require("three");
11805
- var SNAPSHOT_VERTEX_SHADER = `
11806
- varying vec2 vUv;
11807
- void main() {
11808
- vUv = uv;
11809
- gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
11810
- }
11811
- `;
11812
- var HEADER = `
11813
- uniform sampler2D map;
11814
- uniform float progress;
11815
- uniform vec2 resolution;
11816
- varying vec2 vUv;
11817
- ${GLSL_COMMON}
11818
-
11819
- vec2 aspectGrid(float rows) {
11820
- float aspect = resolution.x / max(resolution.y, 1.0);
11821
- return vec2(max(8.0, floor(rows * aspect)), rows);
11822
- }
11823
-
11824
- vec2 gridCellId() {
11825
- return floor(vUv * aspectGrid(16.0));
11826
- }
11827
-
11828
- vec2 gridCellUv() {
11829
- vec2 cells = aspectGrid(16.0);
11830
- return (floor(vUv * cells) + 0.5) / cells;
11831
- }
11832
-
11833
- float gridWipeAlpha(float spatialOrder, float t) {
11834
- vec2 cells = aspectGrid(16.0);
11835
- vec2 id = floor(vUv * cells);
11836
- vec2 local = fract(vUv * cells);
11837
- float order = mix(clamp(spatialOrder, 0.0, 1.0), hash(id), 0.12);
11838
- float disappear = smoothstep(order, order + 0.16, t);
11839
- float sc = mix(1.0, 0.18, disappear);
11840
- vec2 scaled = 0.5 + (local - 0.5) / max(sc, 0.001);
11841
- float inside = step(0.0, scaled.x) * step(scaled.x, 1.0) * step(0.0, scaled.y) * step(scaled.y, 1.0);
11842
- return inside * (1.0 - disappear);
11843
- }
11844
-
11845
- float hexRound(float x) {
11846
- return floor(x + 0.5);
11847
- }
11848
-
11849
- vec2 hexCellId(vec2 uv) {
11850
- float aspect = resolution.x / max(resolution.y, 1.0);
11851
- vec2 p = (uv - 0.5) * vec2(aspect, 1.0) * 12.0;
11852
- float q = 1.1547005 * p.x;
11853
- float r = -0.5773503 * p.x + p.y;
11854
- vec3 cube = vec3(q, -q - r, r);
11855
- vec3 rounded = vec3(hexRound(cube.x), hexRound(cube.y), hexRound(cube.z));
11856
- vec3 diff = abs(rounded - cube);
11857
- if (diff.x > diff.y && diff.x > diff.z) {
11858
- rounded.x = -rounded.y - rounded.z;
11859
- } else if (diff.y > diff.z) {
11860
- rounded.y = -rounded.x - rounded.z;
11861
- }
11862
- return rounded.xz;
11791
+ return rounded.xz;
11863
11792
  }
11864
11793
  `;
11865
11794
  var FOOTER = `
@@ -12061,23 +11990,250 @@ var SNAPSHOT_FRAGMENT_SHADERS = {
12061
11990
  `)
12062
11991
  };
12063
11992
  function createSnapshotMaterial(preset, texture) {
12064
- return new import_three19.ShaderMaterial({
11993
+ return new import_three18.ShaderMaterial({
12065
11994
  transparent: true,
12066
11995
  depthTest: false,
12067
11996
  depthWrite: false,
12068
- side: import_three19.DoubleSide,
11997
+ side: import_three18.DoubleSide,
12069
11998
  uniforms: {
12070
11999
  map: { value: texture },
12071
12000
  progress: { value: 0 },
12072
- resolution: { value: new import_three19.Vector2(1, 1) }
12001
+ resolution: { value: new import_three18.Vector2(1, 1) }
12073
12002
  },
12074
12003
  vertexShader: SNAPSHOT_VERTEX_SHADER,
12075
12004
  fragmentShader: SNAPSHOT_FRAGMENT_SHADERS[preset]
12076
12005
  });
12077
12006
  }
12078
12007
 
12079
- // src/scene-transitions/snapshot-overlay.tsx
12008
+ // src/scene-transitions/snapshot-hold.tsx
12009
+ var import_jsx_runtime19 = require("react/jsx-runtime");
12010
+ function SnapshotHold({ snapshot }) {
12011
+ const { camera, gl } = (0, import_fiber19.useThree)();
12012
+ const meshRef = (0, import_react43.useRef)(null);
12013
+ const directionRef = (0, import_react43.useRef)(new import_three19.Vector3());
12014
+ const material = (0, import_react43.useMemo)(
12015
+ () => createSnapshotMaterial("crossfade", snapshot.texture),
12016
+ [snapshot.texture]
12017
+ );
12018
+ (0, import_react43.useEffect)(() => () => material.dispose(), [material]);
12019
+ (0, import_fiber19.useFrame)(() => {
12020
+ const mesh = meshRef.current;
12021
+ if (!mesh || !isPerspectiveCamera(camera)) {
12022
+ return;
12023
+ }
12024
+ placeFullscreenOverlay(mesh, camera, directionRef.current);
12025
+ const context = gl.getContext();
12026
+ material.uniforms.resolution.value.set(
12027
+ context.drawingBufferWidth,
12028
+ context.drawingBufferHeight
12029
+ );
12030
+ material.uniforms.progress.value = 0;
12031
+ });
12032
+ return /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("mesh", { frustumCulled: false, ref: meshRef, renderOrder: OVERLAY_RENDER_ORDER, children: [
12033
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("primitive", { attach: "geometry", object: FULLSCREEN_PLANE }),
12034
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("primitive", { attach: "material", object: material })
12035
+ ] });
12036
+ }
12037
+
12038
+ // src/scene-transition-policy.ts
12039
+ function pendingSceneUsesBaseLayer(phase, isPending) {
12040
+ return isPending && (phase === "preloading" || phase === "capturing");
12041
+ }
12042
+ function normalizeTransitionWaitMs(value) {
12043
+ if (typeof value !== "number" || !Number.isFinite(value) || value <= 0) {
12044
+ return 0;
12045
+ }
12046
+ return value;
12047
+ }
12048
+ function planDetailHold(input) {
12049
+ if (input.waitMs <= 0) {
12050
+ return null;
12051
+ }
12052
+ return {
12053
+ generation: input.generation,
12054
+ sceneId: input.sceneId,
12055
+ deadline: input.now + input.waitMs
12056
+ };
12057
+ }
12058
+ function acceptDetailWait(wait, signal) {
12059
+ if (!wait) {
12060
+ return { wait: null, start: false };
12061
+ }
12062
+ switch (signal.kind) {
12063
+ case "ready":
12064
+ if (signal.generation !== wait.generation || signal.sceneId !== wait.sceneId) {
12065
+ return { wait, start: false };
12066
+ }
12067
+ return { wait: null, start: true };
12068
+ case "timeout":
12069
+ if (signal.generation !== wait.generation || signal.now < wait.deadline) {
12070
+ return { wait, start: false };
12071
+ }
12072
+ return { wait: null, start: true };
12073
+ case "cancel":
12074
+ if (signal.generation !== wait.generation) {
12075
+ return { wait, start: false };
12076
+ }
12077
+ return { wait: null, start: false };
12078
+ default: {
12079
+ const exhaustive = signal;
12080
+ return exhaustive;
12081
+ }
12082
+ }
12083
+ }
12084
+ function phaseAfterSnapshot(preset, hold) {
12085
+ if (hold) {
12086
+ return "awaitingDetail";
12087
+ }
12088
+ if (preset === "none") {
12089
+ return "idle";
12090
+ }
12091
+ return "transitioning";
12092
+ }
12093
+
12094
+ // src/scene-transitions/particle-overlay.tsx
12095
+ var import_fiber20 = require("@react-three/fiber");
12096
+ var import_react44 = require("react");
12097
+ var import_three20 = require("three");
12080
12098
  var import_jsx_runtime20 = require("react/jsx-runtime");
12099
+ var PARTICLE_GRID = 48;
12100
+ var PARTICLE_COUNT = PARTICLE_GRID * PARTICLE_GRID;
12101
+ var PARTICLE_VERTEX_SHADER = `
12102
+ attribute float instanceIndex;
12103
+ uniform float progress;
12104
+ uniform vec2 grid;
12105
+ varying vec2 vUv;
12106
+ varying float vAlpha;
12107
+ ${GLSL_COMMON}
12108
+
12109
+ void main() {
12110
+ float id = instanceIndex;
12111
+ float gx = mod(id, grid.x);
12112
+ float gy = floor(id / grid.x);
12113
+ vec2 cell = vec2(gx, gy);
12114
+ float h = hash(cell);
12115
+ float h2 = hash(cell + 19.2);
12116
+ float h3 = hash(cell + 7.7);
12117
+ vec2 randomDir = normalize(vec2(h, h2) * 2.0 - 1.0 + 1e-5);
12118
+ vec2 fromCenter = (cell + 0.5) / grid - 0.5 + 1e-5;
12119
+ vec2 dir = normalize(mix(randomDir, normalize(fromCenter), 0.65));
12120
+ float delay = h3 * 0.28;
12121
+ float lt = clamp((progress - delay) / max(1.0 - delay, 0.001), 0.0, 1.0);
12122
+ float explode = lt * lt;
12123
+ float scale = mix(1.0, 0.18, explode);
12124
+ float angle = (h * 2.0 - 1.0) * explode * 4.2;
12125
+ float ca = cos(angle);
12126
+ float sa = sin(angle);
12127
+ vec2 cellSize = 1.0 / grid;
12128
+ vec2 local = position.xy * cellSize * scale;
12129
+ vec2 rotated = vec2(local.x * ca - local.y * sa, local.x * sa + local.y * ca);
12130
+ vec2 planeCenter = (cell + 0.5) / grid - 0.5;
12131
+ vec2 exploded = planeCenter + dir * explode * 0.9;
12132
+ vec3 pos = vec3(exploded + rotated, -explode * 0.14);
12133
+ vUv = (cell + uv) / grid;
12134
+ vAlpha = 1.0 - explode;
12135
+ gl_Position = projectionMatrix * modelViewMatrix * vec4(pos, 1.0);
12136
+ }
12137
+ `;
12138
+ var PARTICLE_FRAGMENT_SHADER = `
12139
+ uniform sampler2D map;
12140
+ varying vec2 vUv;
12141
+ varying float vAlpha;
12142
+
12143
+ void main() {
12144
+ vec4 old = texture2D(map, vUv);
12145
+ old.rgb *= 1.0 + 0.22 * (1.0 - vAlpha);
12146
+ gl_FragColor = vec4(old.rgb, old.a * vAlpha);
12147
+ #include <colorspace_fragment>
12148
+ }
12149
+ `;
12150
+ function createParticleGeometry() {
12151
+ const quad = new import_three20.PlaneGeometry(1, 1);
12152
+ const geometry = new import_three20.InstancedBufferGeometry();
12153
+ if (quad.index) {
12154
+ geometry.setIndex(quad.index.clone());
12155
+ }
12156
+ geometry.setAttribute("position", quad.attributes.position.clone());
12157
+ geometry.setAttribute("uv", quad.attributes.uv.clone());
12158
+ const indexes = new Float32Array(PARTICLE_COUNT);
12159
+ for (let i = 0; i < PARTICLE_COUNT; i += 1) {
12160
+ indexes[i] = i;
12161
+ }
12162
+ geometry.setAttribute("instanceIndex", new import_three20.InstancedBufferAttribute(indexes, 1));
12163
+ geometry.instanceCount = PARTICLE_COUNT;
12164
+ quad.dispose();
12165
+ return geometry;
12166
+ }
12167
+ function ParticleOverlay({
12168
+ snapshot,
12169
+ transition,
12170
+ running,
12171
+ runId,
12172
+ onFinish
12173
+ }) {
12174
+ const { camera } = (0, import_fiber20.useThree)();
12175
+ const meshRef = (0, import_react44.useRef)(null);
12176
+ const startRef = (0, import_react44.useRef)(null);
12177
+ const finishedRef = (0, import_react44.useRef)(false);
12178
+ const directionRef = (0, import_react44.useRef)(new import_three20.Vector3());
12179
+ const geometry = (0, import_react44.useMemo)(() => createParticleGeometry(), []);
12180
+ const material = (0, import_react44.useMemo)(
12181
+ () => new import_three20.ShaderMaterial({
12182
+ transparent: true,
12183
+ depthTest: false,
12184
+ depthWrite: false,
12185
+ side: import_three20.DoubleSide,
12186
+ uniforms: {
12187
+ map: { value: snapshot.texture },
12188
+ progress: { value: 0 },
12189
+ grid: { value: new import_three20.Vector2(PARTICLE_GRID, PARTICLE_GRID) }
12190
+ },
12191
+ vertexShader: PARTICLE_VERTEX_SHADER,
12192
+ fragmentShader: PARTICLE_FRAGMENT_SHADER
12193
+ }),
12194
+ [snapshot.texture]
12195
+ );
12196
+ (0, import_react44.useEffect)(() => () => geometry.dispose(), [geometry]);
12197
+ (0, import_react44.useEffect)(() => () => material.dispose(), [material]);
12198
+ (0, import_react44.useEffect)(() => {
12199
+ startRef.current = null;
12200
+ finishedRef.current = false;
12201
+ material.uniforms.progress.value = 0;
12202
+ }, [material, runId]);
12203
+ (0, import_fiber20.useFrame)((state) => {
12204
+ const mesh = meshRef.current;
12205
+ if (!mesh || !isPerspectiveCamera(camera)) {
12206
+ return;
12207
+ }
12208
+ placeFullscreenOverlay(mesh, camera, directionRef.current);
12209
+ if (!running || finishedRef.current) {
12210
+ return;
12211
+ }
12212
+ const next = overlayProgress(state.clock.elapsedTime, transition.duration, startRef.current);
12213
+ startRef.current = next.startTime;
12214
+ material.uniforms.progress.value = next.progress;
12215
+ if (next.progress === 1) {
12216
+ finishedRef.current = true;
12217
+ onFinish();
12218
+ }
12219
+ });
12220
+ return /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
12221
+ "mesh",
12222
+ {
12223
+ ref: meshRef,
12224
+ frustumCulled: false,
12225
+ geometry,
12226
+ material,
12227
+ renderOrder: OVERLAY_RENDER_ORDER
12228
+ }
12229
+ );
12230
+ }
12231
+
12232
+ // src/scene-transitions/snapshot-overlay.tsx
12233
+ var import_fiber21 = require("@react-three/fiber");
12234
+ var import_react45 = require("react");
12235
+ var import_three21 = require("three");
12236
+ var import_jsx_runtime21 = require("react/jsx-runtime");
12081
12237
  function SnapshotOverlay({
12082
12238
  snapshot,
12083
12239
  transition,
@@ -12085,26 +12241,26 @@ function SnapshotOverlay({
12085
12241
  runId,
12086
12242
  onFinish
12087
12243
  }) {
12088
- const { camera, gl } = (0, import_fiber20.useThree)();
12089
- const meshRef = (0, import_react43.useRef)(null);
12090
- const startRef = (0, import_react43.useRef)(null);
12091
- const finishedRef = (0, import_react43.useRef)(false);
12092
- const directionRef = (0, import_react43.useRef)(new import_three20.Vector3());
12093
- const material = (0, import_react43.useMemo)(() => {
12244
+ const { camera, gl } = (0, import_fiber21.useThree)();
12245
+ const meshRef = (0, import_react45.useRef)(null);
12246
+ const startRef = (0, import_react45.useRef)(null);
12247
+ const finishedRef = (0, import_react45.useRef)(false);
12248
+ const directionRef = (0, import_react45.useRef)(new import_three21.Vector3());
12249
+ const material = (0, import_react45.useMemo)(() => {
12094
12250
  if (!isSnapshotTransition(transition.preset)) {
12095
12251
  return null;
12096
12252
  }
12097
12253
  return createSnapshotMaterial(transition.preset, snapshot.texture);
12098
12254
  }, [snapshot.texture, transition.preset]);
12099
- (0, import_react43.useEffect)(() => () => material?.dispose(), [material]);
12100
- (0, import_react43.useEffect)(() => {
12255
+ (0, import_react45.useEffect)(() => () => material?.dispose(), [material]);
12256
+ (0, import_react45.useEffect)(() => {
12101
12257
  startRef.current = null;
12102
12258
  finishedRef.current = false;
12103
12259
  if (material) {
12104
12260
  material.uniforms.progress.value = 0;
12105
12261
  }
12106
12262
  }, [material, runId]);
12107
- (0, import_fiber20.useFrame)((state) => {
12263
+ (0, import_fiber21.useFrame)((state) => {
12108
12264
  const mesh = meshRef.current;
12109
12265
  if (!mesh || !material || !isPerspectiveCamera(camera)) {
12110
12266
  return;
@@ -12126,21 +12282,21 @@ function SnapshotOverlay({
12126
12282
  if (!material) {
12127
12283
  return null;
12128
12284
  }
12129
- return /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("mesh", { ref: meshRef, renderOrder: OVERLAY_RENDER_ORDER, frustumCulled: false, children: [
12130
- /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("primitive", { attach: "geometry", object: FULLSCREEN_PLANE }),
12131
- /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("primitive", { attach: "material", object: material })
12285
+ return /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("mesh", { ref: meshRef, renderOrder: OVERLAY_RENDER_ORDER, frustumCulled: false, children: [
12286
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("primitive", { attach: "geometry", object: FULLSCREEN_PLANE }),
12287
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("primitive", { attach: "material", object: material })
12132
12288
  ] });
12133
12289
  }
12134
12290
 
12135
12291
  // src/scene-transitions/transition-overlay.tsx
12136
- var import_jsx_runtime21 = require("react/jsx-runtime");
12292
+ var import_jsx_runtime22 = require("react/jsx-runtime");
12137
12293
  function TransitionOverlay(props) {
12138
12294
  const { preset } = props.transition;
12139
12295
  switch (preset) {
12140
12296
  case "none":
12141
12297
  return null;
12142
12298
  case "particles":
12143
- return /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(ParticleOverlay, { ...props });
12299
+ return /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(ParticleOverlay, { ...props });
12144
12300
  case "crossfade":
12145
12301
  case "zoom":
12146
12302
  case "blackout":
@@ -12168,7 +12324,7 @@ function TransitionOverlay(props) {
12168
12324
  case "zoomBlur":
12169
12325
  case "hexDissolve":
12170
12326
  case "filmBurn":
12171
- return /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(SnapshotOverlay, { ...props });
12327
+ return /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(SnapshotOverlay, { ...props });
12172
12328
  default: {
12173
12329
  const exhaustive = preset;
12174
12330
  void exhaustive;
@@ -12178,12 +12334,12 @@ function TransitionOverlay(props) {
12178
12334
  }
12179
12335
 
12180
12336
  // src/tile/tile.tsx
12181
- var import_fiber21 = require("@react-three/fiber");
12182
- var import_react44 = require("react");
12183
- var import_three22 = require("three");
12337
+ var import_fiber22 = require("@react-three/fiber");
12338
+ var import_react46 = require("react");
12339
+ var import_three23 = require("three");
12184
12340
 
12185
12341
  // src/tile/face-layout.ts
12186
- var import_three21 = require("three");
12342
+ var import_three22 = require("three");
12187
12343
  var CUBE_FACES = ["f", "r", "b", "l", "u", "d"];
12188
12344
  var PREVIEW_FACE_ORDER = ["l", "f", "r", "b", "u", "d"];
12189
12345
  var CUBE_RADIUS = DEFAULT_PANORAMA_RADIUS;
@@ -12234,8 +12390,8 @@ function getFaceQuaternion(face) {
12234
12390
  return cached;
12235
12391
  }
12236
12392
  const transform = getFaceTransform(face);
12237
- const quaternion = new import_three21.Quaternion().setFromEuler(
12238
- new import_three21.Euler(...transform.rotation, "XYZ")
12393
+ const quaternion = new import_three22.Quaternion().setFromEuler(
12394
+ new import_three22.Euler(...transform.rotation, "XYZ")
12239
12395
  );
12240
12396
  faceQuaternionCache.set(face, quaternion);
12241
12397
  return quaternion;
@@ -12246,17 +12402,17 @@ function getTileBoundingBox(address, radius = CUBE_RADIUS) {
12246
12402
  const halfWidth = local.width / 2;
12247
12403
  const halfHeight = local.height / 2;
12248
12404
  const quaternion = getFaceQuaternion(address.face);
12249
- const position = new import_three21.Vector3(...transform.position);
12405
+ const position = new import_three22.Vector3(...transform.position);
12250
12406
  const corners = [
12251
- new import_three21.Vector3(local.x - halfWidth, local.y - halfHeight, 0),
12252
- new import_three21.Vector3(local.x + halfWidth, local.y - halfHeight, 0),
12253
- new import_three21.Vector3(local.x - halfWidth, local.y + halfHeight, 0),
12254
- new import_three21.Vector3(local.x + halfWidth, local.y + halfHeight, 0)
12407
+ new import_three22.Vector3(local.x - halfWidth, local.y - halfHeight, 0),
12408
+ new import_three22.Vector3(local.x + halfWidth, local.y - halfHeight, 0),
12409
+ new import_three22.Vector3(local.x - halfWidth, local.y + halfHeight, 0),
12410
+ new import_three22.Vector3(local.x + halfWidth, local.y + halfHeight, 0)
12255
12411
  ];
12256
12412
  for (const corner of corners) {
12257
12413
  corner.applyQuaternion(quaternion).add(position);
12258
12414
  }
12259
- return new import_three21.Box3().setFromPoints(corners);
12415
+ return new import_three22.Box3().setFromPoints(corners);
12260
12416
  }
12261
12417
  function makeTileAddress(face, level, faceSize, tileSize, col, row) {
12262
12418
  const left = (col - 1) * tileSize;
@@ -12359,21 +12515,37 @@ function resolveTemplateUrl(template, address) {
12359
12515
  }
12360
12516
 
12361
12517
  // src/tile/tile.tsx
12362
- var import_jsx_runtime22 = require("react/jsx-runtime");
12518
+ var import_jsx_runtime23 = require("react/jsx-runtime");
12363
12519
  var MAX_LOD_UPDATE_INTERVAL_MS = 100;
12364
12520
  var FAST_ROTATION_THRESHOLD_RADIANS = Math.PI / 180;
12365
12521
  var FAST_FOV_THRESHOLD_DEGREES = 0.5;
12366
12522
  var VIEW_CHANGE_EPSILON = 1e-4;
12523
+ function decideTileLodUpdate(input) {
12524
+ if (input.loadMode === "preview") {
12525
+ return false;
12526
+ }
12527
+ const loadModeChanged = input.loadMode !== input.trackedLoadMode;
12528
+ const viewChanged = input.visibilityDirty || loadModeChanged || input.viewportChanged || input.rotationDelta > VIEW_CHANGE_EPSILON || input.fovDelta > VIEW_CHANGE_EPSILON;
12529
+ if (!viewChanged) {
12530
+ return false;
12531
+ }
12532
+ const movingQuickly = input.rotationDelta >= FAST_ROTATION_THRESHOLD_RADIANS || input.fovDelta >= FAST_FOV_THRESHOLD_DEGREES;
12533
+ const immediate = input.visibilityDirty || loadModeChanged || input.viewportChanged || movingQuickly;
12534
+ if (!immediate && input.now - input.lastUpdateAt < MAX_LOD_UPDATE_INTERVAL_MS) {
12535
+ return false;
12536
+ }
12537
+ return true;
12538
+ }
12367
12539
  var VISIBILITY_FOV_PADDING_DEGREES = 8;
12368
12540
  var PREVIEW_RADIUS = CUBE_RADIUS + 0.05;
12369
- var SHARED_TILE_GEOMETRY = new import_three22.PlaneGeometry(1, 1);
12541
+ var SHARED_TILE_GEOMETRY = new import_three23.PlaneGeometry(1, 1);
12370
12542
  function PreviewFace({
12371
12543
  face,
12372
12544
  texture,
12373
12545
  faceOrder
12374
12546
  }) {
12375
- const geometry = (0, import_react44.useMemo)(() => {
12376
- const nextGeometry = new import_three22.PlaneGeometry(
12547
+ const geometry = (0, import_react46.useMemo)(() => {
12548
+ const nextGeometry = new import_three23.PlaneGeometry(
12377
12549
  PREVIEW_RADIUS * 2,
12378
12550
  PREVIEW_RADIUS * 2
12379
12551
  );
@@ -12387,21 +12559,21 @@ function PreviewFace({
12387
12559
  uv.needsUpdate = true;
12388
12560
  return nextGeometry;
12389
12561
  }, [face, faceOrder]);
12390
- (0, import_react44.useEffect)(
12562
+ (0, import_react46.useEffect)(
12391
12563
  () => () => {
12392
12564
  geometry.dispose();
12393
12565
  },
12394
12566
  [geometry]
12395
12567
  );
12396
12568
  const transform = getFaceTransform(face, PREVIEW_RADIUS);
12397
- return /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
12569
+ return /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
12398
12570
  "mesh",
12399
12571
  {
12400
12572
  geometry,
12401
12573
  position: transform.position,
12402
12574
  renderOrder: -100,
12403
12575
  rotation: transform.rotation,
12404
- children: /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
12576
+ children: /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
12405
12577
  PanoBasicMaterial,
12406
12578
  {
12407
12579
  depthTest: false,
@@ -12417,7 +12589,7 @@ function PreviewCube({
12417
12589
  texture,
12418
12590
  faceOrder
12419
12591
  }) {
12420
- return CUBE_FACES.map((face) => /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
12592
+ return CUBE_FACES.map((face) => /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
12421
12593
  PreviewFace,
12422
12594
  {
12423
12595
  face,
@@ -12427,7 +12599,7 @@ function PreviewCube({
12427
12599
  face
12428
12600
  ));
12429
12601
  }
12430
- var TileMesh = (0, import_react44.memo)(function TileMesh2({
12602
+ var TileMesh = (0, import_react46.memo)(function TileMesh2({
12431
12603
  address,
12432
12604
  manager,
12433
12605
  renderOrder,
@@ -12441,14 +12613,14 @@ var TileMesh = (0, import_react44.memo)(function TileMesh2({
12441
12613
  if (!snapshot.texture) {
12442
12614
  return null;
12443
12615
  }
12444
- return /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("group", { position: transform.position, rotation: transform.rotation, children: /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
12616
+ return /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("group", { position: transform.position, rotation: transform.rotation, children: /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
12445
12617
  "mesh",
12446
12618
  {
12447
12619
  geometry: SHARED_TILE_GEOMETRY,
12448
12620
  position: [layout.x, layout.y, 0],
12449
12621
  renderOrder,
12450
12622
  scale: [layout.width, layout.height, 1],
12451
- children: /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
12623
+ children: /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
12452
12624
  PanoBasicMaterial,
12453
12625
  {
12454
12626
  depthTest: false,
@@ -12460,12 +12632,12 @@ var TileMesh = (0, import_react44.memo)(function TileMesh2({
12460
12632
  }
12461
12633
  ) });
12462
12634
  });
12463
- var TileLayerMeshes = (0, import_react44.memo)(function TileLayerMeshes2({
12635
+ var TileLayerMeshes = (0, import_react46.memo)(function TileLayerMeshes2({
12464
12636
  layer,
12465
12637
  manager,
12466
12638
  resolveUrl
12467
12639
  }) {
12468
- return layer.addresses.map((address) => /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
12640
+ return layer.addresses.map((address) => /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
12469
12641
  TileMesh,
12470
12642
  {
12471
12643
  address,
@@ -12565,8 +12737,8 @@ function parentAddresses(child, parentLevel, parentFaceSize, tileSize) {
12565
12737
  return addresses;
12566
12738
  }
12567
12739
  function centerFacingAddress(candidates, camera) {
12568
- const direction = camera.getWorldDirection(new import_three22.Vector3());
12569
- const center = new import_three22.Vector3();
12740
+ const direction = camera.getWorldDirection(new import_three23.Vector3());
12741
+ const center = new import_three23.Vector3();
12570
12742
  let bestCandidate = candidates[0];
12571
12743
  let bestAlignment = -Infinity;
12572
12744
  for (const candidate of candidates) {
@@ -12631,11 +12803,11 @@ function Tile({
12631
12803
  onTileError,
12632
12804
  onLevelChange
12633
12805
  }) {
12634
- const { camera, gl, size } = (0, import_fiber21.useThree)();
12635
- const multiresConfig = (0, import_react44.useMemo)(() => parseMultires(multires), [multires]);
12806
+ const { camera, gl, size } = (0, import_fiber22.useThree)();
12807
+ const multiresConfig = (0, import_react46.useMemo)(() => parseMultires(multires), [multires]);
12636
12808
  const { levels, tileSize } = multiresConfig;
12637
12809
  const multiresToken = `${tileSize}:${levels.join(",")}`;
12638
- const candidatesByLevel = (0, import_react44.useMemo)(
12810
+ const candidatesByLevel = (0, import_react46.useMemo)(
12639
12811
  () => buildTileCandidates(levels, tileSize),
12640
12812
  [levels, tileSize]
12641
12813
  );
@@ -12647,13 +12819,13 @@ function Tile({
12647
12819
  onPreviewError
12648
12820
  );
12649
12821
  const sharedManager = useSharedTileTextureManager();
12650
- const progressRef = (0, import_react44.useRef)(onLoadProgress);
12651
- const errorRef = (0, import_react44.useRef)(onTileError);
12652
- const levelChangeRef = (0, import_react44.useRef)(onLevelChange);
12822
+ const progressRef = (0, import_react46.useRef)(onLoadProgress);
12823
+ const errorRef = (0, import_react46.useRef)(onTileError);
12824
+ const levelChangeRef = (0, import_react46.useRef)(onLevelChange);
12653
12825
  progressRef.current = onLoadProgress;
12654
12826
  errorRef.current = onTileError;
12655
12827
  levelChangeRef.current = onLevelChange;
12656
- const ownedManager = (0, import_react44.useMemo)(
12828
+ const ownedManager = (0, import_react46.useMemo)(
12657
12829
  () => new TileTextureManager({
12658
12830
  anisotropy,
12659
12831
  maxBytes: Math.max(1, maxTextureMemoryMb) * 1024 * 1024,
@@ -12674,7 +12846,7 @@ function Tile({
12674
12846
  ]
12675
12847
  );
12676
12848
  const manager = sharedManager ?? ownedManager;
12677
- (0, import_react44.useEffect)(() => {
12849
+ (0, import_react46.useEffect)(() => {
12678
12850
  manager.resume();
12679
12851
  return () => {
12680
12852
  if (manager === ownedManager) {
@@ -12684,11 +12856,11 @@ function Tile({
12684
12856
  queueMicrotask(() => manager.releaseUnused());
12685
12857
  };
12686
12858
  }, [manager, ownedManager]);
12687
- const readyRef = (0, import_react44.useRef)(false);
12688
- (0, import_react44.useEffect)(() => {
12859
+ const readyRef = (0, import_react46.useRef)(false);
12860
+ (0, import_react46.useEffect)(() => {
12689
12861
  readyRef.current = false;
12690
12862
  }, [effectivePreviewUrl]);
12691
- (0, import_react44.useEffect)(() => {
12863
+ (0, import_react46.useEffect)(() => {
12692
12864
  if (!previewTexture || readyRef.current) {
12693
12865
  return;
12694
12866
  }
@@ -12696,31 +12868,37 @@ function Tile({
12696
12868
  onReady?.();
12697
12869
  }, [onReady, previewTexture]);
12698
12870
  const template = urlTemplate ?? buildDefaultTileUrlTemplate();
12699
- const resolveUrl = (0, import_react44.useMemo)(
12871
+ const resolveUrl = (0, import_react46.useMemo)(
12700
12872
  () => (address) => {
12701
12873
  const relativePath = resolveTileUrl ? resolveTileUrl(address) : resolveTemplateUrl(template, address);
12702
12874
  return resolveRelativeTileUrl(baseUrl, relativePath);
12703
12875
  },
12704
12876
  [baseUrl, resolveTileUrl, template]
12705
12877
  );
12706
- const [layers, setLayers] = (0, import_react44.useState)([]);
12707
- const layerTokenRef = (0, import_react44.useRef)("");
12708
- const currentLevelRef = (0, import_react44.useRef)(1);
12709
- const lastUpdateAtRef = (0, import_react44.useRef)(-Infinity);
12710
- const visibilityDirtyRef = (0, import_react44.useRef)(true);
12711
- const lastVisibilityQuaternionRef = (0, import_react44.useRef)(camera.quaternion.clone());
12712
- const lastVisibilityFovRef = (0, import_react44.useRef)(Number.NaN);
12713
- const lastViewportRef = (0, import_react44.useRef)({ width: 0, height: 0, dpr: 0 });
12714
- const frustumRef = (0, import_react44.useRef)(new import_three22.Frustum());
12715
- const projectionMatrixRef = (0, import_react44.useRef)(new import_three22.Matrix4());
12716
- const visibilityCameraRef = (0, import_react44.useRef)(new import_three22.PerspectiveCamera());
12717
- (0, import_react44.useEffect)(() => {
12878
+ const [layers, setLayers] = (0, import_react46.useState)([]);
12879
+ const layerTokenRef = (0, import_react46.useRef)("");
12880
+ const currentLevelRef = (0, import_react46.useRef)(1);
12881
+ const lastUpdateAtRef = (0, import_react46.useRef)(-Infinity);
12882
+ const visibilityDirtyRef = (0, import_react46.useRef)(true);
12883
+ const lastVisibilityQuaternionRef = (0, import_react46.useRef)(camera.quaternion.clone());
12884
+ const lastVisibilityFovRef = (0, import_react46.useRef)(Number.NaN);
12885
+ const lastViewportRef = (0, import_react46.useRef)({ width: 0, height: 0, dpr: 0 });
12886
+ const frustumRef = (0, import_react46.useRef)(new import_three23.Frustum());
12887
+ const projectionMatrixRef = (0, import_react46.useRef)(new import_three23.Matrix4());
12888
+ const visibilityCameraRef = (0, import_react46.useRef)(new import_three23.PerspectiveCamera());
12889
+ const trackedLoadModeRef = (0, import_react46.useRef)(loadMode);
12890
+ const targetKeysRef = (0, import_react46.useRef)([]);
12891
+ const detailTokenRef = (0, import_react46.useRef)("");
12892
+ const detailReporter = useSceneDetailReporter();
12893
+ const detailReporterRef = (0, import_react46.useRef)(detailReporter);
12894
+ detailReporterRef.current = detailReporter;
12895
+ (0, import_react46.useEffect)(() => {
12718
12896
  currentLevelRef.current = 1;
12719
12897
  layerTokenRef.current = "";
12720
12898
  visibilityDirtyRef.current = true;
12721
12899
  setLayers([]);
12722
12900
  }, [manager, multiresToken]);
12723
- (0, import_react44.useEffect)(() => {
12901
+ (0, import_react46.useEffect)(() => {
12724
12902
  if (loadMode !== "preview") {
12725
12903
  return;
12726
12904
  }
@@ -12734,11 +12912,14 @@ function Tile({
12734
12912
  setLayers(nextLayers);
12735
12913
  }
12736
12914
  };
12737
- (0, import_fiber21.useFrame)(() => {
12738
- if (loadMode === "preview") {
12915
+ (0, import_fiber22.useFrame)(() => {
12916
+ if (!(camera instanceof import_three23.PerspectiveCamera)) {
12739
12917
  return;
12740
12918
  }
12741
- if (!(camera instanceof import_three22.PerspectiveCamera)) {
12919
+ if (loadMode === "preview") {
12920
+ trackedLoadModeRef.current = "preview";
12921
+ targetKeysRef.current = [];
12922
+ publishSceneDetail(detailReporterRef.current, detailTokenRef, false);
12742
12923
  return;
12743
12924
  }
12744
12925
  const now = performance.now();
@@ -12749,60 +12930,75 @@ function Tile({
12749
12930
  const fovDelta = Number.isFinite(lastVisibilityFovRef.current) ? Math.abs(camera.fov - lastVisibilityFovRef.current) : Infinity;
12750
12931
  const lastViewport = lastViewportRef.current;
12751
12932
  const viewportChanged = lastViewport.width !== size.width || lastViewport.height !== size.height || lastViewport.dpr !== pixelRatio;
12752
- const viewChanged = visibilityDirtyRef.current || viewportChanged || rotationDelta > VIEW_CHANGE_EPSILON || fovDelta > VIEW_CHANGE_EPSILON;
12753
- const movingQuickly = rotationDelta >= FAST_ROTATION_THRESHOLD_RADIANS || fovDelta >= FAST_FOV_THRESHOLD_DEGREES;
12754
- if (!viewChanged) {
12755
- return;
12756
- }
12757
- const needsImmediateUpdate = visibilityDirtyRef.current || viewportChanged || movingQuickly;
12758
- if (!needsImmediateUpdate && now - lastUpdateAtRef.current < MAX_LOD_UPDATE_INTERVAL_MS) {
12759
- return;
12760
- }
12761
- lastUpdateAtRef.current = now;
12762
- const targetLevel = loadMode === "base" ? 1 : getPreferredLevel(
12763
- levels,
12764
- size.height,
12765
- pixelRatio,
12766
- camera.fov,
12767
- currentLevelRef.current
12768
- );
12769
- if (targetLevel !== currentLevelRef.current) {
12770
- currentLevelRef.current = targetLevel;
12771
- levelChangeRef.current?.(targetLevel);
12772
- }
12773
- const visibilityCamera = visibilityCameraRef.current;
12774
- visibilityCamera.copy(camera, false);
12775
- visibilityCamera.fov = Math.min(
12776
- 179,
12777
- camera.fov + VISIBILITY_FOV_PADDING_DEGREES
12778
- );
12779
- visibilityCamera.aspect = camera.aspect;
12780
- updateVisibilityFrustum(
12781
- visibilityCamera,
12782
- projectionMatrixRef.current,
12783
- frustumRef.current
12784
- );
12785
- const nextLayers = buildLayers(
12786
- targetLevel,
12787
- levels,
12788
- tileSize,
12789
- frustumRef.current,
12790
- camera,
12791
- candidatesByLevel
12933
+ const updateLod = decideTileLodUpdate({
12934
+ loadMode,
12935
+ trackedLoadMode: trackedLoadModeRef.current,
12936
+ now,
12937
+ lastUpdateAt: lastUpdateAtRef.current,
12938
+ visibilityDirty: visibilityDirtyRef.current,
12939
+ viewportChanged,
12940
+ rotationDelta,
12941
+ fovDelta
12942
+ });
12943
+ if (updateLod) {
12944
+ trackedLoadModeRef.current = loadMode;
12945
+ lastUpdateAtRef.current = now;
12946
+ const targetLevel = loadMode === "base" ? 1 : getPreferredLevel(
12947
+ levels,
12948
+ size.height,
12949
+ pixelRatio,
12950
+ camera.fov,
12951
+ currentLevelRef.current
12952
+ );
12953
+ if (targetLevel !== currentLevelRef.current) {
12954
+ currentLevelRef.current = targetLevel;
12955
+ levelChangeRef.current?.(targetLevel);
12956
+ }
12957
+ const visibilityCamera = visibilityCameraRef.current;
12958
+ visibilityCamera.copy(camera, false);
12959
+ visibilityCamera.fov = Math.min(
12960
+ 179,
12961
+ camera.fov + VISIBILITY_FOV_PADDING_DEGREES
12962
+ );
12963
+ visibilityCamera.aspect = camera.aspect;
12964
+ updateVisibilityFrustum(
12965
+ visibilityCamera,
12966
+ projectionMatrixRef.current,
12967
+ frustumRef.current
12968
+ );
12969
+ const nextLayers = buildLayers(
12970
+ targetLevel,
12971
+ levels,
12972
+ tileSize,
12973
+ frustumRef.current,
12974
+ camera,
12975
+ candidatesByLevel
12976
+ );
12977
+ visibilityDirtyRef.current = false;
12978
+ lastVisibilityQuaternionRef.current.copy(camera.quaternion);
12979
+ lastVisibilityFovRef.current = camera.fov;
12980
+ lastViewportRef.current = {
12981
+ width: size.width,
12982
+ height: size.height,
12983
+ dpr: pixelRatio
12984
+ };
12985
+ const targetLayer = nextLayers.find((layer) => layer.level === targetLevel);
12986
+ targetKeysRef.current = loadMode === "full" ? (targetLayer?.addresses ?? []).map(
12987
+ (address) => `${resolveUrl(address)}\0${tileKey(address)}`
12988
+ ) : [];
12989
+ commitLayers(nextLayers);
12990
+ }
12991
+ publishSceneDetail(
12992
+ detailReporterRef.current,
12993
+ detailTokenRef,
12994
+ loadMode === "full" && viewTilesAreDrawable(
12995
+ targetKeysRef.current.map((key) => manager.getSnapshot(key).texture)
12996
+ )
12792
12997
  );
12793
- visibilityDirtyRef.current = false;
12794
- lastVisibilityQuaternionRef.current.copy(camera.quaternion);
12795
- lastVisibilityFovRef.current = camera.fov;
12796
- lastViewportRef.current = {
12797
- width: size.width,
12798
- height: size.height,
12799
- dpr: pixelRatio
12800
- };
12801
- commitLayers(nextLayers);
12802
12998
  });
12803
- return /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("group", { visible, children: [
12804
- previewTexture ? /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(PreviewCube, { texture: previewTexture, faceOrder: previewFaceOrder }) : null,
12805
- layers.map((layer) => /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
12999
+ return /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("group", { visible, children: [
13000
+ previewTexture ? /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(PreviewCube, { texture: previewTexture, faceOrder: previewFaceOrder }) : null,
13001
+ layers.map((layer) => /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
12806
13002
  TileLayerMeshes,
12807
13003
  {
12808
13004
  layer,
@@ -12815,7 +13011,7 @@ function Tile({
12815
13011
  }
12816
13012
 
12817
13013
  // src/scenes.tsx
12818
- var import_jsx_runtime23 = require("react/jsx-runtime");
13014
+ var import_jsx_runtime24 = require("react/jsx-runtime");
12819
13015
  function SceneSource({
12820
13016
  scene,
12821
13017
  visible,
@@ -12828,7 +13024,7 @@ function SceneSource({
12828
13024
  }
12829
13025
  switch (scene.type) {
12830
13026
  case "sphere":
12831
- return /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
13027
+ return /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
12832
13028
  Sphere,
12833
13029
  {
12834
13030
  src: scene.src,
@@ -12841,7 +13037,7 @@ function SceneSource({
12841
13037
  );
12842
13038
  case "tile": {
12843
13039
  const { id: _id, type: _type, ...tileProps } = scene;
12844
- return /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
13040
+ return /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
12845
13041
  Tile,
12846
13042
  {
12847
13043
  ...tileProps,
@@ -12854,7 +13050,7 @@ function SceneSource({
12854
13050
  }
12855
13051
  case "sphereTile": {
12856
13052
  const { id: _id, type: _type, ...tileProps } = scene;
12857
- return /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
13053
+ return /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
12858
13054
  SphereTile,
12859
13055
  {
12860
13056
  ...tileProps,
@@ -12877,17 +13073,17 @@ function SnapshotCapture({
12877
13073
  maxPixels,
12878
13074
  onCaptured
12879
13075
  }) {
12880
- const { camera, gl, scene, size } = (0, import_fiber22.useThree)();
12881
- const capturedRequestRef = (0, import_react45.useRef)(0);
12882
- const renderTargetRef = (0, import_react45.useRef)(null);
12883
- (0, import_react45.useEffect)(
13076
+ const { camera, gl, scene, size } = (0, import_fiber23.useThree)();
13077
+ const capturedRequestRef = (0, import_react47.useRef)(0);
13078
+ const renderTargetRef = (0, import_react47.useRef)(null);
13079
+ (0, import_react47.useEffect)(
12884
13080
  () => () => {
12885
13081
  renderTargetRef.current?.dispose();
12886
13082
  renderTargetRef.current = null;
12887
13083
  },
12888
13084
  []
12889
13085
  );
12890
- (0, import_fiber22.useFrame)(() => {
13086
+ (0, import_fiber23.useFrame)(() => {
12891
13087
  if (requestId === 0 || requestId === capturedRequestRef.current) {
12892
13088
  return;
12893
13089
  }
@@ -12897,14 +13093,14 @@ function SnapshotCapture({
12897
13093
  const scale = Math.min(1, Math.sqrt(maxPixels / (sourceWidth * sourceHeight)));
12898
13094
  const width = Math.max(1, Math.floor(sourceWidth * scale));
12899
13095
  const height = Math.max(1, Math.floor(sourceHeight * scale));
12900
- const nextTarget = new import_three23.WebGLRenderTarget(width, height, {
13096
+ const nextTarget = new import_three24.WebGLRenderTarget(width, height, {
12901
13097
  depthBuffer: false,
12902
13098
  stencilBuffer: false
12903
13099
  });
12904
- nextTarget.texture.colorSpace = import_three23.LinearSRGBColorSpace;
13100
+ nextTarget.texture.colorSpace = import_three24.LinearSRGBColorSpace;
12905
13101
  nextTarget.texture.generateMipmaps = false;
12906
- nextTarget.texture.minFilter = import_three23.LinearFilter;
12907
- nextTarget.texture.magFilter = import_three23.LinearFilter;
13102
+ nextTarget.texture.minFilter = import_three24.LinearFilter;
13103
+ nextTarget.texture.magFilter = import_three24.LinearFilter;
12908
13104
  const previousTarget = gl.getRenderTarget();
12909
13105
  gl.setRenderTarget(nextTarget);
12910
13106
  gl.clear();
@@ -12935,53 +13131,90 @@ function ScenesController({
12935
13131
  onTransitionEnd,
12936
13132
  onTransitionError,
12937
13133
  snapshotMaxPixels = 3686400,
13134
+ transitionWaitForDetailMs,
12938
13135
  phaseRef: externalPhaseRef
12939
13136
  }) {
12940
- const controlsRef = (0, import_react45.useContext)(PanoramaViewContext);
13137
+ const controlsRef = (0, import_react47.useContext)(PanoramaViewContext);
12941
13138
  const manager = useSharedTileTextureManager();
12942
- const transition = (0, import_react45.useMemo)(
13139
+ const transition = (0, import_react47.useMemo)(
12943
13140
  () => resolveTransition(transitionInput),
12944
13141
  [transitionInput]
12945
13142
  );
12946
- const sceneMap = (0, import_react45.useMemo)(
13143
+ const sceneMap = (0, import_react47.useMemo)(
12947
13144
  () => new Map(scenes.map((scene) => [scene.id, scene])),
12948
13145
  [scenes]
12949
13146
  );
12950
13147
  const initialScene = sceneMap.get(activeSceneId) ?? null;
12951
- const [slots, setSlots] = (0, import_react45.useState)([
13148
+ const [slots, setSlots] = (0, import_react47.useState)([
12952
13149
  initialScene,
12953
13150
  null
12954
13151
  ]);
12955
- const [activeSlot, setActiveSlot] = (0, import_react45.useState)(0);
12956
- const [liveSlot, setLiveSlot] = (0, import_react45.useState)(0);
12957
- const [pendingSlot, setPendingSlot] = (0, import_react45.useState)(null);
12958
- const [phase, setPhase] = (0, import_react45.useState)(initialScene ? "idle" : "preloading");
12959
- const [captureRequestId, setCaptureRequestId] = (0, import_react45.useState)(0);
12960
- const [transitionRunId, setTransitionRunId] = (0, import_react45.useState)(0);
12961
- const [snapshot, setSnapshot] = (0, import_react45.useState)(null);
12962
- const [recoveryKey, setRecoveryKey] = (0, import_react45.useState)(0);
12963
- const requestedSceneIdRef = (0, import_react45.useRef)(activeSceneId);
12964
- const captureReasonRef = (0, import_react45.useRef)("start");
12965
- const interactionReleaseRef = (0, import_react45.useRef)(null);
12966
- const slotsRef = (0, import_react45.useRef)(slots);
12967
- const phaseRef = (0, import_react45.useRef)(phase);
12968
- const liveSlotRef = (0, import_react45.useRef)(liveSlot);
12969
- const transitionFromRef = (0, import_react45.useRef)(initialScene);
12970
- const readySceneRef = (0, import_react45.useRef)(null);
13152
+ const [activeSlot, setActiveSlot] = (0, import_react47.useState)(0);
13153
+ const [liveSlot, setLiveSlot] = (0, import_react47.useState)(0);
13154
+ const [pendingSlot, setPendingSlot] = (0, import_react47.useState)(null);
13155
+ const [phase, setPhase] = (0, import_react47.useState)(initialScene ? "idle" : "preloading");
13156
+ const [captureRequestId, setCaptureRequestId] = (0, import_react47.useState)(0);
13157
+ const [transitionRunId, setTransitionRunId] = (0, import_react47.useState)(0);
13158
+ const [snapshot, setSnapshot] = (0, import_react47.useState)(null);
13159
+ const [recoveryKey, setRecoveryKey] = (0, import_react47.useState)(0);
13160
+ const requestedSceneIdRef = (0, import_react47.useRef)(activeSceneId);
13161
+ const captureReasonRef = (0, import_react47.useRef)("start");
13162
+ const interactionReleaseRef = (0, import_react47.useRef)(null);
13163
+ const slotsRef = (0, import_react47.useRef)(slots);
13164
+ const phaseRef = (0, import_react47.useRef)(phase);
13165
+ const liveSlotRef = (0, import_react47.useRef)(liveSlot);
13166
+ const transitionFromRef = (0, import_react47.useRef)(initialScene);
13167
+ const readySceneRef = (0, import_react47.useRef)(null);
13168
+ const waitRef = (0, import_react47.useRef)(null);
13169
+ const waitTimerRef = (0, import_react47.useRef)(null);
13170
+ const detailGenerationRef = (0, import_react47.useRef)(0);
13171
+ const [detailGeneration, setDetailGeneration] = (0, import_react47.useState)(0);
13172
+ const mountedRef = (0, import_react47.useRef)(true);
13173
+ const waitForDetailMsRef = (0, import_react47.useRef)(0);
13174
+ waitForDetailMsRef.current = normalizeTransitionWaitMs(transitionWaitForDetailMs);
12971
13175
  slotsRef.current = slots;
12972
13176
  phaseRef.current = phase;
12973
13177
  if (externalPhaseRef) {
12974
13178
  externalPhaseRef.current = phase;
12975
13179
  }
12976
13180
  liveSlotRef.current = liveSlot;
12977
- const releaseInteraction = (0, import_react45.useCallback)(() => {
13181
+ const releaseInteraction = (0, import_react47.useCallback)(() => {
12978
13182
  interactionReleaseRef.current?.();
12979
13183
  interactionReleaseRef.current = null;
12980
13184
  }, []);
12981
- const reportError = (0, import_react45.useCallback)((sceneId, error) => {
13185
+ const reportError = (0, import_react47.useCallback)((sceneId, error) => {
12982
13186
  onTransitionError?.({ sceneId, error });
12983
13187
  }, [onTransitionError]);
12984
- const startPreload = (0, import_react45.useCallback)((scene) => {
13188
+ const clearDetailWait = (0, import_react47.useCallback)((bumpGeneration) => {
13189
+ if (waitTimerRef.current !== null) {
13190
+ clearTimeout(waitTimerRef.current);
13191
+ waitTimerRef.current = null;
13192
+ }
13193
+ const generation = waitRef.current?.generation;
13194
+ if (generation === void 0) {
13195
+ waitRef.current = null;
13196
+ } else {
13197
+ waitRef.current = acceptDetailWait(waitRef.current, {
13198
+ kind: "cancel",
13199
+ generation
13200
+ }).wait;
13201
+ }
13202
+ if (!bumpGeneration || !mountedRef.current) {
13203
+ return;
13204
+ }
13205
+ const nextGeneration = detailGenerationRef.current + 1;
13206
+ detailGenerationRef.current = nextGeneration;
13207
+ setDetailGeneration(nextGeneration);
13208
+ }, []);
13209
+ (0, import_react47.useEffect)(() => {
13210
+ mountedRef.current = true;
13211
+ return () => {
13212
+ mountedRef.current = false;
13213
+ clearDetailWait(false);
13214
+ };
13215
+ }, [clearDetailWait]);
13216
+ const startPreload = (0, import_react47.useCallback)((scene) => {
13217
+ clearDetailWait(true);
12985
13218
  const nextSlot = 1 - liveSlotRef.current;
12986
13219
  requestedSceneIdRef.current = scene.id;
12987
13220
  setSlots((current) => {
@@ -12991,8 +13224,8 @@ function ScenesController({
12991
13224
  });
12992
13225
  setPendingSlot(nextSlot);
12993
13226
  setPhase("preloading");
12994
- }, []);
12995
- (0, import_react45.useEffect)(() => {
13227
+ }, [clearDetailWait]);
13228
+ (0, import_react47.useEffect)(() => {
12996
13229
  const requested = sceneMap.get(activeSceneId);
12997
13230
  if (!requested) {
12998
13231
  reportError(activeSceneId, new Error(`Unknown panorama scene: ${activeSceneId}`));
@@ -13007,22 +13240,23 @@ function ScenesController({
13007
13240
  requestedSceneIdRef.current = requested.id;
13008
13241
  return;
13009
13242
  }
13010
- if (phaseRef.current === "transitioning" || phaseRef.current === "capturing") {
13243
+ if (phaseRef.current === "transitioning" || phaseRef.current === "capturing" || phaseRef.current === "awaitingDetail") {
13011
13244
  if (requestedSceneIdRef.current === requested.id) return;
13012
13245
  requestedSceneIdRef.current = requested.id;
13013
13246
  captureReasonRef.current = "interrupt";
13247
+ clearDetailWait(true);
13014
13248
  setPhase("recapturing");
13015
13249
  setCaptureRequestId((current) => current + 1);
13016
13250
  return;
13017
13251
  }
13018
13252
  startPreload(requested);
13019
- }, [activeSceneId, pendingSlot, reportError, sceneMap, startPreload]);
13020
- const notifySceneReady = (0, import_react45.useCallback)((scene) => {
13253
+ }, [activeSceneId, clearDetailWait, pendingSlot, reportError, sceneMap, startPreload]);
13254
+ const notifySceneReady = (0, import_react47.useCallback)((scene) => {
13021
13255
  if (!scene || readySceneRef.current === scene) return;
13022
13256
  readySceneRef.current = scene;
13023
13257
  onSceneReady?.(scene.id);
13024
13258
  }, [onSceneReady]);
13025
- const handleReady = (0, import_react45.useCallback)((slot) => {
13259
+ const handleReady = (0, import_react47.useCallback)((slot) => {
13026
13260
  if (slot === liveSlotRef.current && pendingSlot === null && phaseRef.current === "idle") {
13027
13261
  notifySceneReady(slotsRef.current[slot]);
13028
13262
  return;
@@ -13030,7 +13264,7 @@ function ScenesController({
13030
13264
  if (slot !== pendingSlot || phaseRef.current !== "preloading") {
13031
13265
  return;
13032
13266
  }
13033
- if (transition.preset === "none") {
13267
+ if (transition.preset === "none" && waitForDetailMsRef.current === 0) {
13034
13268
  const previousScene = slotsRef.current[liveSlotRef.current];
13035
13269
  const nextScene = slotsRef.current[slot];
13036
13270
  setSlots((current) => {
@@ -13058,64 +13292,167 @@ function ScenesController({
13058
13292
  setPhase("capturing");
13059
13293
  setCaptureRequestId((current) => current + 1);
13060
13294
  }, [controlsRef, notifySceneReady, onTransitionEnd, pendingSlot, transition.preset]);
13061
- const handleCaptured = (0, import_react45.useCallback)((nextSnapshot) => {
13062
- setSnapshot((current) => {
13063
- current?.dispose();
13064
- return nextSnapshot;
13065
- });
13295
+ const finishTransition = (0, import_react47.useCallback)(() => {
13296
+ const nextSlot = pendingSlot;
13297
+ const previousScene = transitionFromRef.current;
13298
+ const nextScene = nextSlot === null ? null : slotsRef.current[nextSlot];
13299
+ if (nextSlot === null || !nextScene) {
13300
+ releaseInteraction();
13301
+ setPhase("idle");
13302
+ return;
13303
+ }
13304
+ setActiveSlot(nextSlot);
13305
+ setLiveSlot(nextSlot);
13306
+ setPendingSlot(null);
13307
+ setPhase("idle");
13308
+ const oldSnapshot = snapshot;
13309
+ setSnapshot(null);
13310
+ oldSnapshot?.dispose();
13311
+ releaseInteraction();
13312
+ if (previousScene) {
13313
+ onTransitionEnd?.({
13314
+ previousSceneId: previousScene.id,
13315
+ sceneId: nextScene.id,
13316
+ preset: transition.preset
13317
+ });
13318
+ }
13319
+ }, [onTransitionEnd, pendingSlot, releaseInteraction, snapshot, transition.preset]);
13320
+ const finishTransitionRef = (0, import_react47.useRef)(finishTransition);
13321
+ finishTransitionRef.current = finishTransition;
13322
+ const transitionRef = (0, import_react47.useRef)(transition);
13323
+ transitionRef.current = transition;
13324
+ const consumeDetailSignal = (0, import_react47.useCallback)((signal) => {
13325
+ const decision = acceptDetailWait(waitRef.current, signal);
13326
+ waitRef.current = decision.wait;
13327
+ if (!decision.start) {
13328
+ return;
13329
+ }
13330
+ if (waitTimerRef.current !== null) {
13331
+ clearTimeout(waitTimerRef.current);
13332
+ waitTimerRef.current = null;
13333
+ }
13334
+ if (!mountedRef.current) {
13335
+ return;
13336
+ }
13337
+ if (transitionRef.current.preset === "none") {
13338
+ finishTransitionRef.current();
13339
+ return;
13340
+ }
13341
+ setPhase("transitioning");
13342
+ setTransitionRunId((current) => current + 1);
13343
+ }, []);
13344
+ const handleCaptured = (0, import_react47.useCallback)((nextSnapshot) => {
13066
13345
  if (captureReasonRef.current === "interrupt") {
13346
+ setSnapshot((current) => {
13347
+ current?.dispose();
13348
+ return nextSnapshot;
13349
+ });
13067
13350
  startPreload(sceneMap.get(requestedSceneIdRef.current));
13068
13351
  return;
13069
13352
  }
13070
- const sourceSlot = liveSlotRef.current;
13071
- setSlots((current) => {
13072
- const next = [...current];
13073
- next[sourceSlot] = null;
13074
- return next;
13353
+ const sourceSlot = liveSlotRef.current;
13354
+ const incoming = pendingSlot === null ? null : slotsRef.current[pendingSlot];
13355
+ setSlots((current) => {
13356
+ const next = [...current];
13357
+ next[sourceSlot] = null;
13358
+ return next;
13359
+ });
13360
+ manager?.releaseUnused();
13361
+ if (pendingSlot !== null && incoming) {
13362
+ notifySceneReady(incoming);
13363
+ setLiveSlot(pendingSlot);
13364
+ }
13365
+ if (waitTimerRef.current !== null) {
13366
+ clearTimeout(waitTimerRef.current);
13367
+ waitTimerRef.current = null;
13368
+ }
13369
+ waitRef.current = null;
13370
+ let hold = null;
13371
+ if (incoming && waitForDetailMsRef.current > 0) {
13372
+ const now = performance.now();
13373
+ const generation = detailGenerationRef.current + 1;
13374
+ detailGenerationRef.current = generation;
13375
+ hold = planDetailHold({
13376
+ waitMs: waitForDetailMsRef.current,
13377
+ now,
13378
+ generation,
13379
+ sceneId: incoming.id
13380
+ });
13381
+ if (hold) {
13382
+ const deadline = hold.deadline;
13383
+ waitRef.current = hold;
13384
+ setDetailGeneration(generation);
13385
+ waitTimerRef.current = setTimeout(() => {
13386
+ consumeDetailSignal({
13387
+ kind: "timeout",
13388
+ generation,
13389
+ now: deadline
13390
+ });
13391
+ }, Math.max(0, deadline - performance.now()));
13392
+ }
13393
+ }
13394
+ const nextPhase = phaseAfterSnapshot(transition.preset, hold);
13395
+ if (nextPhase === "awaitingDetail") {
13396
+ setSnapshot((current) => {
13397
+ current?.dispose();
13398
+ return nextSnapshot;
13399
+ });
13400
+ setPhase("awaitingDetail");
13401
+ return;
13402
+ }
13403
+ if (nextPhase === "idle") {
13404
+ nextSnapshot.dispose();
13405
+ setSnapshot((current) => {
13406
+ current?.dispose();
13407
+ return null;
13408
+ });
13409
+ if (pendingSlot !== null) {
13410
+ setActiveSlot(pendingSlot);
13411
+ }
13412
+ setPendingSlot(null);
13413
+ setPhase("idle");
13414
+ releaseInteraction();
13415
+ const previousScene = transitionFromRef.current;
13416
+ if (previousScene && incoming) {
13417
+ onTransitionEnd?.({
13418
+ previousSceneId: previousScene.id,
13419
+ sceneId: incoming.id,
13420
+ preset: "none"
13421
+ });
13422
+ }
13423
+ return;
13424
+ }
13425
+ setSnapshot((current) => {
13426
+ current?.dispose();
13427
+ return nextSnapshot;
13075
13428
  });
13076
- manager?.releaseUnused();
13077
- if (pendingSlot !== null) {
13078
- notifySceneReady(slotsRef.current[pendingSlot]);
13079
- setLiveSlot(pendingSlot);
13080
- }
13081
13429
  setPhase("transitioning");
13082
13430
  setTransitionRunId((current) => current + 1);
13083
- }, [manager, notifySceneReady, pendingSlot, sceneMap, startPreload]);
13084
- const finishTransition = (0, import_react45.useCallback)(() => {
13085
- const nextSlot = pendingSlot;
13086
- const previousScene = transitionFromRef.current;
13087
- const nextScene = nextSlot === null ? null : slotsRef.current[nextSlot];
13088
- if (nextSlot === null || !nextScene) {
13089
- releaseInteraction();
13090
- setPhase("idle");
13091
- return;
13092
- }
13093
- setActiveSlot(nextSlot);
13094
- setLiveSlot(nextSlot);
13095
- setPendingSlot(null);
13096
- setPhase("idle");
13097
- const oldSnapshot = snapshot;
13098
- setSnapshot(null);
13099
- oldSnapshot?.dispose();
13100
- releaseInteraction();
13101
- if (previousScene) {
13102
- onTransitionEnd?.({
13103
- previousSceneId: previousScene.id,
13104
- sceneId: nextScene.id,
13105
- preset: transition.preset
13106
- });
13107
- }
13108
- }, [onTransitionEnd, pendingSlot, releaseInteraction, snapshot, transition.preset]);
13109
- (0, import_react45.useEffect)(() => () => {
13431
+ }, [
13432
+ consumeDetailSignal,
13433
+ manager,
13434
+ notifySceneReady,
13435
+ onTransitionEnd,
13436
+ pendingSlot,
13437
+ releaseInteraction,
13438
+ sceneMap,
13439
+ startPreload,
13440
+ transition.preset
13441
+ ]);
13442
+ const snapshotRef = (0, import_react47.useRef)(snapshot);
13443
+ snapshotRef.current = snapshot;
13444
+ (0, import_react47.useEffect)(() => () => {
13110
13445
  releaseInteraction();
13111
- snapshot?.dispose();
13112
- }, [releaseInteraction, snapshot]);
13113
- const { gl } = (0, import_fiber22.useThree)();
13114
- (0, import_react45.useEffect)(() => {
13446
+ snapshotRef.current?.dispose();
13447
+ snapshotRef.current = null;
13448
+ }, [releaseInteraction]);
13449
+ const { gl } = (0, import_fiber23.useThree)();
13450
+ (0, import_react47.useEffect)(() => {
13115
13451
  const canvas = gl.domElement;
13116
13452
  const onContextLost = (event) => {
13117
13453
  event.preventDefault();
13118
13454
  releaseInteraction();
13455
+ clearDetailWait(true);
13119
13456
  manager?.dispose();
13120
13457
  snapshot?.dispose();
13121
13458
  setSnapshot(null);
@@ -13133,11 +13470,30 @@ function ScenesController({
13133
13470
  canvas.removeEventListener("webglcontextlost", onContextLost);
13134
13471
  canvas.removeEventListener("webglcontextrestored", onContextRestored);
13135
13472
  };
13136
- }, [gl, manager, releaseInteraction, snapshot]);
13473
+ }, [clearDetailWait, gl, manager, releaseInteraction, snapshot]);
13137
13474
  const renderedScene = slots[liveSlot];
13138
13475
  const snapshotVisible = snapshot !== null && (phase === "transitioning" || phase === "recapturing" || phase === "preloading");
13139
- return /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)(import_react45.Fragment, { children: [
13140
- /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
13476
+ const slotSceneKey = `${slots[0]?.id ?? ""}
13477
+ ${slots[1]?.id ?? ""}`;
13478
+ const detailReporters = (0, import_react47.useMemo)(() => {
13479
+ const [firstSceneId = "", secondSceneId = ""] = slotSceneKey.split("\n");
13480
+ const sceneIds = [firstSceneId, secondSceneId];
13481
+ return sceneIds.map((sceneId) => ({
13482
+ generation: detailGeneration,
13483
+ report: (ready) => {
13484
+ if (!ready || sceneId === "") {
13485
+ return;
13486
+ }
13487
+ consumeDetailSignal({
13488
+ kind: "ready",
13489
+ generation: detailGeneration,
13490
+ sceneId
13491
+ });
13492
+ }
13493
+ }));
13494
+ }, [consumeDetailSignal, detailGeneration, slotSceneKey]);
13495
+ return /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)(import_react47.Fragment, { children: [
13496
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
13141
13497
  SnapshotCapture,
13142
13498
  {
13143
13499
  requestId: captureRequestId,
@@ -13149,23 +13505,30 @@ function ScenesController({
13149
13505
  const source = slots[slot];
13150
13506
  const isLive = slot === liveSlot;
13151
13507
  const isPending = slot === pendingSlot;
13152
- return /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
13153
- SceneSource,
13508
+ return /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
13509
+ SceneDetailContext.Provider,
13154
13510
  {
13155
- scene: source,
13156
- visible: isLive,
13157
- baseOnly: isPending && phase !== "idle",
13158
- onReady: () => handleReady(slot),
13159
- onError: (error) => {
13160
- if (source) {
13161
- reportError(source.id, error);
13511
+ value: detailReporters[slot],
13512
+ children: /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
13513
+ SceneSource,
13514
+ {
13515
+ scene: source,
13516
+ visible: isLive,
13517
+ baseOnly: pendingSceneUsesBaseLayer(phase, isPending),
13518
+ onReady: () => handleReady(slot),
13519
+ onError: (error) => {
13520
+ if (source) {
13521
+ reportError(source.id, error);
13522
+ }
13523
+ }
13162
13524
  }
13163
- }
13525
+ )
13164
13526
  },
13165
13527
  `${slot}:${source?.id ?? "empty"}:${recoveryKey}`
13166
13528
  );
13167
13529
  }),
13168
- snapshotVisible ? /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
13530
+ snapshot !== null && phase === "awaitingDetail" ? /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(SnapshotHold, { snapshot }) : null,
13531
+ snapshotVisible ? /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
13169
13532
  TransitionOverlay,
13170
13533
  {
13171
13534
  snapshot,
@@ -13188,11 +13551,11 @@ function Scenes({
13188
13551
  ...rest
13189
13552
  }) {
13190
13553
  const isControlled = controlledId !== void 0;
13191
- const [internalId, setInternalId] = (0, import_react45.useState)(
13554
+ const [internalId, setInternalId] = (0, import_react47.useState)(
13192
13555
  () => controlledId ?? defaultActiveSceneId ?? scenes[0]?.id ?? ""
13193
13556
  );
13194
13557
  const resolvedId = isControlled ? controlledId : internalId;
13195
- const requestSceneChange = (0, import_react45.useCallback)(
13558
+ const requestSceneChange = (0, import_react47.useCallback)(
13196
13559
  (id) => {
13197
13560
  if (isControlled) {
13198
13561
  onActiveSceneIdChange?.(id);
@@ -13202,13 +13565,13 @@ function Scenes({
13202
13565
  },
13203
13566
  [isControlled, onActiveSceneIdChange]
13204
13567
  );
13205
- const scenesRef = (0, import_react45.useRef)(scenes);
13568
+ const scenesRef = (0, import_react47.useRef)(scenes);
13206
13569
  scenesRef.current = scenes;
13207
- const resolvedIdRef = (0, import_react45.useRef)(resolvedId);
13570
+ const resolvedIdRef = (0, import_react47.useRef)(resolvedId);
13208
13571
  resolvedIdRef.current = resolvedId;
13209
- const host = (0, import_react45.useContext)(ScenesHostContext);
13210
- const phaseRef = (0, import_react45.useRef)("idle");
13211
- (0, import_react45.useEffect)(() => {
13572
+ const host = (0, import_react47.useContext)(ScenesHostContext);
13573
+ const phaseRef = (0, import_react47.useRef)("idle");
13574
+ (0, import_react47.useEffect)(() => {
13212
13575
  if (!host) {
13213
13576
  return;
13214
13577
  }
@@ -13258,12 +13621,12 @@ function Scenes({
13258
13621
  }
13259
13622
  };
13260
13623
  }, [host, requestSceneChange]);
13261
- return /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
13624
+ return /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
13262
13625
  TileTextureManagerProvider,
13263
13626
  {
13264
13627
  maxTextureMemoryMb,
13265
13628
  maxConcurrentLoads: maxConcurrentTileLoads,
13266
- children: /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
13629
+ children: /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
13267
13630
  ScenesController,
13268
13631
  {
13269
13632
  ...rest,
@@ -13277,28 +13640,28 @@ function Scenes({
13277
13640
  }
13278
13641
 
13279
13642
  // src/hotspot/image-hotspot.tsx
13280
- var import_fiber25 = require("@react-three/fiber");
13281
- var import_react49 = require("react");
13282
- var import_three28 = require("three");
13643
+ var import_fiber26 = require("@react-three/fiber");
13644
+ var import_react51 = require("react");
13645
+ var import_three29 = require("three");
13283
13646
 
13284
13647
  // src/hotspot/hotspot-anchor.tsx
13285
- var import_fiber24 = require("@react-three/fiber");
13286
- var import_react48 = require("react");
13287
- var import_three26 = require("three");
13648
+ var import_fiber25 = require("@react-three/fiber");
13649
+ var import_react50 = require("react");
13650
+ var import_three27 = require("three");
13288
13651
 
13289
13652
  // src/hotspot/hotspot-tooltip.tsx
13290
- var import_react47 = require("react");
13653
+ var import_react49 = require("react");
13291
13654
 
13292
13655
  // src/webvr/stereo-html.tsx
13293
- var import_fiber23 = require("@react-three/fiber");
13294
- var import_react46 = require("react");
13656
+ var import_fiber24 = require("@react-three/fiber");
13657
+ var import_react48 = require("react");
13295
13658
  var import_client = require("react-dom/client");
13296
- var import_three24 = require("three");
13297
- var import_jsx_runtime24 = require("react/jsx-runtime");
13659
+ var import_three25 = require("three");
13660
+ var import_jsx_runtime25 = require("react/jsx-runtime");
13298
13661
  function useFallbackStereoView() {
13299
- const runtime = (0, import_react46.useContext)(WebVRRuntimeContext);
13662
+ const runtime = (0, import_react48.useContext)(WebVRRuntimeContext);
13300
13663
  const host = runtime?.host ?? null;
13301
- const fallback = (0, import_react46.useSyncExternalStore)(
13664
+ const fallback = (0, import_react48.useSyncExternalStore)(
13302
13665
  (onStoreChange) => host ? subscribeWebVRHost(host, onStoreChange) : () => void 0,
13303
13666
  () => isFallbackStereoMode(host?.snapshot.mode ?? null),
13304
13667
  () => false
@@ -13313,10 +13676,10 @@ function ProjectedHtml({
13313
13676
  stereoView,
13314
13677
  eye
13315
13678
  }) {
13316
- const { camera, gl, events, size } = (0, import_fiber23.useThree)();
13317
- const group = (0, import_react46.useRef)(null);
13318
- const overlay = (0, import_react46.useRef)(null);
13319
- const scratch = (0, import_react46.useRef)(new import_three24.Vector3());
13679
+ const { camera, gl, events, size } = (0, import_fiber24.useThree)();
13680
+ const group = (0, import_react48.useRef)(null);
13681
+ const overlay = (0, import_react48.useRef)(null);
13682
+ const scratch = (0, import_react48.useRef)(new import_three25.Vector3());
13320
13683
  const target = events.connected || gl.domElement.parentElement;
13321
13684
  const updatePosition = () => {
13322
13685
  const anchor = group.current;
@@ -13344,7 +13707,7 @@ function ProjectedHtml({
13344
13707
  )
13345
13708
  );
13346
13709
  };
13347
- (0, import_react46.useLayoutEffect)(() => {
13710
+ (0, import_react48.useLayoutEffect)(() => {
13348
13711
  if (!target) return;
13349
13712
  const element = document.createElement("div");
13350
13713
  Object.assign(element.style, {
@@ -13362,9 +13725,9 @@ function ProjectedHtml({
13362
13725
  queueMicrotask(() => root.unmount());
13363
13726
  };
13364
13727
  }, [target]);
13365
- (0, import_react46.useLayoutEffect)(() => {
13728
+ (0, import_react48.useLayoutEffect)(() => {
13366
13729
  overlay.current?.root.render(
13367
- /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
13730
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
13368
13731
  "div",
13369
13732
  {
13370
13733
  "aria-hidden": eye === "right" || void 0,
@@ -13375,19 +13738,19 @@ function ProjectedHtml({
13375
13738
  );
13376
13739
  updatePosition();
13377
13740
  });
13378
- (0, import_fiber23.useFrame)(updatePosition);
13379
- return /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("group", { ref: group });
13741
+ (0, import_fiber24.useFrame)(updatePosition);
13742
+ return /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("group", { ref: group });
13380
13743
  }
13381
13744
  function PanoHtml(props) {
13382
13745
  const stereoView = useFallbackStereoView();
13383
- return stereoView ? /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)(import_jsx_runtime24.Fragment, { children: [
13384
- /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(ProjectedHtml, { ...props, stereoView, eye: "left" }),
13385
- /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(ProjectedHtml, { ...props, stereoView, eye: "right" })
13386
- ] }) : /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(ProjectedHtml, { ...props });
13746
+ return stereoView ? /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(import_jsx_runtime25.Fragment, { children: [
13747
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(ProjectedHtml, { ...props, stereoView, eye: "left" }),
13748
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(ProjectedHtml, { ...props, stereoView, eye: "right" })
13749
+ ] }) : /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(ProjectedHtml, { ...props });
13387
13750
  }
13388
13751
 
13389
13752
  // src/hotspot/hotspot-tooltip.tsx
13390
- var import_jsx_runtime25 = require("react/jsx-runtime");
13753
+ var import_jsx_runtime26 = require("react/jsx-runtime");
13391
13754
  var DEFAULT_HOTSPOT_TOOLTIP_OFFSET = 12;
13392
13755
  var DEFAULT_HOTSPOT_TOOLTIP_APPEARANCE = {
13393
13756
  background: "rgba(22, 22, 22, 0.72)",
@@ -13459,16 +13822,16 @@ function HotspotTooltip({
13459
13822
  offset = DEFAULT_HOTSPOT_TOOLTIP_OFFSET,
13460
13823
  appearance
13461
13824
  }) {
13462
- const [imageFailed, setImageFailed] = (0, import_react47.useState)(false);
13463
- (0, import_react47.useEffect)(() => {
13825
+ const [imageFailed, setImageFailed] = (0, import_react49.useState)(false);
13826
+ (0, import_react49.useEffect)(() => {
13464
13827
  setImageFailed(false);
13465
13828
  }, [content.image]);
13466
13829
  const showImage = Boolean(content.image) && !imageFailed;
13467
- const resolvedAppearance = (0, import_react47.useMemo)(
13830
+ const resolvedAppearance = (0, import_react49.useMemo)(
13468
13831
  () => resolveHotspotTooltipAppearance(appearance),
13469
13832
  [appearance]
13470
13833
  );
13471
- const bubbleStyle = (0, import_react47.useMemo)(
13834
+ const bubbleStyle = (0, import_react49.useMemo)(
13472
13835
  () => ({
13473
13836
  background: resolvedAppearance.background,
13474
13837
  border: resolvedAppearance.border,
@@ -13490,8 +13853,8 @@ function HotspotTooltip({
13490
13853
  if (!showImage && !content.text) {
13491
13854
  return null;
13492
13855
  }
13493
- return /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(PanoHtml, { pointerEvents: "none", style: WRAPPER_STYLE, zIndexRange: [20, 10], children: /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("div", { className: "pano-hotspot-tooltip", role: "tooltip", style: bubbleStyle, children: [
13494
- showImage ? /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
13856
+ return /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(PanoHtml, { pointerEvents: "none", style: WRAPPER_STYLE, zIndexRange: [20, 10], children: /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)("div", { className: "pano-hotspot-tooltip", role: "tooltip", style: bubbleStyle, children: [
13857
+ showImage ? /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(
13495
13858
  "img",
13496
13859
  {
13497
13860
  alt: content.imageAlt ?? content.text ?? "",
@@ -13500,7 +13863,7 @@ function HotspotTooltip({
13500
13863
  src: content.image
13501
13864
  }
13502
13865
  ) : null,
13503
- content.text ? /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
13866
+ content.text ? /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(
13504
13867
  "p",
13505
13868
  {
13506
13869
  className: "pano-hotspot-tooltip-text",
@@ -13516,18 +13879,18 @@ function HotspotTooltip({
13516
13879
  }
13517
13880
 
13518
13881
  // src/hotspot/transform.ts
13519
- var import_three25 = require("three");
13520
- var LOCAL_FORWARD = new import_three25.Vector3(0, 0, 1);
13521
- var CAMERA_POSITION = new import_three25.Vector3();
13882
+ var import_three26 = require("three");
13883
+ var LOCAL_FORWARD = new import_three26.Vector3(0, 0, 1);
13884
+ var CAMERA_POSITION = new import_three26.Vector3();
13522
13885
  function applyHotspotTransform(group, camera, orientation2, surfaceQuaternion3, rotation, scaleMode, referenceFov, useAngularScale, worldWidth, worldHeight, distance) {
13523
13886
  if (orientation2 === "billboard") {
13524
13887
  group.quaternion.copy(camera.quaternion);
13525
13888
  } else {
13526
13889
  group.quaternion.copy(surfaceQuaternion3);
13527
13890
  }
13528
- group.rotateOnAxis(LOCAL_FORWARD, import_three25.MathUtils.degToRad(-rotation));
13529
- let scaleFactor = scaleMode === "fixed" && camera instanceof import_three25.PerspectiveCamera ? fixedScaleFactor(camera.fov, referenceFov) : 1;
13530
- if (scaleMode === "fixed" && orientation2 === "billboard" && useAngularScale && camera instanceof import_three25.PerspectiveCamera) {
13891
+ group.rotateOnAxis(LOCAL_FORWARD, import_three26.MathUtils.degToRad(-rotation));
13892
+ let scaleFactor = scaleMode === "fixed" && camera instanceof import_three26.PerspectiveCamera ? fixedScaleFactor(camera.fov, referenceFov) : 1;
13893
+ if (scaleMode === "fixed" && orientation2 === "billboard" && useAngularScale && camera instanceof import_three26.PerspectiveCamera) {
13531
13894
  group.updateWorldMatrix(true, false);
13532
13895
  CAMERA_POSITION.setFromMatrixPosition(group.matrixWorld).applyMatrix4(
13533
13896
  camera.matrixWorldInverse
@@ -13542,12 +13905,12 @@ function applyHotspotTransform(group, camera, orientation2, surfaceQuaternion3,
13542
13905
  group.updateMatrixWorld();
13543
13906
  }
13544
13907
  function fixedScaleFactor(cameraFov, referenceFov) {
13545
- const safeReferenceFov = import_three25.MathUtils.clamp(referenceFov, 1, 179);
13546
- return Math.tan(import_three25.MathUtils.degToRad(cameraFov) / 2) / Math.tan(import_three25.MathUtils.degToRad(safeReferenceFov) / 2);
13908
+ const safeReferenceFov = import_three26.MathUtils.clamp(referenceFov, 1, 179);
13909
+ return Math.tan(import_three26.MathUtils.degToRad(cameraFov) / 2) / Math.tan(import_three26.MathUtils.degToRad(safeReferenceFov) / 2);
13547
13910
  }
13548
13911
 
13549
13912
  // src/hotspot/hotspot-anchor.tsx
13550
- var import_jsx_runtime26 = require("react/jsx-runtime");
13913
+ var import_jsx_runtime27 = require("react/jsx-runtime");
13551
13914
  var DEFAULT_FLOATING_DISTANCE = 10;
13552
13915
  var PANORAMA_RADIUS = DEFAULT_PANORAMA_RADIUS;
13553
13916
  var PANORAMA_SURFACE_INSET = 4;
@@ -13555,27 +13918,27 @@ var DEFAULT_REFERENCE_FOV = 75;
13555
13918
  var MIN_ANGULAR_SIZE = 0.01;
13556
13919
  var MAX_ANGULAR_SIZE = 179;
13557
13920
  var DRAG_EPSILON_DEGREES = 1e-3;
13558
- var TOOLTIP_WORLD_BOX = new import_three26.Box3();
13559
- var TOOLTIP_LOCAL_BOX = new import_three26.Box3();
13560
- var TOOLTIP_CORNER = new import_three26.Vector3();
13561
- var TOOLTIP_INVERSE = new import_three26.Matrix4();
13562
- var TOOLTIP_WORLD_CORNER = new import_three26.Vector3();
13563
- var TOOLTIP_PROJECTED = new import_three26.Vector3();
13564
- var TOOLTIP_RAY_ORIGIN = new import_three26.Vector3();
13565
- var TOOLTIP_RAY_FAR = new import_three26.Vector3();
13566
- var TOOLTIP_RAY_DIRECTION = new import_three26.Vector3();
13567
- var TOOLTIP_RAY = new import_three26.Ray();
13568
- var TOOLTIP_PLANE = new import_three26.Plane();
13569
- var TOOLTIP_INTERSECTION = new import_three26.Vector3();
13570
- var TOOLTIP_PLANE_NORMAL = new import_three26.Vector3();
13571
- var TOOLTIP_PLANE_POINT = new import_three26.Vector3();
13921
+ var TOOLTIP_WORLD_BOX = new import_three27.Box3();
13922
+ var TOOLTIP_LOCAL_BOX = new import_three27.Box3();
13923
+ var TOOLTIP_CORNER = new import_three27.Vector3();
13924
+ var TOOLTIP_INVERSE = new import_three27.Matrix4();
13925
+ var TOOLTIP_WORLD_CORNER = new import_three27.Vector3();
13926
+ var TOOLTIP_PROJECTED = new import_three27.Vector3();
13927
+ var TOOLTIP_RAY_ORIGIN = new import_three27.Vector3();
13928
+ var TOOLTIP_RAY_FAR = new import_three27.Vector3();
13929
+ var TOOLTIP_RAY_DIRECTION = new import_three27.Vector3();
13930
+ var TOOLTIP_RAY = new import_three27.Ray();
13931
+ var TOOLTIP_PLANE = new import_three27.Plane();
13932
+ var TOOLTIP_INTERSECTION = new import_three27.Vector3();
13933
+ var TOOLTIP_PLANE_NORMAL = new import_three27.Vector3();
13934
+ var TOOLTIP_PLANE_POINT = new import_three27.Vector3();
13572
13935
  var HOTSPOT_MODE_RENDERING = {
13573
13936
  surface: { orientation: "surface", placement: "surface" },
13574
13937
  billboard: { orientation: "billboard", placement: "floating" }
13575
13938
  };
13576
13939
  function angularSizeToWorldSize(size, radius) {
13577
- const safeSize = Number.isFinite(size) ? import_three26.MathUtils.clamp(Math.abs(size), MIN_ANGULAR_SIZE, MAX_ANGULAR_SIZE) : MIN_ANGULAR_SIZE;
13578
- return 2 * radius * Math.tan(import_three26.MathUtils.degToRad(safeSize) / 2);
13940
+ const safeSize = Number.isFinite(size) ? import_three27.MathUtils.clamp(Math.abs(size), MIN_ANGULAR_SIZE, MAX_ANGULAR_SIZE) : MIN_ANGULAR_SIZE;
13941
+ return 2 * radius * Math.tan(import_three27.MathUtils.degToRad(safeSize) / 2);
13579
13942
  }
13580
13943
  function resolveScale(scale) {
13581
13944
  return Number.isFinite(scale) && scale > 0 ? scale : 1;
@@ -13588,39 +13951,39 @@ function resolveDistance(placement, distance, width, height) {
13588
13951
  if (!Number.isFinite(distance)) {
13589
13952
  return DEFAULT_FLOATING_DISTANCE;
13590
13953
  }
13591
- return import_three26.MathUtils.clamp(Math.abs(distance), 0.1, maximumDistance);
13954
+ return import_three27.MathUtils.clamp(Math.abs(distance), 0.1, maximumDistance);
13592
13955
  }
13593
13956
  function maximumHotspotDistance(width, height) {
13594
- const safeWidth = import_three26.MathUtils.clamp(
13957
+ const safeWidth = import_three27.MathUtils.clamp(
13595
13958
  Math.abs(Number.isFinite(width) ? width : MIN_ANGULAR_SIZE),
13596
13959
  MIN_ANGULAR_SIZE,
13597
13960
  MAX_ANGULAR_SIZE
13598
13961
  );
13599
- const safeHeight = import_three26.MathUtils.clamp(
13962
+ const safeHeight = import_three27.MathUtils.clamp(
13600
13963
  Math.abs(Number.isFinite(height) ? height : MIN_ANGULAR_SIZE),
13601
13964
  MIN_ANGULAR_SIZE,
13602
13965
  MAX_ANGULAR_SIZE
13603
13966
  );
13604
13967
  const cornerFactor = Math.hypot(
13605
13968
  1,
13606
- Math.tan(import_three26.MathUtils.degToRad(safeWidth) / 2),
13607
- Math.tan(import_three26.MathUtils.degToRad(safeHeight) / 2)
13969
+ Math.tan(import_three27.MathUtils.degToRad(safeWidth) / 2),
13970
+ Math.tan(import_three27.MathUtils.degToRad(safeHeight) / 2)
13608
13971
  );
13609
13972
  return (PANORAMA_RADIUS - PANORAMA_SURFACE_INSET) / cornerFactor;
13610
13973
  }
13611
13974
  function createSurfaceQuaternion(position) {
13612
13975
  const outward = panoPositionToVector3(position).normalize();
13613
13976
  const inward = outward.clone().negate();
13614
- const pitch = import_three26.MathUtils.degToRad(position.pitch);
13615
- const yaw = import_three26.MathUtils.degToRad(position.yaw);
13616
- const localUp = new import_three26.Vector3(
13977
+ const pitch = import_three27.MathUtils.degToRad(position.pitch);
13978
+ const yaw = import_three27.MathUtils.degToRad(position.yaw);
13979
+ const localUp = new import_three27.Vector3(
13617
13980
  -Math.sin(pitch) * Math.sin(yaw),
13618
13981
  Math.cos(pitch),
13619
13982
  Math.sin(pitch) * Math.cos(yaw)
13620
13983
  ).normalize();
13621
13984
  const localRight = localUp.clone().cross(inward).normalize();
13622
- const basis = new import_three26.Matrix4().makeBasis(localRight, localUp, inward);
13623
- return new import_three26.Quaternion().setFromRotationMatrix(basis);
13985
+ const basis = new import_three27.Matrix4().makeBasis(localRight, localUp, inward);
13986
+ return new import_three27.Quaternion().setFromRotationMatrix(basis);
13624
13987
  }
13625
13988
  function makeInteractionEvent(id, position, event) {
13626
13989
  return {
@@ -13633,7 +13996,7 @@ function makeInteractionEvent(id, position, event) {
13633
13996
  function angularDistance(a, b) {
13634
13997
  const aVector = panoPositionToVector3(a);
13635
13998
  const bVector = panoPositionToVector3(b);
13636
- return import_three26.MathUtils.radToDeg(aVector.angleTo(bVector));
13999
+ return import_three27.MathUtils.radToDeg(aVector.angleTo(bVector));
13637
14000
  }
13638
14001
  function isTooltipOpen(trigger, hovered, focused, pinned) {
13639
14002
  switch (trigger) {
@@ -13864,24 +14227,24 @@ function HotspotAnchor({
13864
14227
  onPositionChange,
13865
14228
  onDragEnd
13866
14229
  }) {
13867
- const controlsRef = (0, import_react48.useContext)(PanoramaViewContext);
13868
- const hotspotTargetRegistry = (0, import_react48.useContext)(HotspotTargetRegistryContext);
13869
- const eventBus = (0, import_react48.useContext)(PanoEventBusContext);
14230
+ const controlsRef = (0, import_react50.useContext)(PanoramaViewContext);
14231
+ const hotspotTargetRegistry = (0, import_react50.useContext)(HotspotTargetRegistryContext);
14232
+ const eventBus = (0, import_react50.useContext)(PanoEventBusContext);
13870
14233
  const cursorApi = usePanoCursor();
13871
- const { camera, size } = (0, import_fiber24.useThree)();
13872
- const groupRef = (0, import_react48.useRef)(null);
13873
- const tooltipAnchorRef = (0, import_react48.useRef)(null);
13874
- const dragStateRef = (0, import_react48.useRef)(null);
13875
- const suppressNextClickRef = (0, import_react48.useRef)(false);
13876
- const [hovered, setHovered] = (0, import_react48.useState)(false);
13877
- const [dragging, setDragging] = (0, import_react48.useState)(false);
13878
- const [pinned, setPinned] = (0, import_react48.useState)(false);
13879
- const tooltipContent = (0, import_react48.useMemo)(
14234
+ const { camera, size } = (0, import_fiber25.useThree)();
14235
+ const groupRef = (0, import_react50.useRef)(null);
14236
+ const tooltipAnchorRef = (0, import_react50.useRef)(null);
14237
+ const dragStateRef = (0, import_react50.useRef)(null);
14238
+ const suppressNextClickRef = (0, import_react50.useRef)(false);
14239
+ const [hovered, setHovered] = (0, import_react50.useState)(false);
14240
+ const [dragging, setDragging] = (0, import_react50.useState)(false);
14241
+ const [pinned, setPinned] = (0, import_react50.useState)(false);
14242
+ const tooltipContent = (0, import_react50.useMemo)(
13880
14243
  () => resolveHotspotTooltipContent(tooltip),
13881
14244
  [tooltip]
13882
14245
  );
13883
14246
  const normalizedPosition = normalizePanoPosition(position);
13884
- (0, import_react48.useEffect)(() => {
14247
+ (0, import_react50.useEffect)(() => {
13885
14248
  if (!hotspotTargetRegistry) {
13886
14249
  return;
13887
14250
  }
@@ -13898,19 +14261,19 @@ function HotspotAnchor({
13898
14261
  scaledWidth,
13899
14262
  scaledHeight
13900
14263
  );
13901
- const worldPosition = (0, import_react48.useMemo)(
14264
+ const worldPosition = (0, import_react50.useMemo)(
13902
14265
  () => panoPositionToVector3(normalizedPosition, resolvedDistance),
13903
14266
  [normalizedPosition.pitch, normalizedPosition.yaw, resolvedDistance]
13904
14267
  );
13905
- const surfaceQuaternion3 = (0, import_react48.useMemo)(
14268
+ const surfaceQuaternion3 = (0, import_react50.useMemo)(
13906
14269
  () => createSurfaceQuaternion(normalizedPosition),
13907
14270
  [normalizedPosition.pitch, normalizedPosition.yaw]
13908
14271
  );
13909
14272
  const worldWidth = angularSizeToWorldSize(scaledWidth, resolvedDistance);
13910
14273
  const worldHeight = angularSizeToWorldSize(scaledHeight, resolvedDistance);
13911
- const focusGeometry = (0, import_react48.useMemo)(() => {
13912
- const planeGeometry = new import_three26.PlaneGeometry(1, 1);
13913
- const geometry = new import_three26.EdgesGeometry(planeGeometry);
14274
+ const focusGeometry = (0, import_react50.useMemo)(() => {
14275
+ const planeGeometry = new import_three27.PlaneGeometry(1, 1);
14276
+ const geometry = new import_three27.EdgesGeometry(planeGeometry);
13914
14277
  planeGeometry.dispose();
13915
14278
  return geometry;
13916
14279
  }, []);
@@ -13935,14 +14298,14 @@ function HotspotAnchor({
13935
14298
  });
13936
14299
  const tooltipOpen = visible && tooltipContent !== null && isTooltipOpen(tooltipTrigger, hovered, focused, pinned);
13937
14300
  const cursorClaimId = hotspotCursorClaimId(id);
13938
- (0, import_react48.useEffect)(
14301
+ (0, import_react50.useEffect)(
13939
14302
  () => () => {
13940
14303
  dragStateRef.current?.releaseInteractionLock();
13941
14304
  dragStateRef.current = null;
13942
14305
  },
13943
14306
  []
13944
14307
  );
13945
- (0, import_react48.useEffect)(() => {
14308
+ (0, import_react50.useEffect)(() => {
13946
14309
  if (!cursorApi) {
13947
14310
  return;
13948
14311
  }
@@ -13964,14 +14327,14 @@ function HotspotAnchor({
13964
14327
  hovered,
13965
14328
  visible
13966
14329
  ]);
13967
- (0, import_react48.useEffect)(
14330
+ (0, import_react50.useEffect)(
13968
14331
  () => () => {
13969
14332
  cursorApi?.release(cursorClaimId);
13970
14333
  },
13971
14334
  [cursorApi, cursorClaimId]
13972
14335
  );
13973
- (0, import_react48.useEffect)(() => () => focusGeometry.dispose(), [focusGeometry]);
13974
- (0, import_react48.useEffect)(() => {
14336
+ (0, import_react50.useEffect)(() => () => focusGeometry.dispose(), [focusGeometry]);
14337
+ (0, import_react50.useEffect)(() => {
13975
14338
  if (tooltipTrigger !== "click") {
13976
14339
  setPinned(false);
13977
14340
  return;
@@ -13980,12 +14343,12 @@ function HotspotAnchor({
13980
14343
  setPinned(false);
13981
14344
  });
13982
14345
  }, [eventBus, tooltipTrigger]);
13983
- (0, import_react48.useEffect)(() => {
14346
+ (0, import_react50.useEffect)(() => {
13984
14347
  if (tooltipTrigger !== "hover") {
13985
14348
  setHovered(false);
13986
14349
  }
13987
14350
  }, [tooltipTrigger]);
13988
- (0, import_react48.useEffect)(() => {
14351
+ (0, import_react50.useEffect)(() => {
13989
14352
  if (acceptsPointer) {
13990
14353
  return;
13991
14354
  }
@@ -13998,7 +14361,7 @@ function HotspotAnchor({
13998
14361
  dragStateRef.current = null;
13999
14362
  setDragging(false);
14000
14363
  }, [acceptsPointer]);
14001
- (0, import_react48.useLayoutEffect)(() => {
14364
+ (0, import_react50.useLayoutEffect)(() => {
14002
14365
  const group = groupRef.current;
14003
14366
  if (!group) {
14004
14367
  return;
@@ -14041,7 +14404,7 @@ function HotspotAnchor({
14041
14404
  worldHeight,
14042
14405
  worldWidth
14043
14406
  ]);
14044
- (0, import_fiber24.useFrame)((state) => {
14407
+ (0, import_fiber25.useFrame)((state) => {
14045
14408
  const group = groupRef.current;
14046
14409
  if (!group) {
14047
14410
  return;
@@ -14100,7 +14463,7 @@ function HotspotAnchor({
14100
14463
  setHovered(true);
14101
14464
  }
14102
14465
  };
14103
- return /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)(
14466
+ return /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)(
14104
14467
  "group",
14105
14468
  {
14106
14469
  ref: groupRef,
@@ -14177,18 +14540,18 @@ function HotspotAnchor({
14177
14540
  } : void 0,
14178
14541
  onPointerUp: acceptsPointer ? (event) => releasePointer(event, true) : void 0,
14179
14542
  children: [
14180
- focused ? focusContent ?? /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(
14543
+ focused ? focusContent ?? /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
14181
14544
  "lineSegments",
14182
14545
  {
14183
14546
  geometry: focusGeometry,
14184
14547
  position: [0, 0, 0.01],
14185
14548
  renderOrder: renderOrder + 1,
14186
14549
  scale: [1.12, 1.12, 1],
14187
- children: /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("lineBasicMaterial", { color: "#f5fbfc", depthTest: false })
14550
+ children: /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("lineBasicMaterial", { color: "#f5fbfc", depthTest: false })
14188
14551
  }
14189
14552
  ) : null,
14190
14553
  children,
14191
- tooltipOpen && tooltipContent ? /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("group", { ref: tooltipAnchorRef, children: /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(
14554
+ tooltipOpen && tooltipContent ? /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("group", { ref: tooltipAnchorRef, children: /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
14192
14555
  HotspotTooltip,
14193
14556
  {
14194
14557
  appearance: tooltipAppearance,
@@ -14203,10 +14566,10 @@ function HotspotAnchor({
14203
14566
  }
14204
14567
 
14205
14568
  // src/hotspot/hotspot-plane.tsx
14206
- var import_three27 = require("three");
14207
- var import_jsx_runtime27 = require("react/jsx-runtime");
14569
+ var import_three28 = require("three");
14570
+ var import_jsx_runtime28 = require("react/jsx-runtime");
14208
14571
  var HOTSPOT_ALPHA_CUTOFF = 0.05;
14209
- var SAMPLE_UV = new import_three27.Vector2();
14572
+ var SAMPLE_UV = new import_three28.Vector2();
14210
14573
  var RAYCAST_HITS = [];
14211
14574
  var IMAGE_DATA_CACHE = /* @__PURE__ */ new WeakMap();
14212
14575
  function clampOpacity(opacity) {
@@ -14280,8 +14643,8 @@ function sampleTextureAlpha(texture, u, v) {
14280
14643
  }
14281
14644
  function hotspotPlaneRaycast(raycaster, intersects2) {
14282
14645
  const material = Array.isArray(this.material) ? this.material[0] : this.material;
14283
- if (!(material instanceof import_three27.MeshBasicMaterial)) {
14284
- import_three27.Mesh.prototype.raycast.call(this, raycaster, intersects2);
14646
+ if (!(material instanceof import_three28.MeshBasicMaterial)) {
14647
+ import_three28.Mesh.prototype.raycast.call(this, raycaster, intersects2);
14285
14648
  return;
14286
14649
  }
14287
14650
  const cutoff = Math.max(material.alphaTest, HOTSPOT_ALPHA_CUTOFF);
@@ -14289,7 +14652,7 @@ function hotspotPlaneRaycast(raycaster, intersects2) {
14289
14652
  return;
14290
14653
  }
14291
14654
  RAYCAST_HITS.length = 0;
14292
- import_three27.Mesh.prototype.raycast.call(this, raycaster, RAYCAST_HITS);
14655
+ import_three28.Mesh.prototype.raycast.call(this, raycaster, RAYCAST_HITS);
14293
14656
  const map = material.map;
14294
14657
  for (const hit of RAYCAST_HITS) {
14295
14658
  if (!map || !hit.uv) {
@@ -14306,16 +14669,16 @@ function HotspotPlane({
14306
14669
  map,
14307
14670
  opacity
14308
14671
  }) {
14309
- return /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("mesh", { raycast: hotspotPlaneRaycast, children: [
14310
- /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("planeGeometry", { args: [1, 1] }),
14311
- /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
14672
+ return /* @__PURE__ */ (0, import_jsx_runtime28.jsxs)("mesh", { raycast: hotspotPlaneRaycast, children: [
14673
+ /* @__PURE__ */ (0, import_jsx_runtime28.jsx)("planeGeometry", { args: [1, 1] }),
14674
+ /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(
14312
14675
  PanoBasicMaterial,
14313
14676
  {
14314
14677
  target: "hotspot",
14315
14678
  alphaTest: HOTSPOT_ALPHA_CUTOFF,
14316
14679
  map,
14317
14680
  opacity: map ? clampOpacity(opacity) : 0,
14318
- side: import_three27.DoubleSide,
14681
+ side: import_three28.DoubleSide,
14319
14682
  toneMapped: false,
14320
14683
  transparent: true
14321
14684
  }
@@ -14324,15 +14687,15 @@ function HotspotPlane({
14324
14687
  }
14325
14688
 
14326
14689
  // src/hotspot/image-hotspot.tsx
14327
- var import_jsx_runtime28 = require("react/jsx-runtime");
14690
+ var import_jsx_runtime29 = require("react/jsx-runtime");
14328
14691
  function useHotspotImageTexture(src, onLoad, onError) {
14329
- const gl = (0, import_fiber25.useThree)((state) => state.gl);
14330
- const [texture, setTexture] = (0, import_react49.useState)(null);
14331
- const onLoadRef = (0, import_react49.useRef)(onLoad);
14332
- const onErrorRef = (0, import_react49.useRef)(onError);
14692
+ const gl = (0, import_fiber26.useThree)((state) => state.gl);
14693
+ const [texture, setTexture] = (0, import_react51.useState)(null);
14694
+ const onLoadRef = (0, import_react51.useRef)(onLoad);
14695
+ const onErrorRef = (0, import_react51.useRef)(onError);
14333
14696
  onLoadRef.current = onLoad;
14334
14697
  onErrorRef.current = onError;
14335
- (0, import_react49.useEffect)(() => {
14698
+ (0, import_react51.useEffect)(() => {
14336
14699
  let active = true;
14337
14700
  setTexture(null);
14338
14701
  if (!src) {
@@ -14340,7 +14703,7 @@ function useHotspotImageTexture(src, onLoad, onError) {
14340
14703
  active = false;
14341
14704
  };
14342
14705
  }
14343
- const loader = new import_three28.TextureLoader();
14706
+ const loader = new import_three29.TextureLoader();
14344
14707
  loader.load(
14345
14708
  src,
14346
14709
  (loadedTexture) => {
@@ -14348,11 +14711,11 @@ function useHotspotImageTexture(src, onLoad, onError) {
14348
14711
  loadedTexture.dispose();
14349
14712
  return;
14350
14713
  }
14351
- loadedTexture.colorSpace = import_three28.SRGBColorSpace;
14352
- loadedTexture.wrapS = import_three28.ClampToEdgeWrapping;
14353
- loadedTexture.wrapT = import_three28.ClampToEdgeWrapping;
14354
- loadedTexture.magFilter = import_three28.LinearFilter;
14355
- loadedTexture.minFilter = import_three28.LinearMipmapLinearFilter;
14714
+ loadedTexture.colorSpace = import_three29.SRGBColorSpace;
14715
+ loadedTexture.wrapS = import_three29.ClampToEdgeWrapping;
14716
+ loadedTexture.wrapT = import_three29.ClampToEdgeWrapping;
14717
+ loadedTexture.magFilter = import_three29.LinearFilter;
14718
+ loadedTexture.minFilter = import_three29.LinearMipmapLinearFilter;
14356
14719
  loadedTexture.generateMipmaps = true;
14357
14720
  loadedTexture.anisotropy = gl.capabilities.getMaxAnisotropy();
14358
14721
  loadedTexture.needsUpdate = true;
@@ -14370,7 +14733,7 @@ function useHotspotImageTexture(src, onLoad, onError) {
14370
14733
  active = false;
14371
14734
  };
14372
14735
  }, [gl, src]);
14373
- (0, import_react49.useEffect)(
14736
+ (0, import_react51.useEffect)(
14374
14737
  () => () => {
14375
14738
  texture?.dispose();
14376
14739
  },
@@ -14388,20 +14751,20 @@ function ImageHotspot({
14388
14751
  ...anchorProps
14389
14752
  }) {
14390
14753
  const texture = useHotspotImageTexture(src, onLoad, onError);
14391
- return /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(HotspotAnchor, { ...anchorProps, height, width, children: /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(HotspotPlane, { map: texture, opacity }) });
14754
+ return /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(HotspotAnchor, { ...anchorProps, height, width, children: /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(HotspotPlane, { map: texture, opacity }) });
14392
14755
  }
14393
14756
 
14394
14757
  // src/hotspot/polygon-hotspot.tsx
14395
- var import_react51 = require("react");
14396
- var import_three30 = require("three");
14758
+ var import_react53 = require("react");
14759
+ var import_three31 = require("three");
14397
14760
 
14398
14761
  // src/hotspot/hotspot-stroke-line.tsx
14399
14762
  var import_drei = require("@react-three/drei");
14400
- var import_fiber26 = require("@react-three/fiber");
14401
- var import_react50 = require("react");
14402
- var import_three29 = require("three");
14403
- var import_jsx_runtime29 = require("react/jsx-runtime");
14404
- var LINE_WORLD_POSITION = new import_three29.Vector3();
14763
+ var import_fiber27 = require("@react-three/fiber");
14764
+ var import_react52 = require("react");
14765
+ var import_three30 = require("three");
14766
+ var import_jsx_runtime30 = require("react/jsx-runtime");
14767
+ var LINE_WORLD_POSITION = new import_three30.Vector3();
14405
14768
  function applyScreenSpaceDashScale(object, camera, viewportHeight) {
14406
14769
  const material = object?.material;
14407
14770
  if (!object || typeof material?.dashScale !== "number") {
@@ -14409,8 +14772,8 @@ function applyScreenSpaceDashScale(object, camera, viewportHeight) {
14409
14772
  }
14410
14773
  object.getWorldPosition(LINE_WORLD_POSITION);
14411
14774
  const depth = Math.max(camera.position.distanceTo(LINE_WORLD_POSITION), 1);
14412
- const fov = camera instanceof import_three29.PerspectiveCamera ? camera.fov : 75;
14413
- material.dashScale = viewportHeight / (2 * Math.tan(import_three29.MathUtils.degToRad(fov) * 0.5) * depth);
14775
+ const fov = camera instanceof import_three30.PerspectiveCamera ? camera.fov : 75;
14776
+ material.dashScale = viewportHeight / (2 * Math.tan(import_three30.MathUtils.degToRad(fov) * 0.5) * depth);
14414
14777
  }
14415
14778
  function resolveDash(dashSize, gapSize) {
14416
14779
  if (dashSize === void 0 || !Number.isFinite(dashSize) || dashSize <= 0) {
@@ -14431,22 +14794,22 @@ function HotspotStrokeLine({
14431
14794
  dashSize,
14432
14795
  gapSize
14433
14796
  }) {
14434
- const lineRef = (0, import_react50.useRef)(null);
14435
- const { camera, size } = (0, import_fiber26.useThree)();
14797
+ const lineRef = (0, import_react52.useRef)(null);
14798
+ const { camera, size } = (0, import_fiber27.useThree)();
14436
14799
  const dash = resolveDash(dashSize, gapSize);
14437
- (0, import_react50.useLayoutEffect)(() => {
14800
+ (0, import_react52.useLayoutEffect)(() => {
14438
14801
  if (!dash.dashed) {
14439
14802
  return;
14440
14803
  }
14441
14804
  applyScreenSpaceDashScale(lineRef.current, camera, size.height);
14442
14805
  }, [camera, dash.dashed, dash.dashSize, dash.gapSize, size.height]);
14443
- (0, import_fiber26.useFrame)((state) => {
14806
+ (0, import_fiber27.useFrame)((state) => {
14444
14807
  if (!dash.dashed) {
14445
14808
  return;
14446
14809
  }
14447
14810
  applyScreenSpaceDashScale(lineRef.current, state.camera, state.size.height);
14448
14811
  });
14449
- return /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
14812
+ return /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(
14450
14813
  import_drei.Line,
14451
14814
  {
14452
14815
  ref: lineRef,
@@ -14468,7 +14831,7 @@ function HotspotStrokeLine({
14468
14831
  }
14469
14832
 
14470
14833
  // src/hotspot/polygon-hotspot.tsx
14471
- var import_jsx_runtime30 = require("react/jsx-runtime");
14834
+ var import_jsx_runtime31 = require("react/jsx-runtime");
14472
14835
  var POLYGON_RADIUS = 990;
14473
14836
  var MAX_FILL_SEGMENT_DEGREES = 7;
14474
14837
  function cloneVertices(vertices) {
@@ -14503,7 +14866,7 @@ function intersects(a, b, c, d) {
14503
14866
  }
14504
14867
  function hasSelfIntersection(vertices) {
14505
14868
  const points = vertices.map(
14506
- (vertex) => new import_three30.Vector2(vertex.unwrappedYaw, vertex.pitch)
14869
+ (vertex) => new import_three31.Vector2(vertex.unwrappedYaw, vertex.pitch)
14507
14870
  );
14508
14871
  for (let index = 0; index < points.length; index += 1) {
14509
14872
  const nextIndex = (index + 1) % points.length;
@@ -14540,7 +14903,7 @@ function polygonContainsDirection(vertices, direction) {
14540
14903
  }
14541
14904
  function fitsHemisphere(vertices) {
14542
14905
  const directions = vertices.map((vertex) => panoPositionToVector3(vertex).normalize());
14543
- const candidates = [new import_three30.Vector3()];
14906
+ const candidates = [new import_three31.Vector3()];
14544
14907
  for (const direction of directions) {
14545
14908
  candidates[0].add(direction);
14546
14909
  candidates.push(direction.clone());
@@ -14564,7 +14927,7 @@ function validatePolygonVertices(vertices) {
14564
14927
  if (hasSelfIntersection(unwrapped)) {
14565
14928
  issues.push({ code: "self_intersection", message: "Polygon edges cannot cross." });
14566
14929
  }
14567
- if (polygonContainsDirection(normalized, new import_three30.Vector3(0, 1, 0)) || polygonContainsDirection(normalized, new import_three30.Vector3(0, -1, 0))) {
14930
+ if (polygonContainsDirection(normalized, new import_three31.Vector3(0, 1, 0)) || polygonContainsDirection(normalized, new import_three31.Vector3(0, -1, 0))) {
14568
14931
  issues.push({ code: "contains_pole", message: "Polygons cannot contain a panorama pole." });
14569
14932
  }
14570
14933
  if (!fitsHemisphere(normalized)) {
@@ -14575,7 +14938,7 @@ function validatePolygonVertices(vertices) {
14575
14938
  function polygonCenter(vertices) {
14576
14939
  const sum = vertices.reduce(
14577
14940
  (total, vertex) => total.add(panoPositionToVector3(vertex).normalize()),
14578
- new import_three30.Vector3()
14941
+ new import_three31.Vector3()
14579
14942
  );
14580
14943
  return sum.lengthSq() > 1e-8 ? vector3ToPanoPosition(sum) : normalizePanoPosition(vertices[0]);
14581
14944
  }
@@ -14584,20 +14947,20 @@ function surfaceQuaternion(position) {
14584
14947
  const inward = outward.clone().negate();
14585
14948
  const pitch = position.pitch * Math.PI / 180;
14586
14949
  const yaw = position.yaw * Math.PI / 180;
14587
- const localUp = new import_three30.Vector3(
14950
+ const localUp = new import_three31.Vector3(
14588
14951
  -Math.sin(pitch) * Math.sin(yaw),
14589
14952
  Math.cos(pitch),
14590
14953
  Math.sin(pitch) * Math.cos(yaw)
14591
14954
  ).normalize();
14592
- return new import_three30.Quaternion().setFromRotationMatrix(
14593
- new import_three30.Matrix4().makeBasis(localUp.clone().cross(inward).normalize(), localUp, inward)
14955
+ return new import_three31.Quaternion().setFromRotationMatrix(
14956
+ new import_three31.Matrix4().makeBasis(localUp.clone().cross(inward).normalize(), localUp, inward)
14594
14957
  );
14595
14958
  }
14596
14959
  function makeWorldToLocal(center) {
14597
- return new import_three30.Matrix4().compose(
14960
+ return new import_three31.Matrix4().compose(
14598
14961
  panoPositionToVector3(center, POLYGON_RADIUS),
14599
14962
  surfaceQuaternion(center),
14600
- new import_three30.Vector3(1, 1, 1)
14963
+ new import_three31.Vector3(1, 1, 1)
14601
14964
  ).invert();
14602
14965
  }
14603
14966
  function projectedPoint(a, b, c, weightB, weightC, radius, worldToLocal) {
@@ -14652,8 +15015,8 @@ function addSubdividedTriangle(positions, indices, a, b, c, worldToLocal, steps)
14652
15015
  }
14653
15016
  function makeFillGeometry(vertices, center) {
14654
15017
  const unwrapped = unwrapPolygonVertices(vertices);
14655
- const contour = unwrapped.map((vertex) => new import_three30.Vector2(vertex.unwrappedYaw, vertex.pitch));
14656
- const triangles = import_three30.ShapeUtils.triangulateShape(contour, []);
15018
+ const contour = unwrapped.map((vertex) => new import_three31.Vector2(vertex.unwrappedYaw, vertex.pitch));
15019
+ const triangles = import_three31.ShapeUtils.triangulateShape(contour, []);
14657
15020
  const positions = [];
14658
15021
  const indices = [];
14659
15022
  const worldToLocal = makeWorldToLocal(center);
@@ -14669,7 +15032,7 @@ function makeFillGeometry(vertices, center) {
14669
15032
  steps
14670
15033
  );
14671
15034
  }
14672
- return new import_three30.BufferGeometry().setAttribute("position", new import_three30.Float32BufferAttribute(positions, 3)).setIndex(indices);
15035
+ return new import_three31.BufferGeometry().setAttribute("position", new import_three31.Float32BufferAttribute(positions, 3)).setIndex(indices);
14673
15036
  }
14674
15037
  function makeStrokePositions(vertices, center) {
14675
15038
  const points = [];
@@ -14724,24 +15087,24 @@ function PolygonHotspot({
14724
15087
  onInvalid,
14725
15088
  ...anchorProps
14726
15089
  }) {
14727
- const issues = (0, import_react51.useMemo)(() => validatePolygonVertices(vertices), [vertices]);
15090
+ const issues = (0, import_react53.useMemo)(() => validatePolygonVertices(vertices), [vertices]);
14728
15091
  const valid = issues.length === 0;
14729
- const center = (0, import_react51.useMemo)(() => valid ? polygonCenter(vertices) : null, [valid, vertices]);
14730
- const fillGeometry = (0, import_react51.useMemo)(
15092
+ const center = (0, import_react53.useMemo)(() => valid ? polygonCenter(vertices) : null, [valid, vertices]);
15093
+ const fillGeometry = (0, import_react53.useMemo)(
14731
15094
  () => valid && center ? makeFillGeometry(vertices, center) : null,
14732
15095
  [center, valid, vertices]
14733
15096
  );
14734
- const strokePoints = (0, import_react51.useMemo)(
15097
+ const strokePoints = (0, import_react53.useMemo)(
14735
15098
  () => valid && center ? makeStrokePositions(vertices, center) : null,
14736
15099
  [center, valid, vertices]
14737
15100
  );
14738
15101
  const resolvedStrokeOpacity = Math.max(0, Math.min(strokeOpacity, 1));
14739
- const startVerticesRef = (0, import_react51.useRef)(null);
15102
+ const startVerticesRef = (0, import_react53.useRef)(null);
14740
15103
  const issuesKey = issues.map((issue) => issue.code).join(",");
14741
- (0, import_react51.useEffect)(() => {
15104
+ (0, import_react53.useEffect)(() => {
14742
15105
  if (!valid) onInvalid?.(issues);
14743
15106
  }, [issues, issuesKey, onInvalid, valid]);
14744
- (0, import_react51.useEffect)(() => () => fillGeometry?.dispose(), [fillGeometry]);
15107
+ (0, import_react53.useEffect)(() => () => fillGeometry?.dispose(), [fillGeometry]);
14745
15108
  if (!valid || !center || !fillGeometry || !strokePoints || strokePoints.length < 2) {
14746
15109
  return null;
14747
15110
  }
@@ -14756,7 +15119,7 @@ function PolygonHotspot({
14756
15119
  startPosition: event.startPosition
14757
15120
  });
14758
15121
  };
14759
- return /* @__PURE__ */ (0, import_jsx_runtime30.jsxs)(
15122
+ return /* @__PURE__ */ (0, import_jsx_runtime31.jsxs)(
14760
15123
  HotspotAnchor,
14761
15124
  {
14762
15125
  ...anchorProps,
@@ -14771,7 +15134,7 @@ function PolygonHotspot({
14771
15134
  draggable,
14772
15135
  interactive,
14773
15136
  useAngularScale: false,
14774
- focusContent: /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(
15137
+ focusContent: /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(
14775
15138
  HotspotStrokeLine,
14776
15139
  {
14777
15140
  color: "#75cbd3",
@@ -14793,17 +15156,17 @@ function PolygonHotspot({
14793
15156
  startVerticesRef.current = null;
14794
15157
  },
14795
15158
  children: [
14796
- /* @__PURE__ */ (0, import_jsx_runtime30.jsx)("mesh", { geometry: fillGeometry, renderOrder, children: /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(
15159
+ /* @__PURE__ */ (0, import_jsx_runtime31.jsx)("mesh", { geometry: fillGeometry, renderOrder, children: /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(
14797
15160
  "meshBasicMaterial",
14798
15161
  {
14799
15162
  color: fill,
14800
15163
  depthWrite: false,
14801
15164
  opacity: Math.max(0, Math.min(fillOpacity, 1)),
14802
- side: import_three30.DoubleSide,
15165
+ side: import_three31.DoubleSide,
14803
15166
  transparent: true
14804
15167
  }
14805
15168
  ) }),
14806
- /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(
15169
+ /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(
14807
15170
  HotspotStrokeLine,
14808
15171
  {
14809
15172
  color: stroke,
@@ -14821,9 +15184,9 @@ function PolygonHotspot({
14821
15184
  }
14822
15185
 
14823
15186
  // src/hotspot/polyline-hotspot.tsx
14824
- var import_react52 = require("react");
14825
- var import_three31 = require("three");
14826
- var import_jsx_runtime31 = require("react/jsx-runtime");
15187
+ var import_react54 = require("react");
15188
+ var import_three32 = require("three");
15189
+ var import_jsx_runtime32 = require("react/jsx-runtime");
14827
15190
  var POLYLINE_RADIUS = 990;
14828
15191
  var MAX_SEGMENT_DEGREES = 7;
14829
15192
  function cloneVertices2(vertices) {
@@ -14848,29 +15211,29 @@ function unwrapVertices(vertices) {
14848
15211
  function polylineCenter(vertices) {
14849
15212
  const sum = vertices.reduce(
14850
15213
  (total, vertex) => total.add(panoPositionToVector3(vertex).normalize()),
14851
- new import_three31.Vector3()
15214
+ new import_three32.Vector3()
14852
15215
  );
14853
15216
  return sum.lengthSq() > 1e-8 ? vector3ToPanoPosition(sum) : normalizePanoPosition(vertices[0]);
14854
15217
  }
14855
15218
  function surfaceQuaternion2(position) {
14856
15219
  const outward = panoPositionToVector3(position).normalize();
14857
15220
  const inward = outward.clone().negate();
14858
- const pitch = import_three31.MathUtils.degToRad(position.pitch);
14859
- const yaw = import_three31.MathUtils.degToRad(position.yaw);
14860
- const localUp = new import_three31.Vector3(
15221
+ const pitch = import_three32.MathUtils.degToRad(position.pitch);
15222
+ const yaw = import_three32.MathUtils.degToRad(position.yaw);
15223
+ const localUp = new import_three32.Vector3(
14861
15224
  -Math.sin(pitch) * Math.sin(yaw),
14862
15225
  Math.cos(pitch),
14863
15226
  Math.sin(pitch) * Math.cos(yaw)
14864
15227
  ).normalize();
14865
- return new import_three31.Quaternion().setFromRotationMatrix(
14866
- new import_three31.Matrix4().makeBasis(localUp.clone().cross(inward).normalize(), localUp, inward)
15228
+ return new import_three32.Quaternion().setFromRotationMatrix(
15229
+ new import_three32.Matrix4().makeBasis(localUp.clone().cross(inward).normalize(), localUp, inward)
14867
15230
  );
14868
15231
  }
14869
15232
  function makeWorldToLocal2(center) {
14870
- return new import_three31.Matrix4().compose(
15233
+ return new import_three32.Matrix4().compose(
14871
15234
  panoPositionToVector3(center, POLYLINE_RADIUS),
14872
15235
  surfaceQuaternion2(center),
14873
- new import_three31.Vector3(1, 1, 1)
15236
+ new import_three32.Vector3(1, 1, 1)
14874
15237
  ).invert();
14875
15238
  }
14876
15239
  function subdivisionSteps(vertices) {
@@ -14885,7 +15248,7 @@ function subdivisionSteps(vertices) {
14885
15248
  }
14886
15249
  return Math.min(
14887
15250
  8,
14888
- Math.max(1, Math.ceil(import_three31.MathUtils.radToDeg(maxAngle) / MAX_SEGMENT_DEGREES))
15251
+ Math.max(1, Math.ceil(import_three32.MathUtils.radToDeg(maxAngle) / MAX_SEGMENT_DEGREES))
14889
15252
  );
14890
15253
  }
14891
15254
  function makeLinePositions(vertices, center) {
@@ -14940,16 +15303,16 @@ function PolylineHotspot({
14940
15303
  onInvalid,
14941
15304
  ...anchorProps
14942
15305
  }) {
14943
- const issues = (0, import_react52.useMemo)(() => validatePolylineVertices(vertices), [vertices]);
15306
+ const issues = (0, import_react54.useMemo)(() => validatePolylineVertices(vertices), [vertices]);
14944
15307
  const valid = issues.length === 0;
14945
- const center = (0, import_react52.useMemo)(() => valid ? polylineCenter(vertices) : null, [valid, vertices]);
14946
- const linePoints = (0, import_react52.useMemo)(
15308
+ const center = (0, import_react54.useMemo)(() => valid ? polylineCenter(vertices) : null, [valid, vertices]);
15309
+ const linePoints = (0, import_react54.useMemo)(
14947
15310
  () => valid && center ? makeLinePositions(vertices, center) : null,
14948
15311
  [center, valid, vertices]
14949
15312
  );
14950
15313
  const opacity = Math.max(0, Math.min(strokeOpacity, 1));
14951
- const startVerticesRef = (0, import_react52.useRef)(null);
14952
- (0, import_react52.useEffect)(() => {
15314
+ const startVerticesRef = (0, import_react54.useRef)(null);
15315
+ (0, import_react54.useEffect)(() => {
14953
15316
  if (!valid) onInvalid?.(issues);
14954
15317
  }, [issues, onInvalid, valid]);
14955
15318
  if (!valid || !center || !linePoints || linePoints.length < 2) return null;
@@ -14963,7 +15326,7 @@ function PolylineHotspot({
14963
15326
  startPosition: event.startPosition
14964
15327
  });
14965
15328
  };
14966
- return /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(
15329
+ return /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(
14967
15330
  HotspotAnchor,
14968
15331
  {
14969
15332
  ...anchorProps,
@@ -14977,7 +15340,7 @@ function PolylineHotspot({
14977
15340
  renderOrder,
14978
15341
  draggable,
14979
15342
  useAngularScale: false,
14980
- focusContent: /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(
15343
+ focusContent: /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(
14981
15344
  HotspotStrokeLine,
14982
15345
  {
14983
15346
  color: "#75cbd3",
@@ -14998,7 +15361,7 @@ function PolylineHotspot({
14998
15361
  emitVerticesChange(event, onDragEnd);
14999
15362
  startVerticesRef.current = null;
15000
15363
  },
15001
- children: /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(
15364
+ children: /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(
15002
15365
  HotspotStrokeLine,
15003
15366
  {
15004
15367
  color: stroke,
@@ -15015,9 +15378,9 @@ function PolylineHotspot({
15015
15378
  }
15016
15379
 
15017
15380
  // src/hotspot/graphic-hotspot.tsx
15018
- var import_react53 = require("react");
15019
- var import_three32 = require("three");
15020
- var import_jsx_runtime32 = require("react/jsx-runtime");
15381
+ var import_react55 = require("react");
15382
+ var import_three33 = require("three");
15383
+ var import_jsx_runtime33 = require("react/jsx-runtime");
15021
15384
  var GRAPHIC_TEXTURE_SIZE = 512;
15022
15385
  function resolveStrokeWidth(value) {
15023
15386
  return Number.isFinite(value) ? Math.max(value, 0) : 8;
@@ -15195,23 +15558,23 @@ function createGraphicTexture(graphic, aspectWidth, aspectHeight) {
15195
15558
  throw new Error("Canvas 2D is unavailable for this graphic hotspot.");
15196
15559
  }
15197
15560
  drawGraphic(context, graphic, aspectWidth, aspectHeight);
15198
- const texture = new import_three32.CanvasTexture(canvas);
15199
- texture.colorSpace = import_three32.SRGBColorSpace;
15200
- texture.wrapS = import_three32.ClampToEdgeWrapping;
15201
- texture.wrapT = import_three32.ClampToEdgeWrapping;
15202
- texture.magFilter = import_three32.LinearFilter;
15203
- texture.minFilter = import_three32.LinearMipmapLinearFilter;
15561
+ const texture = new import_three33.CanvasTexture(canvas);
15562
+ texture.colorSpace = import_three33.SRGBColorSpace;
15563
+ texture.wrapS = import_three33.ClampToEdgeWrapping;
15564
+ texture.wrapT = import_three33.ClampToEdgeWrapping;
15565
+ texture.magFilter = import_three33.LinearFilter;
15566
+ texture.minFilter = import_three33.LinearMipmapLinearFilter;
15204
15567
  texture.generateMipmaps = true;
15205
15568
  texture.needsUpdate = true;
15206
15569
  return texture;
15207
15570
  }
15208
15571
  function useGraphicTexture(graphic, aspectWidth, aspectHeight, onLoad, onError) {
15209
- const [texture, setTexture] = (0, import_react53.useState)(null);
15210
- const onLoadRef = (0, import_react53.useRef)(onLoad);
15211
- const onErrorRef = (0, import_react53.useRef)(onError);
15572
+ const [texture, setTexture] = (0, import_react55.useState)(null);
15573
+ const onLoadRef = (0, import_react55.useRef)(onLoad);
15574
+ const onErrorRef = (0, import_react55.useRef)(onError);
15212
15575
  onLoadRef.current = onLoad;
15213
15576
  onErrorRef.current = onError;
15214
- (0, import_react53.useEffect)(() => {
15577
+ (0, import_react55.useEffect)(() => {
15215
15578
  let nextTexture = null;
15216
15579
  try {
15217
15580
  nextTexture = createGraphicTexture(graphic, aspectWidth, aspectHeight);
@@ -15237,22 +15600,22 @@ function CanvasGraphicHotspot({
15237
15600
  ...anchorProps
15238
15601
  }) {
15239
15602
  const texture = useGraphicTexture(graphic, width, height, onLoad, onError);
15240
- return /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(HotspotAnchor, { ...anchorProps, height, width, children: /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(HotspotPlane, { map: texture, opacity }) });
15603
+ return /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(HotspotAnchor, { ...anchorProps, height, width, children: /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(HotspotPlane, { map: texture, opacity }) });
15241
15604
  }
15242
15605
  function GraphicHotspot(props) {
15243
15606
  const { graphic, ...restProps } = props;
15244
15607
  if (graphic.kind === "svg") {
15245
15608
  const imageProps = restProps;
15246
- return /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(ImageHotspot, { ...imageProps, src: graphic.src });
15609
+ return /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(ImageHotspot, { ...imageProps, src: graphic.src });
15247
15610
  }
15248
- return /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(CanvasGraphicHotspot, { ...restProps, graphic });
15611
+ return /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(CanvasGraphicHotspot, { ...restProps, graphic });
15249
15612
  }
15250
15613
 
15251
15614
  // src/hotspot/sequence-hotspot.tsx
15252
- var import_fiber27 = require("@react-three/fiber");
15253
- var import_react54 = require("react");
15254
- var import_three33 = require("three");
15255
- var import_jsx_runtime33 = require("react/jsx-runtime");
15615
+ var import_fiber28 = require("@react-three/fiber");
15616
+ var import_react56 = require("react");
15617
+ var import_three34 = require("three");
15618
+ var import_jsx_runtime34 = require("react/jsx-runtime");
15256
15619
  var DEFAULT_SEQUENCE_FPS = 12;
15257
15620
  function resolveFps(value) {
15258
15621
  return Number.isFinite(value) && value > 0 ? value : DEFAULT_SEQUENCE_FPS;
@@ -15266,13 +15629,13 @@ function useSpriteTexture({
15266
15629
  onError,
15267
15630
  onLoadProgress
15268
15631
  }) {
15269
- const gl = (0, import_fiber27.useThree)((state) => state.gl);
15270
- const [texture, setTexture] = (0, import_react54.useState)(null);
15271
- const onErrorRef = (0, import_react54.useRef)(onError);
15272
- const onLoadProgressRef = (0, import_react54.useRef)(onLoadProgress);
15632
+ const gl = (0, import_fiber28.useThree)((state) => state.gl);
15633
+ const [texture, setTexture] = (0, import_react56.useState)(null);
15634
+ const onErrorRef = (0, import_react56.useRef)(onError);
15635
+ const onLoadProgressRef = (0, import_react56.useRef)(onLoadProgress);
15273
15636
  onErrorRef.current = onError;
15274
15637
  onLoadProgressRef.current = onLoadProgress;
15275
- (0, import_react54.useEffect)(() => {
15638
+ (0, import_react56.useEffect)(() => {
15276
15639
  let active = true;
15277
15640
  setTexture(null);
15278
15641
  if (!src) {
@@ -15281,7 +15644,7 @@ function useSpriteTexture({
15281
15644
  active = false;
15282
15645
  };
15283
15646
  }
15284
- const loader = new import_three33.TextureLoader();
15647
+ const loader = new import_three34.TextureLoader();
15285
15648
  loader.load(
15286
15649
  src,
15287
15650
  (loadedTexture) => {
@@ -15289,11 +15652,11 @@ function useSpriteTexture({
15289
15652
  loadedTexture.dispose();
15290
15653
  return;
15291
15654
  }
15292
- loadedTexture.colorSpace = import_three33.SRGBColorSpace;
15293
- loadedTexture.wrapS = import_three33.ClampToEdgeWrapping;
15294
- loadedTexture.wrapT = import_three33.ClampToEdgeWrapping;
15295
- loadedTexture.magFilter = import_three33.LinearFilter;
15296
- loadedTexture.minFilter = import_three33.LinearMipmapLinearFilter;
15655
+ loadedTexture.colorSpace = import_three34.SRGBColorSpace;
15656
+ loadedTexture.wrapS = import_three34.ClampToEdgeWrapping;
15657
+ loadedTexture.wrapT = import_three34.ClampToEdgeWrapping;
15658
+ loadedTexture.magFilter = import_three34.LinearFilter;
15659
+ loadedTexture.minFilter = import_three34.LinearMipmapLinearFilter;
15297
15660
  loadedTexture.generateMipmaps = true;
15298
15661
  loadedTexture.anisotropy = gl.capabilities.getMaxAnisotropy();
15299
15662
  loadedTexture.needsUpdate = true;
@@ -15313,7 +15676,7 @@ function useSpriteTexture({
15313
15676
  active = false;
15314
15677
  };
15315
15678
  }, [gl, id, src]);
15316
- (0, import_react54.useEffect)(
15679
+ (0, import_react56.useEffect)(
15317
15680
  () => () => {
15318
15681
  texture?.dispose();
15319
15682
  },
@@ -15342,24 +15705,24 @@ function SequenceHotspot({
15342
15705
  const texture = useSpriteTexture({ id, src, onError, onLoadProgress });
15343
15706
  const frameCount = resolveFrameCount(requestedFrameCount);
15344
15707
  const safeFps = resolveFps(fps);
15345
- const [frameIndex, setFrameIndex] = (0, import_react54.useState)(0);
15346
- const elapsedRef = (0, import_react54.useRef)(0);
15347
- const frameIndexRef = (0, import_react54.useRef)(0);
15348
- const endedRef = (0, import_react54.useRef)(false);
15349
- const lastPlaybackStateRef = (0, import_react54.useRef)(null);
15350
- const onFrameChangeRef = (0, import_react54.useRef)(onFrameChange);
15351
- const onPlaybackStateChangeRef = (0, import_react54.useRef)(onPlaybackStateChange);
15352
- const onEndedRef = (0, import_react54.useRef)(onEnded);
15708
+ const [frameIndex, setFrameIndex] = (0, import_react56.useState)(0);
15709
+ const elapsedRef = (0, import_react56.useRef)(0);
15710
+ const frameIndexRef = (0, import_react56.useRef)(0);
15711
+ const endedRef = (0, import_react56.useRef)(false);
15712
+ const lastPlaybackStateRef = (0, import_react56.useRef)(null);
15713
+ const onFrameChangeRef = (0, import_react56.useRef)(onFrameChange);
15714
+ const onPlaybackStateChangeRef = (0, import_react56.useRef)(onPlaybackStateChange);
15715
+ const onEndedRef = (0, import_react56.useRef)(onEnded);
15353
15716
  onFrameChangeRef.current = onFrameChange;
15354
15717
  onPlaybackStateChangeRef.current = onPlaybackStateChange;
15355
15718
  onEndedRef.current = onEnded;
15356
- (0, import_react54.useEffect)(() => {
15719
+ (0, import_react56.useEffect)(() => {
15357
15720
  elapsedRef.current = 0;
15358
15721
  frameIndexRef.current = 0;
15359
15722
  endedRef.current = false;
15360
15723
  setFrameIndex(0);
15361
15724
  }, [frameCount, frameDirection, src]);
15362
- (0, import_react54.useEffect)(() => {
15725
+ (0, import_react56.useEffect)(() => {
15363
15726
  if (!texture) {
15364
15727
  return;
15365
15728
  }
@@ -15373,13 +15736,13 @@ function SequenceHotspot({
15373
15736
  );
15374
15737
  texture.needsUpdate = true;
15375
15738
  }, [frameCount, frameDirection, frameIndex, texture]);
15376
- (0, import_react54.useEffect)(() => {
15739
+ (0, import_react56.useEffect)(() => {
15377
15740
  if (!texture) {
15378
15741
  return;
15379
15742
  }
15380
15743
  onFrameChangeRef.current?.({ id, index: 0, src });
15381
15744
  }, [id, src, texture]);
15382
- (0, import_react54.useEffect)(() => {
15745
+ (0, import_react56.useEffect)(() => {
15383
15746
  if (!texture) {
15384
15747
  return;
15385
15748
  }
@@ -15398,7 +15761,7 @@ function SequenceHotspot({
15398
15761
  onPlaybackStateChangeRef.current?.(nextState);
15399
15762
  }
15400
15763
  }, [playing, texture]);
15401
- (0, import_fiber27.useFrame)((_, deltaSeconds) => {
15764
+ (0, import_fiber28.useFrame)((_, deltaSeconds) => {
15402
15765
  if (!texture || !playing || endedRef.current) {
15403
15766
  return;
15404
15767
  }
@@ -15428,14 +15791,14 @@ function SequenceHotspot({
15428
15791
  onFrameChangeRef.current?.({ id, index: nextIndex, src });
15429
15792
  }
15430
15793
  });
15431
- return /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(HotspotAnchor, { ...anchorProps, id, height, width, children: /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(HotspotPlane, { map: texture, opacity }) });
15794
+ return /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(HotspotAnchor, { ...anchorProps, id, height, width, children: /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(HotspotPlane, { map: texture, opacity }) });
15432
15795
  }
15433
15796
 
15434
15797
  // src/hotspot/video-hotspot.tsx
15435
- var import_fiber28 = require("@react-three/fiber");
15436
- var import_react55 = require("react");
15437
- var import_three34 = require("three");
15438
- var import_jsx_runtime34 = require("react/jsx-runtime");
15798
+ var import_fiber29 = require("@react-three/fiber");
15799
+ var import_react57 = require("react");
15800
+ var import_three35 = require("three");
15801
+ var import_jsx_runtime35 = require("react/jsx-runtime");
15439
15802
  function clampVolume2(volume) {
15440
15803
  if (!Number.isFinite(volume)) {
15441
15804
  return 1;
@@ -15443,11 +15806,11 @@ function clampVolume2(volume) {
15443
15806
  return Math.max(0, Math.min(volume, 1));
15444
15807
  }
15445
15808
  function usePosterTexture2(id, poster, onError) {
15446
- const gl = (0, import_fiber28.useThree)((state) => state.gl);
15447
- const [texture, setTexture] = (0, import_react55.useState)(null);
15448
- const onErrorRef = (0, import_react55.useRef)(onError);
15809
+ const gl = (0, import_fiber29.useThree)((state) => state.gl);
15810
+ const [texture, setTexture] = (0, import_react57.useState)(null);
15811
+ const onErrorRef = (0, import_react57.useRef)(onError);
15449
15812
  onErrorRef.current = onError;
15450
- (0, import_react55.useEffect)(() => {
15813
+ (0, import_react57.useEffect)(() => {
15451
15814
  let active = true;
15452
15815
  setTexture(null);
15453
15816
  if (!poster) {
@@ -15455,7 +15818,7 @@ function usePosterTexture2(id, poster, onError) {
15455
15818
  active = false;
15456
15819
  };
15457
15820
  }
15458
- const loader = new import_three34.TextureLoader();
15821
+ const loader = new import_three35.TextureLoader();
15459
15822
  loader.load(
15460
15823
  poster,
15461
15824
  (loadedTexture) => {
@@ -15463,11 +15826,11 @@ function usePosterTexture2(id, poster, onError) {
15463
15826
  loadedTexture.dispose();
15464
15827
  return;
15465
15828
  }
15466
- loadedTexture.colorSpace = import_three34.SRGBColorSpace;
15467
- loadedTexture.wrapS = import_three34.ClampToEdgeWrapping;
15468
- loadedTexture.wrapT = import_three34.ClampToEdgeWrapping;
15469
- loadedTexture.magFilter = import_three34.LinearFilter;
15470
- loadedTexture.minFilter = import_three34.LinearMipmapLinearFilter;
15829
+ loadedTexture.colorSpace = import_three35.SRGBColorSpace;
15830
+ loadedTexture.wrapS = import_three35.ClampToEdgeWrapping;
15831
+ loadedTexture.wrapT = import_three35.ClampToEdgeWrapping;
15832
+ loadedTexture.magFilter = import_three35.LinearFilter;
15833
+ loadedTexture.minFilter = import_three35.LinearMipmapLinearFilter;
15471
15834
  loadedTexture.generateMipmaps = true;
15472
15835
  loadedTexture.anisotropy = gl.capabilities.getMaxAnisotropy();
15473
15836
  loadedTexture.needsUpdate = true;
@@ -15484,7 +15847,7 @@ function usePosterTexture2(id, poster, onError) {
15484
15847
  active = false;
15485
15848
  };
15486
15849
  }, [gl, id, poster]);
15487
- (0, import_react55.useEffect)(
15850
+ (0, import_react57.useEffect)(
15488
15851
  () => () => {
15489
15852
  texture?.dispose();
15490
15853
  },
@@ -15502,14 +15865,14 @@ function useVideoResource({
15502
15865
  poster,
15503
15866
  src
15504
15867
  }) {
15505
- const [resource, setResource] = (0, import_react55.useState)(null);
15506
- const onEndedRef = (0, import_react55.useRef)(onEnded);
15507
- const onErrorRef = (0, import_react55.useRef)(onError);
15508
- const onPlaybackStateChangeRef = (0, import_react55.useRef)(onPlaybackStateChange);
15868
+ const [resource, setResource] = (0, import_react57.useState)(null);
15869
+ const onEndedRef = (0, import_react57.useRef)(onEnded);
15870
+ const onErrorRef = (0, import_react57.useRef)(onError);
15871
+ const onPlaybackStateChangeRef = (0, import_react57.useRef)(onPlaybackStateChange);
15509
15872
  onEndedRef.current = onEnded;
15510
15873
  onErrorRef.current = onError;
15511
15874
  onPlaybackStateChangeRef.current = onPlaybackStateChange;
15512
- (0, import_react55.useEffect)(() => {
15875
+ (0, import_react57.useEffect)(() => {
15513
15876
  if (!src) {
15514
15877
  setResource(null);
15515
15878
  return;
@@ -15526,12 +15889,12 @@ function useVideoResource({
15526
15889
  video.setAttribute("webkit-playsinline", "true");
15527
15890
  }
15528
15891
  video.poster = poster ?? "";
15529
- const texture = new import_three34.VideoTexture(video);
15530
- texture.colorSpace = import_three34.SRGBColorSpace;
15531
- texture.wrapS = import_three34.ClampToEdgeWrapping;
15532
- texture.wrapT = import_three34.ClampToEdgeWrapping;
15533
- texture.magFilter = import_three34.LinearFilter;
15534
- texture.minFilter = import_three34.LinearFilter;
15892
+ const texture = new import_three35.VideoTexture(video);
15893
+ texture.colorSpace = import_three35.SRGBColorSpace;
15894
+ texture.wrapS = import_three35.ClampToEdgeWrapping;
15895
+ texture.wrapT = import_three35.ClampToEdgeWrapping;
15896
+ texture.magFilter = import_three35.LinearFilter;
15897
+ texture.minFilter = import_three35.LinearFilter;
15535
15898
  texture.generateMipmaps = false;
15536
15899
  const notifyState = (state) => {
15537
15900
  if (active) {
@@ -15616,11 +15979,11 @@ function VideoHotspot({
15616
15979
  src
15617
15980
  });
15618
15981
  const posterTexture = usePosterTexture2(id, poster, onError);
15619
- const onPlaybackErrorRef = (0, import_react55.useRef)(onPlaybackError);
15620
- const onPlaybackStateChangeRef = (0, import_react55.useRef)(onPlaybackStateChange);
15982
+ const onPlaybackErrorRef = (0, import_react57.useRef)(onPlaybackError);
15983
+ const onPlaybackStateChangeRef = (0, import_react57.useRef)(onPlaybackStateChange);
15621
15984
  onPlaybackErrorRef.current = onPlaybackError;
15622
15985
  onPlaybackStateChangeRef.current = onPlaybackStateChange;
15623
- (0, import_react55.useEffect)(() => {
15986
+ (0, import_react57.useEffect)(() => {
15624
15987
  if (!resource) {
15625
15988
  return;
15626
15989
  }
@@ -15637,7 +16000,7 @@ function VideoHotspot({
15637
16000
  }
15638
16001
  resource.video.preload = preload;
15639
16002
  }, [loop, muted, playsInline, preload, resource, volume]);
15640
- (0, import_react55.useEffect)(() => {
16003
+ (0, import_react57.useEffect)(() => {
15641
16004
  if (!resource) {
15642
16005
  return;
15643
16006
  }
@@ -15660,14 +16023,14 @@ function VideoHotspot({
15660
16023
  };
15661
16024
  }, [playing, resource]);
15662
16025
  const activeTexture = resource?.ready ? resource.texture : posterTexture;
15663
- return /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(HotspotAnchor, { ...anchorProps, id, height, width, children: /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(HotspotPlane, { map: activeTexture, opacity }) });
16026
+ return /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(HotspotAnchor, { ...anchorProps, id, height, width, children: /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(HotspotPlane, { map: activeTexture, opacity }) });
15664
16027
  }
15665
16028
 
15666
16029
  // src/hotspot/audio-hotspot.tsx
15667
- var import_fiber29 = require("@react-three/fiber");
15668
- var import_react56 = require("react");
15669
- var import_three35 = require("three");
15670
- var import_jsx_runtime35 = require("react/jsx-runtime");
16030
+ var import_fiber30 = require("@react-three/fiber");
16031
+ var import_react58 = require("react");
16032
+ var import_three36 = require("three");
16033
+ var import_jsx_runtime36 = require("react/jsx-runtime");
15671
16034
  var SPEAKER_TEXTURE_SIZE = 512;
15672
16035
  function paintSpeakerBody(context, center) {
15673
16036
  context.fillStyle = "#f5fbfc";
@@ -15720,19 +16083,19 @@ function createSpeakerTexture(state) {
15720
16083
  return exhaustive;
15721
16084
  }
15722
16085
  }
15723
- const texture = new import_three35.CanvasTexture(canvas);
15724
- texture.colorSpace = import_three35.SRGBColorSpace;
15725
- texture.wrapS = import_three35.ClampToEdgeWrapping;
15726
- texture.wrapT = import_three35.ClampToEdgeWrapping;
15727
- texture.magFilter = import_three35.LinearFilter;
15728
- texture.minFilter = import_three35.LinearMipmapLinearFilter;
16086
+ const texture = new import_three36.CanvasTexture(canvas);
16087
+ texture.colorSpace = import_three36.SRGBColorSpace;
16088
+ texture.wrapS = import_three36.ClampToEdgeWrapping;
16089
+ texture.wrapT = import_three36.ClampToEdgeWrapping;
16090
+ texture.magFilter = import_three36.LinearFilter;
16091
+ texture.minFilter = import_three36.LinearMipmapLinearFilter;
15729
16092
  texture.generateMipmaps = true;
15730
16093
  texture.needsUpdate = true;
15731
16094
  return texture;
15732
16095
  }
15733
16096
  function useSpeakerTextures(enabled) {
15734
- const [textures, setTextures] = (0, import_react56.useState)({ playing: null, stopped: null });
15735
- (0, import_react56.useEffect)(() => {
16097
+ const [textures, setTextures] = (0, import_react58.useState)({ playing: null, stopped: null });
16098
+ (0, import_react58.useEffect)(() => {
15736
16099
  if (!enabled) {
15737
16100
  setTextures({ playing: null, stopped: null });
15738
16101
  return;
@@ -15748,11 +16111,11 @@ function useSpeakerTextures(enabled) {
15748
16111
  return textures;
15749
16112
  }
15750
16113
  function useIconTexture(icon, enabled, onError, id) {
15751
- const gl = (0, import_fiber29.useThree)((state) => state.gl);
15752
- const [texture, setTexture] = (0, import_react56.useState)(null);
15753
- const onErrorRef = (0, import_react56.useRef)(onError);
16114
+ const gl = (0, import_fiber30.useThree)((state) => state.gl);
16115
+ const [texture, setTexture] = (0, import_react58.useState)(null);
16116
+ const onErrorRef = (0, import_react58.useRef)(onError);
15754
16117
  onErrorRef.current = onError;
15755
- (0, import_react56.useEffect)(() => {
16118
+ (0, import_react58.useEffect)(() => {
15756
16119
  let active = true;
15757
16120
  setTexture(null);
15758
16121
  if (!enabled || !icon) {
@@ -15760,7 +16123,7 @@ function useIconTexture(icon, enabled, onError, id) {
15760
16123
  active = false;
15761
16124
  };
15762
16125
  }
15763
- const loader = new import_three35.TextureLoader();
16126
+ const loader = new import_three36.TextureLoader();
15764
16127
  loader.load(
15765
16128
  icon,
15766
16129
  (loadedTexture) => {
@@ -15768,11 +16131,11 @@ function useIconTexture(icon, enabled, onError, id) {
15768
16131
  loadedTexture.dispose();
15769
16132
  return;
15770
16133
  }
15771
- loadedTexture.colorSpace = import_three35.SRGBColorSpace;
15772
- loadedTexture.wrapS = import_three35.ClampToEdgeWrapping;
15773
- loadedTexture.wrapT = import_three35.ClampToEdgeWrapping;
15774
- loadedTexture.magFilter = import_three35.LinearFilter;
15775
- loadedTexture.minFilter = import_three35.LinearMipmapLinearFilter;
16134
+ loadedTexture.colorSpace = import_three36.SRGBColorSpace;
16135
+ loadedTexture.wrapS = import_three36.ClampToEdgeWrapping;
16136
+ loadedTexture.wrapT = import_three36.ClampToEdgeWrapping;
16137
+ loadedTexture.magFilter = import_three36.LinearFilter;
16138
+ loadedTexture.minFilter = import_three36.LinearMipmapLinearFilter;
15776
16139
  loadedTexture.generateMipmaps = true;
15777
16140
  loadedTexture.anisotropy = gl.capabilities.getMaxAnisotropy();
15778
16141
  loadedTexture.needsUpdate = true;
@@ -15789,7 +16152,7 @@ function useIconTexture(icon, enabled, onError, id) {
15789
16152
  active = false;
15790
16153
  };
15791
16154
  }, [enabled, gl, icon, id]);
15792
- (0, import_react56.useEffect)(
16155
+ (0, import_react58.useEffect)(
15793
16156
  () => () => {
15794
16157
  texture?.dispose();
15795
16158
  },
@@ -15808,13 +16171,13 @@ function useAudioHowl({
15808
16171
  playing,
15809
16172
  src
15810
16173
  }) {
15811
- const [howl, setHowl] = (0, import_react56.useState)(null);
15812
- const playingRef = (0, import_react56.useRef)(playing);
15813
- const loopRef = (0, import_react56.useRef)(loop ?? false);
15814
- const onEndedRef = (0, import_react56.useRef)(onEnded);
15815
- const onErrorRef = (0, import_react56.useRef)(onError);
15816
- const onPlaybackErrorRef = (0, import_react56.useRef)(onPlaybackError);
15817
- const onPlaybackStateChangeRef = (0, import_react56.useRef)(onPlaybackStateChange);
16174
+ const [howl, setHowl] = (0, import_react58.useState)(null);
16175
+ const playingRef = (0, import_react58.useRef)(playing);
16176
+ const loopRef = (0, import_react58.useRef)(loop ?? false);
16177
+ const onEndedRef = (0, import_react58.useRef)(onEnded);
16178
+ const onErrorRef = (0, import_react58.useRef)(onError);
16179
+ const onPlaybackErrorRef = (0, import_react58.useRef)(onPlaybackError);
16180
+ const onPlaybackStateChangeRef = (0, import_react58.useRef)(onPlaybackStateChange);
15818
16181
  playingRef.current = playing;
15819
16182
  loopRef.current = loop ?? false;
15820
16183
  onEndedRef.current = onEnded;
@@ -15822,7 +16185,7 @@ function useAudioHowl({
15822
16185
  onPlaybackErrorRef.current = onPlaybackError;
15823
16186
  onPlaybackStateChangeRef.current = onPlaybackStateChange;
15824
16187
  const sourcesKey = sourceList(src).join("\0");
15825
- (0, import_react56.useEffect)(() => {
16188
+ (0, import_react58.useEffect)(() => {
15826
16189
  const sources = sourcesKey.length > 0 ? sourcesKey.split("\0") : [];
15827
16190
  if (sources.length === 0) {
15828
16191
  setHowl(null);
@@ -15859,7 +16222,7 @@ function useAudioHowl({
15859
16222
  handle.dispose();
15860
16223
  };
15861
16224
  }, [crossOrigin, id, sourcesKey]);
15862
- (0, import_react56.useEffect)(() => {
16225
+ (0, import_react58.useEffect)(() => {
15863
16226
  howl?.loop(loop ?? false);
15864
16227
  }, [howl, loop]);
15865
16228
  return howl;
@@ -15887,7 +16250,7 @@ function AudioHotspot({
15887
16250
  ...anchorProps
15888
16251
  }) {
15889
16252
  usePanoMediaActivationIntent(playing);
15890
- const camera = (0, import_fiber29.useThree)((state) => state.camera);
16253
+ const camera = (0, import_fiber30.useThree)((state) => state.camera);
15891
16254
  const howl = useAudioHowl({
15892
16255
  crossOrigin,
15893
16256
  id,
@@ -15903,15 +16266,15 @@ function AudioHotspot({
15903
16266
  const stoppedIconTexture = useIconTexture(icon, marker, onError, id);
15904
16267
  const playingIconTexture = useIconTexture(playingIcon, marker, onError, id);
15905
16268
  const markerTexture = playing ? playingIconTexture ?? stoppedIconTexture ?? speakerTextures.playing : stoppedIconTexture ?? speakerTextures.stopped;
15906
- const playingRef = (0, import_react56.useRef)(playing);
16269
+ const playingRef = (0, import_react58.useRef)(playing);
15907
16270
  playingRef.current = playing;
15908
- const mutedRef = (0, import_react56.useRef)(muted);
15909
- const volumeRef = (0, import_react56.useRef)(volume);
15910
- const rangeRef = (0, import_react56.useRef)(range);
16271
+ const mutedRef = (0, import_react58.useRef)(muted);
16272
+ const volumeRef = (0, import_react58.useRef)(volume);
16273
+ const rangeRef = (0, import_react58.useRef)(range);
15911
16274
  mutedRef.current = muted;
15912
16275
  volumeRef.current = volume;
15913
16276
  rangeRef.current = range;
15914
- (0, import_react56.useEffect)(() => {
16277
+ (0, import_react58.useEffect)(() => {
15915
16278
  if (!howl) {
15916
16279
  return;
15917
16280
  }
@@ -15921,7 +16284,7 @@ function AudioHotspot({
15921
16284
  }
15922
16285
  howl.play();
15923
16286
  }, [howl, playing]);
15924
- (0, import_react56.useEffect)(() => {
16287
+ (0, import_react58.useEffect)(() => {
15925
16288
  if (!howl || !pauseWhenHidden) {
15926
16289
  return;
15927
16290
  }
@@ -15939,7 +16302,7 @@ function AudioHotspot({
15939
16302
  document.removeEventListener("visibilitychange", handleVisibility);
15940
16303
  };
15941
16304
  }, [howl, pauseWhenHidden]);
15942
- (0, import_fiber29.useFrame)(() => {
16305
+ (0, import_fiber30.useFrame)(() => {
15943
16306
  if (!howl) {
15944
16307
  return;
15945
16308
  }
@@ -15952,13 +16315,13 @@ function AudioHotspot({
15952
16315
  howl.mute(mutedRef.current);
15953
16316
  howl.volume(clampAudioVolume(volumeRef.current) * spatial.gain);
15954
16317
  });
15955
- return /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(HotspotAnchor, { ...anchorProps, id, height, width, children: marker ? /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(HotspotPlane, { map: markerTexture, opacity }) : null });
16318
+ return /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(HotspotAnchor, { ...anchorProps, id, height, width, children: marker ? /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(HotspotPlane, { map: markerTexture, opacity }) : null });
15956
16319
  }
15957
16320
 
15958
16321
  // src/hotspot/text-hotspot.tsx
15959
- var import_react57 = require("react");
15960
- var import_three36 = require("three");
15961
- var import_jsx_runtime36 = require("react/jsx-runtime");
16322
+ var import_react59 = require("react");
16323
+ var import_three37 = require("three");
16324
+ var import_jsx_runtime37 = require("react/jsx-runtime");
15962
16325
  var TEXT_TEXTURE_LONG_SIDE = 1024;
15963
16326
  var DEFAULT_FONT_FAMILY = "system-ui, sans-serif";
15964
16327
  var DEFAULT_FONT_SIZE = 96;
@@ -16167,23 +16530,23 @@ function createTextTexture(text, width, height, style) {
16167
16530
  throw new Error("Canvas 2D is unavailable for this text hotspot.");
16168
16531
  }
16169
16532
  drawTextHotspot(context, canvasWidth, canvasHeight, text, style);
16170
- const texture = new import_three36.CanvasTexture(canvas);
16171
- texture.colorSpace = import_three36.SRGBColorSpace;
16172
- texture.wrapS = import_three36.ClampToEdgeWrapping;
16173
- texture.wrapT = import_three36.ClampToEdgeWrapping;
16174
- texture.magFilter = import_three36.LinearFilter;
16175
- texture.minFilter = import_three36.LinearMipmapLinearFilter;
16533
+ const texture = new import_three37.CanvasTexture(canvas);
16534
+ texture.colorSpace = import_three37.SRGBColorSpace;
16535
+ texture.wrapS = import_three37.ClampToEdgeWrapping;
16536
+ texture.wrapT = import_three37.ClampToEdgeWrapping;
16537
+ texture.magFilter = import_three37.LinearFilter;
16538
+ texture.minFilter = import_three37.LinearMipmapLinearFilter;
16176
16539
  texture.generateMipmaps = true;
16177
16540
  texture.needsUpdate = true;
16178
16541
  return texture;
16179
16542
  }
16180
16543
  function useTextTexture(text, width, height, style, onLoad, onError) {
16181
- const [texture, setTexture] = (0, import_react57.useState)(null);
16182
- const onLoadRef = (0, import_react57.useRef)(onLoad);
16183
- const onErrorRef = (0, import_react57.useRef)(onError);
16544
+ const [texture, setTexture] = (0, import_react59.useState)(null);
16545
+ const onLoadRef = (0, import_react59.useRef)(onLoad);
16546
+ const onErrorRef = (0, import_react59.useRef)(onError);
16184
16547
  onLoadRef.current = onLoad;
16185
16548
  onErrorRef.current = onError;
16186
- (0, import_react57.useEffect)(() => {
16549
+ (0, import_react59.useEffect)(() => {
16187
16550
  let cancelled = false;
16188
16551
  let nextTexture = null;
16189
16552
  const run = async () => {
@@ -16276,13 +16639,13 @@ function TextHotspot({
16276
16639
  whiteSpace
16277
16640
  };
16278
16641
  const texture = useTextTexture(text, width, height, style, onLoad, onError);
16279
- return /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(HotspotAnchor, { ...anchorProps, height, width, children: /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(HotspotPlane, { map: texture, opacity }) });
16642
+ return /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(HotspotAnchor, { ...anchorProps, height, width, children: /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(HotspotPlane, { map: texture, opacity }) });
16280
16643
  }
16281
16644
 
16282
16645
  // src/hotspot/iframe-hotspot.tsx
16283
16646
  var import_drei2 = require("@react-three/drei");
16284
- var import_three37 = require("three");
16285
- var import_jsx_runtime37 = require("react/jsx-runtime");
16647
+ var import_three38 = require("three");
16648
+ var import_jsx_runtime38 = require("react/jsx-runtime");
16286
16649
  var IFRAME_LONG_SIDE = 800;
16287
16650
  var CSS3D_DISTANCE_FACTOR = 400;
16288
16651
  var DEFAULT_SANDBOX = "allow-scripts allow-popups allow-forms";
@@ -16339,7 +16702,7 @@ function IframeHotspot({
16339
16702
  interactive,
16340
16703
  pointerEvents
16341
16704
  );
16342
- return /* @__PURE__ */ (0, import_jsx_runtime37.jsxs)(
16705
+ return /* @__PURE__ */ (0, import_jsx_runtime38.jsxs)(
16343
16706
  HotspotAnchor,
16344
16707
  {
16345
16708
  ...anchorProps,
@@ -16348,20 +16711,20 @@ function IframeHotspot({
16348
16711
  pointerEvents,
16349
16712
  width,
16350
16713
  children: [
16351
- /* @__PURE__ */ (0, import_jsx_runtime37.jsxs)("mesh", { children: [
16352
- /* @__PURE__ */ (0, import_jsx_runtime37.jsx)("planeGeometry", { args: [1, 1] }),
16353
- /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(
16714
+ /* @__PURE__ */ (0, import_jsx_runtime38.jsxs)("mesh", { children: [
16715
+ /* @__PURE__ */ (0, import_jsx_runtime38.jsx)("planeGeometry", { args: [1, 1] }),
16716
+ /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(
16354
16717
  "meshBasicMaterial",
16355
16718
  {
16356
16719
  depthWrite: false,
16357
16720
  opacity: 0,
16358
- side: import_three37.DoubleSide,
16721
+ side: import_three38.DoubleSide,
16359
16722
  toneMapped: false,
16360
16723
  transparent: true
16361
16724
  }
16362
16725
  )
16363
16726
  ] }),
16364
- /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(
16727
+ /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(
16365
16728
  import_drei2.Html,
16366
16729
  {
16367
16730
  distanceFactor: CSS3D_DISTANCE_FACTOR,
@@ -16376,7 +16739,7 @@ function IframeHotspot({
16376
16739
  },
16377
16740
  transform: true,
16378
16741
  zIndexRange: [10, 0],
16379
- children: /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(
16742
+ children: /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(
16380
16743
  "iframe",
16381
16744
  {
16382
16745
  allow,