UNPKG

@threlte/extras

Version:

Utilities, abstractions and plugins for your Threlte apps

105 lines (104 loc) 4.62 kB
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>;