Cabinet door¶
projects.cabinet_door
A small cabinet door of 2 x 3 cm stock with mitred shoulder tenons, a plywood panel below the middle rail and a glass one above; outside sizes.
Two stiles, a top, a middle and a bottom rail. A groove runs through
along the inside edges of all of them, centered in the thickness, the
panels as thick as it is wide. Each rail reaches mitre_depth into a
notch in the stile, mitred at 45 degrees at its inside edges, where the
grooves meet like in a mitred frame; the notch is deeper than the
grooves, so they don't show at the ends of the stiles. The tenons are as
thick as the grooves are wide and keep out of them, reaching only a
little under the mitres. At the corners, mitred only inside, they go
through the stiles, with full shoulders towards the ends; the middle
rail, mitred at both edges, has a hidden stub tenon.
The panels don't move with moisture, but are set clearance short of
the bottoms of the grooves all round, e.g. for glazing putty at the glass.
The frame has to be glued up round them.
Parameters¶
| Parameter | Default |
|---|---|
height |
600 |
width |
400 |
member_width |
30 |
mitre_depth |
10 |
groove_width |
6 |
groove_depth |
8 |
clearance |
2 |
stock |
20 mm board, oak |
bottom_panel_stock |
6 mm board, plywood |
top_panel_stock |
6 mm board, glass |
Change them in a design file (see Change an example):
Drawings¶
The plans in one PDF: plans.pdf.
Cut list¶
stile 600 x 30 x 20 mm oak, 2 pieces: stile_left, stile_right
- 2 x through mortise 12 x 6 mm in back_edge
- 2 x notch 30 long, 10 deep, mitred at one end, in back_edge
- mortise 14 x 6 mm, 25 deep, in back_edge
- notch 30 long, 10 deep, mitred at both ends, in back_edge
- groove 6 mm, 8 deep, in back_edge
rail 400 x 30 x 20 mm oak, 2 pieces: rail_top, rail_bottom
- tenon 12 x 6 mm, 20 long, reaching 10 beyond the shoulder, mitred at back_edge, on left_end
- tenon 12 x 6 mm, 20 long, reaching 10 beyond the shoulder, mitred at back_edge, on right_end
- groove 6 mm, 8 deep, in back_edge
rail_middle 386 x 30 x 20 mm oak
- tenon 14 x 6 mm, 13 long, reaching 10 beyond the shoulder, mitred at front_edge, back_edge, on left_end
- tenon 14 x 6 mm, 13 long, reaching 10 beyond the shoulder, mitred at front_edge, back_edge, on right_end
- groove 6 mm, 8 deep, in front_edge
- groove 6 mm, 8 deep, in back_edge
panel_top 352 x 267 x 6 mm glass
panel_bottom 352 x 267 x 6 mm plywood
Code¶
From woodwright/examples/projects.py, which imports the names it uses (see From an example to your own design):
def cabinet_door(
height: float = 600,
width: float = 400,
member_width: float = 30,
mitre_depth: float = 10,
groove_width: float = 6,
groove_depth: float = 8,
clearance: float = 2,
stock: Stock = CABINET_DOOR_OAK,
bottom_panel_stock: Stock = PLYWOOD,
top_panel_stock: Stock = GLASS,
) -> Assembly:
"""A small cabinet door of 2 x 3 cm stock with mitred shoulder tenons,
a plywood panel below the middle rail and a glass one above; outside sizes.
Two stiles, a top, a middle and a bottom rail. A groove runs through
along the inside edges of all of them, centered in the thickness, the
panels as thick as it is wide. Each rail reaches `mitre_depth` into a
notch in the stile, mitred at 45 degrees at its inside edges, where the
grooves meet like in a mitred frame; the notch is deeper than the
grooves, so they don't show at the ends of the stiles. The tenons are as
thick as the grooves are wide and keep out of them, reaching only a
little under the mitres. At the corners, mitred only inside, they go
through the stiles, with full shoulders towards the ends; the middle
rail, mitred at both edges, has a hidden stub tenon.
The panels don't move with moisture, but are set `clearance` short of
the bottoms of the grooves all round, e.g. for glazing putty at the glass.
The frame has to be glued up round them.
"""
rail_length = width - 2 * member_width
def corner(rail_end: SideRef, stile_edge: SideRef, position: Position, outer: SideRef) -> Joint:
rail = rail_end.part
inner = rail.back_edge if outer == rail.front_edge else rail.front_edge
shoulders = (mitre_depth, groove_depth)
return MitredShoulderTenon(
tenon=rail_end,
mortise=stile_edge,
position=position,
mitre_depth=mitre_depth,
mitred=(inner,),
shoulder=shoulders if outer == rail.front_edge else shoulders[::-1],
tenon_thickness=groove_width,
tenon_length=member_width - mitre_depth, # through
)
asm, (stile_left, stile_right, rail_top, rail_bottom) = _frame(
"cabinet_door", corner, height, rail_length, member_width, stock
)
# The rails' front edges are at the top.
rail_middle = asm.add(Board("rail_middle", stock, length=rail_length, width=member_width))
for rail_end, stile_edge, stile_end in [
(rail_middle.left_end, stile_left.back_edge, stile_left.left_end),
(rail_middle.right_end, stile_right.front_edge, stile_right.left_end),
]:
asm.join(
MitredShoulderTenon(
tenon=rail_end,
mortise=stile_edge,
position=offset((height - member_width) / 2, stile_end),
mitre_depth=mitre_depth,
shoulder=groove_depth,
tenon_thickness=groove_width,
tenon_length=13, # leaving 5 mm behind the mortise
)
)
opening_height = (height - 3 * member_width) / 2
reach = groove_depth - clearance
# Lying like the rails, the front edges up.
for name, panel_stock, above, below, stile_end in [
("top", top_panel_stock, rail_top, rail_middle, "right_end"),
("bottom", bottom_panel_stock, rail_middle, rail_bottom, "left_end"),
]:
if panel_stock.thickness != groove_width:
raise ValueError(f"the {name} panel must be as thick as the groove is wide")
panel = asm.add(Board(f"panel_{name}", panel_stock, rail_length, opening_height))
for side, groove, position in [
(panel.left_end, stile_left.back_edge, getattr(stile_left, stile_end)),
(panel.right_end, stile_right.front_edge, getattr(stile_right, stile_end)),
(panel.front_edge, above.back_edge, None),
(panel.back_edge, below.front_edge, None),
]:
asm.join(
TongueAndGroove(
tongue=side,
groove=groove,
tongue_thickness=groove_width,
tongue_length=reach,
cut_tongue=False,
position=CENTERED if position is None else offset(member_width, position),
across=CENTERED,
clearance=clearance,
)
)
return asm
Exported with woodwright 0.9.0 on 2026-10-25.