@parametron/parametric/compute is the standalone compute substrate: pure geometry/value functions with no engine coupling — value in, value out, no registry, no Store, no node classes. It's the surface a node registry wires into NodeDefinition computes (/nodes does exactly that) and the surface another project reuses without adopting the default node catalog. Everything here is namespaced per domain module — method names are only unique within a domain (e.g. entity.reverse vs a different reverse elsewhere), so there is deliberately no flat re-export.
Import
import * as compute from "@parametron/parametric/compute"
compute.vector.add([1, 2, 3], [4, 5, 6]) // [5, 7, 9]
compute.curve.polyline([[0, 0, 0], [10, 0, 0]]) // CurveJSONor destructure just the domain namespaces you need from the same entry point (there's only one ./compute subpath — no per-domain subpaths):
import { curve, entity, solid } from "@parametron/parametric/compute"
curve.polyline([[0, 0, 0], [10, 0, 0]])This is exactly how packages/parametric/src/nodesRegistry/wiring.ts wires the stock catalog: import * as compute from "../compute.js", then tables like { curveEntity: compute.curve, faceEntity: { ...compute.face,
...compute.solid, ...compute.surface }, pointEntity: compute.point, vector:
compute.vector } map registry entity kinds to the domain that implements them.
Domain catalog
| domain | role |
|---|---|
axis | Axis.* expression namespace — a directed half-line { origin, direction }, direction always unit. |
curve | curveEntity producers (polyline, spline, arcs, bezier, rectangle, circle, polygon, textCurve, nurbsCurve), curve modifiers (split/fillet/chamfer), 2D boolean modifiers (curveUnion/Subtract/Intersect, curveSelfUnionImpl), and the Curve.* computation namespace (length, pointAt, tangentAt, divide, …). |
entities | Whole-stream generators/modifiers: clone, entities (literal → renderable), placeModel, and the array/mirror family (arrayLinear, arrayDistances, arrayRadial, arrayCurve, mirror). |
entity | Per-entity modifiers (1 EntityJSON → 1 EntityJSON): move/rotate/flip/reverse, immutable property setters (material/layer/visible/name), plus whole-array resize/solidSelfUnion/curveSelfUnion/flatten. |
face | The face geometry model ({ loops, uvMatrix }), the 2D boolean/offset kernel bridge (PolyShape), fill, faceOffset, coplanarGroups. |
faceValue | Face.* computation namespace — pure value math over a face's geometry: area, normal, centroid, contains. |
font | opentype.js wrapper: parse, textClean (text → boolean-unioned Shape2d[]), fallback-font registry (setFallbackFont/getFallbackFont). |
group | bakeGroup only — explode a groupEntity placement into flat, independently-transformed leaf entities. |
parameter | Parameter (value-node) converters: number/length/area/volume/mass/currency/angle/boolean/string/text/color/fn/font/group/model/object — raw evaluated value → typed JSON. |
plane | Plane.* expression namespace — { point, normal } plus signed distance. |
point | Point.* computation namespace (distance, midpoint, interpolate, translate) plus the pointEntity generator (Point3D[] → PointJSON[] markers). |
render | render only — EntityJSON → SceneEntity (curve polyline / triangulated mesh / point); throws if it's handed an un-baked groupEntity. |
solid | Face[] topology: the mesh bridge (facesToPolygonMesh/facesToMesh/meshToFaces/nurbsToFaces), extrude/curveFill, 3D CSG (solidUnion/solidSubtract/solidIntersect), faceExtrude/edgeFillet/edgeChamfer/faceLattice, and markWholeArray. |
surface | Curved generators — loft/revolve/patchFromCurve/patchFromCorners build a kernel NurbsSurface, then tessellate to Face[] (a NURBS surface is not a scene entity). |
surfaceValue | Surface.* computation namespace over a NurbsSurfaceJSON value: pointAt, normalAt, curvature, area, isocurve. |
vector | Vector.* expression namespace: length, normalize, dot, cross, angle, add, subtract, scale, between. |
Every scene entity the graph ever holds is a Point, Curve, or Face (a solid is Face[]) — see Model & pull graph for the entity JSON shapes and Entity API for the full per-entity method table these domains implement.
Value math vs entity generators
Two shapes recur across the domain table:
- Value namespaces (
Point.*,Vector.*,Curve.*,Plane.*,Axis.*,Face.*,Surface.*) compute a VALUE from a value —axis,plane,vector,faceValue, andsurfaceValueare pure math with no entity wrapper at all. These are what expression strings call (Vector.cross(a, b)). - Entity producers/modifiers (
curve,face,solid,surface,point'spointEntity) build or transform renderable{ id, geometry, … }JSON.curve/face/surfaceoverlap:curveandfaceValueboth read geometry a producer incurve/facebuilt.
import * as compute from "@parametron/parametric/compute"
const curve = compute.curve.polyline([[0, 0, 0], [10, 0, 0], [10, 10, 0]])
compute.curve.length(curve) // > 0
compute.curve.pointAt(curve, 0) // === startPoint(curve)
compute.curve.divide(curve, 4) // 5 points, evenly spaced by parameterWhole-array modifiers
Some ops need the parent's entire output array at once — hole detection (extrude/curveFill's groupLoopsByArea), coplanar grouping (curveOffset/curveThicken/arrayLinear), or n→1 reduction (solidSelfUnion/curveSelfUnion). These are branded with solid.ts's markWholeArray(fn), which stamps fn.wholeArray = true so the engine passes the whole array in one call instead of mapping per-entity. Whole-array exports across the domains: entities.arrayLinear/arrayDistances/arrayRadial/ arrayCurve/mirror, entity.resize/solidSelfUnion/curveSelfUnion/ flatten, curve.curveOffset/curveThicken, solid.extrude/curveFill/ solidUnion/solidSubtract/solidIntersect/faceExtrude/edgeFillet/ edgeChamfer/faceLattice.
Immutability
Compute never mutates its input — per-step caches key on identity. Every modifier returns a new object ({ ...entity, geometry: … }, a fresh FaceJSON/CurveJSON from wrap()) rather than editing the argument in place; entity.transformEntity and friends always build a new geometry array. This is what lets the graph's per-node cache key a step's cached result on its input's identity — mutating an entity in place would silently invalidate every downstream cache keyed on that identity without the graph ever seeing a change. bakeGroup/clone/array modifiers additionally give every emitted copy a fresh id (entityId() / refreshIds) so instanced/cloned geometry never collides in the scene.
The kernel boundary
Curve, face-boolean, and solid-topology domains are thin JSON ⇄ @huukhanhnguyen/shapemetry adapters: curve.ts wraps NurbsCurve, face.ts bridges a face's { loops, uvMatrix } to a 2D PolyShape for booleans/offsets, solid.ts bridges Face[] to a PolygonMesh/half-edge Mesh for CSG and edge ops (facesToPolygonMesh is the cheap render-tessellation tier; facesToMesh/toMesh() is the expensive weld+half-edge promotion topology ops need), and surface.ts builds a kernel NurbsSurface then tessellates to Face[] — NURBS/half-edge mesh are internal kernel concepts, never a scene entity. The graph only ever holds Point/Curve/Face.
See also
- Node catalog — wires these functions to
OperationDefinition.compute/create. - Entity API — per-entity method reference (SSOT).
- Model authoring reference — the authoring guide for the methods these domains implement.
- Render contract — how
render()'s output andbakeGroup's flattened leaves reach a renderer. - Model & pull graph — the
EntityJSON/CurveJSON/FaceJSON/PointJSONshapes these functions consume and produce.