Skip to main content

Mesh export

All evaluated outputs can produce a mesh and shared mesh formats:
MeshData contains flat typed arrays:
Each consecutive three indices forms one triangle. A reflected assembly placement reverses triangle winding during mesh transformation so outward orientation remains coherent.

Tessellation options

Exact B-Rep output is tessellated on demand:
Options affect the extracted mesh, not the exact native shape. Manifold already is a mesh representation and may ignore B-Rep-specific controls.

STEP and BREP

Use OCCT:
Unsupported native formats throw CadError with an EXPORT_UNSUPPORTED diagnostic because export() is a direct operation on a live output. Select a compatible kernel before evaluation.

Deterministic single-product STEP

This strong contract is implemented for the unreleased 0.2 line. The current 0.1.1 npm package retains ordinary weak native STEP export.
The bundled zero-override createOcctKernel() stock runtime advertises the optional KERNEL_STEP_EXPORT_PROTOCOL_VERSION === 1 capability. This versioned capability is stronger than nativeExports containing "step": nativeExports says only that the format can be written. Inspect the kernel’s capability object—not the kernel itself—before relying on the stronger contract:
A "valid" result contains the strong immutable snapshot; "absent" means only weak STEP availability, while "malformed" means the advertised envelope is invalid. output.export("step") without a second argument remains compatible with weak native exporters; a supporting kernel uses deterministic defaults. Passing any options object, including {}, requests the strong contract; an absent or malformed stepExport envelope throws CadError with KERNEL_CAPABILITY_MISSING instead of silently ignoring the request. Explicit wasm, moduleFactory, and attestedRuntime initialization remains on weak raw STEP export even when the supplied artifact is derived from stock OCCT. InvariantCAD omits stepExport until that exact writer artifact has a separate qualification boundary. Pass deterministic metadata, cancellation, and a caller-specific output ceiling through the STEP-only overload:
Each metadata override is optional; every omitted field receives one of these closed automatic defaults. FILE_NAME uses the design document name and its timestamp is 1970-01-01T00:00:00. A solid output uses its output alias for both product ID and name, with an empty description. A part uses its authored part number when present, otherwise its part-node ID, as the product ID; its part-node ID is the product name, and its authored part description is the product description. An explicit timestamp must be a real calendar value in YYYY-MM-DDTHH:MM:SS form. It remains deterministic because it is caller-supplied input; changing it intentionally changes the bytes. The four identity/description values accept Unicode scalar text. Apostrophes use STEP’s doubled-apostrophe convention. Literal backslashes and non-ASCII scalars are encoded with ISO-10303-21 \X2\...\X0\ or \X4\...\X0\ directives as required. Control characters and unpaired UTF-16 surrogates are rejected. fileName, productId, and productName must be nonempty. Invalid option structure, metadata text, calendar values, or the advertised authored-metadata budget throw CadError with EXPORT_OPTIONS_INVALID. Its path is a JSON Pointer relative to the StepExportOptions input, such as /metadata/timestamp or /maxOutputBytes. An already-aborted valid signal still throws AbortError; low-level kernel.exportShape(...) calls retain their kernel-specific validation exceptions. Those defaults are a field-specific identity mapping, not a general metadata pass-through. Root document metadata, arbitrary part metadata, material identity, and the active configuration are omitted. A caller may explicitly override a semantically corresponding supported STEP field, but protocol v1 provides no arbitrary key/value metadata channel. It does not silently fold material data into the description. The stock writer emits one AP214IS product. InvariantCAD then applies a purpose-built structural ISO-10303-21 scanner and transformer to the exact FILE_NAME and PRODUCT string fields; it does not use an unbounded regular expression rewrite. The default output ceiling is 64 MiB and the combined metadata ceiling is 64 KiB measured over the five resolved strings as UTF-8. Part 21 escaping can expand that text; the expanded representation counts toward the 64 MiB output ceiling. Input traversal, scan work, and entity count also have fixed ceilings, and the scan checks cancellation. The underlying stock native writer is synchronous and necessarily materializes its original complete STEP string before InvariantCAD can apply post-write limits or observe cancellation again. Metadata shape, content, timestamp, and the authored UTF-8 budget are validated and encoded before that writer starts, so known-invalid metadata never triggers native serialization. The writer cannot be interrupted mid-call. After it returns, cancellation is checked before, during, and after bounded scanning and before successful return. maxOutputBytes limits the transformed bytes returned to the caller; it does not cap the native writer’s peak allocation or its original string. Isolate untrusted or potentially pathological native work in a disposable worker or process. Byte equality is guaranteed only for the same backend shape representation, options, resolved metadata, implementation, and exact runtime artifact. It does not claim that geometrically equivalent B-Reps serialize identically, make bytes portable as a cross-runtime cache identity, or canonicalize third-party STEP. Exact aggregate STEP for assemblies and body-set results remains unsupported; export retained single solid or part leaves explicitly.

