npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@sachitv/safe-math-ts

v0.2.0

Published

A zero-dependency Deno/TypeScript 3D math library with strict compile-time safety.

Readme

safe-math-ts

JSR Version npm version CI Deno Node.js Bun Cloudflare Browser License: MIT

A zero-dependency Deno/TypeScript 3D math library with strict compile-time safety for:

  • Units
  • Frames of reference
  • Transform composition

The library is functional and exports types + functions only (no classes).

Strictness model

This library intentionally requires explicit tags when creating values:

  • You must create units with unit('m'), unit('s'), etc.
  • You must create frames with frame('world'), frame('body'), etc.
  • You must pass those tags into constructors like quantity, point3, delta3, dir3, quat, and mat4.

This prevents accidental creation of unframed or unitless math objects.

Install / import

Deno (JSR)

deno add jsr:@sachitv/safe-math-ts
import { delta3, frame, point3, unit } from '@sachitv/safe-math-ts';

Node.js / Bun / Cloudflare Workers (npm)

npm install @sachitv/safe-math-ts
# or
bun add @sachitv/safe-math-ts
import { delta3, frame, point3, unit } from '@sachitv/safe-math-ts';

Direct import (Deno, no install step)

import {
  delta3,
  dimensionlessUnit,
  dir3,
  frame,
  mat4FromRigidTransform,
  point3,
  quantity,
  quat,
  transformPoint3,
  unit,
} from './mod.ts';

Quick start

import {
  delta3,
  dimensionlessUnit,
  dir3,
  frame,
  mat4FromRigidTransform,
  point3,
  quantity,
  quat,
  transformPoint3,
  unit,
} from './mod.ts';

const V = frame('V'); // Source frame
const L = frame('L'); // Destination frame
const m = unit('m');
const none = dimensionlessUnit;

const point_V = point3(
  V,
  quantity(m, 1),
  quantity(m, 2),
  quantity(m, 3),
);

const delta_offset_L = delta3(
  L,
  quantity(m, 10),
  quantity(m, 0),
  quantity(m, 0),
);

const dir_axisz_V = dir3(
  V,
  quantity(none, 0),
  quantity(none, 0),
  quantity(none, 1),
);

const quat_turn_LV = quat(
  L,
  V,
  dir_axisz_V[0] * Math.sin(Math.PI / 4),
  dir_axisz_V[1] * Math.sin(Math.PI / 4),
  dir_axisz_V[2] * Math.sin(Math.PI / 4),
  Math.cos(Math.PI / 4),
);

const pose_LV = mat4FromRigidTransform(
  L,
  V,
  quat_turn_LV,
  delta_offset_L,
);

const point_L = transformPoint3(pose_LV, point_V);

Common usage patterns

  • Use point3 for absolute locations in a frame.
  • Use delta3 for translations/displacements.
  • Use dir3 for unitless axes and orientation vectors.
  • Compute relative motion with subPoint3(point_a, point_b).
  • Apply rigid transforms to points with transformPoint3.
  • Apply linear transforms/rotations to displacements with transformDirection3 or rotateVec3ByQuat.

Safe and unsafe APIs

  • Safe APIs are the default functions (for example normalizeVec3, clamp, mat4Perspective, projectPoint3).
  • Unsafe APIs end with Unsafe (for example normalizeVec3Unsafe, clampUnsafe, mat4PerspectiveUnsafe, projectPoint3Unsafe).
  • Safe APIs validate inputs and throw on invalid/degenerate cases.
  • Unsafe APIs skip validation and can produce NaN/Infinity on invalid inputs.
  • matrix.quat() is a safe helper: it validates that the upper-left 3x3 block is a finite orthonormal rotation basis and throws for non-rotation matrices (for example non-uniform scale/shear).
  • Recommended pattern:
    1. Validate at system boundaries with safe APIs.
    2. Use unsafe APIs only in hot paths where inputs are already guaranteed.

Naming best practices

  • Transform and rotation generics always use <To, From> order.
  • Transform matrices use pose_<frame rules>.
  • Quaternions use quat_<name>_<frame rules>.
  • Position vectors use point_<name>_<frame> (or point_<frame> when no name is needed).
  • Direction vectors use dir_<name>_<frame> (or dir_<frame> when no name is needed).
  • Displacement vectors use delta_<name>_<frame> (or delta_<frame>).
  • Single-letter frame symbols use compact ToFrom suffixes: pose_LV, quat_turn_LV, point_L, dir_V, delta_V.
  • Multi-letter frame symbols use one token per frame: pose_local_vehicle, quat_turn_local_vehicle, point_local, dir_vehicle, delta_vehicle.
  • Frame tokens themselves are single words. If a frame name would include spaces, smash it into one word (for example earthcenter, vehiclerear), then use names like pose_earthcenter_vehiclerear and quat_turn_earthcenter_vehiclerear.
  • Frame tag variable names themselves can be whatever you prefer (L, frame_local, localFrame), but choose frame tokens that keep derived variable names readable.
  • This naming convention is for frame-bearing quantities only; it does not apply to units (for example, meter, second, none are fine).
  • Prefer short uppercase frame symbols (L, V, B, W) in handwritten math and derived variable names.

