quaternion

Pure Gleam quaternion math library for 3D rotations.

Quaternions are a mathematical representation of rotations in 3D space that:

Quick Start

import q
import vec/vec3

// Create quaternion from axis-angle
let rotation = q.from_axis_angle(vec3.Vec3(0.0, 1.0, 0.0), 1.57)

// Or from Euler angles
let rotation = q.from_euler(vec3.Vec3(0.0, 1.57, 0.0))

// Rotate a vector
let rotated = q.rotate(rotation, vec3.Vec3(1.0, 0.0, 0.0))

// Interpolate between rotations
let halfway = q.slerp(from: rot1, to: rot2, t: 0.5)

Types

Quaternion represents a rotation in 3D space.

Quaternions use four components (x, y, z, w) where:

  • (x, y, z) represents the rotation axis scaled by sin(angle/2)
  • w represents cos(angle/2)
pub type Quaternion {
  Quaternion(x: Float, y: Float, z: Float, w: Float)
}

Constructors

  • Quaternion(x: Float, y: Float, z: Float, w: Float)

Values

pub fn angle(quat: Quaternion) -> Float

Get the rotation angle in radians.

pub fn axis(quat: Quaternion) -> Result(vec3.Vec3(Float), Nil)

Get the rotation axis.

Returns Error if the quaternion represents no rotation (identity).

pub fn conjugate(quat: Quaternion) -> Quaternion

Compute the conjugate of a quaternion.

The conjugate represents the inverse rotation.

pub fn dot(q1: Quaternion, q2: Quaternion) -> Float

Compute the dot product of two quaternions.

pub fn from_axis_angle(
  axis: vec3.Vec3(Float),
  angle: Float,
) -> Quaternion

Create a quaternion from axis-angle representation.

Parameters

  • axis: The rotation axis
  • angle: The rotation angle in radians

Example

// 90 degree rotation around Y axis
let rotation = q.from_axis_angle(vec3.Vec3(0.0, 1.0, 0.0), 1.57)
pub fn from_euler(euler: vec3.Vec3(Float)) -> Quaternion

Convert Euler angles (radians) to quaternion using XYZ rotation order.

Example

// Rotate 90 degrees around Y axis
let rotation = q.from_euler(vec3.Vec3(0.0, 1.57, 0.0))
pub fn from_to_rotation(
  from: vec3.Vec3(Float),
  to: vec3.Vec3(Float),
) -> Quaternion

Create a quaternion that rotates from one direction to another.

pub const identity: Quaternion

Identity quaternion (no rotation).

pub fn inverse(quat: Quaternion) -> Quaternion

Compute the inverse of a quaternion.

For unit quaternions (normalized), this is equivalent to the conjugate.

pub fn linear_interpolation(
  from from: Quaternion,
  to to: Quaternion,
  t t: Float,
) -> Quaternion

Linear interpolation between two quaternions.

Faster than slerp but doesn’t maintain constant angular velocity. Result should be normalized.

pub fn look_at(
  forward forward: vec3.Vec3(Float),
  target target: vec3.Vec3(Float),
  up up: vec3.Vec3(Float),
) -> Quaternion

Create a quaternion that looks from one direction toward a target direction.

Creates a rotation that orients the forward direction to point toward the target direction, with the given up vector for orientation. Useful for cameras and billboards.

Parameters

  • forward: The current forward direction (usually Vec3(0.0, 0.0, -1.0) for cameras)
  • target: The direction to look toward
  • up: The up vector for orientation (usually Vec3(0.0, 1.0, 0.0))

Example

// Make camera look at target from position
let camera_pos = Vec3(10.0, 10.0, 10.0)
let target_pos = Vec3(0.0, 0.0, 0.0)
let direction = vec3f.normalize(vec3f.subtract(target_pos, camera_pos))
let quat = look_at(Vec3(0.0, 0.0, -1.0), direction, Vec3(0.0, 1.0, 0.0))
pub fn loosely_equals(
  q1: Quaternion,
  q2: Quaternion,
  tolerating epsilon: Float,
) -> Bool

Check if two quaternions are approximately equal within a tolerance.

Useful for floating-point comparisons where exact equality is problematic. Note: Quaternions q and -q represent the same rotation, so this function checks both orientations.

Parameters

  • q1: First quaternion
  • q2: Second quaternion
  • epsilon: Tolerance for comparison (typically 0.0001 to 0.001)

Example

let q1 = from_euler(Vec3(0.0, 1.57, 0.0))
let q2 = from_euler(Vec3(0.0, 1.57001, 0.0))
loosely_equals(q1, q2, epsilon: 0.001)  // True
pub fn multiply(q1: Quaternion, q2: Quaternion) -> Quaternion

Multiply two quaternions (q1 * q2).

Represents the combined rotation of applying q1 then q2.

Example

let rotate_y = q.from_axis_angle(vec3.Vec3(0.0, 1.0, 0.0), 1.57)
let rotate_x = q.from_axis_angle(vec3.Vec3(1.0, 0.0, 0.0), 0.5)
let combined = q.multiply(rotate_y, rotate_x)
pub fn normalize(quat: Quaternion) -> Quaternion

Normalize a quaternion to unit length.

All rotation quaternions should be normalized.

pub fn rotate(
  quat: Quaternion,
  v: vec3.Vec3(Float),
) -> vec3.Vec3(Float)

Rotate a vector by a quaternion.

Example

let rotation = q.from_axis_angle(vec3.Vec3(0.0, 1.0, 0.0), 1.57)
let point = vec3.Vec3(1.0, 0.0, 0.0)
let rotated = q.rotate(rotation, point)  // ~Vec3(0.0, 0.0, -1.0)
pub fn spherical_linear_interpolation(
  from from: Quaternion,
  to to: Quaternion,
  t t: Float,
) -> Quaternion

Spherical linear interpolation (slerp) between two quaternions.

Provides smooth rotation interpolation without gimbal lock issues.

Parameters

  • from: Starting quaternion
  • to: Target quaternion
  • t: Interpolation factor (0.0 = from, 1.0 = to)

Example

let start = q.from_euler(vec3.Vec3(0.0, 0.0, 0.0))
let end = q.from_euler(vec3.Vec3(0.0, 1.57, 0.0))
let halfway = q.slerp(from: start, to: end, t: 0.5)
pub fn to_euler(quat: Quaternion) -> vec3.Vec3(Float)

Convert quaternion to Euler angles (radians) using XYZ rotation order.

Returns Vec3(roll, pitch, yaw).

Search Document