New Project

Quickstart#

A minimal valid .kdl skeleton

Get a first draft through design_compile (or ww check) with zero diagnostics before you add anything real. Then use features/INDEX.md for the syntax of whatever comes next, nodes.md to find the file for a node, and tasks.md for a "how do I..." jump-in. The language contract is docs/KDL_AUTHORING.md.

Four rules cause most first-draft diagnostics:

  • Every dimension is a float (19.0, never 19), and units must be mm.
  • Z is negative going down from a part's top face (z=0.0 is the top).
  • A quoted string is a CEL expression; a bare word is a name or enum (x="width / 2.0", normal=pos_x).
  • A joint is join joint=<Name> male=Part@Mark female=Part@Mark, unquoted Part@Mark; the word connect is dead.
// A minimal one-part project: a single board, no joinery.
project name="Test Shelf" units=mm schema_version=1 {

    params {
        width  600.0 min=300.0 max=1200.0 step=10.0 label="Width"  category="Envelope"
        depth  250.0 min=150.0 max=400.0  step=10.0 label="Depth"  category="Envelope"
        thick   19.0 min=12.0  max=32.0   step=1.0  label="Thickness" category="Stock"
    }

    materials {
        material WhiteOak type=hardwood
    }

    assembly Root {
        part Board material=WhiteOak role=shelf {
            stock WhiteOak width depth thick
            by top_sw
            pos x=0.0 y=0.0 z=0.0
        }
    }
}

Adding a second part and a joint#

A real design uses component (a reusable template with marks to join on) and joinery + join (the two-body contract). Here an apron's tenon enters a leg. The apron's mark sits on the shoulder, the end of its stock line, facing out (neg_x); the leg's mark sits on the face the tenon enters, facing the apron (pos_x). Their positions must line up when placed.

project name="Test Frame" units=mm schema_version=1 {

    params {
        leg_dim  45.0 min=30.0 max=64.0 step=1.0 label="Leg Section" category="Stock"
        leg_len 700.0 min=400.0 max=900.0 step=10.0 label="Leg Length" category="Stock"
        apron_len 400.0 min=200.0 max=1200.0 step=10.0 label="Apron Length" category="Stock"
        apron_h 100.0 min=60.0 max=140.0 step=5.0 label="Apron Height" category="Stock"
        apron_th 20.0 min=16.0 max=25.0 step=1.0 label="Apron Thickness" category="Stock"
        glue_clearance 0.2
    }

    materials {
        material Ash type=hardwood
    }

    component Leg role=leg {
        stock Ash leg_dim leg_dim leg_len
        mark MortiseFace_X x=leg_dim y="leg_dim / 2.0" z=-55.0 normal=pos_x
    }

    component Apron role=apron {
        stock Ash apron_len apron_th apron_h
        mark Shoulder x=0.0 y="apron_th / 2.0" z="0.0 - apron_h / 2.0" normal=neg_x
    }

    joinery mortise_and_tenon name=ApronJoint {
        tenon_thickness 8.0
        tenon_length   25.0
        clearance      glue_clearance
        centering axis=z
    }

    assembly Root {
        part Leg_FL instance=Leg { by top_sw; pos x=0.0 y=0.0 z=0.0 }
        part Apron_Front instance=Apron {
            by top_sw
            pos x=leg_dim y="(leg_dim - apron_th) / 2.0" z=-5.0
        }

        join joint=ApronJoint male=Apron_Front@Shoulder female=Leg_FL@MortiseFace_X
    }
}

Validate#

ww check your_file.kdl          # clashes, joint contacts, and the joinery verdicts
cargo run --manifest-path tools/kdl-check/Cargo.toml -- your_file.kdl   # lint only

kdl-check is a linter: it cannot see geometry, so a green lint is not a joint that builds. Run ww check (or design_compile over MCP) and read its diagnostics. Joinery kinds that refuse an impossible configuration say why in the diagnostic; the family file in features/ names the rules.

Settings

Region

A region picks sensible defaults; change any of these separately.

Units

In inches, type lengths the way you say them: 34 1/2, 3/4", 1'-2" or 12.7mm. A length that can't be read is flagged, never rounded to something else.

Paper
Date order
Clock