# Tenon Joinery

*Mortise-and-tenon and round tenon: haunch, through, proud, pin, wedge, key, and oblique*

**Names:** `mortise_and_tenon` `round_tenon` `tenon_thickness` `tenon_width` `tenon_length` `haunch` `centering` `through` `proud` `end_chamfer` `pin` `wedge` `key` `taper_to` `draw` `enter` `ends_proud`

## When to use

A rail or rung that enters a leg or post: the strong, traditional frame joint. Use
`mortise_and_tenon` for a rectangular tenon (aprons, rails, stretchers) and `round_tenon` for a
turned member (a chair rung, a spindle) into a bored socket. The marks, `join` and the common
layout rule are in `joinery-contract`.

## Syntax

```text
joinery mortise_and_tenon name=<N> {
    tenon_thickness <mm>  [tenon_length <mm>]  clearance <mm>
    [tenon_width <mm>]  [haunch length=<mm> depth=<mm>]  [centering axis=<x|y|z>]
    [through #true  [proud <mm>]  [end_chamfer <mm>]]
    [pin shape=round|square size= draw= count= spacing= [taper= at= enter= ends_proud= material= label=]]
    [wedge count= kerf= depth= flare= flare_depth= [material= label=]]
    [key size= thickness= taper= [draw= ends_proud= material= label=]]
}
joinery round_tenon name=<N> { diameter <mm>  length <mm>  [taper_to <mm>]  clearance <mm> }
```

- **Layout.** The male mark sits on the **shoulder**, the end of the male's stock line. The
  tenon is **added** outside it, `tenon_length` long (the stock line stays shoulder to
  shoulder; the stock list buys the blank longer). `tenon_thickness` runs across the
  shoulder's narrower side, centred on the mark. Along the wider side the tenon is
  `tenon_width` wide, or without it leaves **equal shoulders all round**. The female mark names
  the face the tenon enters; the mortise is the tenon grown by `clearance / 2` per face.
- **Thickness axis.** Always the smaller of the shoulder's two extents (exactly square: the
  first axis), never chosen by `tenon_width` or `haunch`. Within 2 % of square but not exactly square, with a
  `tenon_width`/`haunch` the compiler warns `tenon-axis` and names the side it took; make the
  stock differ by more to get the other orientation.
- **On a `cut_path keep="inside"` part** the tenon stands on the end face the outline leaves
  (stepped or short faces included); none left is a `material` error naming the outline.
- **`clearance 0`** is fine; round sockets are floored just above tessellation so they still clear.
- **Blind or through.** A tenon that reaches the far face is through; what would stand proud is
  cut flush by default. `through #true` asserts it and, with `tenon_length` omitted, computes
  the length to reach the far face exactly, so a resize cannot silently turn it blind.
- **`proud`** moves the flush-trim plane out (needs a through tenon). **`end_chamfer`** needs
  `proud` greater than zero, less than `proud` and less than a quarter of `tenon_thickness`.
- **`haunch length= depth=`**: the `length` of the tenon's width toward the nearer end of the
  mortised part stands only `depth` off the shoulder, and the mortise steps with it.
