// Credenza
// Eric Moderbacher
// A Danish-style teak sideboard: a low panel body on four splayed round legs, fronted by
// a mitred face frame whose beveled openings hold a bank of drawers on the left and a pair of
// sliding doors on the right, under a flat top. X = width, Y = depth (front at Y = 0), Z = up.
// Dimensions in millimeters.
//
// Overall dimensions are estimates from the reference photos (see reference/measurements/)
// and are flagged below — swap in real measurements as they come.
use <units.scad>;
use <legs.scad>;
use <drawers.scad>;
use <doors.scad>;
$fn = 80;
// ---- overall dimensions ----
bodyWidth = inchesToMM(72); // ESTIMATE — overall width (left<->right)
bodyDepth = inchesToMM(18); // ESTIMATE — overall depth (front<->back)
bodyHeight = inchesToMM(20); // ESTIMATE — the box only, without legs or top
panel = inchesToMM(0.75); // body panel thickness
topThickness = inchesToMM(0.9); // flat top slab
topOverhang = inchesToMM(0); // flush with the case (no lip); side profiles show from above
legHeight = inchesToMM(12); // read ~12" off the tape (IMG_5263)
legInset = inchesToMM(4); // leg centre in from each corner
// ---- front layout ----
drawerCount = 4; // stacked drawers in the left bank
drawerFraction = 0.30; // share of the interior width taken by the drawer bank
// ---- face frame (mitred front frame with beveled openings for the drawers & doors) ----
faceThickness = inchesToMM(0.7);
frameW = inchesToMM(0.55); // frame member width around/between the openings
frameBevel = inchesToMM(0.35); // chamfer width around each opening
frameBevelDepth = inchesToMM(0.28); // how far the chamfer runs back before the opening
doorOverlap = inchesToMM(1.5); // how far the two sliding doors overlap in the middle
doorSetback = inchesToMM(0.2); // depth offset so the rear door clears the front one
// ---- derived geometry ----
interiorWidth = bodyWidth - 2 * panel;
drawerBankWidth = (interiorWidth - panel) * drawerFraction;
doorBankWidth = (interiorWidth - panel) * (1 - drawerFraction);
bayZ0 = panel; // bottom of the opening region
bayH = bodyHeight - panel; // height of the opening region
drawerBayX = panel; // left edge of the drawer bay
doorBayX = panel + drawerBankWidth + panel;// left edge of the door bay (past the divider)
// opening rectangles on the front face: [x, z, w, h]
function drawerOpening(i) =
let (cellH = bayH / drawerCount)
[ drawerBayX + frameW, bayZ0 + i * cellH + frameW,
drawerBankWidth - 2 * frameW, cellH - 2 * frameW ];
doorOpening = [ doorBayX + frameW, bayZ0 + frameW,
doorBankWidth - 2 * frameW, bayH - 2 * frameW ];
module body()
{
cube([bodyWidth, bodyDepth, panel]); // bottom
cube([panel, bodyDepth, bodyHeight]); // left side
translate([bodyWidth - panel, 0, 0]) cube([panel, bodyDepth, bodyHeight]); // right side
translate([0, bodyDepth - panel, 0]) cube([bodyWidth, panel, bodyHeight]); // back
translate([panel + drawerBankWidth, 0, 0])
cube([panel, bodyDepth - panel, bodyHeight]); // divider
}
module top()
{
// flat slab; overhangs the front and both sides slightly, flush at the back
o = topOverhang;
translate([-o, -o, bodyHeight])
cube([bodyWidth + 2 * o, bodyDepth + o, topThickness]);
}
module beveledOpening(rect)
{
x = rect[0]; z = rect[1]; w = rect[2]; h = rect[3];
c = frameBevel; d = frameBevelDepth;
// through opening
translate([x, -0.05, z]) cube([w, faceThickness + 0.1, h]);
// beveled front lip: wide at the face, narrowing to the opening at depth d (mitred corners)
hull()
{
translate([x - c, 0, z - c]) cube([w + 2 * c, 0.02, h + 2 * c]);
translate([x, d, z]) cube([w, 0.02, h]);
}
}
module faceFrame()
{
difference()
{
cube([bodyWidth, faceThickness, bodyHeight]);
for (i = [0 : drawerCount - 1]) beveledOpening(drawerOpening(i));
beveledOpening(doorOpening);
}
}
frontLap = inchesToMM(0.12); // how far the fronts tuck behind the frame all round
frontRecess = frameBevelDepth + 1; // how far the fronts sit back from the bevel
module drawerFronts()
{
for (i = [0 : drawerCount - 1])
{
r = drawerOpening(i);
translate([r[0] - frontLap, frontRecess, r[1] - frontLap])
drawer(width = r[2] + 2 * frontLap,
height = r[3] + 2 * frontLap,
depth = bodyDepth - panel - frontRecess);
}
}
module doorFronts()
{
r = doorOpening;
x = r[0]; z = r[1]; w = r[2]; h = r[3];
doorWidth = (w + doorOverlap) / 2;
// left door in front, right door set back so it can slide past
translate([x - frontLap, frontRecess, z - frontLap])
slidingDoor(doorWidth + frontLap, h + 2 * frontLap);
translate([x + w - doorWidth, frontRecess + doorSetback, z - frontLap])
slidingDoor(doorWidth + frontLap, h + 2 * frontLap);
}
module legPlacement()
{
// vertical round tapered legs, inset from each corner
for (x = [legInset, bodyWidth - legInset],
y = [legInset, bodyDepth - legInset])
translate([x, y, 0]) leg(height = legHeight);
}
module credenza()
{
legPlacement();
translate([0, 0, legHeight])
{
body();
top();
faceFrame();
drawerFronts();
doorFronts();
}
}
credenza();