Skip to content

linalg

stable

Linear algebra library providing 2D, 3D, and 4D vectors, 3x3 and 4x4 matrices, quaternions, and common graphics transforms like perspective, look-at, and quaternion slerp.

use plugin linalg::{vec2, vec2_add, vec2_sub, …}
57 functions Math
/ filter jk navigate Esc clear
Functions (57)
  1. vec2 Create a 2D vector
  2. vec2_add Add two vec2 values
  3. vec2_sub Subtract two vec2 values
  4. vec2_dot Dot product of two vec2 values
  5. vec2_length Magnitude of a vec2
  6. vec2_normalize Unit-length vec2
  7. vec2_rotate Rotate a vec2 by angle in radians
  8. vec2_perpendicular 90-degree perpendicular vec2
  9. vec2_scale Multiply vec2 by a scalar
  10. vec2_distance Distance between two vec2 points
  11. vec2_lerp Linear interpolation between two vec2 values
  12. vec3 Create a 3D vector
  13. vec3_add Add two vec3 values
  14. vec3_sub Subtract two vec3 values
  15. vec3_dot Dot product of two vec3 values
  16. vec3_cross Cross product of two vec3 values
  17. vec3_normalize Unit-length vec3
  18. vec3_length Magnitude of a vec3
  19. vec3_scale Multiply vec3 by a scalar
  20. vec3_distance Distance between two vec3 points
  21. vec3_lerp Linear interpolation between two vec3 values
  22. vec3_negate Negate all components of a vec3
  23. vec3_angle Angle in radians between two vec3 values
  24. vec4 Create a 4D vector
  25. vec4_add Add two vec4 values
  26. vec4_sub Subtract two vec4 values
  27. vec4_dot Dot product of two vec4 values
  28. vec4_normalize Unit-length vec4
  29. vec4_length Magnitude of a vec4
  30. vec4_scale Multiply vec4 by a scalar
  31. vec4_lerp Linear interpolation between two vec4 values
  32. project Project vec3 onto another vec3
  33. reflect Reflect vec3 around a surface normal
  34. mat3_identity Create a 3x3 identity matrix
  35. mat3_mul Multiply two 3x3 matrices
  36. mat3_transpose Transpose a 3x3 matrix
  37. mat3_inverse Invert a 3x3 matrix
  38. mat3_determinant Determinant of a 3x3 matrix
  39. mat4_identity Create a 4x4 identity matrix
  40. mat4_mul Multiply two 4x4 matrices
  41. mat4_translation Translation matrix from x, y, z
  42. mat4_rotation_x Rotation matrix around X axis
  43. mat4_rotation_y Rotation matrix around Y axis
  44. mat4_rotation_z Rotation matrix around Z axis
  45. mat4_scale Scale matrix from x, y, z
  46. mat4_perspective Perspective projection matrix
  47. mat4_orthographic Orthographic projection matrix
  48. mat4_look_at Camera view matrix
  49. mat4_transpose Transpose a 4x4 matrix
  50. mat4_inverse Invert a 4x4 matrix
  51. mat4_determinant Determinant of a 4x4 matrix
  52. mat4_from_quat Rotation matrix from quaternion components
  53. quat_from_euler Quaternion from pitch, yaw, roll
  54. quat_mul Multiply two quaternions
  55. quat_slerp Spherical interpolation between quaternions
  56. transform_point Apply mat4 to a point (with translation)
  57. transform_direction Apply mat4 to a direction (no translation)

Overview

linalg is a dependency-free math toolkit for 2D, 3D, and 4D graphics. It has no opaque handles or hidden state: a vector is an ordinary table ({x, y}, {x, y, z}, or {x, y, z, w}), a matrix is a flat array table of 9 or 16 numbers in column-major order, and a quaternion is just a vec4 {x, y, z, w}. Every function takes plain tables and returns plain tables, so values are easy to store, pass around, and inspect by field.

