Zenve3DZenve3D
Join the beta
All posts
Engineering

Choosing a geometry kernel (and why we didn't write our own)

Commercial kernels behind licensing walls, promising-but-incomplete newcomers, and the one open-source B-rep kernel that compiles for an iPad. How Zenve3D picked OpenCASCADE — and what got built around it.

Zenve3D TeamJul 24, 2026 · 6 min read
Matte grey block with a cylindrical bore, its lower half dissolving into a blue wireframe boundary representation

The geometry kernel is the one decision in a CAD app you don't get to revisit. It's the code that represents solids exactly — faces, edges, the boolean operations that cut and join them — and everything else in the app ends up shaped around it. A serious B-rep kernel is decades of accumulated numerical robustness work; Parasolid and ACIS have been in development since the 1980s, and they're still fixing edge cases.

So before writing any product code, Zenve3D had to answer: buy, adopt, or build?

The field

Commercial kernels were out first. Parasolid — the kernel inside Fusion 360's ancestors, Solid Edge, Onshape — is excellent and priced for companies that already have revenue. Licensing walls, per-seat economics, and terms that don't fit "indie app on an iPad" ended that conversation quickly.

Writing our own was out second, and it's worth being honest about why: a from-scratch kernel is the classic way ambitious CAD projects die. The core data structures are a semester of work; making booleans robust against the geometry real users draw is a decade. Every hour spent there is an hour not spent on the actual product bet — that precision parametric CAD can feel native on a touch screen.

The Rust newcomers — truck, Fornjot — are genuinely interesting and genuinely incomplete. No fillets, partial booleans, no STEP. Betting the app on a kernel that might grow the features we need was the same trap as writing one, with extra steps.

That leaves OpenCASCADE (OCCT) — the only serious open-source B-rep kernel. Extrude, revolve, booleans, fillets, STEP and STL, an LGPL license, and — the make-or-break question for this product — it cross-compiles for iOS arm64.

The kernel picks your language

Choosing OCCT decided more than geometry: OCCT is C++, so the engine is C++. A forced move, embraced — because C++ is also the one language that compiles in-process on every platform we care about: iPad, Mac, Windows someday, WebAssembly for a future web client. Swift doesn't reach Windows or the web; Rust would spend its life wrapping a giant C++ kernel through FFI.

So the app is split in two: one portable C++ engine holding all the brains — the document model, the rebuild engine, expressions, serialization, OCCT, the sketch solver — and thin native client shells that do rendering and input, nothing more. The SwiftUI client covers iPad and Mac from one codebase; a web client later speaks the same protocol via WASM. It's the Shapr3D playbook, and it means everything subtle and hard to get right twice exists exactly once.

In-process matters as much as portable. There's no server and no IPC: calling the kernel is a function call, which is what keeps drag-to-solve running at frame rate.

The kernel is quarantined

Adopting a 25-year-old kernel without letting it colonize the codebase took a rule with teeth: OCCT types never cross the engine's boundary. The façade the clients see is plain C — opaque IDs, flat structs, typed errors. The engine tessellates and hands out mesh buffers; a client never walks B-rep topology. Even inside the engine, OCCT's booleans sit behind their own internal seam, and the solver behind another.

That quarantine pays in ways that have nothing to do with taste. The engine compiles headless on Linux, so CI replays command scripts and asserts on the resulting geometry — no device, no simulator. And kernel failures become states instead of crashes: a feature that fails is marked failed in the timeline, downstream features are blocked, and you fix it and rebuild. A kernel error must never take the app down.

One consequence surprised us: the engine contains no filesystem code — a WASM build has no filesystem — and OCCT's STL writer takes a file path. So Zenve3D's STL export is hand-rolled: 84 header bytes, 50 per triangle, streamed out through the same byte-oriented door as everything else. When STEP export shipped recently, OCCT's newer stream APIs meant the boundary cost nothing that time.

The solver is its own choice

A geometry kernel doesn't solve sketches — the 2D constraint solver is a separate decision. Zenve3D uses libslvs, the solver extracted from SolveSpace: battle-tested, a small C library, and fast enough for 60 fps drag-solve on Apple Silicon. It's vendored with a handful of small patches, including an allocation-arena change that cut a heavy benchmark sketch from 322 ms to 67 ms. (How the solver works is its own post.)

The week of CMake hell that wasn't

The riskiest assumption — "OCCT actually builds for an iPad" — got its own spike before any product code, budgeted at a week of cross-compilation misery. It cost hours. OCCT 7.9.3 cross-compiles for iOS arm64 with no patches, provided you switch every optional dependency off: no Tcl/Tk, no FreeType, no TBB, no VTK, no OpenGL. The build needs nothing but a toolchain, and OCCT is pruned to the modeling modules — its visualization stack is excluded entirely, because the client renders.

The binary-size worry was unfounded too. Statically linked OCCT is 71 MB per slice as a library, but the linker dead-strips everything the app doesn't reach: the release device binary is 4.7 MB.

The build needs nothing but a toolchain — and the "tens of megabytes" worry ended at 4.7 MB.

What we actually built

So no, Zenve3D didn't write a kernel — it wrote everything a kernel doesn't give you, which turns out to be most of a CAD app: the document-as-recipe model where geometry is just a cached output of replaying your history; the persistent-reference layer that keeps "the face you meant" meaningful across rebuilds; the expression system with units and cycle detection; the serialization format; the constraint-solving UX. The kernel computes solids. Deciding which solids, when, and what they mean is the product.

That's the real answer to build-versus-buy in CAD: buy the twenty years of boolean robustness, and spend your own years where no kernel can help you.

Geometry kernelC++Architecture
Keep reading

Try it yourself in the beta.

Zenve3D is free during the beta on macOS and iPad.

Join the beta