Lily Math library for Graphics and Rendering.

Math library only for presentation, has support for 2D and 3D vector, Quaternion, and Matrix

⚠️ WARNING: NOT CROSS-PLATFORM BITWISE DETERMINISTIC

This library does NOT produce bitwise-identical results across platforms.

The same code with the same inputs is likely to produce different results on different machines (x86, Arm, WASM, etc.).

Cross-platform divergence can be caused by:

  • Platform-specific SIMD optimizations
  • Instruction selection, evaluation order, and FMA (fused multiply-add)
  • Platform/libm differences in internal transcendental functions
  • Denormal/subnormal handling and flush-to-zero (used sometimes for performance)
  • NaN and signed-zero edge-case differences
  • Approximation algorithms used by optimized math paths
  • Compiler/backend/version-specific optimizations

You MUST NOT use this library for:

  • Physics simulation
  • Gameplay logic
  • Lockstep or rollback networking
  • Replay or re-simulation systems
  • Serialization (can be accidentily used by gameplay, physics or used by other devices)

Conventions:

  • Angles are in radians.
  • Matrices are column-major.

References:

Structs

Vec2

struct Vec2 {
    secret: Block<U8, 8>
}

2D vector.

Member Functions

new

fn Vec2::new(x: Float, y: Float) -> Vec2

Return a new 2D vector

x

fn Vec2::x(self) -> Float

Return the x component

y

fn Vec2::y(self) -> Float

Return the y component

magnitude

fn Vec2::magnitude(self) -> Float

Return the magnitude (length) of the vector

normalize

fn Vec2::normalize(self) -> Vec2

Return a normalized (unit length) vector.

Behavior is undefined if the input has zero magnitude.

add

fn Vec2::add(self, other: Vec2) -> Vec2

Add two vectors

sub

fn Vec2::sub(self, other: Vec2) -> Vec2

Subtract two vectors

dot

fn Vec2::dot(self, other: Vec2) -> Float

Compute the dot product of two vectors

lerp

fn Vec2::lerp(
  self,
  other: Vec2,
  t: Float
) -> Vec2

Linear interpolation between two vectors.

t = 0.0 returns self. t = 1.0 returns other.

distance

fn Vec2::distance(self, other: Vec2) -> Float

Distance between two points

string

fn Vec2::string(self) -> String

Convert vector to string for debugging

Vec3

struct Vec3 {
    secret: Block<U8, 12>
}

3D vector.

Member Functions

new

fn Vec3::new(
  x: Float,
  y: Float,
  z: Float
) -> Vec3

Return a new 3D vector

x

fn Vec3::x(self) -> Float

Return the x component

y

fn Vec3::y(self) -> Float

Return the y component

z

fn Vec3::z(self) -> Float

Return the z component

magnitude

fn Vec3::magnitude(self) -> Float

Return the magnitude (length) of the vector

normalize

fn Vec3::normalize(self) -> Vec3

Return a normalized (unit magnitude) vector.

Behavior is undefined if the input has zero magnitude.

add

fn Vec3::add(self, other: Vec3) -> Vec3

Add two vectors

sub

fn Vec3::sub(self, other: Vec3) -> Vec3

Subtract two vectors

dot

fn Vec3::dot(self, other: Vec3) -> Float

Compute the dot product of two vectors

lerp

fn Vec3::lerp(
  self,
  other: Vec3,
  t: Float
) -> Vec3

Linear interpolation between two vectors.

t = 0.0 returns self. t = 1.0 returns other.

distance

fn Vec3::distance(self, other: Vec3) -> Float

Distance between two points

string

fn Vec3::string(self) -> String

Convert vector to string for debugging

Mat3

struct Mat3 {
    secret: Block<U8, 36>
}

3x3 column-major matrix.

Member Functions

identity

fn Mat3::identity() -> Mat3

Return an identity matrix

mul

fn Mat3::mul(self, other: Mat3) -> Mat3

Multiply (compose) two matrices.

Multiplication order matters.

string

fn Mat3::string(self) -> String

Convert matrix to string for debugging

Vec4

struct Vec4 {
    secret: Block<U8, 16>
}

4D vector.

Member Functions

new

fn Vec4::new(
  x: Float,
  y: Float,
  z: Float,
  w: Float
) -> Vec4

Return a new 4D vector

x

fn Vec4::x(self) -> Float

Return the x component

y

fn Vec4::y(self) -> Float

Return the y component

z

fn Vec4::z(self) -> Float

Return the z component

w

fn Vec4::w(self) -> Float

Return the w component

string

fn Vec4::string(self) -> String

Convert vector to string for debugging

Quat

struct Quat {
    secret: Block<U8, 16>
}

Quaternion for 3D rotations

Member Functions

identity

fn Quat::identity() -> Quat

Return an identity quaternion (no rotation)

from_rotation_z

fn Quat::from_rotation_z(radians: Float) -> Quat

Return a quaternion from rotation around Z axis

from_rotation_x

fn Quat::from_rotation_x(radians: Float) -> Quat

Return a quaternion from rotation around X axis

from_rotation_y

fn Quat::from_rotation_y(radians: Float) -> Quat

Return a quaternion from rotation around Y axis

x

fn Quat::x(self) -> Float

Return the x component

y

fn Quat::y(self) -> Float

Return the y component

z

fn Quat::z(self) -> Float

Return the z component

w

fn Quat::w(self) -> Float