The core concept is composition. Build vectors with vec2 / vec3 / vec4, build transform matrices with the mat4_* constructors (mat4_translation, mat4_rotation_y, mat4_perspective, mat4_look_at, ...), chain them together with mat4_mul, and finally apply the result to geometry with transform_point and transform_direction. Quaternion helpers (quat_from_euler, quat_mul, quat_slerp, mat4_from_quat) cover smooth rotation. Use it whenever you need camera math, model transforms, normals, projections, or interpolation without pulling in an external linear-algebra dependency.

A few invariants are worth keeping in mind: matrices are column-major, rotation angles are in radians, and functions like vec3_normalize, mat4_inverse, and mat4_look_at raise an error on degenerate input (zero vectors, singular matrices, or an eye point equal to the center) rather than returning garbage.

Common patterns

Build a model-view-projection matrix and transform a point with it:

use plugin linalg::{vec3, mat4_perspective, mat4_look_at, mat4_translation, mat4_mul, transform_point}

let proj = mat4_perspective(1.0472, 1.7778, 0.1, 1000.0)
let view = mat4_look_at(vec3(0.0, 5.0, 10.0), vec3(0.0, 0.0, 0.0), vec3(0.0, 1.0, 0.0))
let model = mat4_translation(2.0, 0.0, 0.0)

let mvp = mat4_mul(mat4_mul(proj, view), model)
let screen = transform_point(mvp, vec3(0.0, 0.0, 0.0))
print("x={screen["x"]} y={screen["y"]} z={screen["z"]}")

Convert Euler angles to a quaternion, turn it into a rotation matrix, and rotate a direction:

use plugin linalg::{vec3, quat_from_euler, mat4_from_quat, transform_direction}

let q = quat_from_euler(0.0, 1.5707963, 0.0)
let rot = mat4_from_quat(q["x"], q["y"], q["z"], q["w"])
let facing = transform_direction(rot, vec3(0.0, 0.0, -1.0))
print("facing: {facing["x"]}, {facing["y"]}, {facing["z"]}")

Compute a triangle's surface normal from its three corners:

use plugin linalg::{vec3, vec3_sub, vec3_cross, vec3_normalize}

let a = vec3(0.0, 0.0, 0.0)
let b = vec3(1.0, 0.0, 0.0)
let c = vec3(0.0, 1.0, 0.0)
let normal = vec3_normalize(vec3_cross(vec3_sub(b, a), vec3_sub(c, a)))
print("normal: {normal["x"]}, {normal["y"]}, {normal["z"]}")

Create a 2D vector

Creates a 2D vector table with x and y fields.

use plugin linalg::{vec2, vec2_add, vec2_length}

let a = vec2(3.0, 4.0)
let b = vec2(1.0, 0.0)
let sum = vec2_add(a, b)
print("Length: {vec2_length(a)}")

Add two vec2 values

Adds two vec2 tables component-wise. Returns a new vec2.

use plugin linalg::{vec2, vec2_add}

let result = vec2_add(vec2(1.0, 2.0), vec2(3.0, 4.0))

Subtract two vec2 values

Subtracts b from a component-wise.

use plugin linalg::{vec2, vec2_sub}

let delta = vec2_sub(vec2(5.0, 5.0), vec2(2.0, 1.0))

Dot product of two vec2 values

Returns the scalar dot product of two vec2 values.

use plugin linalg::{vec2, vec2_dot}

let d = vec2_dot(vec2(1.0, 0.0), vec2(0.0, 1.0))

Magnitude of a vec2

Returns the Euclidean length (magnitude) of a vec2.

use plugin linalg::{vec2, vec2_length}

print(vec2_length(vec2(3.0, 4.0)))

Unit-length vec2

Returns a unit-length copy of v. Errors if v is the zero vector.

use plugin linalg::{vec2, vec2_normalize}

let n = vec2_normalize(vec2(3.0, 4.0))

Rotate a vec2 by angle in radians

Rotates v by angle radians counter-clockwise.

