Exact B-Rep solid modeling kernel for Rust and WebAssembly.
Kernel contract · Architecture · Performance · Getting started · Known limitations · Contributing
One exact-geometry engine, from Rust and from JavaScript. Cut a solid, measure it, export it.
use remus::prelude::*;
# fn main() -> Result<(), Box<dyn std::error::Error>> {
let mut model = Model::new();
// Primitives are anchored at the origin, so this cylinder rounds off the
// block's corner. Transform it first to place the cut elsewhere.
let block = model.make_box(30.0, 20.0, 10.0)?;
let cutter = model.make_cylinder(5.0, 15.0)?;
let notched = model.cut(block, cutter)?;
// Every policy-aware boolean discloses whether its result stayed exact.
assert_eq!(notched.quality, BooleanQuality::Exact);
let volume = model.volume(notched.solid, 0.1)?;
let step = model.write_step(&[notched.solid])?;
assert!(volume > 0.0);
assert!(step.starts_with("ISO-10303-21;"));
# Ok(())
# }import { BrepKernel } from 'remus-wasm';
import { RemusIo } from 'remus-wasm-io';
const kernel = new BrepKernel();
// Primitives are anchored at the origin, so this cylinder rounds off the
// block's corner. Use `transformSolid` to place it somewhere else.
const block = kernel.makeBox(30, 20, 10);
const cutter = kernel.makeCylinder(5, 15);
const cut = kernel.cutDetailed(block, cutter);
if (cut.status === 'error') {
throw new Error(`${cut.code}: ${cut.details.message}`);
}
const notched = cut.value;
const vol = kernel.volume(notched, 0.1);
// File formats live in a separate translator module, loaded only around
// import and export. Bodies cross between the two as exact arena documents.
const io = new RemusIo();
const step = io.exportStep(kernel.serializeSolids(Uint32Array.of(notched))); // Uint8ArrayRemus is a B-Rep solid modeling kernel written from scratch in Rust. It targets
WebAssembly, so the same kernel runs in the browser and on the desktop.
unsafe is denied by lint, as are unwrap and panic. Every public operation
returns a Result.
Parametric CAD in the browser has long meant choosing between proprietary kernels and large C++ codebases compiled to WASM. Remus exists to be the third option: a from-scratch Rust kernel with exact geometry and a permanent Apache-2.0 license. It is maintained by Esau Engineering as the Apache-2.0 continuation of an upstream kernel that relicensed at v3 — see Provenance for how that boundary is enforced.
The geometry is exact. Booleans run on analytic and NURBS surfaces and keep those surfaces through the operation, so a cylinder stays a cylinder instead of becoming a bag of triangles. That keeps face counts low and round-trips lossless.
Remus's canonical modeling convention is millimetres for length and radians for angle. The kernel does not attach units to scalar values or silently convert them; applications using another length unit must scale all coordinates, dimensions, deflections, and linear tolerances consistently at their boundary. See the tolerance and robustness guide.
Remus is being driven from a broad-but-maturing kernel toward a professional-grade one, and the rules for that are written down rather than implied. This is the part of the repository worth reading before you trust a feature label.
- Kernel maturity target — what "professional-grade" means here, the program invariants, and the program-wide definition of done.
- Capability matrix — the qualification structure. Every cell of every operation family is Qualified, Partial, Unqualified, Unsupported-typed, or Unsupported-untyped. It is the promotion authority for the feature labels in Status: no feature is promoted on a single successful fixture.
- Operation contract — the result, quality, fallback, and postcondition contract every operation converges on.
- Failure taxonomy — stable failure categories, and how they map onto the error-code registry.
- Testing strategy — what kind of evidence qualifies a capability cell, and what CI gates.
- Stability matrix — the audited disposition of each label shipping today, including the rows whose advertised domain is not yet fully evidenced.
- Stabilization plan — the working plan for promoting every Beta/Experimental row below to Stable, sequenced under the capability-matrix promotion rules.
- Unified roadmap — the live work queue across the correctness program (P-Class) and the adoption program (Open Kernel), each with a status ledger updated in the PR that changes it.
- Industrial parity overlay — where each capability stands against the incumbent open-source reference kernel, on a competitive axis kept separate from the contract states above; it changes no label here.
Four mechanisms carry that contract in code:
| Mechanism | Where | What it gives you |
|---|---|---|
| Operation context | remus_math::context::OperationContext (RFC 0001) |
Tolerances, hard work budgets, fallback policy, and cooperative cancellation as explicit caller-visible policy. Defaults reproduce prior behavior exactly; cancellation is typed and transactional. |
| Structured diagnostics | remus_math::diagnostic |
Every failure carries a stable category plus a stable code, independent of the Rust error type. Codes are explicit literals, never derived from type or variant names, and the registry is additive only. |
| Coedges and per-use p-curves | remus_topology (RFC 0002) |
First-class edge uses, so seams, poles, and periodic surfaces are represented correctly. Seam p-curve access is fail-closed rather than silently picking one side. |
| Reproduction bundles | remus_wasm::repro |
Versioned JSON that replays an operation sequence and its expected results through the batch dispatch path — identically on native and WASM. Bundles are the canonical carrier for new regressions; expected failures are first-class. |
Structural work lands through versioned RFCs in docs/design
and incremental vertical slices, not repository-wide rewrites. Tests are not
weakened, tolerances are not widened, and a mesh fallback is not introduced to
make a failing case pass.
Remus is in active development. Core modeling is solid. Each feature below carries the label the stability matrix assigns it (stable, beta, experimental, or partial, with any declared domain in parentheses), and that matrix records what evidence each label currently rests on. Known Limitations covers the gaps.
| Category | Feature | Status |
|---|---|---|
| Primitives | Box, cylinder, cone, sphere, torus, ellipsoid | Stable |
| Primitives | Convex hull, Minkowski sum (convex inputs) | Stable |
| Booleans | Union, cut, intersect on plane, cylinder, cone, sphere, NURBS | Stable |
| Booleans | Batch fuse-all (disjoint-aware union) | Stable |
| Booleans | Torus booleans (box ± torus, coaxial torus) | Beta |
| Booleans | Cellular and Compound operands (severing planar cuts, disjoint fuses) | Experimental |
| Modifiers | Validated planar fillet/chamfer and axisymmetric closed-rim fillet; other curved blend geometry (experimental assembly) | Stable / Experimental |
| Modifiers | Fillet overflow: transactional stop-at-cliff refusal (rollover unqualified) | Stable |
| Modifiers | Variable-radius, curved-support, and N-way vertex blends | Experimental |
| Modifiers | Face-face blend sheets and hold lines | Experimental |
| Modifiers | Resize or remove an analytic blend band (resize_blend) |
Experimental |
| Modifiers | Push/pull and move face (analytic cylinder caps, holed planar boss supports) | Stable (declared domain) |
| Modifiers | Replace surface (plane, coaxial bore cylinder) | Experimental |
| Modifiers | Shell (hollow solid) | Stable |
| Modifiers | Offset face, offset solid, thicken, mirror, pattern | Stable |
| Modifiers | Draft (planar faces) | Stable |
| Sweeps | Extrude (planar + NURBS profiles) | Stable |
| Sweeps | Revolve, sweep, loft, pipe (planar profiles) | Stable |
| Sweeps | Helical sweep | Stable |
| Sweeps | Non-planar profiles for loft, sweep, pipe, revolve | Stable |
| Sweeps | First-class wire bodies as sweep profiles | Experimental |
| Construction | Coons-patch face fill, sew, untrim | Stable |
| Sectioning | Cross-section faces, split by plane | Stable |
| Sectioning | Sheet split/trim and planar solid imprint | Experimental |
| Measurement | Bounding box, area, volume, center of mass, inertia tensor + principal axes | Stable |
| Measurement | Point-to-solid, solid-to-solid distance, point classification | Stable |
| Measurement | Sheet area, bounds, and centroid; wire length | Experimental |
| Drawing | Hidden-line edge projection | Stable |
| Geometry | NURBS evaluation, derivatives, knot ops, fitting, projection | Stable |
| Geometry | Analytic intersections (plane × cylinder, cone, sphere exact; torus sampled) | Stable |
| Geometry | Surface-surface intersection (analytic + marching) | Stable |
| Geometry | Curve-curve intersection (Bezier clipping) | Stable |
| Tessellation | Adaptive deflection, CDT, analytic-surface optimization | Stable |
| Tessellation | Open sheet bodies | Experimental |
| Repair | Shape healing (wire, face, shell fixes), sewing, validation | Stable |
| I/O | STEP import/export (analytic-preserving round-trip) | Stable |
| I/O | STL, 3MF, OBJ, PLY, glTF (.glb) import/export |
Stable |
| I/O | IGES import/export | Experimental |
| I/O | Sheet and wire bodies in arena documents; STEP sheet models | Experimental |
| Sketching | 2D constraint solver (DogLeg) | Stable |
| Feature Recognition | Holes, pockets, chamfers, fillets | Stable |
| Assemblies | Hierarchy, transforms, bill of materials | Stable |
| Evolution | Face provenance (booleans, blends, direct moves, offset, patterns, draft, defeature, split, shell) | Stable (declared coverage) |
| Defeaturing | Remove planar faces | Stable |
| Defeaturing | Curved rim-band removal | Partial |
| Rendering | Offscreen wgpu render to image plus face-id buffer (remus-render) |
Experimental |
A few areas are still maturing. Worth knowing before you build on them:
- Boolean fallback. Most booleans run on an exact path that preserves analytic and NURBS surfaces. Hard configurations may use a bounded mesh-based fallback, which tessellates curved faces. If its input/work budgets are exceeded or the welded result is open, non-manifold, or invalid, the operation returns an error instead of a partial solid. Bounded off-axis cone-sphere, sphere-cylinder, and torus-sphere configurations are now exact for fuse, cut, and intersect across three scales and rigid placement, but general quartic seam arrangements are not. Exact tangency and sliver crossings are the two contact configurations that still fall over to that path rather than being answered analytically.
- Walking fillet/chamfer and offset. The v2 modifier APIs validate completed topology and reject partial results. Unsupported/no-op trimming and offsetting a solid that already contains cavity shells return explicit errors; they do not silently drop faces or cavities. Radii the rolling ball cannot fit are refused as typed errors naming the edge and the limit, not delivered as a partial result. Constant-radius closed rims on cylinder/cone, cylinder/sphere, and cone/cone supports assemble; the cross-drilled cylinder/cylinder rim refuses rather than adding material on the wrong side, and correct-side assembly there is still unqualified.
- Torus booleans. Box-with-torus, coaxial-torus, plane-through-centre, and coaxial-cylinder cases give correct volumes; coaxial torus×cylinder / axis-centred torus×sphere sections are exact circles; a box notch partitions the torus into winding-correct annuli; and a bounded off-axis torus×sphere matrix is exact for fuse, cut, and intersect across three scales and two placements. Broader quartic torus pairs and tangent contacts are unqualified and resolve through the bounded mesh fallback, an oversized torus×sphere witness refuses on its march budget, and general torus-to-torus intersections have known gaps.
- Non-planar profiles. Loft, sweep, and pipe close non-planar section boundaries with bilinear (4-sided) or Coons (5-or-more-sided) caps whose boundary iso-curves are exactly the ring chords. Sweep and pipe also preserve disjoint rectangular iso-parametric holes on bilinear and Coons caps as single trimmed faces (B12 annular-Coons cell); off-surface, curved, touching/overlapping, and multi-span-straddling hole trims refuse typed. Loft profiles with holes now refuse instead of discarding their inner wires. Revolve accepts non-planar profile surfaces; a full revolution takes any boundary, and a partial revolution closes non-planar polygonal boundaries with the same caps (curved-edge non-planar boundaries and holes stay typed refusals). Only the miter-corner sweep variant still requires planar profiles (its bisector-plane joint faces would otherwise be non-planar).
- Evolution coverage. Face provenance is exact and construction-derived for booleans, the walking and planar blend builders, qualified direct face moves, the default offset builder, patterns, draft, defeature, plane split, and shell. Arc-joint and self-intersection-removal offsets and direct edits outside the qualified cells still journal as explicit barriers, and edge/vertex provenance beyond the boolean path is roadmap work.
- Sheet and wire bodies. Standalone sheets and wires are first-class bodies (RFC 0005) with declared bounds: a validated closed planar wire sweeps to a solid, planar sheets split and trim solids and each other, and trimmed NURBS sheets measure and tessellate. Open or non-planar wire profiles and configurations outside those cells refuse with typed errors.
- IGES is experimental. Export writes planar and NURBS surfaces but skips analytic surfaces and approximates circular and elliptical edges as polylines. Import reconstructs planar placeholder faces only. Use STEP for B-Rep exchange.
- Declared domains. Feature recognition claims only its declared feature set (holes, rectangular pockets, chamfers, curved fillet bands) — outside it, absence of a claim is the contract. Defeaturing removes features whose wound lies on planar kept faces (the removed feature itself may be curved); draft targets planar faces. Each refuses outside its domain by name.
The versioned WASM fillet/chamfer provenance payload and its strict decoder are documented in WASM face evolution.
Remus deliberately does not:
- Bundle a viewport into the kernel. The core emits exact geometry and tessellated meshes; camera, lighting, and shading belong to the caller (Three.js and the like). The optional
remus-rendercrate provides offscreen wgpu rendering with a face-id buffer, for tests and headless verification, and is not required by any core operation. - Plan toolpaths or slice. Export STEP, STL, or 3MF and pass the output to a CAM tool or slicer.
- Model with meshes. The kernel operates on exact B-Rep geometry. Subdivision surfaces, polygon meshes, and voxels are out of scope.
- Provide a GUI. Remus is a library. Building a UI around it is the application's job.
- Simulate physics. Measurement (volume, area, center of mass) is included. Stress analysis, collision detection, and dynamics are not.
Layered Cargo workspace. Each crate depends only on the same or lower layers,
and CI enforces the boundaries with scripts/check-boundaries.sh.
| Layer | Crate | What it does |
|---|---|---|
| L0 | remus-math |
Points, vectors, matrices, NURBS curves and surfaces, geometric predicates, CDT, convex hull, operation context, diagnostics |
| L1 | remus-geometry |
Curve sampling (uniform, deflection, arc-length, curvature), extrema, analytic-to-NURBS conversion |
| L1 | remus-topology |
Arena-allocated B-Rep: vertex, edge, coedge, loop, wire, face, shell, solid, with an edge-to-face adjacency index |
| L2 | remus-algo |
General Fuse boolean engine: pave filler, face classification, solid assembly |
| L2 | remus-blend |
Walking-based fillet and chamfer with constant, variable, and custom radius laws |
| L2 | remus-heal |
Shape healing: analysis, fixing, upgrading, sewing, tolerance management, configurable pipeline |
| L2 | remus-check |
Point classification, validation, properties (volume, area, center of mass), distance |
| L2 | remus-offset |
Solid offset and thickening via global face-face intersection |
| L2 | remus-sketch |
2D parametric constraint solver (GCS) using a DogLeg trust-region method |
| L3 | remus-operations |
Booleans, fillet, chamfer, extrude, revolve, sweep, loft, shell, offset, measure, tessellation |
| L3 | remus-io |
Import and export: STEP, IGES, STL, 3MF, OBJ, PLY, glTF |
| L4 | remus-wasm |
JavaScript API via wasm-bindgen, with batch execution, checkpoint/restore, and reproduction bundles |
| L4 | remus-wasm-io |
JavaScript file-format translators as a separate module; bodies cross to and from the kernel as exact arena documents |
| L4 | remus-render |
Offscreen wgpu rendering to a color image plus a face-id buffer. Optional, nothing depends on it |
| L5 | remus |
Native Rust facade: owned model session, explicit operation policy, curated modeling and I/O API |
The layer DAG is a program invariant: preserving it is a constraint on every change, and a violation fails both the pre-push hook and CI.
Median times from the brepjs benchmark suite (5 iterations, Node.js, Linux x86_64). WASM is single-threaded. Native benchmarks use criterion.
| Operation | Remus (WASM) | OCCT (WASM) | Speedup | Remus (native) |
|---|---|---|---|---|
| fuse(box, box) (×10) | 0.5 ms | 43.7 ms | 87x | 122 µs |
| cut(box, cylinder) (×10) | 28.3 ms | 64.3 ms | 2.3x | 9.3 ms |
| box + chamfer | 0.2 ms | 5.4 ms | 27x | 46 µs |
| box + fillet | 0.3 ms | 6.2 ms | 21x | 127 µs |
| multi-boolean (16 holes) | 4.7 ms | 30.1 ms | 6.4x | 2.8 ms |
| mesh sphere (tol=0.01) | 7.1 ms | 51.9 ms | 7.3x | 6.0 ms |
| exportSTEP (×10) | 0.9 ms | 14.3 ms | 16x | n/a |
Every quoted row is output-verified across both kernels before timing is
compared: fuse, chamfer, and sphere volumes match exactly; cut, fillet, and
multi-boolean volumes agree within 0.004%. The sphere mesh densities are
comparable at equal tolerance (9,800 triangles vs 10,176). The
intersect(box, sphere) row is excluded: the kernel currently keeps the wrong
sphere region for that configuration (an open, pinned defect), so its ~200x
timing would not be a like-for-like comparison.
Booleans preserve analytic surfaces, so face counts stay low across chained operations. A nine-step compound boolean settles at 72 faces while a mesh-based approach would reach roughly 7,000. The same holds for blends: a straight edge filleted between two planar faces keeps an exact cylindrical wall rather than a NURBS approximation of one.
The OCCT comparison uses occt-wasm, an OpenCASCADE build compiled to WebAssembly. Both kernels ran single-threaded in Node.js. Boolean and
exportSTEProws were timed as batches of ten operations. WASM figures are medians ofkernel-comparison.bench.test.ts(5 iterations) against a localcargo xtask wasm-buildpackage, hash-verified at the require path. Native figures came fromcargo bench -p remus-operations --bench cad_operations, except the mesh-sphere row, which usedcrates/operations/examples/perf_probe.rsat matching parameters. Measured 2026-08-06, before the Apache-only line was established; the upstream head-to-head harness is retired, so treat these figures as historical and do not quote them as current. Runscripts/bench-compare.shfor the maintained native Criterion baselines.
| Format | Type | Import | Export |
|---|---|---|---|
| STEP | B-Rep | ✓ | ✓ |
| STL | Mesh | ✓ | ✓ |
| 3MF | Mesh | ✓ | ✓ |
| OBJ | Mesh | ✓ | ✓ |
| PLY | Mesh | ✓ | ✓ |
glTF (.glb) |
Mesh | ✓ | ✓ |
| IGES | B-Rep | preview | lossy |
STEP preserves exact geometry on round-trip. Analytic surfaces (plane, cylinder, cone, sphere, torus) are written as native STEP surface entities rather than tessellated, and they read back to the same surface types. NURBS surfaces are preserved too, as are line, circle, ellipse, and NURBS edges.
Mesh formats export tessellated triangles. glTF is binary .glb, with no
materials or scene graph. IGES is experimental, as described in
Known Limitations.
In the browser, every format lives in the remus-wasm-io translator module
rather than the kernel package, so applications that never touch files do not
pay for the readers and writers. The kernel serialises bodies to exact arena
documents (serializeSolids) and the translator consumes those; imports flow
back through deserializeSolids.
All Rust importer entry points apply production defaults through
ImportLimits: 256 MiB encoded input, 256 MiB for the uncompressed 3MF model
XML entry, and 3,000,000 format-specific model entities. Use each format's
*_with_limits reader to choose stricter or application-specific budgets; the
WASM importers accept optional maxInputBytes / maxEntities arguments for
the same purpose. Limit violations return IoError::LimitExceeded before
avoidable large allocations. The WASM batch API separately limits JSON to
16 MiB and 10,000 operations.
Remus publishes nothing yet. No crates.io releases, no npm packages, no GitHub releases. Release ownership — named maintainers, package identity, vulnerability intake, signing and provenance, rollback and yank authority — has to be established first; the gate is documented in fork maintenance and release policy.
Two consequences worth stating plainly:
- A
remus-wasmpackage on npm does not come from this repository. It belongs to the historical upstream line, which is no longer permissively licensed. Installing it does not get you this kernel. - The checked-in
crates/wasm/pkg(kernel) andcrates/wasm-io/pkg(file-format translators) directories are frozen compatibility snapshots for an existing consumer that installs them by git path, pinned to one commit. They are not a release channel and not the way to adopt Remus.
Until packages exist, build from source.
[dependencies]
remus = { git = "https://github.com/esaueng/remus" }Pin a revision (rev = "...") for anything you intend to reproduce: no
first-party package has been published yet, and main moves.
The Remus versioning policy defines the
YYYY.RELEASE.PATCH numbers in source manifests and future releases. A version
in this repository does not imply that an artifact has been published.
MSRV is Rust 1.88, and CI holds that floor. Day-to-day development uses the
toolchain pinned in rust-toolchain.toml, which rustup picks up automatically
along with the wasm32-unknown-unknown target.
cargo build --workspace
cargo test --workspace
cargo clippy --all-targets -- -D warnings
cargo fmt --all
# WASM packages (kernel + file-format translators): dual-target build,
# merge, and validation
cargo xtask wasm-build
# Plain WASM builds: the kernel as shipped (no translators), the single-module
# kernel with translators bundled, and the translator module
cargo build -p remus-wasm --target wasm32-unknown-unknown --release --no-default-features
cargo build -p remus-wasm --target wasm32-unknown-unknown --release
cargo build -p remus-wasm-io --target wasm32-unknown-unknown --release
# API docs
cargo doc --workspace --no-deps --openRepository invariants have their own checks, all of which CI runs:
./scripts/check-boundaries.sh # layer dependency DAG
./scripts/check-doc-paths.sh # documented file paths still resolve
./scripts/check-apache-lineage.sh # no prohibited upstream lineage
python3 scripts/check-apache-replay-provenance.py # provenance ledger integrity| Where | What |
|---|---|
book/ |
Task-oriented guide: getting started, architecture, concepts, operation reference, tolerances, data exchange, WASM, rendering, troubleshooting |
docs/kernel-maturity/ |
The maturity contract (target, capability matrix, operation contract, failure taxonomy, testing strategy), the master roadmap and its supporting capability/adoption specifications |
docs/design/ |
RFCs and design research: operation context (0001), coedge architecture (0002), persistent naming (0003), tolerant modeling (0004), body taxonomy (0005), swept analytic surfaces (0006) |
docs/production-readiness/ |
Audit, stability matrix, coverage, release checklist, fork maintenance, Apache replay provenance |
AGENTS.md |
Working guide: module map, ripple-effect checklists, common pitfalls |
CHANGELOG.md |
Full history, including the pre-fork series |
Maintainers should use the production-readiness audit, stability matrix, and release checklist before cutting an artifact. The checklist is validation guidance and does not grant authority to publish.
The Remus master roadmap is the single source of truth for priorities, dependencies, implementation status and remaining work. It consolidates P-Class, Open Kernel, bridge work, stabilization residue and all 111 performance packages. Start with its current priorities and check in-flight PR ownership before selecting one bounded item.
Detailed specifications, design RFCs and source-pinned audits remain supporting references. The kernel maturity target, capability matrix and stability matrix continue to define correctness and public claims.
See CONTRIBUTING.md. Contributions are inbound under
Apache-2.0 and require a Developer Certificate of Origin sign-off. Commits are
conventional commits, enforced by commitlint; the pre-commit hook runs
cargo fmt and clippy, and CI gates the full test suite, the layer-boundary
check, and the license-lineage check on every push.
New regressions should land as reproduction bundles where the failure is expressible through the batch API — every discovered defect is meant to become a permanent, replayable regression.
Security reports: see SECURITY.md.
Remus continues a codebase whose upstream relicensed to AGPL at v3. This
repository is the permanent Apache-2.0 line of that work, maintained by
Esau Engineering. The last permissive upstream release is v2.129.15;
nothing from v3 or later is merged, and behavior from those releases enters
only under an explicit Apache-2.0 grant or as an independent implementation
proven by a regression test.
That boundary is enforced in CI and every replayed contribution is recorded in an auditable ledger — see Apache contribution provenance.
The project's use of AI tooling is disclosed in AI-DISCLOSURE-ETHICS.md.
Remus is licensed under the Apache License, Version 2.0, permanently — see Provenance for how the AGPL boundary with the historical upstream is enforced. Attribution is in NOTICE, and contributions come in under the same license (see CONTRIBUTING.md).