@ericchen1990/pano-view 3.2.3 → 3.3.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
@@ -9699,8 +9699,8 @@ function usePanoViewer() {
9699
9699
  }
9700
9700
 
9701
9701
  // src/sphere-tile/sphere-tile.tsx
9702
- var import_fiber15 = require("@react-three/fiber");
9703
- var import_react38 = require("react");
9702
+ var import_fiber16 = require("@react-three/fiber");
9703
+ var import_react39 = require("react");
9704
9704
  var import_three14 = require("three");
9705
9705
 
9706
9706
  // src/asset-url.ts
@@ -9989,6 +9989,9 @@ var TileTextureManager = class {
9989
9989
  this.generation = 0;
9990
9990
  this.options = options;
9991
9991
  }
9992
+ get memoryBudgetBytes() {
9993
+ return this.options.maxBytes;
9994
+ }
9992
9995
  resume() {
9993
9996
  this.disposed = false;
9994
9997
  this.drain();
@@ -10056,7 +10059,7 @@ var TileTextureManager = class {
10056
10059
  this.totalBytes = 0;
10057
10060
  }
10058
10061
  /**
10059
- * Releases textures that are no longer rendered by any Tile instance.
10062
+ * Releases textures that are no longer rendered by any tile source.
10060
10063
  * Scene transitions call this after the outgoing panorama has been
10061
10064
  * snapshotted, so the incoming scene never competes with stale GPU tiles.
10062
10065
  */
@@ -10190,14 +10193,45 @@ var TileTextureManager = class {
10190
10193
  }
10191
10194
  };
10192
10195
 
10193
- // src/tile/texture-hooks.ts
10196
+ // src/tile/texture-manager-context.tsx
10197
+ var import_fiber15 = require("@react-three/fiber");
10194
10198
  var import_react37 = require("react");
10199
+ var import_jsx_runtime15 = require("react/jsx-runtime");
10200
+ var TileTextureManagerContext = (0, import_react37.createContext)(null);
10201
+ function TileTextureManagerProvider({
10202
+ children,
10203
+ maxTextureMemoryMb = 128,
10204
+ maxConcurrentLoads = 4
10205
+ }) {
10206
+ const gl = (0, import_fiber15.useThree)((state) => state.gl);
10207
+ const anisotropy = gl.capabilities.getMaxAnisotropy();
10208
+ const manager = (0, import_react37.useMemo)(
10209
+ () => new TileTextureManager({
10210
+ anisotropy,
10211
+ maxBytes: Math.max(1, maxTextureMemoryMb) * 1024 * 1024,
10212
+ concurrency: Math.max(1, Math.floor(maxConcurrentLoads)),
10213
+ retryCount: 1
10214
+ }),
10215
+ [anisotropy, maxConcurrentLoads, maxTextureMemoryMb]
10216
+ );
10217
+ (0, import_react37.useEffect)(() => {
10218
+ manager.resume();
10219
+ return () => manager.dispose();
10220
+ }, [manager]);
10221
+ return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(TileTextureManagerContext.Provider, { value: manager, children });
10222
+ }
10223
+ function useSharedTileTextureManager() {
10224
+ return (0, import_react37.useContext)(TileTextureManagerContext);
10225
+ }
10226
+
10227
+ // src/tile/texture-hooks.ts
10228
+ var import_react38 = require("react");
10195
10229
  var import_three12 = require("three");