use plugin linalg::{vec2, vec2_rotate}

let rotated = vec2_rotate(vec2(1.0, 0.0), 1.5707963)

90-degree perpendicular vec2

Returns a vector perpendicular to v (rotated 90 degrees counter-clockwise): (-y, x).

use plugin linalg::{vec2, vec2_perpendicular}

let perp = vec2_perpendicular(vec2(1.0, 0.0))

Multiply vec2 by a scalar

Multiplies each component of v by scalar s.

use plugin linalg::{vec2, vec2_scale}

let doubled = vec2_scale(vec2(1.0, 2.0), 2.0)

Distance between two vec2 points

Returns the Euclidean distance between two vec2 points.

use plugin linalg::{vec2, vec2_distance}

let d = vec2_distance(vec2(0.0, 0.0), vec2(3.0, 4.0))

Linear interpolation between two vec2 values

Linearly interpolates between a and b by factor t (0.0 = a, 1.0 = b).

use plugin linalg::{vec2, vec2_lerp}

let mid = vec2_lerp(vec2(0.0, 0.0), vec2(10.0, 10.0), 0.5)

Sample the path between two points to animate a position over several frames:

use plugin linalg::{vec2, vec2_lerp}

let from = vec2(0.0, 0.0)
let to = vec2(100.0, 50.0)
for i in 0..5 {
  let p = vec2_lerp(from, to, i / 4.0)
  print("frame {i}: ({p["x"]}, {p["y"]})")
}

Create a 3D vector

Creates a 3D vector table with x, y, and z fields.

use plugin linalg::{vec3, vec3_cross, vec3_normalize}

let up = vec3(0.0, 1.0, 0.0)
let fwd = vec3(0.0, 0.0, -1.0)
let right = vec3_normalize(vec3_cross(fwd, up))

Add two vec3 values

Adds two vec3 tables component-wise.

use plugin linalg::{vec3, vec3_add}

let sum = vec3_add(vec3(1.0, 2.0, 3.0), vec3(4.0, 5.0, 6.0))

Subtract two vec3 values

Subtracts b from a component-wise.

use plugin linalg::{vec3, vec3_sub}

let diff = vec3_sub(vec3(5.0, 5.0, 5.0), vec3(1.0, 2.0, 3.0))

Dot product of two vec3 values

Returns the scalar dot product of two vec3 values. Useful for computing angles and projections.

use plugin linalg::{vec3, vec3_dot}

let d = vec3_dot(vec3(1.0, 0.0, 0.0), vec3(0.0, 1.0, 0.0))

Cross product of two vec3 values

Returns the cross product of a and b, a vector perpendicular to both. Commonly used to compute surface normals.

use plugin linalg::{vec3, vec3_cross}

let normal = vec3_cross(vec3(1.0, 0.0, 0.0), vec3(0.0, 1.0, 0.0))

Build an orthonormal basis: derive the camera's right vector from forward and up.

use plugin linalg::{vec3, vec3_cross, vec3_normalize}

let forward = vec3(0.0, 0.0, -1.0)
let up = vec3(0.0, 1.0, 0.0)
let right = vec3_normalize(vec3_cross(forward, up))
print("right: {right["x"]}, {right["y"]}, {right["z"]}")

Unit-length vec3

Returns a unit-length copy of v. Errors if v is the zero vector.

use plugin linalg::{vec3, vec3_normalize}

let n = vec3_normalize(vec3(1.0, 2.0, 2.0))

Magnitude of a vec3

Returns the Euclidean length of a vec3.

use plugin linalg::{vec3, vec3_length}

print(vec3_length(vec3(1.0, 2.0, 2.0)))

Multiply vec3 by a scalar

Multiplies each component of v by scalar s.

use plugin linalg::{vec3, vec3_scale}

let big = vec3_scale(vec3(1.0, 1.0, 1.0), 10.0)

Distance between two vec3 points

Returns the Euclidean distance between two vec3 points.

