Engineering / 2026-05-20

Why We Wrote a CAD Kernel in Rust

Building a new CAD startup in 2025 and not using OpenCascade was treated like building a new database in 2010 and not using MySQL. Everyone assumed you would lose. We did not. solidSF runs on a custom Rust kernel with a half-edge B-rep, NURBS and analytic surfaces, exact booleans, Euler operators, and a Gauss-Newton solver, written from scratch with zero C++ geometry dependencies. This is the case for why we did it, what the architecture looks like, where we got things wrong, and what we are going to open-source.

The state of the art before us

If you start a CAD company today, three kernels are normally on the table. None of them are great.

OpenCascade. Around 1.4 million lines of C++, descended from Matra Datavision's 1990s codebase. It is the only mature open-source B-rep kernel and that fact alone has kept it in business for thirty years. The license (LGPL with a custom exception) is workable. The reality of using it is not. OpenCascade's boolean operations are famously brittle on real-world inputs; you can find dozens of public issue threads where boolean fuse on two seemingly trivial solids returns invalid topology. Compile times are measured in tens of minutes. The API has the layered ergonomics of every C++ codebase that has been continuously developed since 1993. Compiling to WASM works but produces a 30-40 MB binary before you have done anything with it, and the runtime carries the memory-management style of code written before smart pointers.

Parasolid. Siemens' proprietary kernel. Used by SolidWorks, NX, Solid Edge, Onshape, and most of the industry's commercial CAD. It is genuinely excellent. It is also closed source, license-encumbered to the point of absurdity for a startup, and its terms forbid running it inside a browser or shipping it to end-user devices. For a browser CAD product, Parasolid is not an option in any direction. You can rent compute time on Parasolid (Siemens calls it "Parasolid Communicator") but you cannot deploy it client-side.

CGAL. A mature research library. Brilliant computational geometry, real numerics, exact arithmetic options. Not a B-rep kernel in the CAD sense. You can build a kernel on top of CGAL, and people have, but you are still building the kernel; CGAL is a substrate, not a product.

There is also a long tail of research kernels: OCCT forks, Mayo, Truck (Rust), fornjot (Rust), libcork, Cinolib, and dozens of academic projects. We learned from all of them. None of them are ready to ship a commercial CAD product on. We tried.

So if you are starting a CAD company in 2025, the dependency reality is: lean on OpenCascade and inherit its baggage, license Parasolid and limit yourself to non-browser deployment, or write your own. The first two roads lead to the same products that already exist. Only the third lets you build something different.

What we wanted from a kernel

Before we wrote a line of code, we wrote down what the kernel had to be. This list became our acceptance criteria, and it ruled out OpenCascade and Parasolid quickly.

OpenCascade fails most of these. Parasolid fails the browser, scriptability, and open-source requirements outright. So we wrote our own.

Why Rust

The language choice was not romantic. We picked Rust because every other option was worse for this specific job.

Memory safety without a garbage collector. A CAD kernel allocates millions of small topology objects (half-edges, loops, faces, shells) and deallocates them in bursts when features get rolled back or invalidated. A GC would either pause the viewport at exactly the wrong moments or force us to architect around the GC, which means we are programming around the runtime instead of the problem. Rust's ownership model gives us deterministic allocation patterns and arena-based memory management with no GC pauses, and the borrow checker catches the entire class of double-free and use-after-free bugs at compile time.

Fearless concurrency. Rust's type system prevents data races at compile time. For a kernel that wants to parallelize boolean operations across multiple solids, run the sketch solver concurrently with topology updates, and stream tessellation tasks to a thread pool, this is not a convenience, it is a structural feature. The amount of debugging time we have saved by not chasing race conditions is enormous.

WASM as a first-class target. Rust's WASM toolchain (wasm-bindgen, wasm-pack, wasi-sdk) is the best in the industry. We compile to wasm32-unknown-unknown for browser, wasm32-wasi for sandboxed server execution, and x86_64-unknown-linux-gnu for our backend native pipeline, from the same source tree with the same code paths.

The type system. A B-rep kernel has dozens of subtle invariants: every half-edge has a twin, every face has at least one outer loop, every loop is oriented consistently, every shell is closed or marked open. We encode many of these as types. The kernel will not compile if you build a topology that violates the invariants we have encoded.

The ecosystem. nalgebra for linear algebra. rayon for parallelism. serde for serialization. thiserror for error handling. parry3d for collision primitives. Cargo for builds. Crates.io for distribution. Every piece is honest, well-maintained, and free of the LGPL-with-exceptions tangle that surrounds OpenCascade.

