B-Rep Documents
The central design decision of the geometry kernel: a B-Rep solid is a JSON document — a string — not an object graph.
Why documents, not objects
- No aliasing, no invalidation. Every
Brep.*door parses the document on entry and returns a fresh document. The input is never mutated, so there is no stale-reference class of bugs and nothing to free. - Boundaries are explicit. Documents cross JS↔wasm, main↔worker, and disk unchanged.
JSON.stringify/parseis the whole serialization story. - Diffable and debuggable. A solid in your debugger or a test fixture is readable JSON, not a pointer.
The cost — parse per call — is deliberately paid at door time; the kernel works on its native structures inside.
Shell v2: four tables
The scene vocabulary type (@huukhanhnguyen/types) is four entity tables and nothing else:
type Shell = {
vertices: Vertex[]
edges: Edge[]
loops: Loop[]
faces: Face[]
}One Shell = one shell = one set of connected faces. There is no per-document version field and no root declaring "this is a solid" — solid-ness is derived (Brep.isClosed), never stored.
Version 1 spelled face boundaries with OCCT's words (wires / outerWire / innerWires) and carried a root. Nothing writes v1 anymore, and it is rejected at the door by assertBrepVersion2 — old documents must be regenerated, not upgraded.
One shell vs solid-root Brep
At the wasm boundary the document is a solid-root Brep: four tables plus version: 2 and a shells partition ({ faces: number[] }[]) grouping faces into connected shells. Scene entities stay one-shell Shell. Converters in @huukhanhnguyen/geometry move between the forms:
type Brep = {
version: 2
vertices: Vertex[]
edges: Edge[]
loops: Loop[]
faces: Face[]
shells: { faces: number[] }[]
}toKernelDocument(shell)— one scene shell →BrepJSON string (one shell spanning all faces).fromKernelDocument(document)—Brep→Shell[]. Multi-shell cavity solids come back as severalShellvalues.
Multi-body files
A STEP file can hold several solid bodies — that is a file-level fact, not a document-level one. Each body is its own document; readStepSolids returns string[], and readStep throws rather than picking one for you. See Import STEP and IGES.
What you do with documents
| Goal | Door |
|---|---|
| Build / edit | Brep.box, Brep.subtract, Brep.fillet, … |
| Measure | Brep.volume, Brep.surfaceArea |
| Inspect | Brep.isClosed, Brep.freeEdgeCount, Brep.entityCounts |
| Display | Brep.tessellate → TriangleMesh |
| Exchange | readStep/writeStep, writeStl, … via @huukhanhnguyen/io |
Where next
- Concepts: Memory model — documents vs arena handles.
- Guide: Create and measure solids.