# Materials & Hardware

*Material definitions, finish, colour, and purchased hardware catalogue items*

**Names:** `materials` `material` `type` `color` `finish` `hardware` `hardware_use` `hardware_mount` `qty`

## When to use

- **`material`** for anything you cut from stock: a timber species, a sheet good, solid metal.
- **`hardware`** for anything you buy as-is and never machine: hinges, pulls, slides, screws,
  nails, casters, and non-wood fill sold by the hank or roll (rush, cane, webbing).
- **`finish=`** to print a finishing note on the cut sheet. **`color=`** only to tint a
  material in the viewer.

This file covers the *declarations* and how hardware reaches the hardware schedule.
Recesses and proxy geometry for hardware are a separate family; see `INDEX.md`.

## Syntax

```text
materials {
    material <Name> type=hardwood|softwood|sheet|metal [nominal_th= finished_th=] [mill=rough|s2s|s4s|dimensional] [finish="'...'"] [color="#rrggbb"]
    hardware <Name> [supplier="..." part_no="..."] [price=<expr>] [<any other numeric property>=<expr>]
}
hardware_use <Name> [qty=<int|expr>] [at=<Part>@<Mark>]
joinery hardware_mount name=<J> { hardware <Name> qty=<n> }
```

- `type=`: `hardwood`, `softwood`, `sheet` or `metal`. A `sheet` declares both
  `nominal_th=` and `finished_th=`; joinery uses the finished figure (real plywood is
  undersized). Glass and laminate are `sheet`. `metal` is solid stock with no grain.