use plugin linalg::{vec3, vec3_distance}

let d = vec3_distance(vec3(0.0, 0.0, 0.0), vec3(1.0, 1.0, 1.0))

Linear interpolation between two vec3 values

Linearly interpolates between vec3 a and b by factor t.

use plugin linalg::{vec3, vec3_lerp}

let mid = vec3_lerp(vec3(0.0, 0.0, 0.0), vec3(10.0, 0.0, 0.0), 0.5)

Negate all components of a vec3

Returns a vec3 with all components negated.

use plugin linalg::{vec3, vec3_negate}

let neg = vec3_negate(vec3(1.0, -2.0, 3.0))

Angle in radians between two vec3 values

Returns the angle in radians between two vec3 values. Errors if either vector is zero.

use plugin linalg::{vec3, vec3_angle}

let angle = vec3_angle(vec3(1.0, 0.0, 0.0), vec3(0.0, 1.0, 0.0))

Create a 4D vector

Creates a 4D vector table with x, y, z, and w fields. Used for homogeneous coordinates and quaternions.

use plugin linalg::{vec4}

let v = vec4(0.0, 0.0, 0.0, 1.0)

Add two vec4 values

Adds two vec4 tables component-wise.

use plugin linalg::{vec4, vec4_add}

let sum = vec4_add(vec4(1.0, 2.0, 3.0, 4.0), vec4(1.0, 1.0, 1.0, 1.0))

Subtract two vec4 values

Subtracts b from a component-wise.

use plugin linalg::{vec4, vec4_sub}

let diff = vec4_sub(vec4(4.0, 3.0, 2.0, 1.0), vec4(1.0, 1.0, 1.0, 1.0))

Dot product of two vec4 values

Returns the scalar dot product of two vec4 values.

use plugin linalg::{vec4, vec4_dot}

let d = vec4_dot(vec4(1.0, 0.0, 0.0, 0.0), vec4(1.0, 0.0, 0.0, 0.0))

Unit-length vec4

Returns a unit-length copy of v. Errors if v is the zero vector.

use plugin linalg::{vec4, vec4_normalize}

let n = vec4_normalize(vec4(1.0, 2.0, 3.0, 4.0))

Magnitude of a vec4

Returns the Euclidean length of a vec4.

use plugin linalg::{vec4, vec4_length}

print(vec4_length(vec4(1.0, 0.0, 0.0, 0.0)))

Multiply vec4 by a scalar

Multiplies each component of v by scalar s.

use plugin linalg::{vec4, vec4_scale}

let scaled = vec4_scale(vec4(1.0, 2.0, 3.0, 4.0), 0.5)

Linear interpolation between two vec4 values

Linearly interpolates between vec4 a and b by factor t.

use plugin linalg::{vec4, vec4_lerp}

let mid = vec4_lerp(vec4(0.0, 0.0, 0.0, 0.0), vec4(1.0, 1.0, 1.0, 1.0), 0.5)

Project vec3 onto another vec3

Projects vec3 v onto vec3 onto. Returns the component of v parallel to onto. Errors if onto is the zero vector.

use plugin linalg::{vec3, project}

let shadow = project(vec3(3.0, 4.0, 0.0), vec3(1.0, 0.0, 0.0))

Reflect vec3 around a surface normal

Reflects vec3 v around surface normal. The normal should be unit-length for correct results.

use plugin linalg::{vec3, reflect}

let bounced = reflect(vec3(1.0, -1.0, 0.0), vec3(0.0, 1.0, 0.0))

Bounce an incoming velocity off a wall, normalizing the surface normal first:

use plugin linalg::{vec3, vec3_normalize, reflect}

let velocity = vec3(3.0, -2.0, 0.0)
let wall = vec3_normalize(vec3(0.0, 1.0, 0.0))
let outgoing = reflect(velocity, wall)
print("bounced y: {outgoing["y"]}")

Create a 3x3 identity matrix

