WebCAE
← Back to documentation

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_script tool 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
reactions

What 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 = expr declares/assigns a variable.
  • if / else, for x in <range or list>, while — standard control flow. A for range 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), and null.

Built-in functions

abs, sqrt, min, max, floor, ceil, round, len, str, num, basename.

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,0

Boolean 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=body2

Features 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,7

Generative 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=5

Direct 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,0

Mesh

`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 bonded

Boundary 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

QuantityMeaningUnits
displacement_magnitudeTotal displacementm
vonMisesVon Mises stressPa
principalMaxMaximum principal stressPa
principalMinMinimum principal stressPa
frequencyModal frequencyHz
load_factorBuckling load factor
temperatureTemperatureK (or as configured)
body_countNumber of bodies
volumeVolume
element_countMesh element count
clash_countInterference clash count
interference_volumeInterference overlap volume
areaSurface area
wall_thicknessLocal wall thicknessm
min_distanceMinimum distance between targetsm
solid_countNumber of solids
boundary_quad_countQuad elements on boundary
boundary_tri_countTri elements on boundary
volume_element_countVolumetric element count
mesh_component_countDisconnected mesh pieces (1 ⇒ fully connected assembly)
mesh_region_countDistinct volumetric mesh regions (≥2 needed for contact)
reaction_x / reaction_y / reaction_z / reaction_magnitudeSupport reaction force componentsN
hotspot_countNumber 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. The units command does not rescale OCCT geometry coordinates.
  • The `units` command only governs procedural commandsbeam, 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-load force/moment, and reactions output 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, and thermoelastic, but everything else — including thermal — falls through to the same code path as static, 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. Use refine zone at=x,y,z radius=r size=h for local refinement near a surface instead.
  • The hex-dominant mesher is not available in the web build. mesh hex is rejected with an explanation — the web mesher is tetrahedral-only. Use mesh tet or mesh shell.
  • A handful of mesh option names are rejected, not silently ignored. algo2d=, algo3d=, recombine=, and hexdom= 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=2 in 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 honour order=2 and 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 ... frictionless and contact ... frictional always 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 on order=2, on a load-free model, and on an unrecognized prestress= value.

We use essential cookies to run this site, plus analytics cookies if you agree. Privacy Policy