Architecture overview

The kernel is split into a small number of focused crates. The split is deliberate: each crate has a clear interface, an owned area of responsibility, and a path to open-source independently of the others.

+----------------------------------------------------+ | solidsf-workspace (browser) | +----------------------------------------------------+ | solidsf-kernel (feature tree, history, params) | +----------------------------------------------------+ | solidsf-features (extrude, sweep, fillet, etc.) | +----------------------------------------------------+ | solidsf-bool (booleans, healing) | +----------------------------------------------------+ | solidsf-topo (half-edge B-rep, Euler ops) | +----------------------------------------------------+ | solidsf-geom (NURBS, analytic surfaces, curves) | +----------------------------------------------------+ | solidsf-sketch (constraint solver, Gauss-Newton) | +----------------------------------------------------+ | solidsf-tess (tessellation, edge silhouettes) | +----------------------------------------------------+ | solidsf-step (STEP AP203/AP214, STL, OBJ, 3MF) | +----------------------------------------------------+

solidsf-geom holds the math: NURBS curves and surfaces, analytic primitives (plane, cylinder, cone, sphere, torus), curve-curve and surface-surface intersection routines, evaluators, derivatives, and projection. It is the only crate that talks to nalgebra directly and is the most numerically delicate.

solidsf-topo holds the topology: a half-edge data structure with arena-backed allocation, Euler operators (MEL, MEKL, KEMR, and friends), validity invariants, and traversal primitives. This crate has zero geometric reasoning; it manipulates connectivity only. That split is what lets us test booleans without dragging in NURBS bugs and vice versa.

solidsf-sketch is the 2D constraint solver: distance, angle, parallel, perpendicular, tangent, coincident, equal, and the rest of the standard SolidWorks-style constraint set, with Gauss-Newton over the residuals and a Levenberg-Marquardt fallback for ill-conditioned systems.

solidsf-bool is the booleans, which is the part everyone gets wrong. We use exact predicates for orientation tests and an exact-then-numeric strategy for surface-surface intersection in the boolean path, with topology healing on the output. More on this below.

solidsf-features is the parametric feature layer: extrude, revolve, sweep, loft, fillet, chamfer, shell, draft, rib, hole wizard, sheet metal, patterns, mirror, helix, flex, wrap, scale, combine, SDF booleans, and TPMS lattice. Each feature consumes the lower crates and produces a topology delta.

solidsf-kernel wraps the feature tree, history, parameter graph, rollback, and named-element tracking. This is where "the part you see in the workspace" lives.

solidsf-tess tessellates surfaces for rendering, computes silhouettes for edge rendering, and produces meshes for export. It can target a CPU thread pool or push work to WebGPU compute.

solidsf-step reads and writes STEP AP203 and AP214, with healing, plus STL, OBJ, PLY, and 3MF.

Where it runs

The same source tree compiles to three targets. None of the kernel code is target-specific; the difference is at the edges.

TargetTripleUsed for
Browser (WASM)wasm32-unknown-unknownThe live workspace at solidsf.com. Kernel runs in the page, threaded via SharedArrayBuffer.
Server (native)x86_64-unknown-linux-gnuHeadless model edits, API endpoints, batch jobs, agent tool execution.
GPU (future)CUDA via cust / WebGPU computeHeavy tessellation, SDF lattice evaluation, parallel boolean reduction.

WebGPU compute work is currently scoped to tessellation and SDF-style ops where the GPU advantage is unambiguous. We are deliberately not trying to put the entire B-rep on the GPU; that is a research project, not a 2026 product.

The boolean ops problem

Every CAD kernel author knows that boolean operations are the part that breaks. You give two solids to a boolean fuse, you expect one solid back, and what comes back is sometimes garbage. Sometimes it is invalid topology that crashes downstream features. Sometimes it is silently wrong, which is worse. OpenCascade's bug tracker has hundreds of boolean failure tickets and they are not new tickets.

The reason is that boolean operations sit on top of two of the hardest problems in computational geometry: robust surface-surface intersection and robust topology construction from intersection curves. Surface-surface intersection of two general NURBS surfaces produces curves that, in exact arithmetic, may share endpoints with existing edges of the solids. In floating-point arithmetic, those endpoints are "near" the existing edges but not "at" them, and "near" is exactly where every numeric algorithm breaks. You can use thicker tolerances and the result becomes geometrically wrong. You can use exact predicates and the result becomes slow. The right answer is a layered strategy: exact arithmetic for orientation and incidence tests, interval arithmetic for filtering, and adaptive numeric refinement for surface intersections, with a topology-healing pass that fixes near-degeneracies before they propagate.

