@ericchen1990/pano-view 3.6.7 → 3.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.mjs CHANGED
@@ -2310,12 +2310,12 @@ import {
2310
2310
  forwardRef as forwardRef2,
2311
2311
  useCallback as useCallback6,
2312
2312
  useContext as useContext16,
2313
- useEffect as useEffect13,
2313
+ useEffect as useEffect14,
2314
2314
  useImperativeHandle as useImperativeHandle2,
2315
2315
  useMemo as useMemo8,
2316
2316
  useRef as useRef13,
2317
- useState as useState6,
2318
- useSyncExternalStore as useSyncExternalStore6
2317
+ useState as useState7,
2318
+ useSyncExternalStore as useSyncExternalStore8
2319
2319
  } from "react";
2320
2320
 
2321
2321
  // src/background-audio-host.ts
@@ -3464,9 +3464,529 @@ function subscribeFullscreenChange(onChange) {
3464
3464
  };
3465
3465
  }
3466
3466
 
3467
+ // src/ios-landscape-fullscreen.ts
3468
+ var BAR_COLLAPSED_TOLERANCE_PX = 32;
3469
+ var CHROME_GROWTH_PX = 24;
3470
+ var SCROLL_OFFSET_TOLERANCE_PX = 2;
3471
+ var REMEASURE_DELAY_MS = 280;
3472
+ var ELEMENT_STYLE_PROPERTIES = [
3473
+ "background",
3474
+ "height",
3475
+ "left",
3476
+ "position",
3477
+ "top",
3478
+ "width",
3479
+ "z-index"
3480
+ ];
3481
+ var globalListeners = /* @__PURE__ */ new Set();
3482
+ var activeSession = null;
3483
+ var lastSnapshot = {
3484
+ active: false,
3485
+ allowsDocumentScroll: false,
3486
+ element: null,
3487
+ portrait: false,
3488
+ state: 0
3489
+ };
3490
+ function readStandaloneDisplay() {
3491
+ if (typeof window === "undefined" || typeof navigator === "undefined") {
3492
+ return false;
3493
+ }
3494
+ const nav = navigator;
3495
+ if (nav.standalone === true) {
3496
+ return true;
3497
+ }
3498
+ try {
3499
+ return window.matchMedia("(display-mode: standalone)").matches;
3500
+ } catch {
3501
+ return false;
3502
+ }
3503
+ }
3504
+ function isIphoneLandscapeFullscreenCandidate(userAgent = typeof navigator !== "undefined" ? navigator.userAgent : "", options = {}) {
3505
+ if (!userAgent) {
3506
+ return false;
3507
+ }
3508
+ if (/iPad/i.test(userAgent)) {
3509
+ return false;
3510
+ }
3511
+ if (!/iPhone|iPod/i.test(userAgent)) {
3512
+ return false;
3513
+ }
3514
+ const fullscreenEnabled = options.fullscreenEnabled ?? (typeof document !== "undefined" ? isFullscreenEnabled() : false);
3515
+ if (fullscreenEnabled) {
3516
+ return false;
3517
+ }
3518
+ const standalone = options.standalone ?? readStandaloneDisplay();
3519
+ if (standalone) {
3520
+ return false;
3521
+ }
3522
+ return true;
3523
+ }
3524
+ function supportsIphoneLandscapeFullscreen() {
3525
+ if (typeof window === "undefined") {
3526
+ return false;
3527
+ }
3528
+ return isIphoneLandscapeFullscreenCandidate();
3529
+ }
3530
+ function canEnterViewerFullscreen() {
3531
+ return isFullscreenEnabled() || supportsIphoneLandscapeFullscreen();
3532
+ }
3533
+ function readLargeViewportHeight(win) {
3534
+ const root = win.document.documentElement;
3535
+ let probe = root.querySelector("[data-pano-lvh-probe]");
3536
+ if (!probe) {
3537
+ probe = win.document.createElement("div");
3538
+ probe.setAttribute("data-pano-lvh-probe", "");
3539
+ probe.setAttribute("aria-hidden", "true");
3540
+ probe.style.cssText = "position:fixed;left:0;top:0;width:0;height:100lvh;visibility:hidden;pointer-events:none;";
3541
+ root.appendChild(probe);
3542
+ }
3543
+ const measured = probe.getBoundingClientRect().height;
3544
+ if (measured > 0) {
3545
+ return measured;
3546
+ }
3547
+ const screen = win.screen;
3548
+ if (screen?.width > 0 && screen.height > 0) {
3549
+ return Math.min(screen.width, screen.height);
3550
+ }
3551
+ return win.innerHeight;
3552
+ }
3553
+ function removeLargeViewportProbe(win = window) {
3554
+ win.document.documentElement.querySelector("[data-pano-lvh-probe]")?.remove();
3555
+ }
3556
+ function readIphoneFullscreenViewport(win = window) {
3557
+ const visual = win.visualViewport;
3558
+ const landscape = typeof win.matchMedia === "function" ? win.matchMedia("(orientation: landscape)").matches : win.innerWidth > win.innerHeight;
3559
+ let inIframe = false;
3560
+ try {
3561
+ inIframe = win.self !== win.top;
3562
+ } catch {
3563
+ inIframe = true;
3564
+ }
3565
+ return {
3566
+ inIframe,
3567
+ landscape,
3568
+ largeViewportHeight: readLargeViewportHeight(win),
3569
+ scrollY: win.scrollY || win.pageYOffset || 0,
3570
+ visualViewportHeight: visual?.height ?? win.innerHeight,
3571
+ visualViewportOffsetTop: visual?.offsetTop ?? 0
3572
+ };
3573
+ }
3574
+ function computeChromeOverlapPx(viewport) {
3575
+ return Math.max(0, viewport.largeViewportHeight - viewport.visualViewportHeight);
3576
+ }
3577
+ function emptyExtents() {
3578
+ return {
3579
+ maxVisualHeight: 0,
3580
+ minVisualHeight: Number.POSITIVE_INFINITY
3581
+ };
3582
+ }
3583
+ function noteVisualHeight(extents, height) {
3584
+ if (!(height > 0)) {
3585
+ return;
3586
+ }
3587
+ extents.minVisualHeight = Math.min(extents.minVisualHeight, height);
3588
+ extents.maxVisualHeight = Math.max(extents.maxVisualHeight, height);
3589
+ }
3590
+ function isIphoneChromeCollapsed(viewport, extents) {
3591
+ const overlap = computeChromeOverlapPx(viewport);
3592
+ if (overlap <= BAR_COLLAPSED_TOLERANCE_PX) {
3593
+ return true;
3594
+ }
3595
+ if (!extents || !(extents.minVisualHeight > 0) || !(extents.maxVisualHeight > 0)) {
3596
+ return false;
3597
+ }
3598
+ const growth = extents.maxVisualHeight - extents.minVisualHeight;
3599
+ const atHighWater = viewport.visualViewportHeight >= extents.maxVisualHeight - 2;
3600
+ return growth >= CHROME_GROWTH_PX && atHighWater;
3601
+ }
3602
+ function computeScrollAwayDistance(viewport, extents) {
3603
+ if (!viewport.landscape || viewport.inIframe) {
3604
+ return 0;
3605
+ }
3606
+ if (isIphoneChromeCollapsed(viewport, extents)) {
3607
+ return 0;
3608
+ }
3609
+ return Math.max(1, Math.ceil(computeChromeOverlapPx(viewport)));
3610
+ }
3611
+ function computeIphoneFullscreenState(viewport, extents) {
3612
+ if (!viewport.landscape || viewport.inIframe) {
3613
+ return 0;
3614
+ }
3615
+ if (isIphoneChromeCollapsed(viewport, extents)) {
3616
+ return 0;
3617
+ }
3618
+ if (viewport.scrollY > SCROLL_OFFSET_TOLERANCE_PX || viewport.visualViewportOffsetTop > SCROLL_OFFSET_TOLERANCE_PX) {
3619
+ return 2;
3620
+ }
3621
+ return 1;
3622
+ }
3623
+ function captureElementStyle(element) {
3624
+ const snapshot = {};
3625
+ for (const property of ELEMENT_STYLE_PROPERTIES) {
3626
+ snapshot[property] = element.style.getPropertyValue(property);
3627
+ }
3628
+ return snapshot;
3629
+ }
3630
+ function restoreElementStyle(element, snapshot) {
3631
+ for (const property of ELEMENT_STYLE_PROPERTIES) {
3632
+ const previous = snapshot[property];
3633
+ if (previous) {
3634
+ element.style.setProperty(property, previous);
3635
+ } else {
3636
+ element.style.removeProperty(property);
3637
+ }
3638
+ }
3639
+ }
3640
+ function captureDocumentStyle() {
3641
+ const documentElement = document.documentElement;
3642
+ const body = document.body;
3643
+ return {
3644
+ bodyHeight: body.style.height,
3645
+ bodyMinHeight: body.style.minHeight,
3646
+ bodyOverflow: body.style.overflow,
3647
+ documentHeight: documentElement.style.height,
3648
+ documentOverflow: documentElement.style.overflow,
3649
+ scrollX: window.scrollX || window.pageXOffset || 0,
3650
+ scrollY: window.scrollY || window.pageYOffset || 0
3651
+ };
3652
+ }
3653
+ function restoreDocumentStyle(snapshot) {
3654
+ const documentElement = document.documentElement;
3655
+ const body = document.body;
3656
+ documentElement.style.overflow = snapshot.documentOverflow;
3657
+ documentElement.style.height = snapshot.documentHeight;
3658
+ body.style.overflow = snapshot.bodyOverflow;
3659
+ body.style.height = snapshot.bodyHeight;
3660
+ body.style.minHeight = snapshot.bodyMinHeight;
3661
+ window.scrollTo(snapshot.scrollX, snapshot.scrollY);
3662
+ }
3663
+ function applyCoverStyle(element) {
3664
+ const visual = window.visualViewport;
3665
+ const top = visual?.offsetTop ?? 0;
3666
+ const left = visual?.offsetLeft ?? 0;
3667
+ const width = visual?.width ?? window.innerWidth;
3668
+ const height = visual?.height ?? window.innerHeight;
3669
+ element.style.setProperty("background", "#000");
3670
+ element.style.setProperty("position", "fixed");
3671
+ element.style.setProperty("top", `${top}px`);
3672
+ element.style.setProperty("left", `${left}px`);
3673
+ element.style.setProperty("width", `${width}px`);
3674
+ element.style.setProperty("height", `${height}px`);
3675
+ element.style.setProperty("z-index", "2147483000");
3676
+ }
3677
+ function setDocumentScrollable(scrollDistance) {
3678
+ const documentElement = document.documentElement;
3679
+ const body = document.body;
3680
+ documentElement.style.overflow = "visible";
3681
+ body.style.overflow = "visible";
3682
+ if (scrollDistance > 0) {
3683
+ body.style.minHeight = `${window.innerHeight + scrollDistance + 64}px`;
3684
+ } else {
3685
+ body.style.minHeight = "";
3686
+ }
3687
+ }
3688
+ function lockDocumentScroll() {
3689
+ document.documentElement.style.overflow = "hidden";
3690
+ document.body.style.overflow = "hidden";
3691
+ document.body.style.minHeight = "";
3692
+ }
3693
+ function notifyListeners() {
3694
+ for (const listener of globalListeners) {
3695
+ listener();
3696
+ }
3697
+ }
3698
+ function publishSnapshot(session2, viewport, state) {
3699
+ lastSnapshot = {
3700
+ active: true,
3701
+ allowsDocumentScroll: viewport.landscape && !viewport.inIframe && state !== 0,
3702
+ element: session2.element,
3703
+ portrait: !viewport.landscape,
3704
+ state
3705
+ };
3706
+ notifyListeners();
3707
+ }
3708
+ function rememberViewport(session2, viewport) {
3709
+ if (session2.extentsLandscape !== viewport.landscape) {
3710
+ session2.extents = emptyExtents();
3711
+ session2.extentsLandscape = viewport.landscape;
3712
+ session2.barsHidden = false;
3713
+ }
3714
+ noteVisualHeight(session2.extents, viewport.visualViewportHeight);
3715
+ }
3716
+ function resolveState(session2, viewport) {
3717
+ const state = computeIphoneFullscreenState(viewport, session2.extents);
3718
+ if (!viewport.landscape || viewport.inIframe) {
3719
+ return state;
3720
+ }
3721
+ if (state === 0) {
3722
+ session2.barsHidden = true;
3723
+ return 0;
3724
+ }
3725
+ if (!session2.barsHidden) {
3726
+ return state;
3727
+ }
3728
+ if (viewport.visualViewportHeight < session2.extents.maxVisualHeight - 48) {
3729
+ session2.barsHidden = false;
3730
+ return state;
3731
+ }
3732
+ return 0;
3733
+ }
3734
+ function syncSessionLayout(session2, options) {
3735
+ const viewport = readIphoneFullscreenViewport();
3736
+ rememberViewport(session2, viewport);
3737
+ const state = resolveState(session2, viewport);
3738
+ applyCoverStyle(session2.element);
3739
+ if (!viewport.landscape || viewport.inIframe || state === 0) {
3740
+ lockDocumentScroll();
3741
+ publishSnapshot(session2, viewport, state);
3742
+ return;
3743
+ }
3744
+ const distance = computeScrollAwayDistance(viewport, session2.extents);
3745
+ setDocumentScrollable(distance);
3746
+ if (distance > 0 && viewport.scrollY < distance - 1) {
3747
+ window.scrollTo(0, distance);
3748
+ }
3749
+ applyCoverStyle(session2.element);
3750
+ const settled = readIphoneFullscreenViewport();
3751
+ rememberViewport(session2, settled);
3752
+ publishSnapshot(session2, settled, resolveState(session2, settled));
3753
+ if (options?.followUp) {
3754
+ return;
3755
+ }
3756
+ window.clearTimeout(session2.remeasureTimer);
3757
+ session2.remeasureTimer = window.setTimeout(() => {
3758
+ if (activeSession !== session2) {
3759
+ return;
3760
+ }
3761
+ syncSessionLayout(session2, { followUp: true });
3762
+ }, REMEASURE_DELAY_MS);
3763
+ window.requestAnimationFrame(() => {
3764
+ if (activeSession !== session2) {
3765
+ return;
3766
+ }
3767
+ syncSessionLayout(session2, { followUp: true });
3768
+ });
3769
+ }
3770
+ function attachSessionListeners(session2) {
3771
+ const onChange = () => {
3772
+ if (activeSession !== session2) {
3773
+ return;
3774
+ }
3775
+ syncSessionLayout(session2);
3776
+ };
3777
+ window.addEventListener("resize", onChange);
3778
+ window.addEventListener("orientationchange", onChange);
3779
+ window.addEventListener("scroll", onChange, { passive: true });
3780
+ window.visualViewport?.addEventListener("resize", onChange);
3781
+ window.visualViewport?.addEventListener("scroll", onChange);
3782
+ session2.orientationCleanup = () => {
3783
+ window.removeEventListener("resize", onChange);
3784
+ window.removeEventListener("orientationchange", onChange);
3785
+ window.removeEventListener("scroll", onChange);
3786
+ window.visualViewport?.removeEventListener("resize", onChange);
3787
+ window.visualViewport?.removeEventListener("scroll", onChange);
3788
+ };
3789
+ }
3790
+ function endSession(session2) {
3791
+ if (activeSession !== session2) {
3792
+ return;
3793
+ }
3794
+ activeSession = null;
3795
+ window.clearTimeout(session2.remeasureTimer);
3796
+ session2.orientationCleanup?.();
3797
+ session2.orientationCleanup = null;
3798
+ restoreElementStyle(session2.element, session2.elementStyle);
3799
+ removeLargeViewportProbe();
3800
+ restoreDocumentStyle(session2.documentStyle);
3801
+ lastSnapshot = {
3802
+ active: false,
3803
+ allowsDocumentScroll: false,
3804
+ element: null,
3805
+ portrait: false,
3806
+ state: 0
3807
+ };
3808
+ notifyListeners();
3809
+ }
3810
+ function acquireIphoneLandscapeFullscreen(element, holder) {
3811
+ if (!(element instanceof HTMLElement)) {
3812
+ return false;
3813
+ }
3814
+ if (!supportsIphoneLandscapeFullscreen()) {
3815
+ return false;
3816
+ }
3817
+ if (activeSession) {
3818
+ if (activeSession.element !== element) {
3819
+ endSession(activeSession);
3820
+ } else {
3821
+ activeSession.holders.add(holder);
3822
+ syncSessionLayout(activeSession);
3823
+ return true;
3824
+ }
3825
+ }
3826
+ const session2 = {
3827
+ barsHidden: false,
3828
+ documentStyle: captureDocumentStyle(),
3829
+ element,
3830
+ elementStyle: captureElementStyle(element),
3831
+ extents: emptyExtents(),
3832
+ extentsLandscape: null,
3833
+ holders: /* @__PURE__ */ new Set([holder]),
3834
+ orientationCleanup: null,
3835
+ remeasureTimer: 0
3836
+ };
3837
+ activeSession = session2;
3838
+ attachSessionListeners(session2);
3839
+ syncSessionLayout(session2);
3840
+ return true;
3841
+ }
3842
+ function releaseIphoneLandscapeFullscreen(element, holder) {
3843
+ const session2 = activeSession;
3844
+ if (!session2 || session2.element !== element) {
3845
+ return;
3846
+ }
3847
+ session2.holders.delete(holder);
3848
+ if (session2.holders.size > 0) {
3849
+ return;
3850
+ }
3851
+ endSession(session2);
3852
+ }
3853
+ function isIphoneLandscapeFullscreenActive(element) {
3854
+ if (!activeSession) {
3855
+ return false;
3856
+ }
3857
+ if (!element) {
3858
+ return true;
3859
+ }
3860
+ return activeSession.element === element || activeSession.element.contains(element) || element.contains(activeSession.element);
3861
+ }
3862
+ function getIphoneLandscapeFullscreenSnapshot() {
3863
+ return lastSnapshot;
3864
+ }
3865
+ function subscribeIphoneLandscapeFullscreen(onChange) {
3866
+ globalListeners.add(onChange);
3867
+ return () => {
3868
+ globalListeners.delete(onChange);
3869
+ };
3870
+ }
3871
+
3872
+ // src/ios-landscape-fullscreen-chrome.tsx
3873
+ import { useSyncExternalStore } from "react";
3874
+
3875
+ // src/webvr/host.ts
3876
+ import { createContext as createContext5 } from "react";
3877
+ var WebVRRuntimeContext = createContext5(null);
3878
+ function createWebVRHost() {
3879
+ return {
3880
+ controller: null,
3881
+ revision: 0,
3882
+ snapshot: {
3883
+ available: false,
3884
+ chrome: true,
3885
+ mode: null,
3886
+ setupOpen: false,
3887
+ settings: { screensize: "auto", profileId: "cardboard-v1" }
3888
+ },
3889
+ listeners: /* @__PURE__ */ new Set()
3890
+ };
3891
+ }
3892
+ function updateWebVRHost(host, snapshot) {
3893
+ host.snapshot = { ...host.snapshot, ...snapshot };
3894
+ host.revision += 1;
3895
+ for (const listener of host.listeners) {
3896
+ listener();
3897
+ }
3898
+ }
3899
+ function subscribeWebVRHost(host, listener) {
3900
+ host.listeners.add(listener);
3901
+ return () => {
3902
+ host.listeners.delete(listener);
3903
+ };
3904
+ }
3905
+
3906
+ // src/ios-landscape-fullscreen-chrome.tsx
3907
+ import { jsx, jsxs } from "react/jsx-runtime";
3908
+ function RotatePhoneIcon() {
3909
+ return /* @__PURE__ */ jsxs(
3910
+ "svg",
3911
+ {
3912
+ "aria-hidden": "true",
3913
+ className: "pano-webvr-portrait-icon",
3914
+ fill: "none",
3915
+ height: "48",
3916
+ stroke: "currentColor",
3917
+ strokeLinecap: "round",
3918
+ strokeLinejoin: "round",
3919
+ strokeWidth: "2",
3920
+ viewBox: "0 0 48 48",
3921
+ width: "48",
3922
+ children: [
3923
+ /* @__PURE__ */ jsx("rect", { height: "28", rx: "3", width: "18", x: "15", y: "6" }),
3924
+ /* @__PURE__ */ jsx("path", { d: "M10 34c-3-3-4-7-3-11" }),
3925
+ /* @__PURE__ */ jsx("path", { d: "M8 36l2-2 2 2" }),
3926
+ /* @__PURE__ */ jsx("path", { d: "M38 14c3 3 4 7 3 11" }),
3927
+ /* @__PURE__ */ jsx("path", { d: "M40 12l-2 2-2-2" })
3928
+ ]
3929
+ }
3930
+ );
3931
+ }
3932
+ function swipeMessage(state) {
3933
+ switch (state) {
3934
+ case 0:
3935
+ return null;
3936
+ case 1:
3937
+ return "Swipe up to hide the browser bars";
3938
+ case 2:
3939
+ return "Swipe down, then swipe up to hide the browser bars";
3940
+ default: {
3941
+ const _exhaustive = state;
3942
+ return _exhaustive;
3943
+ }
3944
+ }
3945
+ }
3946
+ function IphoneLandscapeFullscreenChrome({
3947
+ webVRHost
3948
+ }) {
3949
+ const snapshot = useSyncExternalStore(
3950
+ subscribeIphoneLandscapeFullscreen,
3951
+ getIphoneLandscapeFullscreenSnapshot,
3952
+ getIphoneLandscapeFullscreenSnapshot
3953
+ );
3954
+ useSyncExternalStore(
3955
+ (listener) => subscribeWebVRHost(webVRHost, listener),
3956
+ () => webVRHost.revision,
3957
+ () => webVRHost.revision
3958
+ );
3959
+ if (!snapshot.active) {
3960
+ return null;
3961
+ }
3962
+ const vrMode = webVRHost.snapshot.mode;
3963
+ const vrOwnsPortraitPrompt = vrMode === "mobilevr";
3964
+ if (snapshot.portrait) {
3965
+ if (vrOwnsPortraitPrompt) {
3966
+ return null;
3967
+ }
3968
+ return /* @__PURE__ */ jsxs("div", { className: "pano-webvr-portrait-prompt", role: "status", children: [
3969
+ /* @__PURE__ */ jsx(RotatePhoneIcon, {}),
3970
+ /* @__PURE__ */ jsx("p", { className: "pano-webvr-portrait-text", children: "Rotate your phone to landscape" })
3971
+ ] });
3972
+ }
3973
+ const message = swipeMessage(snapshot.state);
3974
+ if (!message) {
3975
+ return null;
3976
+ }
3977
+ return /* @__PURE__ */ jsx(
3978
+ "div",
3979
+ {
3980
+ className: "pano-iphone-fullscreen-swipe-prompt",
3981
+ role: "status",
3982
+ children: /* @__PURE__ */ jsx("p", { className: "pano-iphone-fullscreen-swipe-text", children: message })
3983
+ }
3984
+ );
3985
+ }
3986
+
3467
3987
  // src/hotspot/accessibility.tsx