Save in Node.js

Send from a web server

Dispose the evaluated design after the response body has copied or taken ownership of the returned detached bytes.

Verified single-body import

This public workflow is implemented for the unreleased 0.2 line. It is not present in the current invariantcad@0.1.1 npm package.
The public imported-body boundary deliberately covers one exact solid, not the broader staged product-document model:
createImportedBodyDocument(...) captures and validates the commitment but does not read, fetch, or hash the bytes. The caller computes the SHA-256 digest and exact byte length. locations are ordered hints passed to the resolver; InvariantCAD never interprets them as files, URLs, or package paths. The protocol-v1 media and unit policy is closed: The explicit format selects the native reader. mediaType is committed provenance and resolver context; it is never sniffed or used to infer the format. Healing is fixed to { mode: "none" }, and the strong kernel contract must produce exactly one valid positive-volume solid. Multiple solids, shells, loose topology, approximate conversion, and weak-import fallback are rejected. Persist only the opaque document facade:
Parsing uses the bounded, duplicate-member-rejecting document boundary and then admits only one resource, one imported-body node, and one direct solid output. It does not publish or accept the broader product Document v7 grammar. Evaluation requires an exact B-Rep evaluator with the strong document-body import capability and a caller-supplied resolver:
The resolver receives a frozen request containing the authored ID, digest, length, media type, location hints, and optional signal. Resolution, byte-length admission, and SHA-256 verification finish before importDocumentBody(...) runs. A successful EvaluatedImportedBody exposes exact B-Rep measurement, topology, tessellation, and capability-gated single-solid STEP/BREP export. Dispose that result independently; it owns the imported native shape but borrows the evaluator and kernel. This executable module creates an exact OCCT box, exports STEP entirely in memory, commits and canonically persists the one-body document, resolves the same bytes, imports them through the strong boundary, inspects measurement and topology, and re-exports deterministic STEP:
The release gate compiles and executes examples/docs/imported-body-round-trip.ts. This slice does not provide imported-body healing or repair, multiple-body selection, body sets, external components, assemblies, automatic location I/O, media-type inference, a public general Document v7 alias, or integration with the ordinary v6 design builder and evaluate(...). Those remain separate product milestones.

Browser download

Repository-only product-document staging

The ordinary v6 design builder still does not expose an imported-body or body-set feature node. The narrow public workflow above is separate from the repository-only broader product grammar. The repository contains stagedBodySetDesignV7(...), a source-only authoring facade for the exact graph admitted by the staged evaluators. This is executable Document v7 evidence, not an end-user product-document workflow: the package-root DesignDocument alias, ordinary builder/evaluator, and migration target remain on the frozen v6 model, and no package subpath exposes the facade. The public one-body facade does not make these broader types callable. The staged facade authors:
  • typed length, angle, mass-density, and scalar parameters, named parameter configurations, document-owned materials, typed part-material substitutions, and assembly-definition instance-suppression overrides;
  • direct boxes, cylinders, and spheres by privately composing the existing v6 builder;
  • owner-bound solid DAGs whose leaves are those primitives or imported bodies and whose internal nodes are ordered union(...), subtract(...), intersect(...), or transform operations, with typed translate(...), rotate(...), scale(...), and mirror(...) conveniences;
  • document-owned commitments with an explicit SHA-256 digest, byte length, media type, ordered location hints, and detached metadata;
  • owner-bound imported-body leaves for STEP with file units or text/binary BREP with an explicit mm, cm, m, or in length unit;
  • owner-bound body sets whose dense, non-empty ordered memberships reference facade-created primitive/import/Boolean/transform DAG roots;
  • owner-bound parts whose geometry is one staged solid DAG root or one admitted body set;
  • external-part handles that bind one named part output from a committed InvariantCAD document resource without publishing a local feature node;
  • external-assembly handles that bind one named assembly output from a committed InvariantCAD document resource without publishing a local feature node; and
  • acyclic nested fixed-placement product assemblies whose instances reference owned local parts, already-completed local assemblies, or either external handle and select inherited, base, or named child configuration contexts, plus outputs that directly target an imported body, body set, part, or staged product assembly.
