# Frame Joinery

*Mitred corners and stile-and-rail panel frames*

**Names:** `miter` `stile_and_rail` `mitred_moulding` `angle` `groove_width` `groove_depth` `stub_tenon_length` `profile`

## When to use

- `miter`: two boards that meet at a corner, both cut back to the plane bisecting it (a plinth,
  a picture frame, a box lid rim).
- `stile_and_rail`: the corner of a **panel frame** (a door, a lid frame, a cabinet back) where
  a rail meets a stile and both carry a panel groove. The rail gets a stub tenon that fills the
  stile's groove.
- `mitred_moulding` (#460): a mitred corner — `miter`'s own two symmetric ends, no T, no cope —
  where **both** members also carry the same stuck profile the whole way to the corner, so the
  moulding runs on round it (a door's own moulded frame corner, not a panel-frame T-joint).

For a rail into a leg without a panel groove, use `mortise_and_tenon` (`joinery-tenons`). The
marks, `join` and the layout rule are in `joinery-contract`.

## Syntax

```text
joinery miter          name=<N> { angle <deg> }
joinery stile_and_rail name=<N> {
    groove_width <mm>  groove_depth <mm>  stub_tenon_length <mm>  [profile "square"]
}
```

- **`miter`**: the marks sit on the two boards' **ends**, facing out along each board. Both
  boards run **full length to the corner's outer edge**, so the two end faces meet in that
  edge; each is cut back to the plane bisecting it. `angle` is each end's cut off square, as a
  mitre saw reads it: 45 for a square corner, 30 for a hexagon's. It is **checked against the
  placement**: the declaration and the corner disagree is an error. A mitre has no cavity, so
  `clearance` is unused.
- **`stile_and_rail`**: both parts declare a `groove target=panel` (a part feature; see
  `edge-and-face-cuts`) with the same `groove_width` and `groove_depth` as the joint. The
  rail's male mark sits on its **end**, the stile's female mark on the face the rail meets. The
  stub tenon is `groove_width` thick, `stub_tenon_length` long, from the edge nearer the
  stile's end to the rail's own panel groove (cut back `groove_depth` there, so the panel runs
  on past it), into the stile's groove.
- **`profile`**: only `"square"` (flat sticking), which is also the default. Any other value is
  reported unsupported. A stuck moulding with coped shoulders is not synthesised by this joint
  as built here; check `INDEX.md` for a newer file that adds it.
- **`mitred_moulding`**: `angle` means the same thing `miter`'s own does, and the marks sit on
  the two members' ends the same way. `profile`/`profile_size`/`profile_face` are
  `stile_and_rail`'s own three (the six moulding sections, `tenon-tips-wedges-and-coped-rails`
  has the full syntax). Both members are stuck the whole length, then both are mitred — the
  mitre cuts through the sticking, not a plain box. `profile "square"` degenerates to exactly
  `joinery miter`'s own geometry. Which side face carries the moulding (its "inside" edge,
  opposite `profile_face`'s own show face) is **not** a parameter: it is derived from the
  corner itself (the width-axis face farther from the mitre's own outer edge) — place the
  components so it lands where intended, the same way placement already decides which face
  `profile_face` resolves to.

  ```text
  joinery mitred_moulding name=<N> {
      angle <deg>
      profile "ogee"           // ovolo cove ogee thumbnail half_round cockbead; "square" is flat
      profile_size <mm>
      profile_face "'neg_y'"   // pos_x neg_x pos_y neg_y pos_z neg_z
  }
  ```

## Example

```kdl
project name="Frames" units=mm schema_version=1 {
    params { glue_clearance 0.2 }
    materials { material Oak type=hardwood }
    component Board role=board {
        stock Oak 300.0 20.0 60.0
        mark End x=0.0 y=10.0 z=-30.0 normal=neg_x
    }
    component Stile role=stile {
        stock Oak 60.0 20.0 400.0
        groove target=panel face=pos_x width=6.0 depth=10.0 offset=7.0
        mark Seat x=60.0 y=10.0 z=-30.0 normal=pos_x
    }
    component Rail role=rail {
        stock Oak 300.0 20.0 60.0
        groove target=panel face=neg_z width=6.0 depth=10.0 offset=7.0
        mark End x=0.0 y=10.0 z=-30.0 normal=neg_x
    }
    joinery miter name=Corner {
        angle 45.0
    }
    joinery stile_and_rail name=FrameCorner {
        groove_width 6.0
        groove_depth 10.0
        stub_tenon_length 10.0
        profile "square"
    }
    assembly Frames {
        part Front instance=Board { by top_sw; pos x=0.0 y=1000.0 z=0.0 }
        part Side instance=Board { by top_nw; pos x=0.0 y=1000.0 z=0.0; rot z=90.0 }
        join joint=Corner male=Front@End female=Side@End

        part Stile_A instance=Stile { by top_sw; pos x=0.0 y=1500.0 z=0.0 }
        part Rail_A instance=Rail { by top_sw; pos x=60.0 y=1500.0 z=0.0 }
        join joint=FrameCorner male=Rail_A@End female=Stile_A@Seat
    }
}
```

## Pitfalls and diagnostics

- **`angle` must match the corner**: two boards meeting at 90 degrees are each cut 45. A
  mismatch reads "`angle` is 30.0, but `Front` and `Side` meet at 90.0, which a mitre halves".
  `angle` is in the range 1 to 89.
- **A compound mitre** (boards that lean as well as turn, a splayed box) is reported
  unsupported (`corner`, RFC-0022); so are ends that do not meet in a corner edge, or a plane
  that misses a board or cuts it through its length.
- **A mitre's boards must both run to the outer edge.** Writing one short of the corner
  leaves the bisecting plane missing it.
- **`stile_and_rail` without the parts' own grooves** has nothing for the stub tenon to fill:
  declare `groove target=panel ...` on both parts first, matching the joint's `groove_width`
  and `groove_depth`. A `profile` other than `"square"` is reported unsupported.
- A muntin or mid-rail into the **middle** of a stile is a T, not a corner: use a plain
  `mortise_and_tenon` (`panel_door_and_window.kdl`'s `MuntinTenonJoint`), and `cross_lap` where
  two muntins cross.
- **`mitred_moulding`'s own checks**: `params`/`cope-profile` (a stuck `profile` needs
  `profile_size` and `profile_face`; an unknown profile or face word is named; a sticking
  deeper than half the member's own width, on either end). `corner` — a stuck profile on a
  genuinely compound corner (a member leaning as well as turning) is refused: no side face of
  a leaning member lines up with any world direction for `profile_face` to resolve at all, so
  this combination never reaches the chord-by-chord mirror check `profile "square"` reuses
  from `miter`'s own compound-mitre handling unchanged.

## See also

- `docs/KDL_AUTHORING.md` §8 (`stile_and_rail`, `miter`, `mitred_moulding`); ADR-0013;
  RFC-0022 (oriented marks, compound mitres).
- `examples/blanket_chest.kdl` (`PlinthMiter`, `LidFrameJoint`),
  `examples/filing_cabinet_lateral.kdl` (`PlinthMiter`), `examples/welsh_dresser.kdl`
  (`DoorFrameJoint`), `examples/panel_door_and_window.kdl`,
  `docs/styles/models/mitred-moulding-corner.kdl` (#460).
- `joinery-contract.md`, `joinery-tenons.md`, `joinery-laps-and-boxes.md`,
  `edge-and-face-cuts.md` (grooves, mouldings),
  `tenon-tips-wedges-and-coped-rails.md` (the stuck-profile syntax `mitred_moulding` reuses).

## Names

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

### `miter`

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

Shortest real use, from `serpentine_chest_bracket_feet.kdl`:

```kdl
joinery miter name=FootMiter {
    angle 45.0
}
```

### `stile_and_rail`

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

Shortest real use, from `ebonised_incised_cabinet.kdl`:

```kdl
joinery stile_and_rail name=PanelFrame {
    groove_width panel_th
    groove_depth groove_d
    stub_tenon_length stub_l
    profile "square"
}
```

### `mitred_moulding`

joinery kind; not used by any example yet.

### `angle`

property; node in 6 of 116 examples (6 uses); property in 10 of 116 examples (22 uses); value in 2 of 116 examples (3 uses).

Shortest real use, from `blanket_chest.kdl`:

```kdl
angle 45.0
```

### `groove_width`

node in 9 of 116 examples (9 uses).

Shortest real use, from `arts_crafts_cabinet_on_stand.kdl`:

```kdl
groove_width panel_th
```

### `groove_depth`

node in 16 of 116 examples (16 uses); value in 7 of 116 examples (23 uses).

Shortest real use, from `acrylic_panel_frame.kdl`:

```kdl
groove_depth 8.0
```

### `stub_tenon_length`

node in 9 of 116 examples (9 uses).

Shortest real use, from `arts_crafts_cabinet_on_stand.kdl`:

```kdl
stub_tenon_length 10.0
```

### `profile`

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

Shortest real use, from `arts_crafts_cabinet_on_stand.kdl`:

```kdl
profile "square"
```

## Related terms

- [Compound mitre](/almanac/techniques#compound-mitre)
- [Groove](/almanac/techniques#groove)
- [Mitre joint](/almanac/techniques#mitre-joint)
- [Mitred moulding corner](/almanac/techniques#mitred-moulding-corner)
- [Mortise and tenon](/almanac/techniques#mortise-and-tenon)
- [Rail](/almanac/techniques#rail)
- [Round tenon](/almanac/techniques#round-tenon)
- [Stile](/almanac/techniques#stile)
- [Stile-and-rail joint](/almanac/techniques#stile-and-rail)
- [Tongue and groove](/almanac/techniques#tongue-and-groove)
