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#
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.angleis 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, soclearanceis unused. -
stile_and_rail: both parts declare agroove target=panel(a part feature; seeedge-and-face-cuts) with the samegroove_widthandgroove_depthas 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 isgroove_widththick,stub_tenon_lengthlong, from the edge nearer the stile's end to the rail's own panel groove (cut backgroove_depththere, 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; checkINDEX.mdfor a newer file that adds it. -
mitred_moulding:anglemeans the same thingmiter's own does, and the marks sit on the two members' ends the same way.profile/profile_size/profile_facearestile_and_rail's own three (the six moulding sections,tenon-tips-wedges-and-coped-railshas 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 exactlyjoinery miter's own geometry. Which side face carries the moulding (its "inside" edge, oppositeprofile_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 faceprofile_faceresolves to.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#
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#
anglemust match the corner: two boards meeting at 90 degrees are each cut 45. A mismatch reads "angleis 30.0, butFrontandSidemeet at 90.0, which a mitre halves".angleis 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_railwithout the parts' own grooves has nothing for the stub tenon to fill: declaregroove target=panel ...on both parts first, matching the joint'sgroove_widthandgroove_depth. Aprofileother 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'sMuntinTenonJoint), andcross_lapwhere two muntins cross. mitred_moulding's own checks:params/cope-profile(a stuckprofileneedsprofile_sizeandprofile_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 forprofile_faceto resolve at all, so this combination never reaches the chord-by-chord mirror checkprofile "square"reuses frommiter'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 syntaxmitred_mouldingreuses).
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:
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:
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:
angle 45.0
groove_width#
node in 9 of 116 examples (9 uses).
Shortest real use, from arts_crafts_cabinet_on_stand.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:
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:
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:
profile "square"