manifold-csg-sys 3.5.100

Raw FFI bindings to the manifold3d C API for constructive solid geometry
Documentation

manifold-csg

crates.io docs.rs CI

Safe Rust bindings to the manifold3d geometry kernel for constructive solid geometry (CSG).

manifold3d is a fast, robust C++ library for boolean operations on 3D triangle meshes. These bindings make its capabilities accessible from Rust with minimal overhead and without requiring users to manage C pointers or memory. See the upstream documentation for details on the underlying algorithms and behavior.

What's included

manifold-csg-sys provides raw FFI bindings to the manifold3d C API. If you need direct C-level control, it's there.

manifold-csg wraps the most commonly needed operations in safe Rust:

  • 3D solids (Manifold) — primitives (cube, sphere, cylinder, tetrahedron), boolean operations (union, difference, intersection), transforms, convex hull, decomposition, Minkowski sum/difference, mesh refinement, smoothing, SDF level sets, warp deformation, and OBJ I/O
  • 2D regions (CrossSection) — primitives (square, circle, polygons), boolean operations, Clipper2-based geometric offset, convex hull, transforms, warp, and simplification
  • Mesh data (MeshGL64 / MeshGL) — f64 and f32 mesh types for getting data in and out
  • Triangulation (triangulate_polygons) — constrained Delaunay triangulation of 2D polygons
  • 2D-to-3D — extrude (with optional twist and scale) and revolve cross-sections into solids; slice solids back to cross-sections