Every imported node fixes healing to none and expects one solid. Its explicit format chooses the reader; committed mediaType is provenance and resolver context, not reader inference. The caller supplies the digest and byte-length commitments; the facade does not read or hash the resource bytes. Ordered resource locations are resolver hints only. Neither the facade nor the staged evaluators perform file, URL, or package I/O. Authoring methods validate namespaces, commitments, owner identity, material and configuration references, dense collections, and unique member IDs. Build applies caller-selected DesignDocumentLimits and strict v7 validation before returning detached, deeply frozen v7 data. Immediate authoring ceilings default to 10,000 resources, 100,000 aggregate location hints, and 16 MiB of aggregate UTF-8 location text. An individual body set is also rejected before copying above the default 1,000,000 structural-value ceiling. Caller-selected build limits can be stricter but cannot raise these immediate safeguards. Parameter, configuration, material, part, assembly-instance, placement, resource, import, unit-policy, and body-member options must be plain own-data records, and required collections must be dense. Accessor-backed and unknown fields are rejected without invocation or silent interpretation, and caller metadata is detached. The repository has four source-only staged geometry-evaluator slices:
  • A direct imported-body output admits bytes only through the caller-supplied resolver, verifies the declared byte length and SHA-256 digest, and invokes the kernel’s strong exact single-solid import contract.
  • A direct body-set output preserves authored member order, stable member IDs, optional names, and detached metadata. Every listed member is active and no member is treated as a primary body. Its solid reference may point to a box, cylinder, sphere, imported-body leaf, or a bounded Boolean/transform DAG rooted in those leaves. Shared graph nodes are evaluated once without collapsing authored memberships.
  • A direct part output preserves part metadata and effective material/density provenance while retaining an explicit single-solid or body-set geometry branch. Its geometry must be one supported solid DAG root or one body set admitted by the preceding slice. The staged facade authors exactly this part boundary through material(...), part(...), configuration .partMaterial(...), and direct part output(...).
  • A product-assembly output iteratively expands active local assemblies, resolves direct external-part outputs, and expands one fixed external subassembly boundary into its child-local part leaves. It preserves full root-to-leaf occurrence paths, root-relative placements composed parent first, and each part occurrence’s effective inherit, base, or named configuration context. Every containing assembly’s context controls that definition’s suppression and placement expressions, including explicit false unsuppression, before component admission. Active local and external leaves may use the same single-solid or multibody geometry admitted by the direct part slice, including verified imported leaves.

Document-scoped external resources

