Skip to content

CAD text language: advanced reference ​

For new solid parts, start with the modeling API quickstart and complete cut/chamfer guide. cad.model() provides the primary sketch → Solid → parameter edit → save/load path without public version selection. The text compiler below is a separate advanced interface; the preserved Source0–3 workflow page is a historical source-pinned reference.

The CAD language describes native rational B-spline geometry and bounded construction intent. It is data for compileCadModel, not browser CSS. Use the selected source dialect explicitly. All dialects produce native Model version 0 in millimetres. The text language does not yet express every implemented CAD operation. Sketch constraints, qualified Solids, Solid Boolean operations and chamfer belong to separate APIs or bounded authored JSON documents; adding an engine operation does not automatically add grammar.

Compile and evaluate examples · Open the CAD playground · Compiler API

What can the model language express today? ​

The current modeling API covers convex line sketches, positive +Z extrusion, one X/Y through-slab cut and one cardinal component-edge chamfer. Use withParameters, save() and cad.load() for that bounded workflow; see supported inputs and refusals. It does not add declarations to this text grammar.

The following is the historical text/native-interface coverage table. The Source0–3 grammar/execution coverage remains pinned to 0c9aa7e159d3713a70a4b67631715e027da28fef; the separately versioned JSON/API rows include the newer adopted v2 serial-part profile. Source dialect versions, native Model versions and JSON document versions are separate contracts, even when their numbers match. The native capability map gives each Solid operation's exact input limits and evidence.

TaskCAD textAdvanced/native or historical consumption path
Rational B-spline CurveSource0/1/2/3 @curveNative Curve APIs
NURBS Surface (literal in Source0; expressions in Source2/3)Source0/2/3 @surface; not Source1Native Surface APIs
Translate a Curve into an open SurfaceSource1/2/3 @extrudeCurve → Surface construction; no caps or Solid
Typed length/scalar Parameters and arithmeticSource2/3 @parameterResolved quantities and dependencies in IR; complete source recompile
Reusable numeric calculationsSource3 @function, named argumentsPure length/scalar returns only; no geometry returns, loops or branches
Constrained XY sketch → qualified convex prismNo Sketch, constraint or Solid declarationbuildXYAffineSketch → buildXYAffineSketchPrism; bounded JSON feature-document recipes
Plane split and convex intersectionNo text declarationQualified native Solid APIs; complete context and exact admitted inputs required
Through-slab subtractionNo text declarationNative API or authored feature-document v0/v1/v2 subtraction recipe
One original-edge chamferNo text declarationNative API; optional v1 feature-document chamfer on the original prism, sibling to subtraction
Serial cut-component chamferNo text declarationAuthored v2 part: explicit coordinate-span prisms, actual second subtraction component, mandatory chamfer; no automatic migration
Solid mass propertiesNo text declarationDerived numerical query on a qualified Solid, not an authoring feature
Trimmed Solid display meshNo text declarationDerived display output with lineage, not replacement native geometry

For compatibility, see the historical API/JSON workflow for sketch → prism → slab cut → parameter edit → serialize/reopen. That executed recipe keeps its own tested source pin. Its separate chamfer is on the uncut prism, not on a generated cut-part edge.

For older saved serial-part files, use the historical serial-part v2 JSON and concise API guide. Its engine version does not add a Source4 grammar or a textual Solid declaration.

There is no supported automatic conversion from those Solid feature recipes into this text language. A future feature-IR bridge or new language syntax needs its own versioned contract and implementation; this manual does not present proposed syntax as executable.

Practice complete CAD inputs ​

For this advanced text interface, use four complete Source0–3 programs, measured outputs, parameter edits and exact diagnostics. These downloadable inputs are checked against the adopted compiler independently of the historical interactive gallery pins.

The CAD language practice examples add typed weighted Surface and curved extrusion programs, plus a rational Curve with original U domain [2,7]. Each includes an editable input, expected native values and an actual output image.

Choose a source dialect ​

