@ericchen1990/pano-view 3.6.0 → 3.6.2

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
@@ -2587,6 +2587,7 @@ var PanoramaViewRuntime = forwardRef(function PanoramaViewRuntime2({ initialView
2587
2587
  const { camera, gl } = useThree();
2588
2588
  const xrSession = useXR((state) => state.session);
2589
2589
  const xrSessionRef = useRef(xrSession);
2590
+ const pointerRevisionRef = useRef(0);
2590
2591
  const viewRef = useRef({ ...initialView });
2591
2592
  const targetViewRef = useRef({ ...initialView });
2592
2593
  const initialViewRef = useRef({ ...initialView });
@@ -2681,6 +2682,7 @@ var PanoramaViewRuntime = forwardRef(function PanoramaViewRuntime2({ initialView
2681
2682
  };
2682
2683
  const acquireInteractionLock = () => {
2683
2684
  cancelNavigation();
2685
+ pointerRevisionRef.current += 1;
2684
2686
  interactionLockCountRef.current += 1;
2685
2687
  stopVelocity();
2686
2688
  if (mouseActiveRef.current) {
@@ -2712,6 +2714,7 @@ var PanoramaViewRuntime = forwardRef(function PanoramaViewRuntime2({ initialView
2712
2714
  legacyFovRef.current.maxFov
2713
2715
  );
2714
2716
  if (JSON.stringify(next) === JSON.stringify(limitsRef.current)) return;
2717
+ pointerRevisionRef.current += 1;
2715
2718
  limitsRef.current = next;
2716
2719
  cancelNavigation();
2717
2720
  stopVelocity();
@@ -2727,6 +2730,7 @@ var PanoramaViewRuntime = forwardRef(function PanoramaViewRuntime2({ initialView
2727
2730
  };
2728
2731
  const setView = (view, setOptions) => {
2729
2732
  cancelNavigation();
2733
+ pointerRevisionRef.current += 1;
2730
2734
  const nextView = hardConstrainView(view);
2731
2735
  if (gyroActiveRef.current) {
2732
2736
  gyroOffsetRef.current = {
@@ -2746,6 +2750,7 @@ var PanoramaViewRuntime = forwardRef(function PanoramaViewRuntime2({ initialView
2746
2750
  if (xrSessionRef.current != null || gyroActiveRef.current || interactionLockCountRef.current > 0) {
2747
2751
  return Promise.resolve({ status: "cancelled" });
2748
2752
  }
2753
+ pointerRevisionRef.current += 1;
2749
2754
  const from = { ...viewRef.current };
2750
2755
  const safeTargetInput = {
2751
2756
  yaw: targetInput.yaw !== void 0 && Number.isFinite(targetInput.yaw) ? targetInput.yaw : from.yaw,
@@ -2810,19 +2815,24 @@ var PanoramaViewRuntime = forwardRef(function PanoramaViewRuntime2({ initialView
2810
2815
  return false;
2811
2816
  }
2812
2817
  const current = targetViewRef.current;
2818
+ const origin = !gyroActiveRef.current ? applyOptions?.pointerOrigin : void 0;
2819
+ const reference = origin ?? current;
2813
2820
  const gyroMode = gyroTouchModeRef.current;
2814
2821
  const gyroControlsView = gyroActiveRef.current;
2815
2822
  const appliesTouchMode = gyroControlsView && applyOptions?.source === "touch";
2816
2823
  const acceptsYaw = !appliesTouchMode || gyroMode === "horizontaloffset" || gyroMode === "full";
2817
2824
  const acceptsPitch = !appliesTouchMode || gyroMode === "full";
2818
- const nextYaw = acceptsYaw && delta.yaw !== void 0 && Number.isFinite(delta.yaw) ? applyLimitedYawDelta(current.yaw, delta.yaw, limitsRef.current.yaw) : current.yaw;
2819
- const nextPitch = acceptsPitch && delta.pitch !== void 0 && Number.isFinite(delta.pitch) ? current.pitch + delta.pitch : current.pitch;
2825
+ const nextYaw = acceptsYaw && delta.yaw !== void 0 && Number.isFinite(delta.yaw) ? applyLimitedYawDelta(reference.yaw, delta.yaw, limitsRef.current.yaw) : current.yaw;
2826
+ const nextPitch = acceptsPitch && delta.pitch !== void 0 && Number.isFinite(delta.pitch) ? reference.pitch + delta.pitch : current.pitch;
2820
2827
  const nextFov = delta.fov !== void 0 && Number.isFinite(delta.fov) ? current.fov + delta.fov : current.fov;
2821
2828
  targetViewRef.current = softConstrainView({
2822
2829
  yaw: nextYaw,
2823
2830
  pitch: nextPitch,
2824
2831
  fov: nextFov
2825
2832
  });
2833
+ if (origin) {
2834
+ viewRef.current = { ...viewRef.current, yaw: targetViewRef.current.yaw, pitch: targetViewRef.current.pitch };
2835
+ }
2826
2836
  if (gyroControlsView) {
2827
2837
  if (acceptsYaw && delta.yaw !== void 0 && Number.isFinite(delta.yaw)) {
2828
2838
  gyroOffsetRef.current.yaw = shortestYawDelta(gyroPoseRef.current.yaw, targetViewRef.current.yaw);
@@ -2832,16 +2842,21 @@ var PanoramaViewRuntime = forwardRef(function PanoramaViewRuntime2({ initialView
2832
2842
  }
2833
2843
  }
2834
2844
  markDirty();
2835
- if (applyOptions?.recordVelocity && !gyroControlsView) {
2845
+ const releaseVelocity = applyOptions?.velocity;
2846
+ if (!gyroControlsView && releaseVelocity && Number.isFinite(releaseVelocity.yaw) && Number.isFinite(releaseVelocity.pitch)) {
2847
+ yawVelocityRef.current = releaseVelocity.yaw;
2848
+ pitchVelocityRef.current = releaseVelocity.pitch;
2849
+ lastVelocitySampleAtRef.current = performance.now();
2850
+ } else if (applyOptions?.recordVelocity && !gyroControlsView) {
2836
2851
  const now = performance.now();
2837
2852
  const previousAt = lastVelocitySampleAtRef.current;
2838
2853
  const elapsed = previousAt === null ? 1 / 60 : Math.max((now - previousAt) / 1e3, 1 / 120);
2839
2854
  lastVelocitySampleAtRef.current = now;
2840
2855
  if (delta.yaw !== void 0 && Number.isFinite(delta.yaw)) {
2841
- yawVelocityRef.current = delta.yaw / elapsed;
2856
+ yawVelocityRef.current = limitedYawDelta(current.yaw, targetViewRef.current.yaw, limitsRef.current.yaw) / elapsed;
2842
2857
  }
2843
2858
  if (delta.pitch !== void 0 && Number.isFinite(delta.pitch)) {
2844
- pitchVelocityRef.current = delta.pitch / elapsed;
2859
+ pitchVelocityRef.current = (targetViewRef.current.pitch - current.pitch) / elapsed;
2845
2860
  }
2846
2861
  if (delta.fov !== void 0 && Number.isFinite(delta.fov)) {
2847
2862
  zoomVelocityRef.current = clamp(delta.fov / elapsed, -180, 180);
@@ -2855,6 +2870,7 @@ var PanoramaViewRuntime = forwardRef(function PanoramaViewRuntime2({ initialView
2855
2870
  ref,
2856
2871
  () => ({
2857
2872
  getView: () => ({ ...viewRef.current }),
2873
+ getPointerDragState: () => ({ revision: pointerRevisionRef.current, anchored: !gyroActiveRef.current && xrSessionRef.current == null }),
2858
2874
  setSceneViewLimits: (limits) => {
2859
2875
  sceneLimitsRef.current = parseViewLimits(limits);
2860
2876
  refreshLimits();
@@ -2894,6 +2910,9 @@ var PanoramaViewRuntime = forwardRef(function PanoramaViewRuntime2({ initialView
2894
2910
  }
2895
2911
  syncInteracting();
2896
2912
  if (active && !wasActive) {
2913
+ if (!gyroActiveRef.current) {
2914
+ targetViewRef.current = { ...targetViewRef.current, yaw: viewRef.current.yaw, pitch: viewRef.current.pitch };
2915
+ }
2897
2916
  eventBusRef.current.emit("viewinteractionstart", { source });
2898
2917
  } else if (!active && wasActive) {
2899
2918
  eventBusRef.current.emit("viewinteractionend", { source });
@@ -2913,6 +2932,7 @@ var PanoramaViewRuntime = forwardRef(function PanoramaViewRuntime2({ initialView
2913
2932
  isInteractionLocked: () => interactionLockCountRef.current > 0,
2914
2933
  isUserInteracting,
2915
2934
  setGyroActive: (active) => {
2935
+ if (gyroActiveRef.current !== active) pointerRevisionRef.current += 1;
2916
2936
  if (active) {
2917
2937
  cancelNavigation();
2918
2938
  }
@@ -3668,8 +3688,218 @@ function KeyboardControls({
3668
3688
  }
3669
3689
 
3670
3690
  // src/mouse-controls.tsx
3671
- import { useThree as useThree3 } from "@react-three/fiber";
3691
+ import { useFrame as useFrame4, useThree as useThree3 } from "@react-three/fiber";
3672
3692
  import { useContext as useContext5, useEffect as useEffect5, useRef as useRef5 } from "react";
3693
+
3694
+ // src/pointer-drag.ts
3695
+ import { Euler as Euler2, MathUtils as MathUtils2, PerspectiveCamera as PerspectiveCamera2, Vector3 } from "three";
3696
+ var DEFAULT_POINTER_DRAG_SPEED = 0.35;
3697
+ var POINTER_FOLLOW_TIME_SECONDS = 0.01;
3698
+ var MIN_VELOCITY_SAMPLE_SECONDS = 1 / 120;
3699
+ function pointerReleaseVelocity(samples, releasedAt, solve, maxAgeMs = POINTER_VELOCITY_MAX_AGE_MS) {
3700
+ if (samples.length < 2) return { yaw: 0, pitch: 0 };
3701
+ const newest = samples[samples.length - 1];
3702
+ if (releasedAt < newest.at || releasedAt - newest.at > maxAgeMs) return { yaw: 0, pitch: 0 };
3703
+ let oldest = newest;
3704
+ for (let index = samples.length - 1; index >= 0; index -= 1) {
3705
+ const sample = samples[index];
3706
+ if (releasedAt - sample.at <= maxAgeMs) oldest = sample;
3707
+ else break;
3708
+ }
3709
+ if (oldest === newest) return { yaw: 0, pitch: 0 };
3710
+ const elapsed = Math.max((newest.at - oldest.at) / 1e3, MIN_VELOCITY_SAMPLE_SECONDS);
3711
+ const from = solve(oldest);
3712
+ const to = solve(newest);
3713
+ return {
3714
+ yaw: normalizeViewYaw(to.yaw - from.yaw) / elapsed,
3715
+ pitch: (to.pitch - from.pitch) / elapsed
3716
+ };
3717
+ }
3718
+ var PointerDragAnchor = class {
3719
+ constructor(start, origin, rect, projection) {
3720
+ this.start = start;
3721
+ this.origin = origin;
3722
+ this.rect = rect;
3723
+ this.projection = projection;
3724
+ this.local = new Vector3();
3725
+ this.rotation = new Euler2(0, 0, 0, "YXZ");
3726
+ this.anchor = this.ray(start).clone().applyEuler(this.rotation.set(
3727
+ MathUtils2.degToRad(origin.pitch),
3728
+ MathUtils2.degToRad(-origin.yaw),
3729
+ 0,
3730
+ "YXZ"
3731
+ ));
3732
+ }
3733
+ ray(point) {
3734
+ return this.local.set(
3735
+ (point.x - this.rect.left) / Math.max(this.rect.width, 1) * 2 - 1,
3736
+ 1 - (point.y - this.rect.top) / Math.max(this.rect.height, 1) * 2,
3737
+ 0.5
3738
+ ).applyMatrix4(this.projection.projectionMatrixInverse).normalize();
3739
+ }
3740
+ solve(point, speed = DEFAULT_POINTER_DRAG_SPEED, invert = false) {
3741
+ const multiplier = (Number.isFinite(speed) && speed >= 0 ? speed : DEFAULT_POINTER_DRAG_SPEED) / DEFAULT_POINTER_DRAG_SPEED * (invert ? -1 : 1);
3742
+ if (multiplier === 0) return { yaw: 0, pitch: 0 };
3743
+ const ray = this.ray({
3744
+ x: this.start.x + (point.x - this.start.x) * multiplier,
3745
+ y: this.start.y + (point.y - this.start.y) * multiplier
3746
+ });
3747
+ const latitude = Math.asin(MathUtils2.clamp(this.anchor.y / Math.max(Math.hypot(ray.y, ray.z), 1e-12), -1, 1));
3748
+ const offset = Math.atan2(ray.y, -ray.z);
3749
+ const originPitch = MathUtils2.degToRad(this.origin.pitch);
3750
+ const candidates = [latitude - offset, Math.PI - latitude - offset, -Math.PI - latitude - offset];
3751
+ let pitch = candidates[0];
3752
+ let distance = Infinity;
3753
+ for (const candidate of candidates) {
3754
+ const bounded = MathUtils2.clamp(candidate, -Math.PI / 2, Math.PI / 2);
3755
+ const nextDistance = Math.abs(candidate - bounded) * 10 + Math.abs(bounded - originPitch);
3756
+ if (nextDistance < distance) {
3757
+ pitch = bounded;
3758
+ distance = nextDistance;
3759
+ }
3760
+ }
3761
+ const z = Math.sin(pitch) * ray.y + Math.cos(pitch) * ray.z;
3762
+ const yaw = MathUtils2.radToDeg(Math.atan2(this.anchor.x, -this.anchor.z) - Math.atan2(ray.x, -z));
3763
+ return { yaw: normalizeViewYaw(yaw - this.origin.yaw), pitch: MathUtils2.radToDeg(pitch) - this.origin.pitch };
3764
+ }
3765
+ };
3766
+ function createPointerDrag(camera, element, runtime, source) {
3767
+ let anchor;
3768
+ let revision = -1;
3769
+ let projectionKey = "";
3770
+ let pending;
3771
+ let displayed;
3772
+ let lastPoint;
3773
+ let fresh = false;
3774
+ let lastFrameDelta = 1 / 60;
3775
+ let samples = [];
3776
+ let gestureSpeed = DEFAULT_POINTER_DRAG_SPEED;
3777
+ let gestureInvert = false;
3778
+ const key = (rect) => `${rect.left},${rect.top},${rect.width},${rect.height},${camera.projectionMatrix.elements.join(",")}`;
3779
+ const place = (point) => {
3780
+ const handle = runtime();
3781
+ displayed = { ...point };
3782
+ lastPoint = { ...point };
3783
+ pending = void 0;
3784
+ revision = handle?.getPointerDragState().revision ?? -1;
3785
+ anchor = void 0;
3786
+ if (!(camera instanceof PerspectiveCamera2) || !handle?.getPointerDragState().anchored) return;
3787
+ const rect = element.getBoundingClientRect();
3788
+ projectionKey = key(rect);
3789
+ anchor = new PointerDragAnchor(point, handle.getView(), rect, camera.clone());
3790
+ };
3791
+ const remember = (point, at) => {
3792
+ samples.push({ x: point.x, y: point.y, at });
3793
+ const cutoff = at - POINTER_VELOCITY_MAX_AGE_MS;
3794
+ while (samples.length > 2 && samples[0].at < cutoff) samples.shift();
3795
+ };
3796
+ const apply = (point, previous, speed, invert, recordVelocity, releaseVelocity) => {
3797
+ const handle = runtime();
3798
+ if (!handle) return;
3799
+ const rect = element.getBoundingClientRect();
3800
+ if (anchor && key(rect) !== projectionKey) {
3801
+ const queued = pending;
3802
+ place(displayed ?? previous);
3803
+ pending = queued;
3804
+ }
3805
+ const options = {
3806
+ recordVelocity: releaseVelocity ? false : recordVelocity,
3807
+ source,
3808
+ ...releaseVelocity ? { velocity: releaseVelocity } : {}
3809
+ };
3810
+ if (anchor) {
3811
+ handle.applyViewDelta(anchor.solve(point, speed, invert), {
3812
+ ...options,
3813
+ pointerOrigin: anchor.origin
3814
+ });
3815
+ } else {
3816
+ handle.applyViewDelta({
3817
+ yaw: -(point.x - previous.x) * 360 * speed / Math.max(rect.width, 1) * (invert ? -1 : 1),
3818
+ pitch: (point.y - previous.y) * 180 * speed / Math.max(rect.height, 1) * (invert ? -1 : 1)
3819
+ }, options);
3820
+ }
3821
+ };
3822
+ const valid = () => revision === (runtime()?.getPointerDragState().revision ?? -1) && !runtime()?.isInteractionLocked();
3823
+ const clear = () => {
3824
+ anchor = void 0;
3825
+ revision = -1;
3826
+ pending = void 0;
3827
+ displayed = void 0;
3828
+ samples = [];
3829
+ };
3830
+ return {
3831
+ start(point, at = performance.now()) {
3832
+ gestureSpeed = DEFAULT_POINTER_DRAG_SPEED;
3833
+ gestureInvert = false;
3834
+ samples = [];
3835
+ remember(point, at);
3836
+ place(point);
3837
+ },
3838
+ valid,
3839
+ clear,
3840
+ suspend: () => {
3841
+ anchor = void 0;
3842
+ pending = void 0;
3843
+ displayed = void 0;
3844
+ samples = [];
3845
+ },
3846
+ move(point, previous, speed, invert, at = performance.now()) {
3847
+ fresh = true;
3848
+ gestureSpeed = speed;
3849
+ gestureInvert = invert;
3850
+ remember(point, at);
3851
+ pending = { point, previous: lastPoint ?? previous, speed, invert };
3852
+ },
3853
+ flush(deltaSeconds = lastFrameDelta, immediate = false, releaseVelocity) {
3854
+ if (deltaSeconds > 0) lastFrameDelta = deltaSeconds;
3855
+ if (!pending) return;
3856
+ const sample = pending;
3857
+ if (!anchor || immediate) {
3858
+ pending = void 0;
3859
+ apply(sample.point, sample.previous, sample.speed, sample.invert, fresh, releaseVelocity);
3860
+ fresh = false;
3861
+ lastPoint = sample.point;
3862
+ displayed = sample.point;
3863
+ return;
3864
+ }
3865
+ const dt = deltaSeconds > 0 ? deltaSeconds : lastFrameDelta;
3866
+ const previousDisplay = displayed ?? sample.previous;
3867
+ const dx = sample.point.x - previousDisplay.x;
3868
+ const dy = sample.point.y - previousDisplay.y;
3869
+ const distance = Math.hypot(dx, dy);
3870
+ const ratio = distance > 0.01 ? POINTER_FOLLOW_TIME_SECONDS / (POINTER_FOLLOW_TIME_SECONDS + dt) : 0;
3871
+ const point = { x: sample.point.x - dx * ratio, y: sample.point.y - dy * ratio };
3872
+ apply(point, sample.previous, sample.speed, sample.invert, fresh);
3873
+ fresh = false;
3874
+ lastPoint = sample.point;
3875
+ displayed = point;
3876
+ if (ratio === 0) pending = void 0;
3877
+ },
3878
+ release() {
3879
+ const handle = runtime();
3880
+ if (!handle || !valid()) {
3881
+ clear();
3882
+ return;
3883
+ }
3884
+ const newestAt = samples[samples.length - 1]?.at ?? 0;
3885
+ const velocity = pointerReleaseVelocity(samples, Math.max(performance.now(), newestAt), (point) => {
3886
+ if (anchor) return anchor.solve(point, gestureSpeed, gestureInvert);
3887
+ const origin = samples[0] ?? point;
3888
+ const rect = element.getBoundingClientRect();
3889
+ const sign = gestureInvert ? -1 : 1;
3890
+ return {
3891
+ yaw: -(point.x - origin.x) * 360 * gestureSpeed / Math.max(rect.width, 1) * sign,
3892
+ pitch: (point.y - origin.y) * 180 * gestureSpeed / Math.max(rect.height, 1) * sign
3893
+ };
3894
+ });
3895
+ if (pending) this.flush(lastFrameDelta, true, velocity);
3896
+ else handle.applyViewDelta({}, { velocity, source });
3897
+ clear();
3898
+ }
3899
+ };
3900
+ }
3901
+
3902
+ // src/mouse-controls.tsx
3673
3903
  var DEFAULT_ROTATE_SPEED2 = 0.35;
3674
3904
  var DEFAULT_ZOOM_SPEED2 = 0.08;
3675
3905
  var BUTTON_FLAG = {
@@ -3680,6 +3910,9 @@ var BUTTON_FLAG = {
3680
3910
  function resolveSpeed2(value, fallback) {
3681
3911
  return Number.isFinite(value) && value >= 0 ? value : fallback;
3682
3912
  }
3913
+ function pointerAt(event) {
3914
+ return event.timeStamp > 0 ? event.timeStamp : performance.now();
3915
+ }
3683
3916
  function resolveButtons(buttons) {
3684
3917
  const list = buttons && buttons.length > 0 ? buttons : ["left"];
3685
3918
  return new Set(list.map((button) => BUTTON_FLAG[button]));
@@ -3695,7 +3928,9 @@ function MouseControls({
3695
3928
  }) {
3696
3929
  useClaimControlChannel("mouse");
3697
3930
  const controlsRef = useContext5(PanoramaViewContext);
3698
- const { gl } = useThree3();
3931
+ const { gl, camera } = useThree3();
3932
+ const validateDragRef = useRef5(void 0);
3933
+ useFrame4((_, delta) => validateDragRef.current?.(delta), -1);
3699
3934
  const pointersRef = useRef5(
3700
3935
  /* @__PURE__ */ new Map()
3701
3936
  );
@@ -3718,6 +3953,7 @@ function MouseControls({
3718
3953
  };
3719
3954
  useEffect5(() => {
3720
3955
  const element = gl.domElement;
3956
+ const drag = createPointerDrag(camera, element, () => controlsRef.current, "mouse");
3721
3957
  const allowedButtons = resolveButtons(buttons);
3722
3958
  const clearPointers = () => {
3723
3959
  for (const pointerId of pointersRef.current.keys()) {
@@ -3726,8 +3962,13 @@ function MouseControls({
3726
3962
  }
3727
3963
  }
3728
3964
  pointersRef.current.clear();
3965
+ drag.clear();
3729
3966
  controlsRef.current?.setPointerActive("mouse", false, { cancelled: true });
3730
3967
  };
3968
+ validateDragRef.current = (delta) => {
3969
+ if (pointersRef.current.size && !drag.valid()) clearPointers();
3970
+ else drag.flush(delta);
3971
+ };
3731
3972
  if (!enabled) {
3732
3973
  clearPointers();
3733
3974
  return;
@@ -3758,6 +3999,7 @@ function MouseControls({
3758
3999
  });
3759
4000
  element.setPointerCapture?.(event.pointerId);
3760
4001
  syncActive();
4002
+ drag.start({ x: event.clientX, y: event.clientY }, pointerAt(event));
3761
4003
  };
3762
4004
  const onPointerMove = (event) => {
3763
4005
  if (!isMouseLike(event)) {
@@ -3777,23 +4019,15 @@ function MouseControls({
3777
4019
  at: performance.now()
3778
4020
  };
3779
4021
  pointersRef.current.set(event.pointerId, next);
3780
- const rect = element.getBoundingClientRect();
3781
- const speed = resolveSpeed2(
3782
- optionsRef.current.rotateSpeed,
3783
- DEFAULT_ROTATE_SPEED2
3784
- );
3785
- const sign = optionsRef.current.invert ? -1 : 1;
3786
- const deltaYaw = sign * -(next.x - previous.x) * 360 * speed / Math.max(rect.width, 1);
3787
- const deltaPitch = sign * (next.y - previous.y) * 180 * speed / Math.max(rect.height, 1);
3788
- controlsRef.current?.applyViewDelta(
3789
- { yaw: deltaYaw, pitch: deltaPitch },
3790
- { recordVelocity: true, source: "mouse" }
3791
- );
4022
+ const speed = resolveSpeed2(optionsRef.current.rotateSpeed, DEFAULT_ROTATE_SPEED2);
4023
+ drag.move(next, previous, speed, optionsRef.current.invert, pointerAt(event));
3792
4024
  };
3793
4025
  const releasePointer = (event) => {
3794
4026
  if (!pointersRef.current.has(event.pointerId)) {
3795
4027
  return;
3796
4028
  }
4029
+ if (event.type === "pointerup") drag.release();
4030
+ else drag.clear();
3797
4031
  pointersRef.current.delete(event.pointerId);
3798
4032
  if (element.hasPointerCapture?.(event.pointerId)) {
3799
4033
  element.releasePointerCapture?.(event.pointerId);
@@ -3830,6 +4064,7 @@ function MouseControls({
3830
4064
  element.addEventListener("lostpointercapture", releasePointer);
3831
4065
  element.addEventListener("wheel", onWheel, { passive: false });
3832
4066
  return () => {
4067
+ validateDragRef.current = void 0;
3833
4068
  element.removeEventListener("pointerdown", onPointerDown);
3834
4069
  element.removeEventListener("pointermove", onPointerMove);
3835
4070
  element.removeEventListener("pointerup", releasePointer);
@@ -3838,7 +4073,7 @@ function MouseControls({
3838
4073
  element.removeEventListener("wheel", onWheel);
3839
4074
  clearPointers();
3840
4075
  };
3841
- }, [buttons, controlsRef, enabled, gl]);
4076
+ }, [buttons, controlsRef, enabled, gl, camera]);
3842
4077
  return null;
3843
4078
  }
3844
4079
 
@@ -4863,7 +5098,7 @@ function PanoCursorController({
4863
5098
  }
4864
5099
 
4865
5100
  // src/pano-events.tsx
4866
- import { useFrame as useFrame4, useThree as useThree5 } from "@react-three/fiber";
5101
+ import { useFrame as useFrame5, useThree as useThree5 } from "@react-three/fiber";
4867
5102
  import { useContext as useContext10, useEffect as useEffect9, useRef as useRef9 } from "react";
4868
5103
  var DEFAULT_IDLE_TIME_MS = 2e3;
4869
5104
  function resolveIdleTime(value) {
@@ -5118,7 +5353,7 @@ function usePanoEvents({
5118
5353
  observer.disconnect();
5119
5354
  };
5120
5355
  }, [gl]);
5121
- useFrame4((_, deltaSeconds) => {
5356
+ useFrame5((_, deltaSeconds) => {
5122
5357
  const interacting = controlsRef.current?.isUserInteracting() ?? false;
5123
5358
  if (interacting) {
5124
5359
  idleElapsedRef.current = 0;
@@ -5276,10 +5511,10 @@ function usePanoOverlayHost(isFullscreen) {
5276
5511
  // src/panorama-event-surface.tsx
5277
5512
  import { useThree as useThree6 } from "@react-three/fiber";
5278
5513
  import { useContext as useContext12, useEffect as useEffect10 } from "react";
5279
- import { BackSide, Raycaster, Vector2, Vector3 as Vector32 } from "three";
5514
+ import { BackSide, Raycaster, Vector2, Vector3 as Vector33 } from "three";
5280
5515
 
5281
5516
  // src/hotspot/coordinates.ts
5282
- import { MathUtils as MathUtils2, Vector3 } from "three";
5517
+ import { MathUtils as MathUtils3, Vector3 as Vector32 } from "three";
5283
5518
 
5284
5519
  // src/hotspot/types.ts
5285
5520
  var MAX_HOTSPOT_PITCH = 90;
@@ -5302,13 +5537,13 @@ function normalizePanoYaw(yaw) {
5302
5537
  if (!Number.isFinite(yaw)) {
5303
5538
  return 0;
5304
5539
  }
5305
- return MathUtils2.euclideanModulo(yaw + 180, 360) - 180;
5540
+ return MathUtils3.euclideanModulo(yaw + 180, 360) - 180;
5306
5541
  }
5307
5542
  function clampPanoPitch(pitch) {
5308
5543
  if (!Number.isFinite(pitch)) {
5309
5544
  return 0;
5310
5545
  }
5311
- const clamped = MathUtils2.clamp(
5546
+ const clamped = MathUtils3.clamp(
5312
5547
  pitch,
5313
5548
  -MAX_HOTSPOT_PITCH,
5314
5549
  MAX_HOTSPOT_PITCH
@@ -5325,10 +5560,10 @@ function normalizePanoPosition(position) {
5325
5560
  function panoPositionToVector3(position, radius = 1) {
5326
5561
  const normalized = normalizePanoPosition(position);
5327
5562
  const safeRadius = Number.isFinite(radius) ? Math.max(0, radius) : 1;
5328
- const yaw = MathUtils2.degToRad(normalized.yaw);
5329
- const pitch = MathUtils2.degToRad(normalized.pitch);
5563
+ const yaw = MathUtils3.degToRad(normalized.yaw);
5564
+ const pitch = MathUtils3.degToRad(normalized.pitch);
5330
5565
  const cosPitch = Math.cos(pitch);
5331
- return new Vector3(
5566
+ return new Vector32(
5332
5567
  cosPitch * Math.sin(yaw) * safeRadius,
5333
5568
  Math.sin(pitch) * safeRadius,
5334
5569
  -cosPitch * Math.cos(yaw) * safeRadius
@@ -5340,9 +5575,9 @@ function vector3ToPanoPosition(vector) {
5340
5575
  return { yaw: 0, pitch: 0 };
5341
5576
  }
5342
5577
  return normalizePanoPosition({
5343
- yaw: MathUtils2.radToDeg(Math.atan2(vector.x, -vector.z)),
5344
- pitch: MathUtils2.radToDeg(
5345
- Math.asin(MathUtils2.clamp(vector.y / length, -1, 1))
5578
+ yaw: MathUtils3.radToDeg(Math.atan2(vector.x, -vector.z)),
5579
+ pitch: MathUtils3.radToDeg(
5580
+ Math.asin(MathUtils3.clamp(vector.y / length, -1, 1))
5346
5581
  )
5347
5582
  });
5348
5583
  }
@@ -5377,7 +5612,7 @@ function PanoramaEventSurface() {
5377
5612
  const element = gl.domElement;
5378
5613
  const ndc = new Vector2();
5379
5614
  const raycaster = new Raycaster();
5380
- const direction = new Vector32();
5615
+ const direction = new Vector33();
5381
5616
  const handleContextMenu = (nativeEvent) => {
5382
5617
  const rect = element.getBoundingClientRect();
5383
5618
  if (rect.width <= 0 || rect.height <= 0) {
@@ -5456,9 +5691,12 @@ function notifyScenesHost(host) {
5456
5691
  }
5457
5692
 
5458
5693
  // src/touch-controls.tsx
5459
- import { useThree as useThree7 } from "@react-three/fiber";
5694
+ import { useFrame as useFrame6, useThree as useThree7 } from "@react-three/fiber";
5460
5695
  import { useContext as useContext13, useEffect as useEffect11, useRef as useRef10 } from "react";
5461
5696
  var DEFAULT_ROTATE_SPEED3 = 0.35;
5697
+ function pointerAt2(event) {
5698
+ return event.timeStamp > 0 ? event.timeStamp : performance.now();
5699
+ }
5462
5700
  function resolveSpeed3(value, fallback) {
5463
5701
  return Number.isFinite(value) && value >= 0 ? value : fallback;
5464
5702
  }
@@ -5473,7 +5711,9 @@ function TouchControls({
5473
5711
  }) {
5474
5712
  useClaimControlChannel("touch");
5475
5713
  const controlsRef = useContext13(PanoramaViewContext);
5476
- const { gl } = useThree7();
5714
+ const { gl, camera } = useThree7();
5715
+ const validateDragRef = useRef10(void 0);
5716
+ useFrame6((_, delta) => validateDragRef.current?.(delta), -1);
5477
5717
  const pointersRef = useRef10(/* @__PURE__ */ new Map());
5478
5718
  const pinchDistanceRef = useRef10(null);
5479
5719
  const optionsRef = useRef10({ rotateSpeed, invert, pinchZoom });
@@ -5483,6 +5723,7 @@ function TouchControls({
5483
5723
  optionsRef.current = { rotateSpeed, invert, pinchZoom };
5484
5724
  useEffect11(() => {
5485
5725
  const element = gl.domElement;
5726
+ const drag = createPointerDrag(camera, element, () => controlsRef.current, "touch");
5486
5727
  const clearPointers = () => {
5487
5728
  for (const pointerId of pointersRef.current.keys()) {
5488
5729
  if (element.hasPointerCapture?.(pointerId)) {
@@ -5490,9 +5731,14 @@ function TouchControls({
5490
5731
  }
5491
5732
  }
5492
5733
  pointersRef.current.clear();
5734
+ drag.clear();
5493
5735
  pinchDistanceRef.current = null;
5494
5736
  controlsRef.current?.setPointerActive("touch", false, { cancelled: true });
5495
5737
  };
5738
+ validateDragRef.current = (delta) => {
5739
+ if (pointersRef.current.size && !drag.valid()) clearPointers();
5740
+ else drag.flush(delta);
5741
+ };
5496
5742
  if (!enabled) {
5497
5743
  clearPointers();
5498
5744
  return;
@@ -5519,7 +5765,9 @@ function TouchControls({
5519
5765
  });
5520
5766
  element.setPointerCapture?.(event.pointerId);
5521
5767
  syncActive();
5522
- if (pointersRef.current.size === 2) {
5768
+ drag.start({ x: event.clientX, y: event.clientY }, pointerAt2(event));
5769
+ if (pointersRef.current.size >= 2) {
5770
+ drag.suspend();
5523
5771
  const [first, second] = Array.from(pointersRef.current.values());
5524
5772
  pinchDistanceRef.current = pointerDistance(first, second);
5525
5773
  }
@@ -5544,6 +5792,7 @@ function TouchControls({
5544
5792
  pointersRef.current.set(event.pointerId, next);
5545
5793
  const pointers = Array.from(pointersRef.current.values());
5546
5794
  if (pointers.length >= 2) {
5795
+ drag.suspend();
5547
5796
  if (!optionsRef.current.pinchZoom) {
5548
5797
  return;
5549
5798
  }
@@ -5562,23 +5811,16 @@ function TouchControls({
5562
5811
  }
5563
5812
  return;
5564
5813
  }
5565
- const rect = element.getBoundingClientRect();
5566
- const speed = resolveSpeed3(
5567
- optionsRef.current.rotateSpeed,
5568
- DEFAULT_ROTATE_SPEED3
5569
- );
5570
- const sign = optionsRef.current.invert ? -1 : 1;
5571
- const deltaYaw = sign * -(next.x - previous.x) * 360 * speed / Math.max(rect.width, 1);
5572
- const deltaPitch = sign * (next.y - previous.y) * 180 * speed / Math.max(rect.height, 1);
5573
- controlsRef.current?.applyViewDelta(
5574
- { yaw: deltaYaw, pitch: deltaPitch },
5575
- { recordVelocity: true, source: "touch" }
5576
- );
5814
+ const speed = resolveSpeed3(optionsRef.current.rotateSpeed, DEFAULT_ROTATE_SPEED3);
5815
+ drag.move(next, previous, speed, optionsRef.current.invert, pointerAt2(event));
5577
5816
  };
5578
5817
  const releasePointer = (event) => {
5579
5818
  if (!pointersRef.current.has(event.pointerId)) {
5580
5819
  return;
5581
5820
  }
5821
+ const pinch = pointersRef.current.size >= 2;
5822
+ if (event.type === "pointerup" && !pinch) drag.release();
5823
+ else drag.clear();
5582
5824
  pointersRef.current.delete(event.pointerId);
5583
5825
  if (element.hasPointerCapture?.(event.pointerId)) {
5584
5826
  element.releasePointerCapture?.(event.pointerId);
@@ -5587,6 +5829,8 @@ function TouchControls({
5587
5829
  pinchDistanceRef.current = null;
5588
5830
  }
5589
5831
  syncActive(event.type !== "pointerup");
5832
+ const remaining = pointersRef.current.values().next().value;
5833
+ if (remaining) drag.start(remaining, pointerAt2(event));
5590
5834
  };
5591
5835
  element.addEventListener("pointerdown", onPointerDown);
5592
5836
  element.addEventListener("pointermove", onPointerMove);
@@ -5594,6 +5838,7 @@ function TouchControls({
5594
5838
  element.addEventListener("pointercancel", releasePointer);
5595
5839
  element.addEventListener("lostpointercapture", releasePointer);
5596
5840
  return () => {
5841
+ validateDragRef.current = void 0;
5597
5842
  element.removeEventListener("pointerdown", onPointerDown);
5598
5843
  element.removeEventListener("pointermove", onPointerMove);
5599
5844
  element.removeEventListener("pointerup", releasePointer);
@@ -5601,7 +5846,7 @@ function TouchControls({
5601
5846
  element.removeEventListener("lostpointercapture", releasePointer);
5602
5847
  clearPointers();
5603
5848
  };
5604
- }, [controlsRef, enabled, gl]);
5849
+ }, [controlsRef, enabled, gl, camera]);
5605
5850
  return null;
5606
5851
  }
5607
5852
 
@@ -7233,8 +7478,8 @@ function WebVRChromeBridge({ host }) {
7233
7478
  }
7234
7479
 
7235
7480
  // src/webvr/stereo-view.ts
7236
- import { StereoCamera, Vector3 as Vector33 } from "three";
7237
- var PROJECT = new Vector33();
7481
+ import { StereoCamera, Vector3 as Vector34 } from "three";
7482
+ var PROJECT = new Vector34();
7238
7483
  function createWebVRStereoView() {
7239
7484
  return {
7240
7485
  active: false,
@@ -7259,17 +7504,17 @@ function projectStereoHtmlPosition(el, camera, size, eye) {
7259
7504
  }
7260
7505
 
7261
7506
  // src/webvr/xr-origin.tsx
7262
- import { useFrame as useFrame5, useThree as useThree8 } from "@react-three/fiber";
7507
+ import { useFrame as useFrame7, useThree as useThree8 } from "@react-three/fiber";
7263
7508
  import { useXR as useXR2, XROrigin } from "@react-three/xr";
7264
7509
  import { useRef as useRef12 } from "react";
7265
- import { Vector3 as Vector34 } from "three";
7510
+ import { Vector3 as Vector35 } from "three";
7266
7511
  import { jsx as jsx11 } from "react/jsx-runtime";
7267
7512
  function PanoramaXROrigin() {
7268
7513
  const originRef = useRef12(null);
7269
- const localHeadPositionRef = useRef12(new Vector34());
7514
+ const localHeadPositionRef = useRef12(new Vector35());
7270
7515
  const session2 = useXR2((state) => state.session);
7271
7516
  const gl = useThree8((state) => state.gl);
7272
- useFrame5(() => {
7517
+ useFrame7(() => {
7273
7518
  const origin = originRef.current;
7274
7519
  if (!session2 || !origin || !gl.xr.isPresenting) {
7275
7520
  return;
@@ -8018,7 +8263,7 @@ import {
8018
8263
  } from "react";
8019
8264
 
8020
8265
  // src/scenes.tsx
8021
- import { useFrame as useFrame11, useThree as useThree16 } from "@react-three/fiber";
8266
+ import { useFrame as useFrame13, useThree as useThree16 } from "@react-three/fiber";
8022
8267
  import {
8023
8268
  Fragment as Fragment4,
8024
8269
  useCallback as useCallback8,
@@ -8102,9 +8347,9 @@ function isSnapshotTransition(preset) {
8102
8347
  }
8103
8348
 
8104
8349
  // src/scene-transitions/snapshot-hold.tsx
8105
- import { useFrame as useFrame6, useThree as useThree9 } from "@react-three/fiber";
8350
+ import { useFrame as useFrame8, useThree as useThree9 } from "@react-three/fiber";
8106
8351
  import { useEffect as useEffect14, useMemo as useMemo9, useRef as useRef14 } from "react";
8107
- import { Vector3 as Vector36 } from "three";
8352
+ import { Vector3 as Vector37 } from "three";
8108
8353
 
8109
8354
  // src/scene-transitions/overlay-utils.ts
8110
8355
  import { PlaneGeometry } from "three";
@@ -8440,13 +8685,13 @@ import { jsx as jsx13, jsxs as jsxs7 } from "react/jsx-runtime";
8440
8685
  function SnapshotHold({ snapshot }) {
8441
8686
  const { camera, gl } = useThree9();
8442
8687
  const meshRef = useRef14(null);
8443
- const directionRef = useRef14(new Vector36());
8688
+ const directionRef = useRef14(new Vector37());
8444
8689
  const material = useMemo9(
8445
8690
  () => createSnapshotMaterial("crossfade", snapshot.texture),
8446
8691
  [snapshot.texture]
8447
8692
  );
8448
8693
  useEffect14(() => () => material.dispose(), [material]);
8449
- useFrame6(() => {
8694
+ useFrame8(() => {
8450
8695
  const mesh = meshRef.current;
8451
8696
  if (!mesh || !isPerspectiveCamera(camera)) {
8452
8697
  return;
@@ -8522,7 +8767,7 @@ function phaseAfterSnapshot(preset, hold) {
8522
8767
  }
8523
8768
 
8524
8769
  // src/scene-transitions/particle-overlay.tsx
8525
- import { useFrame as useFrame7, useThree as useThree10 } from "@react-three/fiber";
8770
+ import { useFrame as useFrame9, useThree as useThree10 } from "@react-three/fiber";
8526
8771
  import { useEffect as useEffect15, useMemo as useMemo10, useRef as useRef15 } from "react";
8527
8772
  import {
8528
8773
  DoubleSide as DoubleSide2,
@@ -8531,7 +8776,7 @@ import {
8531
8776
  PlaneGeometry as PlaneGeometry2,
8532
8777
  ShaderMaterial as ShaderMaterial2,
8533
8778
  Vector2 as Vector23,
8534
- Vector3 as Vector37
8779
+ Vector3 as Vector38
8535
8780
  } from "three";
8536
8781
  import { jsx as jsx14 } from "react/jsx-runtime";
8537
8782
  var PARTICLE_GRID = 48;
@@ -8613,7 +8858,7 @@ function ParticleOverlay({
8613
8858
  const meshRef = useRef15(null);
8614
8859
  const startRef = useRef15(null);
8615
8860
  const finishedRef = useRef15(false);
8616
- const directionRef = useRef15(new Vector37());
8861
+ const directionRef = useRef15(new Vector38());
8617
8862
  const geometry = useMemo10(() => createParticleGeometry(), []);
8618
8863
  const material = useMemo10(
8619
8864
  () => new ShaderMaterial2({
@@ -8638,7 +8883,7 @@ function ParticleOverlay({
8638
8883
  finishedRef.current = false;
8639
8884
  material.uniforms.progress.value = 0;
8640
8885
  }, [material, runId]);
8641
- useFrame7((state) => {
8886
+ useFrame9((state) => {
8642
8887
  const mesh = meshRef.current;
8643
8888
  if (!mesh || !isPerspectiveCamera(camera)) {
8644
8889
  return;
@@ -8668,9 +8913,9 @@ function ParticleOverlay({
8668
8913
  }
8669
8914
 
8670
8915
  // src/scene-transitions/snapshot-overlay.tsx
8671
- import { useFrame as useFrame8, useThree as useThree11 } from "@react-three/fiber";
8916
+ import { useFrame as useFrame10, useThree as useThree11 } from "@react-three/fiber";
8672
8917
  import { useEffect as useEffect16, useMemo as useMemo11, useRef as useRef16 } from "react";
8673
- import { Vector3 as Vector38 } from "three";
8918
+ import { Vector3 as Vector39 } from "three";
8674
8919
  import { jsx as jsx15, jsxs as jsxs8 } from "react/jsx-runtime";
8675
8920
  function SnapshotOverlay({
8676
8921
  snapshot,
@@ -8683,7 +8928,7 @@ function SnapshotOverlay({
8683
8928
  const meshRef = useRef16(null);
8684
8929
  const startRef = useRef16(null);
8685
8930
  const finishedRef = useRef16(false);
8686
- const directionRef = useRef16(new Vector38());
8931
+ const directionRef = useRef16(new Vector39());
8687
8932
  const material = useMemo11(() => {
8688
8933
  if (!isSnapshotTransition(transition.preset)) {
8689
8934
  return null;
@@ -8698,7 +8943,7 @@ function SnapshotOverlay({
8698
8943
  material.uniforms.progress.value = 0;
8699
8944
  }
8700
8945
  }, [material, runId]);
8701
- useFrame8((state) => {
8946
+ useFrame10((state) => {
8702
8947
  const mesh = meshRef.current;
8703
8948
  if (!mesh || !material || !isPerspectiveCamera(camera)) {
8704
8949
  return;
@@ -8778,7 +9023,7 @@ import {
8778
9023
  BackSide as BackSide2,
8779
9024
  LinearFilter,
8780
9025
  LinearMipmapLinearFilter,
8781
- MathUtils as MathUtils3,
9026
+ MathUtils as MathUtils4,
8782
9027
  RepeatWrapping,
8783
9028
  SRGBColorSpace,
8784
9029
  TextureLoader
@@ -9144,7 +9389,7 @@ function Sphere({
9144
9389
  return /* @__PURE__ */ jsxs9(
9145
9390
  "mesh",
9146
9391
  {
9147
- rotation: [0, MathUtils3.degToRad(90 + yawOffset2), 0],
9392
+ rotation: [0, MathUtils4.degToRad(90 + yawOffset2), 0],
9148
9393
  visible,
9149
9394
  children: [
9150
9395
  /* @__PURE__ */ jsx18("sphereGeometry", { args: [DEFAULT_PANORAMA_RADIUS, 128, 64] }),
@@ -9162,9 +9407,9 @@ function Sphere({
9162
9407
  }
9163
9408
 
9164
9409
  // src/sphere-tile/sphere-tile.tsx
9165
- import { useFrame as useFrame9, useThree as useThree14 } from "@react-three/fiber";
9410
+ import { useFrame as useFrame11, useThree as useThree14 } from "@react-three/fiber";
9166
9411
  import { memo, useCallback as useCallback7, useEffect as useEffect20, useMemo as useMemo15, useRef as useRef20, useState as useState9 } from "react";
9167
- import { BackSide as BackSide3, Frustum, Matrix4 as Matrix42, PerspectiveCamera as PerspectiveCamera3 } from "three";
9412
+ import { BackSide as BackSide3, Frustum, Matrix4 as Matrix42, PerspectiveCamera as PerspectiveCamera4 } from "three";
9168
9413
 
9169
9414
  // src/tile/texture-manager.ts
9170
9415
  import {
@@ -9516,8 +9761,8 @@ import {
9516
9761
  Box3,
9517
9762
  BufferGeometry,
9518
9763
  Float32BufferAttribute,
9519
- MathUtils as MathUtils4,
9520
- Vector3 as Vector39
9764
+ MathUtils as MathUtils5,
9765
+ Vector3 as Vector310
9521
9766
  } from "three";
9522
9767
  function positiveInteger2(value, name) {
9523
9768
  if (!Number.isSafeInteger(value) || value <= 0) {
@@ -9589,9 +9834,9 @@ function sphereTileRange(address) {
9589
9834
  };
9590
9835
  }
9591
9836
  function spherePoint(u, v, yawOffset2 = 0, radius = DEFAULT_PANORAMA_RADIUS) {
9592
- const yaw = (u - 0.5) * Math.PI * 2 + MathUtils4.degToRad(yawOffset2);
9837
+ const yaw = (u - 0.5) * Math.PI * 2 + MathUtils5.degToRad(yawOffset2);
9593
9838
  const pitch = (0.5 - v) * Math.PI;
9594
- return new Vector39(
9839
+ return new Vector310(
9595
9840
  Math.sin(yaw) * Math.cos(pitch) * radius,
9596
9841
  Math.sin(pitch) * radius,
9597
9842
  -Math.cos(yaw) * Math.cos(pitch) * radius
@@ -9821,7 +10066,7 @@ function SphereTileSource({
9821
10066
  const targetKeysRef = useRef20([]);
9822
10067
  const scratch = useMemo15(
9823
10068
  () => ({
9824
- camera: new PerspectiveCamera3(),
10069
+ camera: new PerspectiveCamera4(),
9825
10070
  frustum: new Frustum(),
9826
10071
  matrix: new Matrix42(),
9827
10072
  quaternion: camera.quaternion.clone(),
@@ -9837,8 +10082,8 @@ function SphereTileSource({
9837
10082
  }),
9838
10083
  [camera, candidates]
9839
10084
  );
9840
- useFrame9(() => {
9841
- if (!(camera instanceof PerspectiveCamera3)) return;
10085
+ useFrame11(() => {
10086
+ if (!(camera instanceof PerspectiveCamera4)) return;
9842
10087
  const now = performance.now(), dpr = gl.getPixelRatio();
9843
10088
  const managerChanged = scratch.manager !== manager;
9844
10089
  const loadModeChanged = scratch.loadMode !== loadMode;
@@ -9940,22 +10185,22 @@ function SphereTile({ multires, ...props }) {
9940
10185
  }
9941
10186
 
9942
10187
  // src/tile/tile.tsx
9943
- import { useFrame as useFrame10, useThree as useThree15 } from "@react-three/fiber";
10188
+ import { useFrame as useFrame12, useThree as useThree15 } from "@react-three/fiber";
9944
10189
  import { memo as memo2, useEffect as useEffect21, useMemo as useMemo16, useRef as useRef21, useState as useState10 } from "react";
9945
10190
  import {
9946
10191
  Frustum as Frustum2,
9947
10192
  Matrix4 as Matrix43,
9948
10193
  PlaneGeometry as PlaneGeometry3,
9949
- PerspectiveCamera as PerspectiveCamera4,
9950
- Vector3 as Vector311
10194
+ PerspectiveCamera as PerspectiveCamera5,
10195
+ Vector3 as Vector312
9951
10196
  } from "three";
9952
10197
 
9953
10198
  // src/tile/face-layout.ts
9954
10199
  import {
9955
10200
  Box3 as Box32,
9956
- Euler as Euler2,
10201
+ Euler as Euler3,
9957
10202
  Quaternion,
9958
- Vector3 as Vector310
10203
+ Vector3 as Vector311
9959
10204
  } from "three";
9960
10205
  var CUBE_FACES = ["f", "r", "b", "l", "u", "d"];
9961
10206
  var PREVIEW_FACE_ORDER = ["l", "f", "r", "b", "u", "d"];
@@ -10008,7 +10253,7 @@ function getFaceQuaternion(face) {
10008
10253
  }
10009
10254
  const transform = getFaceTransform(face);
10010
10255
  const quaternion = new Quaternion().setFromEuler(
10011
- new Euler2(...transform.rotation, "XYZ")
10256
+ new Euler3(...transform.rotation, "XYZ")
10012
10257
  );
10013
10258
  faceQuaternionCache.set(face, quaternion);
10014
10259
  return quaternion;
@@ -10019,12 +10264,12 @@ function getTileBoundingBox(address, radius = CUBE_RADIUS) {
10019
10264
  const halfWidth = local.width / 2;
10020
10265
  const halfHeight = local.height / 2;
10021
10266
  const quaternion = getFaceQuaternion(address.face);
10022
- const position = new Vector310(...transform.position);
10267
+ const position = new Vector311(...transform.position);
10023
10268
  const corners = [
10024
- new Vector310(local.x - halfWidth, local.y - halfHeight, 0),
10025
- new Vector310(local.x + halfWidth, local.y - halfHeight, 0),
10026
- new Vector310(local.x - halfWidth, local.y + halfHeight, 0),
10027
- new Vector310(local.x + halfWidth, local.y + halfHeight, 0)
10269
+ new Vector311(local.x - halfWidth, local.y - halfHeight, 0),
10270
+ new Vector311(local.x + halfWidth, local.y - halfHeight, 0),
10271
+ new Vector311(local.x - halfWidth, local.y + halfHeight, 0),
10272
+ new Vector311(local.x + halfWidth, local.y + halfHeight, 0)
10028
10273
  ];
10029
10274
  for (const corner of corners) {
10030
10275
  corner.applyQuaternion(quaternion).add(position);
@@ -10298,8 +10543,8 @@ function parentAddresses(child, parentLevel, parentFaceSize, tileSize) {
10298
10543
  return addresses;
10299
10544
  }
10300
10545
  function centerFacingAddress(candidates, camera) {
10301
- const direction = camera.getWorldDirection(new Vector311());
10302
- const center = new Vector311();
10546
+ const direction = camera.getWorldDirection(new Vector312());
10547
+ const center = new Vector312();
10303
10548
  let bestCandidate = candidates[0];
10304
10549
  let bestAlignment = -Infinity;
10305
10550
  for (const candidate of candidates) {
@@ -10446,7 +10691,7 @@ function Tile({
10446
10691
  const lastViewportRef = useRef21({ width: 0, height: 0, dpr: 0 });
10447
10692
  const frustumRef = useRef21(new Frustum2());
10448
10693
  const projectionMatrixRef = useRef21(new Matrix43());
10449
- const visibilityCameraRef = useRef21(new PerspectiveCamera4());
10694
+ const visibilityCameraRef = useRef21(new PerspectiveCamera5());
10450
10695
  const trackedLoadModeRef = useRef21(loadMode);
10451
10696
  const targetKeysRef = useRef21([]);
10452
10697
  const detailTokenRef = useRef21("");
@@ -10473,8 +10718,8 @@ function Tile({
10473
10718
  setLayers(nextLayers);
10474
10719
  }
10475
10720
  };
10476
- useFrame10(() => {
10477
- if (!(camera instanceof PerspectiveCamera4)) {
10721
+ useFrame12(() => {
10722
+ if (!(camera instanceof PerspectiveCamera5)) {
10478
10723
  return;
10479
10724
  }
10480
10725
  if (loadMode === "preview") {
@@ -10644,7 +10889,7 @@ function SnapshotCapture({
10644
10889
  },
10645
10890
  []
10646
10891
  );
10647
- useFrame11(() => {
10892
+ useFrame13(() => {
10648
10893
  if (requestId === 0 || requestId === capturedRequestRef.current) {
10649
10894
  return;
10650
10895
  }
@@ -11220,7 +11465,7 @@ import {
11220
11465
  } from "three";
11221
11466
 
11222
11467
  // src/hotspot/hotspot-anchor.tsx
11223
- import { useFrame as useFrame14, useThree as useThree19 } from "@react-three/fiber";
11468
+ import { useFrame as useFrame16, useThree as useThree19 } from "@react-three/fiber";
11224
11469
  import {
11225
11470
  useContext as useContext21,
11226
11471
  useEffect as useEffect24,
@@ -11232,20 +11477,20 @@ import {
11232
11477
  import {
11233
11478
  Box3 as Box34,
11234
11479
  EdgesGeometry,
11235
- MathUtils as MathUtils7,
11480
+ MathUtils as MathUtils8,
11236
11481
  Matrix4 as Matrix44,
11237
11482
  Plane,
11238
11483
  PlaneGeometry as PlaneGeometry4,
11239
11484
  Quaternion as Quaternion3,
11240
11485
  Ray,
11241
- Vector3 as Vector315
11486
+ Vector3 as Vector316
11242
11487
  } from "three";
11243
11488
 
11244
11489
  // src/hotspot/hotspot-tooltip.tsx
11245
11490
  import { useEffect as useEffect23, useMemo as useMemo18, useState as useState12 } from "react";
11246
11491
 
11247
11492
  // src/webvr/stereo-html.tsx
11248
- import { useFrame as useFrame12, useThree as useThree17 } from "@react-three/fiber";
11493
+ import { useFrame as useFrame14, useThree as useThree17 } from "@react-three/fiber";
11249
11494
  import {
11250
11495
  useContext as useContext20,
11251
11496
  useLayoutEffect as useLayoutEffect5,
@@ -11253,7 +11498,7 @@ import {
11253
11498
  useSyncExternalStore as useSyncExternalStore7
11254
11499
  } from "react";
11255
11500
  import { createRoot } from "react-dom/client";
11256
- import { Vector3 as Vector312 } from "three";
11501
+ import { Vector3 as Vector313 } from "three";
11257
11502
  import { Fragment as Fragment5, jsx as jsx23, jsxs as jsxs13 } from "react/jsx-runtime";
11258
11503
  function useFallbackStereoView() {
11259
11504
  const runtime = useContext20(WebVRRuntimeContext);
@@ -11276,7 +11521,7 @@ function ProjectedHtml({
11276
11521
  const { camera, gl, events, size } = useThree17();
11277
11522
  const group = useRef23(null);
11278
11523
  const overlay = useRef23(null);
11279
- const scratch = useRef23(new Vector312());
11524
+ const scratch = useRef23(new Vector313());
11280
11525
  const target = events.connected || gl.domElement.parentElement;
11281
11526
  const updatePosition = () => {
11282
11527
  const anchor = group.current;
@@ -11335,7 +11580,7 @@ function ProjectedHtml({
11335
11580
  );
11336
11581
  updatePosition();
11337
11582
  });
11338
- useFrame12(updatePosition);
11583
+ useFrame14(updatePosition);
11339
11584
  return /* @__PURE__ */ jsx23("group", { ref: group });
11340
11585
  }
11341
11586
  function PanoHtml(props) {
@@ -11477,21 +11722,21 @@ function HotspotTooltip({
11477
11722
 
11478
11723
  // src/hotspot/transform.ts
11479
11724
  import {
11480
- MathUtils as MathUtils5,
11481
- PerspectiveCamera as PerspectiveCamera5,
11482
- Vector3 as Vector313
11725
+ MathUtils as MathUtils6,
11726
+ PerspectiveCamera as PerspectiveCamera6,
11727
+ Vector3 as Vector314
11483
11728
  } from "three";
11484
- var LOCAL_FORWARD = new Vector313(0, 0, 1);
11485
- var CAMERA_POSITION = new Vector313();
11729
+ var LOCAL_FORWARD = new Vector314(0, 0, 1);
11730
+ var CAMERA_POSITION = new Vector314();
11486
11731
  function applyHotspotTransform(group, camera, orientation2, surfaceQuaternion3, rotation, scaleMode, referenceFov, useAngularScale, worldWidth, worldHeight, distance) {
11487
11732
  if (orientation2 === "billboard") {
11488
11733
  group.quaternion.copy(camera.quaternion);
11489
11734
  } else {
11490
11735
  group.quaternion.copy(surfaceQuaternion3);
11491
11736
  }
11492
- group.rotateOnAxis(LOCAL_FORWARD, MathUtils5.degToRad(-rotation));
11493
- let scaleFactor = scaleMode === "fixed" && camera instanceof PerspectiveCamera5 ? fixedScaleFactor(camera.fov, referenceFov) : 1;
11494
- if (scaleMode === "fixed" && orientation2 === "billboard" && useAngularScale && camera instanceof PerspectiveCamera5) {
11737
+ group.rotateOnAxis(LOCAL_FORWARD, MathUtils6.degToRad(-rotation));
11738
+ let scaleFactor = scaleMode === "fixed" && camera instanceof PerspectiveCamera6 ? fixedScaleFactor(camera.fov, referenceFov) : 1;
11739
+ if (scaleMode === "fixed" && orientation2 === "billboard" && useAngularScale && camera instanceof PerspectiveCamera6) {
11495
11740
  group.updateWorldMatrix(true, false);
11496
11741
  CAMERA_POSITION.setFromMatrixPosition(group.matrixWorld).applyMatrix4(
11497
11742
  camera.matrixWorldInverse
@@ -11506,21 +11751,21 @@ function applyHotspotTransform(group, camera, orientation2, surfaceQuaternion3,
11506
11751
  group.updateMatrixWorld();
11507
11752
  }
11508
11753
  function fixedScaleFactor(cameraFov, referenceFov) {
11509
- const safeReferenceFov = MathUtils5.clamp(referenceFov, 1, 179);
11510
- return Math.tan(MathUtils5.degToRad(cameraFov) / 2) / Math.tan(MathUtils5.degToRad(safeReferenceFov) / 2);
11754
+ const safeReferenceFov = MathUtils6.clamp(referenceFov, 1, 179);
11755
+ return Math.tan(MathUtils6.degToRad(cameraFov) / 2) / Math.tan(MathUtils6.degToRad(safeReferenceFov) / 2);
11511
11756
  }
11512
11757
 
11513
11758
  // src/hotspot/hotspot-stroke-line.tsx
11514
11759
  import { Line } from "@react-three/drei";
11515
- import { useFrame as useFrame13, useThree as useThree18 } from "@react-three/fiber";
11760
+ import { useFrame as useFrame15, useThree as useThree18 } from "@react-three/fiber";
11516
11761
  import { useLayoutEffect as useLayoutEffect6, useRef as useRef24 } from "react";
11517
11762
  import {
11518
- MathUtils as MathUtils6,
11519
- PerspectiveCamera as PerspectiveCamera6,
11520
- Vector3 as Vector314
11763
+ MathUtils as MathUtils7,
11764
+ PerspectiveCamera as PerspectiveCamera7,
11765
+ Vector3 as Vector315
11521
11766
  } from "three";
11522
11767
  import { jsx as jsx25 } from "react/jsx-runtime";
11523
- var LINE_WORLD_POSITION = new Vector314();
11768
+ var LINE_WORLD_POSITION = new Vector315();
11524
11769
  function applyScreenSpaceDashScale(object, camera, viewportHeight) {
11525
11770
  const material = object?.material;
11526
11771
  if (!object || typeof material?.dashScale !== "number") {
@@ -11528,8 +11773,8 @@ function applyScreenSpaceDashScale(object, camera, viewportHeight) {
11528
11773
  }
11529
11774
  object.getWorldPosition(LINE_WORLD_POSITION);
11530
11775
  const depth = Math.max(camera.position.distanceTo(LINE_WORLD_POSITION), 1);
11531
- const fov = camera instanceof PerspectiveCamera6 ? camera.fov : 75;
11532
- material.dashScale = viewportHeight / (2 * Math.tan(MathUtils6.degToRad(fov) * 0.5) * depth);
11776
+ const fov = camera instanceof PerspectiveCamera7 ? camera.fov : 75;
11777
+ material.dashScale = viewportHeight / (2 * Math.tan(MathUtils7.degToRad(fov) * 0.5) * depth);
11533
11778
  }
11534
11779
  function resolveDash(dashSize, gapSize) {
11535
11780
  if (dashSize === void 0 || !Number.isFinite(dashSize) || dashSize <= 0) {
@@ -11559,7 +11804,7 @@ function HotspotStrokeLine({
11559
11804
  }
11560
11805
  applyScreenSpaceDashScale(lineRef.current, camera, size.height);
11561
11806
  }, [camera, dash.dashed, dash.dashSize, dash.gapSize, size.height]);
11562
- useFrame13((state) => {
11807
+ useFrame15((state) => {
11563
11808
  if (!dash.dashed) {
11564
11809
  return;
11565
11810
  }
@@ -11604,25 +11849,25 @@ var SELECTION_BORDER_POINTS = [
11604
11849
  ];
11605
11850
  var TOOLTIP_WORLD_BOX = new Box34();
11606
11851
  var TOOLTIP_LOCAL_BOX = new Box34();
11607
- var TOOLTIP_CORNER = new Vector315();
11852
+ var TOOLTIP_CORNER = new Vector316();
11608
11853
  var TOOLTIP_INVERSE = new Matrix44();
11609
- var TOOLTIP_WORLD_CORNER = new Vector315();
11610
- var TOOLTIP_PROJECTED = new Vector315();
11611
- var TOOLTIP_RAY_ORIGIN = new Vector315();
11612
- var TOOLTIP_RAY_FAR = new Vector315();
11613
- var TOOLTIP_RAY_DIRECTION = new Vector315();
11854
+ var TOOLTIP_WORLD_CORNER = new Vector316();
11855
+ var TOOLTIP_PROJECTED = new Vector316();
11856
+ var TOOLTIP_RAY_ORIGIN = new Vector316();
11857
+ var TOOLTIP_RAY_FAR = new Vector316();
11858
+ var TOOLTIP_RAY_DIRECTION = new Vector316();
11614
11859
  var TOOLTIP_RAY = new Ray();
11615
11860
  var TOOLTIP_PLANE = new Plane();
11616
- var TOOLTIP_INTERSECTION = new Vector315();
11617
- var TOOLTIP_PLANE_NORMAL = new Vector315();
11618
- var TOOLTIP_PLANE_POINT = new Vector315();
11861
+ var TOOLTIP_INTERSECTION = new Vector316();
11862
+ var TOOLTIP_PLANE_NORMAL = new Vector316();
11863
+ var TOOLTIP_PLANE_POINT = new Vector316();
11619
11864
  var HOTSPOT_MODE_RENDERING = {
11620
11865
  surface: { orientation: "surface", placement: "surface" },
11621
11866
  billboard: { orientation: "billboard", placement: "floating" }
11622
11867
  };
11623
11868
  function angularSizeToWorldSize(size, radius) {
11624
- const safeSize = Number.isFinite(size) ? MathUtils7.clamp(Math.abs(size), MIN_ANGULAR_SIZE, MAX_ANGULAR_SIZE) : MIN_ANGULAR_SIZE;
11625
- return 2 * radius * Math.tan(MathUtils7.degToRad(safeSize) / 2);
11869
+ const safeSize = Number.isFinite(size) ? MathUtils8.clamp(Math.abs(size), MIN_ANGULAR_SIZE, MAX_ANGULAR_SIZE) : MIN_ANGULAR_SIZE;
11870
+ return 2 * radius * Math.tan(MathUtils8.degToRad(safeSize) / 2);
11626
11871
  }
11627
11872
  function resolveScale(scale) {
11628
11873
  return Number.isFinite(scale) && scale > 0 ? scale : 1;
@@ -11635,32 +11880,32 @@ function resolveDistance(placement, distance, width, height) {
11635
11880
  if (!Number.isFinite(distance)) {
11636
11881
  return DEFAULT_FLOATING_DISTANCE;
11637
11882
  }
11638
- return MathUtils7.clamp(Math.abs(distance), 0.1, maximumDistance);
11883
+ return MathUtils8.clamp(Math.abs(distance), 0.1, maximumDistance);
11639
11884
  }
11640
11885
  function maximumHotspotDistance(width, height) {
11641
- const safeWidth = MathUtils7.clamp(
11886
+ const safeWidth = MathUtils8.clamp(
11642
11887
  Math.abs(Number.isFinite(width) ? width : MIN_ANGULAR_SIZE),
11643
11888
  MIN_ANGULAR_SIZE,
11644
11889
  MAX_ANGULAR_SIZE
11645
11890
  );
11646
- const safeHeight = MathUtils7.clamp(
11891
+ const safeHeight = MathUtils8.clamp(
11647
11892
  Math.abs(Number.isFinite(height) ? height : MIN_ANGULAR_SIZE),
11648
11893
  MIN_ANGULAR_SIZE,
11649
11894
  MAX_ANGULAR_SIZE
11650
11895
  );
11651
11896
  const cornerFactor = Math.hypot(
11652
11897
  1,
11653
- Math.tan(MathUtils7.degToRad(safeWidth) / 2),
11654
- Math.tan(MathUtils7.degToRad(safeHeight) / 2)
11898
+ Math.tan(MathUtils8.degToRad(safeWidth) / 2),
11899
+ Math.tan(MathUtils8.degToRad(safeHeight) / 2)
11655
11900
  );
11656
11901
  return (PANORAMA_RADIUS - PANORAMA_SURFACE_INSET) / cornerFactor;
11657
11902
  }
11658
11903
  function createSurfaceQuaternion(position) {
11659
11904
  const outward = panoPositionToVector3(position).normalize();
11660
11905
  const inward = outward.clone().negate();
11661
- const pitch = MathUtils7.degToRad(position.pitch);
11662
- const yaw = MathUtils7.degToRad(position.yaw);
11663
- const localUp = new Vector315(
11906
+ const pitch = MathUtils8.degToRad(position.pitch);
11907
+ const yaw = MathUtils8.degToRad(position.yaw);
11908
+ const localUp = new Vector316(
11664
11909
  -Math.sin(pitch) * Math.sin(yaw),
11665
11910
  Math.cos(pitch),
11666
11911
  Math.sin(pitch) * Math.cos(yaw)
@@ -11680,7 +11925,7 @@ function makeInteractionEvent(id, position, event) {
11680
11925
  function angularDistance(a, b) {
11681
11926
  const aVector = panoPositionToVector3(a);
11682
11927
  const bVector = panoPositionToVector3(b);
11683
- return MathUtils7.radToDeg(aVector.angleTo(bVector));
11928
+ return MathUtils8.radToDeg(aVector.angleTo(bVector));
11684
11929
  }
11685
11930
  function isTooltipOpen(trigger, hovered, focused, pinned) {
11686
11931
  switch (trigger) {
@@ -12093,7 +12338,7 @@ function HotspotAnchor({
12093
12338
  worldHeight,
12094
12339
  worldWidth
12095
12340
  ]);
12096
- useFrame14((state) => {
12341
+ useFrame16((state) => {
12097
12342
  const group = groupRef.current;
12098
12343
  if (!group) {
12099
12344
  return;
@@ -12708,7 +12953,7 @@ function GraphicHotspot(props) {
12708
12953
  }
12709
12954
 
12710
12955
  // src/hotspot/sequence-hotspot.tsx
12711
- import { useFrame as useFrame15, useThree as useThree21 } from "@react-three/fiber";
12956
+ import { useFrame as useFrame17, useThree as useThree21 } from "@react-three/fiber";
12712
12957
  import { useEffect as useEffect27, useRef as useRef28, useState as useState16 } from "react";
12713
12958
  import {
12714
12959
  ClampToEdgeWrapping as ClampToEdgeWrapping5,
@@ -12863,7 +13108,7 @@ function SequenceHotspot({
12863
13108
  onPlaybackStateChangeRef.current?.(nextState);
12864
13109
  }
12865
13110
  }, [playing, texture]);
12866
- useFrame15((_, deltaSeconds) => {
13111
+ useFrame17((_, deltaSeconds) => {
12867
13112
  if (!texture || !playing || endedRef.current) {
12868
13113
  return;
12869
13114
  }
@@ -13188,7 +13433,7 @@ function VideoHotspot({
13188
13433
  }
13189
13434
 
13190
13435
  // src/hotspot/audio-hotspot.tsx
13191
- import { useFrame as useFrame16, useThree as useThree23 } from "@react-three/fiber";
13436
+ import { useFrame as useFrame18, useThree as useThree23 } from "@react-three/fiber";
13192
13437
  import { useEffect as useEffect29, useRef as useRef30, useState as useState18 } from "react";
13193
13438
  import {
13194
13439
  CanvasTexture as CanvasTexture2,
@@ -13200,10 +13445,10 @@ import {
13200
13445
  } from "three";
13201
13446
 
13202
13447
  // src/hotspot/audio-spatial.ts
13203
- import { MathUtils as MathUtils8, Vector3 as Vector316 } from "three";
13204
- var LOOK_DIR = new Vector316();
13205
- var SOURCE_DIR = new Vector316();
13206
- var RIGHT_DIR = new Vector316();
13448
+ import { MathUtils as MathUtils9, Vector3 as Vector317 } from "three";
13449
+ var LOOK_DIR = new Vector317();
13450
+ var SOURCE_DIR = new Vector317();
13451
+ var RIGHT_DIR = new Vector317();
13207
13452
  function clampAudioVolume(volume) {
13208
13453
  if (!Number.isFinite(volume)) {
13209
13454
  return 1;
@@ -13228,11 +13473,11 @@ function lookRangeGain(angleDegrees, range) {
13228
13473
  function audioSpatialFromView(camera, position, range) {
13229
13474
  camera.getWorldDirection(LOOK_DIR);
13230
13475
  SOURCE_DIR.copy(panoPositionToVector3(position)).normalize();
13231
- const angleDegrees = MathUtils8.radToDeg(
13232
- Math.acos(MathUtils8.clamp(LOOK_DIR.dot(SOURCE_DIR), -1, 1))
13476
+ const angleDegrees = MathUtils9.radToDeg(
13477
+ Math.acos(MathUtils9.clamp(LOOK_DIR.dot(SOURCE_DIR), -1, 1))
13233
13478
  );
13234
13479
  RIGHT_DIR.set(1, 0, 0).applyQuaternion(camera.quaternion);
13235
- const pan = MathUtils8.clamp(
13480
+ const pan = MathUtils9.clamp(
13236
13481
  Math.atan2(SOURCE_DIR.dot(RIGHT_DIR), SOURCE_DIR.dot(LOOK_DIR)) / (Math.PI / 2),
13237
13482
  -1,
13238
13483
  1
@@ -13521,7 +13766,7 @@ function AudioHotspot({
13521
13766
  document.removeEventListener("visibilitychange", handleVisibility);
13522
13767
  };
13523
13768
  }, [howl, pauseWhenHidden]);
13524
- useFrame16(() => {
13769
+ useFrame18(() => {
13525
13770
  if (!howl) {
13526
13771
  return;
13527
13772
  }
@@ -13539,13 +13784,13 @@ function AudioHotspot({
13539
13784
 
13540
13785
  // src/hotspot/text-hotspot.tsx
13541
13786
  import { useEffect as useEffect30, useRef as useRef31, useState as useState19 } from "react";
13542
- import { useFrame as useFrame17, useThree as useThree24 } from "@react-three/fiber";
13787
+ import { useFrame as useFrame19, useThree as useThree24 } from "@react-three/fiber";
13543
13788
  import {
13544
13789
  CanvasTexture as CanvasTexture3,
13545
13790
  ClampToEdgeWrapping as ClampToEdgeWrapping8,
13546
13791
  LinearFilter as LinearFilter10,
13547
- MathUtils as MathUtils9,
13548
- PerspectiveCamera as PerspectiveCamera7,
13792
+ MathUtils as MathUtils10,
13793
+ PerspectiveCamera as PerspectiveCamera8,
13549
13794
  SRGBColorSpace as SRGBColorSpace9
13550
13795
  } from "three";
13551
13796
  import { jsx as jsx33 } from "react/jsx-runtime";
@@ -13619,7 +13864,7 @@ function projectedDevicePixels(angleDeg, fovDeg, viewportHeight) {
13619
13864
  }
13620
13865
  const fov = Math.min(179, Math.max(1, resolvePositive(fovDeg, DEFAULT_REFERENCE_FOV2)));
13621
13866
  const angle = Math.min(179, Math.max(0.01, Math.abs(angleDeg)));
13622
- return Math.tan(MathUtils9.degToRad(angle) / 2) / Math.tan(MathUtils9.degToRad(fov) / 2) * viewportHeight;
13867
+ return Math.tan(MathUtils10.degToRad(angle) / 2) / Math.tan(MathUtils10.degToRad(fov) / 2) * viewportHeight;
13623
13868
  }
13624
13869
  function snapRasterLongSide(screenLong, layoutLong) {
13625
13870
  if (!(screenLong > 0)) {
@@ -13821,7 +14066,7 @@ function useRasterLongSide(width, height, scale, scaleMode, referenceFov) {
13821
14066
  const measure = () => {
13822
14067
  const pixelRatio = getPixelRatio();
13823
14068
  const viewportHeight = size.height * (Number.isFinite(pixelRatio) && pixelRatio > 0 ? pixelRatio : 1);
13824
- const cameraFov = camera instanceof PerspectiveCamera7 ? camera.fov : DEFAULT_REFERENCE_FOV2;
14069
+ const cameraFov = camera instanceof PerspectiveCamera8 ? camera.fov : DEFAULT_REFERENCE_FOV2;
13825
14070
  const screenLong = Math.max(
13826
14071
  projectedDevicePixels(
13827
14072
  width * resolveScale2(scale),
@@ -13845,7 +14090,7 @@ function useRasterLongSide(width, height, scale, scaleMode, referenceFov) {
13845
14090
  if (measured !== rasterLong) {
13846
14091
  setRasterLong(measured);
13847
14092
  }
13848
- useFrame17(() => {
14093
+ useFrame19(() => {
13849
14094
  const next = measure();
13850
14095
  setRasterLong((current) => current === next ? current : next);
13851
14096
  });
@@ -14099,7 +14344,7 @@ import {
14099
14344
  Quaternion as Quaternion4,
14100
14345
  ShapeUtils,
14101
14346
  Vector2 as Vector25,
14102
- Vector3 as Vector317
14347
+ Vector3 as Vector318
14103
14348
  } from "three";
14104
14349
  import { jsx as jsx35, jsxs as jsxs18 } from "react/jsx-runtime";
14105
14350
  var POLYGON_RADIUS = 990;
@@ -14173,7 +14418,7 @@ function polygonContainsDirection(vertices, direction) {
14173
14418
  }
14174
14419
  function fitsHemisphere(vertices) {
14175
14420
  const directions = vertices.map((vertex) => panoPositionToVector3(vertex).normalize());
14176
- const candidates = [new Vector317()];
14421
+ const candidates = [new Vector318()];
14177
14422
  for (const direction of directions) {
14178
14423
  candidates[0].add(direction);
14179
14424
  candidates.push(direction.clone());
@@ -14197,7 +14442,7 @@ function validatePolygonVertices(vertices) {
14197
14442
  if (hasSelfIntersection(unwrapped)) {
14198
14443
  issues.push({ code: "self_intersection", message: "Polygon edges cannot cross." });
14199
14444
  }
14200
- if (polygonContainsDirection(normalized, new Vector317(0, 1, 0)) || polygonContainsDirection(normalized, new Vector317(0, -1, 0))) {
14445
+ if (polygonContainsDirection(normalized, new Vector318(0, 1, 0)) || polygonContainsDirection(normalized, new Vector318(0, -1, 0))) {
14201
14446
  issues.push({ code: "contains_pole", message: "Polygons cannot contain a panorama pole." });
14202
14447
  }
14203
14448
  if (!fitsHemisphere(normalized)) {
@@ -14208,7 +14453,7 @@ function validatePolygonVertices(vertices) {
14208
14453
  function polygonCenter(vertices) {
14209
14454
  const sum = vertices.reduce(
14210
14455
  (total, vertex) => total.add(panoPositionToVector3(vertex).normalize()),
14211
- new Vector317()
14456
+ new Vector318()
14212
14457
  );
14213
14458
  return sum.lengthSq() > 1e-8 ? vector3ToPanoPosition(sum) : normalizePanoPosition(vertices[0]);
14214
14459
  }
@@ -14217,7 +14462,7 @@ function surfaceQuaternion(position) {
14217
14462
  const inward = outward.clone().negate();
14218
14463
  const pitch = position.pitch * Math.PI / 180;
14219
14464
  const yaw = position.yaw * Math.PI / 180;
14220
- const localUp = new Vector317(
14465
+ const localUp = new Vector318(
14221
14466
  -Math.sin(pitch) * Math.sin(yaw),
14222
14467
  Math.cos(pitch),
14223
14468
  Math.sin(pitch) * Math.cos(yaw)
@@ -14230,7 +14475,7 @@ function makeWorldToLocal(center) {
14230
14475
  return new Matrix45().compose(
14231
14476
  panoPositionToVector3(center, POLYGON_RADIUS),
14232
14477
  surfaceQuaternion(center),
14233
- new Vector317(1, 1, 1)
14478
+ new Vector318(1, 1, 1)
14234
14479
  ).invert();
14235
14480
  }
14236
14481
  function projectedPoint(a, b, c, weightB, weightC, radius, worldToLocal) {
@@ -14456,10 +14701,10 @@ function PolygonHotspot({
14456
14701
  // src/hotspot/polyline-hotspot.tsx
14457
14702
  import { useEffect as useEffect32, useMemo as useMemo21, useRef as useRef33 } from "react";
14458
14703
  import {
14459
- MathUtils as MathUtils10,
14704
+ MathUtils as MathUtils11,
14460
14705
  Matrix4 as Matrix46,
14461
14706
  Quaternion as Quaternion5,
14462
- Vector3 as Vector318
14707
+ Vector3 as Vector319
14463
14708
  } from "three";
14464
14709
  import { jsx as jsx36 } from "react/jsx-runtime";
14465
14710
  var POLYLINE_RADIUS = 990;
@@ -14486,16 +14731,16 @@ function unwrapVertices(vertices) {
14486
14731
  function polylineCenter(vertices) {
14487
14732
  const sum = vertices.reduce(
14488
14733
  (total, vertex) => total.add(panoPositionToVector3(vertex).normalize()),
14489
- new Vector318()
14734
+ new Vector319()
14490
14735
  );
14491
14736
  return sum.lengthSq() > 1e-8 ? vector3ToPanoPosition(sum) : normalizePanoPosition(vertices[0]);
14492
14737
  }
14493
14738
  function surfaceQuaternion2(position) {
14494
14739
  const outward = panoPositionToVector3(position).normalize();
14495
14740
  const inward = outward.clone().negate();
14496
- const pitch = MathUtils10.degToRad(position.pitch);
14497
- const yaw = MathUtils10.degToRad(position.yaw);
14498
- const localUp = new Vector318(
14741
+ const pitch = MathUtils11.degToRad(position.pitch);
14742
+ const yaw = MathUtils11.degToRad(position.yaw);
14743
+ const localUp = new Vector319(
14499
14744
  -Math.sin(pitch) * Math.sin(yaw),
14500
14745
  Math.cos(pitch),
14501
14746
  Math.sin(pitch) * Math.cos(yaw)
@@ -14508,7 +14753,7 @@ function makeWorldToLocal2(center) {
14508
14753
  return new Matrix46().compose(
14509
14754
  panoPositionToVector3(center, POLYLINE_RADIUS),
14510
14755
  surfaceQuaternion2(center),
14511
- new Vector318(1, 1, 1)
14756
+ new Vector319(1, 1, 1)
14512
14757
  ).invert();
14513
14758
  }
14514
14759
  function subdivisionSteps(vertices) {
@@ -14523,7 +14768,7 @@ function subdivisionSteps(vertices) {
14523
14768
  }
14524
14769
  return Math.min(
14525
14770
  8,
14526
- Math.max(1, Math.ceil(MathUtils10.radToDeg(maxAngle) / MAX_SEGMENT_DEGREES))
14771
+ Math.max(1, Math.ceil(MathUtils11.radToDeg(maxAngle) / MAX_SEGMENT_DEGREES))
14527
14772
  );
14528
14773
  }
14529
14774
  function makeLinePositions(vertices, center) {
@@ -15286,7 +15531,7 @@ function PanoFilter({
15286
15531
  }
15287
15532
 
15288
15533
  // src/gyro.tsx
15289
- import { useFrame as useFrame18, useThree as useThree25 } from "@react-three/fiber";
15534
+ import { useFrame as useFrame20, useThree as useThree25 } from "@react-three/fiber";
15290
15535
  import {
15291
15536
  forwardRef as forwardRef3,
15292
15537
  useCallback as useCallback9,
@@ -15298,12 +15543,12 @@ import {
15298
15543
  } from "react";
15299
15544
 
15300
15545
  // src/gyro-orientation.ts
15301
- import { Euler as Euler3, MathUtils as MathUtils11, Quaternion as Quaternion6, Vector3 as Vector319 } from "three";
15546
+ import { Euler as Euler4, MathUtils as MathUtils12, Quaternion as Quaternion6, Vector3 as Vector320 } from "three";
15302
15547
  var DEVICE_FORWARD_CORRECTION = new Quaternion6().setFromAxisAngle(
15303
- new Vector319(1, 0, 0),
15548
+ new Vector320(1, 0, 0),
15304
15549
  -Math.PI / 2
15305
15550
  );
15306
- var SCREEN_AXIS = new Vector319(0, 0, 1);
15551
+ var SCREEN_AXIS = new Vector320(0, 0, 1);
15307
15552
  function getScreenOrientationAngle() {
15308
15553
  if (typeof window === "undefined") {
15309
15554
  return 0;
@@ -15317,31 +15562,31 @@ function getScreenOrientationAngle() {
15317
15562
  }
15318
15563
  function deviceOrientationToQuaternion(sample, screenOrientation) {
15319
15564
  const alpha = Number.isFinite(sample.compassHeading) ? 360 - sample.compassHeading : sample.alpha;
15320
- const deviceEuler = new Euler3(
15321
- MathUtils11.degToRad(sample.beta),
15322
- MathUtils11.degToRad(alpha),
15323
- MathUtils11.degToRad(-sample.gamma),
15565
+ const deviceEuler = new Euler4(
15566
+ MathUtils12.degToRad(sample.beta),
15567
+ MathUtils12.degToRad(alpha),
15568
+ MathUtils12.degToRad(-sample.gamma),
15324
15569
  "YXZ"
15325
15570
  );
15326
15571
  const screenCorrection = new Quaternion6().setFromAxisAngle(
15327
15572
  SCREEN_AXIS,
15328
- -MathUtils11.degToRad(screenOrientation)
15573
+ -MathUtils12.degToRad(screenOrientation)
15329
15574
  );
15330
15575
  return new Quaternion6().setFromEuler(deviceEuler).multiply(DEVICE_FORWARD_CORRECTION).multiply(screenCorrection).normalize();
15331
15576
  }
15332
15577
  function quaternionToGyroPose(quaternion) {
15333
- const euler = new Euler3().setFromQuaternion(quaternion, "YXZ");
15578
+ const euler = new Euler4().setFromQuaternion(quaternion, "YXZ");
15334
15579
  return {
15335
- yaw: MathUtils11.radToDeg(-euler.y),
15336
- pitch: MathUtils11.radToDeg(euler.x),
15337
- roll: MathUtils11.radToDeg(euler.z)
15580
+ yaw: MathUtils12.radToDeg(-euler.y),
15581
+ pitch: MathUtils12.radToDeg(euler.x),
15582
+ roll: MathUtils12.radToDeg(euler.z)
15338
15583
  };
15339
15584
  }
15340
15585
  function createRelativeCalibration(deviceQuaternion, yaw, pitch) {
15341
15586
  const targetQuaternion = new Quaternion6().setFromEuler(
15342
- new Euler3(
15343
- MathUtils11.degToRad(pitch),
15344
- MathUtils11.degToRad(-yaw),
15587
+ new Euler4(
15588
+ MathUtils12.degToRad(pitch),
15589
+ MathUtils12.degToRad(-yaw),
15345
15590
  0,
15346
15591
  "YXZ"
15347
15592
  )
@@ -15686,7 +15931,7 @@ var Gyro = forwardRef3(function Gyro2({
15686
15931
  internallyDisabled,
15687
15932
  requestPermission
15688
15933
  ]);
15689
- useFrame18((_, deltaSeconds) => {
15934
+ useFrame20((_, deltaSeconds) => {
15690
15935
  const rawQuaternion = rawQuaternionRef.current;
15691
15936
  if (!activeRef.current || !rawQuaternion) {
15692
15937
  return;
@@ -15779,13 +16024,13 @@ async function detectWebVRCapabilities() {
15779
16024
  }
15780
16025
 
15781
16026
  // src/webvr/reticle.tsx
15782
- import { useFrame as useFrame19, useThree as useThree26 } from "@react-three/fiber";
16027
+ import { useFrame as useFrame21, useThree as useThree26 } from "@react-three/fiber";
15783
16028
  import { useRef as useRef36 } from "react";
15784
16029
  import {
15785
16030
  DoubleSide as DoubleSide6,
15786
16031
  Raycaster as Raycaster3,
15787
16032
  Vector2 as Vector26,
15788
- Vector3 as Vector320
16033
+ Vector3 as Vector321
15789
16034
  } from "three";
15790
16035
  import { jsx as jsx38, jsxs as jsxs19 } from "react/jsx-runtime";
15791
16036
  var CENTER_NDC = new Vector26(0, 0);
@@ -15873,13 +16118,13 @@ function WebVRReticle({
15873
16118
  }) {
15874
16119
  const groupRef = useRef36(null);
15875
16120
  const ringMeshRef = useRef36(null);
15876
- const directionRef = useRef36(new Vector320());
16121
+ const directionRef = useRef36(new Vector321());
15877
16122
  const raycasterRef = useRef36(new Raycaster3());
15878
16123
  const hoveredRef = useRef36(null);
15879
16124
  const dwellRef = useRef36(0);
15880
16125
  const clickedRef = useRef36(false);
15881
16126
  const { camera, gl, scene } = useThree26();
15882
- useFrame19((_, deltaSeconds) => {
16127
+ useFrame21((_, deltaSeconds) => {
15883
16128
  const group = groupRef.current;
15884
16129
  const ringMesh = ringMeshRef.current;
15885
16130
  if (!visible || !group) {
@@ -16039,12 +16284,12 @@ function WebVRReticle({
16039
16284
  }
16040
16285
 
16041
16286
  // src/webvr/stereo.tsx
16042
- import { useFrame as useFrame20, useThree as useThree27 } from "@react-three/fiber";
16287
+ import { useFrame as useFrame22, useThree as useThree27 } from "@react-three/fiber";
16043
16288
  import { useContext as useContext26, useEffect as useEffect36, useMemo as useMemo25, useRef as useRef37 } from "react";
16044
16289
  import {
16045
16290
  Mesh as Mesh6,
16046
16291
  OrthographicCamera,
16047
- PerspectiveCamera as PerspectiveCamera8,
16292
+ PerspectiveCamera as PerspectiveCamera9,
16048
16293
  PlaneGeometry as PlaneGeometry5,
16049
16294
  Scene,
16050
16295
  ShaderMaterial as ShaderMaterial3,
@@ -16155,7 +16400,7 @@ function WebVRStereoRenderer({
16155
16400
  useEffect36(() => {
16156
16401
  const originalRender = gl.render.bind(gl);
16157
16402
  gl.render = (sceneToRender, cameraToRender) => {
16158
- if (!stereoActiveRef.current || !(cameraToRender instanceof PerspectiveCamera8)) {
16403
+ if (!stereoActiveRef.current || !(cameraToRender instanceof PerspectiveCamera9)) {
16159
16404
  originalRender(sceneToRender, cameraToRender);
16160
16405
  return;
16161
16406
  }
@@ -16224,13 +16469,13 @@ function WebVRStereoRenderer({
16224
16469
  },
16225
16470
  [runtime]
16226
16471
  );
16227
- useFrame20(() => {
16472
+ useFrame22(() => {
16228
16473
  const fallback = isFallbackStereoMode(mode);
16229
16474
  stereoActiveRef.current = fallback;
16230
16475
  if (runtime) {
16231
16476
  runtime.stereoView.active = fallback;
16232
16477
  }
16233
- if (fallback && camera instanceof PerspectiveCamera8) {
16478
+ if (fallback && camera instanceof PerspectiveCamera9) {
16234
16479
  syncStereoCameras(
16235
16480
  stereoRef.current,
16236
16481
  camera,
@@ -16241,7 +16486,7 @@ function WebVRStereoRenderer({
16241
16486
  );
16242
16487
  return;
16243
16488
  }
16244
- if (originalFovRef.current !== null && camera instanceof PerspectiveCamera8) {
16489
+ if (originalFovRef.current !== null && camera instanceof PerspectiveCamera9) {
16245
16490
  camera.fov = originalFovRef.current;
16246
16491
  camera.updateProjectionMatrix();
16247
16492
  originalFovRef.current = null;
@@ -16935,7 +17180,7 @@ import {
16935
17180
  BackSide as BackSide4,
16936
17181
  LinearFilter as LinearFilter11,
16937
17182
  LinearMipmapLinearFilter as LinearMipmapLinearFilter7,
16938
- MathUtils as MathUtils12,
17183
+ MathUtils as MathUtils13,
16939
17184
  RepeatWrapping as RepeatWrapping2,
16940
17185
  SRGBColorSpace as SRGBColorSpace10,
16941
17186
  TextureLoader as TextureLoader8,
@@ -17644,7 +17889,7 @@ function PanoVideo({
17644
17889
  activeTexture ? /* @__PURE__ */ jsxs21(
17645
17890
  "mesh",
17646
17891
  {
17647
- rotation: [0, MathUtils12.degToRad(90 + yawOffset2), 0],
17892
+ rotation: [0, MathUtils13.degToRad(90 + yawOffset2), 0],
17648
17893
  visible,
17649
17894
  children: [
17650
17895
  /* @__PURE__ */ jsx40("sphereGeometry", { args: [DEFAULT_PANORAMA_RADIUS, 128, 64] }),