The staged product evaluator resolves external document JSON from the root document’s resource registry before resolving geometry resources declared by those children. Its resolver requests carry a frozen documentScope:
The root scope identifies commitments in the product document, including each external document. An external scope identifies the admitted child registry by the root resource ID and digest. Resolver implementations for this staged operation must use both the scope and request.id: two child documents may legitimately reuse the same document-local resource ID while resolving different committed bytes. Ordinary resolveResourcesV7(...) requests remain unscoped; documentScope belongs to this repository-only staged session, not a new public 0.1.1 resolver contract. Resolution is deterministic and two-phase. All selected external document commitments are preflighted and resolved before child assembly expansion or part preparation. Prepared child batches and kernel capabilities are then preflighted before any child geometry resource callback, and all child geometry bytes are admitted before document-body import callbacks run. Repeated (documentScope, resourceId) commitments reuse verified retained bytes; the same resource ID in a different scope remains distinct. Native primitive/Boolean/transform body sets can run on either exact or approximate kernels, and the result records the kernel representation as mesh, brep, or sdf together with its exactness claim. Stock OCCT constructs exact B-Rep geometry with partial Boolean history; a matched owned facade supplies complete bounded evolution for the current Boolean only when it proves the existing feature-scoped protocol. That promise cannot upgrade partial history already carried by an operand, and the result’s exact flag describes geometry rather than complete history. Manifold constructs approximate mesh geometry with no topology snapshots. Evaluation never falls back from one backend to the other. An imported member, including an imported leaf below Booleans or transforms, is different: the complete body set must use an exact brep kernel with strong single-solid document-body import support. Imported bytes cross the same verified-resource boundary as a direct imported-body output. There is no weak importShape(...) fallback and no automatic conversion to a mesh representation. Executable stock-OCCT evidence resolves a commitment-verified STEP box, subtracts a native tool, transforms the result, inspects partial topology, exports STEP, and restores the native ownership baseline. Separate real Manifold evidence evaluates configuration-sensitive native Boolean graphs through nested products, BOM, mass, suppression, limits, and complete cleanup. External-product OCCT evidence separately resolves a child document and its scoped STEP resource, evaluates an imported/translated/Boolean child part beside a native part through a nested local subassembly, reuses both exact child leaves across two fixed-subassembly occurrences, exports retained child solids as STEP, produces aggregate mesh/STL, and restores the native ownership baseline. The staged body-set result owns its distinct kernel shapes until disposal. Each member can produce a detached mesh and measurements. Topology and native single-body STEP/BREP export remain gated by the kernel’s separate capabilities. A shared leaf can be evaluated once without collapsing its distinct authored memberships; shared Boolean and transform nodes are memoized the same way. Aggregate tessellation preserves the authored member sequence, while aggregate STL and OBJ export are mesh-derived and therefore explicitly approximate/lossy even when the source bodies are exact. No exact aggregate STEP or BREP export is available: the evaluator does not fuse the bodies, invent a compound, or otherwise reinterpret the authored set. The selected kernel must advertise and implement boolean before resolver or shape work, and malformed optional exact-evolution metadata fails closed. A null or exactly zero-volume subtraction/intersection returns error-level EMPTY_RESULT; an impossible empty union or invalid measurement is a kernel protocol failure. There is no staged allowEmpty option. Failure releases every distinct acquired or intermediate shape exactly once. Success keeps those shapes live until the staged design is disposed; subsequent facade and per-body solid operations then fail deterministically. The supplied kernel is borrowed and is never disposed by this operation. The staged operation bounds selected outputs, caller parameter overrides, authored memberships, distinct primitive/import leaves, all solid-graph nodes, all Boolean target/tool and transform input edges, authored transform operations, documents, and resolved resources. Repeated Boolean tool references count as repeated edges. The solid-DAG ceilings are maxSolidGraphNodes, maxSolidDependencyLinks, and maxTransformOperations, each defaulting to 100,000; maxDistinctSolids separately counts leaves. Those admission limits do not bound mesh buffers created by later facade calls; applications handling hostile or very large tessellations still need a disposable worker or process and an application-owned output ceiling. For a direct part, a named configuration can replace the authored materialId. An explicit part density still overrides the effective material density, and a legacy material label or material name is never used as a catalogue lookup. Length and density parameters first resolve in the selected configuration and may then be specialized by bounded caller overrides. The one-row part BOM and physicalMassProperties() use one uniform effective density across all memberships. Mass is additive over independent bodies: repeated aliases and spatial overlaps each contribute once per authored membership rather than being fused or unioned. The numeric result inherits the selected backend’s measurement quality; a kernel capability marked exact is not a separate proof of mathematically exact floating-point mass. Part-level mesh() and STL/OBJ export are aggregate tessellation views and are therefore approximate/lossy. Exact native export remains a per-solid or per-body capability. Multibody parts do not expose aggregate geometric measurement, exact aggregate STEP/BREP, a cross-body topology namespace, interference subtraction, or primary-body inference. Bare body sets still have no aggregate mass contract; the part supplies the uniform-density semantics. For a product assembly, repeated part instances retain distinct full occurrence paths and BOM quantities. One local part result is reused for equal (part, effective configuration) contexts; one direct external-part result is reused for equal (resource, output, effective child configuration) contexts. Fixed-subassembly leaves reuse geometry by (resource, child part node, effective child configuration). Distinct external output aliases retain distinct component, diagnostic, and BOM identity even when they select the same child part or assembly and share the same evaluated geometry. Neither optimization is a cross-run cache or geometric-equivalence claim. Aggregate product mesh, binary/ASCII STL, and OBJ apply each root-relative occurrence placement and remain approximate/lossy. Exact native export remains available from a retained child solid when its kernel supports the requested format: the stock-OCCT product evidence exports the child as STEP. The product itself rejects STEP/BREP aggregate export with EXPORT_UNSUPPORTED; evaluation does not fuse child solids or invent a compound. The contextual BOM keeps unlike component/configuration states separate, while physical mass applies each effective density and placement before combining mass, center of mass, and inertia. A suppressed assembly edge prunes its entire subtree before descendant admission or work accounting. Traversal is bounded by maxAssemblyDepth, maxOccurrencePathSegments, scanned-instance, active-occurrence, placement, and downstream part/resource ceilings. Solid-graph nodes, all Boolean target/tool and transform input edges, and transform operations are counted globally by (node, effective configuration) across active occurrences: repeated occurrences in one context share the charge, while different contexts are independent. Repeated Boolean references still charge every authored edge. An active external part or fixed subassembly is evaluated only after its committed child document has been admitted. Child inherit maps parent base to child base or a parent named configuration to the same child ID; explicit base and named selectors target the child directly. Descendant selectors, suppression, and placement expressions are interpreted inside that child document. Root caller parameter overrides never flow into it. An external-part handle must select a direct part output, and an external-assembly handle must select a direct assembly output. The latter may expand child-local parts and nested local assemblies. Each active occurrence path may cross only that one external-document boundary: a suppressed nested external component is inert, while an active one is rejected before nested resolution or child geometry/kernel work. The facade cannot construct a local cycle because it accepts only already-completed same-builder local assembly handles; strict document admission and evaluation reject hand-authored recursive local graphs. The authoring facade, all four staged geometry-evaluator slices, and the kernel-independent datum resolver remain repository-only source work for 0.2: none is exported by the public 0.1.1 package root, available from a package subpath, or integrated with the public builder or CLI. The facade can author datum points, axes, planes, and coordinate systems, but they are resolved by selected node ID rather than published as design outputs or consumed by sketches or shape algebra. The facade authors direct external-part and external-assembly handles, but not a recursive external product graph. External part outputs and the local part leaves reached through one selected external assembly must still be admitted by the existing staged part evaluator; the product evaluator does not widen the child’s supported feature families. A migrated v6 part backed by an extrusion, for example, is rejected before geometry or scoped child-resource work. Cyclic local-assembly graphs, Boolean or transform inputs that are body sets, parts, or assemblies, other body-consuming operations, per-body materials, and general solid graphs beyond primitive/import/Boolean/transform DAGs remain unsupported. The facade cannot publish a direct primitive or a generic Boolean or transformed solid output either; generic solid geometry must be retained by a body set or part. The narrower imported-body handle remains the only directly publishable solid-like staged reference. The operations perform no location I/O and admit no healing beyond none. A resource’s mediaType is committed provenance passed to the resolver; it is not used to choose the reader or accepted as a substitute for the imported-body node’s explicit format. Assembly mates, motion, interference/collision, assembly-wide topology or geometric measurement, and exact aggregate STEP/BREP remain unsupported. The narrow public one-body facade applies the closed protocol-v1 format/media/unit table documented above; that policy does not promote this broader product grammar. There are deliberately two kernel boundaries:
  • nativeImports plus importShape(...) is weak exchange support. It may return any shape accepted by the backend.
  • documentBodyImport plus importDocumentBody(...) is the versioned strong boundary required by a canonical imported-body node.
Stock OCCT admits STEP only with { mode: "from-file" }. Text and binary BREP are unitless, so they require { mode: "declared", length: "mm" | "cm" | "m" | "in" }. Protocol v1 requires { healing: { mode: "none" } }.
This low-level call snapshots the supplied bytes but does not verify a document resource digest. Every staged evaluator that admits an imported leaf composes the existing resolver and strong importer: byte-length and SHA-256 admission completes before the imported parser is called. Missing resolvers, failed resolution, integrity mismatches, limits, cancellation, unsupported capability combinations, and kernel failures remain structured diagnostics. The strong importer requires exactly one valid, positive-volume solid with no loose topology and reports only partial imported history. It does not invent stable feature lineage or authored topology roles. Native STEP/BREP parsers can allocate or execute beyond JavaScript byte limits. Applications handling hostile files still need a disposable worker or process boundary; cooperative cancellation cannot preempt a synchronous native parser.

Exchange is not artifact caching

STL, OBJ, STEP, and BREP are interoperability formats. They do not preserve the complete evaluator wrapper state, topology evolution history, analytic overrides, or compatibility fingerprint needed for transparent feature-cache reuse. See design impact and hashes.