Source dialectAdmitted declarationsNumeric fieldsReturned IR
0@curve, @surfaceFinite signed decimal literalsschemaVersion 1,sourceVersion 0
1@curve, @extrudeFinite signed decimal literalsschemaVersion 1,sourceVersion 1
2@curve, @surface, @extrude, @parameterBounded typed expressionsschemaVersion 2,sourceVersion 2
3All Source2 declarations plus typed @functionTyped expressions and named numeric callsschemaVersion 3,sourceVersion 3

For Source3 function signatures, defaults, lexical scope, call receipts and budgets, read quantity functions and open its language example. That interactive example retains its recorded 4f93558d provider; the current source-backed syntax check below uses the separately pinned adopted compiler.

Choose an editable example ​

InputEditable example
Source0 Curve or literal SurfaceCAD curve or CAD surface
Source1 Curve and ExtrudeCAD extrude
Source2 Parameters, expressions and geometryCAD parameters
Source3 Functions and typed geometry expressionsCAD quantity functions

Each playground preset selects its compiler version explicitly: Curve and Surface use source0, Extrude uses source1, and Parameters uses source2. Choose the matching preset before editing its header or declarations. Changing a header alone does not change the selected compiler option. In your application, pass the matching version to compileCadModel explicitly.

Source1 is not a superset of source0. A literal @surface block is refused in source1. Use source0 for literal Surfaces or source2 for literal/expression-driven Surfaces. Source1 produces Surfaces through @extrude.

ts
import { compileCadModel } from '@barocss/cad';
const compiled = compileCadModel(source, { sourceVersion: 2 });
if (!compiled.ok) {
  console.log(compiled.diagnostics[0]);
}

source is the authored string, with a matching version:2 header. The options record must contain exactly the own enumerable data field sourceVersion:0, 1, 2 or 3. Plain and null-prototype records are accepted. Getters, symbols, extra options and unsupported versions refuse. A source header does not select the compiler option automatically.

From authored source to native geometry ​

compileCadModel(text, {sourceVersion}) orchestrates the following stages. Passing a later dialect is an explicit caller decision; the header alone does not upgrade the compiler option or an editor/Loader consumer.

  1. Parse the selected grammar into a ranged AST. Check tokens, fields, declaration kinds and the matching model header
  2. Lower the AST into that dialect's IR. Resolve IDs, dependencies, typed Parameters and, for Source3, bounded function calls. Refuse missing references, cycles and invalid quantities
  3. Lower geometry/constructions into native Model version 0. Native degree, knot, weight, coordinate and extrusion constraints still apply to resolved values
  4. Optionally evaluate or tessellate the native geometry through separate APIs. A successful compiler result does not certify Solid topology or rendered pixels

On success, inspect ast, ir, model and constructions. Native model.objects contains Curves and Surfaces, not live Parameter or function objects. IR retains authoring/evaluation information. On compiler failure, diagnostics are returned without a partial AST, IR or Model to adopt. Keep the previously accepted source/result separately and recompile the complete candidate after an edit.

The compiler, declaration parser and native lowering are pinned to the adopted source used for this manual increment.

Common model structure ​

A file contains one model. Fields and declarations can appear in any order inside it:

text
model        = "@model" modelName "{" (modelField | declaration)* "}"
modelField   = "version" ":" versionNumber ";"
             | "length-unit" ":" "mm" ";"
declaration  = a declaration admitted by the selected dialect

This grammar describes structure. Semantic checks also require both model fields, unique fields, 1..16 geometry declarations and valid geometry. Parameters and Source3 functions do not count as geometry. Extra text or a second model after the closing brace refuses.

css
@model part_name {
  version: 0;
  length-unit: mm;
  /* Geometry declarations go here. */
}

The block above shows the header only. It does not compile until geometry is added. length-unit:mm remains required in source2, even when an individual expression uses cm or m.

Names, IDs and references ​

