Skip to content
Plugins (190)

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
57 functions Math
Runs with the native Zolo host

Plugin snippets can be edited in the Playground, but native capabilities are executed locally with the Zolo CLI.

/ 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)

From import to result

  1. 01Import only what you use
  2. 02Copy the smallest example
  3. 03Run it with the Zolo CLI

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"]}")

Global index

Find your way through Zolo

Try an idea

Start here

9 results

9 results

en