@pmndrs/klipp 0.0.0-stage → 0.14.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/LICENSE +21 -0
- package/README.md +72 -2
- package/dist/_virtual/_rolldown/runtime.js +13 -0
- package/dist/core/CameraState.d.ts +32 -0
- package/dist/core/CameraState.js +97 -0
- package/dist/core/EventDispatcher.d.ts +18 -0
- package/dist/core/EventDispatcher.js +28 -0
- package/dist/core/Klipp.d.ts +109 -0
- package/dist/core/Klipp.js +253 -0
- package/dist/core/TargetExtent.d.ts +11 -0
- package/dist/core/TargetExtent.js +54 -0
- package/dist/core/TargetPose.d.ts +13 -0
- package/dist/core/TargetPose.js +21 -0
- package/dist/core/VirtualCamera.d.ts +102 -0
- package/dist/core/VirtualCamera.js +290 -0
- package/dist/core/aim/HardLookAtAim.d.ts +10 -0
- package/dist/core/aim/HardLookAtAim.js +19 -0
- package/dist/core/aim/PanTiltAim.d.ts +26 -0
- package/dist/core/aim/PanTiltAim.js +38 -0
- package/dist/core/aim/RotateWithFollowTargetAim.d.ts +19 -0
- package/dist/core/aim/RotateWithFollowTargetAim.js +23 -0
- package/dist/core/aim/RotationComposerAim.d.ts +27 -0
- package/dist/core/aim/RotationComposerAim.js +27 -0
- package/dist/core/aim/hardLookAt.d.ts +4 -0
- package/dist/core/aim/hardLookAt.js +13 -0
- package/dist/core/aim/index.d.ts +11 -0
- package/dist/core/aim/lookRotation.d.ts +6 -0
- package/dist/core/aim/lookRotation.js +46 -0
- package/dist/core/aim/panTilt.d.ts +16 -0
- package/dist/core/aim/panTilt.js +121 -0
- package/dist/core/aim/rotateWithFollowTarget.d.ts +20 -0
- package/dist/core/aim/rotateWithFollowTarget.js +35 -0
- package/dist/core/aim/rotationComposer.d.ts +58 -0
- package/dist/core/aim/rotationComposer.js +284 -0
- package/dist/core/blend/BlendCurves.d.ts +19 -0
- package/dist/core/blend/BlendCurves.js +22 -0
- package/dist/core/blend/BlendDefinition.d.ts +21 -0
- package/dist/core/blend/BlendDefinition.js +9 -0
- package/dist/core/blend/BlendDriver.d.ts +23 -0
- package/dist/core/blend/BlendDriver.js +42 -0
- package/dist/core/blend/BlendHints.d.ts +9 -0
- package/dist/core/blend/BlendHints.js +13 -0
- package/dist/core/blend/blend.d.ts +41 -0
- package/dist/core/blend/blend.js +110 -0
- package/dist/core/blend/index.d.ts +6 -0
- package/dist/core/blend/lerpCameraState.d.ts +4 -0
- package/dist/core/blend/lerpCameraState.js +143 -0
- package/dist/core/body/BindingModes.d.ts +9 -0
- package/dist/core/body/BindingModes.js +11 -0
- package/dist/core/body/FollowBody.d.ts +24 -0
- package/dist/core/body/FollowBody.js +26 -0
- package/dist/core/body/HardLockToTargetBody.d.ts +17 -0
- package/dist/core/body/HardLockToTargetBody.js +20 -0
- package/dist/core/body/OrbitFollowBody.d.ts +47 -0
- package/dist/core/body/OrbitFollowBody.js +48 -0
- package/dist/core/body/PositionComposerBody.d.ts +28 -0
- package/dist/core/body/PositionComposerBody.js +27 -0
- package/dist/core/body/follow.d.ts +33 -0
- package/dist/core/body/follow.js +83 -0
- package/dist/core/body/hardLockToTarget.d.ts +17 -0
- package/dist/core/body/hardLockToTarget.js +26 -0
- package/dist/core/body/index.d.ts +17 -0
- package/dist/core/body/orbitFollow.d.ts +76 -0
- package/dist/core/body/orbitFollow.js +336 -0
- package/dist/core/body/positionComposer.d.ts +56 -0
- package/dist/core/body/positionComposer.js +207 -0
- package/dist/core/body/safeFromToRotation.d.ts +3 -0
- package/dist/core/body/safeFromToRotation.js +39 -0
- package/dist/core/body/threeRing.d.ts +28 -0
- package/dist/core/body/threeRing.js +100 -0
- package/dist/core/body/tracker.d.ts +42 -0
- package/dist/core/body/tracker.js +193 -0
- package/dist/core/damping/Damper.d.ts +11 -0
- package/dist/core/damping/Damper.js +22 -0
- package/dist/core/damping/damping.d.ts +30 -0
- package/dist/core/damping/damping.js +119 -0
- package/dist/core/damping/index.d.ts +5 -0
- package/dist/core/damping/predictor.d.ts +16 -0
- package/dist/core/damping/predictor.js +56 -0
- package/dist/core/debug/debugZones.d.ts +16 -0
- package/dist/core/debug/debugZones.js +38 -0
- package/dist/core/debug/index.d.ts +2 -0
- package/dist/core/extension/GroupFramingExtension.d.ts +26 -0
- package/dist/core/extension/GroupFramingExtension.js +24 -0
- package/dist/core/extension/LensExtension.d.ts +20 -0
- package/dist/core/extension/LensExtension.js +12 -0
- package/dist/core/extension/groupFraming.d.ts +62 -0
- package/dist/core/extension/groupFraming.js +271 -0
- package/dist/core/extension/index.d.ts +6 -0
- package/dist/core/extension/lens.d.ts +35 -0
- package/dist/core/extension/lens.js +57 -0
- package/dist/core/groups/ClearShot.d.ts +32 -0
- package/dist/core/groups/MixingCamera.d.ts +20 -0
- package/dist/core/groups/Sequencer.d.ts +24 -0
- package/dist/core/groups/StateDrivenCamera.d.ts +26 -0
- package/dist/core/groups/clearShotState.d.ts +32 -0
- package/dist/core/groups/index.d.ts +11 -0
- package/dist/core/groups/mixCameraStates.d.ts +13 -0
- package/dist/core/groups/sequencerState.d.ts +26 -0
- package/dist/core/groups/stateDrivenState.d.ts +28 -0
- package/dist/core/impulse/ImpulseField.d.ts +15 -0
- package/dist/core/impulse/ImpulseField.js +22 -0
- package/dist/core/impulse/ImpulseListenerNoise.d.ts +19 -0
- package/dist/core/impulse/ImpulseListenerNoise.js +29 -0
- package/dist/core/impulse/impulseListener.d.ts +13 -0
- package/dist/core/impulse/impulseListener.js +14 -0
- package/dist/core/impulse/impulses.d.ts +54 -0
- package/dist/core/impulse/impulses.js +84 -0
- package/dist/core/impulse/index.d.ts +6 -0
- package/dist/core/index.d.ts +20 -0
- package/dist/core/index.js +52 -0
- package/dist/core/input/InputAxis.d.ts +29 -0
- package/dist/core/input/InputAxis.js +28 -0
- package/dist/core/input/InputAxisOwner.d.ts +6 -0
- package/dist/core/input/InputAxisOwner.js +4 -0
- package/dist/core/input/InputController.d.ts +15 -0
- package/dist/core/input/InputController.js +24 -0
- package/dist/core/input/axis.d.ts +52 -0
- package/dist/core/input/axis.js +89 -0
- package/dist/core/input/consumedInput.d.ts +37 -0
- package/dist/core/input/consumedInput.js +34 -0
- package/dist/core/input/index.d.ts +9 -0
- package/dist/core/input/inputMapping.d.ts +46 -0
- package/dist/core/input/inputMapping.js +55 -0
- package/dist/core/input/shortestWrappedDelta.d.ts +2 -0
- package/dist/core/input/shortestWrappedDelta.js +11 -0
- package/dist/core/internal.d.ts +16 -0
- package/dist/core/internal.js +19 -0
- package/dist/core/klippState.d.ts +78 -0
- package/dist/core/klippState.js +124 -0
- package/dist/core/noise/BasicMultiChannelPerlinNoise.d.ts +21 -0
- package/dist/core/noise/BasicMultiChannelPerlinNoise.js +13 -0
- package/dist/core/noise/index.d.ts +3 -0
- package/dist/core/noise/perlinNoise.d.ts +36 -0
- package/dist/core/noise/perlinNoise.js +110 -0
- package/dist/core/params.d.ts +2 -0
- package/dist/core/params.js +12 -0
- package/dist/dom/DebugOverlay.d.ts +11 -0
- package/dist/dom/DebugOverlay.js +96 -0
- package/dist/dom/InputControllerDom.d.ts +15 -0
- package/dist/dom/InputControllerDom.js +31 -0
- package/dist/dom/InputSystem.d.ts +40 -0
- package/dist/dom/InputSystem.js +113 -0
- package/dist/dom/index.d.ts +3 -0
- package/dist/dom/index.js +5 -0
- package/dist/input-sources/buttonInput.d.ts +15 -0
- package/dist/input-sources/buttonInput.js +23 -0
- package/dist/input-sources/isInsideInteractiveArea.d.ts +9 -0
- package/dist/input-sources/isInsideInteractiveArea.js +11 -0
- package/dist/input-sources/mouse.d.ts +47 -0
- package/dist/input-sources/mouse.js +171 -0
- package/dist/input-sources/safariGesture.d.ts +32 -0
- package/dist/input-sources/safariGesture.js +107 -0
- package/dist/input-sources/suppressNativeGestures.d.ts +5 -0
- package/dist/input-sources/suppressNativeGestures.js +32 -0
- package/dist/input-sources/touch.d.ts +47 -0
- package/dist/input-sources/touch.js +173 -0
- package/dist/input-sources/wheel.d.ts +28 -0
- package/dist/input-sources/wheel.js +44 -0
- package/dist/react/CameraFrustumHelper.d.ts +13 -0
- package/dist/react/CameraFrustumHelper.js +32 -0
- package/dist/react/DebugZoneOverlay.d.ts +7 -0
- package/dist/react/DebugZoneOverlay.js +23 -0
- package/dist/react/Klipp.d.ts +20 -0
- package/dist/react/Klipp.js +47 -0
- package/dist/react/KlippContext.d.ts +5 -0
- package/dist/react/KlippContext.js +11 -0
- package/dist/react/VirtualCamera.d.ts +28 -0
- package/dist/react/VirtualCamera.js +81 -0
- package/dist/react/VirtualCameraContext.d.ts +11 -0
- package/dist/react/VirtualCameraContext.js +21 -0
- package/dist/react/aim/Aim.d.ts +11 -0
- package/dist/react/aim/Aim.js +14 -0
- package/dist/react/aim/HardLookAt.d.ts +10 -0
- package/dist/react/aim/HardLookAt.js +15 -0
- package/dist/react/aim/PanTilt.d.ts +31 -0
- package/dist/react/aim/PanTilt.js +38 -0
- package/dist/react/aim/RotateWithFollowTarget.d.ts +10 -0
- package/dist/react/aim/RotateWithFollowTarget.js +18 -0
- package/dist/react/aim/RotationComposer.d.ts +12 -0
- package/dist/react/aim/RotationComposer.js +34 -0
- package/dist/react/body/Body.d.ts +11 -0
- package/dist/react/body/Body.js +14 -0
- package/dist/react/body/CameraControls.d.ts +50 -0
- package/dist/react/body/CameraControls.js +106 -0
- package/dist/react/body/Follow.d.ts +10 -0
- package/dist/react/body/Follow.js +20 -0
- package/dist/react/body/HardLockToTarget.d.ts +10 -0
- package/dist/react/body/HardLockToTarget.js +18 -0
- package/dist/react/body/OrbitFollow.d.ts +25 -0
- package/dist/react/body/OrbitFollow.js +67 -0
- package/dist/react/body/PositionComposer.d.ts +12 -0
- package/dist/react/body/PositionComposer.js +32 -0
- package/dist/react/body/camera-controls.d.ts +2 -0
- package/dist/react/body/camera-controls.js +3 -0
- package/dist/react/extension/Extension.d.ts +7 -0
- package/dist/react/extension/Extension.js +10 -0
- package/dist/react/extension/GroupFraming.d.ts +14 -0
- package/dist/react/extension/GroupFraming.js +52 -0
- package/dist/react/extension/Lens.d.ts +7 -0
- package/dist/react/extension/Lens.js +31 -0
- package/dist/react/impulse/ImpulseListener.d.ts +12 -0
- package/dist/react/impulse/ImpulseListener.js +33 -0
- package/dist/react/index.d.ts +24 -0
- package/dist/react/index.js +24 -0
- package/dist/react/input/InputAxisOwnerContext.d.ts +3 -0
- package/dist/react/input/InputAxisOwnerContext.js +6 -0
- package/dist/react/input/InputController.d.ts +53 -0
- package/dist/react/input/InputController.js +115 -0
- package/dist/react/noise/BasicMultiChannelPerlin.d.ts +7 -0
- package/dist/react/noise/BasicMultiChannelPerlin.js +14 -0
- package/dist/react/noise/Noise.d.ts +5 -0
- package/dist/react/noise/Noise.js +6 -0
- package/dist/react/noise/useBasicMultiChannelPerlinNoise.d.ts +4 -0
- package/dist/react/noise/useBasicMultiChannelPerlinNoise.js +21 -0
- package/dist/react/useCameraTransitionEvent.d.ts +12 -0
- package/dist/react/useCameraTransitionEvent.js +14 -0
- package/dist/three/CameraFrustumHelperThree.d.ts +11 -0
- package/dist/three/CameraFrustumHelperThree.js +44 -0
- package/dist/three/KlippThree.d.ts +18 -0
- package/dist/three/KlippThree.js +50 -0
- package/dist/three/VirtualCameraThree.d.ts +35 -0
- package/dist/three/VirtualCameraThree.js +108 -0
- package/dist/three/aim/HardLookAtAimThree.d.ts +10 -0
- package/dist/three/aim/HardLookAtAimThree.js +14 -0
- package/dist/three/aim/PanTiltAimThree.d.ts +10 -0
- package/dist/three/aim/PanTiltAimThree.js +15 -0
- package/dist/three/aim/RotateWithFollowTargetAimThree.d.ts +11 -0
- package/dist/three/aim/RotateWithFollowTargetAimThree.js +15 -0
- package/dist/three/aim/RotationComposerAimThree.d.ts +26 -0
- package/dist/three/aim/RotationComposerAimThree.js +35 -0
- package/dist/three/body/CameraControlsBodyThree.d.ts +30 -0
- package/dist/three/body/CameraControlsBodyThree.js +54 -0
- package/dist/three/body/FollowBodyThree.d.ts +16 -0
- package/dist/three/body/FollowBodyThree.js +23 -0
- package/dist/three/body/HardLockToTargetBodyThree.d.ts +11 -0
- package/dist/three/body/HardLockToTargetBodyThree.js +14 -0
- package/dist/three/body/OrbitFollowBodyThree.d.ts +16 -0
- package/dist/three/body/OrbitFollowBodyThree.js +23 -0
- package/dist/three/body/OrbitFollowHelperThree.d.ts +23 -0
- package/dist/three/body/OrbitFollowHelperThree.js +85 -0
- package/dist/three/body/PositionComposerBodyThree.d.ts +24 -0
- package/dist/three/body/PositionComposerBodyThree.js +31 -0
- package/dist/three/camera.d.ts +10 -0
- package/dist/three/camera.js +39 -0
- package/dist/three/damping/Predictor.d.ts +12 -0
- package/dist/three/damping/Predictor.js +30 -0
- package/dist/three/damping/QuaternionDamper.d.ts +10 -0
- package/dist/three/damping/QuaternionDamper.js +28 -0
- package/dist/three/damping/Vector3Damper.d.ts +10 -0
- package/dist/three/damping/Vector3Damper.js +26 -0
- package/dist/three/extension/GroupFramingExtensionThree.d.ts +13 -0
- package/dist/three/extension/GroupFramingExtensionThree.js +23 -0
- package/dist/three/extension/TargetGroup.d.ts +32 -0
- package/dist/three/extension/TargetGroup.js +53 -0
- package/dist/three/index.d.ts +24 -0
- package/dist/three/index.js +25 -0
- package/dist/three/noise/BasicMultiChannelPerlinNoiseThree.d.ts +16 -0
- package/dist/three/noise/BasicMultiChannelPerlinNoiseThree.js +17 -0
- package/dist/three/readTargetExtent.d.ts +9 -0
- package/dist/three/readTargetExtent.js +25 -0
- package/dist/three/readTargetPose.d.ts +8 -0
- package/dist/three/readTargetPose.js +21 -0
- package/dist/three/resolve/Target.d.ts +17 -0
- package/dist/three/resolve/Target.js +62 -0
- package/dist/three/resolve/TargetRegistry.d.ts +27 -0
- package/dist/three/resolve/TargetRegistry.js +78 -0
- package/dist/three/resolve/resolveVector3.d.ts +12 -0
- package/dist/three/resolve/resolveVector3.js +29 -0
- package/package.json +120 -4
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { type ReactNode, type Ref } from 'react';
|
|
2
|
+
import type { DampingConstant } from '../../core/damping/damping.js';
|
|
3
|
+
import type { InputAxisRecentering } from '../../core/input/axis.js';
|
|
4
|
+
import { PanTiltAimThree } from '../../three/aim/PanTiltAimThree.js';
|
|
5
|
+
import type { Target } from '../../three/resolve/Target.js';
|
|
6
|
+
export type PanTiltProps = {
|
|
7
|
+
/** Rotation frame `pan`/`tilt` compose on top of.
|
|
8
|
+
* `null`/`undefined`/omitted is world (`referenceUp`-aware) */
|
|
9
|
+
target?: Target;
|
|
10
|
+
/** Applied to both `pan.damping` and `tilt.damping`. */
|
|
11
|
+
damping?: DampingConstant;
|
|
12
|
+
/** Applied to both `pan.maxSpeed` and `tilt.maxSpeed` - caps how fast `damping` can close the gap, in degrees/sec. */
|
|
13
|
+
maxSpeed?: number;
|
|
14
|
+
/** `pan.autoNormalize`. Only applies while `panWrap` is `true`. */
|
|
15
|
+
autoNormalize?: boolean;
|
|
16
|
+
/** `pan.wrap` - loops at `panRange`'s edges or hard-clamps them. */
|
|
17
|
+
panWrap?: boolean;
|
|
18
|
+
/** `tilt.wrap` - see `panWrap`. */
|
|
19
|
+
tiltWrap?: boolean;
|
|
20
|
+
/** `pan.range` - its edges wrap or clamp depending on `panWrap`. */
|
|
21
|
+
panRange?: [number, number];
|
|
22
|
+
/** `tilt.range` - its edges wrap or clamp depending on `tiltWrap`. */
|
|
23
|
+
tiltRange?: [number, number];
|
|
24
|
+
/** Applied to both `pan.recentering` and `tilt.recentering`. */
|
|
25
|
+
recentering?: InputAxisRecentering;
|
|
26
|
+
ref?: Ref<PanTiltAimThree>;
|
|
27
|
+
/** Nested `<InputController>` picks up `pan`/`tilt` automatically without an explicit `target`. */
|
|
28
|
+
children?: ReactNode;
|
|
29
|
+
};
|
|
30
|
+
/** Thin wrapper around `PanTiltAimThree`. */
|
|
31
|
+
export declare function PanTilt({ target, damping, maxSpeed, autoNormalize, panWrap, tiltWrap, panRange, tiltRange, recentering, ref, children, }: PanTiltProps): import("react").JSX.Element;
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { PanTiltAimThree } from "../../three/aim/PanTiltAimThree.js";
|
|
2
|
+
import { useVirtualCamera } from "../VirtualCameraContext.js";
|
|
3
|
+
import { InputAxisOwnerContext } from "../input/InputAxisOwnerContext.js";
|
|
4
|
+
import { useEffect, useImperativeHandle, useState } from "react";
|
|
5
|
+
import { jsx } from "react/jsx-runtime";
|
|
6
|
+
//#region src/react/aim/PanTilt.tsx
|
|
7
|
+
var defaultPanRange = [-180, 180];
|
|
8
|
+
var defaultTiltRange = [-90, 90];
|
|
9
|
+
var defaultRecentering = {
|
|
10
|
+
enabled: false,
|
|
11
|
+
wait: 1,
|
|
12
|
+
time: 1
|
|
13
|
+
};
|
|
14
|
+
/** Thin wrapper around `PanTiltAimThree`. */
|
|
15
|
+
function PanTilt({ target, damping = 0, maxSpeed = Infinity, autoNormalize = false, panWrap = true, tiltWrap = false, panRange = defaultPanRange, tiltRange = defaultTiltRange, recentering = defaultRecentering, ref, children }) {
|
|
16
|
+
const camera = useVirtualCamera();
|
|
17
|
+
const [aim] = useState(() => new PanTiltAimThree());
|
|
18
|
+
aim.target = target;
|
|
19
|
+
aim.pan.damping = damping;
|
|
20
|
+
aim.pan.maxSpeed = maxSpeed;
|
|
21
|
+
aim.pan.autoNormalize = autoNormalize;
|
|
22
|
+
aim.pan.wrap = panWrap;
|
|
23
|
+
aim.pan.range = panRange;
|
|
24
|
+
aim.pan.recentering = recentering;
|
|
25
|
+
aim.tilt.damping = damping;
|
|
26
|
+
aim.tilt.maxSpeed = maxSpeed;
|
|
27
|
+
aim.tilt.wrap = tiltWrap;
|
|
28
|
+
aim.tilt.range = tiltRange;
|
|
29
|
+
aim.tilt.recentering = recentering;
|
|
30
|
+
useImperativeHandle(ref, () => aim, [aim]);
|
|
31
|
+
useEffect(() => camera.setAim(aim), [camera, aim]);
|
|
32
|
+
return /* @__PURE__ */ jsx(InputAxisOwnerContext.Provider, {
|
|
33
|
+
value: aim,
|
|
34
|
+
children
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
//#endregion
|
|
38
|
+
export { PanTilt };
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { type Ref } from 'react';
|
|
2
|
+
import { RotateWithFollowTargetAimThree, type RotateWithFollowTargetOptions } from '../../three/aim/RotateWithFollowTargetAimThree.js';
|
|
3
|
+
import type { Target } from '../../three/resolve/Target.js';
|
|
4
|
+
export type RotateWithFollowTargetProps = RotateWithFollowTargetOptions & {
|
|
5
|
+
/** Target rotation to copy. Unresolved targets are ignored. */
|
|
6
|
+
target?: Target;
|
|
7
|
+
ref?: Ref<RotateWithFollowTargetAimThree>;
|
|
8
|
+
};
|
|
9
|
+
/** Thin wrapper around `RotateWithFollowTargetAimThree`. */
|
|
10
|
+
export declare function RotateWithFollowTarget({ target, ref, ...settings }: RotateWithFollowTargetProps): null;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { createParams } from "../../core/aim/rotateWithFollowTarget.js";
|
|
2
|
+
import { RotateWithFollowTargetAimThree } from "../../three/aim/RotateWithFollowTargetAimThree.js";
|
|
3
|
+
import { useVirtualCamera } from "../VirtualCameraContext.js";
|
|
4
|
+
import { useEffect, useImperativeHandle, useState } from "react";
|
|
5
|
+
//#region src/react/aim/RotateWithFollowTarget.tsx
|
|
6
|
+
/** Thin wrapper around `RotateWithFollowTargetAimThree`. */
|
|
7
|
+
function RotateWithFollowTarget({ target, ref, ...settings }) {
|
|
8
|
+
const camera = useVirtualCamera();
|
|
9
|
+
const params = createParams(settings);
|
|
10
|
+
const [aim] = useState(() => new RotateWithFollowTargetAimThree(target, params));
|
|
11
|
+
aim.target = target;
|
|
12
|
+
Object.assign(aim, params);
|
|
13
|
+
useImperativeHandle(ref, () => aim, [aim]);
|
|
14
|
+
useEffect(() => camera.setAim(aim), [camera, aim]);
|
|
15
|
+
return null;
|
|
16
|
+
}
|
|
17
|
+
//#endregion
|
|
18
|
+
export { RotateWithFollowTarget };
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { type Ref } from 'react';
|
|
2
|
+
import { RotationComposerAimThree, type RotationComposerThreeOptions } from '../../three/aim/RotationComposerAimThree.js';
|
|
3
|
+
import type { Target } from '../../three/resolve/Target.js';
|
|
4
|
+
export type RotationComposerProps = Omit<RotationComposerThreeOptions, 'aspect'> & {
|
|
5
|
+
/** Target to compose at `screenPosition`. Unresolved targets are ignored. */
|
|
6
|
+
target?: Target;
|
|
7
|
+
/** Draws the `deadZone` and `hardLimit` overlays. */
|
|
8
|
+
debug?: boolean;
|
|
9
|
+
ref?: Ref<RotationComposerAimThree>;
|
|
10
|
+
};
|
|
11
|
+
/** Keeps a target within a chosen screen region by rotating the camera. */
|
|
12
|
+
export declare function RotationComposer({ target, targetOffset, debug, ref, ...settings }: RotationComposerProps): import("react").JSX.Element | null;
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { createParams } from "../../core/aim/rotationComposer.js";
|
|
2
|
+
import { composer } from "../../core/debug/debugZones.js";
|
|
3
|
+
import { resolveVec3 } from "../../three/resolve/resolveVector3.js";
|
|
4
|
+
import { RotationComposerAimThree } from "../../three/aim/RotationComposerAimThree.js";
|
|
5
|
+
import { useVirtualCamera } from "../VirtualCameraContext.js";
|
|
6
|
+
import { DebugZoneOverlay } from "../DebugZoneOverlay.js";
|
|
7
|
+
import { useThree } from "@react-three/fiber";
|
|
8
|
+
import { useEffect, useImperativeHandle, useState } from "react";
|
|
9
|
+
import { jsx } from "react/jsx-runtime";
|
|
10
|
+
//#region src/react/aim/RotationComposer.tsx
|
|
11
|
+
/** Keeps a target within a chosen screen region by rotating the camera. */
|
|
12
|
+
function RotationComposer({ target, targetOffset, debug = false, ref, ...settings }) {
|
|
13
|
+
const camera = useVirtualCamera();
|
|
14
|
+
const aspect = useThree((state) => state.viewport.aspect);
|
|
15
|
+
const { targetOffset: defaultTargetOffset, ...params } = createParams({
|
|
16
|
+
...settings,
|
|
17
|
+
aspect
|
|
18
|
+
});
|
|
19
|
+
const [aim] = useState(() => new RotationComposerAimThree(target, params));
|
|
20
|
+
aim.target = target;
|
|
21
|
+
Object.assign(aim, params);
|
|
22
|
+
resolveVec3(aim.targetOffset, targetOffset ?? defaultTargetOffset);
|
|
23
|
+
aim.radius = settings.radius;
|
|
24
|
+
aim.size = settings.size;
|
|
25
|
+
useImperativeHandle(ref, () => aim, [aim]);
|
|
26
|
+
useEffect(() => camera.setAim(aim), [camera, aim]);
|
|
27
|
+
if (!debug) return null;
|
|
28
|
+
return /* @__PURE__ */ jsx(DebugZoneOverlay, {
|
|
29
|
+
zones: composer(aim.screenPosition, aim.deadZone, aim.hardLimit),
|
|
30
|
+
crosshair: aim.screenPosition
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
//#endregion
|
|
34
|
+
export { RotationComposer };
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { Follow } from './Follow.js';
|
|
2
|
+
import { HardLockToTarget } from './HardLockToTarget.js';
|
|
3
|
+
import { OrbitFollow } from './OrbitFollow.js';
|
|
4
|
+
import { PositionComposer } from './PositionComposer.js';
|
|
5
|
+
/** Body components control a `<VirtualCamera>`'s position. Use at most one per camera. */
|
|
6
|
+
export declare const Body: {
|
|
7
|
+
HardLockToTarget: typeof HardLockToTarget;
|
|
8
|
+
Follow: typeof Follow;
|
|
9
|
+
PositionComposer: typeof PositionComposer;
|
|
10
|
+
OrbitFollow: typeof OrbitFollow;
|
|
11
|
+
};
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { Follow } from "./Follow.js";
|
|
2
|
+
import { HardLockToTarget } from "./HardLockToTarget.js";
|
|
3
|
+
import { OrbitFollow } from "./OrbitFollow.js";
|
|
4
|
+
import { PositionComposer } from "./PositionComposer.js";
|
|
5
|
+
//#region src/react/body/Body.ts
|
|
6
|
+
/** Body components control a `<VirtualCamera>`'s position. Use at most one per camera. */
|
|
7
|
+
var Body = {
|
|
8
|
+
HardLockToTarget,
|
|
9
|
+
Follow,
|
|
10
|
+
PositionComposer,
|
|
11
|
+
OrbitFollow
|
|
12
|
+
};
|
|
13
|
+
//#endregion
|
|
14
|
+
export { Body };
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import type { ThreeElement, Vector3 as Vector3Like } from '@react-three/fiber';
|
|
2
|
+
import CameraControlsImpl, { EventDispatcher } from 'camera-controls';
|
|
3
|
+
import { type Ref } from 'react';
|
|
4
|
+
import { CameraControlsBodyThree } from '../../three/body/CameraControlsBodyThree.js';
|
|
5
|
+
import type { Target } from '../../three/resolve/Target.js';
|
|
6
|
+
type Overwrite<T, U> = Omit<T, keyof U> & U;
|
|
7
|
+
export type CameraControlsProps = Omit<Overwrite<ThreeElement<typeof CameraControlsImpl>, {
|
|
8
|
+
/** Target for orbiting and dollying. Omit for free camera controls. */
|
|
9
|
+
target?: Target;
|
|
10
|
+
/** World-space starting position, applied at construction regardless of `target`'s state. */
|
|
11
|
+
initialPosition?: Vector3Like;
|
|
12
|
+
/** `camera-controls`' own transition-easing argument for every call this makes. */
|
|
13
|
+
enableTransition?: boolean;
|
|
14
|
+
/** Custom `CameraControlsImpl` subclass to instantiate instead of the base class. */
|
|
15
|
+
impl?: typeof CameraControlsImpl;
|
|
16
|
+
/** Wait for an in-progress blend into this camera before listening to input. */
|
|
17
|
+
waitForBlend?: boolean;
|
|
18
|
+
/** Registers this instance as r3f's `state.controls` while it accepts input. */
|
|
19
|
+
makeDefault?: boolean;
|
|
20
|
+
ref?: Ref<CameraControlsBodyThree>;
|
|
21
|
+
/** Also lowers r3f's render quality while dragging/transitioning. */
|
|
22
|
+
regress?: boolean;
|
|
23
|
+
onControlStart?: (event: {
|
|
24
|
+
type: 'controlstart';
|
|
25
|
+
}) => void;
|
|
26
|
+
onControl?: (event: {
|
|
27
|
+
type: 'control';
|
|
28
|
+
}) => void;
|
|
29
|
+
onControlEnd?: (event: {
|
|
30
|
+
type: 'controlend';
|
|
31
|
+
}) => void;
|
|
32
|
+
onTransitionStart?: (event: {
|
|
33
|
+
type: 'transitionstart';
|
|
34
|
+
}) => void;
|
|
35
|
+
onUpdate?: (event: {
|
|
36
|
+
type: 'update';
|
|
37
|
+
}) => void;
|
|
38
|
+
onWake?: (event: {
|
|
39
|
+
type: 'wake';
|
|
40
|
+
}) => void;
|
|
41
|
+
onRest?: (event: {
|
|
42
|
+
type: 'rest';
|
|
43
|
+
}) => void;
|
|
44
|
+
onSleep?: (event: {
|
|
45
|
+
type: 'sleep';
|
|
46
|
+
}) => void;
|
|
47
|
+
}>, 'args' | keyof EventDispatcher>;
|
|
48
|
+
/** Connects `camera-controls` to the active virtual camera. */
|
|
49
|
+
export declare function CameraControls({ target, initialPosition, enableTransition, impl, waitForBlend, makeDefault, ref, regress, onControlStart, onControl, onControlEnd, onTransitionStart, onUpdate, onWake, onRest, onSleep, ...controlsProps }: CameraControlsProps): import("react").JSX.Element;
|
|
50
|
+
export {};
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
import { resolveVector3 } from "../../three/resolve/resolveVector3.js";
|
|
2
|
+
import { CameraControlsBodyThree } from "../../three/body/CameraControlsBodyThree.js";
|
|
3
|
+
import { useIsActiveVirtualCamera, useIsLiveVirtualCamera, useVirtualCamera } from "../VirtualCameraContext.js";
|
|
4
|
+
import { Vector3 } from "three";
|
|
5
|
+
import CameraControls from "camera-controls";
|
|
6
|
+
import { useThree } from "@react-three/fiber";
|
|
7
|
+
import { useEffect, useEffectEvent, useImperativeHandle, useState } from "react";
|
|
8
|
+
import { jsx } from "react/jsx-runtime";
|
|
9
|
+
//#region src/react/body/CameraControls.tsx
|
|
10
|
+
/** Connects `camera-controls` to the active virtual camera. */
|
|
11
|
+
function CameraControls$1({ target, initialPosition, enableTransition = false, impl = CameraControls, waitForBlend = true, makeDefault = false, ref, regress = false, onControlStart, onControl, onControlEnd, onTransitionStart, onUpdate, onWake, onRest, onSleep, ...controlsProps }) {
|
|
12
|
+
const camera = useVirtualCamera();
|
|
13
|
+
const isActive = useIsActiveVirtualCamera();
|
|
14
|
+
const isLive = useIsLiveVirtualCamera();
|
|
15
|
+
const shouldConnect = isActive && (waitForBlend ? isLive : true);
|
|
16
|
+
const aspect = useThree((state) => state.viewport.aspect);
|
|
17
|
+
const domElement = useThree((state) => state.gl.domElement);
|
|
18
|
+
const invalidate = useThree((state) => state.invalidate);
|
|
19
|
+
const performance = useThree((state) => state.performance);
|
|
20
|
+
const set = useThree((state) => state.set);
|
|
21
|
+
const get = useThree((state) => state.get);
|
|
22
|
+
const [body] = useState(() => new CameraControlsBodyThree(target, {
|
|
23
|
+
aspect,
|
|
24
|
+
initialPosition: initialPosition ? resolveVector3(new Vector3(), initialPosition) : null,
|
|
25
|
+
impl,
|
|
26
|
+
enableTransition
|
|
27
|
+
}));
|
|
28
|
+
body.target = target;
|
|
29
|
+
body.aspect = aspect;
|
|
30
|
+
body.enableTransition = enableTransition;
|
|
31
|
+
useImperativeHandle(ref, () => body, [body]);
|
|
32
|
+
useEffect(() => camera.setBody(body), [camera, body]);
|
|
33
|
+
useEffect(() => {
|
|
34
|
+
if (!makeDefault || !shouldConnect) return;
|
|
35
|
+
const previous = get().controls;
|
|
36
|
+
set({ controls: body.controls });
|
|
37
|
+
return () => set({ controls: previous });
|
|
38
|
+
}, [
|
|
39
|
+
makeDefault,
|
|
40
|
+
shouldConnect,
|
|
41
|
+
body,
|
|
42
|
+
set,
|
|
43
|
+
get
|
|
44
|
+
]);
|
|
45
|
+
const invalidateAndRegress = useEffectEvent(() => {
|
|
46
|
+
invalidate();
|
|
47
|
+
if (regress) performance.regress();
|
|
48
|
+
});
|
|
49
|
+
const handleControlStart = useEffectEvent((e) => {
|
|
50
|
+
invalidateAndRegress();
|
|
51
|
+
onControlStart?.(e);
|
|
52
|
+
});
|
|
53
|
+
const handleControl = useEffectEvent((e) => {
|
|
54
|
+
invalidateAndRegress();
|
|
55
|
+
onControl?.(e);
|
|
56
|
+
});
|
|
57
|
+
const handleControlEnd = useEffectEvent((e) => onControlEnd?.(e));
|
|
58
|
+
const handleTransitionStart = useEffectEvent((e) => {
|
|
59
|
+
invalidateAndRegress();
|
|
60
|
+
onTransitionStart?.(e);
|
|
61
|
+
});
|
|
62
|
+
const handleUpdate = useEffectEvent((e) => {
|
|
63
|
+
invalidateAndRegress();
|
|
64
|
+
onUpdate?.(e);
|
|
65
|
+
});
|
|
66
|
+
const handleWake = useEffectEvent((e) => {
|
|
67
|
+
invalidateAndRegress();
|
|
68
|
+
onWake?.(e);
|
|
69
|
+
});
|
|
70
|
+
const handleRest = useEffectEvent((e) => onRest?.(e));
|
|
71
|
+
const handleSleep = useEffectEvent((e) => onSleep?.(e));
|
|
72
|
+
useEffect(() => {
|
|
73
|
+
if (!shouldConnect) return;
|
|
74
|
+
body.controls.connect(domElement);
|
|
75
|
+
body.controls.addEventListener("controlstart", handleControlStart);
|
|
76
|
+
body.controls.addEventListener("control", handleControl);
|
|
77
|
+
body.controls.addEventListener("controlend", handleControlEnd);
|
|
78
|
+
body.controls.addEventListener("transitionstart", handleTransitionStart);
|
|
79
|
+
body.controls.addEventListener("update", handleUpdate);
|
|
80
|
+
body.controls.addEventListener("wake", handleWake);
|
|
81
|
+
body.controls.addEventListener("rest", handleRest);
|
|
82
|
+
body.controls.addEventListener("sleep", handleSleep);
|
|
83
|
+
if (domElement.ownerDocument.pointerLockElement === domElement) body.controls.lockPointer();
|
|
84
|
+
return () => {
|
|
85
|
+
body.controls.disconnect();
|
|
86
|
+
body.controls.removeEventListener("controlstart", handleControlStart);
|
|
87
|
+
body.controls.removeEventListener("control", handleControl);
|
|
88
|
+
body.controls.removeEventListener("controlend", handleControlEnd);
|
|
89
|
+
body.controls.removeEventListener("transitionstart", handleTransitionStart);
|
|
90
|
+
body.controls.removeEventListener("update", handleUpdate);
|
|
91
|
+
body.controls.removeEventListener("wake", handleWake);
|
|
92
|
+
body.controls.removeEventListener("rest", handleRest);
|
|
93
|
+
body.controls.removeEventListener("sleep", handleSleep);
|
|
94
|
+
};
|
|
95
|
+
}, [
|
|
96
|
+
body,
|
|
97
|
+
domElement,
|
|
98
|
+
shouldConnect
|
|
99
|
+
]);
|
|
100
|
+
return /* @__PURE__ */ jsx("primitive", {
|
|
101
|
+
object: body.controls,
|
|
102
|
+
...controlsProps
|
|
103
|
+
});
|
|
104
|
+
}
|
|
105
|
+
//#endregion
|
|
106
|
+
export { CameraControls$1 as CameraControls };
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { type Ref } from 'react';
|
|
2
|
+
import { FollowBodyThree, type FollowThreeOptions } from '../../three/body/FollowBodyThree.js';
|
|
3
|
+
import type { Target } from '../../three/resolve/Target.js';
|
|
4
|
+
export type FollowProps = FollowThreeOptions & {
|
|
5
|
+
/** Target to follow. Unresolved targets are ignored. */
|
|
6
|
+
target?: Target;
|
|
7
|
+
ref?: Ref<FollowBodyThree>;
|
|
8
|
+
};
|
|
9
|
+
/** Follows a target with a configurable offset and rotation frame. */
|
|
10
|
+
export declare function Follow({ target, offset, ref, ...settings }: FollowProps): null;
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { createParams } from "../../core/body/follow.js";
|
|
2
|
+
import { resolveVec3 } from "../../three/resolve/resolveVector3.js";
|
|
3
|
+
import { FollowBodyThree } from "../../three/body/FollowBodyThree.js";
|
|
4
|
+
import { useVirtualCamera } from "../VirtualCameraContext.js";
|
|
5
|
+
import { useEffect, useImperativeHandle, useState } from "react";
|
|
6
|
+
//#region src/react/body/Follow.tsx
|
|
7
|
+
/** Follows a target with a configurable offset and rotation frame. */
|
|
8
|
+
function Follow({ target, offset, ref, ...settings }) {
|
|
9
|
+
const camera = useVirtualCamera();
|
|
10
|
+
const { offset: defaultOffset, ...params } = createParams(settings);
|
|
11
|
+
const [body] = useState(() => new FollowBodyThree(target, params));
|
|
12
|
+
body.target = target;
|
|
13
|
+
Object.assign(body, params);
|
|
14
|
+
resolveVec3(body.offset, offset ?? defaultOffset);
|
|
15
|
+
useImperativeHandle(ref, () => body, [body]);
|
|
16
|
+
useEffect(() => camera.setBody(body), [camera, body]);
|
|
17
|
+
return null;
|
|
18
|
+
}
|
|
19
|
+
//#endregion
|
|
20
|
+
export { Follow };
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { type Ref } from 'react';
|
|
2
|
+
import { HardLockToTargetBodyThree, type HardLockToTargetOptions } from '../../three/body/HardLockToTargetBodyThree.js';
|
|
3
|
+
import type { Target } from '../../three/resolve/Target.js';
|
|
4
|
+
export type HardLockToTargetProps = HardLockToTargetOptions & {
|
|
5
|
+
/** Target position to follow. Unresolved targets are ignored. */
|
|
6
|
+
target?: Target;
|
|
7
|
+
ref?: Ref<HardLockToTargetBodyThree>;
|
|
8
|
+
};
|
|
9
|
+
/** Simple body that locks the camera to a target position, optionally with damping. */
|
|
10
|
+
export declare function HardLockToTarget({ target, ref, ...settings }: HardLockToTargetProps): null;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { createParams } from "../../core/body/hardLockToTarget.js";
|
|
2
|
+
import { HardLockToTargetBodyThree } from "../../three/body/HardLockToTargetBodyThree.js";
|
|
3
|
+
import { useVirtualCamera } from "../VirtualCameraContext.js";
|
|
4
|
+
import { useEffect, useImperativeHandle, useState } from "react";
|
|
5
|
+
//#region src/react/body/HardLockToTarget.tsx
|
|
6
|
+
/** Simple body that locks the camera to a target position, optionally with damping. */
|
|
7
|
+
function HardLockToTarget({ target, ref, ...settings }) {
|
|
8
|
+
const camera = useVirtualCamera();
|
|
9
|
+
const params = createParams(settings);
|
|
10
|
+
const [body] = useState(() => new HardLockToTargetBodyThree(target, params));
|
|
11
|
+
body.target = target;
|
|
12
|
+
Object.assign(body, params);
|
|
13
|
+
useImperativeHandle(ref, () => body, [body]);
|
|
14
|
+
useEffect(() => camera.setBody(body), [camera, body]);
|
|
15
|
+
return null;
|
|
16
|
+
}
|
|
17
|
+
//#endregion
|
|
18
|
+
export { HardLockToTarget };
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { type ReactNode, type Ref } from 'react';
|
|
2
|
+
import type { InputAxisParams } from '../../core/input/axis.js';
|
|
3
|
+
import { OrbitFollowBodyThree, type OrbitFollowThreeOptions } from '../../three/body/OrbitFollowBodyThree.js';
|
|
4
|
+
import type { Target } from '../../three/resolve/Target.js';
|
|
5
|
+
/** Settings of one orbit axis. It starts at `center`, then input drives its value. */
|
|
6
|
+
export type OrbitFollowAxisSettings = Partial<Omit<InputAxisParams, 'value'>>;
|
|
7
|
+
export type OrbitFollowProps = OrbitFollowThreeOptions & {
|
|
8
|
+
/** Target to orbit. Unresolved targets are ignored. */
|
|
9
|
+
target?: Target;
|
|
10
|
+
/** Angle around the target, in degrees. */
|
|
11
|
+
horizontal?: OrbitFollowAxisSettings;
|
|
12
|
+
/** Elevation above the target in degrees, or from the bottom to the top ring for `threeRing`. */
|
|
13
|
+
vertical?: OrbitFollowAxisSettings;
|
|
14
|
+
/** Natural log of the radius scale. */
|
|
15
|
+
radial?: OrbitFollowAxisSettings;
|
|
16
|
+
/** `horizontal.autoNormalize`: keeps it inside its range after each drag. */
|
|
17
|
+
autoNormalize?: boolean;
|
|
18
|
+
/** Draws the orbit in the scene. */
|
|
19
|
+
debug?: boolean;
|
|
20
|
+
ref?: Ref<OrbitFollowBodyThree>;
|
|
21
|
+
/** Nested `<InputController>` picks up `horizontal`/`vertical`/`radial` without an explicit `target`. */
|
|
22
|
+
children?: ReactNode;
|
|
23
|
+
};
|
|
24
|
+
/** Orbits a target, driven by the `horizontal`, `vertical` and `radial` axes. */
|
|
25
|
+
export declare function OrbitFollow({ target, targetOffset, horizontal, vertical, radial, autoNormalize, debug, ref, children, ...settings }: OrbitFollowProps): import("react").JSX.Element;
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import { withDefaults } from "../../core/params.js";
|
|
2
|
+
import { createParams } from "../../core/input/axis.js";
|
|
3
|
+
import { createAxisSettings, createParams as createParams$1 } from "../../core/body/orbitFollow.js";
|
|
4
|
+
import { resolveVec3 } from "../../three/resolve/resolveVector3.js";
|
|
5
|
+
import { OrbitFollowBodyThree } from "../../three/body/OrbitFollowBodyThree.js";
|
|
6
|
+
import { OrbitFollowHelperThree } from "../../three/body/OrbitFollowHelperThree.js";
|
|
7
|
+
import { useVirtualCamera } from "../VirtualCameraContext.js";
|
|
8
|
+
import { InputAxisOwnerContext } from "../input/InputAxisOwnerContext.js";
|
|
9
|
+
import { useFrame } from "@react-three/fiber";
|
|
10
|
+
import { useEffect, useImperativeHandle, useState } from "react";
|
|
11
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
12
|
+
//#region src/react/body/OrbitFollow.tsx
|
|
13
|
+
function applyAxis(axis, defaults, settings) {
|
|
14
|
+
const params = withDefaults(createParams(defaults), settings);
|
|
15
|
+
params.value = axis.value;
|
|
16
|
+
Object.assign(axis, params);
|
|
17
|
+
}
|
|
18
|
+
function applyAxes(body, { horizontal, vertical, radial, autoNormalize }) {
|
|
19
|
+
const defaults = createAxisSettings();
|
|
20
|
+
defaults.horizontal.autoNormalize = autoNormalize;
|
|
21
|
+
applyAxis(body.horizontal, defaults.horizontal, horizontal);
|
|
22
|
+
applyAxis(body.vertical, defaults.vertical, vertical);
|
|
23
|
+
applyAxis(body.radial, defaults.radial, radial);
|
|
24
|
+
}
|
|
25
|
+
/** Orbits a target, driven by the `horizontal`, `vertical` and `radial` axes. */
|
|
26
|
+
function OrbitFollow({ target, targetOffset, horizontal, vertical, radial, autoNormalize = false, debug = false, ref, children, ...settings }) {
|
|
27
|
+
const camera = useVirtualCamera();
|
|
28
|
+
const { targetOffset: defaultTargetOffset, ...params } = createParams$1(settings);
|
|
29
|
+
const [body] = useState(() => {
|
|
30
|
+
const created = new OrbitFollowBodyThree(target, params);
|
|
31
|
+
applyAxes(created, {
|
|
32
|
+
horizontal,
|
|
33
|
+
vertical,
|
|
34
|
+
radial,
|
|
35
|
+
autoNormalize
|
|
36
|
+
});
|
|
37
|
+
for (const axis of [
|
|
38
|
+
created.horizontal,
|
|
39
|
+
created.vertical,
|
|
40
|
+
created.radial
|
|
41
|
+
]) axis.setValue(axis.center);
|
|
42
|
+
return created;
|
|
43
|
+
});
|
|
44
|
+
body.target = target;
|
|
45
|
+
Object.assign(body, params);
|
|
46
|
+
resolveVec3(body.targetOffset, targetOffset ?? defaultTargetOffset);
|
|
47
|
+
applyAxes(body, {
|
|
48
|
+
horizontal,
|
|
49
|
+
vertical,
|
|
50
|
+
radial,
|
|
51
|
+
autoNormalize
|
|
52
|
+
});
|
|
53
|
+
useImperativeHandle(ref, () => body, [body]);
|
|
54
|
+
useEffect(() => camera.setBody(body), [camera, body]);
|
|
55
|
+
return /* @__PURE__ */ jsxs(InputAxisOwnerContext.Provider, {
|
|
56
|
+
value: body,
|
|
57
|
+
children: [children, debug && /* @__PURE__ */ jsx(OrbitDebug, { body })]
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
function OrbitDebug({ body }) {
|
|
61
|
+
const [helper] = useState(() => new OrbitFollowHelperThree());
|
|
62
|
+
useEffect(() => () => helper.dispose(), [helper]);
|
|
63
|
+
useFrame(() => helper.sync(body));
|
|
64
|
+
return /* @__PURE__ */ jsx("primitive", { object: helper });
|
|
65
|
+
}
|
|
66
|
+
//#endregion
|
|
67
|
+
export { OrbitFollow };
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { type Ref } from 'react';
|
|
2
|
+
import { PositionComposerBodyThree, type PositionComposerThreeOptions } from '../../three/body/PositionComposerBodyThree.js';
|
|
3
|
+
import type { Target } from '../../three/resolve/Target.js';
|
|
4
|
+
export type PositionComposerProps = Omit<PositionComposerThreeOptions, 'aspect'> & {
|
|
5
|
+
/** Target to compose around. Unresolved targets are ignored. */
|
|
6
|
+
target?: Target;
|
|
7
|
+
/** Draws the `deadZone` and `hardLimit` overlays. */
|
|
8
|
+
debug?: boolean;
|
|
9
|
+
ref?: Ref<PositionComposerBodyThree>;
|
|
10
|
+
};
|
|
11
|
+
/** Positions the camera around a target while maintaining screen composition. */
|
|
12
|
+
export declare function PositionComposer({ target, debug, ref, ...settings }: PositionComposerProps): import("react").JSX.Element | null;
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { createParams } from "../../core/body/positionComposer.js";
|
|
2
|
+
import { composer } from "../../core/debug/debugZones.js";
|
|
3
|
+
import { PositionComposerBodyThree } from "../../three/body/PositionComposerBodyThree.js";
|
|
4
|
+
import { useVirtualCamera } from "../VirtualCameraContext.js";
|
|
5
|
+
import { DebugZoneOverlay } from "../DebugZoneOverlay.js";
|
|
6
|
+
import { useThree } from "@react-three/fiber";
|
|
7
|
+
import { useEffect, useImperativeHandle, useState } from "react";
|
|
8
|
+
import { jsx } from "react/jsx-runtime";
|
|
9
|
+
//#region src/react/body/PositionComposer.tsx
|
|
10
|
+
/** Positions the camera around a target while maintaining screen composition. */
|
|
11
|
+
function PositionComposer({ target, debug = false, ref, ...settings }) {
|
|
12
|
+
const camera = useVirtualCamera();
|
|
13
|
+
const aspect = useThree((state) => state.viewport.aspect);
|
|
14
|
+
const params = createParams({
|
|
15
|
+
...settings,
|
|
16
|
+
aspect
|
|
17
|
+
});
|
|
18
|
+
const [body] = useState(() => new PositionComposerBodyThree(target, params));
|
|
19
|
+
body.target = target;
|
|
20
|
+
Object.assign(body, params);
|
|
21
|
+
body.radius = settings.radius;
|
|
22
|
+
body.size = settings.size;
|
|
23
|
+
useImperativeHandle(ref, () => body, [body]);
|
|
24
|
+
useEffect(() => camera.setBody(body), [camera, body]);
|
|
25
|
+
if (!debug) return null;
|
|
26
|
+
return /* @__PURE__ */ jsx(DebugZoneOverlay, {
|
|
27
|
+
zones: composer(body.screenPosition, body.deadZone, body.hardLimit),
|
|
28
|
+
crosshair: body.screenPosition
|
|
29
|
+
});
|
|
30
|
+
}
|
|
31
|
+
//#endregion
|
|
32
|
+
export { PositionComposer };
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { GroupFraming } from './GroupFraming.js';
|
|
2
|
+
import { Lens } from './Lens.js';
|
|
3
|
+
/** Extensions run after Body/Aim and before Noise; multiple extensions can be registered. */
|
|
4
|
+
export declare const Extension: {
|
|
5
|
+
GroupFraming: typeof GroupFraming;
|
|
6
|
+
Lens: typeof Lens;
|
|
7
|
+
};
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { GroupFraming } from "./GroupFraming.js";
|
|
2
|
+
import { Lens } from "./Lens.js";
|
|
3
|
+
//#region src/react/extension/Extension.ts
|
|
4
|
+
/** Extensions run after Body/Aim and before Noise; multiple extensions can be registered. */
|
|
5
|
+
var Extension = {
|
|
6
|
+
GroupFraming,
|
|
7
|
+
Lens
|
|
8
|
+
};
|
|
9
|
+
//#endregion
|
|
10
|
+
export { Extension };
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { type Ref } from 'react';
|
|
2
|
+
import { GroupFramingExtensionThree, type GroupFramingOptions } from '../../three/extension/GroupFramingExtensionThree.js';
|
|
3
|
+
import { type TargetGroupMember, type TargetGroupPositionMode } from '../../three/extension/TargetGroup.js';
|
|
4
|
+
export type GroupFramingProps = Omit<GroupFramingOptions, 'viewportWidth' | 'viewportHeight'> & {
|
|
5
|
+
/** Targets to keep in frame. */
|
|
6
|
+
members: TargetGroupMember[];
|
|
7
|
+
/** Strategy used to compute the group's position. */
|
|
8
|
+
positionMode?: TargetGroupPositionMode;
|
|
9
|
+
/** Draws the padding boundary while this camera is live. */
|
|
10
|
+
debug?: boolean;
|
|
11
|
+
ref?: Ref<GroupFramingExtensionThree>;
|
|
12
|
+
};
|
|
13
|
+
/** Keeps a target group framed within the camera. */
|
|
14
|
+
export declare function GroupFraming({ members, positionMode, debug, ref, ...settings }: GroupFramingProps): import("react").JSX.Element | null;
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { createParams } from "../../core/extension/groupFraming.js";
|
|
2
|
+
import { groupFramingPaddingBox } from "../../core/debug/debugZones.js";
|
|
3
|
+
import { TargetGroup } from "../../three/extension/TargetGroup.js";
|
|
4
|
+
import { GroupFramingExtensionThree } from "../../three/extension/GroupFramingExtensionThree.js";
|
|
5
|
+
import { useVirtualCamera } from "../VirtualCameraContext.js";
|
|
6
|
+
import { DebugZoneOverlay } from "../DebugZoneOverlay.js";
|
|
7
|
+
import { Vector3 } from "three";
|
|
8
|
+
import { useFrame, useThree } from "@react-three/fiber";
|
|
9
|
+
import { useEffect, useImperativeHandle, useState } from "react";
|
|
10
|
+
import { jsx } from "react/jsx-runtime";
|
|
11
|
+
//#region src/react/extension/GroupFraming.tsx
|
|
12
|
+
var scratchGroupPosition = new Vector3();
|
|
13
|
+
var scratchCameraPosition = new Vector3();
|
|
14
|
+
/** Minimum visible change for the debug overlay. */
|
|
15
|
+
var DEBUG_BOX_EPSILON = .002;
|
|
16
|
+
/** Keeps a target group framed within the camera. */
|
|
17
|
+
function GroupFraming({ members, positionMode = "groupCenter", debug = false, ref, ...settings }) {
|
|
18
|
+
const camera = useVirtualCamera();
|
|
19
|
+
const cameraState = camera.state;
|
|
20
|
+
const size = useThree((state) => state.size);
|
|
21
|
+
const params = createParams({
|
|
22
|
+
...settings,
|
|
23
|
+
viewportWidth: size.width,
|
|
24
|
+
viewportHeight: size.height
|
|
25
|
+
});
|
|
26
|
+
const [group] = useState(() => new TargetGroup(members, positionMode));
|
|
27
|
+
const [extension] = useState(() => new GroupFramingExtensionThree(group, params));
|
|
28
|
+
group.members = members;
|
|
29
|
+
group.positionMode = positionMode;
|
|
30
|
+
Object.assign(extension, params);
|
|
31
|
+
useImperativeHandle(ref, () => extension, [extension]);
|
|
32
|
+
useEffect(() => camera.addExtension(extension), [camera, extension]);
|
|
33
|
+
const [paddingBox, setPaddingBox] = useState(null);
|
|
34
|
+
useFrame(() => {
|
|
35
|
+
if (!debug) return;
|
|
36
|
+
if (group.computeBounds(scratchGroupPosition) <= 0) {
|
|
37
|
+
setPaddingBox((previous) => previous === null ? previous : null);
|
|
38
|
+
return;
|
|
39
|
+
}
|
|
40
|
+
const distance = scratchCameraPosition.fromArray(cameraState.position).distanceTo(scratchGroupPosition);
|
|
41
|
+
const next = groupFramingPaddingBox([0, 0], cameraState.fov, size.width / size.height, distance, extension.padding, extension.framingMode);
|
|
42
|
+
setPaddingBox((previous) => previous && Math.abs(previous[0] - next[0]) < DEBUG_BOX_EPSILON && Math.abs(previous[1] - next[1]) < DEBUG_BOX_EPSILON ? previous : next);
|
|
43
|
+
});
|
|
44
|
+
if (!debug || !paddingBox) return null;
|
|
45
|
+
return /* @__PURE__ */ jsx(DebugZoneOverlay, { zones: [{
|
|
46
|
+
screenPosition: extension.screenPosition,
|
|
47
|
+
size: paddingBox,
|
|
48
|
+
className: "klipp-debug-groupframing"
|
|
49
|
+
}] });
|
|
50
|
+
}
|
|
51
|
+
//#endregion
|
|
52
|
+
export { GroupFraming };
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { type Ref } from 'react';
|
|
2
|
+
import { LensExtension, type LensOptions } from '../../core/extension/LensExtension.js';
|
|
3
|
+
export type LensProps = LensOptions & {
|
|
4
|
+
ref?: Ref<LensExtension>;
|
|
5
|
+
};
|
|
6
|
+
/** Animates the camera lens without forcing a React re-render. */
|
|
7
|
+
export declare function Lens({ ref, ...settings }: LensProps): null;
|