@ericchen1990/pano-view 3.3.0 → 3.4.0

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