NameSyntaxMeaning
Model name[A-Za-z_][A-Za-z0-9_-]*Names the model
Geometry ID# followed by [A-Za-z_][A-Za-z0-9_-]*Names a Curve, Surface or extrusion output
Parameter ID# followed by [A-Za-z_][A-Za-z0-9_]*Names a source2 parameter; hyphens are excluded
Geometry reference#profile in curveMust name a Curve declaration
Parameter reference$width inside an expressionMust name a Parameter declaration

Declaration IDs are globally unique across parameters and geometry. #width cannot name a Parameter and a Curve in the same model. Case is significant. $width does not refer to geometry named #width. A hyphen in a parameter expression is subtraction: $a-$b.

References may point forward. Compilation checks the complete parameter reference graph and cycles before evaluating parameter quantities. Native objects retain authored geometry declaration order, even when an extrusion appears before its input Curve. Parameter declarations are absent from model.objects.

Punctuation and literals ​

Every field ends with ;. Arrays use commas. Trailing commas refuse. Spaces, newlines and /* block comments */ are accepted; // is outside the comment grammar. Declarations close with } and have no trailing semicolon.

Source0/1 numeric literals use this form:

text
signedDecimal = ("+" | "-")? (digits ("." digits?)? | "." digits)

Examples: 10, -1.25, +.5, 1.. Values must be finite. Exponent spelling such as 1e2, quoted numbers, unit suffixes, arithmetic, function calls and substitutions refuse in source0/1. In source2, a sign is a unary expression rather than part of the unsigned numeric leaf.

Curves in source0, source1, source2 and source3 ​

Each Curve requires these five fields:

css
@curve #edge {
  type: nurbs;
  degree: 1;
  knots: [0,0,1,1];
  control-points: [[0,0,0],[20,0,0]];
  weights: [1,1];
}

type:nurbs is the only accepted type. Poles are ordered XYZ triples in mm. Knots and weights are dimensionless. The number of weights equals the number of poles. Source2 permits a numeric expression in each numeric leaf, with the quantity requirements below.

For N poles and degree p:

  • Degree is an integer 1..5 and is smaller than N.
  • N is 2..64.
  • Knot count is N+p+1. Knots are finite and nondecreasing.
  • Both endpoint values repeat exactly p+1 times. Interior multiplicity is at most p.
  • The original parameter domain [knots[p],knots[N]] has positive length.
  • Each coordinate is finite and within ±1e6 mm. Every weight is 1e-6..1e6.

Complete source0 Curve ​

css
@model original_domain {
  version: 0;
  length-unit: mm;
  @curve #edge {
    type: nurbs;
    degree: 1;
    knots: [2,2,7,7];
    control-points: [[0,0,0],[20,0,0]];
    weights: [1,1];
  }
}

Compile with {sourceVersion:0}. curveDomain(curve) returns [2,7]; evaluateCurve(curve,4.5) returns [10,0,0] mm. A parameter of 0 is outside this native domain. Sampling this Curve uses its original parameter range, not an assumed0..1 range.

A rational Curve's control polygon is not its sampled shape. Endpoint closure does not itself certify a topological wire, region or Solid.

Surfaces in source0, source2 and source3 ​

A literal Surface requires seven fields:

css
@surface #plane {
  type: nurbs;
  degree-u: 1;
  degree-v: 1;
  knots-u: [0,0,1,1];
  knots-v: [0,0,1,1];
  control-points: [[[0,0,0],[0,10,0]],[[20,0,0],[20,10,0]]];
  weights: [[1,1],[1,1]];
}

The outer control-point index is U; the inner index is V. Weight rows match that same rectangular grid. Each direction has 2..16 poles and at most 256 poles exist in total. Degree/knot rules apply independently in U and V.

Wrap this block in the matching source0 or source2 model header. For the example, evaluateSurface(surface,0.5,0.5) gives [10,5,0] mm. Increasing U follows+X; increasing V follows+Y. A display tessellation retains this authored XYZ; it does not infer a native up axis.

Fields for trims, periodic flags, textures or materials are not accepted by this model language. Specialized public native operations/documents can support their own families without adding a declaration here.

Extrusions in source1, source2 and source3 ​

