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?
