vcad.
Back to Loon Language
Loon Language

Loon Syntax

Complete Loon language syntax: primitives, booleans, transforms, pipe, let, scene

Loon is a Lisp-inspired language for describing parametric CAD geometry. It uses S-expression syntax with square brackets and provides let bindings for naming intermediate results and pipe for chaining operations. Loon is the primary input format for the create_cad_loon MCP tool, offering a more concise alternative to the JSON-based create_cad_document.

Syntax Basics

Loon expressions use square brackets instead of parentheses. The first element after the opening bracket is the operator, and the rest are arguments.

[cube 50 30 5]

Nesting works as expected:

[difference [cube 50 30 5] [translate 25 15 0 [cylinder 3 10]]]

Comments start with ; and extend to the end of the line:

; A simple plate with a hole
[difference [cube 50 30 5] [translate 25 15 0 [cylinder 3 10]]]

Primitives

cube

[cube <sx> <sy> <sz>]

Creates a box with corner at the origin, extending to (sx, sy, sz). All dimensions in millimeters.

[cube 100 60 5]  ; 100mm wide, 60mm deep, 5mm tall

cylinder

[cylinder <radius> <height>]

Creates a cylinder along the Z axis with base center at the origin.

[cylinder 10 25]  ; r=10mm, h=25mm

sphere

[sphere <radius>]

Creates a sphere centered at the origin.

[sphere 15]  ; r=15mm

cone

[cone <r_bottom> <r_top> <height>]

Creates a cone or frustum along the Z axis. Use 0 for r_top for a pointed cone.

[cone 10 0 20]    ; pointed cone
[cone 15 8 25]    ; frustum

Boolean Operations

union

[union <a> <b>]

Combines two shapes into one. Can be nested for multi-body unions.

[union [cube 20 20 10] [translate 10 10 0 [cube 20 20 10]]]

difference

[difference <a> <b>]

Subtracts shape b from shape a.

[difference [cube 50 30 5] [translate 25 15 0 [cylinder 3 10]]]

intersection

[intersection <a> <b>]

Keeps only the overlapping volume.

[intersection [cube 20 20 20] [sphere 15]]

Transforms

translate

[translate <x> <y> <z> <child>]

Moves a shape by the given offset. Note that the child comes last, which enables clean piping.

[translate 50 0 10 [cube 20 20 20]]

rotate

[rotate <rx> <ry> <rz> <child>]

Rotates a shape by Euler angles in degrees.

[rotate 0 0 45 [cube 20 20 20]]

scale

[scale <sx> <sy> <sz> <child>]

Scales a shape by the given factors.

[scale 2 1 1 [cube 10 10 10]]  ; stretch along X

Patterns

linear-pattern

[linear-pattern <dx> <dy> <dz> <count> <spacing> <child>]

Creates count copies along the direction vector with the given spacing.

[linear-pattern 1 0 0 5 20 [cylinder 3 10]]

circular-pattern

[circular-pattern <ox> <oy> <oz> <ax> <ay> <az> <count> <angle> <child>]

Creates copies around an axis defined by origin and direction vector.

[circular-pattern 0 0 0 0 0 1 6 360 [cylinder 3 10]]

Features

fillet

[fillet <radius> <child>]

Rounds all edges of a solid with the given blend radius.

[fillet 2 [cube 30 30 10]]

chamfer

[chamfer <distance> <child>]

Bevels all edges with the given distance.

[chamfer 1 [cube 30 30 10]]

shell

[shell <thickness> <child>]

Hollows a solid, leaving walls of the given thickness.

[shell 2 [cube 50 50 50]]

Sketch Operations

sketch

[sketch <plane> <segments...> end]

Creates a 2D sketch on a standard plane (xy, xz, or yz). Segments are line and arc definitions within the sketch. Close the sketch with end.

[sketch xy
  [line 0 0 10 0]
  [line 10 0 10 5]
  [line 10 5 0 5]
  [line 0 5 0 0]
end]

extrude

[extrude <dx> <dy> <dz> <sketch>]

Pushes a sketch profile along the given direction vector.

[extrude 0 0 20
  [sketch xy
    [line 0 0 10 0]
    [line 10 0 10 5]
    [line 10 5 0 5]
    [line 0 5 0 0]
  end]]

revolve

[revolve <ox> <oy> <oz> <ax> <ay> <az> <angle> <sketch>]

