Trueform 0.7: WASM NDArrays with vectorized geometric queries. From collisions, to mesh booleans

We have released the TS/JS SDK we announced a while back. Built on WASM bindings for the C++ library we use in production to build real time 3D applications.

npm install @polydera/trueform

Easier to show than explain.

Load a mesh, normalize it, slice it with a plane, cap the cross-section, pull the halves apart, and hand everything to Three.js.

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

const mesh = tf.readStl(await (await fetch("dragon-250k.stl")).arrayBuffer());

// fit into unit sphere
const [lo, hi] = [tf.min(mesh.points, 0), tf.max(mesh.points, 0)];
mesh.points.sub_(lo.add(hi).mul(0.5)).div_(tf.max(hi.sub(lo)) * 0.5);

Signed distance to a tilted plane, vectorized over all vertices in one call:

const normal = tf.vector(tf.normalize(tf.ndarray([1, 2, 0])));
const scalars = tf.distance(tf.point(mesh.points), tf.plane(normal, 0));

Same pattern works for rayCast, intersects, closestPoint, neighborSearch — between both primitives and forms (mesh, point cloud). Pass a batch in, get a batch back, auto-parallelized in WASM.

Slice the mesh. One call gives us the cut mesh with per-face band labels and the intersection curves:

const { mesh: cut, labels, curves } = tf.isobands(
  mesh, scalars, new Float32Array([0]), { returnCurves: true },
);

labels is an NDArray — every face tagged 0 or 1 depending on which side of the cut it landed. You could extract each side by mask:

const bottom = tf.reindexedByMask(cut, labels.eq(0));
const top    = tf.reindexedByMask(cut, labels.eq(1));

Or just split them all at once (await tf.async.splitIntoComponents(...) if you want it off the main thread):

const [bottom, top] = tf.splitIntoComponents(cut, labels).components;

The curves are closed loops sitting on the mesh surface. Triangulate them to cap the cross-section:

const cap = tf.triangulate({ faces: curves.paths, points: curves.points });

Pull the halves apart along the plane normal — .add_ broadcasts the [3] direction across every vertex:

const dir = tf.normalize(tf.ndarray([1, 2, 0]));
top.points.add_(dir.mul(0.3));
bottom.points.add_(dir.mul(-0.3));

That’s the geometry. Now hand it to Three.js. points.data and faces.data are typed array views into WASM memory — no copy:

for (const [m, color] of [[top, 0xcccccc], [bottom, 0xcccccc], [cap, 0xff4444]]) {
  const g = new THREE.BufferGeometry();
  g.setAttribute("position", new THREE.BufferAttribute(m.points.data, 3));
  const f = m.faces.data;
  g.setIndex(new THREE.BufferAttribute(new Uint32Array(f.buffer, f.byteOffset, f.length), 1));
  g.computeVertexNormals();
  scene.add(new THREE.Mesh(g, new THREE.MeshStandardMaterial({ color })));
}

That’s it. Load, normalize, slice, cap, separate, render. The interactive live examples on the website are all built with Three.js + this SDK.

Documentation: https://trueform.polydera.com/ts/getting-started

Two questions for the community:

Benchmarks. Right now we defer to our C++ benchmarks. Any suggestions for JS/TS geometry libraries to benchmark against would be welcome.

COOP/COEP headers. The parallelized WASM backend requires Cross-Origin-Opener-Policy: same-origin and Cross-Origin-Embedder-Policy: require-corp headers for SharedArrayBuffer. Is that a dealbreaker for your setup, or something you already have in place?

2 Likes