import type { EulerOrder, Mat3Like, Quat, QuatLike, Vec3, Vec3Like } from './types'; export type { Quat, QuatLike }; /** Create a Quat (default all zero; callers usually call identity() right after). */ export declare function create(): Quat; /** Allocate a new Quat copy. */ export declare function clone(a: QuatLike): Quat; /** out = identity quaternion [0, 0, 0, 1]. Returns out. */ export declare function identity(out: Quat): Quat; /** * out = quaternion representing rotation by angleRadians around axis. Returns out. * * axis does not have to be pre-normalized; this function normalizes it internally. * * @degrade axis is the zero vector (lengthSq < EPS_NORMALIZE) → out = identity * (no throw, registry #8). * * @example * ```ts * quat.fromAxisAngle(out, [0, 1, 0], Math.PI / 2); * // Guard: if (vec3.lengthSq(axis) < EPS_NORMALIZE) skip; * ``` */ export declare function fromAxisAngle(out: Quat, axis: Vec3Like, angleRadians: number): Quat; /** * out = quaternion from intrinsic Euler angles (x, y, z, order). Returns out. * * Angle unit = **radians** (aligned with wgpu-matrix / Three.js; research §fact-correction 4 * deviates from gl-matrix's degrees). * 6 orders: XYZ / YXZ / ZXY / ZYX / YZX / XZY (intrinsic rotation: literal order x → y → z). * Implementation: split each axis rotation into single-axis quaternions, then Hamilton-multiply * in `order`. * * @degrade order outside the EulerOrder union (only possible via `as any` cast) → * **silently computes as if 'XYZ'** (D-P2 + AC-06 no throw; registry #9). * * @example * ```ts * quat.fromEuler(out, 0.5, 0.3, 0.1, 'XYZ'); * quat.fromEuler(out, 0.5, 0.3, 0.1, 'unknown' as any); // silently computed as 'XYZ' * // Guard: pass an EulerOrder union literal; the TS layer already blocks unknown strings. * ``` */ export declare function fromEuler(out: Quat, x: number, y: number, z: number, order: EulerOrder): Quat; /** * out = quaternion from a 3x3 rotation matrix m (column-major, length 9). Returns out. * * Implementation: Shepperd's case-split (branch on trace / largest diagonal entry); numerically * more stable than the direct trace method (avoids sqrt(0) when trace ≈ -1). * * Assumption: m is a pure rotation matrix (|det|=1, columns orthogonal). If not, the result is * undefined but does not throw. * * @degrade m is not a pure rotation (contains shear / scale) → numerically undefined but does * not throw (AC-06 no throw; callers should normalize column vectors first or avoid * introducing non-pure-rotation matrices at the ECS-design layer). * * @example * ```ts * quat.fromRotationMatrix(out, mat3InstanceColumnMajor); * ``` */ export declare function fromRotationMatrix(out: Quat, m: Mat3Like): Quat; /** * out = orientation quaternion for an object placed at `eye` and facing `target`. Returns out. * * This is the ergonomic camera/look-at helper: it yields the WORLD-space orientation an entity's * Transform.rotation needs so that its local -z axis points from `eye` toward `target` (the camera * convention, matching `mat4.lookAt`). Use it instead of hand-wiring * `mat4.lookAt → mat4.invert → mat3.fromMat4 → quat.fromRotationMatrix`; that chain is easy to get * wrong (notably `fromRotationMatrix` takes a mat3, but `Mat4Like`≡`Mat3Like`≡`ArrayLike`, * so passing a mat4 typechecks and silently reads garbage → NaN → nothing renders). * * Convenience composition (like `mat4.computeViewProj`), not a primitive: it builds the same * right/newUp/forward basis as `mat4.lookAt` and reuses `fromRotationMatrix` for the extraction. * * @degrade eye ≈ target (|eye-target| < EPS_NORMALIZE) → out = identity (same convention as * `mat4.lookAt` degenerate #4; no throw, AC-06). * @degrade up collinear with the view direction → alternative up auto-selected (same as * `mat4.lookAt` #5). * * @example * ```ts * // aim a camera at the origin * const q = quat.fromLookAt(quat.create(), [-2.5, 4.5, 9], [0, 0, 0], [0, 1, 0]); * world.set(cameraEntity, Transform, { pos: [-2.5, 4.5, 9], rot: q }); * ``` */ export declare function fromLookAt(out: Quat, eye: Vec3Like, target: Vec3Like, up: Vec3Like): Quat; /** * out = quaternion that rotates the unit vector v to w (shortest arc). Returns out. * * Assumes v and w are normalized; if not, the caller is responsible. * * @degrade v ≈ w (dot > 1 - EPS_QUAT_PARALLEL) → out = identity (registry #13). * @degrade v ≈ -w (dot < -1 + EPS_QUAT_PARALLEL) → pick a perpendicular axis and do a 180° * rotation (prefer (0,1,0); fall back to (1,0,0) when collinear with v; * registry #12 + D-P18). * * @example * ```ts * quat.fromUnitVectors(out, [1,0,0], [0,1,0]); // 90° around Z * quat.fromUnitVectors(out, [1,0,0], [-1,0,0]); // 180° opposite: pick (0,1,0) axis * ``` */ export declare function fromUnitVectors(out: Quat, v: Vec3Like, w: Vec3Like): Quat; /** * out = a * b (Hamilton product). Returns out. * * Aliasing-safe: reads all 8 source elements into locals first. */ export declare function multiply(out: Quat, a: QuatLike, b: QuatLike): Quat; /** * out = the orientation `q` after rotating a further `angleRadians` about world-space `axis`, * re-normalized. Returns out. * * This is the ergonomic *incremental rotate* helper — the per-frame spin/animation move. It folds * the three steps every rotating demo otherwise hand-wires: build the delta quaternion * (`fromAxisAngle`), **pre**-multiply it onto the current orientation (world-space axis, matching * **Bevy `Transform::rotate(r)` = `r * self.rotation`** / `rotate_y(θ)`), and — the step that is * silently omitted and makes the naive loop wrong — **normalize** to shed the floating-point error * that accumulates over thousands of frames into a non-unit quaternion (skew / scale artefacts). * * Prefer this over hand-writing `quat.multiply(q, delta, q)` in an update system: that loop drifts, * so demos work around it with an absolute-angle accumulator + `fromAxisAngle` (can't compose onto an * existing orientation) or raw `sin/cos` quaternion literals. `rotateAxis` composes safely. * * Convenience composition (like `fromLookAt`), not a primitive: same result as * `normalize(out, multiply(out, fromAxisAngle(tmp, axis, angleRadians), q))`, fused + aliasing-safe. * * @degrade `axis` zero-length → the delta is identity (degenerate registry #8), so out = normalize(q) * (no rotation applied; no throw, consistent with the sibling helpers). * * @example * ```ts * // in an Update system: spin a cube about +Y at `speed` rad/s using the frame delta * const dt = world.getResource(Time).delta; * const t = world.get(entity, Transform).unwrap(); * quat.rotateAxis(t.quat, t.quat, [0, 1, 0], speed * dt); // in-place accumulate, no drift * world.set(entity, Transform, t); * ``` */ export declare function rotateAxis(out: Quat, q: QuatLike, axis: Vec3Like, angleRadians: number): Quat; /** * out = spherical linear interpolation(a, b, t). Returns out. * * t is not clamped (extrapolation semantics matches vec.lerp). * * @degrade dot(a, b) < -EPS_SLERP_DOT_LIMIT (anti-parallel) → **negate b' = -b then slerp** * (D-P6; q and -q represent the same rotation; registry #10). * @degrade |dot(a, b)| > 1 - EPS_SLERP_DOT_LIMIT (endpoint coincidence or near-coincidence) → * falls back to nlerp (avoids acos blow-up; registry #11). * * @example * ```ts * quat.slerp(out, a, b, 0.5); * // Anti-parallel (dot ≈ -1): caller does not need to pre-process; the negation fall-back * // happens internally. * ``` */ export declare function slerp(out: Quat, a: QuatLike, b: QuatLike, t: number): Quat; /** * out = normalized lerp(a, b, t). Returns out. * * Faster than slerp but the angular velocity is non-uniform; use it as a slerp substitute near endpoints. * Like slerp, automatically handles dot < 0 by negating b to keep the shortest arc. * * @degrade lerp result is near zero (very rare) → out = identity. * * @example * ```ts * quat.nlerp(out, qA, qB, 0.5); * // Very rare: lerp result lengthSq < EPS_NORMALIZE → out = (0, 0, 0, 1) * ``` */ export declare function nlerp(out: Quat, a: QuatLike, b: QuatLike, t: number): Quat; /** * out = inverse of a (conjugate / lengthSq). Returns out. * * For unit quaternions, invert is equivalent to conjugate (and faster); this implementation uses * the general a/|a|² form to support non-unit inputs. * * @degrade lengthSq(a) < EPS_NORMALIZE (zero quaternion) → out = identity (does not return NaN; * same convention as mat invert). * * @example * ```ts * quat.invert(out, q); * quat.invert(out, quat.create(0, 0, 0, 0)); // → out = identity (0, 0, 0, 1), AC-06 no throw * ``` */ export declare function invert(out: Quat, a: QuatLike): Quat; /** out = conjugate quaternion [-x, -y, -z, w] (aliasing-safe). Returns out. */ export declare function conjugate(out: Quat, a: QuatLike): Quat; /** dot(a, b) = ax*bx + ay*by + az*bz + aw*bw (returns scalar). */ export declare function dot(a: QuatLike, b: QuatLike): number; /** sqrt(x² + y² + z² + w²). Delegates to lengthSq + Math.sqrt (canonical pattern; see clone-5-quat-audit.md). */ export declare function length(a: QuatLike): number; /** x² + y² + z² + w² (no sqrt). */ export declare function lengthSq(a: QuatLike): number; /** * out = q · v · q⁻¹ (rotate vec3 v by the unit quaternion q). Returns out. * * Rodrigues optimized form (research Finding 3, 18 mul + 12 add): * t = 2 · cross(q.xyz, v) * out = v + q.w · t + cross(q.xyz, t) * * 3-5× faster than going through mat4 (fromQuat → transformVec3); same shape as gl-matrix * `vec3.transformQuat` / Three.js `Vector3.applyQuaternion` (industry consensus). * * Aliasing-safe: reads v.xyz / q.xyzw into locals before writing out. * * @degrade q must be a unit-length quaternion. A non-unit q introduces implicit scaling * (D-4 silent convention; no throw; AI users always get unit-length q from * quat.fromAxisAngle / fromEuler / normalize / slerp, so this branch is not hit). * When q = (0,0,0,0), t = 0 → out = v (the natural result of the formula; matches * gl-matrix / Three.js; non-NaN, no throw). * * @example * ```ts * const q = quat.fromAxisAngle(quat.create(), [0, 1, 0], Math.PI / 2); * const out = vec3.create(); * quat.transformVec3(out, q, [1, 0, 0]); // → out ≈ (0, 0, -1) * // Guard: q derived from the quat surface is always unit-length; callers do not need to normalize. * ``` */ export declare function transformVec3(out: Vec3, q: QuatLike, v: Vec3Like): Vec3; /** * out = a / length(a). Returns out. * * @degrade lengthSq(a) < EPS_NORMALIZE → out = [0, 0, 0, 0] (same convention as vec.normalize; * does not write identity, preserving the "zero quaternion" semantics; if the caller * needs identity it should use fromAxisAngle with 0-axis). * * @example * ```ts * quat.normalize(out, q); * quat.normalize(out, quat.create(0, 0, 0, 0)); // → out = (0, 0, 0, 0); zero-quaternion semantics preserved * ``` */ export declare function normalize(out: Quat, a: QuatLike): Quat; /** * Convenience: quaternion representing rotation `theta` radians around the * Y axis. Equivalent to `quat.fromEuler(out, 0, theta, 0, 'YXZ')` but * allocates its own output `Quat`. * * Formula: `(0, sin(theta/2), 0, cos(theta/2))`. * * @degrade eulerY(0) → identity, eulerY(2pi) → identity within epsilon. * * @example * ```ts * const yaw45 = quat.eulerY(Math.PI / 4); * // yaw45 ≈ [0, 0.3826834, 0, 0.9238795] * ``` * * @example Equivalent to the verbose form: * ```ts * const q1 = quat.eulerY(theta); * const q2 = quat.fromEuler(quat.create(), 0, theta, 0, 'YXZ'); * // q1 === q2 (within epsilon) * ``` */ export declare function eulerY(theta: number): Quat; /** * Local right axis: the world-space direction the rotation's own +X axis points. * `right(out, q) = quat.transformVec3(out, q, [1, 0, 0])`. Mirrors * `mat4.getRight`; matches Bevy `Transform::local_x` / `Transform::right`. * * @degrade q must be unit-length (guaranteed by the quat surface); a unit q * yields a unit result. q = (0,0,0,0) → out = (1,0,0) (the natural * transformVec3 result; non-NaN, no throw). * * @example * ```ts * const q = quat.eulerY(Math.PI / 2); // 90° about +Y * quat.right(vec3.create(), q); // → (0, 0, -1): +X yawed a quarter-turn * ``` */ export declare function right(out: Vec3, q: QuatLike): Vec3; /** * Local up axis: the world-space direction the rotation's own +Y axis points. * `up(out, q) = quat.transformVec3(out, q, [0, 1, 0])`. Mirrors `mat4.getUp`; * matches Bevy `Transform::local_y` / `Transform::up`. * * @degrade q must be unit-length (guaranteed by the quat surface); a unit q * yields a unit result. q = (0,0,0,0) → out = (0,1,0). * * @example * ```ts * const q = quat.fromAxisAngle(quat.create(), [1, 0, 0], Math.PI / 2); // pitch 90° * quat.up(vec3.create(), q); // → (0, 0, 1): +Y pitched onto +Z * ``` */ export declare function up(out: Vec3, q: QuatLike): Vec3; /** * Local forward axis: the world-space direction the rotation's own −Z axis * points (−Z look convention, RL-4). `forward(out, q) = * quat.transformVec3(out, q, [0, 0, -1])`. Mirrors `mat4.getForward`; matches * Bevy `Transform::forward` (Bevy also uses −Z). A quat from `fromLookAt(eye, * target, up)` has `forward(q)` ≈ normalize(target − eye). * * @degrade q must be unit-length (guaranteed by the quat surface); a unit q * yields a unit result. q = (0,0,0,0) → out = (0,0,-1). * * @example * ```ts * const q = quat.eulerY(Math.PI / 2); // 90° about +Y * quat.forward(vec3.create(), q); // → (-1, 0, 0): -Z yawed a quarter-turn * ``` */ export declare function forward(out: Vec3, q: QuatLike): Vec3; //# sourceMappingURL=quat.d.ts.map