We implement that. We are not claiming a research breakthrough; the techniques are in the literature. What we are claiming is that we built the whole stack from the start with the assumption that booleans are the hardest part, and we designed the topology and geometry layers around making robust booleans expressible. OpenCascade was built before that lesson was fully internalized in the field; the modern Rust kernels are being built with it as a starting assumption.

Our current boolean test suite has thousands of generated pairs and a handful of dozens of real-world parts that broke other kernels we tested. It does not fail on those parts. It is not finished; new failure modes will keep appearing as customers throw real geometry at it. But the architecture admits fixes instead of requiring deep surgery, which was the OpenCascade pattern.

Performance — early signals

We will publish a full benchmark suite with the open-source release of solidsf-geom and solidsf-step. Rough numbers from internal measurements, all on an M3 MacBook Pro running the kernel as WASM in Chrome, against the same hardware running the comparison kernel natively where applicable:

The honest summary today: we are competitive on import and tessellation, ahead on robustness, and not yet a runaway leader on raw boolean throughput. We will publish full benchmarks with reproducible scripts when we open-source the relevant crates.

What we got wrong

The honest section. Three things, on the record.

1. The first sketch solver was too clever. We started with a graph-based geometric reasoner that tried to identify the constraint subsystem topology before solving. It produced beautiful diagrams and very fragile code. After six weeks we ripped it out and replaced it with straight Gauss-Newton plus Levenberg-Marquardt over the residuals. It is faster, simpler, more robust, and the entire solver crate dropped by about 40 percent. Lesson: in CAD math, simple beats clever, and Newton-style methods are simple for a reason.

2. We tried to use traits to enforce topology invariants. The first version of solidsf-topo encoded "this half-edge has a twin" as a trait bound. It compiled. It was unreadable. We ended up needing so many phantom types and lifetime parameters that the API became unusable from the rest of the kernel. We switched to runtime-checked invariants with debug assertions and made the code 3x shorter. Lesson: types are a tool, not a goal.

3. We over-invested in incremental topology updates too early. We built sophisticated machinery for "given a topology and a small change, mutate in place." It worked, but the surface area for bugs was enormous and the cases where it actually mattered for performance were rare. For most features, we now rebuild affected subtrees from scratch. The code is shorter, the bugs are fewer, and the user does not perceive the difference. Incremental updates are a tool we reach for in specific hot paths now, not the default.

What's next

The plan for the rest of 2026 is concrete.

The kernel crates we keep proprietary for now are solidsf-topo, solidsf-bool, solidsf-features, and solidsf-kernel. Those are the parts that differentiate the product. The math primitives, the solver, the file I/O, and the tessellator are best given back to the community, and we plan to.

If you want to work on this

We are hiring engineers who want to write Rust against a real CAD kernel for a living. If your idea of a good day is debugging a degenerate NURBS intersection, please apply at jobs.solidsf.com. Particular interest in people with backgrounds in computational geometry, numerical analysis, GPU compute, or production B-rep work.

If you are not looking for a job but want to work with the kernel as a partner, the agent tool API is already public via the workspace, and we will be opening more of it through the partner program. Email partner@solidsf.com.

FAQ

Why not use OpenCascade?
OpenCascade is around 1.4 million lines of legacy C++. It compiles to WASM but the resulting binary is heavy, the API has decades of accumulated state, and the boolean ops are famously fragile on real-world inputs. We needed deterministic, GPU-aware, memory-safe code, and that case is hard to make on top of OpenCascade.
Why not Parasolid?
Parasolid is closed-source and licensed by Siemens. You pay per seat plus a percentage. The license forbids running it inside a browser or distributing the binary to end-users. For a browser-native product, Parasolid is structurally impossible.
Is the kernel open source?
Not yet, but the plan is to open-source selected crates incrementally: geometry primitives, the sketch solver, STEP I/O, and the tessellator. The full kernel including booleans and feature replay will stay proprietary while it differentiates the product.
How does it compare to Truck or fornjot?
Truck and fornjot are excellent Rust CAD experiments and we have learned from both. They are research-grade or partial. Our kernel covers parametric modeling, exact booleans, NURBS, drawings, CAM, and import/export end-to-end, with 1,900+ tests against real production parts.
Can I write code against the kernel today?
Yes through the agent tool surface (55 registered operations) and through the workspace scripting console. A formal partner API for the kernel itself is on the roadmap. Email partner@solidsf.com if you have a use case.
Open the workspace Engineering jobs solidSF is browser CAD with a custom Rust kernel and native AI agents.