Mesh export
All evaluated outputs can produce a mesh and shared mesh formats:MeshData contains flat typed arrays:
Tessellation options
Exact B-Rep output is tessellated on demand:STEP and BREP
Use OCCT: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.
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:
"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:
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
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.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:
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:
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 containsstagedBodySetDesignV7(...), 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 typedtranslate(...),rotate(...),scale(...), andmirror(...)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, orinlength 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.
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 partoutput(...). - 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 explicitfalseunsuppression, 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 frozendocumentScope:
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:
nativeImportsplusimportShape(...)is weak exchange support. It may return any shape accepted by the backend.documentBodyImportplusimportDocumentBody(...)is the versioned strong boundary required by a canonical imported-body node.
{ 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" } }.