@threlte/extras
Version:
Utilities, abstractions and plugins for your Threlte apps
105 lines (104 loc) • 4.62 kB
TypeScript
import { Object3D, Vector3, type Vector2Tuple, type Vector3Tuple } from 'three';
import type CameraControls from 'camera-controls';
export interface UseFollowOptions {
target?: Object3D | undefined | null;
/**
* The `CameraControls` instance from `<CameraControls>` that the follow
* behavior is attached to. The hook is a no-op while this is falsy, so
* it's safe to pass a ref that hasn't mounted yet.
*/
controls?: CameraControls | null;
/**
* Offset added to the target's world position when setting the
* `CameraControls` target — used to look at the character's head, chest,
* or some other part of the rig rather than the origin.
* @default [0, 0, 0]
*/
lookAtOffset?: Vector3Tuple;
/**
* Dead zone in camera-space right/up axes. The target may drift this far
* from the currently tracked position before the camera starts following.
* Axes left at `0` have no dead zone on that axis.
* @default [0, 0]
*/
deadZone?: Vector2Tuple;
/**
* Shift the tracked point in the target's direction of motion, expressed
* as seconds of preview (`velocity * lookAhead`). `0` disables look-ahead.
* @default 0
*/
lookAhead?: number;
/**
* Smoothing time in seconds for the velocity that drives `lookAhead`.
* Prevents the look-ahead offset from snapping to full magnitude the
* instant a character starts or stops moving — it ramps in and out over
* this duration instead.
* @default 0.15
*/
lookAheadSmoothTime?: number;
/**
* Smoothing time in seconds for the camera position's translation,
* producing a trailing / cinematic follow. Only the tracked base position
* is smoothed; `lookAtOffset` and `lookAhead` are added unsmoothed on top,
* so tweaking `lookAtOffset` feels snappy. The smoothed target is passed
* to `CameraControls` before its update runs, so collision and other
* `CameraControls` features apply to the smoothed pose.
*
* `0` (the default) disables follow smoothing. Rotation/zoom input still
* smooths via `CameraControls`' own `smoothTime`.
* @default 0
*/
followSmoothTime?: number;
/**
* When `true`, drive the camera's azimuth from the target's Y-axis world
* rotation each frame, so the camera turns with the character. User orbit input
* on the horizontal axis is effectively overridden while this is on; polar orbit
* and zoom still work.
*
* Don't pair with `minAzimuthAngle`/`maxAzimuthAngle` limits on
* `<CameraControls>` — the tracker will fight the limits.
* @default false
*/
trackRotation?: boolean;
/**
* Smoothing time in seconds for rotation tracking. `0` (the default)
* snaps the camera's azimuth to the target's yaw each frame. Higher values ease the
* camera into the character's facing direction.
* @default 0
*/
trackRotationSmoothTime?: number;
/**
* Additional azimuth offset (radians) applied after rotation tracking.
* Set to `Math.PI` to sit the camera behind a character whose local `+Z`
* axis is its forward, or `0` for a character whose local `-Z` is
* forward.
* @default 0
*/
trackRotationOffset?: number;
}
export declare const useFollow: (optionsFn?: () => UseFollowOptions) => {
/** Internal task, exposed for ordering other tasks via `after`/`before`. */
task: import("@threlte/core").Task;
/**
* Project a 2D input into a world-space direction aligned with the
* camera's horizontal basis. `right` maps to the camera's right axis,
* `forward` to its forward axis (both flattened to the XZ plane). Writes
* to `out` and returns it.
*
* Used to make character movement feel correct regardless of how the
* user has orbited the camera: `W` always means "away from camera".
*/
getInputDirection: (right: number, forward: number, out: Vector3) => Vector3;
/**
* Project a 2D input into a world-space direction aligned with the
* target's own horizontal basis — `forward` follows the target's local
* `+Z` axis, `right` follows its local `+X`. Writes to `out` and returns
* it.
*
* Use this instead of `getInputDirection` when `trackRotation` is on:
* camera-relative input combined with rotation tracking creates a
* feedback loop and the character will spin.
*/
getTargetDirection: (right: number, forward: number, out: Vector3) => Vector3;
};
export type UseFollowReturn = ReturnType<typeof useFollow>;