# Bevels & Rabbets

*Stopped mouldings on any edge, straight or vertical*

**Names:** `bevel` `rabbet` `moulding` `trim`

## When to use

- A flat slope across an edge at a chosen angle (a bevelled shelf front, a hopper side's
  mitred edge): `bevel angle=`. For a 45° corner break use `chamfer`.
- A step cut into an edge, including a **vertical** edge (the back rabbet on a standing
  carcass side, a notch at a shelf's front corner, a lipped drawer front's ends):
  `rabbet face= edge=`.
- A profile (`ovolo`, `cove`, `ogee`, ...) that starts and ends part-way along an edge:
  `moulding ... stopped=#true`.
- `trim` aligns a raked end to a plane fixed in **world** space (`reference=world`) or in
  the **nearest enclosing assembly**'s own frame (`reference=assembly`, #458).

## Syntax

```kdl grammar
bevel  angle=<deg 1..<90> [depth=<mm>] { edges <edge>... }      // or:
bevel  face=<face> edge=<adjacent face> angle=<deg> [depth=<mm>]
rabbet width=<mm> depth=<mm> { edges <edge>... }                // or:
rabbet face=<face> edge=<adjacent face> width=<mm> depth=<mm>
       [stopped=#true start=<mm> run_length=<mm>]
moulding section=<ovolo|cove|ogee|thumbnail|half_round|cockbead> size=<mm>
       [stopped=#true start=<mm> run_length=<mm> stop=square|ramp] { edges <edge>... }
```

- `face=` is the face the cut goes into and the angle or width is measured on; `edge=` is an
  adjacent face (not `face`, not its opposite). Faces are `pos_x neg_x pos_y neg_y pos_z neg_z`.
  Use `face=`/`edge=` **or** `{ edges }`, never both.
- Bevel `depth=` defaults to the whole thickness across `face`; the facet is
  `depth / tan(angle)` wide on `face`.
- Rabbet `width` is measured on `face` from `edge`; `depth` goes into `face`.
- Stops: `start=` defaults to 10 mm in; `start=0.0` reaches the end of the edge; omit
  `run_length=` to run out through the far end. `bevel` takes `stop=square|ramp|lambs_tongue`,
  `moulding` takes `square|ramp`, `rabbet` is square-ended only.

## Example

```kdl
project name="Bevel and rabbet" units=mm schema_version=1 {
    materials { material Oak type=hardwood }

    component Side {
        stock Oak 20.0 300.0 600.0
        // Back rabbet on the standing side: the vertical edge where pos_x meets pos_y.
        rabbet face=pos_x edge=pos_y width=18.0 depth=6.0
    }

    component Shelf {
        stock Oak 400.0 250.0 20.0
        // A 35 degree bevel across the front edge, the whole thickness.
        bevel angle=35.0 {
            edges top_s
        }
        // A cove that stops 50mm in from each end of the back edge.
        moulding section=cove size=5.0 stopped=#true start=50.0 run_length=300.0 {
            edges top_n
        }
    }

    assembly Piece {
        part Side instance=Side { pos x=0.0 y=0.0 z=0.0 }
        part Shelf instance=Shelf { pos x=40.0 y=0.0 z=0.0 }
    }
}
```

## Pitfalls and diagnostics

- `angle` outside `[1, 90)` is `ww::build::bad_value`, a missing `angle` is a missing-property
  error. A facet wider than the face, a `depth` thicker than the board, `face=` without
  `edge=` (error) or with `{ edges }` (skip, "not both"), non-adjacent faces ("adjacent"),
  and `stop=` without `stopped=` are skips naming the cause: the built part simply has no
  such cut, so read the skipped list, not just the green tick.
- `upright_*` in `{ edges }` is skipped for `bevel` and `rabbet`. Use `face=`/`edge=`.
- `stop=ramp` on a `rabbet` is a skip ("square"); `stop=lambs_tongue` is for `chamfer` and
  `bevel` only.
- A stopped `moulding` is a 32-layer staircase: it never removes more than the true section
  and falls under 7% short of its volume. Do not expect a smooth curve at the run's ends.
- A through `rabbet face= edge=` that a dovetail socket or other join opens into is
  understood by the join (it is lowered as a housing on `face`); write it, rather than a
  groove at the edge of the face.
- `trim reference=assembly` is built (#458): the nearest enclosing `instance=`-placed
  assembly's own frame, identity (same as `reference=world`) when there is none. A
  `reference=` naming neither `world` nor `assembly` is a named skip.

## See also

- `docs/KDL_AUTHORING.md` section 7, "Bevel, and a rabbet on any edge" and "Moulding profiles"
- `docs/rfc/0143-bevel-and-stopped-mouldings.md`, `docs/adr/0024-bevel-rabbet-stopped-mouldings.md`
- RFC-0051 (rabbet on any edge), RFC-0126 (mouldings), RFC-0025 (stopped chamfers), RFC-0024
  (`trim`)
- Examples: `examples/bedside_cabinet.kdl`, `examples/welsh_dresser.kdl`,
  `examples/wall_shelf.kdl`, `examples/dining_chair.kdl`; `docs/styles/models/bevel.kdl`

## Names

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

### `bevel`

feature; node in 6 of 116 examples (16 uses).

Shortest real use, from `jacobean_joined_chest.kdl`:

```kdl
bevel face=pos_y edge=pos_z angle=10.0 depth=bevel_depth
```

### `rabbet`

feature; node in 24 of 116 examples (56 uses).

Shortest real use, from `tall_white_cutout_cabinet.kdl`:

```kdl
rabbet face=pos_x edge=pos_y width=back_th depth=rd
```

### `moulding`

feature; node in 18 of 116 examples (36 uses); value in 2 of 116 examples (4 uses).

Shortest real use, from `farmhouse_harvest_table.kdl`:

```kdl
moulding section=thumbnail size=6.0 {
    edges top_s
}
```

### `trim`

feature; node in 5 of 116 examples (7 uses); value in 1 of 116 examples (1 uses).

Shortest real use, from `mid_century_credenza.kdl`:

```kdl
trim reference=world normal=pos_z at=floor_z {
    faces pos_x
}
```

## Related terms

- [Bevel](/almanac/techniques#bevel)
- [Rabbet](/almanac/techniques#rabbet)
