# 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`](names.md) for the syntax of whatever
comes next, [`nodes.md`](nodes.md) to find the file for a node, and [`tasks.md`](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.

```kdl
// 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 `mark`s 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.

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

```sh
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.md) names the rules.
