SkillAgentSearch skills...

Maath

🪶 Math helpers for the rest of us

Install / Use

/learn @pmndrs/Maath
About this skill

Quality Score

0/100

Supported Platforms

Universal

README

Discord Shield

<a href="https://github.com/pmndrs/maath"><img src="https://github.com/pmndrs/maath/blob/main/hero.svg?raw=true" /></a> <br />

yarn add maath

This is a collection of useful math helpers, random generators, bits and bobs.

The library is mostly meant to be used with three.js, so if you are using it outside of a three project, make sure you check the source and - if you don't need the dep - just copy paste!

Check out the demos on Codesandbox: 🪶

| <a href="https://codesandbox.io/s/github/pmndrs/maath/tree/main/demo/src/sandboxes/points"><img src="https://codesandbox.io/api/v1/sandboxes/lex1g/screenshot.png" /></a> | <a href="https://codesandbox.io/s/github/pmndrs/maath/tree/main/demo/src/sandboxes/convex-hull"><img src="https://codesandbox.io/api/v1/sandboxes/fh8l2/screenshot.png" /></a> | <a href="https://codesandbox.io/s/github/pmndrs/maath/tree/main/demo/src/sandboxes/circumcircle"><img src="https://codesandbox.io/api/v1/sandboxes/zuff9/screenshot.png" /></a> | | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |

🟡 The library is still heavily WIP

But why?

Yes, there are a lot of these libraries. The more the merrier! We are all here to learn, and maintaining a dedicated library for our creative endeavors at Poimandres just made sense.

Contributing

Do you want to add something? No rules, but keep these in mind:

  • try to add explainers to whatever function you add, if you saw it in a tweet link that!
  • add a cool example! Make it a sandbox or whatever, just show how the function can be used creatively
  • keep copy-paste simple. Try not to add too many inter-dependencies so the functions are copy-paste friendly
  • loose typing. Try to add typing, but don't go crazy with generics and complexity

If you are not sure how to help, check out the 🟡 Roadmap below.

🪶 Reference

Using specific entry points

// you can import the namespaces from the main entrypoint
import { buffer, random } from "maath";
// or import each function or all of them from each namespace entrypoint
import * as buffer from "maath/buffer";
import { inSphere } from "maath/random";

Buffer

import * as buffer from "maath/buffer";

🪶 toVectorArray(buffer, stride)

Converts an [..., x, y, z, ...] typed array to a Vector[]

const myBuffer = new Float32Array(100 * 3);
const myArray = toVectorArray(myBuffer, 3);

🪶 swizzleBuffer(buffer, axes)

Swizzle the individual vectors in a vector buffer

const myBuffer = new Float32Array(100 * 3);
myBuffer.push(0, 1, 2);

swizzleBuffer(myBuffer, "xzy"); // buffer is now [0, 2, 1]

This is a way to make simple rotations.

🪶 addAxis(buffer, size, getZValue)

Adds a z axis to an [..., x, y, ...] typed array:

const my2DBuffer = new Float32Array(100 * 2);
const my3DBuffer = addAxis(my2DBuffer, 2, () => Math.random()); // zAxis will now be a random value between 0 and 1
const my4DBuffer = addAxis(my3DBuffer, 3, () => 1); // 4th value (imagine a in rgba) will be 1

🪶 lerpBuffers(bufferA, bufferB, destinationBuffer, t)

Linearly interpolate two buffers, writing on a third one.

const mySphere = inSphere(new Float32Array(100 * 3), { radius: 4 });
const myBox = inBox(new Float32Array(100 * 3), { side: 4 });

const interpolationTarget = myBox.slice(0);

lerpBuffers(mySphere, myBox, interpolationTarget, Math.sin(performance.now()));

Geometry

import * as geometry from "maath/geometry";

🪶 roundedPlaneGeometry(width = 1, height = 1, radius = 0.2, segments = 16)

const geo = new RoundedPlaneGeometry();
const mesh = new THREE.Mesh(geo, material);

🪶 applyBoxUV(bufferGeometry)

Applies box-projected UVs to a buffer geometry.

🪶 applySphereUV(bufferGeometry)

Applies spherical UVs to a buffer geometry.

🪶 applyCylindricalUV(bufferGeometry)

Applies cylindrical-projected UVs to a buffer geometry.

Easing

import * as easing from "maath/easing";

Unity-smooth-damping functions based on Game Programming Gems 4 Chapter 1.10. These are fast, refresh-rate independent, interruptible animation primitives primed to THREE.Vector2D, 3D, 4D, Euler (shortest path), Matrix4, Quaternion and Color.

export function damp(
  /** The object */
  current: { [key: string]: any },
  /** The key to animate */
  prop: string,
  /** To target (or goal) value */
  target: number,
  /** Approximate time to reach the target. A smaller value will reach the target faster. */
  smoothTime = 0.25,
  /** Frame delta, for refreshrate independence */
  delta = 0.01,
  /** Optionally allows you to clamp the maximum speed. If smoothTime is 0.25s and looks OK
   *  going between two close points but not for points far apart as it'll move very rapid,
   *  then a maxSpeed of e.g. 1 which will clamp the speed to 1 unit per second, it may now
   *  take much longer than smoothTime to reach the target if it is far away. */
  maxSpeed = Infinity,
  /** Easing function */
  easing = (t: number) => 1 / (1 + t + 0.48 * t * t + 0.235 * t * t * t),
  /** End of animation precision */
  eps = 0.001
);
import { damp, damp2, damp3, damp4, dampE, dampM, dampQ, dampS, dampC } from 'maath/easing'