@extrude requires a Curve reference and a three-component vector:

css
@model raised_edge {
  version: 1;
  length-unit: mm;
  @curve #profile {
    type: nurbs;
    degree: 1;
    knots: [0,0,1,1];
    control-points: [[0,0,0],[20,0,0]];
    weights: [1,1];
  }
  @extrude #wall { curve: #profile; vector: [0,0,30]; }
}

Open the source1 extrusion preset to edit this complete input. It compiles with {sourceVersion:1}. Output objects are profile Curve and wall Surface. The resulting Surface satisfies S(u,v)=C(u)+vD, with original U domain and V domain 0..1. evaluateSurface(wall,0.5,0.5) gives [10,0,15] mm.

Each Curve pole becomes two Surface poles, [Pi,Pi+D]; each weight becomes [wi,wi]. U degree/knots are copied; V degree is1 and knots are [0,0,1,1]. At most16 Curve poles fit the Surface envelope. The finite vector must be nonzero, translated poles must remain within ±1e6 mm, and displacement must change at least one represented pole.

References to another extrusion or a literal Surface refuse. A Curve whose poles are wholly collinear with the extrusion vector produces a collapsed construction and refuses. This extrusion creates an open Surface. It creates no caps or Solid topology.

Parameters and expressions in source2 ​

Complete parameter-driven model ​

css
@model driven {
  version: 2;
  length-unit: mm;
  @parameter #width { type: length; value: 10 cm; }
  @parameter #height { type: length; value: $width / 2; }
  @parameter #scale { type: scalar; value: 2; }
  @curve #profile {
    type: nurbs;
    degree: 1;
    knots: [0,0,1,1];
    control-points: [[0,0,0],[$width,0,0]];
    weights: [1,1];
  }
  @extrude #wall { curve: #profile; vector: [0,0,$height * $scale]; }
}

Open the source2 Parameter preset to edit this complete input. It compiles with {sourceVersion:2}. Parameter values are width100mm,height50mm and scale2. The native profile endpoint is [100,0,0]; the wall reaches z100mm. Change 10 cm to 12 cm and recompile: width120mm,height60mm and wall height120mm. Geometry IDs and declaration order remain stable. A previously returned model/report does not change when source text is edited.

Expression grammar and precedence ​

text
expression = sum
sum        = product (("+" | "-") product)*
product    = unary (("*" | "/") unary)*
unary      = ("+" | "-") unary | primary
primary    = unsignedDecimal lengthUnit?
           | "$" parameterName
           | "(" expression ")"
lengthUnit = "mm" | "cm" | "m"

Signs bind first, then multiplication/division, then addition/subtraction. Binary operators at the same level are left associative: 20/2/2 is5. Parentheses change grouping: (2+3)*4 is20; 2+3*4 is14. Unit suffixes can follow a decimal directly or after whitespace: 10cm and 10 cm are equivalent.

In Source2, no function, exponent literal, percentage, member/index access, string, import, interpolation or arbitrary source execution is admitted. Source3 adds only the declared typed quantity calls. calc(2), Math.PI, 1e2, 10%, "10mm" and ${width} are examples outside the grammar.

Quantity rules ​

OperationAdmitted operand kindsResult
Unary +/-length or scalarSame kind
+/-Same kind on both sidesSame kind
*scalar/scalarscalar
*length/scalar or scalar/lengthlength
/scalar/scalarscalar
/length/scalarlength
/length/lengthscalar

Length×length and scalar÷length refuse. Division by positive or negative zero refuses. Numeric leaf and evaluated intermediate magnitudes are finite and at most1e12. Normalization uses1mm=1,1 cm=10 mm,1 m=1000 mm. A valid parameter quantity can still exceed the narrower native coordinate/weight/degree limit when used in geometry.

A Parameter requires type:length or type:scalar and a value of that same kind. @parameter #width {type:length;value:2;} refuses; write 2mm. Parameters have no implicit unit.

Quantity requirements by field ​

