$fn = 64; // --- Parameters --- rail_length = 400; rail_height = 40; rail_thickness = 10; corner_radius = 5; num_hooks = 5; hook_length = 35; hook_base_dia = 12; hook_cap_dia = 20; hook_cap_height = 12; hole_dia = 4.5; // Sized for standard wood/drywall screws countersink_dia = 9.5; countersink_depth = 4; // --- Modules --- module rounded_board() { hull() { translate([corner_radius, corner_radius, 0]) cylinder(r=corner_radius, h=rail_thickness); translate([rail_length - corner_radius, corner_radius, 0]) cylinder(r=corner_radius, h=rail_thickness); translate([rail_length - corner_radius, rail_height - corner_radius, 0]) cylinder(r=corner_radius, h=rail_thickness); translate([corner_radius, rail_height - corner_radius, 0]) cylinder(r=corner_radius, h=rail_thickness); } } module printable_peg() { trunk_height = hook_length - hook_cap_height; // Sturdy base trunk cylinder(d1=hook_base_dia + 6, d2=hook_base_dia, h=trunk_height); // Diamond-profile knob (designed for 3D printing without supports) translate([0, 0, trunk_height]) { cylinder(d1=hook_base_dia, d2=hook_cap_dia, h=hook_cap_height/2); translate([0, 0, hook_cap_height/2]) cylinder(d1=hook_cap_dia, d2=hook_base_dia - 2, h=hook_cap_height/2); } } module mounting_hole() { // Main screw clearance hole translate([0, 0, -1]) cylinder(d=hole_dia, h=rail_thickness + 2); // Countersink for screw head translate([0, 0, rail_thickness - countersink_depth]) cylinder(d1=hole_dia, d2=countersink_dia, h=countersink_depth + 0.1); // Clean top cutout for countersink translate([0, 0, rail_thickness]) cylinder(d=countersink_dia, h=2); } // --- Main Assembly --- difference() { union() { // Main wall rail rounded_board(); // Add hooks hook_spacing = rail_length / num_hooks; for (i = [1 : num_hooks]) { x_pos = (i - 0.5) * hook_spacing; translate([x_pos, rail_height / 2, rail_thickness - 0.1]) printable_peg(); } } // Subtract mounting holes (placed evenly between hooks) hole_spacing = rail_length / num_hooks; for (i = [1 : num_hooks - 1]) { x_pos = i * hole_spacing; translate([x_pos, rail_height / 2, 0]) mounting_hole(); } }