Getting Started | TS

Introduction

Geometric processing powered by WASM. NDArrays in, NDArrays out.

trueform is a TypeScript library for real-time geometric processing. WASM-backed NDArrays with support for vectorized numerical operations and spatial queries. Mesh booleans, registration, remeshing — at native speed in the browser and Node.js. Robust to non-manifold flaps, inconsistent winding, and pipeline artifacts. NDArrays in, NDArrays out.

Try it in your browser

Interactive mesh booleans, registration, isobands, and more. No install needed.

NDArrays become typed primitives — single or batched. Primitives compose into forms with cached geometric and topological structures.

SingleBatchNDArray(shape)NDArray(N, *shape)Primitive N × PrimitivePrimitivesPointLineRaySegmentTrianglePolygonPlaneAABBFormsMeshPointCloudtransformationCached on demand.normals.vertexLink.faceLink.pointNormals.tree...

NDArrays become typed primitives — single or batch. Forms add spatial indexing, on-demand topology and geometry caching, and transformations.

Same functions for primitives, batches, and forms. Algorithms transform forms into new geometry.

PrimitiveQueriestf.distancetf.intersectstf.rayCasttf.closestPointPair...primitivexprimitivenumberbatch(N)xprimitiveNDArray(N)batch(N)xbatch(N)NDArray(N)batch(N)xformNDArray(N)formxformnumberFormAlgorithmstf.booleanUnion(mesh0, mesh1)tf.fitIcpAlignment(cloud0, cloud1)...tf.decimated(mesh, 0.1)

One API for any combination of primitives and forms. Queries broadcast. Forms bridge spatial queries and mesh algorithms.

Installation

Install via npm.

Modules

NDArray, spatial queries, topology, and the algorithms that connect them.

Benchmarks

Performance measurements against native C++ and competitors.

Examples

Guided walkthroughs and runnable Node.js scripts.

Quick Tour

NDArray — WASM-backed numerical arrays:

import * as tf from "@polydera/trueform";

// Extract the z-column from mesh points — zero-copy view
const heights = mesh.points.take(null, 2);

// Two conditions: above ground AND close to a reference plane
const above = heights.gt(0);
const dists = tf.distance(mesh.points, plane);
const close = dists.lt(0.5);
const mask = above.and(close);

// Boolean-index to get matching points
const selected = mesh.points.booleanIndex(mask);

Primitives — typed NDArrays, single or batched:

const triangle = tf.triangle(
  tf.point(0, 0, 0), tf.point(1, 0, 0), tf.point(0, 1, 0)
);
const ray = tf.ray(tf.point(0.2, 0.2, -1), tf.vector(0, 0, 1));

// Add a leading dimension for batches
const pts = tf.point(new Float32Array(/* 1000×3 coords */), 3);
const segs = tf.segment(new Float32Array(/* 500×2×3 coords */), 3);

Meshes are created from NDArrays or read from files:

const faces = tf.ndarray(new Int32Array([0,1,2, 0,2,3, 0,3,1, 1,3,2]), [4, 3]);
const points = tf.ndarray(new Float32Array([
  0,0,0, 1,0,0, 0,1,0, 0,0,1
]), [4, 3]);
const mesh = tf.mesh(faces, points);

// Or read from file (browser)
const response = await fetch("model.stl");
const mesh = tf.readStl(await response.arrayBuffer());

Queries — same functions for any combination. Batches broadcast:

// Batch × primitive — distance field to a plane
const plane = tf.plane(tf.vector(0, 0, 1), 0);
const scalars = tf.distance(pts, plane);            // NDArray [1000]

// Batch × form — nearest face for each segment
const { elementIds, distances } = tf.neighborSearch(mesh, segs);

// Single × single
const { hit, t } = tf.rayCast(ray, triangle);

// Batched — cast N rays against a mesh in one call
const rays = tf.ray(
  tf.ndarray(new Float32Array(/* N×3 origins */), [N, 3]),
  tf.ndarray(new Float32Array(/* N×3 dirs */), [N, 3]),
);
const { hits, ts, elementIds } = tf.rayCast(rays, mesh);
// hits: NDArrayBool [N], ts: NDArray [N], elementIds: NDArray [N]

Mesh analysis reveals structure and defects:

const { nComponents, labels } = tf.connectedComponents(mesh, "manifoldEdge");
const components = tf.splitIntoComponents(mesh, labels);

const bp = tf.boundaryPaths(mesh);
const { k0, k1, d0, d1 } = tf.principalDirections(mesh);
const si = tf.shapeIndex(mesh);

Boolean operations combine meshes:

const union = tf.booleanUnion(mesh0, mesh1);
// union.mesh, union.labels

// With intersection curves
const diff = tf.booleanDifference(box, cylinder, { returnCurves: true });
// diff.mesh, diff.labels, diff.curves

Scalar fields and isocontours:

const scalars = tf.distance(mesh.points, plane);
const { mesh: banded, labels, curves } = tf.isobands(
  mesh, scalars, new Float32Array([-1, 0, 1]), { returnCurves: true }
);

Remeshing — decimate and remesh:

const decimated = tf.decimated(mesh, 0.5);
const mel = tf.meanEdgeLength(decimated);
const remeshed = tf.isotropicRemeshed(decimated, mel);

Mesh cleanup prepares geometry for processing:

const clean = tf.cleaned(mesh);
const oriented = tf.positivelyOriented(mesh);
const tri = tf.triangulate({ faces: quadFaces, points });

Async — every operation available as tf.async.* for non-blocking execution:

const d = await tf.async.distance(mesh, point);
const union = await tf.async.booleanUnion(mesh0, mesh1);
const { hits, ts } = await tf.async.rayCast(rays, mesh);

Continue Learning

The Quick Tour above shows trueform's syntax. To build intuition for real workflows, start with the guided examples — then explore the Modules to understand the underlying patterns.

Examples

Guided walkthroughs and runnable Node.js scripts. See the library in action.

Modules

NDArray, spatial queries, topology, and the algorithms that connect them.