function frameloop() {
  const delta = clock.getDelta()
  // Animates foo.bar to 10
  damp(foo, "bar", 10, 0.25, delta)

  // Animates mesh.position to 0,1,2
  damp3(mesh.position, [0, 1, 2], 0.25, delta)
  // Also takes vectors, shallow vectors and scalars
  // damp3(mesh.position, new THREE.Vector3(0, 1, 2), 0.25, delta)
  // damp3(mesh.position, { x: 0, y: 1, z: 2 }, 0.25, delta)
  // damp3(mesh.scale, 2, 0.25, delta)

  dampC(mesh.material.color, "green", 0.25, delta)
  // Also takes colors, fake colors, numbers and arrays
  // dampC(mesh.material.color, new THREE.Color("green"), 0.25, delta)
  // dampC(mesh.material.color, 0xdead00, 0.25, delta)
  // dampC(mesh.material.color, [1, 0, 0], 0.25, delta)
  // dampC(mesh.material.color, { r: 1, g: 0, b: 0 }, 0.25, delta)

  // Animates an euler with a shortest-path algorithm
  dampE(mesh.rotation, [Math.PI / 2, 0, 0], 0.25, delta)
  // Also takes eulers
  // dampE(mesh.rotation, new THREE.Euler(Math.PI / 2, 0, 0), 0.25, delta)

  // damp2 for Vector2
  // damp4 for Vector4
  // dampM for Matrix4
  // dampQ for Quaternion
  // dampS for Spherical

There are two special damping functions for angles and lookAt:

import { dampAngle, dampLookAt } from "maath/easing";

// Animates angle to targetAngle, with a shortest-path algorithm
dampAngle(angle, targetAngle, 0.25, delta);
// Animates a meshes look-up
dampLookAt(mesh, focus, 0.25, delta);

🪶 easing functions

6 easing functions are available with in, out and inOut variants:

import { sine, cubic, quint, circ, quart, expo } from "maath/easing";

sine.in(t);
sine.out(t);
sine.inOut(t);

3 specific functions:

import { rsqw, exp, linear } from "maath/easing";

// rounded-square wave
rsqw(t, delta);
// unity smooth damping
exp(t);
// linear
linear(t); // === t

Matrix

import * as matrix from "maath/matrix";

🪶 determinant2(...matrixInRowMajorOrder)

Returns the determinant of a passed 2x2 matrix:

const d = determinant2(1, 1, 2, 2);

🪶 determinant3(...matrixInRowMajorOrder)

Returns the determinant of a passed 3x3 matrix:

const d = determinant3(1, 1, 1, 2, 2, 2);

🪶 determinant4(...matrixInRowMajorOrder) // TBD

🪶 getMinor(matrix, column, row)

Returns the minor of a given matrix.

const minor = getMinor([1, 2, 1, 2, 1, 1, 3, 2, 3], 1, 1);

// minor will be the determinant of the submatrix without row 1 and colum 1
// | 1 1 |
// | 2 3 |

Misc

// Clamps a value between a range.
clamp(value: number, min: number, max: number): number
// Loops the value t, so that it is never larger than length and never smaller than 0.
repeat(t: number, length: number): number
// Calculates the shortest difference between two given angles.
deltaAngle(current: number, target: number): number
// Converts degrees to radians.
degToRad(degrees: number): number
// Converts radians to degrees.
radToDeg(radians: number): number
// adapted from https://gist.github.com/stephanbogner/a5f50548a06bec723dcb0991dcbb0856 by https://twitter.com/st_phan
fibonacciOnSphere(buffer: TypedArray, { radius = 1 }): void
// Checks if vector a is equal to vector b, with tolerance
vectorEquals(a, b, eps = Number.EPSILON): boolean
/**
 * Sorts vectors in lexicographic order, works with both v2 and v3
 *
 *  Use as:
 *  const sorted = arrayOfVectors.sort(lexicographicOrder)
 */
// https://en.wikipedia.org/wiki/Lexicographic_order
lexicographic(a: Vector2 | Vector3, b: Vector2 | Vector3): number
/**
 * Convex Hull
 *
 * Returns an array of 2D Vectors representing the convex hull of a set of 2D Vectors
 */
convexHull(_points: Vector2[]): Vector2[]
// ...
remap(x: number, [low1, high1]: number[], [low2, high2]: number[])

Random

import * as random from "maath/random";

🪶 onTorus(buffer, { innerRadius, outerRadius })

[TODO](https://ma

View on GitHub
GitHub Stars966
CategoryDevelopment
Updated3d ago
Forks26

Languages

TypeScript

Security Score

80/100

Audited on Apr 3, 2026

No findings