Returns a 3x3 identity matrix as a 9-element array table (column-major order).

use plugin linalg::{mat3_identity}

let m = mat3_identity()

Multiply two 3x3 matrices

Multiplies two 3x3 matrices (column-major). Returns the product as a 9-element table.

use plugin linalg::{mat3_identity, mat3_mul}

let m = mat3_identity()
let result = mat3_mul(m, m)

Transpose a 3x3 matrix

Returns the transpose of a 3x3 matrix.

use plugin linalg::{mat3_identity, mat3_transpose}

let t = mat3_transpose(mat3_identity())

Invert a 3x3 matrix

Returns the inverse of a 3x3 matrix. Errors if the matrix is singular (determinant near zero).

use plugin linalg::{mat3_identity, mat3_inverse}

let inv = mat3_inverse(mat3_identity())

Determinant of a 3x3 matrix

Returns the scalar determinant of a 3x3 matrix.

use plugin linalg::{mat3_identity, mat3_determinant}

print(mat3_determinant(mat3_identity()))

Create a 4x4 identity matrix

Returns a 4x4 identity matrix as a 16-element array table (column-major order).

use plugin linalg::{mat4_identity}

let m = mat4_identity()

Multiply two 4x4 matrices

Multiplies two 4x4 matrices (column-major). Use this to combine transforms: mat4_mul(projection, view).

use plugin linalg::{mat4_identity, mat4_translation, mat4_mul}

let model = mat4_translation(1.0, 0.0, 0.0)
let mvp = mat4_mul(mat4_identity(), model)

Compose translate-then-rotate into a single transform. Remember matrix multiplication applies right-to-left, so the rightmost matrix acts first:

use plugin linalg::{mat4_translation, mat4_rotation_z, mat4_mul, transform_point, vec3}

let rotate = mat4_rotation_z(1.5707963)
let translate = mat4_translation(10.0, 0.0, 0.0)
let combined = mat4_mul(translate, rotate)
let p = transform_point(combined, vec3(1.0, 0.0, 0.0))
print("({p["x"]}, {p["y"]})")

Translation matrix from x, y, z

Returns a 4x4 translation matrix that moves by (x, y, z).

use plugin linalg::{mat4_translation, transform_point, vec3}

let m = mat4_translation(5.0, 0.0, 0.0)
let moved = transform_point(m, vec3(0.0, 0.0, 0.0))

Rotation matrix around X axis

Returns a 4x4 rotation matrix around the X axis by angle_rad radians.

use plugin linalg::{mat4_rotation_x}

let rx = mat4_rotation_x(1.5707963)

Rotation matrix around Y axis

Returns a 4x4 rotation matrix around the Y axis by angle_rad radians.

use plugin linalg::{mat4_rotation_y}

let ry = mat4_rotation_y(3.14159)

Rotation matrix around Z axis

Returns a 4x4 rotation matrix around the Z axis by angle_rad radians.

use plugin linalg::{mat4_rotation_z}

let rz = mat4_rotation_z(0.7854)

Scale matrix from x, y, z

Returns a 4x4 scale matrix with scale factors (x, y, z).

use plugin linalg::{mat4_scale}

let s = mat4_scale(2.0, 2.0, 2.0)

Perspective projection matrix

Returns a perspective projection matrix. fov_rad is the vertical field of view in radians, aspect is width/height.

use plugin linalg::{mat4_perspective}

let proj = mat4_perspective(1.0472, 1.7778, 0.1, 1000.0)

Orthographic projection matrix

Returns an orthographic projection matrix for 2D or isometric rendering.

use plugin linalg::{mat4_orthographic}

let ortho = mat4_orthographic(-400.0, 400.0, -300.0, 300.0, -1.0, 1.0)

Camera view matrix

Returns a camera view matrix. eye, center, and up are vec3 tables. Errors if eye equals center or if forward is parallel to up.

use plugin linalg::{vec3, mat4_look_at}

