Documentation
    Preparing search index...

    Class Quaternion

    Mutable unit quaternion (x, y, z, w) representing a 3D rotation (§7b). The world is right-handed with +Y up (§7a) and every angle is radians; quaternions compose with the Hamilton product, so a.multiply(b) yields the rotation that applies b first and a second.

    The identity rotation is (0, 0, 0, 1) — hence w defaults to 1 while the vector part defaults to 0.

    Allocation policy (§7b, plan D7): mutating methods mutate in place and return this; only Quaternion.clone allocates. Quaternion.rotateVector3 produces a result that is not this, so it takes a required out parameter and returns it — nothing on that path allocates either.

    Change notification (plan D3): every mutator invokes Quaternion.onChanged exactly once, after the last component is written. Direct field writes (q.x = 1) bypass the hook by design.

    Methods assume unit quaternions where the mathematics requires it (Quaternion.conjugate as inverse, Quaternion.rotateVector3, Quaternion.slerp); nothing normalizes defensively on those hot paths.

    Index
    • Parameters

      • x: number = 0
      • y: number = 0
      • z: number = 0
      • w: number = 1

      Returns Quaternion

    onChanged?: () => void

    Optional change hook invoked at the end of every mutator. Engine-internal: owners install it, user code normally leaves it unset. It is intentionally not copied by Quaternion.copy or Quaternion.clone.

    w: number
    x: number
    y: number
    z: number
    • Allocates a new quaternion with the same components. The clone has no change hook. This is the only allocating method on the type (§7b).

      Returns Quaternion

    • Negates the vector part, giving the conjugate. For a unit quaternion this is the inverse rotation; for a non-unit quaternion it is not (the inverse would also divide by the squared length).

      Returns this

    • Resets this quaternion to the identity rotation (0, 0, 0, 1).

      Returns this

    • Hamilton product this = this * q: the resulting rotation applies q first and this quaternion second. Aliasing-safe — q may be this.

      Parameters

      Returns this

    • Scales this quaternion to unit length.

      Zero-length behaviour (defined here): a zero-length quaternion is not a rotation at all and cannot be scaled into one, so it is reset to the identity rather than producing NaN. This differs from Vector3.normalize, which leaves the zero vector alone — the zero vector is a legitimate value downstream, the zero quaternion never is. The change hook fires in either case.

      Range behaviour — the guard below tests the squared length, so three ranges do not produce a unit quaternion and none of them reports an error (measured from a consumer seat, dogfood cycle 10):

      • Underflow. A squared length that rounds to 0 (components below about 1.57e-162) is read as zero length, so the quaternion is reset to the identity — a tiny but real rotation is discarded silently.
      • Overflow. A component at or above 1.3407807929942597e+154 squares to Infinity, so the reciprocal is 0 and every component becomes 0, including w. Unlike the zero-length branch, this leaves the zero quaternion rather than the identity.
      • Non-finite input. A NaN component makes lengthSquared > 0 false, so the quaternion is reset to the identity; an infinite component gives NaN in that slot and 0 in the others.

      Returns this

    • Rotates v by this (unit) quaternion and writes the result into out, which is required (plan D7: the result is not this, so the caller owns the storage — nothing here allocates). Returns out.

      Aliasing-safe: v and out may be the same vector; v is read into scalars before out is written. This quaternion is not modified and its change hook does not fire; out is written through Vector3.set, so out's hook fires exactly once.

      Uses v' = v + 2 * w * (u x v) + 2 * (u x (u x v)) with u = (x, y, z), the standard expansion of q * v * q⁻¹ for unit q.

      Parameters

      Returns Vector3

    • Sets all four components.

      Parameters

      • x: number
      • y: number
      • z: number
      • w: number

      Returns this

    • Sets this quaternion to the rotation of angleRadians about axis, counter-clockwise when looking down the axis toward the origin (right-handed, §7a). Angles are radians (§7a) — there is no degree overload.

      axis need not be unit length: it is normalized from plain scalars, with no temporary vector. A zero-length axis has no direction to rotate about, so it produces the identity rotation rather than NaN (defined here; the same "no-op beats poisoning the frame" reasoning as Vector3.normalize). The change hook fires in either case.

      Parameters

      • axis: Vector3
      • angleRadians: number

      Returns this

    • Sets this quaternion to the rotation that aims the −Z axis along direction while keeping the +Y axis as close to up as the aim allows (§7a: right-handed, +Y up; §7b: radians and mutable math types).

      −Z is the engine's one "forward" for every node, not a camera special case: Matrix4.setPerspective projects down −Z (plan D8), Camera.viewMatrix is the inverse of a world matrix built on that basis, and a directional or spot light shines along its node's −Z (§68). One convention means a rig aims a camera and a light with the same call.

      Neither argument need be unit length and up need not be perpendicular to direction: the basis is built as

      zAxis = normalize(−direction)      // local +Z, opposite the aim
      xAxis = normalize(up × zAxis)      // local +X
      yAxis = zAxis × xAxis              // local +Y, already unit
      

      and converted with Shepperd's method, so the result is a unit quaternion built from an exactly orthonormal basis. Allocates nothing — the basis lives in plain scalars — and writes through a single set(...), so the change hook fires exactly once.

      A zero-length direction, a zero-length up, an up parallel to direction, or a non-finite component of either leaves every component alone and does not fire the change hook: there is no rotation those inputs describe, and the two rejected alternatives are both worse. Resetting to the identity substitutes a different, plausible-looking orientation for the failure (the reasoning Matrix4.invert already gives for refusing a singular matrix); picking a fallback up silently rewrites the aim the caller asked for. Leaving the previous aim in place is the only outcome that neither invents nor destroys information.

      The math package validates nothing (see Matrix4.setPerspective), so this method reports nothing either. Node.lookAt in @fourjs/scene is the policy layer: it makes the same two tests on its own inputs and throws, so a scene node never reaches the silent branch.

      Parameters

      Returns this

    • Spherically interpolates this quaternion toward target by t, mutating this quaternion. t = 0 leaves it unchanged, t = 1 makes it equal to target (up to sign — see below). Values outside [0, 1] extrapolate along the same arc; no clamping is applied. Both inputs are assumed unit length.

      Shortest arc (plan D8): q and -q denote the same rotation, so when the dot product is negative the target's components are negated for the interpolation. The result then travels the short way round, and at t = 1 equals -target — the same rotation as target, with opposite components.

      Nearly parallel inputs (dot above SLERP_LINEAR_THRESHOLD, 0.9995) fall back to normalized linear interpolation, which avoids dividing by sin(theta) as theta goes to zero. See that constant for the error bound.

      Parameters

      Returns this