Return the w component

normalize

fn Quat::normalize(self) -> Quat

Return a normalized (unit magnitude) quaternion

Behavior is undefined if the input has zero magnitude.

inverse

fn Quat::inverse(self) -> Quat

Return the inverse (opposite) rotation.

Behavior is undefined if the quaternion has zero magnitude.

mul

fn Quat::mul(self, other: Quat) -> Quat

Multiply (compose) two quaternions.

Think of this as combining an existing rotation with an additional “delta” rotation.

Multiplication order matters and is not commutative.

slerp

fn Quat::slerp(
  self,
  other: Quat,
  t: Float
) -> Quat

Return the spherical linear interpolation between self and other.

t = 0.0 returns self. t = 1.0 returns other.

nlerp

fn Quat::nlerp(
  self,
  other: Quat,
  t: Float
) -> Quat

Normalized linear interpolation (nlerp).

Typically faster than slerp, but does not result in constant angular velocity.

Use it for small angular differences or when interpolating frequently (e.g. per frame), as it is faster and looks similar to slerp.

t = 0.0 returns self. t = 1.0 returns other.

string

fn Quat::string(self) -> String

Convert quaternion to string for debugging

Vec4f

struct Vec4f {
    w: F32
    x: F32
    y: F32
    z: F32
}

Mat4

struct Mat4 {
    secret: Block<U8, 64>
}

4x4 column-major matrix.

Member Functions

identity

fn Mat4::identity() -> Mat4

Return an identity matrix (no transformation)

ortho_2d_y_down_int

fn Mat4::ortho_2d_y_down_int(
  width: Int,
  height: Int,
  zoom: Float
) -> Mat4

Return an orthographic projection matrix for 2D (Y-down).

width and height are viewport dimensions in pixels. zoom must be positive. Read more about projections

ortho_2d_int

fn Mat4::ortho_2d_int(
  width: Int,
  height: Int,
  zoom: Float
) -> Mat4

Return an orthographic projection matrix for 2D with normal RH (Y-going up).

width and height are viewport dimensions in pixels. zoom must be positive. Read more about projections

ortho_2d_y_down_near_far_int

fn Mat4::ortho_2d_y_down_near_far_int(
  width: Int,
  height: Int,
  near: Int,
  far: Int
) -> Mat4

ortho_2d_pixel_y_down_near_far_int

fn Mat4::ortho_2d_pixel_y_down_near_far_int(
  width: Int,
  height: Int,
  near: Int,
  far: Int
) -> Mat4

Uses pixel centers (-0.5)

ortho_2d_pixel_near_far_int

fn Mat4::ortho_2d_pixel_near_far_int(
  width: Int,
  height: Int,
  near: Int,
  far: Int
) -> Mat4

Uses pixel centers (-0.5)

from_translation

fn Mat4::from_translation(
  translation: Vec3
) -> Mat4

Return a translation matrix

from_rotation_z

fn Mat4::from_rotation_z(radians: Float) -> Mat4

Return a rotation matrix around Z axis (2D rotation)

from_quat

fn Mat4::from_quat(rotation: Quat) -> Mat4

Return a rotation matrix from a quaternion

from_scale

fn Mat4::from_scale(scale: Vec3) -> Mat4

Return a scale matrix

from_rotation_translation

fn Mat4::from_rotation_translation(
  rotation: Quat,
  translation: Vec3
) -> Mat4

Return a transform from rotation and translation (no scale)

from_scale_rotation_translation

fn Mat4::from_scale_rotation_translation(
  scale: Vec3,
  rotation: Quat,
  translation: Vec3
) -> Mat4

Return a full transform from scale, rotation and translation

mul

fn Mat4::mul(self, other: Mat4) -> Mat4

Multiply (compose) two matrices.

Multiplication order matters.

A * B and B * A (usually) produce different results. For example, rotate-then-translate is different from translate-then-rotate.

Build projection P once (for the viewport), build model M per object (for example, a translation), then multiply P * V * M.

This applies object/world transform first, then projection to clip space.

MVP convention:

  • M (Model): object local space -> world space
  • V (View): world space -> camera/view space
  • P (Projection): maps view space -> clip space and encodes projection (aspect ratio and orthographic/perspective)

translation

fn Mat4::translation(self) -> Vec3

Return the translation component (same as w_axis)

x_axis

fn Mat4::x_axis(self) -> Vec3

Return the first column vector

y_axis

fn Mat4::y_axis(self) -> Vec3

Return the second column vector

z_axis

fn Mat4::z_axis(self) -> Vec3

Return the third column vector

w_axis

fn Mat4::w_axis(self) -> Vec3

Return the fourth column vector (translation)

to_scale_rotation_translation

fn Mat4::to_scale_rotation_translation(
  self
) -> (Vec3, Quat, Vec3)

Decompose transform into scale, rotation and translation.

to_mat4f

fn Mat4::to_mat4f(self) -> Mat4f

Convert to WebGPU type Mat4f (array of 16 F32)

inverse

fn Mat4::inverse(self) -> Mat4

Calculate the inverse matrix.

Behavior is undefined for non-invertible (singular) matrices. (e.g. when zero or close to zero scale on any axis)

transpose

fn Mat4::transpose(self) -> Mat4

Transpose the matrix (swap rows and columns)

string

fn Mat4::string(self) -> String

Convert matrix to string for debugging.

Do not rely on the string being formatted in a specific way.