10196
10230
  function usePreviewTexture(url, anisotropy, onError) {
10197
- const [texture, setTexture] = (0, import_react37.useState)(null);
10198
- const onErrorRef = (0, import_react37.useRef)(onError);
10231
+ const [texture, setTexture] = (0, import_react38.useState)(null);
10232
+ const onErrorRef = (0, import_react38.useRef)(onError);
10199
10233
  onErrorRef.current = onError;
10200
- (0, import_react37.useEffect)(() => {
10234
+ (0, import_react38.useEffect)(() => {
10201
10235
  if (!url) {
10202
10236
  setTexture(null);
10203
10237
  return;
@@ -10234,7 +10268,7 @@ function usePreviewTexture(url, anisotropy, onError) {
10234
10268
  active = false;
10235
10269
  };
10236
10270
  }, [anisotropy, url]);
10237
- (0, import_react37.useEffect)(
10271
+ (0, import_react38.useEffect)(
10238
10272
  () => () => {
10239
10273
  texture?.dispose();
10240
10274
  },
@@ -10243,14 +10277,14 @@ function usePreviewTexture(url, anisotropy, onError) {
10243
10277
  return texture;
10244
10278
  }
10245
10279
  function useManagedTexture(manager, key, url, address) {
10246
- const [managedState, setManagedState] = (0, import_react37.useState)(() => ({
10280
+ const [managedState, setManagedState] = (0, import_react38.useState)(() => ({
10247
10281
  manager,
10248
10282
  key,
10249
10283
  url,
10250
10284
  snapshot: manager.getSnapshot(key)
10251
10285
  }));
10252
10286
  const snapshot = managedState.manager === manager && managedState.key === key && managedState.url === url ? managedState.snapshot : manager.getSnapshot(key);
10253
- (0, import_react37.useEffect)(
10287
+ (0, import_react38.useEffect)(
10254
10288
  () => manager.acquire(key, url, address, (nextSnapshot) => {
10255
10289
  setManagedState({
10256
10290
  manager,
@@ -10392,14 +10426,14 @@ function preferredSphereLevel(levels, height, dpr, verticalFov) {
10392
10426
  }
10393
10427
 
10394
10428
  // src/sphere-tile/sphere-tile.tsx
10395
- var import_jsx_runtime15 = require("react/jsx-runtime");
10429
+ var import_jsx_runtime16 = require("react/jsx-runtime");
10396
10430
  function SpherePatch({
10397
10431
  address,
10398
10432
  texture,
10399
10433
  yawOffset,
10400
10434
  preview = false
10401
10435
  }) {
10402
- const geometry = (0, import_react38.useMemo)(
10436
+ const geometry = (0, import_react39.useMemo)(
10403
10437
  () => sphereTileGeometry(
10404
10438
  address,
10405
10439
  yawOffset,
@@ -10407,13 +10441,13 @@ function SpherePatch({
10407
10441
  ),
10408
10442
  [address, yawOffset, preview]
10409
10443
  );
10410
- (0, import_react38.useEffect)(() => () => geometry.dispose(), [geometry]);
10411
- return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
10444
+ (0, import_react39.useEffect)(() => () => geometry.dispose(), [geometry]);
10445
+ return /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
10412
10446
  "mesh",
10413
10447
  {
10414
10448
  geometry,
10415
10449
  renderOrder: preview ? -1e3 : -900 + address.level,
10416
- children: /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
10450
+ children: /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
10417
10451
  PanoBasicMaterial,
10418
10452
  {
10419
10453
  map: texture,
@@ -10426,7 +10460,7 @@ function SpherePatch({
10426
10460
  }
10427
10461
  );
10428
10462
  }
10429
- var ManagedPatch = (0, import_react38.memo)(function ManagedPatch2({
10463
+ var ManagedPatch = (0, import_react39.memo)(function ManagedPatch2({
10430
10464
  address,
10431
10465
  manager,
10432
10466
  resolveUrl,
@@ -10440,10 +10474,10 @@ var ManagedPatch = (0, import_react38.memo)(function ManagedPatch2({
10440
10474
  url,
10441
10475
  address
10442
10476
  );
10443
- (0, import_react38.useEffect)(() => {
10477
+ (0, import_react39.useEffect)(() => {
10444
10478
  if (snapshot.texture) ready();
10445
10479
  }, [snapshot.texture, ready]);
10446
- return snapshot.texture ? /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
10480
+ return snapshot.texture ? /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
10447
10481
  SpherePatch,
10448
10482
  {
10449
10483
  address,
@@ -10471,28 +10505,29 @@ function SphereTileSource({
10471
10505
  onTileError,
10472
10506
  onLevelChange
10473
10507
  }) {
10474
- const { camera, gl, size } = (0, import_fiber15.useThree)();
10508
+ const { camera, gl, size } = (0, import_fiber16.useThree)();
10475
10509
  const anisotropy = gl.capabilities.getMaxAnisotropy();
10476
10510
  const preview = usePreviewTexture(
10477
10511
  resolveAssetUrl(baseUrl, previewUrl),
10478
10512
  anisotropy,
10479
10513
  onPreviewError
10480
10514
  );
10481
- const callbacks = (0, import_react38.useRef)({
10515
+ const callbacks = (0, import_react39.useRef)({
10482
10516
  onReady,
10483
10517
  onLoadProgress,
10484
10518
  onTileError,
10485
10519
  onLevelChange
10486
10520
  });
10487
10521
  callbacks.current = { onReady, onLoadProgress, onTileError, onLevelChange };
10488
- const budget = Math.max(
10522
+ const sharedManager = useSharedTileTextureManager();
10523
+ const ownedBudget = Math.max(
10489
10524
  1,
10490
10525
  Number.isFinite(maxTextureMemoryMb) ? maxTextureMemoryMb : 128
10491
10526
  ) * 1024 * 1024;
10492
- const manager = (0, import_react38.useMemo)(
10527
+ const ownedManager = (0, import_react39.useMemo)(
10493
10528
  () => new TileTextureManager({
10494
10529
  anisotropy,
10495
- maxBytes: budget,
10530
+ maxBytes: ownedBudget,
10496
10531
  concurrency: Math.max(
10497
10532
  1,
10498
10533
  Math.floor(
@@ -10506,30 +10541,38 @@ function SphereTileSource({
10506
10541
  onProgress: (progress) => callbacks.current.onLoadProgress?.(progress),
10507
10542
  onError: (error) => callbacks.current.onTileError?.(error)
10508
10543
  }),
10509
- [anisotropy, budget, maxConcurrentLoads, retryCount]
10544
+ [anisotropy, ownedBudget, maxConcurrentLoads, retryCount]
10510
10545
  );
10511
- const readyRef = (0, import_react38.useRef)(false);
10512
- const ready = (0, import_react38.useCallback)(() => {
10546
+ const manager = sharedManager ?? ownedManager;
10547
+ const budget = manager.memoryBudgetBytes;
10548
+ const readyRef = (0, import_react39.useRef)(false);
10549
+ const ready = (0, import_react39.useCallback)(() => {
10513
10550
  if (!readyRef.current) {
10514
10551
  readyRef.current = true;
10515
10552
  callbacks.current.onReady?.();
10516
10553
  }
10517
10554
  }, []);
10518
- (0, import_react38.useEffect)(() => {
10555
+ (0, import_react39.useEffect)(() => {
10519
10556
  if (preview) ready();
10520
10557
  }, [preview, ready]);
10521
- (0, import_react38.useEffect)(() => {
10558
+ (0, import_react39.useEffect)(() => {
10522
10559
  manager.resume();
10523
- return () => manager.dispose();
10524
- }, [manager]);
10525
- const resolveUrl = (0, import_react38.useMemo)(
10560
+ return () => {
10561
+ if (manager === ownedManager) {
10562
+ manager.dispose();
10563
+ return;
10564
+ }
10565
+ queueMicrotask(() => manager.releaseUnused());
10566
+ };
10567
+ }, [manager, ownedManager]);
10568
+ const resolveUrl = (0, import_react39.useMemo)(
10526
10569
  () => (address) => resolveAssetUrl(
10527
10570
  baseUrl,
10528
10571
  resolveTileUrl ? resolveTileUrl(address) : resolveSphereTemplateUrl(urlTemplate, address, indexBase)
10529
10572
  ),
10530
10573
  [baseUrl, resolveTileUrl, urlTemplate, indexBase]
10531
10574
  );
10532
- const candidates = (0, import_react38.useMemo)(
10575
+ const candidates = (0, import_react39.useMemo)(
10533
10576
  () => config.levels.map(
10534
10577
  (level, index) => sphereTileAddresses(level, index, config.tileSize).map((address) => ({
10535
10578
  address,
@@ -10538,12 +10581,12 @@ function SphereTileSource({
10538
10581
  ),
10539
10582
  [config, yawOffset]
10540
10583
  );
10541
- const previewAddress = (0, import_react38.useMemo)(
10584
+ const previewAddress = (0, import_react39.useMemo)(
10542
10585
  () => sphereTileAddresses({ width: 2, height: 1 }, 0, 2)[0],
10543
10586
  []
10544
10587
  );
10545
- const [layers, setLayers] = (0, import_react38.useState)([]);
10546
- const scratch = (0, import_react38.useMemo)(
10588
+ const [layers, setLayers] = (0, import_react39.useState)([]);
10589
+ const scratch = (0, import_react39.useMemo)(
10547
10590
  () => ({
10548
10591
  camera: new import_three14.PerspectiveCamera(),
10549
10592
  frustum: new import_three14.Frustum(),
@@ -10561,7 +10604,7 @@ function SphereTileSource({
10561
10604
  }),
10562
10605
  [camera, candidates]
10563
10606
  );
10564
- (0, import_fiber15.useFrame)(() => {
10607
+ (0, import_fiber16.useFrame)(() => {
10565
10608
  if (!(camera instanceof import_three14.PerspectiveCamera)) return;
10566
10609
  const now = performance.now(), dpr = gl.getPixelRatio();
10567
10610
  const reset = scratch.manager !== manager || scratch.loadMode !== loadMode;
@@ -10612,8 +10655,8 @@ function SphereTileSource({
10612
10655
  setLayers(next);
10613
10656
  }
10614
10657
  });
10615
- return /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("group", { visible, children: [
10616
- preview ? /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
10658
+ return /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("group", { visible, children: [
10659
+ preview ? /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
10617
10660
  SpherePatch,
10618
10661
  {
10619
10662
  address: previewAddress,
@@ -10623,7 +10666,7 @@ function SphereTileSource({
10623
10666
  }
10624
10667
  ) : null,
10625
10668
  loadMode !== "preview" ? layers.flatMap(
10626
- (layer) => layer.addresses.map((address) => /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
10669
+ (layer) => layer.addresses.map((address) => /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
10627
10670
  ManagedPatch,
10628
10671
  {
10629
10672
  address,
@@ -10639,23 +10682,23 @@ function SphereTileSource({
10639
10682
  }
10640
10683
  function SphereTile({ multires, ...props }) {
10641
10684
  const token = typeof multires === "string" ? multires : JSON.stringify(multires);
10642
- const config = (0, import_react38.useMemo)(() => parseSphereMultires(multires), [token]);
10685
+ const config = (0, import_react39.useMemo)(() => parseSphereMultires(multires), [token]);
10643
10686
  const sourceKey = `${props.baseUrl}\0${token}\0${props.previewUrl}\0${props.urlTemplate ?? ""}\0${props.indexBase ?? 1}`;
10644
- return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(SphereTileSource, { ...props, config }, sourceKey);
10687
+ return /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(SphereTileSource, { ...props, config }, sourceKey);
10645
10688
  }
10646
10689
 
10647
10690
  // src/sphere.tsx
10648
- var import_fiber16 = require("@react-three/fiber");
10649
- var import_react39 = require("react");
10691
+ var import_fiber17 = require("@react-three/fiber");
10692
+ var import_react40 = require("react");
10650
10693
  var import_three15 = require("three");
10651
- var import_jsx_runtime16 = require("react/jsx-runtime");
10694
+ var import_jsx_runtime17 = require("react/jsx-runtime");
10652
10695
  function useEquirectTexture(url, anisotropy, generateMipmaps, onLoad, onError) {
10653
- const [texture, setTexture] = (0, import_react39.useState)(null);
10654
- const onLoadRef = (0, import_react39.useRef)(onLoad);
10655
- const onErrorRef = (0, import_react39.useRef)(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);
10656
10699
  onLoadRef.current = onLoad;
10657
10700
  onErrorRef.current = onError;
10658
- (0, import_react39.useEffect)(() => {
10701
+ (0, import_react40.useEffect)(() => {
10659
10702
  if (!url) {
10660
10703
  setTexture(null);
10661
10704
  return;
@@ -10694,7 +10737,7 @@ function useEquirectTexture(url, anisotropy, generateMipmaps, onLoad, onError) {
10694
10737
  active = false;
10695
10738
  };
10696
10739
  }, [anisotropy, generateMipmaps, url]);
10697
- (0, import_react39.useEffect)(
10740
+ (0, import_react40.useEffect)(
10698
10741
  () => () => {
10699
10742
  texture?.dispose();
10700
10743
  },
@@ -10712,9 +10755,9 @@ function Sphere({
10712
10755
  onPreviewError,
10713
10756
  visible = true
10714
10757
  }) {
10715
- const gl = (0, import_fiber16.useThree)((state) => state.gl);
10758
+ const gl = (0, import_fiber17.useThree)((state) => state.gl);
10716
10759
  const anisotropy = gl.capabilities.getMaxAnisotropy();
10717
- const resolvedPreviewUrl = (0, import_react39.useMemo)(
10760
+ const resolvedPreviewUrl = (0, import_react40.useMemo)(
10718
10761
  () => resolveUrlAgainstFile(src, previewUrl),
10719
10762
  [previewUrl, src]
10720
10763
  );
@@ -10733,11 +10776,11 @@ function Sphere({
10733
10776
  onPreviewError
10734
10777
  );
10735
10778
  const displayTexture = texture ?? previewTexture;
10736
- const readyRef = (0, import_react39.useRef)(false);
10737
- (0, import_react39.useEffect)(() => {
10779
+ const readyRef = (0, import_react40.useRef)(false);
10780
+ (0, import_react40.useEffect)(() => {
10738
10781
  readyRef.current = false;
10739
10782
  }, [resolvedPreviewUrl, src]);
10740
- (0, import_react39.useEffect)(() => {
10783
+ (0, import_react40.useEffect)(() => {
10741
10784
  if (!displayTexture || readyRef.current) {
10742
10785
  return;
10743
10786
  }
@@ -10747,14 +10790,14 @@ function Sphere({
10747
10790
  if (!displayTexture) {
10748
10791
  return null;
10749
10792
  }
10750
- return /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)(
10793
+ return /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(
10751
10794
  "mesh",
10752
10795
  {
10753
10796
  rotation: [0, import_three15.MathUtils.degToRad(90 + yawOffset), 0],
10754
10797
  visible,
10755
10798
  children: [
10756
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("sphereGeometry", { args: [DEFAULT_PANORAMA_RADIUS, 128, 64] }),
10757
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
10799
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("sphereGeometry", { args: [DEFAULT_PANORAMA_RADIUS, 128, 64] }),
10800
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
10758
10801
  PanoBasicMaterial,
10759
10802
  {
10760
10803
  map: displayTexture,
@@ -10768,10 +10811,10 @@ function Sphere({
10768
10811
  }
10769
10812
 
10770
10813
  // src/video/pano-video.tsx
10771
- var import_fiber17 = require("@react-three/fiber");
10772
- var import_react40 = require("react");
10814
+ var import_fiber18 = require("@react-three/fiber");
10815
+ var import_react41 = require("react");
10773
10816
  var import_three16 = require("three");
10774
- var import_jsx_runtime17 = require("react/jsx-runtime");
10817
+ var import_jsx_runtime18 = require("react/jsx-runtime");
10775
10818
  var EMPTY_TRACKS = [];
10776
10819
  var EMPTY_RATES = DEFAULT_PANO_VIDEO_PLAYBACK_RATES;
10777
10820
  function createEmptySnapshot() {
@@ -10855,11 +10898,11 @@ function applyEquirectangularLayout(texture, anisotropy) {
10855
10898
  texture.needsUpdate = true;
10856
10899
  }
10857
10900
  function usePosterTexture(poster, onError) {
10858
- const gl = (0, import_fiber17.useThree)((state) => state.gl);
10859
- const [texture, setTexture] = (0, import_react40.useState)(null);
10860
- const onErrorRef = (0, import_react40.useRef)(onError);
10901
+ 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);
10861
10904
  onErrorRef.current = onError;
10862
- (0, import_react40.useEffect)(() => {
10905
+ (0, import_react41.useEffect)(() => {
10863
10906
  let active = true;
10864
10907
  setTexture(null);
10865
10908
  if (!poster) {
@@ -10896,7 +10939,7 @@ function usePosterTexture(poster, onError) {
10896
10939
  active = false;
10897
10940
  };
10898
10941
  }, [gl, poster]);
10899
- (0, import_react40.useEffect)(
10942
+ (0, import_react41.useEffect)(
10900
10943
  () => () => {
10901
10944
  texture?.dispose();
10902
10945
  },
@@ -10954,39 +10997,39 @@ function PanoVideo({
10954
10997
  onTrackChange
10955
10998
  }) {
10956
10999
  usePanoMediaActivationIntent(autoPlay);
10957
- const gl = (0, import_fiber17.useThree)((state) => state.gl);
10958
- const host = (0, import_react40.useContext)(PanoVideoHostContext);
10959
- const overlay = (0, import_react40.useContext)(PanoChromeOverlayContext);
10960
- const variants = (0, import_react40.useMemo)(
11000
+ 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)(
10961
11004
  () => resolvePanoVideoVariants({ poster, src, variants: variantsProp }),
10962
11005
  [poster, src, variantsProp]
10963
11006
  );
10964
11007
  const tracks = tracksProp ?? EMPTY_TRACKS;
10965
11008
  const captionsEnabled = captions !== false;
10966
- const captionAppearance = (0, import_react40.useMemo)(
11009
+ const captionAppearance = (0, import_react41.useMemo)(
10967
11010
  () => resolvePanoVideoCaptionAppearance(
10968
11011
  typeof captions === "object" ? captions : void 0
10969
11012
  ),
10970
11013
  [captions]
10971
11014
  );
10972
- const [variantId, setVariantId] = (0, import_react40.useState)(
11015
+ const [variantId, setVariantId] = (0, import_react41.useState)(
10973
11016
  () => resolvePanoVideoVariantId(variants, defaultVariantId)
10974
11017
  );
10975
- const [trackId, setTrackId] = (0, import_react40.useState)(
11018
+ const [trackId, setTrackId] = (0, import_react41.useState)(
10976
11019
  () => captionsEnabled ? defaultPanoVideoTrackId(tracks) : null
10977
11020
  );
10978
- const [ready, setReady] = (0, import_react40.useState)(false);
10979
- const autoPlayRef = (0, import_react40.useRef)(autoPlay);
11021
+ const [ready, setReady] = (0, import_react41.useState)(false);
11022
+ const autoPlayRef = (0, import_react41.useRef)(autoPlay);
10980
11023
  autoPlayRef.current = autoPlay;
10981
- const blockedRef = (0, import_react40.useRef)(false);
10982
- const captionAppearanceOverrideRef = (0, import_react40.useRef)(
11024
+ const blockedRef = (0, import_react41.useRef)(false);
11025
+ const captionAppearanceOverrideRef = (0, import_react41.useRef)(
10983
11026
  {}
10984
11027
  );
10985
- const mediaCapabilitiesRef = (0, import_react40.useRef)({
11028
+ const mediaCapabilitiesRef = (0, import_react41.useRef)({
10986
11029
  volumeAdjustable: true,
10987
11030
  playbackRates: [...DEFAULT_PANO_VIDEO_PLAYBACK_RATES]
10988
11031
  });
10989
- const storeRef = (0, import_react40.useRef)(null);
11032
+ const storeRef = (0, import_react41.useRef)(null);
10990
11033
  if (!storeRef.current) {
10991
11034
  storeRef.current = {
10992
11035
  snapshot: {
@@ -10996,7 +11039,7 @@ function PanoVideo({
10996
11039
  listeners: /* @__PURE__ */ new Set()
10997
11040
  };
10998
11041
  }
10999
- const actionsRef = (0, import_react40.useRef)({
11042
+ const actionsRef = (0, import_react41.useRef)({
11000
11043
  play: async () => {
11001
11044
  },
11002
11045
  pause: () => {
@@ -11016,19 +11059,19 @@ function PanoVideo({
11016
11059
  setCaptionAppearance: (_appearance) => {
11017
11060
  }
11018
11061
  });
11019
- const onLoadRef = (0, import_react40.useRef)(onLoad);
11020
- const onErrorRef = (0, import_react40.useRef)(onError);
11021
- const onPlaybackStateChangeRef = (0, import_react40.useRef)(onPlaybackStateChange);
11022
- const onEndedRef = (0, import_react40.useRef)(onEnded);
11023
- const onVariantChangeRef = (0, import_react40.useRef)(onVariantChange);
11024
- const onTrackChangeRef = (0, import_react40.useRef)(onTrackChange);
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);
11025
11068
  onLoadRef.current = onLoad;
11026
11069
  onErrorRef.current = onError;
11027
11070
  onPlaybackStateChangeRef.current = onPlaybackStateChange;
11028
11071
  onEndedRef.current = onEnded;
11029
11072
  onVariantChangeRef.current = onVariantChange;
11030
11073
  onTrackChangeRef.current = onTrackChange;
11031
- const resource = (0, import_react40.useMemo)(() => {
11074
+ const resource = (0, import_react41.useMemo)(() => {
11032
11075
  if (typeof document === "undefined") {
11033
11076
  return null;
11034
11077
  }
@@ -11045,7 +11088,7 @@ function PanoVideo({
11045
11088
  texture.generateMipmaps = false;
11046
11089
  return { video, texture };
11047
11090
  }, []);
11048
- (0, import_react40.useEffect)(
11091
+ (0, import_react41.useEffect)(
11049
11092
  () => () => {
11050
11093
  if (!resource) {
11051
11094
  return;
@@ -11060,13 +11103,13 @@ function PanoVideo({
11060
11103
  },
11061
11104
  [resource]
11062
11105
  );
11063
- (0, import_react40.useEffect)(() => {
11106
+ (0, import_react41.useEffect)(() => {
11064
11107
  if (!resource) {
11065
11108
  return;
11066
11109
  }
11067
11110
  resource.texture.anisotropy = gl.capabilities.getMaxAnisotropy();
11068
11111
  }, [gl, resource]);
11069
- (0, import_react40.useEffect)(() => {
11112
+ (0, import_react41.useEffect)(() => {
11070
11113
  if (!resource || !overlay?.overlayElement) {
11071
11114
  return;
11072
11115
  }
@@ -11089,7 +11132,7 @@ function PanoVideo({
11089
11132
  activeVariant?.poster ?? poster,
11090
11133
  onError
11091
11134
  );
11092
- const emitSnapshot = (0, import_react40.useCallback)(
11135
+ const emitSnapshot = (0, import_react41.useCallback)(
11093
11136
  (patch) => {
11094
11137
  const store = storeRef.current;
11095
11138
  const video = resource?.video;
@@ -11141,7 +11184,7 @@ function PanoVideo({
11141
11184
  captionAppearance
11142
11185
  ]
11143
11186
  );
11144
- const controller = (0, import_react40.useMemo)(
11187
+ const controller = (0, import_react41.useMemo)(
11145
11188
  () => ({
11146
11189
  subscribe: (onStoreChange) => {
11147
11190
  const store = storeRef.current;
@@ -11193,7 +11236,7 @@ function PanoVideo({
11193
11236
  }),
11194
11237
  []
11195
11238
  );
11196
- (0, import_react40.useLayoutEffect)(() => {
11239
+ (0, import_react41.useLayoutEffect)(() => {
11197
11240
  if (!host || variants.length === 0) {
11198
11241
  return;
11199
11242
  }
@@ -11206,7 +11249,7 @@ function PanoVideo({
11206
11249
  notifyPanoVideoHost(host);
11207
11250
  };
11208
11251
  }, [captionsEnabled, controller, controls, host, variants.length]);
11209
- (0, import_react40.useLayoutEffect)(() => {
11252
+ (0, import_react41.useLayoutEffect)(() => {
11210
11253
  if (!resource) {
11211
11254
  return;
11212
11255
  }
@@ -11219,10 +11262,10 @@ function PanoVideo({
11219
11262
  };
11220
11263
  emitSnapshot();
11221
11264
  }, [emitSnapshot, playbackRates, resource]);
11222
- (0, import_react40.useEffect)(() => {
11265
+ (0, import_react41.useEffect)(() => {
11223
11266
  emitSnapshot();
11224
11267
  }, [emitSnapshot]);
11225
- (0, import_react40.useEffect)(() => {
11268
+ (0, import_react41.useEffect)(() => {
11226
11269
  if (!resource || !activeVariant || !mediaKey) {
11227
11270
  return;
11228
11271
  }
@@ -11279,7 +11322,7 @@ function PanoVideo({
11279
11322
  video.removeEventListener("error", handleError);
11280
11323
  };
11281
11324
  }, [mediaKey, resource]);
11282
- (0, import_react40.useEffect)(() => {
11325
+ (0, import_react41.useEffect)(() => {
11283
11326
  if (!resource) {
11284
11327
  return;
11285
11328
  }
@@ -11371,7 +11414,7 @@ function PanoVideo({
11371
11414
  }
11372
11415
  };
11373
11416
  }, [emitSnapshot, resource]);
11374
- (0, import_react40.useEffect)(() => {
11417
+ (0, import_react41.useEffect)(() => {
11375
11418
  if (!resource) {
11376
11419
  return;
11377
11420
  }
@@ -11391,7 +11434,7 @@ function PanoVideo({
11391
11434
  }
11392
11435
  video.preload = preload;
11393
11436
  }, [loop, muted, playsInline, preload, resource, volume]);
11394
- (0, import_react40.useEffect)(() => {
11437
+ (0, import_react41.useEffect)(() => {
11395
11438
  if (!resource) {
11396
11439
  return;
11397
11440
  }
@@ -11441,7 +11484,7 @@ function PanoVideo({
11441
11484
  video.removeEventListener("ratechange", handleVolume);
11442
11485
  };
11443
11486
  }, [emitSnapshot, resource]);
11444
- (0, import_react40.useEffect)(() => {
11487
+ (0, import_react41.useEffect)(() => {
11445
11488
  if (!resource) {
11446
11489
  return;
11447
11490
  }
@@ -11476,7 +11519,7 @@ function PanoVideo({
11476
11519
  video.textTracks.removeEventListener("change", applyModes);
11477
11520
  };
11478
11521
  }, [emitSnapshot, resource, trackId, tracks]);
11479
- (0, import_react40.useEffect)(() => {
11522
+ (0, import_react41.useEffect)(() => {
11480
11523
  if (!captionsEnabled) {
11481
11524
  setTrackId(null);
11482
11525
  return;
@@ -11487,15 +11530,15 @@ function PanoVideo({
11487
11530
  if (variants.length === 0) {
11488
11531
  return null;
11489
11532
  }
11490
- return /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(import_jsx_runtime17.Fragment, { children: [
11491
- activeTexture ? /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(
11533
+ return /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)(import_jsx_runtime18.Fragment, { children: [
11534
+ activeTexture ? /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)(
11492
11535
  "mesh",
11493
11536
  {
11494
11537
  rotation: [0, import_three16.MathUtils.degToRad(90 + yawOffset), 0],
11495
11538
  visible,
11496
11539
  children: [
11497
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("sphereGeometry", { args: [DEFAULT_PANORAMA_RADIUS, 128, 64] }),
11498
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
11540
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("sphereGeometry", { args: [DEFAULT_PANORAMA_RADIUS, 128, 64] }),
11541
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
11499
11542
  PanoBasicMaterial,
11500
11543
  {
11501
11544
  map: activeTexture,
@@ -11506,7 +11549,7 @@ function PanoVideo({
11506
11549
  ]
11507
11550
  }
11508
11551
  ) : null,
11509
- captionsEnabled ? /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(PanoVideoCaptions, { appearance: typeof captions === "object" ? captions : void 0 }) : null
11552
+ captionsEnabled ? /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(PanoVideoCaptions, { appearance: typeof captions === "object" ? captions : void 0 }) : null
11510
11553
  ] });
11511
11554
  }
11512
11555
 
@@ -11562,8 +11605,8 @@ function isSnapshotTransition(preset) {
11562
11605
  }
11563
11606
 
11564
11607
  // src/scene-transitions/particle-overlay.tsx
11565
- var import_fiber18 = require("@react-three/fiber");
11566
- var import_react41 = require("react");
11608
+ var import_fiber19 = require("@react-three/fiber");
11609
+ var import_react42 = require("react");
11567
11610
  var import_three18 = require("three");
11568
11611
 
11569
11612
  // src/scene-transitions/glsl.ts
@@ -11618,7 +11661,7 @@ function overlayProgress(elapsedTime, duration, startTime) {
11618
11661
  }
11619
11662
 
11620
11663
  // src/scene-transitions/particle-overlay.tsx
11621
- var import_jsx_runtime18 = require("react/jsx-runtime");
11664
+ var import_jsx_runtime19 = require("react/jsx-runtime");
11622
11665
  var PARTICLE_GRID = 48;
11623
11666
  var PARTICLE_COUNT = PARTICLE_GRID * PARTICLE_GRID;
11624
11667
  var PARTICLE_VERTEX_SHADER = `
@@ -11694,13 +11737,13 @@ function ParticleOverlay({
11694
11737
  runId,
11695
11738
  onFinish
11696
11739
  }) {
11697
- const { camera } = (0, import_fiber18.useThree)();
11698
- const meshRef = (0, import_react41.useRef)(null);
11699
- const startRef = (0, import_react41.useRef)(null);
11700
- const finishedRef = (0, import_react41.useRef)(false);
11701
- const directionRef = (0, import_react41.useRef)(new import_three18.Vector3());
11702
- const geometry = (0, import_react41.useMemo)(() => createParticleGeometry(), []);
11703
- const material = (0, import_react41.useMemo)(
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)(
11704
11747
  () => new import_three18.ShaderMaterial({
11705
11748
  transparent: true,
11706
11749
  depthTest: false,
@@ -11716,14 +11759,14 @@ function ParticleOverlay({
11716
11759
  }),
11717
11760
  [snapshot.texture]
11718
11761
  );
11719
- (0, import_react41.useEffect)(() => () => geometry.dispose(), [geometry]);
11720
- (0, import_react41.useEffect)(() => () => material.dispose(), [material]);
11721
- (0, import_react41.useEffect)(() => {
11762
+ (0, import_react42.useEffect)(() => () => geometry.dispose(), [geometry]);
11763
+ (0, import_react42.useEffect)(() => () => material.dispose(), [material]);
11764
+ (0, import_react42.useEffect)(() => {
11722
11765
  startRef.current = null;
11723
11766
  finishedRef.current = false;
11724
11767
  material.uniforms.progress.value = 0;
11725
11768
  }, [material, runId]);
11726
- (0, import_fiber18.useFrame)((state) => {
11769
+ (0, import_fiber19.useFrame)((state) => {
11727
11770
  const mesh = meshRef.current;
11728
11771
  if (!mesh || !isPerspectiveCamera(camera)) {
11729
11772
  return;
@@ -11740,7 +11783,7 @@ function ParticleOverlay({
11740
11783
  onFinish();
11741
11784
  }
11742
11785
  });
11743
- return /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
11786
+ return /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
11744
11787
  "mesh",
11745
11788
  {
11746
11789
  ref: meshRef,
@@ -11753,8 +11796,8 @@ function ParticleOverlay({
11753
11796
  }
11754
11797
 
11755
11798
  // src/scene-transitions/snapshot-overlay.tsx
11756
- var import_fiber19 = require("@react-three/fiber");
11757
- var import_react42 = require("react");
11799
+ var import_fiber20 = require("@react-three/fiber");
11800
+ var import_react43 = require("react");
11758
11801
  var import_three20 = require("three");
11759
11802
 
11760
11803
  // src/scene-transitions/snapshot-shaders.ts
@@ -12034,7 +12077,7 @@ function createSnapshotMaterial(preset, texture) {
12034
12077
  }
12035
12078
 
12036
12079
  // src/scene-transitions/snapshot-overlay.tsx
12037
- var import_jsx_runtime19 = require("react/jsx-runtime");
12080
+ var import_jsx_runtime20 = require("react/jsx-runtime");
12038
12081
  function SnapshotOverlay({
12039
12082
  snapshot,
12040
12083
  transition,
@@ -12042,26 +12085,26 @@ function SnapshotOverlay({
12042
12085
  runId,
12043
12086
  onFinish
12044
12087
  }) {
12045
- const { camera, gl } = (0, import_fiber19.useThree)();
12046
- const meshRef = (0, import_react42.useRef)(null);
12047
- const startRef = (0, import_react42.useRef)(null);
12048
- const finishedRef = (0, import_react42.useRef)(false);
12049
- const directionRef = (0, import_react42.useRef)(new import_three20.Vector3());
12050
- const material = (0, import_react42.useMemo)(() => {
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)(() => {
12051
12094
  if (!isSnapshotTransition(transition.preset)) {
12052
12095
  return null;
12053
12096
  }
12054
12097
  return createSnapshotMaterial(transition.preset, snapshot.texture);
12055
12098
  }, [snapshot.texture, transition.preset]);
12056
- (0, import_react42.useEffect)(() => () => material?.dispose(), [material]);
12057
- (0, import_react42.useEffect)(() => {
12099
+ (0, import_react43.useEffect)(() => () => material?.dispose(), [material]);
12100
+ (0, import_react43.useEffect)(() => {
12058
12101
  startRef.current = null;
12059
12102
  finishedRef.current = false;
12060
12103
  if (material) {
12061
12104
  material.uniforms.progress.value = 0;
12062
12105
  }
12063
12106
  }, [material, runId]);
12064
- (0, import_fiber19.useFrame)((state) => {
12107
+ (0, import_fiber20.useFrame)((state) => {
12065
12108
  const mesh = meshRef.current;
12066
12109
  if (!mesh || !material || !isPerspectiveCamera(camera)) {
12067
12110
  return;
@@ -12083,21 +12126,21 @@ function SnapshotOverlay({
12083
12126
  if (!material) {
12084
12127
  return null;
12085
12128
  }
12086
- return /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("mesh", { ref: meshRef, renderOrder: OVERLAY_RENDER_ORDER, frustumCulled: false, children: [
12087
- /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("primitive", { attach: "geometry", object: FULLSCREEN_PLANE }),
12088
- /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("primitive", { attach: "material", object: material })
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 })
12089
12132
  ] });
12090
12133
  }
12091
12134
 
12092
12135
  // src/scene-transitions/transition-overlay.tsx
12093
- var import_jsx_runtime20 = require("react/jsx-runtime");
12136
+ var import_jsx_runtime21 = require("react/jsx-runtime");
12094
12137
  function TransitionOverlay(props) {
12095
12138
  const { preset } = props.transition;
12096
12139
  switch (preset) {
12097
12140
  case "none":
12098
12141
  return null;
12099
12142
  case "particles":
12100
- return /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(ParticleOverlay, { ...props });
12143
+ return /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(ParticleOverlay, { ...props });
12101
12144
  case "crossfade":
12102
12145
  case "zoom":
12103
12146
  case "blackout":
@@ -12125,7 +12168,7 @@ function TransitionOverlay(props) {
12125
12168
  case "zoomBlur":
12126
12169
  case "hexDissolve":
12127
12170
  case "filmBurn":
12128
- return /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(SnapshotOverlay, { ...props });
12171
+ return /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(SnapshotOverlay, { ...props });
12129
12172
  default: {
12130
12173
  const exhaustive = preset;
12131
12174
  void exhaustive;
@@ -12134,39 +12177,6 @@ function TransitionOverlay(props) {
12134
12177
  }
12135
12178
  }
12136
12179
 
12137
- // src/tile/texture-manager-context.tsx
12138
- var import_fiber20 = require("@react-three/fiber");
12139
- var import_react43 = require("react");
12140
- var import_jsx_runtime21 = require("react/jsx-runtime");
12141
- var TileTextureManagerContext = (0, import_react43.createContext)(
12142
- null
12143
- );
12144
- function TileTextureManagerProvider({
12145
- children,
12146
- maxTextureMemoryMb = 128,
12147
- maxConcurrentLoads = 4
12148
- }) {
12149
- const gl = (0, import_fiber20.useThree)((state) => state.gl);
12150
- const anisotropy = gl.capabilities.getMaxAnisotropy();
12151
- const manager = (0, import_react43.useMemo)(
12152
- () => new TileTextureManager({
12153
- anisotropy,
12154
- maxBytes: Math.max(1, maxTextureMemoryMb) * 1024 * 1024,
12155
- concurrency: Math.max(1, Math.floor(maxConcurrentLoads)),
12156
- retryCount: 1
12157
- }),
12158
- [anisotropy, maxConcurrentLoads, maxTextureMemoryMb]
12159
- );
12160
- (0, import_react43.useEffect)(() => {
12161
- manager.resume();
12162
- return () => manager.dispose();
12163
- }, [manager]);
12164
- return /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(TileTextureManagerContext.Provider, { value: manager, children });
12165
- }
12166
- function useSharedTileTextureManager() {
12167
- return (0, import_react43.useContext)(TileTextureManagerContext);
12168
- }
12169
-
12170
12180
  // src/tile/tile.tsx
12171
12181
  var import_fiber21 = require("@react-three/fiber");
12172
12182
  var import_react44 = require("react");
@@ -12842,6 +12852,19 @@ function SceneSource({
12842
12852
  }
12843
12853
  );
12844
12854
  }
12855
+ case "sphereTile": {
12856
+ const { id: _id, type: _type, ...tileProps } = scene;
12857
+ return /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
12858
+ SphereTile,
12859
+ {
12860
+ ...tileProps,
12861
+ visible,
12862
+ loadMode: baseOnly ? "base" : "full",
12863
+ onReady,
12864
+ onPreviewError: onError
12865
+ }
12866
+ );
12867
+ }
12845
12868
  default: {
12846
12869
  const exhaustive = scene;
12847
12870
  void exhaustive;
@@ -12908,6 +12931,7 @@ function ScenesController({
12908
12931
  activeSceneId,
12909
12932
  transition: transitionInput,
12910
12933
  renderHotspots,
12934
+ onSceneReady,
12911
12935
  onTransitionEnd,
12912
12936
  onTransitionError,
12913
12937
  snapshotMaxPixels = 3686400,
@@ -12943,6 +12967,7 @@ function ScenesController({
12943
12967
  const phaseRef = (0, import_react45.useRef)(phase);
12944
12968
  const liveSlotRef = (0, import_react45.useRef)(liveSlot);
12945
12969
  const transitionFromRef = (0, import_react45.useRef)(initialScene);
12970
+ const readySceneRef = (0, import_react45.useRef)(null);
12946
12971
  slotsRef.current = slots;
12947
12972
  phaseRef.current = phase;
12948
12973
  if (externalPhaseRef) {
@@ -12983,6 +13008,7 @@ function ScenesController({
12983
13008
  return;
12984
13009
  }
12985
13010
  if (phaseRef.current === "transitioning" || phaseRef.current === "capturing") {
13011
+ if (requestedSceneIdRef.current === requested.id) return;
12986
13012
  requestedSceneIdRef.current = requested.id;
12987
13013
  captureReasonRef.current = "interrupt";
12988
13014
  setPhase("recapturing");
@@ -12991,7 +13017,16 @@ function ScenesController({
12991
13017
  }
12992
13018
  startPreload(requested);
12993
13019
  }, [activeSceneId, pendingSlot, reportError, sceneMap, startPreload]);
13020
+ const notifySceneReady = (0, import_react45.useCallback)((scene) => {
13021
+ if (!scene || readySceneRef.current === scene) return;
13022
+ readySceneRef.current = scene;
13023
+ onSceneReady?.(scene.id);
13024
+ }, [onSceneReady]);
12994
13025
  const handleReady = (0, import_react45.useCallback)((slot) => {
13026
+ if (slot === liveSlotRef.current && pendingSlot === null && phaseRef.current === "idle") {
13027
+ notifySceneReady(slotsRef.current[slot]);
13028
+ return;
13029
+ }
12995
13030
  if (slot !== pendingSlot || phaseRef.current !== "preloading") {
12996
13031
  return;
12997
13032
  }
@@ -13007,6 +13042,7 @@ function ScenesController({
13007
13042
  setActiveSlot(slot);
13008
13043
  setPendingSlot(null);
13009
13044
  setPhase("idle");
13045
+ notifySceneReady(nextScene);
13010
13046
  if (previousScene && nextScene) {
13011
13047
  onTransitionEnd?.({
13012
13048
  previousSceneId: previousScene.id,
@@ -13021,7 +13057,7 @@ function ScenesController({
13021
13057
  captureReasonRef.current = "start";
13022
13058
  setPhase("capturing");
13023
13059
  setCaptureRequestId((current) => current + 1);
13024
- }, [controlsRef, onTransitionEnd, pendingSlot, transition.preset]);
13060
+ }, [controlsRef, notifySceneReady, onTransitionEnd, pendingSlot, transition.preset]);
13025
13061
  const handleCaptured = (0, import_react45.useCallback)((nextSnapshot) => {
13026
13062
  setSnapshot((current) => {
13027
13063
  current?.dispose();
@@ -13039,11 +13075,12 @@ function ScenesController({
13039
13075
  });
13040
13076
  manager?.releaseUnused();
13041
13077
  if (pendingSlot !== null) {
13078
+ notifySceneReady(slotsRef.current[pendingSlot]);
13042
13079
  setLiveSlot(pendingSlot);
13043
13080
  }
13044
13081
  setPhase("transitioning");
13045
13082
  setTransitionRunId((current) => current + 1);
13046
- }, [manager, pendingSlot, sceneMap, startPreload]);
13083
+ }, [manager, notifySceneReady, pendingSlot, sceneMap, startPreload]);
13047
13084
  const finishTransition = (0, import_react45.useCallback)(() => {
13048
13085
  const nextSlot = pendingSlot;
13049
13086
  const previousScene = transitionFromRef.current;
@@ -13086,6 +13123,7 @@ function ScenesController({
13086
13123
  setPhase("idle");
13087
13124
  };
13088
13125
  const onContextRestored = () => {
13126
+ readySceneRef.current = null;
13089
13127
  manager?.resume();
13090
13128
  setRecoveryKey((current) => current + 1);
13091
13129
  };