3468
3988
  import {
3469
- createContext as createContext5,
3989
+ createContext as createContext6,
3470
3990
  useCallback,
3471
3991
  useContext as useContext3,
3472
3992
  useEffect as useEffect3,
@@ -3474,8 +3994,8 @@ import {
3474
3994
  useRef as useRef3,
3475
3995
  useState
3476
3996
  } from "react";
3477
- import { jsx } from "react/jsx-runtime";
3478
- var HotspotAccessibilityContext = createContext5(null);
3997
+ import { jsx as jsx2 } from "react/jsx-runtime";
3998
+ var HotspotAccessibilityContext = createContext6(null);
3479
3999
  function warnAboutMissingLabel(id) {
3480
4000
  const nodeEnv = globalThis.process?.env?.NODE_ENV;
3481
4001
  if (nodeEnv !== "production") {
@@ -3544,7 +4064,7 @@ function useHotspotAccessibilityLayer() {
3544
4064
  [register]
3545
4065
  );
3546
4066
  const controls = useMemo(
3547
- () => /* @__PURE__ */ jsx("div", { "aria-label": "Panorama hotspots", style: { pointerEvents: "none" }, children: Array.from(entries.values()).map((entry) => /* @__PURE__ */ jsx(
4067
+ () => /* @__PURE__ */ jsx2("div", { "aria-label": "Panorama hotspots", style: { pointerEvents: "none" }, children: Array.from(entries.values()).map((entry) => /* @__PURE__ */ jsx2(
3548
4068
  "button",
3549
4069
  {
3550
4070
  "aria-label": entry.label,
@@ -3569,8 +4089,8 @@ function useHotspotAccessibilityLayer() {
3569
4089
  }
3570
4090
 
3571
4091
  // src/hotspot/target-registry.ts
3572
- import { createContext as createContext6 } from "react";
3573
- var HotspotTargetRegistryContext = createContext6(
4092
+ import { createContext as createContext7 } from "react";
4093
+ var HotspotTargetRegistryContext = createContext7(
3574
4094
  null
3575
4095
  );
3576
4096
  function createHotspotTargetRegistry() {
@@ -4280,7 +4800,7 @@ function MouseControls({
4280
4800
  }
4281
4801
 
4282
4802
  // src/pano-filter/host.ts
4283
- import { createContext as createContext7, useContext as useContext6, useSyncExternalStore } from "react";
4803
+ import { createContext as createContext8, useContext as useContext6, useSyncExternalStore as useSyncExternalStore2 } from "react";
4284
4804
 
4285
4805
  // src/pano-filter/presets.ts
4286
4806
  var PANO_FILTER_PRESETS = [
@@ -4325,7 +4845,7 @@ function resolvePanoFilterSnapshot(input) {
4325
4845
  }
4326
4846
 
4327
4847
  // src/pano-filter/host.ts
4328
- var PanoFilterHostContext = createContext7(null);
4848
+ var PanoFilterHostContext = createContext8(null);
4329
4849
  function createPanoFilterHost() {
4330
4850
  return {
4331
4851
  snapshot: { ...DEFAULT_PANO_FILTER_SNAPSHOT },
@@ -4380,7 +4900,7 @@ function subscribeNoop() {
4380
4900
  }
4381
4901
  function usePanoFilterSnapshot() {
4382
4902
  const host = useContext6(PanoFilterHostContext);
4383
- const revision = useSyncExternalStore(
4903
+ const revision = useSyncExternalStore2(
4384
4904
  host ? (onStoreChange) => subscribePanoFilterHost(host, onStoreChange) : subscribeNoop,
4385
4905
  () => host ? getPanoFilterHostRevision(host) : 0,
4386
4906
  () => host ? getPanoFilterHostRevision(host) : 0
@@ -4395,8 +4915,8 @@ function isProduction2() {
4395
4915
 
4396
4916
  // src/media-activation.tsx
4397
4917
  var import_howler2 = __toESM(require_howler());
4398
- import { createContext as createContext8, useContext as useContext7, useEffect as useEffect6, useRef as useRef6 } from "react";
4399
- var PanoMediaActivationHostContext = createContext8(null);
4918
+ import { createContext as createContext9, useContext as useContext7, useEffect as useEffect6, useRef as useRef6 } from "react";
4919
+ var PanoMediaActivationHostContext = createContext9(null);
4400
4920
  function createPanoMediaActivationHost() {
4401
4921
  return { intents: /* @__PURE__ */ new Set(), listeners: /* @__PURE__ */ new Set(), revision: 0 };
4402
4922
  }
@@ -4449,7 +4969,7 @@ function usePanoMediaActivationIntent(required) {
4449
4969
 
4450
4970
  // src/pano-context-menu.tsx
4451
4971
  import {
4452
- createContext as createContext9,
4972
+ createContext as createContext10,
4453
4973
  useCallback as useCallback2,
4454
4974
  useContext as useContext8,
4455
4975
  useEffect as useEffect7,
@@ -4459,11 +4979,11 @@ import {
4459
4979
  useRef as useRef7,
4460
4980
  useState as useState2
4461
4981
  } from "react";
4462
- import { jsx as jsx2, jsxs } from "react/jsx-runtime";
4982
+ import { jsx as jsx3, jsxs as jsxs2 } from "react/jsx-runtime";
4463
4983
  var DEFAULT_ICON_SIZE = 16;
4464
4984
  var MENU_EDGE_PADDING = 8;
4465
4985
  var MIN_PANO_CONTEXT_MENU_BACKGROUND_OPACITY = 0.4;
4466
- var PanoContextMenuOverlayContext = createContext9(null);
4986
+ var PanoContextMenuOverlayContext = createContext10(null);
4467
4987
  var DEFAULT_APPEARANCE = {
4468
4988
  background: "#161616",
4469
4989
  color: "#f4f4f4",
@@ -4622,7 +5142,7 @@ function DefaultContextMenuPanel({
4622
5142
  padding: resolved.padding,
4623
5143
  ...style
4624
5144
  };
4625
- return /* @__PURE__ */ jsxs(
5145
+ return /* @__PURE__ */ jsxs2(
4626
5146
  "div",
4627
5147
  {
4628
5148
  ref: menuRef,
@@ -4633,7 +5153,7 @@ function DefaultContextMenuPanel({
4633
5153
  style: panelStyle,
4634
5154
  tabIndex: -1,
4635
5155
  children: [
4636
- /* @__PURE__ */ jsx2(
5156
+ /* @__PURE__ */ jsx3(
4637
5157
  "div",
4638
5158
  {
4639
5159
  "aria-hidden": true,
@@ -4645,9 +5165,9 @@ function DefaultContextMenuPanel({
4645
5165
  }
4646
5166
  }
4647
5167
  ),
4648
- /* @__PURE__ */ jsx2("div", { className: "pano-context-menu-items", children: visibleItems.map((item, index) => {
5168
+ /* @__PURE__ */ jsx3("div", { className: "pano-context-menu-items", children: visibleItems.map((item, index) => {
4649
5169
  if (!isActionItem(item)) {
4650
- return /* @__PURE__ */ jsx2(
5170
+ return /* @__PURE__ */ jsx3(
4651
5171
  "div",
4652
5172
  {
4653
5173
  "aria-hidden": true,
@@ -4664,7 +5184,7 @@ function DefaultContextMenuPanel({
4664
5184
  );
4665
5185
  }
4666
5186
  const disabled = item.disabled === true;
4667
- const iconNode = item.icon ?? (item.image ? /* @__PURE__ */ jsx2(
5187
+ const iconNode = item.icon ?? (item.image ? /* @__PURE__ */ jsx3(
4668
5188
  "img",
4669
5189
  {
4670
5190
  alt: item.imageAlt ?? "",
@@ -4678,7 +5198,7 @@ function DefaultContextMenuPanel({
4678
5198
  }
4679
5199
  }
4680
5200
  ) : null);
4681
- return /* @__PURE__ */ jsxs(
5201
+ return /* @__PURE__ */ jsxs2(
4682
5202
  "button",
4683
5203
  {
4684
5204
  "aria-disabled": disabled || void 0,
@@ -4714,7 +5234,7 @@ function DefaultContextMenuPanel({
4714
5234
  tabIndex: disabled ? -1 : activeIndex === index ? 0 : -1,
4715
5235
  type: "button",
4716
5236
  children: [
4717
- /* @__PURE__ */ jsx2(
5237
+ /* @__PURE__ */ jsx3(
4718
5238
  "span",
4719
5239
  {
4720
5240
  "aria-hidden": true,
@@ -4726,7 +5246,7 @@ function DefaultContextMenuPanel({
4726
5246
  children: iconNode
4727
5247
  }
4728
5248
  ),
4729
- /* @__PURE__ */ jsx2("span", { style: { flex: 1 }, children: item.label })
5249
+ /* @__PURE__ */ jsx3("span", { style: { flex: 1 }, children: item.label })
4730
5250
  ]
4731
5251
  },
4732
5252
  item.id
@@ -4779,7 +5299,7 @@ function PositionedMenuShell({
4779
5299
  top: Math.min(Math.max(rawTop, MENU_EDGE_PADDING), maxTop)
4780
5300
  });
4781
5301
  }, [clientX, clientY, overlayElement, children, viewportRevision]);
4782
- return /* @__PURE__ */ jsx2(
5302
+ return /* @__PURE__ */ jsx3(
4783
5303
  "div",
4784
5304
  {
4785
5305
  className: "pano-context-menu-shell",
@@ -4838,7 +5358,7 @@ function usePanoContextMenuOverlay() {
4838
5358
  document.removeEventListener("keydown", handleKeyDown);
4839
5359
  };
4840
5360
  }, [session2]);
4841
- const overlay = /* @__PURE__ */ jsx2(
5361
+ const overlay = /* @__PURE__ */ jsx3(
4842
5362
  "div",
4843
5363
  {
4844
5364
  ref: setOverlayNode,
@@ -4849,7 +5369,7 @@ function usePanoContextMenuOverlay() {
4849
5369
  position: "absolute",
4850
5370
  zIndex: 20
4851
5371
  },
4852
- children: session2 ? /* @__PURE__ */ jsx2(
5372
+ children: session2 ? /* @__PURE__ */ jsx3(
4853
5373
  PositionedMenuShell,
4854
5374
  {
4855
5375
  clientX: session2.event.clientX,
@@ -4943,9 +5463,9 @@ function PanoContextMenu({
4943
5463
  view,
4944
5464
  render: () => {
4945
5465
  if (hasCustomChildren && current.children) {
4946
- return /* @__PURE__ */ jsx2("div", { "data-pano-context-menu": true, style: { pointerEvents: "auto" }, children: current.children({ event, view, close }) });
5466
+ return /* @__PURE__ */ jsx3("div", { "data-pano-context-menu": true, style: { pointerEvents: "auto" }, children: current.children({ event, view, close }) });
4947
5467
  }
4948
- return /* @__PURE__ */ jsx2(
5468
+ return /* @__PURE__ */ jsx3(
4949
5469
  DefaultContextMenuPanel,
4950
5470
  {
4951
5471
  appearance: current.appearance,
@@ -4983,7 +5503,7 @@ function PanoContextMenu({
4983
5503
  return null;
4984
5504
  }
4985
5505
  function ResetViewIcon() {
4986
- return /* @__PURE__ */ jsxs(
5506
+ return /* @__PURE__ */ jsxs2(
4987
5507
  "svg",
4988
5508
  {
4989
5509
  "aria-hidden": true,
@@ -4996,14 +5516,14 @@ function ResetViewIcon() {
4996
5516
  viewBox: "0 0 16 16",
4997
5517
  width: "100%",
4998
5518
  children: [
4999
- /* @__PURE__ */ jsx2("path", { d: "M3.5 6.5A4.5 4.5 0 1 1 4 10" }),
5000
- /* @__PURE__ */ jsx2("path", { d: "M3.5 3.5v3h3" })
5519
+ /* @__PURE__ */ jsx3("path", { d: "M3.5 6.5A4.5 4.5 0 1 1 4 10" }),
5520
+ /* @__PURE__ */ jsx3("path", { d: "M3.5 3.5v3h3" })
5001
5521
  ]
5002
5522
  }
5003
5523
  );
5004
5524
  }
5005
5525
  function FullscreenIcon() {
5006
- return /* @__PURE__ */ jsx2(
5526
+ return /* @__PURE__ */ jsx3(
5007
5527
  "svg",
5008
5528
  {
5009
5529
  "aria-hidden": true,
@@ -5015,12 +5535,12 @@ function FullscreenIcon() {
5015
5535
  strokeWidth: "1.75",
5016
5536
  viewBox: "0 0 16 16",
5017
5537
  width: "100%",
5018
- children: /* @__PURE__ */ jsx2("path", { d: "M3 6V3h3M10 3h3v3M13 10v3h-3M6 13H3v-3" })
5538
+ children: /* @__PURE__ */ jsx3("path", { d: "M3 6V3h3M10 3h3v3M13 10v3h-3M6 13H3v-3" })
5019
5539
  }
5020
5540
  );
5021
5541
  }
5022
5542
  function ExitFullscreenIcon() {
5023
- return /* @__PURE__ */ jsx2(
5543
+ return /* @__PURE__ */ jsx3(
5024
5544
  "svg",
5025
5545
  {
5026
5546
  "aria-hidden": true,
@@ -5032,7 +5552,7 @@ function ExitFullscreenIcon() {
5032
5552
  strokeWidth: "1.75",
5033
5553
  viewBox: "0 0 16 16",
5034
5554
  width: "100%",
5035
- children: /* @__PURE__ */ jsx2("path", { d: "M6 3v3H3M10 3v3h3M3 10h3v3M10 10h3v3" })
5555
+ children: /* @__PURE__ */ jsx3("path", { d: "M6 3v3H3M10 3v3h3M3 10h3v3M10 10h3v3" })
5036
5556
  }
5037
5557
  );
5038
5558
  }
@@ -5041,7 +5561,7 @@ function createPanoContextMenuPresets(actions) {
5041
5561
  const resetView = {
5042
5562
  id: "pano-reset-view",
5043
5563
  label: "Reset view",
5044
- icon: /* @__PURE__ */ jsx2(ResetViewIcon, {}),
5564
+ icon: /* @__PURE__ */ jsx3(ResetViewIcon, {}),
5045
5565
  onSelect: () => {
5046
5566
  actions.reset();
5047
5567
  }
@@ -5049,7 +5569,7 @@ function createPanoContextMenuPresets(actions) {
5049
5569
  const fullscreen = {
5050
5570
  id: "pano-fullscreen",
5051
5571
  label: isFullscreen ? "Exit fullscreen" : "Enter fullscreen",
5052
- icon: isFullscreen ? /* @__PURE__ */ jsx2(ExitFullscreenIcon, {}) : /* @__PURE__ */ jsx2(FullscreenIcon, {}),
5572
+ icon: isFullscreen ? /* @__PURE__ */ jsx3(ExitFullscreenIcon, {}) : /* @__PURE__ */ jsx3(FullscreenIcon, {}),
5053
5573
  onSelect: () => {
5054
5574
  actions.toggleFullscreen();
5055
5575
  }
@@ -5142,19 +5662,19 @@ function composePanoContextMenuItems(props, presets) {
5142
5662
  ...resolvePanoContextMenuEntries(props.append ?? [], presets)
5143
5663
  ];
5144
5664
  }
5145
- var PanoContextMenuActionsContext = createContext9(null);
5665
+ var PanoContextMenuActionsContext = createContext10(null);
5146
5666
 
5147
5667
  // src/pano-cursor.tsx
5148
5668
  import { useThree as useThree4 } from "@react-three/fiber";
5149
5669
  import {
5150
- createContext as createContext10,
5670
+ createContext as createContext11,
5151
5671
  useCallback as useCallback3,
5152
5672
  useContext as useContext9,
5153
5673
  useEffect as useEffect8,
5154
5674
  useMemo as useMemo4,
5155
5675
  useRef as useRef8
5156
5676
  } from "react";
5157
- import { jsx as jsx3 } from "react/jsx-runtime";
5677
+ import { jsx as jsx4 } from "react/jsx-runtime";
5158
5678
  var DEFAULT_PANO_CURSORS = {
5159
5679
  default: "grab",
5160
5680
  dragging: "grabbing",
@@ -5168,7 +5688,7 @@ var LAYER_PRIORITY = {
5168
5688
  hotspotDragging: 3,
5169
5689
  hidden: 4
5170
5690
  };
5171
- var PanoCursorContext = createContext10(null);
5691
+ var PanoCursorContext = createContext11(null);
5172
5692
  function usePanoCursor() {
5173
5693
  return useContext9(PanoCursorContext);
5174
5694
  }
@@ -5296,7 +5816,7 @@ function PanoCursorController({
5296
5816
  release(PANO_DRAG_CLAIM_ID);
5297
5817
  };
5298
5818
  }, [claim, eventBus, release]);
5299
- return /* @__PURE__ */ jsx3(PanoCursorContext.Provider, { value: api, children });
5819
+ return /* @__PURE__ */ jsx4(PanoCursorContext.Provider, { value: api, children });
5300
5820
  }
5301
5821
 
5302
5822
  // src/pano-events.tsx
@@ -5517,11 +6037,14 @@ function usePanoEvents({
5517
6037
  }
5518
6038
  const wasFullscreenRef = { current: false };
5519
6039
  const isViewerFullscreen = () => {
6040
+ const canvas = gl.domElement;
6041
+ if (isIphoneLandscapeFullscreenActive(canvas)) {
6042
+ return true;
6043
+ }
5520
6044
  const fullscreenElement = getFullscreenElement();
5521
6045
  if (!fullscreenElement) {
5522
6046
  return false;
5523
6047
  }
5524
- const canvas = gl.domElement;
5525
6048
  return fullscreenElement === canvas || fullscreenElement.contains(canvas) || canvas.contains(fullscreenElement);
5526
6049
  };
5527
6050
  const handleFullscreenChange = () => {
@@ -5535,7 +6058,14 @@ function usePanoEvents({
5535
6058
  }
5536
6059
  };
5537
6060
  wasFullscreenRef.current = isViewerFullscreen();
5538
- return subscribeFullscreenChange(handleFullscreenChange);
6061
+ const unsubscribeApi = subscribeFullscreenChange(handleFullscreenChange);
6062
+ const unsubscribeIphone = subscribeIphoneLandscapeFullscreen(
6063
+ handleFullscreenChange
6064
+ );
6065
+ return () => {
6066
+ unsubscribeApi();
6067
+ unsubscribeIphone();
6068
+ };
5539
6069
  }, [gl]);
5540
6070
  useEffect9(() => {
5541
6071
  const element = gl.domElement;
@@ -5623,7 +6153,7 @@ function createPanoModalHost() {
5623
6153
 
5624
6154
  // src/overlay/pano-overlay.tsx
5625
6155
  import {
5626
- createContext as createContext11,
6156
+ createContext as createContext12,
5627
6157
  useContext as useContext11,
5628
6158
  useLayoutEffect as useLayoutEffect3,
5629
6159
  useMemo as useMemo5,
@@ -5640,9 +6170,9 @@ function getOverlayVisibleRect(rect, viewport) {
5640
6170
  }
5641
6171
 
5642
6172
  // src/overlay/pano-overlay.tsx
5643
- import { jsx as jsx4 } from "react/jsx-runtime";
5644
- var PanoOverlayContext = createContext11(null);
5645
- var PanoModalHostContext = createContext11(null);
6173
+ import { jsx as jsx5 } from "react/jsx-runtime";
6174
+ var PanoOverlayContext = createContext12(null);
6175
+ var PanoModalHostContext = createContext12(null);
5646
6176
  function usePanoOverlay() {
5647
6177
  const context = useContext11(PanoOverlayContext);
5648
6178
  if (!context) throw new Error("usePanoOverlay must be used inside PanoViewer.renderOverlay.");
@@ -5659,7 +6189,7 @@ function PanoOverlayPortalProvider({
5659
6189
  }) {
5660
6190
  const context = usePanoOverlay();
5661
6191
  const value = useMemo5(() => ({ ...context, portalContainer: container }), [context, container]);
5662
- return /* @__PURE__ */ jsx4(PanoOverlayContext.Provider, { value, children });
6192
+ return /* @__PURE__ */ jsx5(PanoOverlayContext.Provider, { value, children });
5663
6193
  }
5664
6194
  function usePanoOverlayHost(isFullscreen) {
5665
6195
  const [portalContainer, setPortalContainer] = useState3(null);
@@ -5796,7 +6326,7 @@ var DEFAULT_PANORAMA_CAMERA_NEAR = 0.1;
5796
6326
  var DEFAULT_PANORAMA_CAMERA_FAR = DEFAULT_PANORAMA_RADIUS * 2;
5797
6327
 
5798
6328
  // src/panorama-event-surface.tsx
5799
- import { jsx as jsx5, jsxs as jsxs2 } from "react/jsx-runtime";
6329
+ import { jsx as jsx6, jsxs as jsxs3 } from "react/jsx-runtime";
5800
6330
  var EVENT_SURFACE_RADIUS = DEFAULT_PANORAMA_RADIUS - 1;
5801
6331
  function makePanoramaPointerEvent(event) {
5802
6332
  const nativeEvent = event.nativeEvent;
@@ -5854,7 +6384,7 @@ function PanoramaEventSurface() {
5854
6384
  event.stopPropagation();
5855
6385
  eventBus.emit(type, makePanoramaPointerEvent(event));
5856
6386
  };
5857
- return /* @__PURE__ */ jsxs2(
6387
+ return /* @__PURE__ */ jsxs3(
5858
6388
  "mesh",
5859
6389
  {
5860
6390
  renderOrder: -200,
@@ -5864,8 +6394,8 @@ function PanoramaEventSurface() {
5864
6394
  onPointerUp: (event) => emit("pointerup", event),
5865
6395
  onPointerMove: (event) => emit("pointermove", event),
5866
6396
  children: [
5867
- /* @__PURE__ */ jsx5("sphereGeometry", { args: [EVENT_SURFACE_RADIUS, 64, 32] }),
5868
- /* @__PURE__ */ jsx5(
6397
+ /* @__PURE__ */ jsx6("sphereGeometry", { args: [EVENT_SURFACE_RADIUS, 64, 32] }),
6398
+ /* @__PURE__ */ jsx6(
5869
6399
  "meshBasicMaterial",
5870
6400
  {
5871
6401
  colorWrite: false,
@@ -5882,8 +6412,8 @@ function PanoramaEventSurface() {
5882
6412
  }
5883
6413
 
5884
6414
  // src/scenes-host.ts
5885
- import { createContext as createContext12 } from "react";
5886
- var ScenesHostContext = createContext12(null);
6415
+ import { createContext as createContext13 } from "react";
6416
+ var ScenesHostContext = createContext13(null);
5887
6417
  function createScenesHost() {
5888
6418
  return {
5889
6419
  controller: null,
@@ -5934,6 +6464,7 @@ function TouchControls({
5934
6464
  const drag = createPointerDrag(camera, element, () => controlsRef.current, "touch");
5935
6465
  const pending = /* @__PURE__ */ new Set();
5936
6466
  let disposed = false;
6467
+ let allowsDocumentScroll = getIphoneLandscapeFullscreenSnapshot().allowsDocumentScroll;
5937
6468
  const clearPointers = () => {
5938
6469
  pending.clear();
5939
6470
  for (const pointerId of pointersRef.current.keys()) {
@@ -5954,6 +6485,16 @@ function TouchControls({
5954
6485
  clearPointers();
5955
6486
  return;
5956
6487
  }
6488
+ const unsubscribeIphone = subscribeIphoneLandscapeFullscreen(() => {
6489
+ const next = getIphoneLandscapeFullscreenSnapshot().allowsDocumentScroll;
6490
+ if (next === allowsDocumentScroll) {
6491
+ return;
6492
+ }
6493
+ allowsDocumentScroll = next;
6494
+ if (next) {
6495
+ clearPointers();
6496
+ }
6497
+ });
5957
6498
  const syncActive = (cancelled = false) => {
5958
6499
  controlsRef.current?.setPointerActive(
5959
6500
  "touch",
@@ -5965,6 +6506,9 @@ function TouchControls({
5965
6506
  if (disposed || controlsRef.current?.isInteractionLocked()) {
5966
6507
  return;
5967
6508
  }
6509
+ if (allowsDocumentScroll) {
6510
+ return;
6511
+ }
5968
6512
  if (pointersRef.current.has(event.pointerId)) {
5969
6513
  return;
5970
6514
  }
@@ -5992,6 +6536,9 @@ function TouchControls({
5992
6536
  if (controlsRef.current?.isInteractionLocked()) {
5993
6537
  return;
5994
6538
  }
6539
+ if (allowsDocumentScroll) {
6540
+ return;
6541
+ }
5995
6542
  event.preventDefault();
5996
6543
  const pointerId = event.pointerId;
5997
6544
  pending.add(pointerId);
@@ -6013,6 +6560,9 @@ function TouchControls({
6013
6560
  if (!previous) {
6014
6561
  return;
6015
6562
  }
6563
+ if (allowsDocumentScroll) {
6564
+ return;
6565
+ }
6016
6566
  event.preventDefault();
6017
6567
  const next = {
6018
6568
  x: event.clientX,
@@ -6071,6 +6621,7 @@ function TouchControls({
6071
6621
  return () => {
6072
6622
  disposed = true;
6073
6623
  validateDragRef.current = void 0;
6624
+ unsubscribeIphone();
6074
6625
  element.removeEventListener("pointerdown", onPointerDown);
6075
6626
  element.removeEventListener("pointermove", onPointerMove);
6076
6627
  element.removeEventListener("pointerup", releasePointer);
@@ -6083,9 +6634,9 @@ function TouchControls({
6083
6634
  }
6084
6635
 
6085
6636
  // src/video/chrome-overlay.tsx
6086
- import { createContext as createContext13, useCallback as useCallback4, useMemo as useMemo6, useState as useState4 } from "react";
6087
- import { jsx as jsx6 } from "react/jsx-runtime";
6088
- var PanoChromeOverlayContext = createContext13(null);
6637
+ import { createContext as createContext14, useCallback as useCallback4, useMemo as useMemo6, useState as useState4 } from "react";
6638
+ import { jsx as jsx7 } from "react/jsx-runtime";
6639
+ var PanoChromeOverlayContext = createContext14(null);
6089
6640
  function usePanoChromeOverlay() {
6090
6641
  const [overlayElement, setOverlayElement] = useState4(
6091
6642
  null
@@ -6097,7 +6648,7 @@ function usePanoChromeOverlay() {
6097
6648
  () => ({ overlayElement }),
6098
6649
  [overlayElement]
6099
6650
  );
6100
- const overlay = /* @__PURE__ */ jsx6(
6651
+ const overlay = /* @__PURE__ */ jsx7(
6101
6652
  "div",
6102
6653
  {
6103
6654
  className: "pano-chrome-overlay",
@@ -6109,9 +6660,9 @@ function usePanoChromeOverlay() {
6109
6660
  }
6110
6661
 
6111
6662
  // src/video/host.ts
6112
- import { createContext as createContext14, useContext as useContext14 } from "react";
6113
- var PanoVideoHostContext = createContext14(null);
6114
- var DefaultPanoVideoControlsContext = createContext14(false);
6663
+ import { createContext as createContext15, useContext as useContext14 } from "react";
6664
+ var PanoVideoHostContext = createContext15(null);
6665
+ var DefaultPanoVideoControlsContext = createContext15(false);
6115
6666
  function createPanoVideoHost() {
6116
6667
  return {
6117
6668
  controller: null,
@@ -6170,11 +6721,11 @@ function useClaimPanoVideoControls() {
6170
6721
  }
6171
6722
 
6172
6723
  // src/video/pano-video-chrome-bridge.tsx
6173
- import { useSyncExternalStore as useSyncExternalStore4 } from "react";
6724
+ import { useSyncExternalStore as useSyncExternalStore5 } from "react";
6174
6725
 
6175
6726
  // src/video/pano-video-captions.tsx
6176
- import { useSyncExternalStore as useSyncExternalStore2 } from "react";
6177
- import { jsx as jsx7 } from "react/jsx-runtime";
6727
+ import { useSyncExternalStore as useSyncExternalStore3 } from "react";
6728
+ import { jsx as jsx8 } from "react/jsx-runtime";
6178
6729
  var DEFAULT_PANO_VIDEO_CAPTION_APPEARANCE = {
6179
6730
  color: "#ffffff",
6180
6731
  background: "rgba(0, 0, 0, 0.55)",
@@ -6197,7 +6748,7 @@ function resolvePanoVideoCaptionAppearance(appearance) {
6197
6748
  function PanoVideoCaptionsOverlay({
6198
6749
  controller
6199
6750
  }) {
6200
- const snapshot = useSyncExternalStore2(
6751
+ const snapshot = useSyncExternalStore3(
6201
6752
  controller.subscribe,
6202
6753
  controller.getSnapshot,
6203
6754
  controller.getSnapshot
@@ -6222,13 +6773,13 @@ function PanoVideoCaptionsOverlay({
6222
6773
  textShadow: snapshot.captionAppearance.textShadow,
6223
6774
  whiteSpace: "pre-wrap"
6224
6775
  };
6225
- return /* @__PURE__ */ jsx7(
6776
+ return /* @__PURE__ */ jsx8(
6226
6777
  "div",
6227
6778
  {
6228
6779
  className: "pano-video-captions",
6229
6780
  "data-pano-video-captions": "",
6230
6781
  style: wrapperStyle,
6231
- children: /* @__PURE__ */ jsx7("div", { style: textStyle, children: snapshot.captionText })
6782
+ children: /* @__PURE__ */ jsx8("div", { style: textStyle, children: snapshot.captionText })
6232
6783
  }
6233
6784
  );
6234
6785
  }
@@ -6247,7 +6798,7 @@ import {
6247
6798
  useMemo as useMemo7,
6248
6799
  useRef as useRef11,
6249
6800
  useState as useState5,
6250
- useSyncExternalStore as useSyncExternalStore3
6801
+ useSyncExternalStore as useSyncExternalStore4
6251
6802
  } from "react";
6252
6803
 
6253
6804
  // src/video/format.ts
@@ -6380,7 +6931,7 @@ function cueText(cue) {
6380
6931
  }
6381
6932
 
6382
6933
  // src/video/pano-video-controls.tsx
6383
- import { Fragment, jsx as jsx8, jsxs as jsxs3 } from "react/jsx-runtime";
6934
+ import { Fragment, jsx as jsx9, jsxs as jsxs4 } from "react/jsx-runtime";
6384
6935
  var DEFAULT_PANO_VIDEO_CONTROLS_APPEARANCE = {
6385
6936
  background: "rgba(16, 16, 16, 0.88)",
6386
6937
  color: "#f4f4f4",
@@ -6441,7 +6992,7 @@ function volumeFromClientY(clientY, track) {
6441
6992
  return Math.max(0, Math.min(1, (rect.bottom - clientY) / rect.height));
6442
6993
  }
6443
6994
  function Icon({ path }) {
6444
- return /* @__PURE__ */ jsx8(
6995
+ return /* @__PURE__ */ jsx9(
6445
6996
  "svg",
6446
6997
  {
6447
6998
  "aria-hidden": true,
@@ -6453,7 +7004,7 @@ function Icon({ path }) {
6453
7004
  strokeWidth: "1.75",
6454
7005
  viewBox: "0 0 16 16",
6455
7006
  width: "16",
6456
- children: /* @__PURE__ */ jsx8("path", { d: path })
7007
+ children: /* @__PURE__ */ jsx9("path", { d: path })
6457
7008
  }
6458
7009
  );
6459
7010
  }
@@ -6465,7 +7016,7 @@ function ChromeButton({
6465
7016
  label,
6466
7017
  onClick
6467
7018
  }) {
6468
- return /* @__PURE__ */ jsx8(
7019
+ return /* @__PURE__ */ jsx9(
6469
7020
  "button",
6470
7021
  {
6471
7022
  "aria-label": label,
@@ -6491,14 +7042,14 @@ function ChromeMenu({
6491
7042
  labelledBy,
6492
7043
  items
6493
7044
  }) {
6494
- return /* @__PURE__ */ jsx8(
7045
+ return /* @__PURE__ */ jsx9(
6495
7046
  ChromeMenuSurface,
6496
7047
  {
6497
7048
  appearance,
6498
7049
  id,
6499
7050
  labelledBy,
6500
7051
  role: "menu",
6501
- children: items.map((item) => /* @__PURE__ */ jsx8(
7052
+ children: items.map((item) => /* @__PURE__ */ jsx9(
6502
7053
  ChromeMenuRadioItem,
6503
7054
  {
6504
7055
  active: item.active,
@@ -6518,7 +7069,7 @@ function ChromeMenuSurface({
6518
7069
  labelledBy,
6519
7070
  role
6520
7071
  }) {
6521
- return /* @__PURE__ */ jsx8(
7072
+ return /* @__PURE__ */ jsx9(
6522
7073
  "div",
6523
7074
  {
6524
7075
  "aria-labelledby": labelledBy,
@@ -6542,7 +7093,7 @@ function ChromeMenuRadioItem({
6542
7093
  label,
6543
7094
  onClick
6544
7095
  }) {
6545
- return /* @__PURE__ */ jsx8(
7096
+ return /* @__PURE__ */ jsx9(
6546
7097
  "button",
6547
7098
  {
6548
7099
  "aria-checked": active,
@@ -6567,7 +7118,7 @@ function ChromeMenuActionItem({
6567
7118
  onClick,
6568
7119
  secondary
6569
7120
  }) {
6570
- return /* @__PURE__ */ jsxs3(
7121
+ return /* @__PURE__ */ jsxs4(
6571
7122
  "button",
6572
7123
  {
6573
7124
  className: "pano-video-chrome-menu-action",
@@ -6582,7 +7133,7 @@ function ChromeMenuActionItem({
6582
7133
  },
6583
7134
  type: "button",
6584
7135
  children: [
6585
- /* @__PURE__ */ jsx8("span", { children: label }),
7136
+ /* @__PURE__ */ jsx9("span", { children: label }),
6586
7137
  secondary
6587
7138
  ]
6588
7139
  }
@@ -6591,10 +7142,10 @@ function ChromeMenuActionItem({
6591
7142
  function ChromeMenuSectionLabel({
6592
7143
  children
6593
7144
  }) {
6594
- return /* @__PURE__ */ jsx8("div", { className: "pano-video-chrome-menu-label", children });
7145
+ return /* @__PURE__ */ jsx9("div", { className: "pano-video-chrome-menu-label", children });
6595
7146
  }
6596
7147
  function ChromeMenuDivider() {
6597
- return /* @__PURE__ */ jsx8("div", { className: "pano-video-chrome-menu-divider" });
7148
+ return /* @__PURE__ */ jsx9("div", { className: "pano-video-chrome-menu-divider" });
6598
7149
  }
6599
7150
  function CaptionsMenu({
6600
7151
  appearance,
@@ -6607,16 +7158,16 @@ function CaptionsMenu({
6607
7158
  panel,
6608
7159
  snapshot
6609
7160
  }) {
6610
- return /* @__PURE__ */ jsx8(
7161
+ return /* @__PURE__ */ jsx9(
6611
7162
  ChromeMenuSurface,
6612
7163
  {
6613
7164
  appearance,
6614
7165
  id,
6615
7166
  labelledBy,
6616
7167
  role: "menu",
6617
- children: panel === "tracks" ? /* @__PURE__ */ jsxs3(Fragment, { children: [
6618
- /* @__PURE__ */ jsxs3("div", { className: "pano-video-chrome-menu-list", children: [
6619
- /* @__PURE__ */ jsx8(
7168
+ children: panel === "tracks" ? /* @__PURE__ */ jsxs4(Fragment, { children: [
7169
+ /* @__PURE__ */ jsxs4("div", { className: "pano-video-chrome-menu-list", children: [
7170
+ /* @__PURE__ */ jsx9(
6620
7171
  ChromeMenuRadioItem,
6621
7172
  {
6622
7173
  active: snapshot.trackId === null,
@@ -6629,7 +7180,7 @@ function CaptionsMenu({
6629
7180
  ),
6630
7181
  snapshot.tracks.map((track) => {
6631
7182
  const trackItemId = panoVideoTrackId(track);
6632
- return /* @__PURE__ */ jsx8(
7183
+ return /* @__PURE__ */ jsx9(
6633
7184
  ChromeMenuRadioItem,
6634
7185
  {
6635
7186
  active: snapshot.trackId === trackItemId,
@@ -6643,29 +7194,29 @@ function CaptionsMenu({
6643
7194
  );
6644
7195
  })
6645
7196
  ] }),
6646
- /* @__PURE__ */ jsx8(ChromeMenuDivider, {}),
6647
- /* @__PURE__ */ jsx8(
7197
+ /* @__PURE__ */ jsx9(ChromeMenuDivider, {}),
7198
+ /* @__PURE__ */ jsx9(
6648
7199
  ChromeMenuActionItem,
6649
7200
  {
6650
7201
  appearance,
6651
7202
  label: "Settings",
6652
7203
  onClick: onOpenSettings,
6653
- secondary: /* @__PURE__ */ jsx8("span", { "aria-hidden": true, children: "\u203A" })
7204
+ secondary: /* @__PURE__ */ jsx9("span", { "aria-hidden": true, children: "\u203A" })
6654
7205
  }
6655
7206
  )
6656
- ] }) : /* @__PURE__ */ jsxs3(Fragment, { children: [
6657
- /* @__PURE__ */ jsx8(
7207
+ ] }) : /* @__PURE__ */ jsxs4(Fragment, { children: [
7208
+ /* @__PURE__ */ jsx9(
6658
7209
  ChromeMenuActionItem,
6659
7210
  {
6660
7211
  appearance,
6661
7212
  label: "Back",
6662
7213
  onClick: onShowTracks,
6663
- secondary: /* @__PURE__ */ jsx8("span", { "aria-hidden": true, children: "\u2039" })
7214
+ secondary: /* @__PURE__ */ jsx9("span", { "aria-hidden": true, children: "\u2039" })
6664
7215
  }
6665
7216
  ),
6666
- /* @__PURE__ */ jsx8(ChromeMenuDivider, {}),
6667
- /* @__PURE__ */ jsx8(ChromeMenuSectionLabel, { children: "Font size" }),
6668
- CAPTION_SIZE_OPTIONS.map((option) => /* @__PURE__ */ jsx8(
7217
+ /* @__PURE__ */ jsx9(ChromeMenuDivider, {}),
7218
+ /* @__PURE__ */ jsx9(ChromeMenuSectionLabel, { children: "Font size" }),
7219
+ CAPTION_SIZE_OPTIONS.map((option) => /* @__PURE__ */ jsx9(
6669
7220
  ChromeMenuRadioItem,
6670
7221
  {
6671
7222
  active: Number(snapshot.captionAppearance.fontSize) === option.value,
@@ -6677,9 +7228,9 @@ function CaptionsMenu({
6677
7228
  },
6678
7229
  option.id
6679
7230
  )),
6680
- /* @__PURE__ */ jsx8(ChromeMenuDivider, {}),
6681
- /* @__PURE__ */ jsx8(ChromeMenuSectionLabel, { children: "Background" }),
6682
- CAPTION_BACKGROUND_OPTIONS.map((option) => /* @__PURE__ */ jsx8(
7231
+ /* @__PURE__ */ jsx9(ChromeMenuDivider, {}),
7232
+ /* @__PURE__ */ jsx9(ChromeMenuSectionLabel, { children: "Background" }),
7233
+ CAPTION_BACKGROUND_OPTIONS.map((option) => /* @__PURE__ */ jsx9(
6683
7234
  ChromeMenuRadioItem,
6684
7235
  {
6685
7236
  active: snapshot.captionAppearance.background === option.value,
@@ -6720,7 +7271,7 @@ function VerticalVolumeSlider({
6720
7271
  }
6721
7272
  };
6722
7273
  const percentLabel = formatVolumePercent(volume);
6723
- return /* @__PURE__ */ jsxs3(
7274
+ return /* @__PURE__ */ jsxs4(
6724
7275
  "div",
6725
7276
  {
6726
7277
  className: "pano-video-volume-popover",
@@ -6734,7 +7285,7 @@ function VerticalVolumeSlider({
6734
7285
  pointerEvents: "auto"
6735
7286
  },
6736
7287
  children: [
6737
- /* @__PURE__ */ jsx8(
7288
+ /* @__PURE__ */ jsx9(
6738
7289
  "span",
6739
7290
  {
6740
7291
  "aria-hidden": true,
@@ -6746,14 +7297,14 @@ function VerticalVolumeSlider({
6746
7297
  children: percentLabel
6747
7298
  }
6748
7299
  ),
6749
- /* @__PURE__ */ jsx8(
7300
+ /* @__PURE__ */ jsx9(
6750
7301
  "div",
6751
7302
  {
6752
7303
  style: {
6753
7304
  paddingBottom: VOLUME_THUMB_SIZE / 2,
6754
7305
  paddingTop: VOLUME_THUMB_SIZE / 2
6755
7306
  },
6756
- children: /* @__PURE__ */ jsxs3(
7307
+ children: /* @__PURE__ */ jsxs4(
6757
7308
  "div",
6758
7309
  {
6759
7310
  "aria-label": "Volume",
@@ -6786,7 +7337,7 @@ function VerticalVolumeSlider({
6786
7337
  },
6787
7338
  tabIndex: 0,
6788
7339
  children: [
6789
- /* @__PURE__ */ jsx8(
7340
+ /* @__PURE__ */ jsx9(
6790
7341
  "div",
6791
7342
  {
6792
7343
  style: {
@@ -6801,7 +7352,7 @@ function VerticalVolumeSlider({
6801
7352
  }
6802
7353
  }
6803
7354
  ),
6804
- /* @__PURE__ */ jsx8(
7355
+ /* @__PURE__ */ jsx9(
6805
7356
  "div",
6806
7357
  {
6807
7358
  style: {
@@ -6860,17 +7411,17 @@ function VolumeControl({
6860
7411
  };
6861
7412
  }, [open, volumeAdjustable]);
6862
7413
  if (!volumeAdjustable) {
6863
- return /* @__PURE__ */ jsx8(
7414
+ return /* @__PURE__ */ jsx9(
6864
7415
  ChromeButton,
6865
7416
  {
6866
7417
  appearance,
6867
7418
  label: mutedOrSilent ? "Unmute" : "Mute",
6868
7419
  onClick: onToggleMuted,
6869
- children: mutedOrSilent ? /* @__PURE__ */ jsx8(Icon, { path: "M3 6.5h2.2L8.5 4v8L5.2 9.5H3zM10.2 6.2l3.2 3.6M13.4 6.2l-3.2 3.6" }) : /* @__PURE__ */ jsx8(Icon, { path: "M3 6.5h2.2L8.5 4v8L5.2 9.5H3zM10.5 5.5a3 3 0 0 1 0 5" })
7420
+ children: mutedOrSilent ? /* @__PURE__ */ jsx9(Icon, { path: "M3 6.5h2.2L8.5 4v8L5.2 9.5H3zM10.2 6.2l3.2 3.6M13.4 6.2l-3.2 3.6" }) : /* @__PURE__ */ jsx9(Icon, { path: "M3 6.5h2.2L8.5 4v8L5.2 9.5H3zM10.5 5.5a3 3 0 0 1 0 5" })
6870
7421
  }
6871
7422
  );
6872
7423
  }
6873
- return /* @__PURE__ */ jsxs3(
7424
+ return /* @__PURE__ */ jsxs4(
6874
7425
  "div",
6875
7426
  {
6876
7427
  "data-pano-video-volume": "",
@@ -6898,7 +7449,7 @@ function VolumeControl({
6898
7449
  },
6899
7450
  ref: rootRef,
6900
7451
  children: [
6901
- open ? /* @__PURE__ */ jsx8(
7452
+ open ? /* @__PURE__ */ jsx9(
6902
7453
  VerticalVolumeSlider,
6903
7454
  {
6904
7455
  appearance,
@@ -6906,7 +7457,7 @@ function VolumeControl({
6906
7457
  volume: displayVolume
6907
7458
  }
6908
7459
  ) : null,
6909
- /* @__PURE__ */ jsx8(
7460
+ /* @__PURE__ */ jsx9(
6910
7461
  ChromeButton,
6911
7462
  {
6912
7463
  appearance,
@@ -6917,7 +7468,7 @@ function VolumeControl({
6917
7468
  }
6918
7469
  onToggleMuted();
6919
7470
  },
6920
- children: mutedOrSilent ? /* @__PURE__ */ jsx8(Icon, { path: "M3 6.5h2.2L8.5 4v8L5.2 9.5H3zM10.2 6.2l3.2 3.6M13.4 6.2l-3.2 3.6" }) : /* @__PURE__ */ jsx8(Icon, { path: "M3 6.5h2.2L8.5 4v8L5.2 9.5H3zM10.5 5.5a3 3 0 0 1 0 5" })
7471
+ children: mutedOrSilent ? /* @__PURE__ */ jsx9(Icon, { path: "M3 6.5h2.2L8.5 4v8L5.2 9.5H3zM10.2 6.2l3.2 3.6M13.4 6.2l-3.2 3.6" }) : /* @__PURE__ */ jsx9(Icon, { path: "M3 6.5h2.2L8.5 4v8L5.2 9.5H3zM10.5 5.5a3 3 0 0 1 0 5" })
6921
7472
  }
6922
7473
  )
6923
7474
  ]
@@ -6934,7 +7485,7 @@ function PanoVideoControlsHud({
6934
7485
  () => resolveControlsAppearance(appearance),
6935
7486
  [appearance]
6936
7487
  );
6937
- const snapshot = useSyncExternalStore3(
7488
+ const snapshot = useSyncExternalStore4(
6938
7489
  controller.subscribe,
6939
7490
  controller.getSnapshot,
6940
7491
  controller.getSnapshot
@@ -6954,7 +7505,7 @@ function PanoVideoControlsHud({
6954
7505
  const moreMenuId = `${barId}-more`;
6955
7506
  const compact = overlayWidth < COMPACT_CONTROLS_WIDTH;
6956
7507
  const hideTime = overlayWidth < NARROW_CONTROLS_WIDTH;
6957
- const showFullscreen = isFullscreenEnabled();
7508
+ const showFullscreen = canEnterViewerFullscreen();
6958
7509
  const bumpVisibility = useCallback5(
6959
7510
  (playing) => {
6960
7511
  setVisible(true);
@@ -7077,7 +7628,7 @@ function PanoVideoControlsHud({
7077
7628
  let menuNode = null;
7078
7629
  switch (menu) {
7079
7630
  case "rate":
7080
- menuNode = /* @__PURE__ */ jsx8(
7631
+ menuNode = /* @__PURE__ */ jsx9(
7081
7632
  ChromeMenu,
7082
7633
  {
7083
7634
  appearance: resolved,
@@ -7096,7 +7647,7 @@ function PanoVideoControlsHud({
7096
7647
  );
7097
7648
  break;
7098
7649
  case "variant":
7099
- menuNode = /* @__PURE__ */ jsx8(
7650
+ menuNode = /* @__PURE__ */ jsx9(
7100
7651
  ChromeMenu,
7101
7652
  {
7102
7653
  appearance: resolved,
@@ -7115,7 +7666,7 @@ function PanoVideoControlsHud({
7115
7666
  );
7116
7667
  break;
7117
7668
  case "captions":
7118
- menuNode = /* @__PURE__ */ jsx8(
7669
+ menuNode = /* @__PURE__ */ jsx9(
7119
7670
  CaptionsMenu,
7120
7671
  {
7121
7672
  appearance: resolved,
@@ -7139,7 +7690,7 @@ function PanoVideoControlsHud({
7139
7690
  );
7140
7691
  break;
7141
7692
  case "more":
7142
- menuNode = /* @__PURE__ */ jsx8(
7693
+ menuNode = /* @__PURE__ */ jsx9(
7143
7694
  ChromeMenu,
7144
7695
  {
7145
7696
  appearance: resolved,
@@ -7205,9 +7756,9 @@ function PanoVideoControlsHud({
7205
7756
  transition: "opacity 160ms ease",
7206
7757
  zIndex: 2
7207
7758
  };
7208
- const rateButton = /* @__PURE__ */ jsxs3("div", { className: "pano-video-menu", "data-pano-video-menu": "rate", children: [
7759
+ const rateButton = /* @__PURE__ */ jsxs4("div", { className: "pano-video-menu", "data-pano-video-menu": "rate", children: [
7209
7760
  !compact && menu === "rate" ? menuNode : null,
7210
- /* @__PURE__ */ jsx8(
7761
+ /* @__PURE__ */ jsx9(
7211
7762
  ChromeButton,
7212
7763
  {
7213
7764
  appearance: resolved,
@@ -7215,13 +7766,13 @@ function PanoVideoControlsHud({
7215
7766
  onClick: () => {
7216
7767
  toggleMenu("rate");
7217
7768
  },
7218
- children: /* @__PURE__ */ jsx8("span", { className: "pano-video-chrome-label", id: `${barId}-rate-btn`, children: snapshot.playbackRate === 1 ? "1x" : `${snapshot.playbackRate}x` })
7769
+ children: /* @__PURE__ */ jsx9("span", { className: "pano-video-chrome-label", id: `${barId}-rate-btn`, children: snapshot.playbackRate === 1 ? "1x" : `${snapshot.playbackRate}x` })
7219
7770
  }
7220
7771
  )
7221
7772
  ] });
7222
- const variantButton = canSwitchVariant ? /* @__PURE__ */ jsxs3("div", { className: "pano-video-menu", "data-pano-video-menu": "variant", children: [
7773
+ const variantButton = canSwitchVariant ? /* @__PURE__ */ jsxs4("div", { className: "pano-video-menu", "data-pano-video-menu": "variant", children: [
7223
7774
  !compact && menu === "variant" ? menuNode : null,
7224
- /* @__PURE__ */ jsx8(
7775
+ /* @__PURE__ */ jsx9(
7225
7776
  ChromeButton,
7226
7777
  {
7227
7778
  appearance: resolved,
@@ -7229,13 +7780,13 @@ function PanoVideoControlsHud({
7229
7780
  onClick: () => {
7230
7781
  toggleMenu("variant");
7231
7782
  },
7232
- children: /* @__PURE__ */ jsx8("span", { className: "pano-video-chrome-label", id: `${barId}-variant-btn`, children: snapshot.variants.find((variant) => variant.id === snapshot.variantId)?.label ?? "Quality" })
7783
+ children: /* @__PURE__ */ jsx9("span", { className: "pano-video-chrome-label", id: `${barId}-variant-btn`, children: snapshot.variants.find((variant) => variant.id === snapshot.variantId)?.label ?? "Quality" })
7233
7784
  }
7234
7785
  )
7235
7786
  ] }) : null;
7236
- const captionsButton = showCaptionsMenu ? /* @__PURE__ */ jsxs3("div", { className: "pano-video-menu", "data-pano-video-menu": "captions", children: [
7787
+ const captionsButton = showCaptionsMenu ? /* @__PURE__ */ jsxs4("div", { className: "pano-video-menu", "data-pano-video-menu": "captions", children: [
7237
7788
  !compact && menu === "captions" ? menuNode : null,
7238
- /* @__PURE__ */ jsx8(
7789
+ /* @__PURE__ */ jsx9(
7239
7790
  ChromeButton,
7240
7791
  {
7241
7792
  appearance: resolved,
@@ -7243,18 +7794,18 @@ function PanoVideoControlsHud({
7243
7794
  onClick: () => {
7244
7795
  toggleMenu("captions");
7245
7796
  },
7246
- children: /* @__PURE__ */ jsx8("span", { id: `${barId}-captions-btn`, children: /* @__PURE__ */ jsx8(Icon, { path: "M2.5 4.5h11v7h-11zM5 7.2h2.4M5 9.2h5.5" }) })
7797
+ children: /* @__PURE__ */ jsx9("span", { id: `${barId}-captions-btn`, children: /* @__PURE__ */ jsx9(Icon, { path: "M2.5 4.5h11v7h-11zM5 7.2h2.4M5 9.2h5.5" }) })
7247
7798
  }
7248
7799
  )
7249
7800
  ] }) : null;
7250
- return /* @__PURE__ */ jsxs3(
7801
+ return /* @__PURE__ */ jsxs4(
7251
7802
  "div",
7252
7803
  {
7253
7804
  className: "pano-video-controls",
7254
7805
  "data-pano-video-controls": "",
7255
7806
  style: barStyle,
7256
7807
  children: [
7257
- /* @__PURE__ */ jsx8(
7808
+ /* @__PURE__ */ jsx9(
7258
7809
  ChromeButton,
7259
7810
  {
7260
7811
  appearance: resolved,
@@ -7262,11 +7813,11 @@ function PanoVideoControlsHud({
7262
7813
  onClick: () => {
7263
7814
  controller.togglePlay();
7264
7815
  },
7265
- children: snapshot.playing ? /* @__PURE__ */ jsx8(Icon, { path: "M5 3.5h2.2v9H5zM8.8 3.5H11v9H8.8z" }) : /* @__PURE__ */ jsx8(Icon, { path: "M5 3.2v9.6L13 8z" })
7816
+ children: snapshot.playing ? /* @__PURE__ */ jsx9(Icon, { path: "M5 3.5h2.2v9H5zM8.8 3.5H11v9H8.8z" }) : /* @__PURE__ */ jsx9(Icon, { path: "M5 3.2v9.6L13 8z" })
7266
7817
  }
7267
7818
  ),
7268
- hideTime ? null : /* @__PURE__ */ jsx8("span", { className: "pano-video-time", children: formatMediaTime(snapshot.currentTime) }),
7269
- /* @__PURE__ */ jsx8(
7819
+ hideTime ? null : /* @__PURE__ */ jsx9("span", { className: "pano-video-time", children: formatMediaTime(snapshot.currentTime) }),
7820
+ /* @__PURE__ */ jsx9(
7270
7821
  "input",
7271
7822
  {
7272
7823
  "aria-label": "Seek",
@@ -7288,8 +7839,8 @@ function PanoVideoControlsHud({
7288
7839
  value: duration > 0 ? snapshot.currentTime : 0
7289
7840
  }
7290
7841
  ),
7291
- hideTime ? null : /* @__PURE__ */ jsx8("span", { className: "pano-video-time", children: formatMediaTime(duration) }),
7292
- /* @__PURE__ */ jsx8(
7842
+ hideTime ? null : /* @__PURE__ */ jsx9("span", { className: "pano-video-time", children: formatMediaTime(duration) }),
7843
+ /* @__PURE__ */ jsx9(
7293
7844
  VolumeControl,
7294
7845
  {
7295
7846
  appearance: resolved,
@@ -7305,9 +7856,9 @@ function PanoVideoControlsHud({
7305
7856
  volumeAdjustable: snapshot.volumeAdjustable
7306
7857
  }
7307
7858
  ),
7308
- compact ? /* @__PURE__ */ jsxs3("div", { className: "pano-video-menu", "data-pano-video-menu": "more", children: [
7859
+ compact ? /* @__PURE__ */ jsxs4("div", { className: "pano-video-menu", "data-pano-video-menu": "more", children: [
7309
7860
  menu !== null ? menuNode : null,
7310
- /* @__PURE__ */ jsx8(
7861
+ /* @__PURE__ */ jsx9(
7311
7862
  ChromeButton,
7312
7863
  {
7313
7864
  appearance: resolved,
@@ -7316,15 +7867,15 @@ function PanoVideoControlsHud({
7316
7867
  onClick: () => {
7317
7868
  toggleMenu("more");
7318
7869
  },
7319
- children: /* @__PURE__ */ jsx8(Icon, { path: "M3 8a1 1 0 1 0 2 0 1 1 0 1 0-2 0M7 8a1 1 0 1 0 2 0 1 1 0 1 0-2 0M11 8a1 1 0 1 0 2 0 1 1 0 1 0-2 0" })
7870
+ children: /* @__PURE__ */ jsx9(Icon, { path: "M3 8a1 1 0 1 0 2 0 1 1 0 1 0-2 0M7 8a1 1 0 1 0 2 0 1 1 0 1 0-2 0M11 8a1 1 0 1 0 2 0 1 1 0 1 0-2 0" })
7320
7871
  }
7321
7872
  )
7322
- ] }) : /* @__PURE__ */ jsxs3(Fragment, { children: [
7873
+ ] }) : /* @__PURE__ */ jsxs4(Fragment, { children: [
7323
7874
  rateButton,
7324
7875
  variantButton,
7325
7876
  captionsButton
7326
7877
  ] }),
7327
- showFullscreen ? /* @__PURE__ */ jsx8(
7878
+ showFullscreen ? /* @__PURE__ */ jsx9(
7328
7879
  ChromeButton,
7329
7880
  {
7330
7881
  appearance: resolved,
@@ -7332,7 +7883,7 @@ function PanoVideoControlsHud({
7332
7883
  onClick: () => {
7333
7884
  fullscreen?.toggleFullscreen();
7334
7885
  },
7335
- children: fullscreen?.isFullscreen ? /* @__PURE__ */ jsx8(Icon, { path: "M6 3.5H3.5V6M10 3.5h2.5V6M6 12.5H3.5V10M10 12.5h2.5V10" }) : /* @__PURE__ */ jsx8(Icon, { path: "M3.5 6V3.5H6M10 3.5h2.5V6M3.5 10v2.5H6M10 12.5h2.5V10" })
7886
+ children: fullscreen?.isFullscreen ? /* @__PURE__ */ jsx9(Icon, { path: "M6 3.5H3.5V6M10 3.5h2.5V6M6 12.5H3.5V10M10 12.5h2.5V10" }) : /* @__PURE__ */ jsx9(Icon, { path: "M3.5 6V3.5H6M10 3.5h2.5V6M3.5 10v2.5H6M10 12.5h2.5V10" })
7336
7887
  }
7337
7888
  ) : null
7338
7889
  ]
@@ -7349,13 +7900,13 @@ function PanoVideoControls({ appearance }) {
7349
7900
  }
7350
7901
 
7351
7902
  // src/video/pano-video-chrome-bridge.tsx
7352
- import { Fragment as Fragment2, jsx as jsx9, jsxs as jsxs4 } from "react/jsx-runtime";
7903
+ import { Fragment as Fragment2, jsx as jsx10, jsxs as jsxs5 } from "react/jsx-runtime";
7353
7904
  function PanoVideoChromeBridge({
7354
7905
  fullscreen,
7355
7906
  host,
7356
7907
  overlayElement
7357
7908
  }) {
7358
- useSyncExternalStore4(
7909
+ useSyncExternalStore5(
7359
7910
  (onStoreChange) => subscribePanoVideoHost(host, onStoreChange),
7360
7911
  () => getPanoVideoHostRevision(host),
7361
7912
  () => getPanoVideoHostRevision(host)
@@ -7364,8 +7915,8 @@ function PanoVideoChromeBridge({
7364
7915
  return null;
7365
7916
  }
7366
7917
  const showDefaultControls = host.controller !== null && host.controls !== false && host.controlClaims === 0;
7367
- return /* @__PURE__ */ jsxs4(Fragment2, { children: [
7368
- showDefaultControls ? /* @__PURE__ */ jsx9(
7918
+ return /* @__PURE__ */ jsxs5(Fragment2, { children: [
7919
+ showDefaultControls ? /* @__PURE__ */ jsx10(
7369
7920
  PanoVideoControlsHud,
7370
7921
  {
7371
7922
  appearance: typeof host.controls === "object" ? host.controls : void 0,
@@ -7374,43 +7925,12 @@ function PanoVideoChromeBridge({
7374
7925
  overlayElement
7375
7926
  }
7376
7927
  ) : null,
7377
- host.captions !== false && host.controller ? /* @__PURE__ */ jsx9(PanoVideoCaptionsOverlay, { controller: host.controller }) : null
7928
+ host.captions !== false && host.controller ? /* @__PURE__ */ jsx10(PanoVideoCaptionsOverlay, { controller: host.controller }) : null
7378
7929
  ] });
7379
7930
  }
7380
7931
 
7381
7932
  // src/webvr/chrome.tsx
7382
- import { useSyncExternalStore as useSyncExternalStore5 } from "react";
7383
-
7384
- // src/webvr/host.ts
7385
- import { createContext as createContext15 } from "react";
7386
- var WebVRRuntimeContext = createContext15(null);
7387
- function createWebVRHost() {
7388
- return {
7389
- controller: null,
7390
- revision: 0,
7391
- snapshot: {
7392
- available: false,
7393
- chrome: true,
7394
- mode: null,
7395
- setupOpen: false,
7396
- settings: { screensize: "auto", profileId: "cardboard-v1" }
7397
- },
7398
- listeners: /* @__PURE__ */ new Set()
7399
- };
7400
- }
7401
- function updateWebVRHost(host, snapshot) {
7402
- host.snapshot = { ...host.snapshot, ...snapshot };
7403
- host.revision += 1;
7404
- for (const listener of host.listeners) {
7405
- listener();
7406
- }
7407
- }
7408
- function subscribeWebVRHost(host, listener) {
7409
- host.listeners.add(listener);
7410
- return () => {
7411
- host.listeners.delete(listener);
7412
- };
7413
- }
7933
+ import { useEffect as useEffect13, useState as useState6, useSyncExternalStore as useSyncExternalStore7 } from "react";
7414
7934
 
7415
7935
  // src/webvr/appearance.ts
7416
7936
  var DEFAULT_WEBVR_CHROME_APPEARANCE = {
@@ -7421,6 +7941,46 @@ var DEFAULT_WEBVR_CHROME_APPEARANCE = {
7421
7941
  fontSize: 14
7422
7942
  };
7423
7943
 
7944
+ // src/webvr/orientation.ts
7945
+ import { useSyncExternalStore as useSyncExternalStore6 } from "react";
7946
+ function subscribePortraitOrientation(onChange) {
7947
+ if (typeof window === "undefined") {
7948
+ return () => {
7949
+ };
7950
+ }
7951
+ const media = window.matchMedia("(orientation: portrait)");
7952
+ const notify2 = () => onChange();
7953
+ if (typeof media.addEventListener === "function") {
7954
+ media.addEventListener("change", notify2);
7955
+ } else {
7956
+ media.addListener(notify2);
7957
+ }
7958
+ window.addEventListener("orientationchange", notify2);
7959
+ window.addEventListener("resize", notify2);
7960
+ return () => {
7961
+ if (typeof media.removeEventListener === "function") {
7962
+ media.removeEventListener("change", notify2);
7963
+ } else {
7964
+ media.removeListener(notify2);
7965
+ }
7966
+ window.removeEventListener("orientationchange", notify2);
7967
+ window.removeEventListener("resize", notify2);
7968
+ };
7969
+ }
7970
+ function getPortraitOrientation() {
7971
+ if (typeof window === "undefined") {
7972
+ return false;
7973
+ }
7974
+ return window.matchMedia("(orientation: portrait)").matches;
7975
+ }
7976
+ function usePortraitOrientation() {
7977
+ return useSyncExternalStore6(
7978
+ subscribePortraitOrientation,
7979
+ getPortraitOrientation,
7980
+ () => false
7981
+ );
7982
+ }
7983
+
7424
7984
  // src/webvr/profiles.ts
7425
7985
  var WEBVR_PROFILE_IDS = [
7426
7986
  "none",
@@ -7527,7 +8087,7 @@ function clamp2(value, min, max) {
7527
8087
  }
7528
8088
 
7529
8089
  // src/webvr/chrome.tsx
7530
- import { Fragment as Fragment3, jsx as jsx10, jsxs as jsxs5 } from "react/jsx-runtime";
8090
+ import { Fragment as Fragment3, jsx as jsx11, jsxs as jsxs6 } from "react/jsx-runtime";
7531
8091
  function resolveAppearance(value) {
7532
8092
  return {
7533
8093
  ...DEFAULT_WEBVR_CHROME_APPEARANCE,
@@ -7539,7 +8099,7 @@ function ChromeButton2({
7539
8099
  children,
7540
8100
  onClick
7541
8101
  }) {
7542
- return /* @__PURE__ */ jsx10(
8102
+ return /* @__PURE__ */ jsx11(
7543
8103
  "button",
7544
8104
  {
7545
8105
  className: "pano-webvr-button",
@@ -7576,7 +8136,7 @@ function SetupPanel({
7576
8136
  color: appearance.color,
7577
8137
  fontSize: appearance.fontSize
7578
8138
  };
7579
- return /* @__PURE__ */ jsxs5(
8139
+ return /* @__PURE__ */ jsxs6(
7580
8140
  "div",
7581
8141
  {
7582
8142
  "aria-label": "Mobile VR setup",
@@ -7584,11 +8144,11 @@ function SetupPanel({
7584
8144
  role: "dialog",
7585
8145
  style: panelStyle,
7586
8146
  children: [
7587
- /* @__PURE__ */ jsx10("h2", { className: "pano-webvr-setup-title", children: appearance.setupTitle ?? "MobileVR Setup" }),
7588
- /* @__PURE__ */ jsxs5("label", { className: "pano-webvr-setup-field", children: [
8147
+ /* @__PURE__ */ jsx11("h2", { className: "pano-webvr-setup-title", children: appearance.setupTitle ?? "MobileVR Setup" }),
8148
+ /* @__PURE__ */ jsxs6("label", { className: "pano-webvr-setup-field", children: [
7589
8149
  "Screen size (inch)",
7590
- /* @__PURE__ */ jsxs5("div", { className: "pano-webvr-setup-row", children: [
7591
- /* @__PURE__ */ jsx10(
8150
+ /* @__PURE__ */ jsxs6("div", { className: "pano-webvr-setup-row", children: [
8151
+ /* @__PURE__ */ jsx11(
7592
8152
  "button",
7593
8153
  {
7594
8154
  "aria-label": "Decrease screen size",
@@ -7600,8 +8160,8 @@ function SetupPanel({
7600
8160
  children: "\u2039"
7601
8161
  }
7602
8162
  ),
7603
- /* @__PURE__ */ jsx10("strong", { className: "pano-webvr-setup-value", children: settings.screensize === "auto" ? "Auto" : settings.screensize.toFixed(1) }),
7604
- /* @__PURE__ */ jsx10(
8163
+ /* @__PURE__ */ jsx11("strong", { className: "pano-webvr-setup-value", children: settings.screensize === "auto" ? "Auto" : settings.screensize.toFixed(1) }),
8164
+ /* @__PURE__ */ jsx11(
7605
8165
  "button",
7606
8166
  {
7607
8167
  "aria-label": "Increase screen size",
@@ -7615,10 +8175,10 @@ function SetupPanel({
7615
8175
  )
7616
8176
  ] })
7617
8177
  ] }),
7618
- /* @__PURE__ */ jsxs5("fieldset", { className: "pano-webvr-setup-fieldset", children: [
7619
- /* @__PURE__ */ jsx10("legend", { className: "pano-webvr-setup-legend", children: "VR headset preset" }),
7620
- /* @__PURE__ */ jsxs5("div", { className: "pano-webvr-setup-row", children: [
7621
- /* @__PURE__ */ jsx10(
8178
+ /* @__PURE__ */ jsxs6("fieldset", { className: "pano-webvr-setup-fieldset", children: [
8179
+ /* @__PURE__ */ jsx11("legend", { className: "pano-webvr-setup-legend", children: "VR headset preset" }),
8180
+ /* @__PURE__ */ jsxs6("div", { className: "pano-webvr-setup-row", children: [
8181
+ /* @__PURE__ */ jsx11(
7622
8182
  "button",
7623
8183
  {
7624
8184
  "aria-label": "Previous headset preset",
@@ -7628,8 +8188,8 @@ function SetupPanel({
7628
8188
  children: "\u2039"
7629
8189
  }
7630
8190
  ),
7631
- /* @__PURE__ */ jsx10("strong", { className: "pano-webvr-setup-value-wide", children: WEBVR_PROFILES[settings.profileId].label }),
7632
- /* @__PURE__ */ jsx10(
8191
+ /* @__PURE__ */ jsx11("strong", { className: "pano-webvr-setup-value-wide", children: WEBVR_PROFILES[settings.profileId].label }),
8192
+ /* @__PURE__ */ jsx11(
7633
8193
  "button",
7634
8194
  {
7635
8195
  "aria-label": "Next headset preset",
@@ -7641,7 +8201,7 @@ function SetupPanel({
7641
8201
  )
7642
8202
  ] })
7643
8203
  ] }),
7644
- /* @__PURE__ */ jsx10(
8204
+ /* @__PURE__ */ jsx11(
7645
8205
  ChromeButton2,
7646
8206
  {
7647
8207
  appearance,
@@ -7653,36 +8213,82 @@ function SetupPanel({
7653
8213
  }
7654
8214
  );
7655
8215
  }
8216
+ function SessionActions({
8217
+ appearance,
8218
+ host,
8219
+ mode
8220
+ }) {
8221
+ return /* @__PURE__ */ jsxs6("div", { className: "pano-webvr-toolbar-actions", children: [
8222
+ mode !== "webxr" ? /* @__PURE__ */ jsx11(
8223
+ ChromeButton2,
8224
+ {
8225
+ appearance,
8226
+ onClick: () => host.controller?.openSetup(),
8227
+ children: "VR Setup"
8228
+ }
8229
+ ) : null,
8230
+ /* @__PURE__ */ jsx11(
8231
+ ChromeButton2,
8232
+ {
8233
+ appearance,
8234
+ onClick: () => void host.controller?.exitVR(),
8235
+ children: "Exit VR"
8236
+ }
8237
+ )
8238
+ ] });
8239
+ }
8240
+ function RotatePhoneIcon2() {
8241
+ return /* @__PURE__ */ jsxs6(
8242
+ "svg",
8243
+ {
8244
+ "aria-hidden": "true",
8245
+ className: "pano-webvr-portrait-icon",
8246
+ fill: "none",
8247
+ height: "48",
8248
+ stroke: "currentColor",
8249
+ strokeLinecap: "round",
8250
+ strokeLinejoin: "round",
8251
+ strokeWidth: "2",
8252
+ viewBox: "0 0 48 48",
8253
+ width: "48",
8254
+ children: [
8255
+ /* @__PURE__ */ jsx11("rect", { height: "28", rx: "3", width: "18", x: "15", y: "6" }),
8256
+ /* @__PURE__ */ jsx11("path", { d: "M10 34c-3-3-4-7-3-11" }),
8257
+ /* @__PURE__ */ jsx11("path", { d: "M8 36l2-2 2 2" }),
8258
+ /* @__PURE__ */ jsx11("path", { d: "M38 14c3 3 4 7 3 11" }),
8259
+ /* @__PURE__ */ jsx11("path", { d: "M40 12l-2 2-2-2" })
8260
+ ]
8261
+ }
8262
+ );
8263
+ }
8264
+ function PortraitPrompt() {
8265
+ return /* @__PURE__ */ jsxs6("div", { className: "pano-webvr-portrait-prompt", role: "status", children: [
8266
+ /* @__PURE__ */ jsx11(RotatePhoneIcon2, {}),
8267
+ /* @__PURE__ */ jsx11("p", { className: "pano-webvr-portrait-text", children: "Rotate your phone to landscape" })
8268
+ ] });
8269
+ }
7656
8270
  function WebVRChromeBridge({ host }) {
7657
- useSyncExternalStore5(
8271
+ useSyncExternalStore7(
7658
8272
  (listener) => subscribeWebVRHost(host, listener),
7659
8273
  () => host.revision,
7660
8274
  () => host.revision
7661
8275
  );
8276
+ const portrait = usePortraitOrientation();
7662
8277
  const { available, chrome, mode, settings, setupOpen } = host.snapshot;
8278
+ const [mounted, setMounted] = useState6(false);
8279
+ useEffect13(() => {
8280
+ setMounted(true);
8281
+ }, []);
7663
8282
  if (chrome === false || !host.controller) {
7664
8283
  return null;
7665
8284
  }
7666
8285
  const appearance = resolveAppearance(chrome);
7667
- return /* @__PURE__ */ jsxs5(Fragment3, { children: [
7668
- /* @__PURE__ */ jsx10("div", { className: "pano-webvr-toolbar", children: mode ? /* @__PURE__ */ jsxs5("div", { className: "pano-webvr-toolbar-actions", children: [
7669
- mode !== "webxr" ? /* @__PURE__ */ jsx10(
7670
- ChromeButton2,
7671
- {
7672
- appearance,
7673
- onClick: () => host.controller?.openSetup(),
7674
- children: "VR Setup"
7675
- }
7676
- ) : null,
7677
- /* @__PURE__ */ jsx10(
7678
- ChromeButton2,
7679
- {
7680
- appearance,
7681
- onClick: () => void host.controller?.exitVR(),
7682
- children: "Exit VR"
7683
- }
7684
- )
7685
- ] }) : /* @__PURE__ */ jsx10(
8286
+ const showPortraitPrompt = mode === "mobilevr" && mounted && portrait;
8287
+ if (showPortraitPrompt) {
8288
+ return /* @__PURE__ */ jsx11(PortraitPrompt, {});
8289
+ }
8290
+ return /* @__PURE__ */ jsxs6(Fragment3, { children: [
8291
+ /* @__PURE__ */ jsx11("div", { className: "pano-webvr-toolbar", children: mode ? /* @__PURE__ */ jsx11(SessionActions, { appearance, host, mode }) : /* @__PURE__ */ jsx11(
7686
8292
  ChromeButton2,
7687
8293
  {
7688
8294
  appearance,
@@ -7690,22 +8296,8 @@ function WebVRChromeBridge({ host }) {
7690
8296
  children: available ? "Enter VR" : "VR unavailable"
7691
8297
  }
7692
8298
  ) }),
7693
- mode === "fake" ? /* @__PURE__ */ jsx10(
7694
- "p",
7695
- {
7696
- className: "pano-webvr-hint",
7697
- style: { color: appearance.color },
7698
- children: "Simulated VR Mode \xB7 Click the view to lock the mouse, then move to look around. Use a headset or phone for real VR."
7699
- }
7700
- ) : null,
7701
- setupOpen ? /* @__PURE__ */ jsx10(
7702
- SetupPanel,
7703
- {
7704
- appearance,
7705
- host,
7706
- settings
7707
- }
7708
- ) : null
8299
+ mode === "fake" ? /* @__PURE__ */ jsx11("p", { className: "pano-webvr-hint", style: { color: appearance.color }, children: "Simulated VR Mode \xB7 Click the view to lock the mouse, then move to look around. Use a headset or phone for real VR." }) : null,
8300
+ setupOpen ? /* @__PURE__ */ jsx11(SetupPanel, { appearance, host, settings }) : null
7709
8301
  ] });
7710
8302
  }
7711
8303
 
@@ -7740,7 +8332,7 @@ import { useFrame as useFrame7, useThree as useThree8 } from "@react-three/fiber
7740
8332
  import { useXR as useXR2, XROrigin } from "@react-three/xr";
7741
8333
  import { useRef as useRef12 } from "react";
7742
8334
  import { Vector3 as Vector36 } from "three";
7743
- import { jsx as jsx11 } from "react/jsx-runtime";
8335
+ import { jsx as jsx12 } from "react/jsx-runtime";
7744
8336
  function PanoramaXROrigin() {
7745
8337
  const originRef = useRef12(null);
7746
8338
  const localHeadPositionRef = useRef12(new Vector36());
@@ -7756,11 +8348,11 @@ function PanoramaXROrigin() {
7756
8348
  origin.position.copy(localHeadPositionRef.current).multiplyScalar(-1);
7757
8349
  origin.updateMatrixWorld();
7758
8350
  }, -100);
7759
- return /* @__PURE__ */ jsx11(XROrigin, { ref: originRef });
8351
+ return /* @__PURE__ */ jsx12(XROrigin, { ref: originRef });
7760
8352
  }
7761
8353
 
7762
8354
  // src/pano-viewer.tsx
7763
- import { jsx as jsx12, jsxs as jsxs6 } from "react/jsx-runtime";
8355
+ import { jsx as jsx13, jsxs as jsxs7 } from "react/jsx-runtime";
7764
8356
  var DEFAULT_VIEW = {
7765
8357
  yaw: 0,
7766
8358
  pitch: 0,
@@ -7805,7 +8397,7 @@ function PanoCursorTree({
7805
8397
  if (!cursors) {
7806
8398
  return children;
7807
8399
  }
7808
- return /* @__PURE__ */ jsx12(PanoCursorController, { cursors, children });
8400
+ return /* @__PURE__ */ jsx13(PanoCursorController, { cursors, children });
7809
8401
  }
7810
8402
  function PanoVideoHostReset() {
7811
8403
  const host = useContext16(PanoVideoHostContext);
@@ -7825,10 +8417,10 @@ function DefaultControlChannels({
7825
8417
  if (!claims) {
7826
8418
  return null;
7827
8419
  }
7828
- return /* @__PURE__ */ jsxs6(DefaultControlChannelContext.Provider, { value: true, children: [
7829
- userControlsEnabled && mouseChannel.mount && claims.mouse === 0 ? /* @__PURE__ */ jsx12(MouseControls, { ...mouseChannel.props, fovSpeed }) : null,
7830
- userControlsEnabled && touchChannel.mount && claims.touch === 0 ? /* @__PURE__ */ jsx12(TouchControls, { ...touchChannel.props }) : null,
7831
- userControlsEnabled && keyboardChannel.mount && claims.keyboard === 0 ? /* @__PURE__ */ jsx12(
8420
+ return /* @__PURE__ */ jsxs7(DefaultControlChannelContext.Provider, { value: true, children: [
8421
+ userControlsEnabled && mouseChannel.mount && claims.mouse === 0 ? /* @__PURE__ */ jsx13(MouseControls, { ...mouseChannel.props, fovSpeed }) : null,
8422
+ userControlsEnabled && touchChannel.mount && claims.touch === 0 ? /* @__PURE__ */ jsx13(TouchControls, { ...touchChannel.props }) : null,
8423
+ userControlsEnabled && keyboardChannel.mount && claims.keyboard === 0 ? /* @__PURE__ */ jsx13(
7832
8424
  KeyboardControls,
7833
8425
  {
7834
8426
  ...keyboardChannel.props,
@@ -7861,7 +8453,7 @@ var PanoViewer = forwardRef2(
7861
8453
  const rootRef = useRef13(null);
7862
8454
  const controlsRef = useRef13(null);
7863
8455
  const modalHost = useMemo8(() => createPanoModalHost(), []);
7864
- const modalOpen = useSyncExternalStore6(modalHost.subscribe, modalHost.getSnapshot, () => false);
8456
+ const modalOpen = useSyncExternalStore8(modalHost.subscribe, modalHost.getSnapshot, () => false);
7865
8457
  const setControlsRuntime = useCallback6((runtime) => {
7866
8458
  controlsRef.current = runtime;
7867
8459
  modalHost.connect(runtime);
@@ -7881,12 +8473,12 @@ var PanoViewer = forwardRef2(
7881
8473
  () => mediaActivation === false ? null : mediaActivation ?? {},
7882
8474
  [mediaActivation]
7883
8475
  );
7884
- const mediaActivationRevision = useSyncExternalStore6(
8476
+ const mediaActivationRevision = useSyncExternalStore8(
7885
8477
  (onStoreChange) => subscribePanoMediaActivation(mediaActivationHost, onStoreChange),
7886
8478
  () => getPanoMediaActivationRevision(mediaActivationHost),
7887
8479
  () => getPanoMediaActivationRevision(mediaActivationHost)
7888
8480
  );
7889
- const [mediaActivated, setMediaActivated] = useState6(false);
8481
+ const [mediaActivated, setMediaActivated] = useState7(false);
7890
8482
  const stereoView = useMemo8(() => createWebVRStereoView(), []);
7891
8483
  const xrStore = useMemo8(
7892
8484
  () => createXRStore({
@@ -7933,7 +8525,7 @@ var PanoViewer = forwardRef2(
7933
8525
  }, [runMediaActivation]);
7934
8526
  const hasMediaActivationIntent = mediaActivationRevision >= 0 && hasPanoMediaActivationIntent(mediaActivationHost);
7935
8527
  const shouldActivateMedia = mediaActivationOptions !== null && hasMediaActivationIntent && !mediaActivated;
7936
- useEffect13(() => {
8528
+ useEffect14(() => {
7937
8529
  if (!shouldActivateMedia) {
7938
8530
  return;
7939
8531
  }
@@ -8076,50 +8668,68 @@ var PanoViewer = forwardRef2(
8076
8668
  if (typeof document === "undefined") {
8077
8669
  return;
8078
8670
  }
8079
- if (getFullscreenElement()) {
8080
- return;
8081
- }
8082
8671
  const root = rootRef.current;
8083
8672
  if (!root) {
8084
8673
  return;
8085
8674
  }
8086
- await requestElementFullscreen(root);
8087
- }, []);
8088
- const exitFullscreen = useCallback6(async () => {
8089
- if (typeof document === "undefined") {
8675
+ if (getFullscreenElement() || isIphoneLandscapeFullscreenActive(root)) {
8090
8676
  return;
8091
8677
  }
8092
- if (!getFullscreenElement()) {
8678
+ if (isFullscreenEnabled()) {
8679
+ await requestElementFullscreen(root);
8093
8680
  return;
8094
8681
  }
8095
- await exitElementFullscreen();
8682
+ if (supportsIphoneLandscapeFullscreen()) {
8683
+ acquireIphoneLandscapeFullscreen(root, "viewer");
8684
+ }
8096
8685
  }, []);
8097
- const toggleFullscreen = useCallback6(async () => {
8686
+ const exitFullscreen = useCallback6(async () => {
8098
8687
  if (typeof document === "undefined") {
8099
8688
  return;
8100
8689
  }
8690
+ const root = rootRef.current;
8691
+ if (root && isIphoneLandscapeFullscreenActive(root)) {
8692
+ releaseIphoneLandscapeFullscreen(root, "viewer");
8693
+ }
8101
8694
  if (getFullscreenElement()) {
8102
8695
  await exitElementFullscreen();
8696
+ }
8697
+ }, []);
8698
+ const toggleFullscreen = useCallback6(async () => {
8699
+ if (typeof document === "undefined") {
8103
8700
  return;
8104
8701
  }
8105
8702
  const root = rootRef.current;
8106
8703
  if (!root) {
8107
8704
  return;
8108
8705
  }
8109
- await requestElementFullscreen(root);
8110
- }, []);
8111
- const [isViewerFullscreen, setIsViewerFullscreen] = useState6(false);
8706
+ if (getFullscreenElement() || isIphoneLandscapeFullscreenActive(root)) {
8707
+ await exitFullscreen();
8708
+ return;
8709
+ }
8710
+ await enterFullscreen();
8711
+ }, [enterFullscreen, exitFullscreen]);
8712
+ const [isViewerFullscreen, setIsViewerFullscreen] = useState7(false);
8112
8713
  const { context: overlayContext, setPortalContainer } = usePanoOverlayHost(isViewerFullscreen);
8113
- useEffect13(() => {
8714
+ const iphoneFullscreenAllowsScroll = useSyncExternalStore8(
8715
+ subscribeIphoneLandscapeFullscreen,
8716
+ () => getIphoneLandscapeFullscreenSnapshot().allowsDocumentScroll,
8717
+ () => false
8718
+ );
8719
+ useEffect14(() => {
8114
8720
  if (modalOpen) contextMenuOverlayApi.setSession(null);
8115
8721
  }, [contextMenuOverlayApi, modalOpen]);
8116
- useEffect13(() => {
8722
+ useEffect14(() => {
8117
8723
  if (typeof document === "undefined") {
8118
8724
  return;
8119
8725
  }
8120
8726
  const syncFullscreen = () => {
8121
- const fullscreenElement = getFullscreenElement();
8122
8727
  const root = rootRef.current;
8728
+ if (root && isIphoneLandscapeFullscreenActive(root)) {
8729
+ setIsViewerFullscreen(true);
8730
+ return;
8731
+ }
8732
+ const fullscreenElement = getFullscreenElement();
8123
8733
  if (!fullscreenElement || !root) {
8124
8734
  setIsViewerFullscreen(false);
8125
8735
  return;
@@ -8129,9 +8739,22 @@ var PanoViewer = forwardRef2(
8129
8739
  );
8130
8740
  };
8131
8741
  syncFullscreen();
8132
- return subscribeFullscreenChange(syncFullscreen);
8742
+ const unsubscribeApi = subscribeFullscreenChange(syncFullscreen);
8743
+ const unsubscribeIphone = subscribeIphoneLandscapeFullscreen(syncFullscreen);
8744
+ return () => {
8745
+ unsubscribeApi();
8746
+ unsubscribeIphone();
8747
+ };
8133
8748
  }, []);
8134
- useEffect13(() => {
8749
+ useEffect14(() => {
8750
+ const root = rootRef.current;
8751
+ return () => {
8752
+ if (root) {
8753
+ releaseIphoneLandscapeFullscreen(root, "viewer");
8754
+ }
8755
+ };
8756
+ }, []);
8757
+ useEffect14(() => {
8135
8758
  const root = rootRef.current;
8136
8759
  if (!root) {
8137
8760
  return;
@@ -8165,10 +8788,10 @@ var PanoViewer = forwardRef2(
8165
8788
  [cursors]
8166
8789
  );
8167
8790
  const legacyAutoRotateOptions = controlOptions;
8168
- const [legacyAutoRotate, setLegacyAutoRotate] = useState6(
8791
+ const [legacyAutoRotate, setLegacyAutoRotate] = useState7(
8169
8792
  legacyAutoRotateOptions.autoRotate ?? false
8170
8793
  );
8171
- useEffect13(() => {
8794
+ useEffect14(() => {
8172
8795
  setLegacyAutoRotate(legacyAutoRotateOptions.autoRotate ?? false);
8173
8796
  }, [legacyAutoRotateOptions.autoRotate]);
8174
8797
  const isFullscreenRef = useRef13(false);
@@ -8262,7 +8885,7 @@ var PanoViewer = forwardRef2(
8262
8885
  }),
8263
8886
  [style]
8264
8887
  );
8265
- return /* @__PURE__ */ jsxs6(
8888
+ return /* @__PURE__ */ jsxs7(
8266
8889
  "div",
8267
8890
  {
8268
8891
  ...divProps,
@@ -8272,8 +8895,8 @@ var PanoViewer = forwardRef2(
8272
8895
  "aria-label": ariaLabel,
8273
8896
  style: rootStyle,
8274
8897
  children: [
8275
- /* @__PURE__ */ jsxs6("div", { "data-pano-background": "", inert: modalOpen, style: { position: "absolute", inset: 0 }, children: [
8276
- /* @__PURE__ */ jsx12(
8898
+ /* @__PURE__ */ jsxs7("div", { "data-pano-background": "", inert: modalOpen, style: { position: "absolute", inset: 0 }, children: [
8899
+ /* @__PURE__ */ jsx13(
8277
8900
  Canvas,
8278
8901
  {
8279
8902
  "aria-label": `${ariaLabel} canvas`,
@@ -8294,25 +8917,25 @@ var PanoViewer = forwardRef2(
8294
8917
  },
8295
8918
  style: {
8296
8919
  ...DEFAULT_CANVAS_STYLE,
8297
- touchAction: userControlsEnabled ? "none" : "auto"
8920
+ touchAction: !userControlsEnabled ? "auto" : iphoneFullscreenAllowsScroll ? "pan-y" : "none"
8298
8921
  },
8299
- children: /* @__PURE__ */ jsx12(XR, { store: xrStore, children: /* @__PURE__ */ jsxs6(
8922
+ children: /* @__PURE__ */ jsx13(XR, { store: xrStore, children: /* @__PURE__ */ jsxs7(
8300
8923
  WebVRRuntimeContext.Provider,
8301
8924
  {
8302
8925
  value: { host: webVRHost, xrStore, stereoView },
8303
8926
  children: [
8304
- /* @__PURE__ */ jsx12(PanoramaXROrigin, {}),
8305
- /* @__PURE__ */ jsx12(HotspotAccessibilityContext.Provider, { value: registry, children: /* @__PURE__ */ jsx12(HotspotTargetRegistryContext.Provider, { value: hotspotTargetRegistry, children: /* @__PURE__ */ jsx12(PanoEventBusContext.Provider, { value: eventBus, children: /* @__PURE__ */ jsx12(PanoCursorTree, { cursors: resolvedCursors, children: /* @__PURE__ */ jsx12(PanoramaViewContext.Provider, { value: controlsRef, children: /* @__PURE__ */ jsx12(
8927
+ /* @__PURE__ */ jsx13(PanoramaXROrigin, {}),
8928
+ /* @__PURE__ */ jsx13(HotspotAccessibilityContext.Provider, { value: registry, children: /* @__PURE__ */ jsx13(HotspotTargetRegistryContext.Provider, { value: hotspotTargetRegistry, children: /* @__PURE__ */ jsx13(PanoEventBusContext.Provider, { value: eventBus, children: /* @__PURE__ */ jsx13(PanoCursorTree, { cursors: resolvedCursors, children: /* @__PURE__ */ jsx13(PanoramaViewContext.Provider, { value: controlsRef, children: /* @__PURE__ */ jsx13(
8306
8929
  PanoContextMenuOverlayContext.Provider,
8307
8930
  {
8308
8931
  value: contextMenuOverlayApi,
8309
- children: /* @__PURE__ */ jsx12(PanoChromeOverlayContext.Provider, { value: chromeOverlayApi, children: /* @__PURE__ */ jsx12(PanoVideoHostContext.Provider, { value: videoHost, children: /* @__PURE__ */ jsx12(PanoFilterHostContext.Provider, { value: filterHost, children: /* @__PURE__ */ jsx12(
8932
+ children: /* @__PURE__ */ jsx13(PanoChromeOverlayContext.Provider, { value: chromeOverlayApi, children: /* @__PURE__ */ jsx13(PanoVideoHostContext.Provider, { value: videoHost, children: /* @__PURE__ */ jsx13(PanoFilterHostContext.Provider, { value: filterHost, children: /* @__PURE__ */ jsx13(
8310
8933
  PanoContextMenuActionsContext.Provider,
8311
8934
  {
8312
8935
  value: contextMenuActions,
8313
- children: /* @__PURE__ */ jsx12(ScenesHostContext.Provider, { value: scenesHost, children: /* @__PURE__ */ jsx12(BackgroundAudioHostContext.Provider, { value: bgmHost, children: /* @__PURE__ */ jsxs6(PanoMediaActivationHostContext.Provider, { value: mediaActivationHost, children: [
8314
- /* @__PURE__ */ jsx12(PanoVideoHostReset, {}),
8315
- /* @__PURE__ */ jsx12(
8936
+ children: /* @__PURE__ */ jsx13(ScenesHostContext.Provider, { value: scenesHost, children: /* @__PURE__ */ jsx13(BackgroundAudioHostContext.Provider, { value: bgmHost, children: /* @__PURE__ */ jsxs7(PanoMediaActivationHostContext.Provider, { value: mediaActivationHost, children: [
8937
+ /* @__PURE__ */ jsx13(PanoVideoHostReset, {}),
8938
+ /* @__PURE__ */ jsx13(
8316
8939
  PanoramaViewRuntime,
8317
8940
  {
8318
8941
  ref: setControlsRuntime,
@@ -8324,7 +8947,7 @@ var PanoViewer = forwardRef2(
8324
8947
  options: controlOptions
8325
8948
  }
8326
8949
  ),
8327
- (onViewChange || onPanoramaClick || onPanoramaDoubleClick || onPanoramaPointerMove) && /* @__PURE__ */ jsx12(
8950
+ (onViewChange || onPanoramaClick || onPanoramaDoubleClick || onPanoramaPointerMove) && /* @__PURE__ */ jsx13(
8328
8951
  PanoEvents,
8329
8952
  {
8330
8953
  onViewChange,
@@ -8333,18 +8956,18 @@ var PanoViewer = forwardRef2(
8333
8956
  onPointerMove: onPanoramaPointerMove
8334
8957
  }
8335
8958
  ),
8336
- /* @__PURE__ */ jsx12(
8959
+ /* @__PURE__ */ jsx13(
8337
8960
  AutoRotate,
8338
8961
  {
8339
8962
  enabled: legacyAutoRotate,
8340
8963
  speed: legacyAutoRotateOptions.autoRotateSpeed
8341
8964
  }
8342
8965
  ),
8343
- /* @__PURE__ */ jsx12(PanoramaEventSurface, {}),
8344
- contextMenuChannel.mount ? /* @__PURE__ */ jsx12(PanoContextMenu, { ...contextMenuChannel.props }) : null,
8345
- /* @__PURE__ */ jsxs6(ControlClaimsContext.Provider, { value: controlClaims, children: [
8966
+ /* @__PURE__ */ jsx13(PanoramaEventSurface, {}),
8967
+ contextMenuChannel.mount ? /* @__PURE__ */ jsx13(PanoContextMenu, { ...contextMenuChannel.props }) : null,
8968
+ /* @__PURE__ */ jsxs7(ControlClaimsContext.Provider, { value: controlClaims, children: [
8346
8969
  children,
8347
- /* @__PURE__ */ jsx12(
8970
+ /* @__PURE__ */ jsx13(
8348
8971
  DefaultControlChannels,
8349
8972
  {
8350
8973
  fovSpeed: controlOptions.fovSpeed,
@@ -8365,14 +8988,14 @@ var PanoViewer = forwardRef2(
8365
8988
  ) })
8366
8989
  }
8367
8990
  ),
8368
- /* @__PURE__ */ jsxs6(
8991
+ /* @__PURE__ */ jsxs7(
8369
8992
  "div",
8370
8993
  {
8371
8994
  className: "pano-chrome-overlay",
8372
8995
  "data-pano-chrome-overlay": "",
8373
8996
  ref: setOverlayNode,
8374
8997
  children: [
8375
- /* @__PURE__ */ jsx12(
8998
+ /* @__PURE__ */ jsx13(
8376
8999
  PanoVideoChromeBridge,
8377
9000
  {
8378
9001
  fullscreen: contextMenuActions,
@@ -8380,14 +9003,15 @@ var PanoViewer = forwardRef2(
8380
9003
  overlayElement
8381
9004
  }
8382
9005
  ),
8383
- /* @__PURE__ */ jsx12(WebVRChromeBridge, { host: webVRHost })
9006
+ /* @__PURE__ */ jsx13(WebVRChromeBridge, { host: webVRHost }),
9007
+ /* @__PURE__ */ jsx13(IphoneLandscapeFullscreenChrome, { webVRHost })
8384
9008
  ]
8385
9009
  }
8386
9010
  ),
8387
9011
  contextMenuOverlay,
8388
9012
  hotspotAccessibilityControls
8389
9013
  ] }),
8390
- /* @__PURE__ */ jsx12(PanoModalHostContext.Provider, { value: modalHost, children: /* @__PURE__ */ jsx12(PanoOverlayContext.Provider, { value: overlayContext, children: /* @__PURE__ */ jsx12(
9014
+ /* @__PURE__ */ jsx13(PanoModalHostContext.Provider, { value: modalHost, children: /* @__PURE__ */ jsx13(PanoOverlayContext.Provider, { value: overlayContext, children: /* @__PURE__ */ jsx13(
8391
9015
  "div",
8392
9016
  {
8393
9017
  "data-pano-overlay": "",
@@ -8491,7 +9115,7 @@ function hotspotAction(hotspot, trigger) {
8491
9115
  import {
8492
9116
  useContext as useContext22,
8493
9117
  useMemo as useMemo22,
8494
- useState as useState20
9118
+ useState as useState21
8495
9119
  } from "react";
8496
9120
 
8497
9121
  // src/scenes.tsx
@@ -8500,10 +9124,10 @@ import {
8500
9124
  Fragment as Fragment4,
8501
9125
  useCallback as useCallback8,
8502
9126
  useContext as useContext19,
8503
- useEffect as useEffect22,
9127
+ useEffect as useEffect23,
8504
9128
  useMemo as useMemo17,
8505
9129
  useRef as useRef22,
8506
- useState as useState11
9130
+ useState as useState12
8507
9131
  } from "react";
8508
9132
  import {
8509
9133
  LinearSRGBColorSpace,
@@ -8580,7 +9204,7 @@ function isSnapshotTransition(preset) {
8580
9204
 
8581
9205
  // src/scene-transitions/snapshot-hold.tsx
8582
9206
  import { useFrame as useFrame8, useThree as useThree9 } from "@react-three/fiber";
8583
- import { useEffect as useEffect14, useMemo as useMemo9, useRef as useRef14 } from "react";
9207
+ import { useEffect as useEffect15, useMemo as useMemo9, useRef as useRef14 } from "react";
8584
9208
  import { Vector3 as Vector38 } from "three";
8585
9209
 
8586
9210
  // src/scene-transitions/overlay-utils.ts
@@ -8913,7 +9537,7 @@ function createSnapshotMaterial(preset, texture) {
8913
9537
  }
8914
9538
 
8915
9539
  // src/scene-transitions/snapshot-hold.tsx
8916
- import { jsx as jsx13, jsxs as jsxs7 } from "react/jsx-runtime";
9540
+ import { jsx as jsx14, jsxs as jsxs8 } from "react/jsx-runtime";
8917
9541
  function SnapshotHold({ snapshot }) {
8918
9542
  const { camera, gl } = useThree9();
8919
9543
  const meshRef = useRef14(null);
@@ -8922,7 +9546,7 @@ function SnapshotHold({ snapshot }) {
8922
9546
  () => createSnapshotMaterial("crossfade", snapshot.texture),
8923
9547
  [snapshot.texture]
8924
9548
  );
8925
- useEffect14(() => () => material.dispose(), [material]);
9549
+ useEffect15(() => () => material.dispose(), [material]);
8926
9550
  useFrame8(() => {
8927
9551
  const mesh = meshRef.current;
8928
9552
  if (!mesh || !isPerspectiveCamera(camera)) {
@@ -8936,9 +9560,9 @@ function SnapshotHold({ snapshot }) {
8936
9560
  );
8937
9561
  material.uniforms.progress.value = 0;
8938
9562
  });
8939
- return /* @__PURE__ */ jsxs7("mesh", { frustumCulled: false, ref: meshRef, renderOrder: OVERLAY_RENDER_ORDER, children: [
8940
- /* @__PURE__ */ jsx13("primitive", { attach: "geometry", object: FULLSCREEN_PLANE }),
8941
- /* @__PURE__ */ jsx13("primitive", { attach: "material", object: material })
9563
+ return /* @__PURE__ */ jsxs8("mesh", { frustumCulled: false, ref: meshRef, renderOrder: OVERLAY_RENDER_ORDER, children: [
9564
+ /* @__PURE__ */ jsx14("primitive", { attach: "geometry", object: FULLSCREEN_PLANE }),
9565
+ /* @__PURE__ */ jsx14("primitive", { attach: "material", object: material })
8942
9566
  ] });
8943
9567
  }
8944
9568
 
@@ -9000,7 +9624,7 @@ function phaseAfterSnapshot(preset, hold) {
9000
9624
 
9001
9625
  // src/scene-transitions/particle-overlay.tsx
9002
9626
  import { useFrame as useFrame9, useThree as useThree10 } from "@react-three/fiber";
9003
- import { useEffect as useEffect15, useMemo as useMemo10, useRef as useRef15 } from "react";
9627
+ import { useEffect as useEffect16, useMemo as useMemo10, useRef as useRef15 } from "react";
9004
9628
  import {
9005
9629
  DoubleSide as DoubleSide2,
9006
9630
  InstancedBufferAttribute,
@@ -9010,7 +9634,7 @@ import {
9010
9634
  Vector2 as Vector23,
9011
9635
  Vector3 as Vector39
9012
9636
  } from "three";
9013
- import { jsx as jsx14 } from "react/jsx-runtime";
9637
+ import { jsx as jsx15 } from "react/jsx-runtime";
9014
9638
  var PARTICLE_GRID = 48;
9015
9639
  var PARTICLE_COUNT = PARTICLE_GRID * PARTICLE_GRID;
9016
9640
  var PARTICLE_VERTEX_SHADER = `
@@ -9108,9 +9732,9 @@ function ParticleOverlay({
9108
9732
  }),
9109
9733
  [snapshot.texture]
9110
9734
  );
9111
- useEffect15(() => () => geometry.dispose(), [geometry]);
9112
- useEffect15(() => () => material.dispose(), [material]);
9113
- useEffect15(() => {
9735
+ useEffect16(() => () => geometry.dispose(), [geometry]);
9736
+ useEffect16(() => () => material.dispose(), [material]);
9737
+ useEffect16(() => {
9114
9738
  startRef.current = null;
9115
9739
  finishedRef.current = false;
9116
9740
  material.uniforms.progress.value = 0;
@@ -9132,7 +9756,7 @@ function ParticleOverlay({
9132
9756
  onFinish();
9133
9757
  }
9134
9758
  });
9135
- return /* @__PURE__ */ jsx14(
9759
+ return /* @__PURE__ */ jsx15(
9136
9760
  "mesh",
9137
9761
  {
9138
9762
  ref: meshRef,
@@ -9146,9 +9770,9 @@ function ParticleOverlay({
9146
9770
 
9147
9771
  // src/scene-transitions/snapshot-overlay.tsx
9148
9772
  import { useFrame as useFrame10, useThree as useThree11 } from "@react-three/fiber";
9149
- import { useEffect as useEffect16, useMemo as useMemo11, useRef as useRef16 } from "react";
9773
+ import { useEffect as useEffect17, useMemo as useMemo11, useRef as useRef16 } from "react";
9150
9774
  import { Vector3 as Vector310 } from "three";
9151
- import { jsx as jsx15, jsxs as jsxs8 } from "react/jsx-runtime";
9775
+ import { jsx as jsx16, jsxs as jsxs9 } from "react/jsx-runtime";
9152
9776
  function SnapshotOverlay({
9153
9777
  snapshot,
9154
9778
  transition,
@@ -9167,8 +9791,8 @@ function SnapshotOverlay({
9167
9791
  }
9168
9792
  return createSnapshotMaterial(transition.preset, snapshot.texture);
9169
9793
  }, [snapshot.texture, transition.preset]);
9170
- useEffect16(() => () => material?.dispose(), [material]);
9171
- useEffect16(() => {
9794
+ useEffect17(() => () => material?.dispose(), [material]);
9795
+ useEffect17(() => {
9172
9796
  startRef.current = null;
9173
9797
  finishedRef.current = false;
9174
9798
  if (material) {
@@ -9197,21 +9821,21 @@ function SnapshotOverlay({
9197
9821
  if (!material) {
9198
9822
  return null;
9199
9823
  }
9200
- return /* @__PURE__ */ jsxs8("mesh", { ref: meshRef, renderOrder: OVERLAY_RENDER_ORDER, frustumCulled: false, children: [
9201
- /* @__PURE__ */ jsx15("primitive", { attach: "geometry", object: FULLSCREEN_PLANE }),
9202
- /* @__PURE__ */ jsx15("primitive", { attach: "material", object: material })
9824
+ return /* @__PURE__ */ jsxs9("mesh", { ref: meshRef, renderOrder: OVERLAY_RENDER_ORDER, frustumCulled: false, children: [
9825
+ /* @__PURE__ */ jsx16("primitive", { attach: "geometry", object: FULLSCREEN_PLANE }),
9826
+ /* @__PURE__ */ jsx16("primitive", { attach: "material", object: material })
9203
9827
  ] });
9204
9828
  }
9205
9829
 
9206
9830
  // src/scene-transitions/transition-overlay.tsx
9207
- import { jsx as jsx16 } from "react/jsx-runtime";
9831
+ import { jsx as jsx17 } from "react/jsx-runtime";
9208
9832
  function TransitionOverlay(props) {
9209
9833
  const { preset } = props.transition;
9210
9834
  switch (preset) {
9211
9835
  case "none":
9212
9836
  return null;
9213
9837
  case "particles":
9214
- return /* @__PURE__ */ jsx16(ParticleOverlay, { ...props });
9838
+ return /* @__PURE__ */ jsx17(ParticleOverlay, { ...props });
9215
9839
  case "crossfade":
9216
9840
  case "zoom":
9217
9841
  case "blackout":
@@ -9239,7 +9863,7 @@ function TransitionOverlay(props) {
9239
9863
  case "zoomBlur":
9240
9864
  case "hexDissolve":
9241
9865
  case "filmBurn":
9242
- return /* @__PURE__ */ jsx16(SnapshotOverlay, { ...props });
9866
+ return /* @__PURE__ */ jsx17(SnapshotOverlay, { ...props });
9243
9867
  default: {
9244
9868
  const exhaustive = preset;
9245
9869
  void exhaustive;
@@ -9250,7 +9874,7 @@ function TransitionOverlay(props) {
9250
9874
 
9251
9875
  // src/sphere.tsx
9252
9876
  import { useThree as useThree12 } from "@react-three/fiber";
9253
- import { useEffect as useEffect17, useMemo as useMemo13, useRef as useRef18, useState as useState7 } from "react";
9877
+ import { useEffect as useEffect18, useMemo as useMemo13, useRef as useRef18, useState as useState8 } from "react";
9254
9878
  import {
9255
9879
  BackSide as BackSide2,
9256
9880
  LinearFilter,
@@ -9430,7 +10054,7 @@ function injectPanoColorMatrixShader(shader) {
9430
10054
  }
9431
10055
 
9432
10056
  // src/pano-filter/pano-basic-material.tsx
9433
- import { jsx as jsx17 } from "react/jsx-runtime";
10057
+ import { jsx as jsx18 } from "react/jsx-runtime";
9434
10058
  function matrixUniforms(matrix) {
9435
10059
  return {
9436
10060
  matrix: new Matrix4().set(
@@ -9497,7 +10121,7 @@ function PanoBasicMaterial({
9497
10121
  shader.uniforms.uPanoColorMatrixIntensity.value = snapshot.intensity;
9498
10122
  }
9499
10123
  }, [matrix, snapshot.intensity]);
9500
- return /* @__PURE__ */ jsx17(
10124
+ return /* @__PURE__ */ jsx18(
9501
10125
  "meshBasicMaterial",
9502
10126
  {
9503
10127
  toneMapped: false,
@@ -9509,14 +10133,14 @@ function PanoBasicMaterial({
9509
10133
  }
9510
10134
 
9511
10135
  // src/sphere.tsx
9512
- import { jsx as jsx18, jsxs as jsxs9 } from "react/jsx-runtime";
10136
+ import { jsx as jsx19, jsxs as jsxs10 } from "react/jsx-runtime";
9513
10137
  function useEquirectTexture(url, anisotropy, generateMipmaps, onLoad, onError) {
9514
- const [texture, setTexture] = useState7(null);
10138
+ const [texture, setTexture] = useState8(null);
9515
10139
  const onLoadRef = useRef18(onLoad);
9516
10140
  const onErrorRef = useRef18(onError);
9517
10141
  onLoadRef.current = onLoad;
9518
10142
  onErrorRef.current = onError;
9519
- useEffect17(() => {
10143
+ useEffect18(() => {
9520
10144
  if (!url) {
9521
10145
  setTexture(null);
9522
10146
  return;
@@ -9555,7 +10179,7 @@ function useEquirectTexture(url, anisotropy, generateMipmaps, onLoad, onError) {
9555
10179
  active = false;
9556
10180
  };
9557
10181
  }, [anisotropy, generateMipmaps, url]);
9558
- useEffect17(
10182
+ useEffect18(
9559
10183
  () => () => {
9560
10184
  texture?.dispose();
9561
10185
  },
@@ -9596,10 +10220,10 @@ function Sphere({
9596
10220
  const displayTexture = texture ?? previewTexture;
9597
10221
  const readyRef = useRef18(false);
9598
10222
  const detailReporter = useSceneDetailReporter();
9599
- useEffect17(() => {
10223
+ useEffect18(() => {
9600
10224
  readyRef.current = false;
9601
10225
  }, [resolvedPreviewUrl, src]);
9602
- useEffect17(() => {
10226
+ useEffect18(() => {
9603
10227
  if (!detailReporter) {
9604
10228
  return;
9605
10229
  }
@@ -9608,7 +10232,7 @@ function Sphere({
9608
10232
  detailReporter.report(false);
9609
10233
  };
9610
10234
  }, [detailReporter, texture]);
9611
- useEffect17(() => {
10235
+ useEffect18(() => {
9612
10236
  if (!displayTexture || readyRef.current) {
9613
10237
  return;
9614
10238
  }
@@ -9618,14 +10242,14 @@ function Sphere({
9618
10242
  if (!displayTexture) {
9619
10243
  return null;
9620
10244
  }
9621
- return /* @__PURE__ */ jsxs9(
10245
+ return /* @__PURE__ */ jsxs10(
9622
10246
  "mesh",
9623
10247
  {
9624
10248
  rotation: [0, MathUtils5.degToRad(90 + yawOffset2), 0],
9625
10249
  visible,
9626
10250
  children: [
9627
- /* @__PURE__ */ jsx18("sphereGeometry", { args: [DEFAULT_PANORAMA_RADIUS, 128, 64] }),
9628
- /* @__PURE__ */ jsx18(
10251
+ /* @__PURE__ */ jsx19("sphereGeometry", { args: [DEFAULT_PANORAMA_RADIUS, 128, 64] }),
10252
+ /* @__PURE__ */ jsx19(
9629
10253
  PanoBasicMaterial,
9630
10254
  {
9631
10255
  map: displayTexture,
@@ -9640,7 +10264,7 @@ function Sphere({
9640
10264
 
9641
10265
  // src/sphere-tile/sphere-tile.tsx
9642
10266
  import { useFrame as useFrame11, useThree as useThree14 } from "@react-three/fiber";
9643
- import { memo, useCallback as useCallback7, useEffect as useEffect20, useMemo as useMemo15, useRef as useRef20, useState as useState9 } from "react";
10267
+ import { memo, useCallback as useCallback7, useEffect as useEffect21, useMemo as useMemo15, useRef as useRef20, useState as useState10 } from "react";
9644
10268
  import { BackSide as BackSide3, Frustum, Matrix4 as Matrix42, PerspectiveCamera as PerspectiveCamera4 } from "three";
9645
10269
 
9646
10270
  // src/tile/texture-manager.ts
@@ -9878,10 +10502,10 @@ import { useThree as useThree13 } from "@react-three/fiber";
9878
10502
  import {
9879
10503
  createContext as createContext17,
9880
10504
  useContext as useContext18,
9881
- useEffect as useEffect18,
10505
+ useEffect as useEffect19,
9882
10506
  useMemo as useMemo14
9883
10507
  } from "react";
9884
- import { jsx as jsx19 } from "react/jsx-runtime";
10508
+ import { jsx as jsx20 } from "react/jsx-runtime";
9885
10509
  var TileTextureManagerContext = createContext17(null);
9886
10510
  function TileTextureManagerProvider({
9887
10511
  children,
@@ -9899,18 +10523,18 @@ function TileTextureManagerProvider({
9899
10523
  }),
9900
10524
  [anisotropy, maxConcurrentLoads, maxTextureMemoryMb]
9901
10525
  );
9902
- useEffect18(() => {
10526
+ useEffect19(() => {
9903
10527
  manager.resume();
9904
10528
  return () => manager.dispose();
9905
10529
  }, [manager]);
9906
- return /* @__PURE__ */ jsx19(TileTextureManagerContext.Provider, { value: manager, children });
10530
+ return /* @__PURE__ */ jsx20(TileTextureManagerContext.Provider, { value: manager, children });
9907
10531
  }
9908
10532
  function useSharedTileTextureManager() {
9909
10533
  return useContext18(TileTextureManagerContext);
9910
10534
  }
9911
10535
 
9912
10536
  // src/tile/texture-hooks.ts
9913
- import { useEffect as useEffect19, useRef as useRef19, useState as useState8 } from "react";
10537
+ import { useEffect as useEffect20, useRef as useRef19, useState as useState9 } from "react";
9914
10538
  import {
9915
10539
  ClampToEdgeWrapping as ClampToEdgeWrapping2,
9916
10540
  LinearFilter as LinearFilter3,
@@ -9918,10 +10542,10 @@ import {
9918
10542
  TextureLoader as TextureLoader3
9919
10543
  } from "three";
9920
10544
  function usePreviewTexture(url, anisotropy, onError) {
9921
- const [texture, setTexture] = useState8(null);
10545
+ const [texture, setTexture] = useState9(null);
9922
10546
  const onErrorRef = useRef19(onError);
9923
10547
  onErrorRef.current = onError;
9924
- useEffect19(() => {
10548
+ useEffect20(() => {
9925
10549
  if (!url) {
9926
10550
  setTexture(null);
9927
10551
  return;
@@ -9958,7 +10582,7 @@ function usePreviewTexture(url, anisotropy, onError) {
9958
10582
  active = false;
9959
10583
  };
9960
10584
  }, [anisotropy, url]);
9961
- useEffect19(
10585
+ useEffect20(
9962
10586
  () => () => {
9963
10587
  texture?.dispose();
9964
10588
  },
@@ -9967,14 +10591,14 @@ function usePreviewTexture(url, anisotropy, onError) {
9967
10591
  return texture;
9968
10592
  }
9969
10593
  function useManagedTexture(manager, key, url, address) {
9970
- const [managedState, setManagedState] = useState8(() => ({
10594
+ const [managedState, setManagedState] = useState9(() => ({
9971
10595
  manager,
9972
10596
  key,
9973
10597
  url,
9974
10598
  snapshot: manager.getSnapshot(key)
9975
10599
  }));
9976
10600
  const snapshot = managedState.manager === manager && managedState.key === key && managedState.url === url ? managedState.snapshot : manager.getSnapshot(key);
9977
- useEffect19(
10601
+ useEffect20(
9978
10602
  () => manager.acquire(key, url, address, (nextSnapshot) => {
9979
10603
  setManagedState({
9980
10604
  manager,
@@ -10122,7 +10746,7 @@ function preferredSphereLevel(levels, height, dpr, verticalFov) {
10122
10746
  }
10123
10747
 
10124
10748
  // src/sphere-tile/sphere-tile.tsx
10125
- import { jsx as jsx20, jsxs as jsxs10 } from "react/jsx-runtime";
10749
+ import { jsx as jsx21, jsxs as jsxs11 } from "react/jsx-runtime";
10126
10750
  function sphereTileViewShouldRefresh(input) {
10127
10751
  if (input.loadModeChanged || input.managerChanged) {
10128
10752
  return true;
@@ -10146,13 +10770,13 @@ function SpherePatch({
10146
10770
  ),
10147
10771
  [address, yawOffset2, preview]
10148
10772
  );
10149
- useEffect20(() => () => geometry.dispose(), [geometry]);
10150
- return /* @__PURE__ */ jsx20(
10773
+ useEffect21(() => () => geometry.dispose(), [geometry]);
10774
+ return /* @__PURE__ */ jsx21(
10151
10775
  "mesh",
10152
10776
  {
10153
10777
  geometry,
10154
10778
  renderOrder: preview ? -1e3 : -900 + address.level,
10155
- children: /* @__PURE__ */ jsx20(
10779
+ children: /* @__PURE__ */ jsx21(
10156
10780
  PanoBasicMaterial,
10157
10781
  {
10158
10782
  map: texture,
@@ -10179,10 +10803,10 @@ var ManagedPatch = memo(function ManagedPatch2({
10179
10803
  url,
10180
10804
  address
10181
10805
  );
10182
- useEffect20(() => {
10806
+ useEffect21(() => {
10183
10807
  if (snapshot.texture) ready();
10184
10808
  }, [snapshot.texture, ready]);
10185
- return snapshot.texture ? /* @__PURE__ */ jsx20(
10809
+ return snapshot.texture ? /* @__PURE__ */ jsx21(
10186
10810
  SpherePatch,
10187
10811
  {
10188
10812
  address,
@@ -10257,10 +10881,10 @@ function SphereTileSource({
10257
10881
  callbacks.current.onReady?.();
10258
10882
  }
10259
10883
  }, []);
10260
- useEffect20(() => {
10884
+ useEffect21(() => {
10261
10885
  if (preview) ready();
10262
10886
  }, [preview, ready]);
10263
- useEffect20(() => {
10887
+ useEffect21(() => {
10264
10888
  manager.resume();
10265
10889
  return () => {
10266
10890
  if (manager === ownedManager) {
@@ -10290,7 +10914,7 @@ function SphereTileSource({
10290
10914
  () => sphereTileAddresses({ width: 2, height: 1 }, 0, 2)[0],
10291
10915
  []
10292
10916
  );
10293
- const [layers, setLayers] = useState9([]);
10917
+ const [layers, setLayers] = useState10([]);
10294
10918
  const detailReporter = useSceneDetailReporter();
10295
10919
  const detailReporterRef = useRef20(detailReporter);
10296
10920
  detailReporterRef.current = detailReporter;
@@ -10384,8 +11008,8 @@ function SphereTileSource({
10384
11008
  )
10385
11009
  );
10386
11010
  });
10387
- return /* @__PURE__ */ jsxs10("group", { visible, children: [
10388
- preview ? /* @__PURE__ */ jsx20(
11011
+ return /* @__PURE__ */ jsxs11("group", { visible, children: [
11012
+ preview ? /* @__PURE__ */ jsx21(
10389
11013
  SpherePatch,
10390
11014
  {
10391
11015
  address: previewAddress,
@@ -10395,7 +11019,7 @@ function SphereTileSource({
10395
11019
  }
10396
11020
  ) : null,
10397
11021
  loadMode !== "preview" ? layers.flatMap(
10398
- (layer) => layer.addresses.map((address) => /* @__PURE__ */ jsx20(
11022
+ (layer) => layer.addresses.map((address) => /* @__PURE__ */ jsx21(
10399
11023
  ManagedPatch,
10400
11024
  {
10401
11025
  address,
@@ -10413,12 +11037,12 @@ function SphereTile({ multires, ...props }) {
10413
11037
  const token = typeof multires === "string" ? multires : JSON.stringify(multires);
10414
11038
  const config = useMemo15(() => parseSphereMultires(multires), [token]);
10415
11039
  const sourceKey = `${props.baseUrl}\0${token}\0${props.previewUrl}\0${props.urlTemplate ?? ""}\0${props.indexBase ?? 1}`;
10416
- return /* @__PURE__ */ jsx20(SphereTileSource, { ...props, config }, sourceKey);
11040
+ return /* @__PURE__ */ jsx21(SphereTileSource, { ...props, config }, sourceKey);
10417
11041
  }
10418
11042
 
10419
11043
  // src/tile/tile.tsx
10420
11044
  import { useFrame as useFrame12, useThree as useThree15 } from "@react-three/fiber";
10421
- import { memo as memo2, useEffect as useEffect21, useMemo as useMemo16, useRef as useRef21, useState as useState10 } from "react";
11045
+ import { memo as memo2, useEffect as useEffect22, useMemo as useMemo16, useRef as useRef21, useState as useState11 } from "react";
10422
11046
  import {
10423
11047
  Frustum as Frustum2,
10424
11048
  Matrix4 as Matrix43,
@@ -10553,7 +11177,7 @@ function previewAtlasVRange(face, faceOrder = PREVIEW_FACE_ORDER) {
10553
11177
  }
10554
11178
 
10555
11179
  // src/tile/tile.tsx
10556
- import { jsx as jsx21, jsxs as jsxs11 } from "react/jsx-runtime";
11180
+ import { jsx as jsx22, jsxs as jsxs12 } from "react/jsx-runtime";
10557
11181
  var MAX_LOD_UPDATE_INTERVAL_MS = 100;
10558
11182
  var FAST_ROTATION_THRESHOLD_RADIANS = Math.PI / 180;
10559
11183
  var FAST_FOV_THRESHOLD_DEGREES = 0.5;
@@ -10597,21 +11221,21 @@ function PreviewFace({
10597
11221
  uv.needsUpdate = true;
10598
11222
  return nextGeometry;
10599
11223
  }, [face, faceOrder]);
10600
- useEffect21(
11224
+ useEffect22(
10601
11225
  () => () => {
10602
11226
  geometry.dispose();
10603
11227
  },
10604
11228
  [geometry]
10605
11229
  );
10606
11230
  const transform = getFaceTransform(face, PREVIEW_RADIUS);
10607
- return /* @__PURE__ */ jsx21(
11231
+ return /* @__PURE__ */ jsx22(
10608
11232
  "mesh",
10609
11233
  {
10610
11234
  geometry,
10611
11235
  position: transform.position,
10612
11236
  renderOrder: -100,
10613
11237
  rotation: transform.rotation,
10614
- children: /* @__PURE__ */ jsx21(
11238
+ children: /* @__PURE__ */ jsx22(
10615
11239
  PanoBasicMaterial,
10616
11240
  {
10617
11241
  depthTest: false,
@@ -10627,7 +11251,7 @@ function PreviewCube({
10627
11251
  texture,
10628
11252
  faceOrder
10629
11253
  }) {
10630
- return CUBE_FACES.map((face) => /* @__PURE__ */ jsx21(
11254
+ return CUBE_FACES.map((face) => /* @__PURE__ */ jsx22(
10631
11255
  PreviewFace,
10632
11256
  {
10633
11257
  face,
@@ -10651,14 +11275,14 @@ var TileMesh = memo2(function TileMesh2({
10651
11275
  if (!snapshot.texture) {
10652
11276
  return null;
10653
11277
  }
10654
- return /* @__PURE__ */ jsx21("group", { position: transform.position, rotation: transform.rotation, children: /* @__PURE__ */ jsx21(
11278
+ return /* @__PURE__ */ jsx22("group", { position: transform.position, rotation: transform.rotation, children: /* @__PURE__ */ jsx22(
10655
11279
  "mesh",
10656
11280
  {
10657
11281
  geometry: SHARED_TILE_GEOMETRY,
10658
11282
  position: [layout.x, layout.y, 0],
10659
11283
  renderOrder,
10660
11284
  scale: [layout.width, layout.height, 1],
10661
- children: /* @__PURE__ */ jsx21(
11285
+ children: /* @__PURE__ */ jsx22(
10662
11286
  PanoBasicMaterial,
10663
11287
  {
10664
11288
  depthTest: false,
@@ -10675,7 +11299,7 @@ var TileLayerMeshes = memo2(function TileLayerMeshes2({
10675
11299
  manager,
10676
11300
  resolveUrl
10677
11301
  }) {
10678
- return layer.addresses.map((address) => /* @__PURE__ */ jsx21(
11302
+ return layer.addresses.map((address) => /* @__PURE__ */ jsx22(
10679
11303
  TileMesh,
10680
11304
  {
10681
11305
  address,
@@ -10884,7 +11508,7 @@ function Tile({
10884
11508
  ]
10885
11509
  );
10886
11510
  const manager = sharedManager ?? ownedManager;
10887
- useEffect21(() => {
11511
+ useEffect22(() => {
10888
11512
  manager.resume();
10889
11513
  return () => {
10890
11514
  if (manager === ownedManager) {
@@ -10895,10 +11519,10 @@ function Tile({
10895
11519
  };
10896
11520
  }, [manager, ownedManager]);
10897
11521
  const readyRef = useRef21(false);
10898
- useEffect21(() => {
11522
+ useEffect22(() => {
10899
11523
  readyRef.current = false;
10900
11524
  }, [effectivePreviewUrl]);
10901
- useEffect21(() => {
11525
+ useEffect22(() => {
10902
11526
  if (!previewTexture || readyRef.current) {
10903
11527
  return;
10904
11528
  }
@@ -10913,7 +11537,7 @@ function Tile({
10913
11537
  },
10914
11538
  [baseUrl, resolveTileUrl, template]
10915
11539
  );
10916
- const [layers, setLayers] = useState10([]);
11540
+ const [layers, setLayers] = useState11([]);
10917
11541
  const layerTokenRef = useRef21("");
10918
11542
  const currentLevelRef = useRef21(1);
10919
11543
  const lastUpdateAtRef = useRef21(-Infinity);
@@ -10930,13 +11554,13 @@ function Tile({
10930
11554
  const detailReporter = useSceneDetailReporter();
10931
11555
  const detailReporterRef = useRef21(detailReporter);
10932
11556
  detailReporterRef.current = detailReporter;
10933
- useEffect21(() => {
11557
+ useEffect22(() => {
10934
11558
  currentLevelRef.current = 1;
10935
11559
  layerTokenRef.current = "";
10936
11560
  visibilityDirtyRef.current = true;
10937
11561
  setLayers([]);
10938
11562
  }, [manager, multiresToken]);
10939
- useEffect21(() => {
11563
+ useEffect22(() => {
10940
11564
  if (loadMode !== "preview") {
10941
11565
  return;
10942
11566
  }
@@ -11034,9 +11658,9 @@ function Tile({
11034
11658
  )
11035
11659
  );
11036
11660
  });
11037
- return /* @__PURE__ */ jsxs11("group", { visible, children: [
11038
- previewTexture ? /* @__PURE__ */ jsx21(PreviewCube, { texture: previewTexture, faceOrder: previewFaceOrder }) : null,
11039
- layers.map((layer) => /* @__PURE__ */ jsx21(
11661
+ return /* @__PURE__ */ jsxs12("group", { visible, children: [
11662
+ previewTexture ? /* @__PURE__ */ jsx22(PreviewCube, { texture: previewTexture, faceOrder: previewFaceOrder }) : null,
11663
+ layers.map((layer) => /* @__PURE__ */ jsx22(
11040
11664
  TileLayerMeshes,
11041
11665
  {
11042
11666
  layer,
@@ -11049,7 +11673,7 @@ function Tile({
11049
11673
  }
11050
11674
 
11051
11675
  // src/scenes.tsx
11052
- import { jsx as jsx22, jsxs as jsxs12 } from "react/jsx-runtime";
11676
+ import { jsx as jsx23, jsxs as jsxs13 } from "react/jsx-runtime";
11053
11677
  function SceneSource({
11054
11678
  scene,
11055
11679
  visible,
@@ -11062,7 +11686,7 @@ function SceneSource({
11062
11686
  }
11063
11687
  switch (scene.type) {
11064
11688
  case "sphere":
11065
- return /* @__PURE__ */ jsx22(
11689
+ return /* @__PURE__ */ jsx23(
11066
11690
  Sphere,
11067
11691
  {
11068
11692
  src: scene.src,
@@ -11075,7 +11699,7 @@ function SceneSource({
11075
11699
  );
11076
11700
  case "tile": {
11077
11701
  const { id: _id, type: _type, viewLimits: _limits, ...tileProps } = scene;
11078
- return /* @__PURE__ */ jsx22(
11702
+ return /* @__PURE__ */ jsx23(
11079
11703
  Tile,
11080
11704
  {
11081
11705
  ...tileProps,
@@ -11088,7 +11712,7 @@ function SceneSource({
11088
11712
  }
11089
11713
  case "sphereTile": {
11090
11714
  const { id: _id, type: _type, viewLimits: _limits, ...tileProps } = scene;
11091
- return /* @__PURE__ */ jsx22(
11715
+ return /* @__PURE__ */ jsx23(
11092
11716
  SphereTile,
11093
11717
  {
11094
11718
  ...tileProps,
@@ -11114,7 +11738,7 @@ function SnapshotCapture({
11114
11738
  const { camera, gl, scene, size } = useThree16();
11115
11739
  const capturedRequestRef = useRef22(0);
11116
11740
  const renderTargetRef = useRef22(null);
11117
- useEffect22(
11741
+ useEffect23(
11118
11742
  () => () => {
11119
11743
  renderTargetRef.current?.dispose();
11120
11744
  renderTargetRef.current = null;
@@ -11183,18 +11807,18 @@ function ScenesController({
11183
11807
  [scenes]
11184
11808
  );
11185
11809
  const initialScene = sceneMap.get(activeSceneId) ?? null;
11186
- const [slots, setSlots] = useState11([
11810
+ const [slots, setSlots] = useState12([
11187
11811
  initialScene,
11188
11812
  null
11189
11813
  ]);
11190
- const [activeSlot, setActiveSlot] = useState11(0);
11191
- const [liveSlot, setLiveSlot] = useState11(0);
11192
- const [pendingSlot, setPendingSlot] = useState11(null);
11193
- const [phase, setPhase] = useState11(initialScene ? "idle" : "preloading");
11194
- const [captureRequestId, setCaptureRequestId] = useState11(0);
11195
- const [transitionRunId, setTransitionRunId] = useState11(0);
11196
- const [snapshot, setSnapshot] = useState11(null);
11197
- const [recoveryKey, setRecoveryKey] = useState11(0);
11814
+ const [activeSlot, setActiveSlot] = useState12(0);
11815
+ const [liveSlot, setLiveSlot] = useState12(0);
11816
+ const [pendingSlot, setPendingSlot] = useState12(null);
11817
+ const [phase, setPhase] = useState12(initialScene ? "idle" : "preloading");
11818
+ const [captureRequestId, setCaptureRequestId] = useState12(0);
11819
+ const [transitionRunId, setTransitionRunId] = useState12(0);
11820
+ const [snapshot, setSnapshot] = useState12(null);
11821
+ const [recoveryKey, setRecoveryKey] = useState12(0);
11198
11822
  const requestedSceneIdRef = useRef22(activeSceneId);
11199
11823
  const captureReasonRef = useRef22("start");
11200
11824
  const interactionReleaseRef = useRef22(null);
@@ -11206,7 +11830,7 @@ function ScenesController({
11206
11830
  const waitRef = useRef22(null);
11207
11831
  const waitTimerRef = useRef22(null);
11208
11832
  const detailGenerationRef = useRef22(0);
11209
- const [detailGeneration, setDetailGeneration] = useState11(0);
11833
+ const [detailGeneration, setDetailGeneration] = useState12(0);
11210
11834
  const mountedRef = useRef22(true);
11211
11835
  const waitForDetailMsRef = useRef22(0);
11212
11836
  waitForDetailMsRef.current = normalizeTransitionWaitMs(transitionWaitForDetailMs);
@@ -11216,11 +11840,11 @@ function ScenesController({
11216
11840
  externalPhaseRef.current = phase;
11217
11841
  }
11218
11842
  liveSlotRef.current = liveSlot;
11219
- useEffect22(() => {
11843
+ useEffect23(() => {
11220
11844
  const ready = readySceneRef.current;
11221
11845
  if (ready) controlsRef?.current?.setSceneViewLimits(sceneMap.get(ready.id)?.viewLimits);
11222
11846
  }, [controlsRef, sceneMap]);
11223
- useEffect22(() => () => {
11847
+ useEffect23(() => () => {
11224
11848
  controlsRef?.current?.setSceneViewLimits(void 0);
11225
11849
  }, [controlsRef]);
11226
11850
  const releaseInteraction = useCallback8(() => {
@@ -11251,7 +11875,7 @@ function ScenesController({
11251
11875
  detailGenerationRef.current = nextGeneration;
11252
11876
  setDetailGeneration(nextGeneration);
11253
11877
  }, []);
11254
- useEffect22(() => {
11878
+ useEffect23(() => {
11255
11879
  mountedRef.current = true;
11256
11880
  return () => {
11257
11881
  mountedRef.current = false;
@@ -11270,7 +11894,7 @@ function ScenesController({
11270
11894
  setPendingSlot(nextSlot);
11271
11895
  setPhase("preloading");
11272
11896
  }, [clearDetailWait]);
11273
- useEffect22(() => {
11897
+ useEffect23(() => {
11274
11898
  const requested = sceneMap.get(activeSceneId);
11275
11899
  if (!requested) {
11276
11900
  reportError(activeSceneId, new Error(`Unknown panorama scene: ${activeSceneId}`));
@@ -11487,13 +12111,13 @@ function ScenesController({
11487
12111
  ]);
11488
12112
  const snapshotRef = useRef22(snapshot);
11489
12113
  snapshotRef.current = snapshot;
11490
- useEffect22(() => () => {
12114
+ useEffect23(() => () => {
11491
12115
  releaseInteraction();
11492
12116
  snapshotRef.current?.dispose();
11493
12117
  snapshotRef.current = null;
11494
12118
  }, [releaseInteraction]);
11495
12119
  const { gl } = useThree16();
11496
- useEffect22(() => {
12120
+ useEffect23(() => {
11497
12121
  const canvas = gl.domElement;
11498
12122
  const onContextLost = (event) => {
11499
12123
  event.preventDefault();
@@ -11538,8 +12162,8 @@ ${slots[1]?.id ?? ""}`;
11538
12162
  }
11539
12163
  }));
11540
12164
  }, [consumeDetailSignal, detailGeneration, slotSceneKey]);
11541
- return /* @__PURE__ */ jsxs12(Fragment4, { children: [
11542
- /* @__PURE__ */ jsx22(
12165
+ return /* @__PURE__ */ jsxs13(Fragment4, { children: [
12166
+ /* @__PURE__ */ jsx23(
11543
12167
  SnapshotCapture,
11544
12168
  {
11545
12169
  requestId: captureRequestId,
@@ -11551,11 +12175,11 @@ ${slots[1]?.id ?? ""}`;
11551
12175
  const source = slots[slot];
11552
12176
  const isLive = slot === liveSlot;
11553
12177
  const isPending = slot === pendingSlot;
11554
- return /* @__PURE__ */ jsx22(
12178
+ return /* @__PURE__ */ jsx23(
11555
12179
  SceneDetailContext.Provider,
11556
12180
  {
11557
12181
  value: detailReporters[slot],
11558
- children: /* @__PURE__ */ jsx22(
12182
+ children: /* @__PURE__ */ jsx23(
11559
12183
  SceneSource,
11560
12184
  {
11561
12185
  scene: source,
@@ -11573,8 +12197,8 @@ ${slots[1]?.id ?? ""}`;
11573
12197
  `${slot}:${source?.id ?? "empty"}:${recoveryKey}`
11574
12198
  );
11575
12199
  }),
11576
- snapshot !== null && phase === "awaitingDetail" ? /* @__PURE__ */ jsx22(SnapshotHold, { snapshot }) : null,
11577
- snapshotVisible ? /* @__PURE__ */ jsx22(
12200
+ snapshot !== null && phase === "awaitingDetail" ? /* @__PURE__ */ jsx23(SnapshotHold, { snapshot }) : null,
12201
+ snapshotVisible ? /* @__PURE__ */ jsx23(
11578
12202
  TransitionOverlay,
11579
12203
  {
11580
12204
  snapshot,
@@ -11597,7 +12221,7 @@ function Scenes({
11597
12221
  ...rest
11598
12222
  }) {
11599
12223
  const isControlled = controlledId !== void 0;
11600
- const [internalId, setInternalId] = useState11(
12224
+ const [internalId, setInternalId] = useState12(
11601
12225
  () => controlledId ?? defaultActiveSceneId ?? scenes[0]?.id ?? ""
11602
12226
  );
11603
12227
  const resolvedId = isControlled ? controlledId : internalId;
@@ -11617,7 +12241,7 @@ function Scenes({
11617
12241
  resolvedIdRef.current = resolvedId;
11618
12242
  const host = useContext19(ScenesHostContext);
11619
12243
  const phaseRef = useRef22("idle");
11620
- useEffect22(() => {
12244
+ useEffect23(() => {
11621
12245
  if (!host) {
11622
12246
  return;
11623
12247
  }
@@ -11667,12 +12291,12 @@ function Scenes({
11667
12291
  }
11668
12292
  };
11669
12293
  }, [host, requestSceneChange]);
11670
- return /* @__PURE__ */ jsx22(
12294
+ return /* @__PURE__ */ jsx23(
11671
12295
  TileTextureManagerProvider,
11672
12296
  {
11673
12297
  maxTextureMemoryMb,
11674
12298
  maxConcurrentLoads: maxConcurrentTileLoads,
11675
- children: /* @__PURE__ */ jsx22(
12299
+ children: /* @__PURE__ */ jsx23(
11676
12300
  ScenesController,
11677
12301
  {
11678
12302
  ...rest,
@@ -11687,7 +12311,7 @@ function Scenes({
11687
12311
 
11688
12312
  // src/hotspot/image-hotspot.tsx
11689
12313
  import { useThree as useThree20 } from "@react-three/fiber";
11690
- import { useEffect as useEffect25, useRef as useRef26, useState as useState14 } from "react";
12314
+ import { useEffect as useEffect26, useRef as useRef26, useState as useState15 } from "react";
11691
12315
  import {
11692
12316
  ClampToEdgeWrapping as ClampToEdgeWrapping3,
11693
12317
  LinearFilter as LinearFilter5,
@@ -11700,11 +12324,11 @@ import {
11700
12324
  import { useFrame as useFrame16, useThree as useThree19 } from "@react-three/fiber";
11701
12325
  import {
11702
12326
  useContext as useContext21,
11703
- useEffect as useEffect24,
12327
+ useEffect as useEffect25,
11704
12328
  useLayoutEffect as useLayoutEffect7,
11705
12329
  useMemo as useMemo19,
11706
12330
  useRef as useRef25,
11707
- useState as useState13
12331
+ useState as useState14
11708
12332
  } from "react";
11709
12333
  import {
11710
12334
  Box3 as Box34,
@@ -11810,7 +12434,7 @@ function suppressFollowingClick(target) {
11810
12434
  }
11811
12435
 
11812
12436
  // src/hotspot/hotspot-tooltip.tsx
11813
- import { useEffect as useEffect23, useMemo as useMemo18, useState as useState12 } from "react";
12437
+ import { useEffect as useEffect24, useMemo as useMemo18, useState as useState13 } from "react";
11814
12438
 
11815
12439
  // src/webvr/stereo-html.tsx
11816
12440
  import { useFrame as useFrame14, useThree as useThree17 } from "@react-three/fiber";
@@ -11818,15 +12442,15 @@ import {
11818
12442
  useContext as useContext20,
11819
12443
  useLayoutEffect as useLayoutEffect5,
11820
12444
  useRef as useRef23,
11821
- useSyncExternalStore as useSyncExternalStore7
12445
+ useSyncExternalStore as useSyncExternalStore9
11822
12446
  } from "react";
11823
12447
  import { createRoot } from "react-dom/client";
11824
12448
  import { Vector3 as Vector314 } from "three";
11825
- import { Fragment as Fragment5, jsx as jsx23, jsxs as jsxs13 } from "react/jsx-runtime";
12449
+ import { Fragment as Fragment5, jsx as jsx24, jsxs as jsxs14 } from "react/jsx-runtime";
11826
12450
  function useFallbackStereoView() {
11827
12451
  const runtime = useContext20(WebVRRuntimeContext);
11828
12452
  const host = runtime?.host ?? null;
11829
- const fallback = useSyncExternalStore7(
12453
+ const fallback = useSyncExternalStore9(
11830
12454
  (onStoreChange) => host ? subscribeWebVRHost(host, onStoreChange) : () => void 0,
11831
12455
  () => isFallbackStereoMode(host?.snapshot.mode ?? null),
11832
12456
  () => false
@@ -11892,7 +12516,7 @@ function ProjectedHtml({
11892
12516
  }, [target]);
11893
12517
  useLayoutEffect5(() => {
11894
12518
  overlay.current?.root.render(
11895
- /* @__PURE__ */ jsx23(
12519
+ /* @__PURE__ */ jsx24(
11896
12520
  "div",
11897
12521
  {
11898
12522
  "aria-hidden": eye === "right" || void 0,
@@ -11904,18 +12528,29 @@ function ProjectedHtml({
11904
12528
  updatePosition();
11905
12529
  });
11906
12530
  useFrame14(updatePosition);
11907
- return /* @__PURE__ */ jsx23("group", { ref: group });
12531
+ return /* @__PURE__ */ jsx24("group", { ref: group });
11908
12532
  }
11909
12533
  function PanoHtml(props) {
12534
+ const runtime = useContext20(WebVRRuntimeContext);
12535
+ const host = runtime?.host ?? null;
12536
+ const mode = useSyncExternalStore9(
12537
+ (onStoreChange) => host ? subscribeWebVRHost(host, onStoreChange) : () => void 0,
12538
+ () => host?.snapshot.mode ?? null,
12539
+ () => null
12540
+ );
12541
+ const portrait = usePortraitOrientation();
11910
12542
  const stereoView = useFallbackStereoView();
11911
- return stereoView ? /* @__PURE__ */ jsxs13(Fragment5, { children: [
11912
- /* @__PURE__ */ jsx23(ProjectedHtml, { ...props, stereoView, eye: "left" }),
11913
- /* @__PURE__ */ jsx23(ProjectedHtml, { ...props, stereoView, eye: "right" })
11914
- ] }) : /* @__PURE__ */ jsx23(ProjectedHtml, { ...props });
12543
+ if (mode === "mobilevr" && portrait) {
12544
+ return null;
12545
+ }
12546
+ return stereoView ? /* @__PURE__ */ jsxs14(Fragment5, { children: [
12547
+ /* @__PURE__ */ jsx24(ProjectedHtml, { ...props, stereoView, eye: "left" }),
12548
+ /* @__PURE__ */ jsx24(ProjectedHtml, { ...props, stereoView, eye: "right" })
12549
+ ] }) : /* @__PURE__ */ jsx24(ProjectedHtml, { ...props });
11915
12550
  }
11916
12551
 
11917
12552
  // src/hotspot/hotspot-tooltip.tsx
11918
- import { jsx as jsx24, jsxs as jsxs14 } from "react/jsx-runtime";
12553
+ import { jsx as jsx25, jsxs as jsxs15 } from "react/jsx-runtime";
11919
12554
  var DEFAULT_HOTSPOT_TOOLTIP_OFFSET = 12;
11920
12555
  var DEFAULT_HOTSPOT_TOOLTIP_APPEARANCE = {
11921
12556
  background: "rgba(22, 22, 22, 0.72)",
@@ -11987,8 +12622,8 @@ function HotspotTooltip({
11987
12622
  offset = DEFAULT_HOTSPOT_TOOLTIP_OFFSET,
11988
12623
  appearance
11989
12624
  }) {
11990
- const [imageFailed, setImageFailed] = useState12(false);
11991
- useEffect23(() => {
12625
+ const [imageFailed, setImageFailed] = useState13(false);
12626
+ useEffect24(() => {
11992
12627
  setImageFailed(false);
11993
12628
  }, [content.image]);
11994
12629
  const showImage = Boolean(content.image) && !imageFailed;
@@ -12018,8 +12653,8 @@ function HotspotTooltip({
12018
12653
  if (!showImage && !content.text) {
12019
12654
  return null;
12020
12655
  }
12021
- return /* @__PURE__ */ jsx24(PanoHtml, { pointerEvents: "none", style: WRAPPER_STYLE, zIndexRange: [20, 10], children: /* @__PURE__ */ jsxs14("div", { className: "pano-hotspot-tooltip", role: "tooltip", style: bubbleStyle, children: [
12022
- showImage ? /* @__PURE__ */ jsx24(
12656
+ return /* @__PURE__ */ jsx25(PanoHtml, { pointerEvents: "none", style: WRAPPER_STYLE, zIndexRange: [20, 10], children: /* @__PURE__ */ jsxs15("div", { className: "pano-hotspot-tooltip", role: "tooltip", style: bubbleStyle, children: [
12657
+ showImage ? /* @__PURE__ */ jsx25(
12023
12658
  "img",
12024
12659
  {
12025
12660
  alt: content.imageAlt ?? content.text ?? "",
@@ -12028,7 +12663,7 @@ function HotspotTooltip({
12028
12663
  src: content.image
12029
12664
  }
12030
12665
  ) : null,
12031
- content.text ? /* @__PURE__ */ jsx24(
12666
+ content.text ? /* @__PURE__ */ jsx25(
12032
12667
  "p",
12033
12668
  {
12034
12669
  className: "pano-hotspot-tooltip-text",
@@ -12102,7 +12737,7 @@ import {
12102
12737
  PerspectiveCamera as PerspectiveCamera7,
12103
12738
  Vector3 as Vector316
12104
12739
  } from "three";
12105
- import { jsx as jsx25 } from "react/jsx-runtime";
12740
+ import { jsx as jsx26 } from "react/jsx-runtime";
12106
12741
  var LINE_WORLD_POSITION = new Vector316();
12107
12742
  function applyScreenSpaceDashScale(object, camera, viewportHeight) {
12108
12743
  const material = object?.material;
@@ -12148,7 +12783,7 @@ function HotspotStrokeLine({
12148
12783
  }
12149
12784
  applyScreenSpaceDashScale(lineRef.current, state.camera, state.size.height);
12150
12785
  });
12151
- return /* @__PURE__ */ jsx25(
12786
+ return /* @__PURE__ */ jsx26(
12152
12787
  Line,
12153
12788
  {
12154
12789
  ref: lineRef,
@@ -12170,7 +12805,7 @@ function HotspotStrokeLine({
12170
12805
  }
12171
12806
 
12172
12807
  // src/hotspot/hotspot-anchor.tsx
12173
- import { jsx as jsx26, jsxs as jsxs15 } from "react/jsx-runtime";
12808
+ import { jsx as jsx27, jsxs as jsxs16 } from "react/jsx-runtime";
12174
12809
  var DEFAULT_FLOATING_DISTANCE = 10;
12175
12810
  var PANORAMA_RADIUS = DEFAULT_PANORAMA_RADIUS;
12176
12811
  var PANORAMA_SURFACE_INSET = 4;
@@ -12558,15 +13193,15 @@ function HotspotAnchor({
12558
13193
  const updateDragRef = useRef25(() => void 0);
12559
13194
  const endDragRef = useRef25(() => void 0);
12560
13195
  const suppressNextClickRef = useRef25(false);
12561
- const [hovered, setHovered] = useState13(false);
12562
- const [dragging, setDragging] = useState13(false);
12563
- const [pinned, setPinned] = useState13(false);
13196
+ const [hovered, setHovered] = useState14(false);
13197
+ const [dragging, setDragging] = useState14(false);
13198
+ const [pinned, setPinned] = useState14(false);
12564
13199
  const tooltipContent = useMemo19(
12565
13200
  () => resolveHotspotTooltipContent(tooltip),
12566
13201
  [tooltip]
12567
13202
  );
12568
13203
  const normalizedPosition = normalizePanoPosition(position);
12569
- useEffect24(() => {
13204
+ useEffect25(() => {
12570
13205
  if (!hotspotTargetRegistry) {
12571
13206
  return;
12572
13207
  }
@@ -12600,7 +13235,7 @@ function HotspotAnchor({
12600
13235
  return geometry;
12601
13236
  }, []);
12602
13237
  const eventHovered = useRef25(false);
12603
- useEffect24(() => {
13238
+ useEffect25(() => {
12604
13239
  if (!visible || !interactive || pointerEvents === "none") eventHovered.current = false;
12605
13240
  }, [visible, interactive, pointerEvents]);
12606
13241
  const acceptsPointer = acceptsHotspotPointerEvents(interactive, pointerEvents);
@@ -12624,7 +13259,7 @@ function HotspotAnchor({
12624
13259
  });
12625
13260
  const tooltipOpen = visible && tooltipContent !== null && isTooltipOpen(tooltipTrigger, hovered, focused, pinned);
12626
13261
  const cursorClaimId = hotspotCursorClaimId(id);
12627
- useEffect24(
13262
+ useEffect25(
12628
13263
  () => () => {
12629
13264
  const dragState = dragStateRef.current;
12630
13265
  dragState?.stopTracking();
@@ -12633,7 +13268,7 @@ function HotspotAnchor({
12633
13268
  },
12634
13269
  []
12635
13270
  );
12636
- useEffect24(() => {
13271
+ useEffect25(() => {
12637
13272
  if (!cursorApi) {
12638
13273
  return;
12639
13274
  }
@@ -12655,14 +13290,14 @@ function HotspotAnchor({
12655
13290
  hovered,
12656
13291
  visible
12657
13292
  ]);
12658
- useEffect24(
13293
+ useEffect25(
12659
13294
  () => () => {
12660
13295
  cursorApi?.release(cursorClaimId);
12661
13296
  },
12662
13297
  [cursorApi, cursorClaimId]
12663
13298
  );
12664
- useEffect24(() => () => focusGeometry.dispose(), [focusGeometry]);
12665
- useEffect24(() => {
13299
+ useEffect25(() => () => focusGeometry.dispose(), [focusGeometry]);
13300
+ useEffect25(() => {
12666
13301
  if (tooltipTrigger !== "click") {
12667
13302
  setPinned(false);
12668
13303
  return;
@@ -12671,12 +13306,12 @@ function HotspotAnchor({
12671
13306
  setPinned(false);
12672
13307
  });
12673
13308
  }, [eventBus, tooltipTrigger]);
12674
- useEffect24(() => {
13309
+ useEffect25(() => {
12675
13310
  if (tooltipTrigger !== "hover") {
12676
13311
  setHovered(false);
12677
13312
  }
12678
13313
  }, [tooltipTrigger]);
12679
- useEffect24(() => {
13314
+ useEffect25(() => {
12680
13315
  if (acceptsPointer) {
12681
13316
  return;
12682
13317
  }
@@ -12847,7 +13482,7 @@ function HotspotAnchor({
12847
13482
  startPosition
12848
13483
  });
12849
13484
  };
12850
- return /* @__PURE__ */ jsxs15(
13485
+ return /* @__PURE__ */ jsxs16(
12851
13486
  "group",
12852
13487
  {
12853
13488
  ref: groupRef,
@@ -12951,18 +13586,18 @@ function HotspotAnchor({
12951
13586
  endDragRef.current(event.nativeEvent, true);
12952
13587
  } : void 0,
12953
13588
  children: [
12954
- focused ? focusContent ?? /* @__PURE__ */ jsx26(
13589
+ focused ? focusContent ?? /* @__PURE__ */ jsx27(
12955
13590
  "lineSegments",
12956
13591
  {
12957
13592
  geometry: focusGeometry,
12958
13593
  position: [0, 0, 0.01],
12959
13594
  renderOrder: renderOrder + 1,
12960
13595
  scale: [1.12, 1.12, 1],
12961
- children: /* @__PURE__ */ jsx26("lineBasicMaterial", { color: "#f5fbfc", depthTest: false })
13596
+ children: /* @__PURE__ */ jsx27("lineBasicMaterial", { color: "#f5fbfc", depthTest: false })
12962
13597
  }
12963
13598
  ) : null,
12964
13599
  children,
12965
- selected && useAngularScale ? /* @__PURE__ */ jsx26("group", { ref: selectionFrameRef, children: /* @__PURE__ */ jsx26(
13600
+ selected && useAngularScale ? /* @__PURE__ */ jsx27("group", { ref: selectionFrameRef, children: /* @__PURE__ */ jsx27(
12966
13601
  HotspotStrokeLine,
12967
13602
  {
12968
13603
  points: SELECTION_BORDER_POINTS,
@@ -12972,7 +13607,7 @@ function HotspotAnchor({
12972
13607
  renderOrder: renderOrder + 1
12973
13608
  }
12974
13609
  ) }) : null,
12975
- tooltipOpen && tooltipContent ? /* @__PURE__ */ jsx26("group", { ref: tooltipAnchorRef, children: /* @__PURE__ */ jsx26(
13610
+ tooltipOpen && tooltipContent ? /* @__PURE__ */ jsx27("group", { ref: tooltipAnchorRef, children: /* @__PURE__ */ jsx27(
12976
13611
  HotspotTooltip,
12977
13612
  {
12978
13613
  appearance: tooltipAppearance,
@@ -12993,7 +13628,7 @@ import {
12993
13628
  MeshBasicMaterial,
12994
13629
  Vector2 as Vector25
12995
13630
  } from "three";
12996
- import { jsx as jsx27, jsxs as jsxs16 } from "react/jsx-runtime";
13631
+ import { jsx as jsx28, jsxs as jsxs17 } from "react/jsx-runtime";
12997
13632
  var HOTSPOT_ALPHA_CUTOFF = 0.05;
12998
13633
  var SAMPLE_UV = new Vector25();
12999
13634
  var RAYCAST_HITS = [];
@@ -13095,9 +13730,9 @@ function HotspotPlane({
13095
13730
  map,
13096
13731
  opacity
13097
13732
  }) {
13098
- return /* @__PURE__ */ jsxs16("mesh", { raycast: hotspotPlaneRaycast, children: [
13099
- /* @__PURE__ */ jsx27("planeGeometry", { args: [1, 1] }),
13100
- /* @__PURE__ */ jsx27(
13733
+ return /* @__PURE__ */ jsxs17("mesh", { raycast: hotspotPlaneRaycast, children: [
13734
+ /* @__PURE__ */ jsx28("planeGeometry", { args: [1, 1] }),
13735
+ /* @__PURE__ */ jsx28(
13101
13736
  PanoBasicMaterial,
13102
13737
  {
13103
13738
  target: "hotspot",
@@ -13113,15 +13748,15 @@ function HotspotPlane({
13113
13748
  }
13114
13749
 
13115
13750
  // src/hotspot/image-hotspot.tsx
13116
- import { jsx as jsx28 } from "react/jsx-runtime";
13751
+ import { jsx as jsx29 } from "react/jsx-runtime";
13117
13752
  function useHotspotImageTexture(src, onLoad, onError) {
13118
13753
  const gl = useThree20((state) => state.gl);
13119
- const [texture, setTexture] = useState14(null);
13754
+ const [texture, setTexture] = useState15(null);
13120
13755
  const onLoadRef = useRef26(onLoad);
13121
13756
  const onErrorRef = useRef26(onError);
13122
13757
  onLoadRef.current = onLoad;
13123
13758
  onErrorRef.current = onError;
13124
- useEffect25(() => {
13759
+ useEffect26(() => {
13125
13760
  let active = true;
13126
13761
  setTexture(null);
13127
13762
  if (!src) {
@@ -13159,7 +13794,7 @@ function useHotspotImageTexture(src, onLoad, onError) {
13159
13794
  active = false;
13160
13795
  };
13161
13796
  }, [gl, src]);
13162
- useEffect25(
13797
+ useEffect26(
13163
13798
  () => () => {
13164
13799
  texture?.dispose();
13165
13800
  },
@@ -13177,11 +13812,11 @@ function ImageHotspot({
13177
13812
  ...anchorProps
13178
13813
  }) {
13179
13814
  const texture = useHotspotImageTexture(src, onLoad, onError);
13180
- return /* @__PURE__ */ jsx28(HotspotAnchor, { ...anchorProps, height, width, children: /* @__PURE__ */ jsx28(HotspotPlane, { map: texture, opacity }) });
13815
+ return /* @__PURE__ */ jsx29(HotspotAnchor, { ...anchorProps, height, width, children: /* @__PURE__ */ jsx29(HotspotPlane, { map: texture, opacity }) });
13181
13816
  }
13182
13817
 
13183
13818
  // src/hotspot/graphic-hotspot.tsx
13184
- import { useEffect as useEffect26, useRef as useRef27, useState as useState15 } from "react";
13819
+ import { useEffect as useEffect27, useRef as useRef27, useState as useState16 } from "react";
13185
13820
  import {
13186
13821
  CanvasTexture,
13187
13822
  ClampToEdgeWrapping as ClampToEdgeWrapping4,
@@ -13189,7 +13824,7 @@ import {
13189
13824
  LinearMipmapLinearFilter as LinearMipmapLinearFilter3,
13190
13825
  SRGBColorSpace as SRGBColorSpace5
13191
13826
  } from "three";
13192
- import { jsx as jsx29 } from "react/jsx-runtime";
13827
+ import { jsx as jsx30 } from "react/jsx-runtime";
13193
13828
  var GRAPHIC_TEXTURE_SIZE = 512;
13194
13829
  function resolveStrokeWidth(value) {
13195
13830
  return Number.isFinite(value) ? Math.max(value, 0) : 8;
@@ -13378,12 +14013,12 @@ function createGraphicTexture(graphic, aspectWidth, aspectHeight) {
13378
14013
  return texture;
13379
14014
  }
13380
14015
  function useGraphicTexture(graphic, aspectWidth, aspectHeight, onLoad, onError) {
13381
- const [texture, setTexture] = useState15(null);
14016
+ const [texture, setTexture] = useState16(null);
13382
14017
  const onLoadRef = useRef27(onLoad);
13383
14018
  const onErrorRef = useRef27(onError);
13384
14019
  onLoadRef.current = onLoad;
13385
14020
  onErrorRef.current = onError;
13386
- useEffect26(() => {
14021
+ useEffect27(() => {
13387
14022
  let nextTexture = null;
13388
14023
  try {
13389
14024
  nextTexture = createGraphicTexture(graphic, aspectWidth, aspectHeight);
@@ -13409,20 +14044,20 @@ function CanvasGraphicHotspot({
13409
14044
  ...anchorProps
13410
14045
  }) {
13411
14046
  const texture = useGraphicTexture(graphic, width, height, onLoad, onError);
13412
- return /* @__PURE__ */ jsx29(HotspotAnchor, { ...anchorProps, height, width, children: /* @__PURE__ */ jsx29(HotspotPlane, { map: texture, opacity }) });
14047
+ return /* @__PURE__ */ jsx30(HotspotAnchor, { ...anchorProps, height, width, children: /* @__PURE__ */ jsx30(HotspotPlane, { map: texture, opacity }) });
13413
14048
  }
13414
14049
  function GraphicHotspot(props) {
13415
14050
  const { graphic, ...restProps } = props;
13416
14051
  if (graphic.kind === "svg") {
13417
14052
  const imageProps = restProps;
13418
- return /* @__PURE__ */ jsx29(ImageHotspot, { ...imageProps, src: graphic.src });
14053
+ return /* @__PURE__ */ jsx30(ImageHotspot, { ...imageProps, src: graphic.src });
13419
14054
  }
13420
- return /* @__PURE__ */ jsx29(CanvasGraphicHotspot, { ...restProps, graphic });
14055
+ return /* @__PURE__ */ jsx30(CanvasGraphicHotspot, { ...restProps, graphic });
13421
14056
  }
13422
14057
 
13423
14058
  // src/hotspot/sequence-hotspot.tsx
13424
14059
  import { useFrame as useFrame17, useThree as useThree21 } from "@react-three/fiber";
13425
- import { useEffect as useEffect27, useRef as useRef28, useState as useState16 } from "react";
14060
+ import { useEffect as useEffect28, useRef as useRef28, useState as useState17 } from "react";
13426
14061
  import {
13427
14062
  ClampToEdgeWrapping as ClampToEdgeWrapping5,
13428
14063
  LinearFilter as LinearFilter7,
@@ -13430,7 +14065,7 @@ import {
13430
14065
  SRGBColorSpace as SRGBColorSpace6,
13431
14066
  TextureLoader as TextureLoader5
13432
14067
  } from "three";
13433
- import { jsx as jsx30 } from "react/jsx-runtime";
14068
+ import { jsx as jsx31 } from "react/jsx-runtime";
13434
14069
  var DEFAULT_SEQUENCE_FPS = 12;
13435
14070
  function resolveFps(value) {
13436
14071
  return Number.isFinite(value) && value > 0 ? value : DEFAULT_SEQUENCE_FPS;
@@ -13445,12 +14080,12 @@ function useSpriteTexture({
13445
14080
  onLoadProgress
13446
14081
  }) {
13447
14082
  const gl = useThree21((state) => state.gl);
13448
- const [texture, setTexture] = useState16(null);
14083
+ const [texture, setTexture] = useState17(null);
13449
14084
  const onErrorRef = useRef28(onError);
13450
14085
  const onLoadProgressRef = useRef28(onLoadProgress);
13451
14086
  onErrorRef.current = onError;
13452
14087
  onLoadProgressRef.current = onLoadProgress;
13453
- useEffect27(() => {
14088
+ useEffect28(() => {
13454
14089
  let active = true;
13455
14090
  setTexture(null);
13456
14091
  if (!src) {
@@ -13491,7 +14126,7 @@ function useSpriteTexture({
13491
14126
  active = false;
13492
14127
  };
13493
14128
  }, [gl, id, src]);
13494
- useEffect27(
14129
+ useEffect28(
13495
14130
  () => () => {
13496
14131
  texture?.dispose();
13497
14132
  },
@@ -13520,7 +14155,7 @@ function SequenceHotspot({
13520
14155
  const texture = useSpriteTexture({ id, src, onError, onLoadProgress });
13521
14156
  const frameCount = resolveFrameCount(requestedFrameCount);
13522
14157
  const safeFps = resolveFps(fps);
13523
- const [frameIndex, setFrameIndex] = useState16(0);
14158
+ const [frameIndex, setFrameIndex] = useState17(0);
13524
14159
  const elapsedRef = useRef28(0);
13525
14160
  const frameIndexRef = useRef28(0);
13526
14161
  const endedRef = useRef28(false);
@@ -13531,13 +14166,13 @@ function SequenceHotspot({
13531
14166
  onFrameChangeRef.current = onFrameChange;
13532
14167
  onPlaybackStateChangeRef.current = onPlaybackStateChange;
13533
14168
  onEndedRef.current = onEnded;
13534
- useEffect27(() => {
14169
+ useEffect28(() => {
13535
14170
  elapsedRef.current = 0;
13536
14171
  frameIndexRef.current = 0;
13537
14172
  endedRef.current = false;
13538
14173
  setFrameIndex(0);
13539
14174
  }, [frameCount, frameDirection, src]);
13540
- useEffect27(() => {
14175
+ useEffect28(() => {
13541
14176
  if (!texture) {
13542
14177
  return;
13543
14178
  }
@@ -13551,13 +14186,13 @@ function SequenceHotspot({
13551
14186
  );
13552
14187
  texture.needsUpdate = true;
13553
14188
  }, [frameCount, frameDirection, frameIndex, texture]);
13554
- useEffect27(() => {
14189
+ useEffect28(() => {
13555
14190
  if (!texture) {
13556
14191
  return;
13557
14192
  }
13558
14193
  onFrameChangeRef.current?.({ id, index: 0, src });
13559
14194
  }, [id, src, texture]);
13560
- useEffect27(() => {
14195
+ useEffect28(() => {
13561
14196
  if (!texture) {
13562
14197
  return;
13563
14198
  }
@@ -13606,12 +14241,12 @@ function SequenceHotspot({
13606
14241
  onFrameChangeRef.current?.({ id, index: nextIndex, src });
13607
14242
  }
13608
14243
  });
13609
- return /* @__PURE__ */ jsx30(HotspotAnchor, { ...anchorProps, id, height, width, children: /* @__PURE__ */ jsx30(HotspotPlane, { map: texture, opacity }) });
14244
+ return /* @__PURE__ */ jsx31(HotspotAnchor, { ...anchorProps, id, height, width, children: /* @__PURE__ */ jsx31(HotspotPlane, { map: texture, opacity }) });
13610
14245
  }
13611
14246
 
13612
14247
  // src/hotspot/video-hotspot.tsx
13613
14248
  import { useThree as useThree22 } from "@react-three/fiber";
13614
- import { useEffect as useEffect28, useLayoutEffect as useLayoutEffect8, useRef as useRef29, useState as useState17 } from "react";
14249
+ import { useEffect as useEffect29, useLayoutEffect as useLayoutEffect8, useRef as useRef29, useState as useState18 } from "react";
13615
14250
  import {
13616
14251
  ClampToEdgeWrapping as ClampToEdgeWrapping6,
13617
14252
  LinearFilter as LinearFilter8,
@@ -13672,7 +14307,7 @@ function mountTextureVideo(video, canvas) {
13672
14307
  }
13673
14308
 
13674
14309
  // src/hotspot/video-hotspot.tsx
13675
- import { jsx as jsx31 } from "react/jsx-runtime";
14310
+ import { jsx as jsx32 } from "react/jsx-runtime";
13676
14311
  function clampVolume2(volume) {
13677
14312
  if (!Number.isFinite(volume)) {
13678
14313
  return 1;
@@ -13681,10 +14316,10 @@ function clampVolume2(volume) {
13681
14316
  }
13682
14317
  function usePosterTexture(id, poster, onError) {
13683
14318
  const gl = useThree22((state) => state.gl);
13684
- const [texture, setTexture] = useState17(null);
14319
+ const [texture, setTexture] = useState18(null);
13685
14320
  const onErrorRef = useRef29(onError);
13686
14321
  onErrorRef.current = onError;
13687
- useEffect28(() => {
14322
+ useEffect29(() => {
13688
14323
  let active = true;
13689
14324
  setTexture(null);
13690
14325
  if (!poster) {
@@ -13721,7 +14356,7 @@ function usePosterTexture(id, poster, onError) {
13721
14356
  active = false;
13722
14357
  };
13723
14358
  }, [gl, id, poster]);
13724
- useEffect28(
14359
+ useEffect29(
13725
14360
  () => () => {
13726
14361
  texture?.dispose();
13727
14362
  },
@@ -13740,14 +14375,14 @@ function useVideoResource({
13740
14375
  src
13741
14376
  }) {
13742
14377
  const gl = useThree22((state) => state.gl);
13743
- const [resource, setResource] = useState17(null);
14378
+ const [resource, setResource] = useState18(null);
13744
14379
  const onEndedRef = useRef29(onEnded);
13745
14380
  const onErrorRef = useRef29(onError);
13746
14381
  const onPlaybackStateChangeRef = useRef29(onPlaybackStateChange);
13747
14382
  onEndedRef.current = onEnded;
13748
14383
  onErrorRef.current = onError;
13749
14384
  onPlaybackStateChangeRef.current = onPlaybackStateChange;
13750
- useEffect28(() => {
14385
+ useEffect29(() => {
13751
14386
  if (!src) {
13752
14387
  setResource(null);
13753
14388
  return;
@@ -13874,7 +14509,7 @@ function VideoHotspot({
13874
14509
  applyInlineVideoPlayback(resource.video, playsInline);
13875
14510
  resource.video.preload = preload;
13876
14511
  }, [loop, muted, playsInline, preload, resource, volume]);
13877
- useEffect28(() => {
14512
+ useEffect29(() => {
13878
14513
  if (!resource) {
13879
14514
  return;
13880
14515
  }
@@ -13897,12 +14532,12 @@ function VideoHotspot({
13897
14532
  };
13898
14533
  }, [playing, resource]);
13899
14534
  const activeTexture = resource?.ready ? resource.texture : posterTexture;
13900
- return /* @__PURE__ */ jsx31(HotspotAnchor, { ...anchorProps, id, height, width, children: /* @__PURE__ */ jsx31(HotspotPlane, { map: activeTexture, opacity }) });
14535
+ return /* @__PURE__ */ jsx32(HotspotAnchor, { ...anchorProps, id, height, width, children: /* @__PURE__ */ jsx32(HotspotPlane, { map: activeTexture, opacity }) });
13901
14536
  }
13902
14537
 
13903
14538
  // src/hotspot/audio-hotspot.tsx
13904
14539
  import { useFrame as useFrame18, useThree as useThree23 } from "@react-three/fiber";
13905
- import { useEffect as useEffect29, useRef as useRef30, useState as useState18 } from "react";
14540
+ import { useEffect as useEffect30, useRef as useRef30, useState as useState19 } from "react";
13906
14541
  import {
13907
14542
  CanvasTexture as CanvasTexture2,
13908
14543
  ClampToEdgeWrapping as ClampToEdgeWrapping7,
@@ -13957,7 +14592,7 @@ function audioSpatialFromView(camera, position, range) {
13957
14592
  }
13958
14593
 
13959
14594
  // src/hotspot/audio-hotspot.tsx
13960
- import { jsx as jsx32 } from "react/jsx-runtime";
14595
+ import { jsx as jsx33 } from "react/jsx-runtime";
13961
14596
  var SPEAKER_TEXTURE_SIZE = 512;
13962
14597
  function paintSpeakerBody(context, center) {
13963
14598
  context.fillStyle = "#f5fbfc";
@@ -14021,8 +14656,8 @@ function createSpeakerTexture(state) {
14021
14656
  return texture;
14022
14657
  }
14023
14658
  function useSpeakerTextures(enabled) {
14024
- const [textures, setTextures] = useState18({ playing: null, stopped: null });
14025
- useEffect29(() => {
14659
+ const [textures, setTextures] = useState19({ playing: null, stopped: null });
14660
+ useEffect30(() => {
14026
14661
  if (!enabled) {
14027
14662
  setTextures({ playing: null, stopped: null });
14028
14663
  return;
@@ -14039,10 +14674,10 @@ function useSpeakerTextures(enabled) {
14039
14674
  }
14040
14675
  function useIconTexture(icon, enabled, onError, id) {
14041
14676
  const gl = useThree23((state) => state.gl);
14042
- const [texture, setTexture] = useState18(null);
14677
+ const [texture, setTexture] = useState19(null);
14043
14678
  const onErrorRef = useRef30(onError);
14044
14679
  onErrorRef.current = onError;
14045
- useEffect29(() => {
14680
+ useEffect30(() => {
14046
14681
  let active = true;
14047
14682
  setTexture(null);
14048
14683
  if (!enabled || !icon) {
@@ -14079,7 +14714,7 @@ function useIconTexture(icon, enabled, onError, id) {
14079
14714
  active = false;
14080
14715
  };
14081
14716
  }, [enabled, gl, icon, id]);
14082
- useEffect29(
14717
+ useEffect30(
14083
14718
  () => () => {
14084
14719
  texture?.dispose();
14085
14720
  },
@@ -14099,7 +14734,7 @@ function useAudioHowl({
14099
14734
  src,
14100
14735
  format
14101
14736
  }) {
14102
- const [howl, setHowl] = useState18(null);
14737
+ const [howl, setHowl] = useState19(null);
14103
14738
  const playingRef = useRef30(playing);
14104
14739
  const loopRef = useRef30(loop ?? false);
14105
14740
  const onEndedRef = useRef30(onEnded);
@@ -14114,7 +14749,7 @@ function useAudioHowl({
14114
14749
  onPlaybackStateChangeRef.current = onPlaybackStateChange;
14115
14750
  const sourcesKey = sourceList(src).join("\0");
14116
14751
  const formatsKey = sourceList(format).join("\0");
14117
- useEffect29(() => {
14752
+ useEffect30(() => {
14118
14753
  const sources = sourcesKey.length > 0 ? sourcesKey.split("\0") : [];
14119
14754
  if (sources.length === 0) {
14120
14755
  setHowl(null);
@@ -14152,7 +14787,7 @@ function useAudioHowl({
14152
14787
  handle.dispose();
14153
14788
  };
14154
14789
  }, [crossOrigin, id, sourcesKey, formatsKey]);
14155
- useEffect29(() => {
14790
+ useEffect30(() => {
14156
14791
  howl?.loop(loop ?? false);
14157
14792
  }, [howl, loop]);
14158
14793
  return howl;
@@ -14206,7 +14841,7 @@ function AudioHotspot({
14206
14841
  mutedRef.current = muted;
14207
14842
  volumeRef.current = volume;
14208
14843
  rangeRef.current = range;
14209
- useEffect29(() => {
14844
+ useEffect30(() => {
14210
14845
  if (!howl) {
14211
14846
  return;
14212
14847
  }
@@ -14216,7 +14851,7 @@ function AudioHotspot({
14216
14851
  }
14217
14852
  howl.play();
14218
14853
  }, [howl, playing]);
14219
- useEffect29(() => {
14854
+ useEffect30(() => {
14220
14855
  if (!howl || !pauseWhenHidden) {
14221
14856
  return;
14222
14857
  }
@@ -14247,11 +14882,11 @@ function AudioHotspot({
14247
14882
  howl.mute(mutedRef.current);
14248
14883
  howl.volume(clampAudioVolume(volumeRef.current) * spatial.gain);
14249
14884
  });
14250
- return /* @__PURE__ */ jsx32(HotspotAnchor, { ...anchorProps, id, height, width, children: marker ? /* @__PURE__ */ jsx32(HotspotPlane, { map: markerTexture, opacity }) : null });
14885
+ return /* @__PURE__ */ jsx33(HotspotAnchor, { ...anchorProps, id, height, width, children: marker ? /* @__PURE__ */ jsx33(HotspotPlane, { map: markerTexture, opacity }) : null });
14251
14886
  }
14252
14887
 
14253
14888
  // src/hotspot/text-hotspot.tsx
14254
- import { useEffect as useEffect30, useRef as useRef31, useState as useState19 } from "react";
14889
+ import { useEffect as useEffect31, useRef as useRef31, useState as useState20 } from "react";
14255
14890
  import { useFrame as useFrame19, useThree as useThree24 } from "@react-three/fiber";
14256
14891
  import {
14257
14892
  CanvasTexture as CanvasTexture3,
@@ -14261,7 +14896,7 @@ import {
14261
14896
  PerspectiveCamera as PerspectiveCamera9,
14262
14897
  SRGBColorSpace as SRGBColorSpace9
14263
14898
  } from "three";
14264
- import { jsx as jsx33 } from "react/jsx-runtime";
14899
+ import { jsx as jsx34 } from "react/jsx-runtime";
14265
14900
  var TEXT_TEXTURE_LONG_SIDE = 1024;
14266
14901
  var TEXT_RASTER_SUPERSAMPLE = 2;
14267
14902
  var TEXT_RASTER_MAX_LONG_SIDE = 4096;
@@ -14557,7 +15192,7 @@ function useRasterLongSide(width, height, scale, scaleMode, referenceFov) {
14557
15192
  Math.max(layout.canvasWidth, layout.canvasHeight)
14558
15193
  );
14559
15194
  };
14560
- const [rasterLong, setRasterLong] = useState19(measure);
15195
+ const [rasterLong, setRasterLong] = useState20(measure);
14561
15196
  const measured = measure();
14562
15197
  if (measured !== rasterLong) {
14563
15198
  setRasterLong(measured);
@@ -14570,12 +15205,12 @@ function useRasterLongSide(width, height, scale, scaleMode, referenceFov) {
14570
15205
  }
14571
15206
  function useTextTexture(text, width, height, style, scale, scaleMode, referenceFov, onLoad, onError) {
14572
15207
  const rasterLong = useRasterLongSide(width, height, scale, scaleMode, referenceFov);
14573
- const [texture, setTexture] = useState19(null);
15208
+ const [texture, setTexture] = useState20(null);
14574
15209
  const onLoadRef = useRef31(onLoad);
14575
15210
  const onErrorRef = useRef31(onError);
14576
15211
  onLoadRef.current = onLoad;
14577
15212
  onErrorRef.current = onError;
14578
- useEffect30(() => {
15213
+ useEffect31(() => {
14579
15214
  let cancelled = false;
14580
15215
  let nextTexture = null;
14581
15216
  const run = async () => {
@@ -14679,13 +15314,13 @@ function TextHotspot({
14679
15314
  onLoad,
14680
15315
  onError
14681
15316
  );
14682
- return /* @__PURE__ */ jsx33(HotspotAnchor, { ...anchorProps, height, width, children: /* @__PURE__ */ jsx33(HotspotPlane, { map: texture, opacity }) });
15317
+ return /* @__PURE__ */ jsx34(HotspotAnchor, { ...anchorProps, height, width, children: /* @__PURE__ */ jsx34(HotspotPlane, { map: texture, opacity }) });
14683
15318
  }
14684
15319
 
14685
15320
  // src/hotspot/iframe-hotspot.tsx
14686
15321
  import { Html } from "@react-three/drei";
14687
15322
  import { DoubleSide as DoubleSide4 } from "three";
14688
- import { jsx as jsx34, jsxs as jsxs17 } from "react/jsx-runtime";
15323
+ import { jsx as jsx35, jsxs as jsxs18 } from "react/jsx-runtime";
14689
15324
  var IFRAME_LONG_SIDE = 800;
14690
15325
  var CSS3D_DISTANCE_FACTOR = 400;
14691
15326
  var DEFAULT_SANDBOX = "allow-scripts allow-popups allow-forms";
@@ -14742,7 +15377,7 @@ function IframeHotspot({
14742
15377
  interactive,
14743
15378
  pointerEvents
14744
15379
  );
14745
- return /* @__PURE__ */ jsxs17(
15380
+ return /* @__PURE__ */ jsxs18(
14746
15381
  HotspotAnchor,
14747
15382
  {
14748
15383
  ...anchorProps,
@@ -14751,9 +15386,9 @@ function IframeHotspot({
14751
15386
  pointerEvents,
14752
15387
  width,
14753
15388
  children: [
14754
- /* @__PURE__ */ jsxs17("mesh", { children: [
14755
- /* @__PURE__ */ jsx34("planeGeometry", { args: [1, 1] }),
14756
- /* @__PURE__ */ jsx34(
15389
+ /* @__PURE__ */ jsxs18("mesh", { children: [
15390
+ /* @__PURE__ */ jsx35("planeGeometry", { args: [1, 1] }),
15391
+ /* @__PURE__ */ jsx35(
14757
15392
  "meshBasicMaterial",
14758
15393
  {
14759
15394
  depthWrite: false,
@@ -14764,7 +15399,7 @@ function IframeHotspot({
14764
15399
  }
14765
15400
  )
14766
15401
  ] }),
14767
- /* @__PURE__ */ jsx34(
15402
+ /* @__PURE__ */ jsx35(
14768
15403
  Html,
14769
15404
  {
14770
15405
  distanceFactor: CSS3D_DISTANCE_FACTOR,
@@ -14779,7 +15414,7 @@ function IframeHotspot({
14779
15414
  },
14780
15415
  transform: true,
14781
15416
  zIndexRange: [10, 0],
14782
- children: /* @__PURE__ */ jsx34(
15417
+ children: /* @__PURE__ */ jsx35(
14783
15418
  "iframe",
14784
15419
  {
14785
15420
  allow,
@@ -14801,7 +15436,7 @@ function IframeHotspot({
14801
15436
  }
14802
15437
 
14803
15438
  // src/hotspot/polygon-hotspot.tsx
14804
- import { useEffect as useEffect31, useMemo as useMemo20, useRef as useRef32 } from "react";
15439
+ import { useEffect as useEffect32, useMemo as useMemo20, useRef as useRef32 } from "react";
14805
15440
  import {
14806
15441
  BufferGeometry as BufferGeometry2,
14807
15442
  DoubleSide as DoubleSide5,
@@ -14812,7 +15447,7 @@ import {
14812
15447
  Vector2 as Vector26,
14813
15448
  Vector3 as Vector319
14814
15449
  } from "three";
14815
- import { jsx as jsx35, jsxs as jsxs18 } from "react/jsx-runtime";
15450
+ import { jsx as jsx36, jsxs as jsxs19 } from "react/jsx-runtime";
14816
15451
  var POLYGON_RADIUS = 990;
14817
15452
  var MAX_FILL_SEGMENT_DEGREES = 7;
14818
15453
  function cloneVertices(vertices) {
@@ -15082,10 +15717,10 @@ function PolygonHotspot({
15082
15717
  const resolvedStrokeOpacity = Math.max(0, Math.min(strokeOpacity, 1));
15083
15718
  const startVerticesRef = useRef32(null);
15084
15719
  const issuesKey = issues.map((issue) => issue.code).join(",");
15085
- useEffect31(() => {
15720
+ useEffect32(() => {
15086
15721
  if (!valid) onInvalid?.(issues);
15087
15722
  }, [issues, issuesKey, onInvalid, valid]);
15088
- useEffect31(() => () => fillGeometry?.dispose(), [fillGeometry]);
15723
+ useEffect32(() => () => fillGeometry?.dispose(), [fillGeometry]);
15089
15724
  if (!valid || !center || !fillGeometry || !strokePoints || strokePoints.length < 2) {
15090
15725
  return null;
15091
15726
  }
@@ -15100,7 +15735,7 @@ function PolygonHotspot({
15100
15735
  startPosition: event.startPosition
15101
15736
  });
15102
15737
  };
15103
- return /* @__PURE__ */ jsxs18(
15738
+ return /* @__PURE__ */ jsxs19(
15104
15739
  HotspotAnchor,
15105
15740
  {
15106
15741
  ...anchorProps,
@@ -15115,7 +15750,7 @@ function PolygonHotspot({
15115
15750
  draggable,
15116
15751
  interactive,
15117
15752
  useAngularScale: false,
15118
- focusContent: /* @__PURE__ */ jsx35(
15753
+ focusContent: /* @__PURE__ */ jsx36(
15119
15754
  HotspotStrokeLine,
15120
15755
  {
15121
15756
  color: "#75cbd3",
@@ -15137,7 +15772,7 @@ function PolygonHotspot({
15137
15772
  startVerticesRef.current = null;
15138
15773
  },
15139
15774
  children: [
15140
- /* @__PURE__ */ jsx35("mesh", { geometry: fillGeometry, renderOrder, children: /* @__PURE__ */ jsx35(
15775
+ /* @__PURE__ */ jsx36("mesh", { geometry: fillGeometry, renderOrder, children: /* @__PURE__ */ jsx36(
15141
15776
  "meshBasicMaterial",
15142
15777
  {
15143
15778
  color: fill,
@@ -15147,7 +15782,7 @@ function PolygonHotspot({
15147
15782
  transparent: true
15148
15783
  }
15149
15784
  ) }),
15150
- /* @__PURE__ */ jsx35(
15785
+ /* @__PURE__ */ jsx36(
15151
15786
  HotspotStrokeLine,
15152
15787
  {
15153
15788
  color: stroke,
@@ -15165,14 +15800,14 @@ function PolygonHotspot({
15165
15800
  }
15166
15801
 
15167
15802
  // src/hotspot/polyline-hotspot.tsx
15168
- import { useEffect as useEffect32, useMemo as useMemo21, useRef as useRef33 } from "react";
15803
+ import { useEffect as useEffect33, useMemo as useMemo21, useRef as useRef33 } from "react";
15169
15804
  import {
15170
15805
  MathUtils as MathUtils12,
15171
15806
  Matrix4 as Matrix46,
15172
15807
  Quaternion as Quaternion6,
15173
15808
  Vector3 as Vector320
15174
15809
  } from "three";
15175
- import { jsx as jsx36 } from "react/jsx-runtime";
15810
+ import { jsx as jsx37 } from "react/jsx-runtime";
15176
15811
  var POLYLINE_RADIUS = 990;
15177
15812
  var MAX_SEGMENT_DEGREES = 7;
15178
15813
  function cloneVertices2(vertices) {
@@ -15298,7 +15933,7 @@ function PolylineHotspot({
15298
15933
  );
15299
15934
  const opacity = Math.max(0, Math.min(strokeOpacity, 1));
15300
15935
  const startVerticesRef = useRef33(null);
15301
- useEffect32(() => {
15936
+ useEffect33(() => {
15302
15937
  if (!valid) onInvalid?.(issues);
15303
15938
  }, [issues, onInvalid, valid]);
15304
15939
  if (!valid || !center || !linePoints || linePoints.length < 2) return null;
@@ -15312,7 +15947,7 @@ function PolylineHotspot({
15312
15947
  startPosition: event.startPosition
15313
15948
  });
15314
15949
  };
15315
- return /* @__PURE__ */ jsx36(
15950
+ return /* @__PURE__ */ jsx37(
15316
15951
  HotspotAnchor,
15317
15952
  {
15318
15953
  ...anchorProps,
@@ -15326,7 +15961,7 @@ function PolylineHotspot({
15326
15961
  renderOrder,
15327
15962
  draggable,
15328
15963
  useAngularScale: false,
15329
- focusContent: /* @__PURE__ */ jsx36(
15964
+ focusContent: /* @__PURE__ */ jsx37(
15330
15965
  HotspotStrokeLine,
15331
15966
  {
15332
15967
  color: "#75cbd3",
@@ -15347,7 +15982,7 @@ function PolylineHotspot({
15347
15982
  emitVerticesChange(event, onDragEnd);
15348
15983
  startVerticesRef.current = null;
15349
15984
  },
15350
- children: /* @__PURE__ */ jsx36(
15985
+ children: /* @__PURE__ */ jsx37(
15351
15986
  HotspotStrokeLine,
15352
15987
  {
15353
15988
  color: stroke,
@@ -15364,7 +15999,7 @@ function PolylineHotspot({
15364
15999
  }
15365
16000
 
15366
16001
  // src/project-scenes.tsx
15367
- import { jsx as jsx37 } from "react/jsx-runtime";
16002
+ import { jsx as jsx38 } from "react/jsx-runtime";
15368
16003
  function isMedia(hotspot) {
15369
16004
  return hotspot.type === "audio" || hotspot.type === "video" || hotspot.type === "sequence";
15370
16005
  }
@@ -15411,7 +16046,7 @@ function ProjectHotspotSource({
15411
16046
  const common = { ariaLabel: hotspot.label || hotspot.id, onClick, onHoverChange };
15412
16047
  switch (hotspot.type) {
15413
16048
  case "image":
15414
- return /* @__PURE__ */ jsx37(
16049
+ return /* @__PURE__ */ jsx38(
15415
16050
  ImageHotspot,
15416
16051
  {
15417
16052
  ...hotspotProps(hotspot),
@@ -15420,7 +16055,7 @@ function ProjectHotspotSource({
15420
16055
  }
15421
16056
  );
15422
16057
  case "graphic":
15423
- return /* @__PURE__ */ jsx37(
16058
+ return /* @__PURE__ */ jsx38(
15424
16059
  GraphicHotspot,
15425
16060
  {
15426
16061
  ...hotspotProps(hotspot),
@@ -15429,9 +16064,9 @@ function ProjectHotspotSource({
15429
16064
  }
15430
16065
  );
15431
16066
  case "text":
15432
- return /* @__PURE__ */ jsx37(TextHotspot, { ...hotspotProps(hotspot), ...common, onError });
16067
+ return /* @__PURE__ */ jsx38(TextHotspot, { ...hotspotProps(hotspot), ...common, onError });
15433
16068
  case "iframe":
15434
- return /* @__PURE__ */ jsx37(
16069
+ return /* @__PURE__ */ jsx38(
15435
16070
  IframeHotspot,
15436
16071
  {
15437
16072
  ...hotspotProps(hotspot),
@@ -15441,11 +16076,11 @@ function ProjectHotspotSource({
15441
16076
  }
15442
16077
  );
15443
16078
  case "polygon":
15444
- return /* @__PURE__ */ jsx37(PolygonHotspot, { ...hotspotProps(hotspot), ...common });
16079
+ return /* @__PURE__ */ jsx38(PolygonHotspot, { ...hotspotProps(hotspot), ...common });
15445
16080
  case "polyline":
15446
- return /* @__PURE__ */ jsx37(PolylineHotspot, { ...hotspotProps(hotspot), ...common });
16081
+ return /* @__PURE__ */ jsx38(PolylineHotspot, { ...hotspotProps(hotspot), ...common });
15447
16082
  case "sequence":
15448
- return /* @__PURE__ */ jsx37(
16083
+ return /* @__PURE__ */ jsx38(
15449
16084
  SequenceHotspot,
15450
16085
  {
15451
16086
  ...hotspotProps(hotspot),
@@ -15456,7 +16091,7 @@ function ProjectHotspotSource({
15456
16091
  }
15457
16092
  );
15458
16093
  case "video":
15459
- return /* @__PURE__ */ jsx37(
16094
+ return /* @__PURE__ */ jsx38(
15460
16095
  VideoHotspot,
15461
16096
  {
15462
16097
  ...hotspotProps(hotspot),
@@ -15468,7 +16103,7 @@ function ProjectHotspotSource({
15468
16103
  }
15469
16104
  );
15470
16105
  case "audio":
15471
- return /* @__PURE__ */ jsx37(
16106
+ return /* @__PURE__ */ jsx38(
15472
16107
  AudioHotspot,
15473
16108
  {
15474
16109
  ...hotspotProps(hotspot),
@@ -15491,7 +16126,7 @@ function ProjectHotspot({
15491
16126
  renderHotspot,
15492
16127
  execute
15493
16128
  }) {
15494
- const [playing, setPlaying] = useState20(
16129
+ const [playing, setPlaying] = useState21(
15495
16130
  "playing" in hotspot ? hotspot.playing ?? false : false
15496
16131
  );
15497
16132
  const togglePlayback = () => setPlaying((value) => !value);
@@ -15512,7 +16147,7 @@ function ProjectHotspot({
15512
16147
  };
15513
16148
  const onClick = (event) => dispatch("click", event);
15514
16149
  const onHoverChange = (hovered, event) => dispatch(hovered ? "pointerenter" : "pointerleave", event);
15515
- const renderDefault = () => /* @__PURE__ */ jsx37(
16150
+ const renderDefault = () => /* @__PURE__ */ jsx38(
15516
16151
  ProjectHotspotSource,
15517
16152
  {
15518
16153
  hotspot,
@@ -15550,7 +16185,7 @@ function ProjectScenes({
15550
16185
  const controls = useContext22(PanoramaViewContext);
15551
16186
  if (!controls)
15552
16187
  throw new Error("<ProjectScenes> must be rendered inside <PanoViewer>.");
15553
- const [selection, setSelection] = useState20({
16188
+ const [selection, setSelection] = useState21({
15554
16189
  project,
15555
16190
  id: project.initialSceneId
15556
16191
  });
@@ -15570,7 +16205,7 @@ function ProjectScenes({
15570
16205
  if (activeSceneId === void 0) setSelection({ project, id });
15571
16206
  onActiveSceneIdChange?.(id);
15572
16207
  };
15573
- return /* @__PURE__ */ jsx37(
16208
+ return /* @__PURE__ */ jsx38(
15574
16209
  Scenes,
15575
16210
  {
15576
16211
  ...options,
@@ -15582,7 +16217,7 @@ function ProjectScenes({
15582
16217
  if (view) controls.current?.setView(view, { immediate: true });
15583
16218
  onSceneReady?.(id);
15584
16219
  },
15585
- renderHotspots: (scene) => entries.get(scene.id)?.hotspots.map((hotspot) => /* @__PURE__ */ jsx37(
16220
+ renderHotspots: (scene) => entries.get(scene.id)?.hotspots.map((hotspot) => /* @__PURE__ */ jsx38(
15586
16221
  ProjectHotspot,
15587
16222
  {
15588
16223
  hotspot,
@@ -15614,7 +16249,7 @@ function ProjectScenes({
15614
16249
  }
15615
16250
 
15616
16251
  // src/background-audio.tsx
15617
- import { useContext as useContext23, useEffect as useEffect33, useMemo as useMemo23, useRef as useRef34, useState as useState21 } from "react";
16252
+ import { useContext as useContext23, useEffect as useEffect34, useMemo as useMemo23, useRef as useRef34, useState as useState22 } from "react";
15618
16253
  var DEFAULT_FADE_MS = 400;
15619
16254
  function resolveFadeMs(value) {
15620
16255
  if (!Number.isFinite(value)) {
@@ -15661,7 +16296,7 @@ function BackgroundAudio({
15661
16296
  throw new Error("<BackgroundAudio> must be rendered inside <PanoViewer>.");
15662
16297
  }
15663
16298
  const isControlled = controlledPlaying !== void 0;
15664
- const [internalPlaying, setInternalPlaying] = useState21(defaultPlaying);
16299
+ const [internalPlaying, setInternalPlaying] = useState22(defaultPlaying);
15665
16300
  const playing = isControlled ? controlledPlaying : internalPlaying;
15666
16301
  const urls = resolveBackgroundAudioUrls(src, sources, sceneId);
15667
16302
  usePanoMediaActivationIntent(playing && urls.length > 0);
@@ -15773,7 +16408,7 @@ function BackgroundAudio({
15773
16408
  []
15774
16409
  );
15775
16410
  const bgmHost = useContext23(BackgroundAudioHostContext);
15776
- useEffect33(() => {
16411
+ useEffect34(() => {
15777
16412
  if (!bgmHost) {
15778
16413
  return;
15779
16414
  }
@@ -15786,7 +16421,7 @@ function BackgroundAudio({
15786
16421
  }
15787
16422
  };
15788
16423
  }, [bgmHost, controller]);
15789
- useEffect33(() => {
16424
+ useEffect34(() => {
15790
16425
  return () => {
15791
16426
  fadingInRef.current = false;
15792
16427
  isFirstTrackRef.current = true;
@@ -15798,7 +16433,7 @@ function BackgroundAudio({
15798
16433
  outgoingRef.current = [];
15799
16434
  };
15800
16435
  }, []);
15801
- useEffect33(() => {
16436
+ useEffect34(() => {
15802
16437
  const previous = currentRef.current;
15803
16438
  if (previous?.key === trackKey && previous.crossOrigin === crossOrigin) {
15804
16439
  return;
@@ -15901,7 +16536,7 @@ function BackgroundAudio({
15901
16536
  retire(previous);
15902
16537
  }
15903
16538
  }, [crossOrigin, trackKey]);
15904
- useEffect33(() => {
16539
+ useEffect34(() => {
15905
16540
  const howl = currentRef.current?.handle.howl;
15906
16541
  if (!howl) {
15907
16542
  return;
@@ -15921,7 +16556,7 @@ function BackgroundAudio({
15921
16556
  howl.play();
15922
16557
  }
15923
16558
  }, [playing, trackKey]);
15924
- useEffect33(() => {
16559
+ useEffect34(() => {
15925
16560
  const slot = currentRef.current;
15926
16561
  if (!slot) {
15927
16562
  return;
@@ -15936,7 +16571,7 @@ function BackgroundAudio({
15936
16571
  volume: clampAudioVolume(volumeRef.current)
15937
16572
  });
15938
16573
  }, [loop, muted, trackKey, volume]);
15939
- useEffect33(() => {
16574
+ useEffect34(() => {
15940
16575
  if (!pauseWhenHidden) {
15941
16576
  return;
15942
16577
  }
@@ -15962,7 +16597,7 @@ function BackgroundAudio({
15962
16597
  }
15963
16598
 
15964
16599
  // src/pano-filter/pano-filter.tsx
15965
- import { useContext as useContext24, useEffect as useEffect34, useMemo as useMemo24 } from "react";
16600
+ import { useContext as useContext24, useEffect as useEffect35, useMemo as useMemo24 } from "react";
15966
16601
  function PanoFilter({
15967
16602
  preset = "none",
15968
16603
  intensity,
@@ -15984,13 +16619,13 @@ function PanoFilter({
15984
16619
  }),
15985
16620
  [enabled, intensity, preset, colorMatrix, colorMatrixScope]
15986
16621
  );
15987
- useEffect34(() => {
16622
+ useEffect35(() => {
15988
16623
  claimPanoFilter(host);
15989
16624
  return () => {
15990
16625
  releasePanoFilter(host);
15991
16626
  };
15992
16627
  }, [host]);
15993
- useEffect34(() => {
16628
+ useEffect35(() => {
15994
16629
  setPanoFilterSnapshot(host, snapshot);
15995
16630
  }, [host, snapshot]);
15996
16631
  return null;
@@ -16002,10 +16637,10 @@ import {
16002
16637
  forwardRef as forwardRef3,
16003
16638
  useCallback as useCallback9,
16004
16639
  useContext as useContext25,
16005
- useEffect as useEffect35,
16640
+ useEffect as useEffect36,
16006
16641
  useImperativeHandle as useImperativeHandle3,
16007
16642
  useRef as useRef35,
16008
- useState as useState22
16643
+ useState as useState23
16009
16644
  } from "react";
16010
16645
  import { Quaternion as Quaternion7 } from "three";
16011
16646
  var deviceOrientationPermissionState = "unknown";
@@ -16042,8 +16677,8 @@ var Gyro = forwardRef3(function Gyro2({
16042
16677
  const controlsRef = useContext25(PanoramaViewContext);
16043
16678
  const eventBus = useContext25(PanoEventBusContext);
16044
16679
  const { gl } = useThree25();
16045
- const [internallyDisabled, setInternallyDisabled] = useState22(false);
16046
- const [available, setAvailableState] = useState22(false);
16680
+ const [internallyDisabled, setInternallyDisabled] = useState23(false);
16681
+ const [available, setAvailableState] = useState23(false);
16047
16682
  const availableRef = useRef35(false);
16048
16683
  const availabilityReportedRef = useRef35(null);
16049
16684
  const activeRef = useRef35(false);
@@ -16232,19 +16867,19 @@ var Gyro = forwardRef3(function Gyro2({
16232
16867
  }),
16233
16868
  [requestPermission, resetSensor]
16234
16869
  );
16235
- useEffect35(() => {
16870
+ useEffect36(() => {
16236
16871
  if (!enabled) {
16237
16872
  setInternallyDisabled(false);
16238
16873
  }
16239
16874
  }, [enabled]);
16240
- useEffect35(() => {
16875
+ useEffect36(() => {
16241
16876
  const supported = typeof window !== "undefined" && window.isSecureContext && typeof DeviceOrientationEvent !== "undefined" && (desktopSupport || isMobileDevice());
16242
16877
  setAvailable(supported);
16243
16878
  }, [desktopSupport, setAvailable]);
16244
- useEffect35(() => {
16879
+ useEffect36(() => {
16245
16880
  controlsRef.current?.setGyroTouchMode(touchMode);
16246
16881
  }, [controlsRef, touchMode]);
16247
- useEffect35(() => {
16882
+ useEffect36(() => {
16248
16883
  if (!enabled || internallyDisabled || touchMode !== "disablegyro") {
16249
16884
  return;
16250
16885
  }
@@ -16258,7 +16893,7 @@ var Gyro = forwardRef3(function Gyro2({
16258
16893
  gl.domElement.removeEventListener("pointerdown", onPointerDown);
16259
16894
  };
16260
16895
  }, [enabled, gl, internallyDisabled, touchMode]);
16261
- useEffect35(() => {
16896
+ useEffect36(() => {
16262
16897
  if (!enabled || internallyDisabled || !available) {
16263
16898
  deactivate();
16264
16899
  return;
@@ -16485,11 +17120,11 @@ import {
16485
17120
  forwardRef as forwardRef4,
16486
17121
  useCallback as useCallback10,
16487
17122
  useContext as useContext27,
16488
- useEffect as useEffect39,
17123
+ useEffect as useEffect40,
16489
17124
  useImperativeHandle as useImperativeHandle4,
16490
17125
  useMemo as useMemo26,
16491
17126
  useRef as useRef39,
16492
- useState as useState23
17127
+ useState as useState24
16493
17128
  } from "react";
16494
17129
 
16495
17130
  // src/webvr/detect.ts
@@ -16511,6 +17146,161 @@ async function detectWebVRCapabilities() {
16511
17146
  return { webxr, mobile, sensor };
16512
17147
  }
16513
17148
 
17149
+ // src/webvr/presentation.ts
17150
+ var PRESENTATION_PROPERTIES = [
17151
+ "background",
17152
+ "height",
17153
+ "inset",
17154
+ "left",
17155
+ "position",
17156
+ "top",
17157
+ "width",
17158
+ "z-index"
17159
+ ];
17160
+ var PRESENTATION_STYLE = {
17161
+ background: "#000",
17162
+ height: "100dvh",
17163
+ inset: "0",
17164
+ left: "0",
17165
+ position: "fixed",
17166
+ top: "0",
17167
+ width: "100%",
17168
+ "z-index": "2147483000"
17169
+ };
17170
+ var SCROLL_LOCK_OVERFLOW = "hidden";
17171
+ var activePresentation = null;
17172
+ var iphonePresentationElement = null;
17173
+ function capturePresentationStyle(element) {
17174
+ const snapshot = {};
17175
+ for (const property of PRESENTATION_PROPERTIES) {
17176
+ snapshot[property] = element.style.getPropertyValue(property);
17177
+ }
17178
+ return snapshot;
17179
+ }
17180
+ function applyPresentationStyle(element) {
17181
+ for (const property of PRESENTATION_PROPERTIES) {
17182
+ element.style.setProperty(property, PRESENTATION_STYLE[property]);
17183
+ }
17184
+ }
17185
+ function restorePresentationStyle(element, snapshot) {
17186
+ for (const property of PRESENTATION_PROPERTIES) {
17187
+ const previous = snapshot[property];
17188
+ if (previous) {
17189
+ element.style.setProperty(property, previous);
17190
+ } else {
17191
+ element.style.removeProperty(property);
17192
+ }
17193
+ }
17194
+ }
17195
+ function lockScroll() {
17196
+ const documentElement = document.documentElement;
17197
+ const body = document.body;
17198
+ const snapshot = {
17199
+ bodyOverflow: body.style.overflow,
17200
+ documentOverflow: documentElement.style.overflow
17201
+ };
17202
+ documentElement.style.overflow = SCROLL_LOCK_OVERFLOW;
17203
+ body.style.overflow = SCROLL_LOCK_OVERFLOW;
17204
+ return snapshot;
17205
+ }
17206
+ function unlockScroll(snapshot) {
17207
+ document.documentElement.style.overflow = snapshot.documentOverflow;
17208
+ document.body.style.overflow = snapshot.bodyOverflow;
17209
+ }
17210
+ async function tryLockLandscape() {
17211
+ const orientation2 = window.screen?.orientation;
17212
+ if (typeof orientation2?.lock !== "function") {
17213
+ return;
17214
+ }
17215
+ try {
17216
+ await orientation2.lock("landscape");
17217
+ } catch {
17218
+ }
17219
+ }
17220
+ function tryUnlockOrientation() {
17221
+ const orientation2 = window.screen?.orientation;
17222
+ if (typeof orientation2?.unlock !== "function") {
17223
+ return;
17224
+ }
17225
+ try {
17226
+ orientation2.unlock();
17227
+ } catch {
17228
+ }
17229
+ }
17230
+ async function enterWebVRPresentation(element) {
17231
+ if (!(element instanceof HTMLElement)) {
17232
+ return;
17233
+ }
17234
+ if (supportsIphoneLandscapeFullscreen()) {
17235
+ if (iphonePresentationElement && iphonePresentationElement !== element) {
17236
+ releaseIphoneLandscapeFullscreen(iphonePresentationElement, "vr");
17237
+ }
17238
+ iphonePresentationElement = element;
17239
+ acquireIphoneLandscapeFullscreen(element, "vr");
17240
+ void tryLockLandscape();
17241
+ return;
17242
+ }
17243
+ if (activePresentation?.element === element) {
17244
+ void requestElementFullscreen(element).catch(() => {
17245
+ });
17246
+ void tryLockLandscape();
17247
+ return;
17248
+ }
17249
+ if (activePresentation) {
17250
+ leaveWebVRPresentation();
17251
+ }
17252
+ activePresentation = {
17253
+ element,
17254
+ style: capturePresentationStyle(element),
17255
+ scroll: lockScroll()
17256
+ };
17257
+ applyPresentationStyle(element);
17258
+ try {
17259
+ await requestElementFullscreen(element);
17260
+ } catch {
17261
+ }
17262
+ void tryLockLandscape();
17263
+ }
17264
+ function leaveWebVRPresentation() {
17265
+ if (iphonePresentationElement) {
17266
+ const element = iphonePresentationElement;
17267
+ iphonePresentationElement = null;
17268
+ releaseIphoneLandscapeFullscreen(element, "vr");
17269
+ tryUnlockOrientation();
17270
+ }
17271
+ const presentation = activePresentation;
17272
+ if (!presentation) {
17273
+ if (getFullscreenElement()) {
17274
+ void exitElementFullscreen();
17275
+ }
17276
+ return;
17277
+ }
17278
+ activePresentation = null;
17279
+ restorePresentationStyle(presentation.element, presentation.style);
17280
+ unlockScroll(presentation.scroll);
17281
+ tryUnlockOrientation();
17282
+ const fullscreen = getFullscreenElement();
17283
+ if (fullscreen && (fullscreen === presentation.element || presentation.element.contains(fullscreen))) {
17284
+ void exitElementFullscreen();
17285
+ }
17286
+ }
17287
+ function subscribeWebVRPresentationExit(element, onExit) {
17288
+ if (!(element instanceof HTMLElement)) {
17289
+ return () => {
17290
+ };
17291
+ }
17292
+ return subscribeFullscreenChange(() => {
17293
+ const fullscreen = getFullscreenElement();
17294
+ if (fullscreen) {
17295
+ return;
17296
+ }
17297
+ if (activePresentation?.element !== element) {
17298
+ return;
17299
+ }
17300
+ onExit();
17301
+ });
17302
+ }
17303
+
16514
17304
  // src/webvr/reticle.tsx
16515
17305
  import { useFrame as useFrame21, useThree as useThree26 } from "@react-three/fiber";
16516
17306
  import { useRef as useRef36 } from "react";
@@ -16520,10 +17310,11 @@ import {
16520
17310
  Vector2 as Vector27,
16521
17311
  Vector3 as Vector321
16522
17312
  } from "three";
16523
- import { jsx as jsx38, jsxs as jsxs19 } from "react/jsx-runtime";
17313
+ import { jsx as jsx39, jsxs as jsxs20 } from "react/jsx-runtime";
16524
17314
  var CENTER_NDC = new Vector27(0, 0);
16525
17315
  var HUD_DISTANCE = 2;
16526
17316
  var RETICLE_SCALE = 1;
17317
+ var MOBILE_VR_RETICLE_SCALE = 3;
16527
17318
  var RETICLE_RENDER_ORDER = 1e5;
16528
17319
  var CROSSHAIR_LENGTH = 0.044;
16529
17320
  var CROSSHAIR_THICKNESS = 8e-3;
@@ -16602,6 +17393,7 @@ function resolveDwellMs(value) {
16602
17393
  }
16603
17394
  function WebVRReticle({
16604
17395
  dwellMs,
17396
+ scale = RETICLE_SCALE,
16605
17397
  visible
16606
17398
  }) {
16607
17399
  const groupRef = useRef36(null);
@@ -16678,9 +17470,9 @@ function WebVRReticle({
16678
17470
  }
16679
17471
  group.position.copy(activeCamera.position).addScaledVector(directionRef.current, HUD_DISTANCE);
16680
17472
  group.quaternion.copy(activeCamera.quaternion);
16681
- group.scale.setScalar(RETICLE_SCALE);
17473
+ group.scale.setScalar(scale);
16682
17474
  });
16683
- return /* @__PURE__ */ jsxs19(
17475
+ return /* @__PURE__ */ jsxs20(
16684
17476
  "group",
16685
17477
  {
16686
17478
  frustumCulled: false,
@@ -16688,15 +17480,15 @@ function WebVRReticle({
16688
17480
  renderOrder: RETICLE_RENDER_ORDER,
16689
17481
  visible,
16690
17482
  children: [
16691
- /* @__PURE__ */ jsxs19(
17483
+ /* @__PURE__ */ jsxs20(
16692
17484
  "mesh",
16693
17485
  {
16694
17486
  frustumCulled: false,
16695
17487
  raycast: noopRaycast,
16696
17488
  renderOrder: RETICLE_RENDER_ORDER + 1,
16697
17489
  children: [
16698
- /* @__PURE__ */ jsx38("boxGeometry", { args: [CROSSHAIR_LENGTH, CROSSHAIR_THICKNESS, 1e-3] }),
16699
- /* @__PURE__ */ jsx38(
17490
+ /* @__PURE__ */ jsx39("boxGeometry", { args: [CROSSHAIR_LENGTH, CROSSHAIR_THICKNESS, 1e-3] }),
17491
+ /* @__PURE__ */ jsx39(
16700
17492
  "meshBasicMaterial",
16701
17493
  {
16702
17494
  color: "#ffffff",
@@ -16709,15 +17501,15 @@ function WebVRReticle({
16709
17501
  ]
16710
17502
  }
16711
17503
  ),
16712
- /* @__PURE__ */ jsxs19(
17504
+ /* @__PURE__ */ jsxs20(
16713
17505
  "mesh",
16714
17506
  {
16715
17507
  frustumCulled: false,
16716
17508
  raycast: noopRaycast,
16717
17509
  renderOrder: RETICLE_RENDER_ORDER + 1,
16718
17510
  children: [
16719
- /* @__PURE__ */ jsx38("boxGeometry", { args: [CROSSHAIR_THICKNESS, CROSSHAIR_LENGTH, 1e-3] }),
16720
- /* @__PURE__ */ jsx38(
17511
+ /* @__PURE__ */ jsx39("boxGeometry", { args: [CROSSHAIR_THICKNESS, CROSSHAIR_LENGTH, 1e-3] }),
17512
+ /* @__PURE__ */ jsx39(
16721
17513
  "meshBasicMaterial",
16722
17514
  {
16723
17515
  color: "#ffffff",
@@ -16730,7 +17522,7 @@ function WebVRReticle({
16730
17522
  ]
16731
17523
  }
16732
17524
  ),
16733
- /* @__PURE__ */ jsxs19(
17525
+ /* @__PURE__ */ jsxs20(
16734
17526
  "mesh",
16735
17527
  {
16736
17528
  frustumCulled: false,
@@ -16739,7 +17531,7 @@ function WebVRReticle({
16739
17531
  renderOrder: RETICLE_RENDER_ORDER + 2,
16740
17532
  visible: false,
16741
17533
  children: [
16742
- /* @__PURE__ */ jsx38(
17534
+ /* @__PURE__ */ jsx39(
16743
17535
  "ringGeometry",
16744
17536
  {
16745
17537
  args: [
@@ -16752,7 +17544,7 @@ function WebVRReticle({
16752
17544
  ]
16753
17545
  }
16754
17546
  ),
16755
- /* @__PURE__ */ jsx38(
17547
+ /* @__PURE__ */ jsx39(
16756
17548
  "meshBasicMaterial",
16757
17549
  {
16758
17550
  color: "#ffffff",
@@ -16773,8 +17565,9 @@ function WebVRReticle({
16773
17565
 
16774
17566
  // src/webvr/stereo.tsx
16775
17567
  import { useFrame as useFrame22, useThree as useThree27 } from "@react-three/fiber";
16776
- import { useContext as useContext26, useEffect as useEffect36, useMemo as useMemo25, useRef as useRef37 } from "react";
17568
+ import { useContext as useContext26, useEffect as useEffect37, useMemo as useMemo25, useRef as useRef37 } from "react";
16777
17569
  import {
17570
+ Matrix4 as Matrix47,
16778
17571
  Mesh as Mesh6,
16779
17572
  OrthographicCamera,
16780
17573
  PerspectiveCamera as PerspectiveCamera10,
@@ -16786,6 +17579,41 @@ import {
16786
17579
  Vector4 as Vector42,
16787
17580
  WebGLRenderTarget as WebGLRenderTarget2
16788
17581
  } from "three";
17582
+
17583
+ // src/webvr/stereo-disparity.ts
17584
+ var WEBVR_PANORAMA_VIRTUAL_DISTANCE_M = 2;
17585
+ function panoramaStereoHalfAngle(ipdMm, virtualDistanceM = WEBVR_PANORAMA_VIRTUAL_DISTANCE_M) {
17586
+ const ipdM = Math.max(0, ipdMm) / 1e3;
17587
+ const distance = Math.max(
17588
+ Number.isFinite(virtualDistanceM) ? virtualDistanceM : WEBVR_PANORAMA_VIRTUAL_DISTANCE_M,
17589
+ 0.05
17590
+ );
17591
+ return Math.atan(ipdM / 2 / distance);
17592
+ }
17593
+ function panoramaStereoToeInYaw(eye, halfAngleRad) {
17594
+ return eye === "left" ? -halfAngleRad : halfAngleRad;
17595
+ }
17596
+
17597
+ // src/webvr/stereo-layout.ts
17598
+ function computeStereoLayout(logicalWidth, logicalHeight, pixelRatio) {
17599
+ const fullWidth = Math.max(2, Math.floor(logicalWidth));
17600
+ const fullHeight = Math.max(1, Math.floor(logicalHeight));
17601
+ const leftWidth = Math.max(1, Math.floor(fullWidth / 2));
17602
+ const rightWidth = Math.max(1, fullWidth - leftWidth);
17603
+ const ratio = Number.isFinite(pixelRatio) && pixelRatio > 0 ? pixelRatio : 1;
17604
+ return {
17605
+ fullWidth,
17606
+ fullHeight,
17607
+ left: { width: leftWidth, height: fullHeight, offsetX: 0 },
17608
+ right: { width: rightWidth, height: fullHeight, offsetX: leftWidth },
17609
+ renderTargetWidth: Math.max(1, Math.floor(leftWidth * ratio)),
17610
+ renderTargetHeight: Math.max(1, Math.floor(fullHeight * ratio)),
17611
+ stereoAspect: leftWidth / fullWidth
17612
+ };
17613
+ }
17614
+
17615
+ // src/webvr/stereo.tsx
17616
+ var TOE_IN = new Matrix47();
16789
17617
  var vertexShader = `
16790
17618
  varying vec2 vUv;
16791
17619
  void main() {
@@ -16837,21 +17665,33 @@ function createDistortionResources() {
16837
17665
  target
16838
17666
  };
16839
17667
  }
16840
- function syncStereoCameras(stereo, camera, profile, screensize, drawingSize, gl) {
16841
- gl.getDrawingBufferSize(drawingSize);
16842
- const fullWidth = Math.max(2, Math.floor(drawingSize.x));
16843
- const fullHeight = Math.max(1, Math.floor(drawingSize.y));
16844
- const eyeWidth = Math.max(1, Math.floor(fullWidth / 2));
17668
+ function syncStereoCameras(stereo, camera, profile, screensize, size, gl) {
17669
+ gl.getSize(size);
17670
+ const layout = computeStereoLayout(
17671
+ size.x,
17672
+ size.y,
17673
+ gl.getPixelRatio()
17674
+ );
16845
17675
  const screenToLensMm = profile.screenToLensMm ?? 42;
16846
- const displayAspect = fullWidth / fullHeight;
17676
+ const displayAspect = layout.fullWidth / layout.fullHeight;
16847
17677
  const screenHeightMm = screensize === "auto" ? null : screensize * 25.4 / Math.sqrt(displayAspect * displayAspect + 1);
16848
17678
  const calibratedFov = screenHeightMm === null ? profile.fov : 2 * Math.atan(screenHeightMm / (2 * screenToLensMm)) * 180 / Math.PI;
16849
17679
  camera.fov = Math.max(30, Math.min(140, calibratedFov));
16850
17680
  camera.updateProjectionMatrix();
16851
- stereo.aspect = eyeWidth / fullWidth;
16852
- stereo.eyeSep = profile.ipdMm / 1e3;
17681
+ camera.updateMatrixWorld();
17682
+ stereo.aspect = layout.stereoAspect;
17683
+ stereo.eyeSep = 0;
16853
17684
  stereo.update(camera);
16854
- return { eyeWidth, fullHeight };
17685
+ const halfAngle = panoramaStereoHalfAngle(profile.ipdMm);
17686
+ TOE_IN.makeRotationY(panoramaStereoToeInYaw("left", halfAngle));
17687
+ stereo.cameraL.matrix.multiply(TOE_IN);
17688
+ stereo.cameraL.matrixWorldNeedsUpdate = true;
17689
+ TOE_IN.makeRotationY(panoramaStereoToeInYaw("right", halfAngle));
17690
+ stereo.cameraR.matrix.multiply(TOE_IN);
17691
+ stereo.cameraR.matrixWorldNeedsUpdate = true;
17692
+ stereo.cameraL.updateMatrixWorld(true);
17693
+ stereo.cameraR.updateMatrixWorld(true);
17694
+ return layout;
16855
17695
  }
16856
17696
  function WebVRStereoRenderer({
16857
17697
  mode,
@@ -16868,7 +17708,7 @@ function WebVRStereoRenderer({
16868
17708
  const stereoRef = useRef37(stereo);
16869
17709
  stereoRef.current = stereo;
16870
17710
  const resources = useMemo25(createDistortionResources, []);
16871
- const drawingSizeRef = useRef37(new Vector28());
17711
+ const sizeRef = useRef37(new Vector28());
16872
17712
  const viewportRef = useRef37(new Vector42());
16873
17713
  const scissorRef = useRef37(new Vector42());
16874
17714
  const originalFovRef = useRef37(null);
@@ -16877,7 +17717,7 @@ function WebVRStereoRenderer({
16877
17717
  const screensizeRef = useRef37(screensize);
16878
17718
  profileRef.current = profile;
16879
17719
  screensizeRef.current = screensize;
16880
- useEffect36(
17720
+ useEffect37(
16881
17721
  () => () => {
16882
17722
  resources.geometry.dispose();
16883
17723
  resources.material.dispose();
@@ -16885,7 +17725,7 @@ function WebVRStereoRenderer({
16885
17725
  },
16886
17726
  [resources]
16887
17727
  );
16888
- useEffect36(() => {
17728
+ useEffect37(() => {
16889
17729
  const originalRender = gl.render.bind(gl);
16890
17730
  gl.render = (sceneToRender, cameraToRender) => {
16891
17731
  if (!stereoActiveRef.current || !(cameraToRender instanceof PerspectiveCamera10)) {
@@ -16897,12 +17737,12 @@ function WebVRStereoRenderer({
16897
17737
  if (originalFovRef.current === null) {
16898
17738
  originalFovRef.current = cameraToRender.fov;
16899
17739
  }
16900
- const { eyeWidth, fullHeight } = syncStereoCameras(
17740
+ const layout = syncStereoCameras(
16901
17741
  stereoRef.current,
16902
17742
  cameraToRender,
16903
17743
  currentProfile,
16904
17744
  currentScreensize,
16905
- drawingSizeRef.current,
17745
+ sizeRef.current,
16906
17746
  gl
16907
17747
  );
16908
17748
  const hasDistortion = currentProfile.k1 !== 0 || currentProfile.k2 !== 0;
@@ -16913,18 +17753,19 @@ function WebVRStereoRenderer({
16913
17753
  gl.getScissor(scissorRef.current);
16914
17754
  gl.autoClear = true;
16915
17755
  gl.setScissorTest(true);
16916
- const renderEye = (eyeCamera, offsetX) => {
17756
+ const renderEye = (eyeCamera, eye) => {
16917
17757
  if (hasDistortion) {
16918
- if (resources.target.width !== eyeWidth || resources.target.height !== fullHeight) {
16919
- resources.target.setSize(eyeWidth, fullHeight);
17758
+ if (resources.target.width !== layout.renderTargetWidth || resources.target.height !== layout.renderTargetHeight) {
17759
+ resources.target.setSize(
17760
+ layout.renderTargetWidth,
17761
+ layout.renderTargetHeight
17762
+ );
16920
17763
  }
16921
17764
  gl.setRenderTarget(resources.target);
16922
- gl.setViewport(0, 0, eyeWidth, fullHeight);
16923
- gl.setScissor(0, 0, eyeWidth, fullHeight);
16924
17765
  originalRender(sceneToRender, eyeCamera);
16925
17766
  gl.setRenderTarget(null);
16926
- gl.setViewport(offsetX, 0, eyeWidth, fullHeight);
16927
- gl.setScissor(offsetX, 0, eyeWidth, fullHeight);
17767
+ gl.setViewport(eye.offsetX, 0, eye.width, eye.height);
17768
+ gl.setScissor(eye.offsetX, 0, eye.width, eye.height);
16928
17769
  resources.material.uniforms.distortion?.value.set(
16929
17770
  currentProfile.k1,
16930
17771
  currentProfile.k2
@@ -16933,12 +17774,12 @@ function WebVRStereoRenderer({
16933
17774
  return;
16934
17775
  }
16935
17776
  gl.setRenderTarget(null);
16936
- gl.setViewport(offsetX, 0, eyeWidth, fullHeight);
16937
- gl.setScissor(offsetX, 0, eyeWidth, fullHeight);
17777
+ gl.setViewport(eye.offsetX, 0, eye.width, eye.height);
17778
+ gl.setScissor(eye.offsetX, 0, eye.width, eye.height);
16938
17779
  originalRender(sceneToRender, eyeCamera);
16939
17780
  };
16940
- renderEye(stereoRef.current.cameraL, 0);
16941
- renderEye(stereoRef.current.cameraR, eyeWidth);
17781
+ renderEye(stereoRef.current.cameraL, layout.left);
17782
+ renderEye(stereoRef.current.cameraR, layout.right);
16942
17783
  gl.setRenderTarget(previousTarget);
16943
17784
  gl.setViewport(viewportRef.current);
16944
17785
  gl.setScissor(scissorRef.current);
@@ -16949,7 +17790,7 @@ function WebVRStereoRenderer({
16949
17790
  gl.render = originalRender;
16950
17791
  };
16951
17792
  }, [gl, resources]);
16952
- useEffect36(
17793
+ useEffect37(
16953
17794
  () => () => {
16954
17795
  if (runtime) {
16955
17796
  runtime.stereoView.active = false;
@@ -16969,7 +17810,7 @@ function WebVRStereoRenderer({
16969
17810
  camera,
16970
17811
  profileRef.current,
16971
17812
  screensizeRef.current,
16972
- drawingSizeRef.current,
17813
+ sizeRef.current,
16973
17814
  gl
16974
17815
  );
16975
17816
  return;
@@ -16984,7 +17825,7 @@ function WebVRStereoRenderer({
16984
17825
  }
16985
17826
 
16986
17827
  // src/webvr/pointerlock.ts
16987
- import { useEffect as useEffect37, useRef as useRef38 } from "react";
17828
+ import { useEffect as useEffect38, useRef as useRef38 } from "react";
16988
17829
  var POINTER_LOCK_CURSOR_ID = "webvr:pointerlock";
16989
17830
  async function requestWebVRPointerLock(element) {
16990
17831
  if (typeof document === "undefined") {
@@ -17021,7 +17862,7 @@ function useWebVRPointerLock(enabled, element) {
17021
17862
  const enabledRef = useRef38(enabled);
17022
17863
  cursorRef.current = cursor;
17023
17864
  enabledRef.current = enabled;
17024
- useEffect37(() => {
17865
+ useEffect38(() => {
17025
17866
  if (!enabled || !element) {
17026
17867
  return;
17027
17868
  }
@@ -17051,7 +17892,7 @@ function useWebVRPointerLock(enabled, element) {
17051
17892
  }
17052
17893
 
17053
17894
  // src/webvr/wakelock.ts
17054
- import { useEffect as useEffect38 } from "react";
17895
+ import { useEffect as useEffect39 } from "react";
17055
17896
 
17056
17897
  // src/webvr/wakelock-fallback.ts
17057
17898
  var WEBVR_WAKELOCK_FALLBACK_VIDEO_BASE64 = "AAAAIGZ0eXBpc29tAAACAGlzb21pc28yYXZjMW1wNDEAAAbBbW9vdgAAAGxtdmhkAAAAAAAAAAAAAAAAAAAD6AAAD4AAAQAAAQAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAwAAAxt0cmFrAAAAXHRraGQAAAADAAAAAAAAAAAAAAABAAAAAAAAAggAAAAAAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAABAAAAAABAAAAAQAAAAAAAkZWR0cwAAABxlbHN0AAAAAAAAAAEAAAIIAAAEAAABAAAAAAKTbWRpYQAAACBtZGhkAAAAAAAAAAAAAAAAAAAyAAAAGgBVxAAAAAAALWhkbHIAAAAAAAAAAHZpZGUAAAAAAAAAAAAAAABWaWRlb0hhbmRsZXIAAAACPm1pbmYAAAAUdm1oZAAAAAEAAAAAAAAAAAAAACRkaW5mAAAAHGRyZWYAAAAAAAAAAQAAAAx1cmwgAAAAAQAAAf5zdGJsAAAAvnN0c2QAAAAAAAAAAQAAAK5hdmMxAAAAAAAAAAEAAAAAAAAAAAAAAAAAAAAAABAAEABIAAAASAAAAAAAAAABFUxhdmM2Mi4xMS4xMDAgbGlieDI2NAAAAAAAAAAAAAAAGP//AAAANGF2Y0MBZAAK/+EAF2dkAAqs2V7ARAAAAwAEAAADAMg8SJZYAQAGaOvjyyLA/fj4AAAAABBwYXNwAAAAAQAAAAEAAAAUYnRydAAAAAAAADQ5AAAAAAAAABhzdHRzAAAAAAAAAAEAAAANAAACAAAAABRzdHNzAAAAAAAAAAEAAAABAAAAeGN0dHMAAAAAAAAADQAAAAEAAAQAAAAAAQAACgAAAAABAAAEAAAAAAEAAAAAAAAAAQAAAgAAAAABAAAKAAAAAAEAAAQAAAAAAQAAAAAAAAABAAACAAAAAAEAAAoAAAAAAQAABAAAAAABAAAAAAAAAAEAAAIAAAAAKHN0c2MAAAAAAAAAAgAAAAEAAAADAAAAAQAAAAUAAAABAAAAAQAAAEhzdHN6AAAAAAAAAAAAAAANAAACxQAAAAwAAAAMAAAADAAAAAwAAAASAAAADgAAAAwAAAAMAAAAEgAAAA4AAAAMAAAADAAAACRzdGNvAAAAAAAAAAUAAAcGAAAJ5wAAChUAAAo/AAAKbwAAAtF0cmFrAAAAXHRraGQAAAADAAAAAAAAAAAAAAACAAAAAAAAD4AAAAAAAAAAAAAAAAEBAAAAAAEAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAAkZWR0cwAAABxlbHN0AAAAAAAAAAEAAA+AAAAEAAABAAAAAAJJbWRpYQAAACBtZGhkAAAAAAAAAAAAAAAAAAAfQAAAgABVxAAAAAAALWhkbHIAAAAAAAAAAHNvdW4AAAAAAAAAAAAAAABTb3VuZEhhbmRsZXIAAAAB9G1pbmYAAAAQc21oZAAAAAAAAAAAAAAAJGRpbmYAAAAcZHJlZgAAAAAAAAABAAAADHVybCAAAAABAAABuHN0YmwAAAB+c3RzZAAAAAAAAAABAAAAbm1wNGEAAAAAAAAAAQAAAAAAAAAAAAEAEAAAAAAfQAAAAAAANmVzZHMAAAAAA4CAgCUAAgAEgICAF0AVAAAAAAAfQAAAARsFgICABRWIVuUABoCAgAECAAAAFGJ0cnQAAAAAAAAfQAAAARsAAAAYc3R0cwAAAAAAAAABAAAAIAAABAAAAAAoc3RzYwAAAAAAAAACAAAAAQAAAAEAAAABAAAABgAAABsAAAABAAAAlHN0c3oAAAAAAAAAAAAAACAAAAAVAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAChzdGNvAAAAAAAAAAYAAAbxAAAJ4wAAChEAAAo7AAAKawAACnsAAAAac2dwZAEAAAByb2xsAAAAAgAAAAH//wAAABxzYmdwAAAAAHJvbGwAAAABAAAAIAAAAAEAAABhdWR0YQAAAFltZXRhAAAAAAAAACFoZGxyAAAAAAAAAABtZGlyYXBwbAAAAAAAAAAAAAAAACxpbHN0AAAAJKl0b28AAAAcZGF0YQAAAAEAAAAATGF2ZjYyLjMuMTAwAAAACGZyZWUAAAP+bWRhdN4CAExhdmM2Mi4xMS4xMDAAAjBADgAAAq4GBf//qtxF6b3m2Ui3lizYINkj7u94MjY0IC0gY29yZSAxNjUgcjMyMjIgYjM1NjA1YSAtIEguMjY0L01QRUctNCBBVkMgY29kZWMgLSBDb3B5bGVmdCAyMDAzLTIwMjUgLSBodHRwOi8vd3d3LnZpZGVvbGFuLm9yZy94MjY0Lmh0bWwgLSBvcHRpb25zOiBjYWJhYz0xIHJlZj0zIGRlYmxvY2s9MTowOjAgYW5hbHlzZT0weDM6MHgxMTMgbWU9aGV4IHN1Ym1lPTcgcHN5PTEgcHN5X3JkPTEuMDA6MC4wMCBtaXhlZF9yZWY9MSBtZV9yYW5nZT0xNiBjaHJvbWFfbWU9MSB0cmVsbGlzPTEgOHg4ZGN0PTEgY3FtPTAgZGVhZHpvbmU9MjEsMTEgZmFzdF9wc2tpcD0xIGNocm9tYV9xcF9vZmZzZXQ9LTIgdGhyZWFkcz0xIGxvb2thaGVhZF90aHJlYWRzPTEgc2xpY2VkX3RocmVhZHM9MCBucj0wIGRlY2ltYXRlPTEgaW50ZXJsYWNlZD0wIGJsdXJheV9jb21wYXQ9MCBjb25zdHJhaW5lZF9pbnRyYT0wIGJmcmFtZXM9MyBiX3B5cmFtaWQ9MiBiX2FkYXB0PTEgYl9iaWFzPTAgZGlyZWN0PTEgd2VpZ2h0Yj0xIG9wZW5fZ29wPTAgd2VpZ2h0cD0yIGtleWludD0yNTAga2V5aW50X21pbj0yNSBzY2VuZWN1dD00MCBpbnRyYV9yZWZyZXNoPTAgcmNfbG9va2FoZWFkPTQwIHJjPWNyZiBtYnRyZWU9MSBjcmY9MjMuMCBxY29tcD0wLjYwIHFwbWluPTAgcXBtYXg9NjkgcXBzdGVwPTQgaXBfcmF0aW89MS40MCBhcT0xOjEuMDAAgAAAAA9liIQAO//+906/AptUwmEAAAAIQZokbEN//uAAAAAIQZ5CeIX/wYEBGCAHAAAACAGeYXRCv8SAAAAACAGeY2pCv8SBAAAADkGaaEmoQWiZTAhn//7hARggBwAAAApBnoZFESwv/8GBAAAACAGepXRCv8SBAAAACAGep2pCv8SAARggBwAAAA5BmqxJqEFsmUwIV//+wAAAAApBnspFFSwv/8GBAAAACAGe6XRCv8SAARggBwAAAAgBnutqQr/EgAEYIAcBGCAHARggBwEYIAcBGCAHARggBwEYIAcBGCAHARggBwEYIAcBGCAHARggBwEYIAcBGCAHARggBwEYIAcBGCAHARggBwEYIAcBGCAHARggBwEYIAcBGCAHARggBwEYIAcBGCAHARggBw==";
@@ -17180,7 +18021,7 @@ function releaseWebVRWakeLock() {
17180
18021
  stopFallbackVideo();
17181
18022
  }
17182
18023
  function useWebVRWakeLock(enabled) {
17183
- useEffect38(() => {
18024
+ useEffect39(() => {
17184
18025
  if (!enabled) {
17185
18026
  return;
17186
18027
  }
@@ -17199,7 +18040,7 @@ function useWebVRWakeLock(enabled) {
17199
18040
  }
17200
18041
 
17201
18042
  // src/webvr/webvr.tsx
17202
- import { Fragment as Fragment6, jsx as jsx39, jsxs as jsxs20 } from "react/jsx-runtime";
18043
+ import { Fragment as Fragment6, jsx as jsx40, jsxs as jsxs21 } from "react/jsx-runtime";
17203
18044
  function initializeSettings(screensize, profile) {
17204
18045
  const stored = loadWebVRSettings();
17205
18046
  return {
@@ -17241,8 +18082,8 @@ var WebVR = forwardRef4(function WebVR2({
17241
18082
  const availableRef = useRef39(false);
17242
18083
  const modeRef = useRef39(null);
17243
18084
  const webXRSessionRef = useRef39(null);
17244
- const [mode, setMode] = useState23(null);
17245
- const [settings, setSettings] = useState23(
18085
+ const [mode, setMode] = useState24(null);
18086
+ const [settings, setSettings] = useState24(
17246
18087
  () => initializeSettings(screensize, profile)
17247
18088
  );
17248
18089
  const callbacksRef = useRef39({
@@ -17348,16 +18189,12 @@ var WebVR = forwardRef4(function WebVR2({
17348
18189
  if (wakelock) {
17349
18190
  void acquireWebVRWakeLock();
17350
18191
  }
17351
- void requestElementFullscreen(getViewerElement(gl.domElement)).catch(
17352
- () => {
17353
- }
17354
- );
18192
+ const viewer = getViewerElement(gl.domElement);
18193
+ await enterWebVRPresentation(viewer);
17355
18194
  const granted = await requestPermission();
17356
18195
  if (!granted) {
17357
18196
  releaseWebVRWakeLock();
17358
- if (getFullscreenElement()) {
17359
- void exitElementFullscreen();
17360
- }
18197
+ leaveWebVRPresentation();
17361
18198
  reportDenied();
17362
18199
  return false;
17363
18200
  }
@@ -17371,10 +18208,7 @@ var WebVR = forwardRef4(function WebVR2({
17371
18208
  if (wakelock) {
17372
18209
  void acquireWebVRWakeLock();
17373
18210
  }
17374
- try {
17375
- await requestElementFullscreen(getViewerElement(gl.domElement));
17376
- } catch {
17377
- }
18211
+ await enterWebVRPresentation(getViewerElement(gl.domElement));
17378
18212
  if (mousePointerLock) {
17379
18213
  void requestWebVRPointerLock(gl.domElement);
17380
18214
  }
@@ -17411,9 +18245,7 @@ var WebVR = forwardRef4(function WebVR2({
17411
18245
  return;
17412
18246
  }
17413
18247
  deactivate();
17414
- if (getFullscreenElement()) {
17415
- await exitElementFullscreen();
17416
- }
18248
+ leaveWebVRPresentation();
17417
18249
  }, [deactivate, xrStore]);
17418
18250
  const toggleVR = useCallback10(async () => {
17419
18251
  if (modeRef.current) {
@@ -17455,7 +18287,7 @@ var WebVR = forwardRef4(function WebVR2({
17455
18287
  }),
17456
18288
  [enterVR, exitVR, requestPermission, toggleVR]
17457
18289
  );
17458
- useEffect39(() => {
18290
+ useEffect40(() => {
17459
18291
  let active = true;
17460
18292
  void detectWebVRCapabilities().then((capabilities) => {
17461
18293
  if (!active) {
@@ -17477,7 +18309,7 @@ var WebVR = forwardRef4(function WebVR2({
17477
18309
  active = false;
17478
18310
  };
17479
18311
  }, [desktopSupport, eventBus, fakeSupport, host, mobileVr]);
17480
- useEffect39(() => {
18312
+ useEffect40(() => {
17481
18313
  host.controller = controller;
17482
18314
  return () => {
17483
18315
  if (host.controller === controller) {
@@ -17486,10 +18318,10 @@ var WebVR = forwardRef4(function WebVR2({
17486
18318
  }
17487
18319
  };
17488
18320
  }, [controller, host]);
17489
- useEffect39(() => {
18321
+ useEffect40(() => {
17490
18322
  updateWebVRHost(host, { chrome, mode, settings });
17491
18323
  }, [chrome, host, mode, settings]);
17492
- useEffect39(() => {
18324
+ useEffect40(() => {
17493
18325
  if (mode !== "fake") {
17494
18326
  return;
17495
18327
  }
@@ -17513,7 +18345,7 @@ var WebVR = forwardRef4(function WebVR2({
17513
18345
  document.removeEventListener("mousemove", onMouseMove);
17514
18346
  };
17515
18347
  }, [controlsRef, gl.domElement, mode, mousePointerLock]);
17516
- useEffect39(
18348
+ useEffect40(
17517
18349
  () => () => {
17518
18350
  const session2 = webXRSessionRef.current;
17519
18351
  if (session2) {
@@ -17522,9 +18354,21 @@ var WebVR = forwardRef4(function WebVR2({
17522
18354
  if (modeRef.current === "fake") {
17523
18355
  controlsRef.current?.setGyroActive(false);
17524
18356
  }
18357
+ if (modeRef.current === "mobilevr" || modeRef.current === "fake") {
18358
+ leaveWebVRPresentation();
18359
+ }
17525
18360
  },
17526
18361
  [controlsRef]
17527
18362
  );
18363
+ useEffect40(() => {
18364
+ if (mode !== "mobilevr" && mode !== "fake") {
18365
+ return;
18366
+ }
18367
+ const viewer = getViewerElement(gl.domElement);
18368
+ return subscribeWebVRPresentationExit(viewer, () => {
18369
+ void exitVR();
18370
+ });
18371
+ }, [exitVR, gl.domElement, mode]);
17528
18372
  useWebVRPointerLock(
17529
18373
  mousePointerLock && mode === "fake",
17530
18374
  gl.domElement
@@ -17532,8 +18376,8 @@ var WebVR = forwardRef4(function WebVR2({
17532
18376
  useWebVRWakeLock(
17533
18377
  wakelock && (mode === "mobilevr" || mode === "fake")
17534
18378
  );
17535
- return /* @__PURE__ */ jsxs20(Fragment6, { children: [
17536
- /* @__PURE__ */ jsx39(
18379
+ return /* @__PURE__ */ jsxs21(Fragment6, { children: [
18380
+ /* @__PURE__ */ jsx40(
17537
18381
  Gyro,
17538
18382
  {
17539
18383
  ref: gyroRef,
@@ -17547,7 +18391,7 @@ var WebVR = forwardRef4(function WebVR2({
17547
18391
  touchMode: "off"
17548
18392
  }
17549
18393
  ),
17550
- /* @__PURE__ */ jsx39(
18394
+ /* @__PURE__ */ jsx40(
17551
18395
  WebVRStereoRenderer,
17552
18396
  {
17553
18397
  mode,
@@ -17555,10 +18399,11 @@ var WebVR = forwardRef4(function WebVR2({
17555
18399
  screensize: settings.screensize
17556
18400
  }
17557
18401
  ),
17558
- /* @__PURE__ */ jsx39(
18402
+ /* @__PURE__ */ jsx40(
17559
18403
  WebVRReticle,
17560
18404
  {
17561
18405
  dwellMs: cursorDwellMs,
18406
+ scale: mode === "mobilevr" ? MOBILE_VR_RETICLE_SCALE : 1,
17562
18407
  visible: cursor && mode !== null
17563
18408
  }
17564
18409
  )
@@ -17658,11 +18503,11 @@ import { useThree as useThree29 } from "@react-three/fiber";
17658
18503
  import {
17659
18504
  useCallback as useCallback11,
17660
18505
  useContext as useContext28,
17661
- useEffect as useEffect40,
18506
+ useEffect as useEffect41,
17662
18507
  useLayoutEffect as useLayoutEffect9,
17663
18508
  useMemo as useMemo28,
17664
18509
  useRef as useRef41,
17665
- useState as useState24
18510
+ useState as useState25
17666
18511
  } from "react";
17667
18512
  import {
17668
18513
  BackSide as BackSide4,
@@ -17674,7 +18519,7 @@ import {
17674
18519
  TextureLoader as TextureLoader8,
17675
18520
  VideoTexture as VideoTexture2
17676
18521
  } from "three";
17677
- import { Fragment as Fragment7, jsx as jsx40, jsxs as jsxs21 } from "react/jsx-runtime";
18522
+ import { Fragment as Fragment7, jsx as jsx41, jsxs as jsxs22 } from "react/jsx-runtime";
17678
18523
  var EMPTY_TRACKS = [];
17679
18524
  var EMPTY_RATES = DEFAULT_PANO_VIDEO_PLAYBACK_RATES;
17680
18525
  function createEmptySnapshot() {
@@ -17759,10 +18604,10 @@ function applyEquirectangularLayout(texture, anisotropy) {
17759
18604
  }
17760
18605
  function usePosterTexture2(poster, onError) {
17761
18606
  const gl = useThree29((state) => state.gl);
17762
- const [texture, setTexture] = useState24(null);
18607
+ const [texture, setTexture] = useState25(null);
17763
18608
  const onErrorRef = useRef41(onError);
17764
18609
  onErrorRef.current = onError;
17765
- useEffect40(() => {
18610
+ useEffect41(() => {
17766
18611
  let active = true;
17767
18612
  setTexture(null);
17768
18613
  if (!poster) {
@@ -17799,7 +18644,7 @@ function usePosterTexture2(poster, onError) {
17799
18644
  active = false;
17800
18645
  };
17801
18646
  }, [gl, poster]);
17802
- useEffect40(
18647
+ useEffect41(
17803
18648
  () => () => {
17804
18649
  texture?.dispose();
17805
18650
  },
@@ -17871,13 +18716,13 @@ function PanoVideo({
17871
18716
  ),
17872
18717
  [captions]
17873
18718
  );
17874
- const [variantId, setVariantId] = useState24(
18719
+ const [variantId, setVariantId] = useState25(
17875
18720
  () => resolvePanoVideoVariantId(variants, defaultVariantId)
17876
18721
  );
17877
- const [trackId, setTrackId] = useState24(
18722
+ const [trackId, setTrackId] = useState25(
17878
18723
  () => captionsEnabled ? defaultPanoVideoTrackId(tracks) : null
17879
18724
  );
17880
- const [ready, setReady] = useState24(false);
18725
+ const [ready, setReady] = useState25(false);
17881
18726
  const autoPlayRef = useRef41(autoPlay);
17882
18727
  autoPlayRef.current = autoPlay;
17883
18728
  const blockedRef = useRef41(false);
@@ -17945,7 +18790,7 @@ function PanoVideo({
17945
18790
  texture.generateMipmaps = false;
17946
18791
  return { video, texture };
17947
18792
  }, []);
17948
- useEffect40(
18793
+ useEffect41(
17949
18794
  () => () => {
17950
18795
  if (!resource) {
17951
18796
  return;
@@ -17960,7 +18805,7 @@ function PanoVideo({
17960
18805
  },
17961
18806
  [resource]
17962
18807
  );
17963
- useEffect40(() => {
18808
+ useEffect41(() => {
17964
18809
  if (!resource) {
17965
18810
  return;
17966
18811
  }
@@ -18112,10 +18957,10 @@ function PanoVideo({
18112
18957
  };
18113
18958
  emitSnapshot();
18114
18959
  }, [emitSnapshot, playbackRates, resource]);
18115
- useEffect40(() => {
18960
+ useEffect41(() => {
18116
18961
  emitSnapshot();
18117
18962
  }, [emitSnapshot]);
18118
- useEffect40(() => {
18963
+ useEffect41(() => {
18119
18964
  if (!resource || !activeVariant || !mediaKey) {
18120
18965
  return;
18121
18966
  }
@@ -18172,7 +19017,7 @@ function PanoVideo({
18172
19017
  video.removeEventListener("error", handleError);
18173
19018
  };
18174
19019
  }, [mediaKey, resource]);
18175
- useEffect40(() => {
19020
+ useEffect41(() => {
18176
19021
  if (!resource) {
18177
19022
  return;
18178
19023
  }
@@ -18277,7 +19122,7 @@ function PanoVideo({
18277
19122
  applyInlineVideoPlayback(video, playsInline);
18278
19123
  video.preload = preload;
18279
19124
  }, [loop, muted, playsInline, preload, resource, volume]);
18280
- useEffect40(() => {
19125
+ useEffect41(() => {
18281
19126
  if (!resource) {
18282
19127
  return;
18283
19128
  }
@@ -18327,7 +19172,7 @@ function PanoVideo({
18327
19172
  video.removeEventListener("ratechange", handleVolume);
18328
19173
  };
18329
19174
  }, [emitSnapshot, resource]);
18330
- useEffect40(() => {
19175
+ useEffect41(() => {
18331
19176
  if (!resource) {
18332
19177
  return;
18333
19178
  }
@@ -18362,7 +19207,7 @@ function PanoVideo({
18362
19207
  video.textTracks.removeEventListener("change", applyModes);
18363
19208
  };
18364
19209
  }, [emitSnapshot, resource, trackId, tracks]);
18365
- useEffect40(() => {
19210
+ useEffect41(() => {
18366
19211
  if (!captionsEnabled) {
18367
19212
  setTrackId(null);
18368
19213
  return;
@@ -18373,15 +19218,15 @@ function PanoVideo({
18373
19218
  if (variants.length === 0) {
18374
19219
  return null;
18375
19220
  }
18376
- return /* @__PURE__ */ jsxs21(Fragment7, { children: [
18377
- activeTexture ? /* @__PURE__ */ jsxs21(
19221
+ return /* @__PURE__ */ jsxs22(Fragment7, { children: [
19222
+ activeTexture ? /* @__PURE__ */ jsxs22(
18378
19223
  "mesh",
18379
19224
  {
18380
19225
  rotation: [0, MathUtils13.degToRad(90 + yawOffset2), 0],
18381
19226
  visible,
18382
19227
  children: [
18383
- /* @__PURE__ */ jsx40("sphereGeometry", { args: [DEFAULT_PANORAMA_RADIUS, 128, 64] }),
18384
- /* @__PURE__ */ jsx40(
19228
+ /* @__PURE__ */ jsx41("sphereGeometry", { args: [DEFAULT_PANORAMA_RADIUS, 128, 64] }),
19229
+ /* @__PURE__ */ jsx41(
18385
19230
  PanoBasicMaterial,
18386
19231
  {
18387
19232
  map: activeTexture,
@@ -18392,7 +19237,7 @@ function PanoVideo({
18392
19237
  ]
18393
19238
  }
18394
19239
  ) : null,
18395
- captionsEnabled ? /* @__PURE__ */ jsx40(PanoVideoCaptions, { appearance: typeof captions === "object" ? captions : void 0 }) : null
19240
+ captionsEnabled ? /* @__PURE__ */ jsx41(PanoVideoCaptions, { appearance: typeof captions === "object" ? captions : void 0 }) : null
18396
19241
  ] });
18397
19242
  }
18398
19243
  export {