UNPKG

@needle-tools/engine

Version:

Needle Engine is a web-based runtime for 3D apps. It runs on your machine for development with great integrations into editors like Unity or Blender - and can be deployed onto any device! It is flexible, extensible and networking and XR are built-in.

227 lines (226 loc) 8.89 kB
import type { Quaternion, Vector2, Vector3, Vector4 } from "three"; import type { Vec3 } from "./engine_types.js"; declare type Vector = Vector3 | Vector4 | Vector2 | Quaternion; /** * Math utility class providing common mathematical operations. * Access via the exported `Mathf` constant. * * @example * ```ts * import { Mathf } from "@needle-tools/engine"; * * // Random number between 0 and 10 * const rand = Mathf.random(0, 10); * * // Clamp a value * const clamped = Mathf.clamp(value, 0, 100); * * // Smooth interpolation * const smoothed = Mathf.lerp(start, end, t); * ``` */ declare class MathHelper { /** * Returns a random number or element. * @param arr Array to pick a random element from * @returns Random element from array, or null if array is empty * @example `Mathf.random([1, 2, 3])` - returns random element */ random<T>(arr: Array<T>): T | null; /** * Returns a random number between min and max (inclusive). * @param min Minimum value (inclusive) * @param max Maximum value (inclusive) * @returns Random number in range, or 0-1 if no args provided * @example `Mathf.random(0, 10)` - returns 0 to 10 */ random(min?: number, max?: number): number; /** * Fills a Vector3 with random values. * @param target Vector3 to fill with random values * @param min Minimum value for each component * @param max Maximum value for each component */ randomVector3(target: Vector3, min?: number, max?: number): void; /** * Clamps a value between min and max. * @param value Value to clamp * @param min Minimum bound * @param max Maximum bound * @returns Clamped value */ clamp(value: number, min: number, max: number): number; /** * Clamps a value between 0 and 1. * @param value Value to clamp * @returns Value clamped to [0, 1] */ clamp01(value: number): number; /** * Linearly interpolates between two values. * @param value1 Start value (returned when t=0) * @param value2 End value (returned when t=1) * @param t Interpolation factor, clamped to [0, 1] * @returns Interpolated value */ lerp(value1: number, value2: number, t: number): number; /** * Calculates the linear interpolation parameter that produces the given value. * Inverse of lerp: if `lerp(a, b, t) = v`, then `inverseLerp(a, b, v) = t` * @param value1 Start value * @param value2 End value * @param t The value to find the parameter for * @returns The interpolation parameter (may be outside [0,1] if t is outside [value1, value2]) */ inverseLerp(value1: number, value2: number, t: number): number; /** * Remaps a value from one range to another. * @param value The value to remap. * @param min1 The minimum value of the current range. * @param max1 The maximum value of the current range. * @param min2 The minimum value of the target range. * @param max2 The maximum value of the target range. */ remap(value: number, min1: number, max1: number, min2: number, max2: number): number; /** * Moves a value towards a target by a maximum step amount. * Useful for smooth following or gradual value changes. * @param value1 Current value * @param value2 Target value * @param amount Maximum step to move (positive moves toward target) * @returns New value moved toward target, never overshooting */ moveTowards(value1: number, value2: number, amount: number): number; readonly Rad2Deg: number; readonly Deg2Rad: number; readonly Epsilon = 0.00001; /** * Converts radians to degrees */ toDegrees(radians: number): number; /** * Converts degrees to radians */ toRadians(degrees: number): number; tan(radians: number): number; gammaToLinear(gamma: number): number; linearToGamma(linear: number): number; /** * Checks if two vectors are approximately equal within epsilon tolerance. * Works with Vector2, Vector3, Vector4, and Quaternion. * @param v1 First vector * @param v2 Second vector * @param epsilon Tolerance for comparison (default: Number.EPSILON) * @returns True if all components are within epsilon of each other */ approximately(v1: Vector, v2: Vector, epsilon?: number): boolean; /** * Easing function: slow start, fast middle, slow end (cubic). * @param x Input value from 0 to 1 * @returns Eased value from 0 to 1 */ easeInOutCubic(x: number): number; } export declare const Mathf: MathHelper; declare class LowPassFilter { y: number | null; s: number | null; alpha: number; constructor(alpha: number); setAlpha(alpha: number): void; filter(value: number, alpha: number): number; lastValue(): number | null; reset(value: number): void; } /** * [OneEuroFilter](https://engine.needle.tools/docs/api/OneEuroFilter) is a low-pass filter designed to reduce jitter in noisy signals while maintaining low latency. * It's particularly useful for smoothing tracking data from XR controllers, hand tracking, or other input devices where the signal contains noise but responsiveness is important. * * The filter automatically adapts its smoothing strength based on the signal's velocity: * - When the signal moves slowly, it applies strong smoothing to reduce jitter * - When the signal moves quickly, it reduces smoothing to maintain responsiveness * * Based on the research paper: [1€ Filter: A Simple Speed-based Low-pass Filter for Noisy Input](http://cristal.univ-lille.fr/~casiez/1euro/) * * @example Basic usage with timestamp * ```ts * const filter = new OneEuroFilter(120, 1.0, 0.0); * * // In your update loop: * const smoothedValue = filter.filter(noisyValue, this.context.time.time); * ``` * * @example Without timestamps (using frequency estimate) * ```ts * // Assuming 60 FPS update rate * const filter = new OneEuroFilter(60, 1.0, 0.5); * * // Call without timestamp - uses the frequency estimate * const smoothedValue = filter.filter(noisyValue); * ``` * * @example Smoothing 3D positions * ```ts * const posFilter = new OneEuroFilterXYZ(90, 0.5, 0.0); * * posFilter.filter(trackedPosition, smoothedPosition, this.context.time.time); * ``` * * @see {@link OneEuroFilterXYZ} for filtering 3D vectors */ export declare class OneEuroFilter { /** * An estimate of the frequency in Hz of the signal (> 0), if timestamps are not available. */ freq: number; /** * Min cutoff frequency in Hz (> 0). Lower values allow to remove more jitter. */ minCutOff: number; /** * Parameter to reduce latency (> 0). Higher values make the filter react faster to changes. */ beta: number; /** * Used to filter the derivates. 1 Hz by default. Change this parameter if you know what you are doing. */ dCutOff: number; /** * The low-pass filter for the signal. */ x: LowPassFilter; /** * The low-pass filter for the derivates. */ dx: LowPassFilter; /** * The last time the filter was called. */ lasttime: number | null; /** Create a new OneEuroFilter * @param freq - An estimate of the frequency in Hz of the signal (> 0), if timestamps are not available. * @param minCutOff - Min cutoff frequency in Hz (> 0). Lower values allow to remove more jitter. * @param beta - Parameter to reduce latency (> 0). Higher values make the filter react faster to changes. * @param dCutOff - Used to filter the derivates. 1 Hz by default. Change this parameter if you know what you are doing. */ constructor(freq: number, minCutOff?: number, beta?: number, dCutOff?: number); alpha(cutOff: number): number; /** Filter your value: call with your value and the current timestamp (e.g. from this.context.time.time) */ filter(x: number, time?: number | null): number; reset(x?: number): void; } export declare class OneEuroFilterXYZ { readonly x: OneEuroFilter; readonly y: OneEuroFilter; readonly z: OneEuroFilter; /** Create a new OneEuroFilter * @param freq - An estimate of the frequency in Hz of the signal (> 0), if timestamps are not available. * @param minCutOff - Min cutoff frequency in Hz (> 0). Lower values allow to remove more jitter. * @param beta - Parameter to reduce latency (> 0). Higher values make the filter react faster to changes. * @param dCutOff - Used to filter the derivates. 1 Hz by default. Change this parameter if you know what you are doing. */ constructor(freq: number, minCutOff?: number, beta?: number, dCutOff?: number); filter(value: Vec3, target: Vec3, time?: number | null): void; reset(value?: Vec3): void; } export {};