Numeric fieldRequired kind
control-points componentslength
vector componentslength
degree, degree-u, degree-vscalar integer, then native degree limits
knots, knots-u, knots-vscalar
weightsscalar, then positive native weight limits

For coordinate/vector fields only, a single bare decimal with unary signs or parentheses retains the mm shorthand. Thus 10,(-10) and +(.5) are lengths in those fields. This rule does not convert a compound scalar expression or scalar Parameter to length.

Coordinate expressionAdmission
1010 mm literal shorthand
1mm+2mmlength3mm
$width/2length when width is a length Parameter
1+2Refused: compound scalar
$scaleRefused when scale is a scalar Parameter
1mm*2mmRefused: length product

References, cycles and result records ​

All Parameter references resolve before quantity evaluation. Missing Parameters, references to geometry and cycles refuse, including unused cyclic Parameters. Source2 accepts at most 64 Parameters and 16 geometry declarations.

IR schema2 retains authored-order parameters and field/index-order bindings. A binding records owning object ID, field, array indices, original expression/range, resolved value/kind and Parameter references. Repeated references remain separate dependency occurrences. The native Model contains resolved numbers; its geometry version remains 0. Recompile the complete edited source to apply new Parameter values.

Refusal examples and diagnostics ​

CandidateTypical diagnostic boundary
Header version differs from sourceVersionVERSION
Unsupported declaration, including source1 SurfaceKIND
Missing/unknown fieldFIELD
Duplicate field or globally duplicate IDDUPLICATE
Unsupported unit or incompatible quantityUNIT
Undefined/wrong-kind referenceREFERENCE
Parameter cycleCYCLE
Division by either signed zeroDIVISION_ZERO
Fractional/out-of-domain degreeDEGREE
Invalid knot sequence/domainKNOTS
Invalid native weightWEIGHTS
Array shape/nestingDIMENSION or the reported parser boundary
Malformed token, trailing comma or extra modelSYNTAX
Source/parser/expression allocation capLIMIT

The first reported boundary depends on the actual candidate and compiler stage. Inspect its real code/message/range rather than assuming every invalid string reaches semantic validation.

This standalone module reports the location from the same string that it compiles:

ts
import { compileCadModel } from '@barocss/cad';

const candidateSource = '@model bad { version: 0; length-unit: cm; }';
const rejected = compileCadModel(candidateSource, { sourceVersion: 0 });
if (rejected.ok) throw new Error('Expected a unit refusal');
const { code, message, range } = rejected.diagnostics[0];
console.log({
  code,
  message,
  location: `${range.line}:${range.column}`,
  text: candidateSource.slice(range.start, range.end),
});

The expected code is UNIT, and the highlighted text is cm. Root units must be mm. Failure returns diagnostics and no partial AST, IR or Model. Source ranges use half-open UTF-16 offsets and one-based line/column coordinates, including endLine/endColumn. Keep the exact candidate string with its diagnostics. Apply each range to the candidate that produced it.

Allocation and geometry bounds ​

ResourceLimit
Source262144 UTF-8 bytes
Geometry declarations16
Source2 Parameters64
Array depth3
Shared AST nodes/values65536
Tokens131072
Nodes per expression256
Expression tree depth32
Aggregate expression nodes32768
Expression literal/intermediate magnitude1e12
Curve poles / Surface poles64 / 16×16
Native coordinate magnitude1e6mm
Native weight1e-6..1e6

Parsing checks bounds before further growth. Native validation still applies after expression evaluation. Acceptance does not certify regularity, general topology, Solid validity or display quality. Tessellation can refuse geometry that compiles as a native model. Keep source, native geometry, sampled mesh and image as separate records.

API reference ​

These Source0/1/2/3 language forms belong to the experimental CAD compiler (0.0.0-experimental). Compiler contracts, native domain and derivative queries and typed expression rules describe the public API used above. The newer qualified Body API is a separate construction family; it adds no language declaration to these grammars.

Overview · Quickstart · Guides · API · Examples · Limits

Local manual snapshot. Availability is stated on each package page.