See API_COVERAGE.md for a full table mapping every C API function to its safe wrapper (or noting where one doesn't exist yet).

Design choices

  • f64 by default. Mesh I/O uses MeshGL64 so you don't lose precision through f32 round-trips. f32 paths (from_mesh_f32, to_mesh_f32, MeshGL) are available when you need them.
  • Send + Sync. All types can be moved across threads and shared for concurrent reads.
  • Automatic memory management. All C handles are freed via Drop. No manual cleanup needed.
  • Operator overloads. &a + &b (union), &a - &b (difference), &a ^ &b (intersection) work on both Manifold and CrossSection.
  • Callback-based APIs wrapped safely. warp, set_properties, from_sdf, and OBJ I/O all accept closures with catch_unwind to prevent panics from unwinding through C stack frames.
  • C API parity. Parameter order and names follow the C API so users transitioning from C/C++ find things where they expect.

Quick start

use manifold_csg::{Manifold, CrossSection, JoinType};

// 3D: drill a cylindrical hole through a cube
let cube = Manifold::cube(20.0, 20.0, 20.0, true);
let hole = Manifold::cylinder(30.0, 5.0, 5.0, 32, false);
let result = &cube - &hole;
assert!(result.volume() < cube.volume());

// 2D -> 3D: offset a rectangle and extrude it
let section = CrossSection::square(10.0, 10.0, true);
let expanded = section.offset(2.0, JoinType::Round, 2.0, 16);
let solid = expanded.extrude(20.0);

See the examples/ directory for more complete, runnable examples.

Crates

Crate Description
manifold-csg Safe Rust wrapper (start here)
manifold-csg-sys Raw FFI bindings to the full C API

Build requirements

  • Rust 1.85+
  • git, cmake, a C++ compiler
  • First build clones manifold3d and compiles it from source; subsequent builds use the cached copy. Internet access is required for the initial clone.
cargo build           # builds both crates
cargo test --features nalgebra   # runs the test suite

Tested on Linux, macOS, Windows, wasm32-unknown-emscripten, and wasm32-unknown-unknown (see below).

Browser / WebAssembly (wasm32-unknown-emscripten)

manifold-csg builds and runs in the browser via Emscripten. The C++ kernel is compiled with emcmake/emmake; Rust links against it via emcc.

brew install emscripten   # or install the raw emsdk and source emsdk_env.sh
rustup target add wasm32-unknown-emscripten
cargo build --target wasm32-unknown-emscripten -p manifold-csg --no-default-features

The integration test suite runs under Node (the workspace .cargo/config.toml sets the runner, so no env var needed):

cargo test --target wasm32-unknown-emscripten -p manifold-csg --no-default-features --tests

Notes:

  • The parallel feature is silently disabled on emscripten — TBB requires pthread support which in turn needs the host page to provide SharedArrayBuffer via COOP/COEP HTTP headers. Use --no-default-features to opt out cleanly.
  • Tests using std::thread::spawn are marked #[ignore] on this target for the same reason.
  • For wasm32-unknown-unknown support (the wasm-bindgen-compatible target), see the next section.
  • End-user crates that produce their own bin/cdylib from a wasm build need to forward the same emscripten link flags. Add a one-line build.rs that re-emits DEP_MANIFOLD_LINK_ARGS, or set them via .cargo/config.toml.
  • Existing examples build for wasm too — e.g. cargo build --example basics --target wasm32-unknown-emscripten -p manifold-csg --no-default-features produces a .wasm + .js shim you can run with node target/wasm32-unknown-emscripten/debug/examples/basics.js.

Browser without Emscripten (wasm32-unknown-unknown)

manifold-csg also builds for the bare-wasm target — the same one wasm-bindgen consumers (Bevy, Leptos, Yew, etc.) target. The C++ runtime gap (wasm32-unknown-unknown ships no libc, no libc++, no libc++abi) is filled by wasm-cxx-shim, which is cloned and built automatically by build.rs.

This target is provisional. The build carries patches against upstream manifold and Clipper2, ships without an exception runtime (implicit STL throws abort), and disables OBJ I/O. To acknowledge these constraints, the unstable-wasm-uu cargo feature is required for any build targeting wasm32-unknown-unknown. Without it, build.rs aborts with an instructive error.

manifold-csg = { version = "...", default-features = false, features = ["unstable-wasm-uu"] }

Requirements:

  • A wasm-capable LLVM 20+ install:
    • macOS: brew install llvm (then add /opt/homebrew/opt/llvm@20/bin to PATH)
    • Debian: apt install clang-20 lld-20 libc++-20-dev libc++abi-20-dev
  • Rust target: rustup target add wasm32-unknown-unknown
  • If LLVM is in a non-standard location, set WASM_CXX_SHIM_LLVM_BIN_DIR=/path/to/llvm/bin in your environment.
cargo build --target wasm32-unknown-unknown -p manifold-csg \
    --no-default-features --features unstable-wasm-uu

A runnable smoke example exercises a real CSG operation under Node:

cargo build --example wasm32_uu_smoke --target wasm32-unknown-unknown \
    -p manifold-csg --no-default-features --features unstable-wasm-uu
node crates/manifold-csg/wasm32-uu-runner/run.mjs \
    target/wasm32-unknown-unknown/debug/examples/wasm32_uu_smoke.wasm
# wasm32-uu-smoke: smoke_run() = 36 (triangle count, > 0) ✓

For an interactive end-to-end demo see the boolean playground — a browser app that wires manifold-csg into three.js via a small C ABI and lets you union/diff/intersect cubes/spheres/cylinders with transform gizmos. Source under crates/manifold-csg-playground/ (auto-deployed to GitHub Pages).

Notes:

  • First build is slow (clones manifold + Clipper2 + wasm-cxx-shim, builds three cmake projects in cross-compile). Subsequent builds use the cached artifacts.
  • The parallel feature is unavailable on this target (no threads in default wasm32-unknown-unknown).
  • OBJ I/O is unavailable on this target (Manifold::from_obj/to_obj and MeshGL64::from_obj/to_obj are #[cfg]-elided). Manifold's iostream- based OBJ paths depend on libc++ machinery the freestanding wasm build excludes; use the binary MeshGL64 API to round-trip mesh data instead.
  • Exceptions abort. Compiled with -fno-exceptions; implicit STL throws (bad_alloc, etc.) become unrecoverable wasm traps.
  • See docs/plans/wasm-unknown-unknown.md for the design background and production-readiness checklist.
  • If the build fails, run bash crates/manifold-csg-sys/wasm32-uu/diagnose.sh > bugreport.txt 2>&1 and attach the output to your issue — it captures the LLVM probe ladder, env vars, and cached build state.

Feature flags

Feature Default Description
parallel yes Enables TBB-based parallelism for boolean operations
nalgebra no Adds convenience methods that accept nalgebra::Matrix3, Vector3, Point3
unstable-wasm-uu no Required when targeting wasm32-unknown-unknown. Acknowledges that target's provisional status (carry-patches, no exceptions, no OBJ I/O). Has no effect on other targets.

Documentation

  • API_COVERAGE.md — maps every manifold3d C function to its safe wrapper, with source links
  • docs.rs — generated API docs
  • examples/ — runnable code examples
  • Upstream docs — manifold3d C++ API documentation (helpful for understanding parameter semantics)
  • Migration guides — one per breaking-change version pair, each structured for AI-assisted migration:
    • from 0.0.6 — original manifold3d crate line (pre-transfer to this project).
    • 0.1.8 → 0.2.0ExecutionContext attachment API reshape.

License

Licensed under either of Apache License, Version 2.0 or MIT license at your option.