# Reuse & Collections

*Import, collections, choices, and slots*

**Names:** `import` `from` `export` `collection` `extends` `choice` `slots` `style` `requires` `kind` `construction`

## When to use

- **`import`** to use another file's assembly or component, or the built-in drawer
  (`std:drawer`).
- **`collection`** when one design must come in several "looks" or standards (a US base
  height vs a slab-front frameless kitchen) without forking the file: standards as `params`,
  word-valued settings as `choice`, and role names (`slots`) bound to materials, hardware,
  components or assemblies.

## Syntax

```text
import <Alias> from="lib/x.kdl" export=<Name>[,<Name>]      // or from="std:drawer"
project name="..." units=mm collection=<Name> {
    collection <Name> [extends=<Base>] {
        params { <name> <default> ... }                   // read as coll_<name>
        choice <n>=<word> { <word> <word> ... }           // read as coll_<n>_is_<word> (0 or 1)
        slots { <role> <material|hardware|component|assembly> <Target> [requires="p q"]
                <role> <Target> }                          // a derived collection rebinds
    }
}
```

- **Import:** one line; both values plain text. `from=` is relative to the importing file's
  directory (CLI: inside the entry file's directory only, no absolute paths, no `..`, `.kdl`
  only). `export=` is a comma-separated list; omitted, it takes everything the file offers.
  The imported file marks what it offers with `assembly Name export=Name { ... }`. A file
  resolves in its **own** scope: an imported drawer sees the drawer file's params, never the
  importer's. Override at the instance: child nodes on the `part` (`width 800.0`) set the
  *assembly's own* params. Imported top-level assemblies are templates, never scene roots.
- **`std:drawer`** is built in, works in the browser and on a server: `DrawerBox`, a box-jointed
  Baltic-birch drawer box; params `width` `depth` `height` (outside size; origin the top
  face's south-west corner).
- **Collections:** `project ... collection=Name` selects the one in force; there is no default.
  `extends=Base` merges root-first, a derived collection overriding only keys the base
  declares. `choice n=word { words }` is project-level only; with `n` = `construction` and
  words `face_frame frameless` the params are `coll_construction_is_face_frame` and
  `coll_construction_is_frameless`; branch with `repeat _ count=coll_construction_is_face_frame {...}`.
  **Slots** are declared once in the base as `name kind Target [requires="p1 p2"]`; used as
  `@name` wherever a material, hardware, component or assembly name goes (`stock @carcass ...`,
  `part Door instance=@door {...}`, `hardware_use @pull qty=1`, joinery, `finish`).
  `requires=` lists the params a bound component must declare, checked for every
  collection's slots whether in force or not.
- Materials, hardware and joinery are one global catalogue by name across imports, but an
  imported entry is evaluated in its **own file's** scope.

## Example

```kdl
project name="Kitchen Cabinet" units=mm schema_version=1 collection=SlabFrameless {
    import DrawerBox from="std:drawer" export=DrawerBox
    collection UsBase {
        params {
            base_h (in)34.5
            reveal (in)0.125
        }
        choice construction=face_frame { face_frame frameless }
        slots {
            carcass material CarcassPly
        }
    }
    collection SlabFrameless extends=UsBase {
        params { base_h (in)36 }
        choice construction=frameless
    }
    materials { material CarcassPly type=sheet nominal_th=18.0 finished_th=17.6 }
    assembly Cabinet {
        part Side material=@carcass role=side {
            stock @carcass 560.0 "coll_base_h" 17.6
            by top_sw
            pos x=0.0 y=0.0 z=0.0
        }
        part Drawer instance=DrawerBox width=400.0 depth=450.0 height=120.0 {
            by top_sw
            pos x=20.0 y=0.0 z=-100.0
        }
    }
}
```

## Pitfalls and diagnostics

- Diagnostics: `ww::dsl::collection_unknown_key` (a derived collection sets a key the base lacks),
  `collection_cycle`, `unknown_collection`, `bad_choice`, `slot_contract` (a bound component
  lacks a `requires=` param, reported at the slot line), `unknown_slot` (`@x` with no
  collection in force or naming no slot).
- Import diagnostics: `import_cycle`, `import_too_deep`, `too_many_imports`, `unknown_export`,
  `import_conflict` (a same-name material/hardware/joinery that differs, or reads a param so
  means something different in each file). Diagnostics inside an imported file name that file
  and count from its own line 1 (`lib/bad.kdl:7:15`).
- Limits (documented, not defects): collections are local to the file (not importable);
  `coll_*` params are not visible inside imported components; **computed values cannot be
  exported** (only assemblies and components); `ww` author edits (`join`, marks, joinery)
  refuse targets inside an imported file.
- Imported parts appear with mangled names (`DrawerBox.DrawerBoxEnd~Wide.Bottom.Front`).
- `style` here is the project/collection look; the *style rules* a finish or style file applies
  are a separate family (see `INDEX.md`).

## See also

- `docs/KDL_AUTHORING.md` §14 (`import`), §16 (collections); ADR-0020 (import), ADR-0021.
- `examples/kitchen_collections.kdl` (a three-unit kitchen; the second collection is ten lines).
- `parts-and-assemblies.md` (instance overrides), `materials-and-hardware.md`.

## Names

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

### `import`

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

Shortest real use, from `drawer_stack.kdl`:

```kdl
import DrawerBox from="std:drawer" export=DrawerBox
```

### `from`

word-valued property; property in 7 of 116 examples (11 uses).

Shortest real use, from `drawer_stack.kdl`:

```kdl
import DrawerBox from="std:drawer" export=DrawerBox
```

### `export`

word-valued property; property in 5 of 116 examples (10 uses).

Shortest real use, from `drawer_stack.kdl`:

```kdl
import DrawerBox from="std:drawer" export=DrawerBox
```

### `collection`

project-level node, word-valued property; node in 1 of 116 examples (3 uses); property in 1 of 116 examples (1 uses).

Shortest real use, from `kitchen_collections.kdl`:

```kdl
collection ShakerFaceFrame extends=UsBase style=traditional-shaker {
}
```

### `extends`

word-valued property; property in 1 of 116 examples (2 uses).

Shortest real use, from `kitchen_collections.kdl`:

```kdl
collection ShakerFaceFrame extends=UsBase style=traditional-shaker {
}
```

### `choice`

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

Shortest real use, from `kitchen_collections.kdl`:

```kdl
choice construction=frameless
```

### `slots`

node in 1 of 116 examples (2 uses).

Shortest real use, from `kitchen_collections.kdl`:

```kdl
slots {
    carcass CarcassPly
    door    Door_Slab
    front   WalnutPly
    pull    Knob_1_25
}
```

### `style`

word-valued property; property in 1 of 116 examples (2 uses).

Shortest real use, from `kitchen_collections.kdl`:

```kdl
collection ShakerFaceFrame extends=UsBase style=traditional-shaker {
}
```

### `requires`

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

Shortest real use, from `kitchen_collections.kdl`:

```kdl
door       component Door_Shaker requires="dw dh pull_x pull_y"
```

### `kind`

word-valued property; property in 4 of 116 examples (5 uses).

Shortest real use, from `welsh_dresser.kdl`:

```kdl
travel kind=angle axis=z body=assembly pivot=Pin_Back
```

### `construction`

property; property in 1 of 116 examples (2 uses).

Shortest real use, from `kitchen_collections.kdl`:

```kdl
choice construction=frameless
```

## Related terms

- [Bridle joint](/almanac/techniques#bridle-joint)