let view = mat4_look_at(vec3(0.0, 5.0, 10.0), vec3(0.0, 0.0, 0.0), vec3(0.0, 1.0, 0.0))

Transpose a 4x4 matrix

Returns the transpose of a 4x4 matrix.

use plugin linalg::{mat4_identity, mat4_transpose}

let t = mat4_transpose(mat4_identity())

Invert a 4x4 matrix

Returns the inverse of a 4x4 matrix using cofactor expansion. Errors if the matrix is singular.

use plugin linalg::{mat4_translation, mat4_inverse}

let m = mat4_translation(3.0, 0.0, 0.0)
let inv = mat4_inverse(m)

Determinant of a 4x4 matrix

Returns the scalar determinant of a 4x4 matrix.

use plugin linalg::{mat4_identity, mat4_determinant}

print(mat4_determinant(mat4_identity()))

Rotation matrix from quaternion components

Converts a quaternion (qx, qy, qz, qw) to a 4x4 rotation matrix.

use plugin linalg::{mat4_from_quat}

let rot = mat4_from_quat(0.0, 0.0, 0.0, 1.0)

Quaternion from pitch, yaw, roll

Converts Euler angles (pitch, yaw, roll) in radians to a quaternion, returned as a vec4 table {x, y, z, w}.

use plugin linalg::{quat_from_euler, mat4_from_quat}

let q = quat_from_euler(0.0, 1.5707963, 0.0)
let rot = mat4_from_quat(q["x"], q["y"], q["z"], q["w"])

Multiply two quaternions

Multiplies two quaternions (vec4 tables). Returns the composed rotation as a vec4.

use plugin linalg::{quat_from_euler, quat_mul}

let a = quat_from_euler(0.0, 0.5, 0.0)
let b = quat_from_euler(0.0, 0.5, 0.0)
let combined = quat_mul(a, b)

Spherical interpolation between quaternions

Spherically interpolates between quaternions q1 and q2 by factor t (0.0 = q1, 1.0 = q2). Automatically takes the shortest path.

use plugin linalg::{quat_from_euler, quat_slerp}

let start = quat_from_euler(0.0, 0.0, 0.0)
let end_q = quat_from_euler(0.0, 1.5707963, 0.0)
let halfway = quat_slerp(start, end_q, 0.5)

Animate a smooth turn and convert each step into a usable rotation matrix:

use plugin linalg::{quat_from_euler, quat_slerp, mat4_from_quat}

let a = quat_from_euler(0.0, 0.0, 0.0)
let b = quat_from_euler(0.0, 3.14159, 0.0)
for i in 0..4 {
  let q = quat_slerp(a, b, i / 3.0)
  let m = mat4_from_quat(q["x"], q["y"], q["z"], q["w"])
  print("step {i} ready")
}

Apply mat4 to a point (with translation)

Applies a 4x4 matrix to a vec3 point, including translation (homogeneous w=1). Returns the transformed vec3.

use plugin linalg::{mat4_translation, vec3, transform_point}

let m = mat4_translation(10.0, 0.0, 0.0)
let p = transform_point(m, vec3(0.0, 0.0, 0.0))
print("Moved to: {p["x"]}")

Apply mat4 to a direction (no translation)

Applies a 4x4 matrix to a vec3 direction, ignoring translation (homogeneous w=0). Use for normals and direction vectors.

use plugin linalg::{mat4_rotation_y, vec3, transform_direction}

let rot = mat4_rotation_y(1.5707963)
let fwd = transform_direction(rot, vec3(0.0, 0.0, -1.0))

Unlike transform_point, a pure translation leaves a direction unchanged because the translation column is ignored:

use plugin linalg::{mat4_translation, vec3, transform_direction}

let move = mat4_translation(100.0, 100.0, 100.0)
let dir = transform_direction(move, vec3(0.0, 0.0, 1.0))
print("unchanged: {dir["x"]}, {dir["y"]}, {dir["z"]}")
enespt-br