- Any `material` may add `tolerance_slip=`/`tolerance_snug=`/`tolerance_press=` (mm, issue
  #55): the female-side clearance a joint's `fit=` resolves (`joinery-contract`), read by
  `fit` class, female material wins. `movement_radial_pct=`/`movement_tangential_pct=`
  store a material's cited shrinkage for CEL and for reference; never applied to geometry
  automatically — see `docs/KDL_AUTHORING.md` §5 for the draft table and sourcing.
- `mill=` (issue #56, `hardwood`/`softwood` only — an error on `sheet`): how far along the
  rough-to-S4S road the material's boards already are. Default `s4s` (already at finished
  size, zero allowance) when left off — every example that predates this issue omits it and
  keeps its exact stock-list/BOM output. `mill=rough`/`s2s` adds a milling allowance (by mill
  state, never by species) to the purchase size the stock list and BOM report alongside the
  finished size.
- `finish=` (RFC-0122): optional on any `material` and on any `part`; a CEL expression to
  text, printed on the cut sheet. A part's own `finish=` overrides its material's. Write a
  real string literal: `finish="'milk paint, barn red'"`.
- `color="#RRGGBB"` (or `#rgb`): presentation only (viewer and scene JSON). A value that is not
  a hex colour is a warning, `must be a hex string such as "#c8a06e"; ignored`.
- `hardware <Name>` takes free-form properties, kept verbatim: `supplier=` and `part_no=` are
  plain-text labels (never CEL); `price=` and every other property are CEL numbers, so a
  param can drive them. Typical: a hinge's `leaf_length` `leaf_width` `leaf_thickness`
  `knuckle_dia`, a slide's `travel_distance` `slide_depth` `load_kg`.
- **Two ways to use hardware (ADR-0017).** *Mounted*: `joinery hardware_mount name=... {
  hardware <Name> qty=<n> }` applied through an ordinary `join` on two marks. It **cuts
  nothing**, like `butt`: no leaf mortise and no swing envelope are modelled. *Unmounted*:
  a bare `hardware_use <Name> qty=<n> [at=Part@Mark]` fact, for a slide screwed between two
  flat faces, a hank of rush, a box of screws. `qty` defaults to 1; `at=` is provenance only
  and is never checked against a mark.
- Either way the item reaches the **hardware schedule** (`ww pack`'s
  `hardware-schedule.txt`/`.json`) with a summed quantity, never the cut list.
- `@name` slot references work anywhere a material or hardware name goes (see
  `reuse-and-collections`).

## Example

```kdl
project name="Hinged Lid" units=mm schema_version=1 {
    params { glue_clearance 0.2 }
    materials {
        material WhiteOak type=hardwood finish="'danish oil'"
        material Ply type=sheet nominal_th=18.0 finished_th=17.6 color="#c8a06e"
        hardware ButtHinge_75mm supplier="Horton Brasses" part_no="H-06-75AB" \
            leaf_length=75.0 leaf_width=45.0 leaf_thickness=2.5 knuckle_dia=8.0 price=6.50
        hardware BallBearingSlide_16x300 travel_distance=300.0 slide_depth=16.0 load_kg=30.0 price=14.0
    }
    component Base role=carcass {
        stock Ply 400.0 300.0 18.0
        mark Hinge_Top x=400.0 y=150.0 z=0.0 normal=pos_x
    }
    component Lid role=door {
        stock WhiteOak 400.0 300.0 18.0
        mark Hinge_Top x=0.0 y=150.0 z=0.0 normal=neg_x
    }
    joinery hardware_mount name=LidHinge {
        hardware ButtHinge_75mm qty=2
    }
    assembly Root {
        part Carcass instance=Base { by top_sw; pos x=0.0 y=0.0 z=0.0 }
        part Lid instance=Lid finish="'shellac'" { by top_sw; pos x=400.0 y=0.0 z=0.0 }
        join joint=LidHinge male=Lid@Hinge_Top female=Carcass@Hinge_Top
        hardware_use BallBearingSlide_16x300 qty=2
    }
}
```

## Pitfalls and diagnostics

- **Naming a grain on a `type=sheet` material is a hard error** (ADR-0007): sheet goods are
  cross-laminated and have no solid-timber grain.
- Declare **both** `nominal_th` and `finished_th` on a `sheet` material (KDL_AUTHORING §5).
  The parser keeps them verbatim and does not refuse a missing one, so an omission is
  silent: joinery and the sheet packer then lack the real thickness. Using the nominal
  figure for a dado width is the classic error.
- **Never model a purchased part as a `component` with fake `stock`.** A `component` needs
  exactly one `stock` line, and a hinge has no board to mill. `kdl-check` *warns* on a
  `hardware` item that is declared and never named by `hardware_mount` or `hardware_use`.
- `finish=hardwood` (bare word) reads as an unknown identifier; quote it as a CEL string.
- `hardware_mount` placement is not geometry: nothing is recessed or swung. Do not expect a
  clash or a recess from it.
- `supplier=` / `part_no=` are labels, never expressions; `price=` is an expression.
- Not covered here: hardware with a placed recess or proxy geometry. If a sibling file in
  `features/` (see `INDEX.md`) documents it, that file's `status:` says whether it is built.

## See also

- `docs/KDL_AUTHORING.md` §5 (`materials`, `hardware`), §15 (material `color=`).
- `docs/adr/0017-hardware-and-materials.md`, `docs/rfc/0122-finish-attribute.md`,
  `docs/rfc/0121-non-wood-materials-and-hardware.md`.
- `components-and-stock.md` (grain), `reuse-and-collections.md` (slots),
  `examples/loom_shuttle.kdl` and `examples/filing_cabinet_vertical.kdl` (`hardware_use`).

## Names

Every name this page declares, how the example library uses it, and the shortest real use.

### `materials`

project-level node; node in 114 of 116 examples (114 uses).

Shortest real use, from `spindle.kdl`:

```kdl
materials {
    material Ash type=hardwood
}
```

### `material`

word-valued property; node in 114 of 116 examples (309 uses); property in 34 of 116 examples (116 uses); value in 1 of 116 examples (3 uses).

Shortest real use, from `spindle.kdl`:

```kdl
material Ash type=hardwood
```

### `type`

word-valued property; property in 114 of 116 examples (309 uses).

Shortest real use, from `spindle.kdl`:

```kdl
material Ash type=hardwood
```

### `color`

property; property in 85 of 116 examples (234 uses).

Shortest real use, from `ebonised_incised_cabinet.kdl`:

```kdl
material Brass type=metal color="#b8923a"
```

### `finish`

property; property in 78 of 116 examples (147 uses).

Shortest real use, from `farmhouse_harvest_table.kdl`:

```kdl
material Pine type=softwood finish="'none'"
```

### `hardware`

word-valued property; node in 36 of 116 examples (112 uses); value in 1 of 116 examples (1 uses).

Shortest real use, from `kitchen_collections.kdl`:

```kdl
hardware @pull
```

### `hardware_use`

node in 5 of 116 examples (15 uses).

Shortest real use, from `pennsylvania_schrank.kdl`:

```kdl
hardware_use DoorLock qty=1
```

### `hardware_mount`

joinery kind; value in 35 of 116 examples (49 uses).

Shortest real use, from `step_ladder.kdl`:

```kdl
joinery hardware_mount name=TieRod { hardware TieRod_Steel }
```

### `qty`

property; property in 19 of 116 examples (34 uses).

Shortest real use, from `adirondack_plank_chair.kdl`:

```kdl
hardware WoodScrew qty=2
```

## Related terms

- [Gilt-bronze mount](/almanac/techniques#gilt-bronze-mount)
- [Hardware mount](/almanac/techniques#hardware-mount)
