---
title: "How the catalogue works"
description: "Materials, fixtures and standards — how an id resolves, why a fixture is a machining recipe rather than a mesh, and the licence."
url: https://kaicad.barpom.xyz/docs/catalogue/how-the-catalogue-works
schema: "0.1"
source: packages/catalogue/data
---

# How the catalogue works

The catalogue is the shared data a design references. You do not author it and nothing is
copied into your file — you name entries from it, and the compiler resolves them.

```yaml
catalogs:
  materials: std/lumber@1
  fixtures:  std/fixtures@1
  standards: std/standards@1
```

All three default to the bundled `std/…@1`, so this section is normally omitted.

## Three families

| Family | Ids look like | What an entry is |
| --- | --- | --- |
| **Materials** | `lumber.hardwood.s4s`, `sheet.plywood.birch` | A stock family and the sizes it is actually milled in |
| **Fixtures** | `fixtures.wood_screw.4x50` | A solid, **plus a machining recipe, plus design rules** |
| **Standards** | `standards.bed.slat_gap_max` | A published number, with its citation |

Species sit alongside materials: `walnut`, `pine`, `white_oak` and the rest carry the physical
properties that solid-lumber families inherit.

## Where each one is referenced from

```yaml
materials:
  - id: rail_stock
    from: lumber.hardwood.s4s        # ← a material family
    species: walnut                  # ← a species
    thickness: 38
    width: 190

parameters:
  - id: mattress
    type: catalog_ref
    catalog: standards.mattress      # ← a standard, as a parameter
    value: us-queen

  - id: max_slat_gap
    type: length
    derived: standards.bed.slat_gap_max   # ← a standard, in an expression

joints:
  - id: cleat_to_rail_left
    fixture: fixtures.wood_screw.4x50     # ← a fixture
```

An id that does not exist is [`RES-005`](/docs/validation/error-codes#res-005) or
[`RES-009`](/docs/validation/error-codes#res-009), and the finding lists what does — near
misses first. **Invented ids are the single most common way an LLM-authored design fails**, so
the failure is fast, specific and repairable rather than mysterious.

## A material family is not a board

`lumber.hardwood.s4s` carries nine species, seven thicknesses and eleven widths. A design
narrows it to one real board:

```yaml
- id: post_stock
  from: lumber.hardwood.s4s
  species: walnut
  thickness: 75
  width: 75
```

A combination that is not milled is rejected, and the finding names the nearest two that are.
The sizes are **actual**, never nominal — see [Solid lumber](/docs/catalogue/solid-lumber).

## A fixture is a machining recipe

This is the part that has no equivalent in any open woodworking library, and it is the reason
hardware in a kaicad design is structural rather than decorative.

A fixture entry is:

1. **A solid** — a mesh or a couple of primitives, for the 3D view. Threads are never
   modelled; a smooth shank with a head is all a preview needs and a fraction of the
   triangles.
2. **A machining recipe for its neighbours** — what to cut in the part the fastener passes
   through, and what to cut in the part it goes into. Every hole in a compiled design comes
   from one of these.
3. **The design rules it imposes** — minimum edge distance, end distance, engagement,
   spacing, and whether it may go into end grain.
4. **The dimensions it determines** — a counterbore diameter, a cross-dowel depth.

```yaml
machining:
  through_from: opposite
  through_part:
    - { kind: hole, diameter: 9, through: true }
    - { kind: counterbore, diameter: 18, depth: 8 }
  receiving_part:
    - { kind: hole, diameter: 9, depth: 100, axis: from_mating_face }
    - { kind: cross_hole, diameter: 12.5, at_depth: 80, depth: through_width }
```

The **joint** supplies the position; the **fixture** supplies the operations. You never write
a pilot hole.

### `through_from` is the field that catches people

| Value | Means |
| --- | --- |
| `mating` | The fastener enters on the face that **touches** the other part — a screw through a cleat into a rail. |
| `opposite` | It enters on the **far** face — a bed bolt through a post from the outside, counterbore and head away from the rail. |

Getting this wrong puts an 18 mm counterbore in the wrong surface and runs the clearance hole
down the length of the board instead of across it. That design compiles and exports cleanly
and cannot be built, which is why the fixture declares the direction rather than the joint
guessing it. Your side of it is the joint's
[`through:`](/docs/schema/joints#through--which-way-the-hardware-goes-in) part.

### `N * d` rules

Some rules are written against the fixture's nominal diameter:

```yaml
rules:
  min_edge_distance: "3 * d"
  min_end_distance: "6 * d"
  min_spacing: "8 * d"
```

`d` is `nominalDiameter`. For a 4 mm screw that is 12 mm from an edge, 24 mm from an end and
32 mm between screws — the usual shop rules, applied by something that does not forget them.

## A standard carries its source

```yaml
- id: standards.bed.slat_gap_max
  kind: limit
  source: >
    Consensus of mattress-maker warranty conditions (Tempur, Sealy, IKEA and
    others all specify 75–80 mm); 76 mm is the most commonly stated figure.
  limit: { value: 76, direction: max, unit: mm }
```

**`source` is required.** An uncited number is an opinion, and the whole value of this
validator is that it is not giving you opinions — when a report says a slat gap is too wide,
it can say who says so.

Four kinds:

| Kind | Shape | Example |
| --- | --- | --- |
| `dimension_set` | Named sizes | `standards.mattress.us-queen` |
| `limit` | One bound, `max` or `min` | `standards.bed.slat_gap_max` |
| `range` | `min`, `max`, `typical` | `standards.table.dining_height` |
| `rule` | A requirement in prose, with a condition | `standards.bed.centre_rail_required` |

A `dimension_set` used as a `catalog_ref` parameter behaves like the entry it names, so
`mattress.width` reads naturally. A `limit` or a `range` field can be referenced directly in
an expression.

## What is in it

| Page | |
| --- | --- |
| [Species](/docs/catalogue/species) | Fourteen timbers, with density, stiffness, movement and screw holding |
| [Solid lumber](/docs/catalogue/solid-lumber) | Three families, and every milled thickness and width |
| [Sheet goods](/docs/catalogue/sheet-goods) | Plywood, MDF and veneered MDF, with sheet sizes |
| [Wood screws](/docs/catalogue/wood-screws) | Six sizes, with pilot, clearance and countersink |
| [Bed bolts](/docs/catalogue/bed-bolts) | Four sizes, and the five holes each one cuts |
| [Knock-down hardware](/docs/catalogue/knock-down-hardware) | Threaded inserts, cam locks, dowels, shelf pins |
| [Cable management](/docs/catalogue/cable-management) | Grommets and tie mounts |
| [Standards](/docs/catalogue/standards) | Mattress sizes, slat gaps, ergonomic ranges — each cited |

Coming in v2: concealed hinges, side-mount and undermount slides, pulls and knobs, levelling
feet, and figure-8s, Z-clips and buttons.

## Licence

The catalogue is **CC0-1.0** — public domain, and meant to be adopted elsewhere. It encodes
published standard dimensions and cites vendor part numbers; it never redistributes vendor CAD
files. See [Licences](/docs/reference/licences).

If you build something else that needs to know that an M8 bed bolt wants a 12.5 mm cross bore
at 80 mm, take the data. That is what it is for.
