Open Mesh Library on NPMJS - trimesh-boolean

trimesh-boolean — Mesh boolean operations that work on open surfaces

Gday Mates,

I thought some of you might get value from this library… I had to build to solve an issue, over several months of work it is looking good. It was in order to get my application Kirra to work with open mesh booleans.

trimesh-boolean — a JavaScript library for performing boolean operations (subtract, union, intersect) on triangle meshes. The difference from existing packages: it works on open, non-watertight meshes like terrain surfaces, DTMs, geological shells, and partial meshes, as well as closed solids.

Live Demo · GitHub · npm


I needed boolean operations on open mining surfaces for Kirra, a “free to use” browser-based 3D blast design tool I’m building. Nothing out there handled it, so I built it.

Package Open surfaces? Approach
three-bvh-csg No BVH-accelerated BSP
three-csg-ts No BSP tree (TS)
manifold-3d No WASM C++
trimesh-boolean Yes Moller intersection + fan triangulation + shared Steiner points + hybrid classification + heffalump per-triangle classifier

Two pipelines

The library ships with two boolean pipelines.

Original pipeline

Moller tri-tri intersection → multi-axis spatial grids (XY, YZ, XZ) → flood-fill classification via multi-axis majority vote → fan triangulation with CDT fallback → half-space sub-triangle classification with constraint enforcement → seam deduplication → normal propagation → group combination.

BMS pipeline (Brent’s Mega Soup)

The BMS pipeline was built to solve the reliability problems of the original — vertex identity drift, distance-threshold chaining, and boundary classification on open meshes.

  • Shared vertex pool — both meshes share a spatial-hash vertex pool. Intersection endpoints are the exact same object reference on both sides (=== identity, not string matching). Two segments connect if they share a pool vertex.
  • Identity-based chaining — uses pool vertex integer IDs for O(1) adjacency. At junction vertices (degree 3+), picks the smoothest continuation by dot product.
  • Fan triangulation — chains segments into ordered polylines, fans from each original vertex to sequential chain points. Every sub-triangle has at least one original vertex. Eliminates “pocket triangles” (all-Steiner sub-tris) that plagued CDT. Falls back to CDT for multi-chain or vertex-hit cases.
  • Boundary closure — builds one continuous closed polygon per mesh connecting all intersection chains via barrier-aware graph walks and the mesh’s open boundary.
  • Hybrid classification — open meshes use boundary topology (touches mesh boundary = outside, enclosed by barriers = inside). Closed meshes use barrier-normal dot product.

Heffalump classifier

The elusive heffalump… is the fallback for meshes with defective topology — non-manifold edges, fragmented boundaries, cracks, holes. The name comes from the approach: how do you eat an elephant? One bite at a time. Instead of trying to classify entire components via boundary walks (which break when the boundary is fragmented), the heffalump bites off small chunks — classifying just a few triangles at a time near the intersection:

  • Closed other mesh: ray-cast each triangle’s centroid through the other mesh (odd crossings = inside)
  • Open other mesh: find the nearest surface triangle, check which side the centroid is on

No flood fill, no boundary walk needed. shouldUseHeffalump() auto-detects non-manifold edges and switches automatically.

For the full algorithm breakdown, see the wiki.

Features

  • All standard operations: A−B, B−A, union, intersect, complement variants, and custom group selection
  • Split-and-pick workflowsplitMeshPair returns 4 groups (A-inside, A-outside, B-inside, B-outside), you decide which to keep
  • Per-component decompositionsplitToComponents breaks groups into connected components, mergeSmallComponents absorbs tiny fragments
  • Built-in Three.js adapter — pass in Three.js meshes, get Three.js meshes back
  • Interactive reclassification — click-to-reassign individual triangles or shift-click for flood-fill region reassignment
  • Mesh repair pipeline — vertex deduplication, T-junction resolution, welding, degenerate/sliver removal, boundary stitching, gap filling, force-close
  • Diagnostic overlays in the demo — wireframe, open edges, non-manifold edges, intersection lines, boundary walks
  • Minimal dependencies: delaunator, @kninnug/constrainautor, robust-predicates, tiny-exact-math. Three.js is an optional peer dependency.
  • Works in the browser via CDN or as an npm package

Install

npm install trimesh-boolean

Or via CDN:

html

<script src="https://unpkg.com/trimesh-boolean/build/trimesh-boolean.min.js"></script>

Quick example with Three.js

js

import { booleanFromMeshes } from 'trimesh-boolean/three';

const resultMesh = booleanFromMeshes(threeGroupA, threeGroupB, 'subtract');
scene.add(resultMesh);

Or with plain triangle soup:

js

import { boolean } from 'trimesh-boolean';

const result = boolean(soupA, soupB, 'subtract');
// result = { soup: Triangle[], points: Vertex[], triangles: WeldedTri[] }

BMS pipeline (recommended for open surfaces):

js

import { bmsBooleanOp } from 'trimesh-boolean';

const bms = bmsBooleanOp(meshA, meshB, 'subtract', { preRepair: true });
// bms.groups = { aInside, aOutside, bInside, bOutside }
// bms.segments, bms.polylines, bms.componentWalks

The demo

The live demo ships with several test meshes including terrain surfaces (11,200 tris), convoluted shapes, cylinders, shells, and cubes. You can pick any combination, run any operation, and toggle diagnostic overlays to see exactly what’s happening — intersection lines, open edges, non-manifold edges, wireframe, boundary walks. There’s also a 2D demo for visualising the algorithm steps.

The demo supports both pipelines — the standard splits and the BMS-Heffalump splits — so you can compare results side by side. Import/Export KAP support lets you round-trip surfaces with Kirra.

Where it’s at

Currently v0.5.6. It handles a range of geometry, but it’s still a work in progress — complex concave intersections and high-density meshes with many crossing triangles can still produce the occasional issue. Known issues are tracked in the repo. Contributions and bug reports welcome.

I need tis for drill scheduling where accurate volumes mean the drill schedule is as correct as it can be, so the it is biased towards terrain-style geometry, but it works on closed solids too.

Links:

Happy to answer questions about the approach or discuss the gory details of open-mesh booleans.

1 Like

cool project but yeah… i’d be a bit cautious here

open mesh booleans are one of those problems that look solved until you throw real messy data at them. non-manifold edges, tiny gaps, precision issues… stuff breaks fast. even the post admits it still struggles with complex concave intersections and dense meshes

also the pipeline is… pretty heavy. lots of custom steps, fallback logic, special classifiers. that usually means maintenance cost is high and edge cases keep popping up over time

if someone just needs basic booleans in three.js, this is probably overkill. and for production critical stuff, people usually still lean toward more battle tested libs or backend solutions

that said, handling open surfaces at all is impressive. just wouldn’t assume it’s plug and play reliable yet especially for anything that needs consistent accuracy across lots of inputs