Examples:

  • pose_LV: Mat4<'L', 'V', 'm'> maps points in V to L, so: point_L = transformPoint3(pose_LV, point_V).
  • quat_turn_LV: Quaternion<'L', 'V'> rotates vectors from V into L.
  • delta_local: Delta3<'m', 'local'> represents a translation/displacement in local.
  • pose_local_vehicle: Mat4<'local', 'vehicle', 'm'> maps points in vehicle to local.
  • composeMat4(pose_LB, pose_BV) returns pose_LV (chain L <- B <- V).

API overview

This section documents the important public API and constraints without listing every overload.

Core types

Units:

  • UnitExpr
  • Dimensionless
  • UnitFromString<Expr>
  • UnitTag<Unit>
  • Quantity<Unit>
  • MulUnit<A, B>, DivUnit<A, B>, SqrtUnit<U>

Frames and geometry:

  • FrameTag<Frame>
  • Point3<Unit, Frame>
  • Delta3<Unit, Frame>
  • Dir3<Frame>
  • Quaternion<ToFrame, FromFrame>
  • Mat4<ToFrame, FromFrame, TranslationUnit>
  • LinearMat4<ToFrame, FromFrame>
  • ProjectionMat4<ToFrame, FromFrame, DepthUnit>

Constructors and tokens

unit<Expr extends string>(name: string extends Expr ? never : Expr): UnitTag<UnitFromString<Expr>>
const dimensionlessUnit: UnitTag<Dimensionless>
frame<Frame extends string>(name: Frame): FrameTag<Frame>

quantity<Unit extends UnitExpr>(unitTag: UnitTag<Unit>, value: number): Quantity<Unit>
dimensionless(value: number): Quantity<Dimensionless>
valueOf<Unit extends UnitExpr>(value: Quantity<Unit>): number

Non-obvious constraints:

  • unit(...) accepts literal/narrow string types only.
  • sqrt(...) is compile-time guarded and only allowed for square-rootable units.
sqrt<Unit extends UnitExpr>(
  value: [SqrtUnit<Unit>] extends [never] ? never : Quantity<Unit>,
): Quantity<SqrtUnit<Unit>>

Scalar unit math

  • Arithmetic: add, sub, neg, abs, scale, mul, div, sqrt
  • Bounds: min, max, clamp, clampUnsafe
  • Comparisons: eq, approxEq, lt, lte, gt, gte
  • Aggregation: sum, average

3D vector and point operations

Construction:

  • delta3, point3, dir3, zeroVec3

Affine/frame-safe operations:

  • addVec3, subVec3, negVec3, scaleVec3
  • addPoint3, subPoint3Delta3, subPoint3

Geometry:

  • dotVec3, crossVec3
  • lengthSquaredVec3, lengthVec3
  • distanceVec3, distancePoint3
  • normalizeVec3, normalizeVec3Unsafe
  • lerpVec3
  • projectVec3, projectVec3Unsafe
  • reflectVec3, reflectVec3Unsafe
  • angleBetweenVec3, angleBetweenVec3Unsafe
  • scaleDir3

Quaternion operations

  • Construction and identity: quat, quatIdentity
  • Components: quatX, quatY, quatZ, quatW
  • Algebra: quatConjugate, quatNorm, quatNormSquared, composeQuats
  • Normalization/inversion: quatNormalize, quatNormalizeUnsafe, quatInverse, quatInverseUnsafe
  • Rotations: rotateVec3ByQuat, rotateVec3ByQuatUnsafe
  • Matrix conversion: quatFromRotationMatrix, quatFromRotationMatrixUnsafe
  • Builders/interpolation: quatFromAxisAngle, quatFromAxisAngleUnsafe, quatFromEuler, quatFromEulerUnsafe, quatNlerp, quatNlerpUnsafe, quatSlerp, quatSlerpUnsafe

Matrix operations

Construction:

  • mat4, mat4Unsafe, mat4Identity
  • mat4FromTranslation, mat4FromScale
  • mat4FromQuaternion, mat4FromQuaternionUnsafe
  • mat4FromRigidTransform
  • mat4FromTRS, mat4FromTRSUnsafe
  • createTrsMat4Cache
  • mat4Perspective, mat4PerspectiveUnsafe
  • mat4Ortho, mat4OrthoUnsafe
  • mat4LookAt, mat4LookAtUnsafe

Composition and transforms:

  • Matrix instance helpers: matrix.translation(), matrix.quat()
    • matrix.translation() reads translation from indices 12/13/14.
    • matrix.quat() extracts rotation and throws if the matrix linear part is not a valid rotation basis.
  • transposeMat4
  • composeMat4
  • invertRigidMat4, invertRigidMat4Unsafe
  • normalMatrixFromMat4, normalMatrixFromMat4Unsafe
  • transformPoint3
  • transformDirection3
  • projectPoint3, projectPoint3Unsafe