There's a specific moment, somewhere around the third failed print, when you realise the model in front of you is wrong in a way you can't easily fix. A wall's too thin, a hole's a hair too tight, and the part was drawn — not described. Every fix is manual, and every manual fix risks breaking two other dimensions you'd forgotten were related.
That moment is why I design printable parts in OpenSCAD. It's not the prettiest CAD tool, and it's absolutely not the fastest for organic shapes. But for the brackets, mounts, jigs, and enclosures that make up most of what I actually print, describing the part in code beats drawing it — because the part is really a family of parts, and code is how you express a family.
The part is a function of its inputs
A bracket isn't one object. It's every bracket for every screw spacing you might need. Write it once with the spacing as a parameter and you've built the whole family:
// ---- Parameters (edit these, never the geometry) ----
wall = 3; // structural wall thickness
screw_d = 3.4; // clearance hole for an M3 screw
screw_sep = 24; // centre-to-centre of the two mounting holes
depth = 20; // how far the shelf sticks out
$fn = 48; // circle facet count
module bracket() {
difference() {
// Body: an L made of two overlapping cuboids
union() {
cube([screw_sep + 2*wall, wall, depth + wall]);
cube([screw_sep + 2*wall, depth + wall, wall]);
}
// Two mounting holes through the vertical face
for (x = [wall + screw_d/2, wall + screw_d/2 + screw_sep])
translate([x, -1, depth/2 + wall])
rotate([-90, 0, 0])
cylinder(h = wall + 2, d = screw_d);
}
}
bracket();Change screw_sep and the holes move and the body grows to match — because the body's width is derived from the spacing, not typed next to it. That's the whole discipline: no magic numbers in the geometry. If a dimension appears twice, it's a variable.
Tolerances are variables, not guesses
The gap between "fits" and "fights" on an FDM printer is about 0.2 mm, and it drifts with your filament, nozzle, and slicer. So a fit tolerance is exactly the kind of thing that should be a named parameter you tune once:
fit = 0.20; // per-side clearance for a sliding fit; raise if parts bind
module peg(d, h) { cylinder(d = d, h = h); }
module socket(d, h){ cylinder(d = d + 2*fit, h = h + 0.1); }When a batch of filament prints tight, I change one number instead of re-measuring every hole. The model doesn't know or care what changed.
A few habits that save prints
- Model in the print orientation you'll actually use. Overhangs and layer lines are part of the design, not an afterthought — decide them in CAD, not in the slicer.
- Keep a
render()of the assembly. Seeing the peg inside the socket before slicing catches interference you'd otherwise find at layer 40. - Comment the intent, not the number.
wall = 3; // survives a drop off the benchages better than a bare3.
None of this is about OpenSCAD specifically. It's about treating a physical part like what it is: a small program whose output happens to be plastic. Once the part is code, iterating it costs a variable and a re-render — not a redraw.