- **`centering axis=`** names a male axis the mark must be centred on (checked).
- **`pin`** (drawbore): a peg driven across the tenon's thickness through both parts, the
  tenon's hole displaced `draw` toward the shoulder. `shape` `round` (default) or `square`;
  `size` is the diameter (or square side, required); `count`/`spacing` spread pins across the
  tenon width. `at` is the pin's distance from the shoulder (default: half the female's
  thickness for a through tenon, else half the tenon's length). `taper` makes a square pin
  tapered, and `enter` (a male-local face word on the pin's axis, e.g. `pos_z`) names the cheek
  it is driven in from, so the small end leaves from the other. It makes its own **generated part** `<male>@<mark>/Pin_<k>`: no `part`,
  `mark` or `join` names it. Needs both parts square to one another (multiple of 90 degrees).
- **`wedge`** (wari-kusabi): needs `through #true`. `count` saw kerfs `kerf` wide and `depth`
  deep from the tenon's end, a flared mouth on the female's exit face (`flare` at most a
  quarter of `flare_depth`). Generated parts `<male>@<mark>/Wedge_<k>`. A `pin` and a `wedge`
  on one joint must not cross (`pin-wedge-clash`).
- **`key`** (tusk tenon): needs `through #true` with `proud` large enough (`key-relish`). A
  mortise `size` by `thickness` cut through the tenon's **width**; `size`, `thickness` and
  `taper` required, `draw` defaults to `1.5`. Generated part `<male>@<mark>/Key_0`.
- **Oblique shoulder.** The tenon runs along the male's shoulder normal as placed and may meet
  the female face up to 45 degrees off square (`MAX_OBLIQUE`): a raked leg, a dished spoke. The
  mortise **leans** with the tenon and the shoulder is scribed to the face all round.
- **`round_tenon`**: a bored round socket and a cylindrical tenon. Clearance is on the socket
  only; the tenon is cut at nominal `diameter` even when `taper_to` (its tip diameter, less than
  `diameter`) makes it a cone. **An oblique round tenon is built**: the socket leans up to the
  same 45 degree limit (RFC-0127, closed 2026-09-28). `docs/KDL_AUTHORING.md` §8 still says
  it is "square-shouldered only"; that sentence is stale, and the source and the RFC status
  line are right.

## Example

```kdl
project name="Tenons" units=mm schema_version=1 {
    params {
        glue_clearance 0.2
        leg_dim 45.0
    }
    materials { material Oak type=hardwood }
    component Leg role=leg {
        stock Oak leg_dim leg_dim 700.0
        mark Face_A x=leg_dim y="leg_dim / 2.0" z=-100.0 normal=pos_x
        mark Face_B x=leg_dim y="leg_dim / 2.0" z=-300.0 normal=pos_x
        mark Face_C x=leg_dim y="leg_dim / 2.0" z=-500.0 normal=pos_x
    }
    component Rail role=rail {
        // runs along x; its end face at x=0 is the shoulder
        stock Oak 400.0 20.0 80.0
        mark Shoulder x=0.0 y=10.0 z=-40.0 normal=neg_x
    }
    component Rung role=rung {
        stock Oak 300.0 30.0 30.0
        mark Shoulder x=0.0 y=15.0 z=-15.0 normal=neg_x
    }
    joinery mortise_and_tenon name=HaunchedJoint {
        tenon_thickness 8.0
        tenon_length 25.0
        clearance glue_clearance
        haunch length=12.0 depth=10.0
        centering axis=z
    }
    joinery mortise_and_tenon name=DrawboredJoint {
        tenon_thickness 8.0
        through #true
        proud 4.0
        end_chamfer 1.0
        clearance glue_clearance
        pin shape=round size=2.5 draw=1.0 count=1
    }
    joinery round_tenon name=RungJoint {
        diameter 16.0
        length 30.0
        taper_to 12.0
        clearance 0.3
    }
    assembly Frame {
        part Leg_A instance=Leg { by top_sw; pos x=0.0 y=0.0 z=0.0 }
        part Rail_A instance=Rail { by top_sw; pos x=45.0 y=12.5 z=-60.0 }
        part Rail_B instance=Rail { by top_sw; pos x=45.0 y=12.5 z=-260.0 }
        part Rung_A instance=Rung { by top_sw; pos x=45.0 y=7.5 z=-485.0 }
        join joint=HaunchedJoint male=Rail_A@Shoulder female=Leg_A@Face_A
        join joint=DrawboredJoint male=Rail_B@Shoulder female=Leg_A@Face_B
        join joint=RungJoint male=Rung_A@Shoulder female=Leg_A@Face_C
    }
}
```

## Pitfalls and diagnostics

- **Refused:** a tenon as thick as its stock; a tenon or `tenon_width` off its shoulder; a
  mortise running off the female face; a blind mortise the clearance breaks through; a haunch
  as wide or long as the tenon or with no nearer end; a shoulder more than 45 degrees off
  square or off the face; and **two tenons meeting inside one part** (`tenons-meet`: two
  aprons into one leg at one height: stop each short of the other, or see `INDEX.md` for
  mitred tips).
- `pin`, `wedge` and `key` each need the square, axis-aligned frame (`pin-frame`,
  `wedge-frame`, `key-frame`: unsupported otherwise). `wedge-grain`, `wedge-flare`,
  `wedge-kerf`, `key-relish` and `key-mortise` name the specific refusal.
- A pin much thicker than a third of the tenon warns (`pin-size`): typical is a quarter to a
  third.
- The mortise and tenon are modelled square-cornered; a router's corner radius is a
  fabrication question.
- `round_tenon` refuses a `taper_to` not less than `diameter` and any socket or tenon that
  would run past its face's edge. Tenon the round part's flat end, not its curved surface.
- A mark on a curved turned surface is not reachable; tenon into a square pommel
  (`round-stock-sections`).
- **Stale elsewhere:** `docs/KDL_AUTHORING.md` §8 ("Square-shouldered only", "Refused: the
  shoulder off square by any amount" under `round_tenon`) predates the oblique build. Trust
  this file and `crates/ww-build/src/joinery/round_tenon.rs`.

## See also

- `docs/KDL_AUTHORING.md` §8 ("Tenons, laps, bridles and mitres"); RFC-0090 (pin, wedge),
  RFC-0125 (key), RFC-0127 (round tenon), RFC-0022 (oriented marks); ADR-0013.
- `examples/desk.kdl`, `examples/dining_table.kdl`, `examples/trestle_table.kdl`,
  `examples/wagon_wheel.kdl`, `examples/three_legged_stool.kdl`.
- `joinery-contract.md`, `joinery-laps-and-boxes.md`, `joinery-frames.md`,
  `round-stock-sections.md`, `components-and-stock.md` (`tilt=`/`heading=` marks).

## Names

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

### `mortise_and_tenon`

joinery kind; value in 80 of 116 examples (186 uses).

Shortest real use, from `incised_walnut_washstand.kdl`:

```kdl
joinery mortise_and_tenon name=TopTenon {
    tenon_thickness 12.0
    tenon_length 10.0
    clearance glue_clearance
}
```

### `round_tenon`

joinery kind; value in 22 of 116 examples (40 uses).

Shortest real use, from `appalachian_ladder_back_side_chair.kdl`:

```kdl
joinery round_tenon name=RungJ {
    diameter 15.0
    length 26.0
    clearance 0.4
}
```

### `tenon_thickness`

node in 80 of 116 examples (190 uses); value in 4 of 116 examples (8 uses).

Shortest real use, from `appalachian_ladder_back_side_chair.kdl`:

```kdl
tenon_thickness 8.0
```

### `tenon_width`

node in 54 of 116 examples (120 uses); value in 1 of 116 examples (1 uses).

Shortest real use, from `pasadena_library_table.kdl`:

```kdl
tenon_width tw
```

### `tenon_length`

node in 69 of 116 examples (152 uses); value in 3 of 116 examples (6 uses).

Shortest real use, from `high_back_ladder_chair.kdl`:

```kdl
tenon_length 8.0
```

### `haunch`

node in 6 of 116 examples (9 uses).

Shortest real use, from `filing_cabinet_vertical.kdl`:

```kdl
haunch length=6.0 depth=5.0
```

### `centering`

node in 36 of 116 examples (68 uses).

Shortest real use, from `arched_crest_side_chair.kdl`:

```kdl
centering axis=z
```

### `through`

node in 20 of 116 examples (38 uses).

Shortest real use, from `danish_oak_dining_table.kdl`:

```kdl
through #true
```

### `proud`

node in 14 of 116 examples (29 uses); value in 2 of 116 examples (2 uses).

Shortest real use, from `pasadena_bedside_chest.kdl`:

```kdl
proud tenon_proud
```

### `end_chamfer`

node in 11 of 116 examples (20 uses).

Shortest real use, from `pasadena_bedside_chest.kdl`:

```kdl
end_chamfer 1.0
```

### `pin`

node in 19 of 116 examples (35 uses).

Shortest real use, from `appalachian_ladder_back_side_chair.kdl`:

```kdl
pin shape=round size=3.0
```

### `wedge`

node in 6 of 116 examples (8 uses).

Shortest real use, from `wedged_post_and_rung_stool.kdl`:

```kdl
wedge kerf=3.0 depth=18.0 flare=2.0 flare_depth=10.0
```

### `key`

node in 2 of 116 examples (2 uses); value in 1 of 116 examples (1 uses).

Shortest real use, from `mission_keyed_bookcase.kdl`:

```kdl
key size=key_size thickness=key_thickness taper=key_taper draw=key_draw \
    ends_proud=key_ends_proud label="Key"
```

### `taper_to`

node in 2 of 116 examples (10 uses).

Shortest real use, from `windsor_fan_back_side_chair.kdl`:

```kdl
taper_to 9.0
```

### `draw`

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

Shortest real use, from `danish_oak_dining_table.kdl`:

```kdl
pin shape=round size=peg_size draw=peg_draw count=1
```

### `enter`

word-valued property; not used by any example yet.

### `ends_proud`

property; property in 9 of 116 examples (18 uses).

Shortest real use, from `arts_crafts_cabinet_on_stand.kdl`:

```kdl
pin shape=round size=peg_size draw=1.0 count=1 ends_proud=0.0 label="Peg"
```

## Related terms

- [Bridle joint](/almanac/techniques#bridle-joint)
- [Chamfer](/almanac/techniques#chamfer)
- [Domino joint](/almanac/techniques#domino-joint)
- [Drawbore](/almanac/techniques#drawbore)
- [Haunch](/almanac/techniques#haunch)
- [Kusabi](/almanac/techniques#kusabi)
- [Mortise and tenon](/almanac/techniques#mortise-and-tenon)
- [Peg](/almanac/techniques#peg)
- [Round tenon](/almanac/techniques#round-tenon)
- [Shoulder](/almanac/techniques#shoulder)
- [Stopped chamfer](/almanac/techniques#stopped-chamfer)
- [Taper](/almanac/techniques#taper)
- [Through dovetail](/almanac/techniques#through-dovetail)
- [Through tenon](/almanac/techniques#through-tenon)
- [Tusk tenon](/almanac/techniques#tusk-tenon)
- [Wedged tenon](/almanac/techniques#wedged-tenon)
