larsbrubaker/manifold-rust

Pure Rust port of the Manifold 3D geometry library

20

stars

241

commits

Rust

primary language

Aug 30, 2026

updated

larsbrubaker.github.io/manifold-rust/

README

manifold-rust

crates.io docs.rs NuGet license

3D mesh booleans in pure Rust — exact on clean geometry, robust on real-world geometry.

Live WASM demo

▶ Try the live demo

What this is

Two things in one library:

  1. A pure-Rust port of Manifold (Emmett Lalish's C++ geometry kernel, v3.5.0) — union / intersection / difference on triangle meshes, plus constructors, cross-sections, convex hull, Minkowski, SDF meshing and smooth subdivision. The port targets exact numerical match: same algorithms, same floating-point results, same triangle topology, validated by instrumented boolean-by-boolean trace comparison against a locally built C++ reference.

  2. A second, original "robust" boolean engine that the C++ library does not have. It accepts the meshes real pipelines actually contain — triangle soup, scans, Thingiverse downloads: non-manifold connectivity, self-intersections, doubled sheets, disconnected shells, internal voids, inside-out bodies. It computes on exact rational arithmetic with a mesh-arrangement formulation (Zhou, Grinspun, Zorin & Jacobson 2016), so its answers are decided by exact predicates rather than by tolerances.

Why you'd use it

  • The exact engine matches the C++ reference, down to the tie-breaking order of the symbolic-perturbation predicates — so results are reproducible against the reference implementation the rest of the ecosystem uses, with no FFI and clean WASM builds.
  • The robust engine handles what the exact engine can't. It has been swept over the whole Thingi10K corpus (~10k meshes): 0 NotClosed failures, and every volume disagreement above the sampling-noise floor was arbitrated by an independent Monte-Carlo referee — in the robust engine's favour in every case (~150 arbitrated meshes). The typical exact-engine failure on such input is 2–3× volume overcounting on self-overlapping shells.
  • Auto gives you clean data by default. It picks the fast exact engine only when that is provably safe (both operands manifold and free of self-intersections, a cached ~0.2 ms exact scan), and the robust engine otherwise. You do not have to know which kind of mesh you were handed.

Features

  • Booleans: union, intersection, difference (also + - ^ operators), n-ary batch and CSG-tree evaluation
  • Constructors and modeling: cube / sphere / cylinder, extrude, revolve, convex hull, Minkowski sum & difference, SDF level sets, smooth subdivision, 2D cross-sections
  • Mesh repair utilities: repair_orientation() for inside-out bodies, rebuild_solid(rule) to re-derive a solid from the winding numbers when rewinding is not enough, has_self_intersections() as an exact self-scan
  • Cooperative cancellation and coarse progress reporting through the whole boolean pipeline (library → C FFI → WASM → demo)
  • Optional parallel feature (rayon) — results stay bit-identical to the sequential build; only determinism-preserving sites are parallelized
  • C FFI (ffi/manifold_rs.h) and C#/.NET bindings (dotnet/, ManifoldRust on NuGet)
  • WASM: an interactive demo runs the whole engine in the browser — https://larsbrubaker.github.io/manifold-rust/

Quickstart — Rust

cargo add manifold-rust
use manifold_rust::linalg::Vec3;
use manifold_rust::manifold::Manifold;
use manifold_rust::types::Error;

let cube = Manifold::cube(Vec3::new(1.0, 1.0, 1.0), true);
let sphere = Manifold::sphere(0.6, 32);

let result = cube.difference(&sphere);
assert_eq!(result.status(), Error::NoError);

println!("volume = {}", result.volume());
println!("area   = {}", result.surface_area());

let mesh = result.get_mesh_gl(0); // vert_properties / tri_verts, ready for a GPU

Messy input — import as soup and let Auto choose the engine:

use manifold_rust::types::{BooleanConfig, BooleanEngine};

// Imports geometry the strict pipeline would reject as NotManifold.
let scan = Manifold::from_mesh_gl_robust(&mesh);

// Per call…
let cut = scan.difference_with_engine(&cutter, BooleanEngine::Auto);

// …or once, process-wide.
BooleanConfig::set_default_engine(BooleanEngine::Auto);
let cut = scan.difference(&cutter);

Geometry that is not even closed imports as empty with Error::NotClosed. The default engine remains Exact, so existing code is unchanged.

Parallel execution (bit-identical results, roughly 2× on heavy boolean workloads):

[dependencies]
manifold-rust = { version = "0.12", features = ["parallel"] }

Quickstart — C# / .NET

dotnet add package ManifoldRust
using ManifoldRust;

using Manifold body = Manifold.FromMesh(vertProperties, triVerts);
using Manifold hole = Manifold.FromMesh(holeVerts, holeTris);

// Check Status on every operand: a failed import is absorbed as empty geometry.
if (body.Status != ManifoldStatus.NoError || hole.Status != ManifoldStatus.NoError)
    throw new InvalidOperationException("bad input mesh");

Manifold.DefaultBooleanEngine = BooleanEngine.Auto;   // robust when it matters

using Manifold result = Manifold.BatchBoolean(new[] { body, hole }, ManifoldOpType.Subtract);
MeshGL mesh = result.GetMeshGL();

There is a double-precision path (FromMesh64 / GetMeshGL64), a robust import (FromMeshRobust), and CancellationToken support. Full binding documentation: dotnet/README.md; the ABI itself is described in ffi/manifold_rs.h.

manifold-sharp — the same library, in C#

The ManifoldRust package above is a P/Invoke binding: it loads this Rust cdylib and calls into it. manifold-sharp is the other thing you might want — a complete pure C# port of manifold-rust, with no native library at all, so it runs anywhere .NET runs, browser-wasm included. It is bit-exact with this crate on identical inputs, and it lives as a submodule of agg-sharp.

The two projects check each other: manifold-sharp's oracle test lane runs the same operations through its port and through this library via the binding, then compares the exported meshes row for row with no slack.

State of the project

  • Port: complete. All 18 phases of the C++ engine (v3.5.0) are implemented and every C++ test is ported or covered — 721 tests passing, 0 failing in a debug run, and 730 passing with nothing ignored in release (the 9 #[ignore]d tests are debug-build-speed only). Details in PORTING_PLAN.md.
  • Performance: at parity with the sequential C++ build. Sphere-minus-sphere at 2 M input triangles: 2.61 s (C++) vs 2.57 s (Rust); a 7 999-sphere grid union: 13.5 s vs 14.5 s — identical triangle counts throughout, peak memory within ~10%. The parallel feature roughly doubles throughput. Reproduce with cargo run --release --example perf_test and --example large_scene_test.
  • Robust engine: corpus-validated, with the current numbers, open items and the referee tooling in docs/ROBUST_ENGINE_STATUS.md.
  • Deliberate divergences from C++ are catalogued in docs/CPP_DIVERGENCES.md, in two kinds: accuracy fixes we stand behind, and inherited output shapes we would resolve toward the C++ but cannot change unilaterally without breaking a downstream port that verifies against this tree bit-for-bit. The second kind is disclosed with what a coordinated fix would take.

Known limits, honestly:

  • Very large, heavily self-intersecting meshes can be slow in the robust engine — a handful of the ~10k corpus meshes exceed a 120 s budget and are reported as Cancelled rather than wrong. Speeding up the exact-predicate fallback is the top open item.
  • The WASM build is single-threaded; the parallel feature is native-only.
  • The robust engine requires input to be closed; anything else imports empty with Error::NotClosed.

Building

cargo build
cargo test --release

Exact-match validation against the upstream C++ (needs the submodule):

git submodule update --init --recursive
./validate-reference.ps1            # or: ./validate-reference.ps1 -Phase phase8

The WASM demo:

cd demo && bun run build:wasm && bun run dev

Support the project

manifold-rust is open source, free to use, and maintained in spare time as a labor of love (friends James Smith and Dan Ruskin help out from time to time). MatterHackers sponsors the work — it uses mesh booleans extensively in production 3D-printing workflows, which is why a dependable pure-Rust kernel exists at all.

  • Donate: Buy Me a Coffee
  • Star the repo — costs nothing, helps others find it
  • Report issues: open an issue; the demo's Copy Debug Info button captures everything a boolean bug report needs
  • Contribute: PRs welcome — open an issue first for larger changes

Part of the rust-apps suite — Rust graphics and geometry libraries by Lars Brubaker.

License and credits

Apache-2.0, matching the original Manifold library.

Contributors

larsbrubaker

240 commits

AmadeusWM

1 commits

larsbrubaker/manifold-rust

Pure Rust port of the Manifold 3D geometry library

20

stars

241

commits

Rust

primary language

Aug 30, 2026

updated

larsbrubaker.github.io/manifold-rust/

README

manifold-rust

crates.io docs.rs NuGet license

3D mesh booleans in pure Rust — exact on clean geometry, robust on real-world geometry.

Live WASM demo

▶ Try the live demo

What this is

Two things in one library:

  1. A pure-Rust port of Manifold (Emmett Lalish's C++ geometry kernel, v3.5.0) — union / intersection / difference on triangle meshes, plus constructors, cross-sections, convex hull, Minkowski, SDF meshing and smooth subdivision. The port targets exact numerical match: same algorithms, same floating-point results, same triangle topology, validated by instrumented boolean-by-boolean trace comparison against a locally built C++ reference.

  2. A second, original "robust" boolean engine that the C++ library does not have. It accepts the meshes real pipelines actually contain — triangle soup, scans, Thingiverse downloads: non-manifold connectivity, self-intersections, doubled sheets, disconnected shells, internal voids, inside-out bodies. It computes on exact rational arithmetic with a mesh-arrangement formulation (Zhou, Grinspun, Zorin & Jacobson 2016), so its answers are decided by exact predicates rather than by tolerances.

Why you'd use it

  • The exact engine matches the C++ reference, down to the tie-breaking order of the symbolic-perturbation predicates — so results are reproducible against the reference implementation the rest of the ecosystem uses, with no FFI and clean WASM builds.
  • The robust engine handles what the exact engine can't. It has been swept over the whole Thingi10K corpus (~10k meshes): 0 NotClosed failures, and every volume disagreement above the sampling-noise floor was arbitrated by an independent Monte-Carlo referee — in the robust engine's favour in every case (~150 arbitrated meshes). The typical exact-engine failure on such input is 2–3× volume overcounting on self-overlapping shells.
  • Auto gives you clean data by default. It picks the fast exact engine only when that is provably safe (both operands manifold and free of self-intersections, a cached ~0.2 ms exact scan), and the robust engine otherwise. You do not have to know which kind of mesh you were handed.

Features

  • Booleans: union, intersection, difference (also + - ^ operators), n-ary batch and CSG-tree evaluation
  • Constructors and modeling: cube / sphere / cylinder, extrude, revolve, convex hull, Minkowski sum & difference, SDF level sets, smooth subdivision, 2D cross-sections
  • Mesh repair utilities: repair_orientation() for inside-out bodies, rebuild_solid(rule) to re-derive a solid from the winding numbers when rewinding is not enough, has_self_intersections() as an exact self-scan
  • Cooperative cancellation and coarse progress reporting through the whole boolean pipeline (library → C FFI → WASM → demo)
  • Optional parallel feature (rayon) — results stay bit-identical to the sequential build; only determinism-preserving sites are parallelized
  • C FFI (ffi/manifold_rs.h) and C#/.NET bindings (dotnet/, ManifoldRust on NuGet)
  • WASM: an interactive demo runs the whole engine in the browser — https://larsbrubaker.github.io/manifold-rust/

Quickstart — Rust

cargo add manifold-rust
use manifold_rust::linalg::Vec3;
use manifold_rust::manifold::Manifold;
use manifold_rust::types::Error;

let cube = Manifold::cube(Vec3::new(1.0, 1.0, 1.0), true);
let sphere = Manifold::sphere(0.6, 32);

let result = cube.difference(&sphere);
assert_eq!(result.status(), Error::NoError);

println!("volume = {}", result.volume());
println!("area   = {}", result.surface_area());

let mesh = result.get_mesh_gl(0); // vert_properties / tri_verts, ready for a GPU

Messy input — import as soup and let Auto choose the engine:

use manifold_rust::types::{BooleanConfig, BooleanEngine};

// Imports geometry the strict pipeline would reject as NotManifold.
let scan = Manifold::from_mesh_gl_robust(&mesh);

// Per call…
let cut = scan.difference_with_engine(&cutter, BooleanEngine::Auto);

// …or once, process-wide.
BooleanConfig::set_default_engine(BooleanEngine::Auto);
let cut = scan.difference(&cutter);

Geometry that is not even closed imports as empty with Error::NotClosed. The default engine remains Exact, so existing code is unchanged.

Parallel execution (bit-identical results, roughly 2× on heavy boolean workloads):

[dependencies]
manifold-rust = { version = "0.12", features = ["parallel"] }

Quickstart — C# / .NET

dotnet add package ManifoldRust
using ManifoldRust;

using Manifold body = Manifold.FromMesh(vertProperties, triVerts);
using Manifold hole = Manifold.FromMesh(holeVerts, holeTris);

// Check Status on every operand: a failed import is absorbed as empty geometry.
if (body.Status != ManifoldStatus.NoError || hole.Status != ManifoldStatus.NoError)
    throw new InvalidOperationException("bad input mesh");

Manifold.DefaultBooleanEngine = BooleanEngine.Auto;   // robust when it matters

using Manifold result = Manifold.BatchBoolean(new[] { body, hole }, ManifoldOpType.Subtract);
MeshGL mesh = result.GetMeshGL();

There is a double-precision path (FromMesh64 / GetMeshGL64), a robust import (FromMeshRobust), and CancellationToken support. Full binding documentation: dotnet/README.md; the ABI itself is described in ffi/manifold_rs.h.

manifold-sharp — the same library, in C#

The ManifoldRust package above is a P/Invoke binding: it loads this Rust cdylib and calls into it. manifold-sharp is the other thing you might want — a complete pure C# port of manifold-rust, with no native library at all, so it runs anywhere .NET runs, browser-wasm included. It is bit-exact with this crate on identical inputs, and it lives as a submodule of agg-sharp.

The two projects check each other: manifold-sharp's oracle test lane runs the same operations through its port and through this library via the binding, then compares the exported meshes row for row with no slack.

State of the project

  • Port: complete. All 18 phases of the C++ engine (v3.5.0) are implemented and every C++ test is ported or covered — 721 tests passing, 0 failing in a debug run, and 730 passing with nothing ignored in release (the 9 #[ignore]d tests are debug-build-speed only). Details in PORTING_PLAN.md.
  • Performance: at parity with the sequential C++ build. Sphere-minus-sphere at 2 M input triangles: 2.61 s (C++) vs 2.57 s (Rust); a 7 999-sphere grid union: 13.5 s vs 14.5 s — identical triangle counts throughout, peak memory within ~10%. The parallel feature roughly doubles throughput. Reproduce with cargo run --release --example perf_test and --example large_scene_test.
  • Robust engine: corpus-validated, with the current numbers, open items and the referee tooling in docs/ROBUST_ENGINE_STATUS.md.
  • Deliberate divergences from C++ are catalogued in docs/CPP_DIVERGENCES.md, in two kinds: accuracy fixes we stand behind, and inherited output shapes we would resolve toward the C++ but cannot change unilaterally without breaking a downstream port that verifies against this tree bit-for-bit. The second kind is disclosed with what a coordinated fix would take.

Known limits, honestly:

  • Very large, heavily self-intersecting meshes can be slow in the robust engine — a handful of the ~10k corpus meshes exceed a 120 s budget and are reported as Cancelled rather than wrong. Speeding up the exact-predicate fallback is the top open item.
  • The WASM build is single-threaded; the parallel feature is native-only.
  • The robust engine requires input to be closed; anything else imports empty with Error::NotClosed.

Building

cargo build
cargo test --release

Exact-match validation against the upstream C++ (needs the submodule):

git submodule update --init --recursive
./validate-reference.ps1            # or: ./validate-reference.ps1 -Phase phase8

The WASM demo:

cd demo && bun run build:wasm && bun run dev

Support the project

manifold-rust is open source, free to use, and maintained in spare time as a labor of love (friends James Smith and Dan Ruskin help out from time to time). MatterHackers sponsors the work — it uses mesh booleans extensively in production 3D-printing workflows, which is why a dependable pure-Rust kernel exists at all.

  • Donate: Buy Me a Coffee
  • Star the repo — costs nothing, helps others find it
  • Report issues: open an issue; the demo's Copy Debug Info button captures everything a boolean bug report needs
  • Contribute: PRs welcome — open an issue first for larger changes

Part of the rust-apps suite — Rust graphics and geometry libraries by Lars Brubaker.

License and credits

Apache-2.0, matching the original Manifold library.

Contributors

larsbrubaker

240 commits

AmadeusWM

1 commits

Languages

Rust

90.4%

C#

8.2%

C

1.3%