DSL scripting reference
WebCAE's boundary conditions, geometry, meshing and solver settings all run through a single command layer — usable from the UI, from a script, or from an MCP tool call. This reference documents every command as implemented in the current codebase, with syntax, arguments, units, and honest notes on what's not implemented yet.
Introduction
WebCAE has a single command layer under the hood: every action available from the UI — creating geometry, setting boundary conditions, meshing, solving, reading results — is also a command in a small scripting language (DSL). The wizard panels and the ribbon call the exact same command handlers that a script calls. That means a script can reproduce anything you can do by hand, and anything a script does can be replayed, diffed, and version-controlled as plain text.
You can run a script two ways:
- In the app — open the terminal panel in the UI and paste or type commands. Each command executes immediately against the live model, same as clicking the equivalent button.
- Through MCP — the
cae_run_scripttool takes a DSL script as a string and returns the printed output, recorded values, and any error. This is how an external agent or automation drives WebCAE headlessly.
A script is plain text, one statement per line (loops and blocks use { }). Comments start with # or //.
Quick start: a cantilever beam, start to finish
This is a real, verified example (from the project's own test suite) — a rectangular bar fixed at one end, loaded at the other, checked against beam theory:
units mm
material E=200000000000 nu=0.3 density=0
primitive box dx=20 dy=20 dz=100
mesh tet size=6
fix face z-
load face z+ force=5000 component=z
solve
reactionsWhat happens, step by step:
1. units mm — declares the script's own length unit as millimetres (this only affects procedural commands like beam/shell/mass, not OCCT geometry — see Units and tolerances below).
2. material — sets Young's modulus (200 GPa, in pascals) and Poisson's ratio directly, in SI units.
3. primitive box dx=20 dy=20 dz=100 — a 20×20×100 mm bar.
4. mesh tet size=6 — a tetrahedral mesh with a 6 mm target element size.
5. fix face z- — clamps the face at the z- end of the box's bounding box (a built-in face id shorthand — no need to look up a face index).
6. load face z+ force=5000 component=z — applies 5000 N along +z on the opposite face.
7. solve — runs a static structural analysis.
8. reactions — extracts the support reaction forces.
Expected result: the reaction at the fixed end is R_z ≈ −5000 N (balances the applied load), within the project's standard 5% tolerance. Transverse reaction components stay under 5% of the applied force, as expected for a load aligned with the beam axis.
Language basics
Units
units <m|mm|in> sets the length unit used by procedural commands (beam, shell, mass, mesh sizing zones). Without a declaration the script defaults to metres for those commands. OCCT geometry commands (box, primitive, sketch, imported CAD) already carry their own coordinates — units does not rescale them. See Units and tolerances for the full picture.
Variables, control flow, functions
let x = 10
let faces = list faces of body1
if x > 5 {
print "large"
} else {
print "small"
}
for i in [0..3] {
print i
}
let n = 0
while n < 3 {
n = n + 1
}
func square(v) {
return v * v
}
print square(4)let name = exprdeclares/assigns a variable.if / else,for x in <range or list>,while— standard control flow. Aforrange is written[from..to]or[from..to:step].func name(params) { ... return expr }defines a reusable function.- Loops are capped at 1,000,000 total iterations and recursion at depth 64, as a safety limit.
- Values: numbers, strings, booleans, arrays, objects (e.g. each entry from
list faces of ...is an object with.id,.area,.centroid,.normal), andnull.
Built-in functions
abs, sqrt, min, max, floor, ceil, round, len, str, num, basename.
print / record
print <value...> writes to the script log. record <value...> stores a value under the script's recorded output (useful for pulling numbers back out through MCP).
Vector arguments
Several named arguments take a vector as three comma-separated numbers, e.g. origin=0,0,10 or force=1000,0,0. The full list: origin, normal, axisZ, point, node, delta, vector, pull, neutral_at, neutral_dir, axis, at, step, points, center, faces, edges, openFaces, force, moment, translate, rotate, uaxes, raxes. When only one number is given, it's treated as a plain scalar, not a 1-vector — so load ... force=100 (a scalar magnitude on one axis via component=) still works as expected.
Command reference
Commands are grouped by what they do. Each entry lists the syntax, arguments, units where relevant, a short example, and an honest note on limitations where they exist.
Units and geometry basics
`units [length=]<m|mm|in>` — length unit for procedural commands. Default mm if never declared.
``dsl
units mm
``
`box dx dy dz` — an axis-aligned box, corner at the origin. Positional or dx=/dy=/dz=.
``dsl
box dx=20 dy=20 dz=100
``
`primitive <shape> [params...]` — other primitive solids: box, cylinder, sphere, cone, torus, wedge, hollowHemisphere (dome), solidHemisphere (hemisphere). Parameters are shape-specific numeric fields.
``dsl
primitive cylinder r=10 h=50
``
`import "<path>" [format=step|iges]` — imports a CAD file. The path must be quoted (bare / is division in this language, // is a comment).
``dsl
import "part.step"
``
Body transforms
`body translate [dx= dy= dz=]` — moves the last created body.
`move <target> dx dy dz` (or delta=x,y,z) — moves a named body.
`rotate <target> angle= [axis=] [at=]` — rotates a body about an axis through a point (defaults to the origin / Z axis if omitted).
`mirror <target> [normal=] [at=]` — mirrors a body across a plane.
`scale <target> factor= [at=]` — uniform scale about a point.
`pattern <linear|circular> <target> count= [step=] [axis=] [at=] [angle=]` — creates a linear or circular pattern of copies.
rotate body1 angle=90 axis=0,0,1 at=0,0,0Boolean operations and assembly
`boolean <union|cut|intersect> target= tool=` — combines two bodies.
`sew <a> <b>`, `union <a> <b>`, `imprint <a> <b>` — lower-level assembly/topology operations.
`split target=<body> plane=<name>` or `split target=<body> point= normal=` — splits a body by a datum plane or by an ad-hoc point/normal.
`remove <target...>` / `delete <target...>` — deletes bodies.
`unstitch <target>`, `stitch <target> [tolerance=]` — separate/rejoin shells.
boolean cut target=body1 tool=body2Features and sim-prep
`fillet <target> radius= [edges=i,j]` — rounds edges (all edges if edges= omitted).
`chamfer <target> distance= [edges=]` — chamfers edges.
`hollow <target> thickness= [openFaces=]` — shells a solid to a wall thickness, optionally leaving faces open.
`defeature <target> [maxHoleRadius=] [maxFaceArea=] [faces=i,j,k]` — removes small features below the given thresholds; at least one criterion is required.
`repair <target> [merge] [heal] [tolerance=]` — repairs geometry; with no flags, both merge and heal run.
`autofix [on|off] [element=<mm>] [<body>]` — runs the automatic geometry healing pass used before meshing.
`simplify <target> [min_volume=] [min_diag=] [keep_fraction=]` — removes small solids/features from an assembly for a lighter mesh.
`shrinkwrap <target> [min_volume=] [tol=]` — wraps a body in a simplified outer envelope.
fillet body1 radius=2 edges=3,7Generative geometry (sketch-based)
`sketch points=x0,y0,z0,x1,y1,z1,... [as=face|wire] [closed=true]` — builds a planar profile from at least two points.
`extrude <target> [delta=x,y,z | dx= dy= dz=]` — extrudes a profile into a solid.
`revolve <target> angle= [axis=x,y,z] [at=x,y,z]` — revolves a profile about an axis.
`sweep <profile> path=<body>` — sweeps a profile along a path body.
`loft <section1> <section2> [...]` — lofts through two or more sections.
sketch points=0,0,0, 10,0,0, 10,10,0, 0,10,0 as=face closed=true
extrude body1 dz=5Direct modeling
`offset_face <target> faces=i,j distance=` — offsets selected faces.
`pull <target> faces=i,j distance=` — alias for offset_face.
`move_face <target> faces=i,j vector=x,y,z` — translates selected faces.
`draft_face <target> faces=i,j angle= pull=x,y,z neutral_at=x,y,z neutral_dir=x,y,z` — applies a draft angle to selected faces about a neutral plane.
Datums
`plane [<name>] origin=x,y,z normal=x,y,z` or `plane [<name>] global=XY|YZ|ZX [offset=]` — creates a datum plane.
`cs [<name>] origin=x,y,z [axisZ=] [axisX=]` — creates a local coordinate system. Provide axisX too if you need a fully defined rotation, not just the Z axis.
cs turned origin=0,0,0 axisZ=0,0,1 axisX=1,0,0Mesh
`mesh [all|build|hex|tet|shell] [nx ny nz|size=] [order=1|2] [surface=tri|quad] [quad=0|1|2] [bonding=0|1] [bondtol=] [interference=cut|split|ignore] [glue=auto|contact|full] [fuzzy=]` — builds the mesh. tet and shell are the supported types in the web build (see Known limitations for hex).
``dsl
mesh tet size=6 order=1
``
`refine zone at=x,y,z radius=r size=h [name=] [body=|face=]` — a local sphere-of-influence refinement zone.
`refine clear` — clears all refinement zones.
`weld [tol=]` — welds coincident nodes on a shell mesh, before solve.
Material and section
`material [preset=steel|aluminum|titanium|copper] | E= nu= [density=] [model=linear|neo-hookean] [alpha=] [kappa=]` — sets the material. Presets: steel (E=200 GPa, ν=0.3, ρ=7850 kg/m³), aluminum (E=70 GPa, ν=0.33, ρ=2700), titanium (E=110 GPa, ν=0.34, ρ=4500), copper (E=120 GPa, ν=0.34, ρ=8900) — each preset also sets thermal expansion alpha and conductivity kappa.
``dsl
material preset=aluminum
``
`section shell t=<thickness>` — sets the shell thickness for shell elements.
Contact
`contact <mode> [mu=]` — sets a global default contact mode.
`contact <a> <b> <mode> [mu=]` — sets a per-pair contact mode.
`contact pairs <all|visible> <mode>` — auto-detects touching face pairs and assigns a mode to all of them. Requires the UI wizard host — from a headless/MCP script without an open project this command is unavailable (it throws contact pairs: requires wizard host).
Modes: tied, bonded, rigid, penalty, frictionless, frictional. rigid is a legacy alias for tied. `frictionless` and `frictional` always reject — nonlinear contact solving is not implemented yet; the command exists so scripts fail loudly instead of silently getting a linear approximation.
contact bodyA bodyB bondedBoundary conditions and loads
`fix [kind=face] <target> [component=all|x|y|z|normal] [value=]` — a displacement/rotation constraint.
``dsl
fix face z-
``
`load [kind=face] <target> [pressure=|force=|distributed_force=|accel=] [component=x|y|z|normal] [cs=] [fx= fy= fz=]` — applies a load. Either a scalar magnitude with component=, or a vector form with fx=/fy=/fz= (not combinable with element=pressure). cs= applies the load in a named local coordinate system.
``dsl
load face z+ force=5000 component=z
load face x+ fx=1000 fy=0 fz=0 cs=turned
``
Remote loads and remote motion
Applies a load or a prescribed motion at a point offset from the target face/body, coupled through a rigid or distributing connection — useful for representing a bracket, pin, or attachment that isn't modelled explicitly.
`remote load <kind> <target> point=x,y,z force=fx,fy,fz [moment=mx,my,mz] [cs=]`
``dsl
remote load face x+ point=150,5,5 force=1000,0,0 moment=0,0,5 cs=turned
``
`remote motion <kind> <target> point=x,y,z [translate=ux,uy,uz] [rotate=rx,ry,rz] [uaxes=1,1,1] [raxes=0,0,1] [cs=]` — translate is in metres, rotate in radians (SI, regardless of the units declaration); uaxes/raxes mask which translation/rotation axes are actually enforced.
``dsl
remote motion face x+ point=1,2,3 translate=0.01,0,0 uaxes=1,0,0
remote motion face z+ point=0,0,20 rotate=0,0,0.05
``
Suppressing bodies
`suppress <target> [on|off]` — removes a body from the analysis without deleting it from the model. Default is on (suppress).
``dsl
suppress body2
suppress body2 off
``
Point mass
`mass node=<id|x,y,z> m= [Ixx= Iyy= Izz=]` — attaches a point mass (with optional rotational inertia) at a node or location.
Procedural beam and shell (quick verification models)
`beam L=<length> section=rect|circle|ibeam [w= h= r= n=] [scheme=cantilever|simply-supported] [P=]` — builds a 1D beam model directly, without going through solid geometry — for quick analytical-style checks.
`shell Lx= Ly= t= [nx= ny=] [elem=quad|tri] [scheme=cantilever|all-clamped] [P=]` — builds a flat shell/plate model directly.
Solve
`solve [static|modal|buckling|thermal|thermoelastic] [nmodes=] [deltaT=] [prestress=on|off]` — runs the analysis. prestress=on (also accepts true/1) runs a prestressed modal analysis when combined with modal and a load; see Known limitations for what does and doesn't currently work per analysis type.
``dsl
solve modal nmodes=6
solve modal nmodes=3 prestress=on
``
Postprocessing
`probe <quantity> [x= y= z=|at=x=v] [target=] [tolerance=] [mode=] [bc=] [units=] [source=] [id=]` — extracts a single value at a point or aggregated over a target.
``dsl
probe displacement_magnitude at=0,0,100
``
`minmax <quantity>` — extracts both the minimum and maximum of a field quantity in one call.
`reactions [bc=]` — extracts support reaction forces (reaction_x, reaction_y, reaction_z, reaction_magnitude, all in newtons).
`hotspots [grading=] [refine=] [minsize=]` — runs stress-hotspot analysis on the current results.
Inspection and export
`list faces of <body>` (also list faces <body> / list faces target=<body>) — prints each face's index, stable id, area, centroid and normal, and returns them as an array of objects usable in scripts (e.g. let faces = list faces of body1).
`export vtk [path=]` — exports the current mesh/results to VTK.
Quantities available to probe / minmax
| Quantity | Meaning | Units |
|---|---|---|
displacement_magnitude | Total displacement | m |
vonMises | Von Mises stress | Pa |
principalMax | Maximum principal stress | Pa |
principalMin | Minimum principal stress | Pa |
frequency | Modal frequency | Hz |
load_factor | Buckling load factor | — |
temperature | Temperature | K (or as configured) |
body_count | Number of bodies | — |
volume | Volume | m³ |
element_count | Mesh element count | — |
clash_count | Interference clash count | — |
interference_volume | Interference overlap volume | m³ |
area | Surface area | m² |
wall_thickness | Local wall thickness | m |
min_distance | Minimum distance between targets | m |
solid_count | Number of solids | — |
boundary_quad_count | Quad elements on boundary | — |
boundary_tri_count | Tri elements on boundary | — |
volume_element_count | Volumetric element count | — |
mesh_component_count | Disconnected mesh pieces (1 ⇒ fully connected assembly) | — |
mesh_region_count | Distinct volumetric mesh regions (≥2 needed for contact) | — |
reaction_x / reaction_y / reaction_z / reaction_magnitude | Support reaction force components | N |
hotspot_count | Number of detected stress hotspots (needs hotspots run after solve) | — |
Units and tolerances
- Geometry (
box,primitive,sketch, imported CAD) uses scene units — millimetres by default in the app. Theunitscommand does not rescale OCCT geometry coordinates. - The `units` command only governs procedural commands —
beam,shell,mass, and mesh sizing zone (refine zone) parameters — where the number you type is interpreted in the declared unit. - The solver boundary is always SI: metres, newtons, pascals, kilograms. Loads (
force=,pressure=), material properties (E,density), remote-loadforce/moment, andreactionsoutput are all in SI regardless of the scene's length unit. - Accuracy tolerance: the project's own verification suite checks every solver capability to within 5% relative error against an independent reference; the tolerance is not relaxed to make a case pass — a failing check means the underlying issue gets fixed, not the check.
Known limitations
Be honest about what doesn't work yet — using a feature outside these bounds either throws a clear error or silently gives you a different result than expected, so it's worth reading before you build a script around one of these.
- `solve thermal` does not currently compute a temperature field. In the current implementation, the analysis-type dispatch in the script runner has explicit branches for
modal,buckling, andthermoelastic, but everything else — includingthermal— falls through to the same code path asstatic, which runs a structural static solve (kind: 'static'is hard-coded there). The dedicated heat-conduction solver exists in the product and is used by the UI results pipeline, but the text DSL never calls it. Do not use `solve thermal` expecting a real thermal result — it currently runs a structural static analysis instead. - Boundary layers (inflation) are not implemented in the web mesher.
mesh ... inflate=/inflation=1/layers=/ratio=/first=is rejected outright with an explanation, rather than silently meshing without them — the WASM mesher hard-codes inflation off, so no prismatic wall layers are ever produced. Userefine zone at=x,y,z radius=r size=hfor local refinement near a surface instead. - The hex-dominant mesher is not available in the web build.
mesh hexis rejected with an explanation — the web mesher is tetrahedral-only. Usemesh tetormesh shell. - A handful of mesh option names are rejected, not silently ignored.
algo2d=,algo3d=,recombine=, andhexdom=never reach any actual mesher in the current web build; the parser rejects them with an explicit error rather than silently accepting and ignoring them. - The geometry solve path always builds an order-1 (linear) mesh, regardless of
mesh ... order=2in the script, whenever the script has moved or transformed a body (taking the "geometry" solve path rather than the plain box path). The plain box path, by contrast, does honourorder=2and will build real midside-node tet10 elements — and will reject a request it can't fulfill (e.g. a mesh with no midside nodes) rather than silently solving at the wrong order. - `contact pairs` (auto-detect) requires the UI wizard host. From a purely headless/MCP script with no open project,
contact pairs all|visible <mode>is unavailable and throws an explicit error. Per-pair (contact <a> <b> <mode>) and global-default (contact <mode>) contact assignment have no such restriction. - Nonlinear contact is not solved.
contact ... frictionlessandcontact ... frictionalalways reject with an explicit error rather than silently falling back to a linear approximation. - Prestressed modal analysis (
solve modal ... prestress=on) requires an actual applied load in the model and only works with tet4 (order-1) elements — it rejects onorder=2, on a load-free model, and on an unrecognizedprestress=value.