Revolves a sketch around an axis. Angle in degrees.

[revolve 0 0 0 0 0 1 360
  [sketch xz
    [line 5 0 10 0]
    [line 10 0 10 15]
    [line 10 15 5 15]
    [line 5 15 5 0]
  end]]

let Bindings

The let form names an expression so you can reference it later. This is how you avoid deep nesting and build complex models from named pieces.

[let plate [cube 50 30 5]]
[let hole [translate 25 15 0 [cylinder 3 10]]]
[let result [difference plate hole]]
[root result "aluminum"]

Variables are resolved by name. A let binding does not create a visible part on its own -- you must use root to add it to the scene.

pipe

The pipe form chains operations on a value, passing the result of each step as the last argument to the next. This avoids deeply nested brackets when applying a sequence of transforms or operations.

[pipe
  [cube 50 30 5]
  [fillet 1]
  [translate -25 -15 -2.5]
  [shell 2]]

This is equivalent to:

[shell 2 [translate -25 -15 -2.5 [fillet 1 [cube 50 30 5]]]]

Each step in the pipe receives the previous result as its last argument. This works because all Loon operations accept the child/operand as the last argument.

Scene Directives

root

[root <expr> <material>]

Adds a geometry expression to the scene with the given material. A document can have multiple roots for multi-part scenes.

[let bracket [difference [cube 50 30 5] [translate 25 15 0 [cylinder 3 10]]]]
[root bracket "aluminum"]

material

Materials are referenced by name in root directives. The standard built-in materials (aluminum, steel, abs-black, etc.) are available automatically. Custom materials can be defined with the material directive:

[material "purple-plastic" 0.5 0.2 0.8 0 0.5]

The arguments after the name are: R, G, B, metallic, roughness (all 0-1).

Assembly Directives

part-def

[part-def <id> <root-expr> <material>]

Declares a reusable part definition.

instance

[instance <id> <part-id> <tx> <ty> <tz> <rx> <ry> <rz>]

Places a part instance at the given position and orientation.

joint

[joint-revolute <id> <parent> <child> <px> <py> <pz> <cx> <cy> <cz> <ax> <ay> <az>]
[joint-fixed <id> <parent> <child> <px> <py> <pz> <cx> <cy> <cz>]
[joint-slider <id> <parent> <child> <px> <py> <pz> <cx> <cy> <cz> <ax> <ay> <az>]

Defines kinematic joints between instances. Use _ for the parent to ground the child to the world.

ground

[ground <instance-id>]

Designates the fixed instance.

Complete Examples

Plate with Holes

; Mounting plate: 100x60x5mm with 4 corner holes
[let plate [cube 100 60 5]]
[let hole [cylinder 2.75 10]]

[let h1 [translate 10 10 0 hole]]
[let h2 [translate 90 10 0 hole]]
[let h3 [translate 10 50 0 hole]]
[let h4 [translate 90 50 0 hole]]

[let drilled [difference plate [union h1 [union h2 [union h3 h4]]]]]
[let result [fillet 2 drilled]]
[root result "aluminum"]

Pipe Chaining

; Rounded shell box
[pipe
  [cube 50 50 30]
  [fillet 3]
  [shell 2]
  [translate -25 -25 0]]
[root _ "abs-white"]

Flange with Bolt Circle

[let disc [cylinder 25 5]]
[let holes [circular-pattern 0 0 0 0 0 1 6 360 [cylinder 3 10]]]
[let flange [difference disc [translate 0 0 -1 holes]]]
[root flange "steel"]

Swept Spring

[let profile [sketch xy [line -1 -1 1 -1] [line 1 -1 1 1] [line 1 1 -1 1] [line -1 1 -1 -1] end]]
[let spring [sweep profile [helix 10 5 50]]]
[root spring "steel"]

Using Loon with MCP

Pass Loon source to the create_cad_loon MCP tool:

{
  "source": "[let plate [cube 50 30 5]]\n[let hole [translate 25 15 0 [cylinder 3 10]]]\n[let result [difference plate hole]]\n[root result \"aluminum\"]",
  "format": "compact"
}

The tool evaluates the Loon source through the kernel and returns an IR document in the requested format (compact or JSON). The returned document can then be passed to inspect_cad, export_cad, or open_in_browser.

For a workflow-oriented guide to writing Loon, see Loon for AI Agents. For the create_cad_loon parameter reference, see create_cad_loon.