$fn = 64; // --- PARAMETERS --- rail_length = 400; // Total length of the mounting rail tolerance = 0.4; // Clearance for sliding fit of attachments wall_thickness = 5; // Thickness of the attachment walls // --- LAYOUT --- // Main Wall Rail rail(); // Modular Attachment 1: Leash/Collar Hook translate([60, -40, 0]) hook_attachment(); // Modular Attachment 2: Treat/Bag Bin translate([60, 40, 0]) bin_attachment(); // --- MODULES --- // 2D Profile of the dovetail rail // Designed with 45-degree angles for support-free 3D printing module rail_2d() { polygon([ [0, 0], // Bottom against wall [40, 0], // Top against wall [30, 10], // Top overhang [25, 15], // Top flat [15, 15], // Bottom flat [10, 10] // Bottom overhang ]); } // 3D Extrusion of the rail module rail_3d(length) { rotate([90, 0, 0]) linear_extrude(length, center=true) rail_2d(); } // The complete printable rail with mounting holes module rail() { difference() { rail_3d(rail_length); // Countersunk mounting holes spaced every 80mm for (y = [-160 : 80 : 160]) { translate([20, y, 0]) { // Shaft for 5mm screw cylinder(h=50, d=5, center=true); // Cutout for screw head (leaves 5mm of plastic against wall) translate([0, 0, 10]) cylinder(h=10, d=10, center=true); } } } } // Universal sliding base for all modular attachments module attachment_base(length) { difference() { // Outer block translate([20, 0, 12.5]) cube([50, length, 25], center=true); // Rail Cutout (expanded by tolerance for sliding fit) rotate([90, 0, 0]) linear_extrude(length + 2, center=true) offset(r=tolerance) rail_2d(); // Trim bottom to ensure it sits perfectly flush against the wall translate([20, 0, -5]) cube([60, length + 2, 10], center=true); } } // 2D Profile for the J-hook module hook_profile() { difference() { offset(r=2) offset(r=-2) // Round the sharp edges slightly polygon([ [-12, 0], [12, 0], [10, 15], [20, 25], [20, 40], [10, 40], [10, 30], [0, 20], [-12, 20] ]); // Keep bottom perfectly flat for union translate([-20, -10]) square([40, 10]); } } // Complete hook attachment module module hook_attachment() { union() { attachment_base(30); // Hook protruding from the front face translate([20, 0, 25]) rotate([90, 0, 0]) linear_extrude(15, center=true) hook_profile(); } } // Complete storage bin attachment module module bin_attachment() { union() { attachment_base(60); // Bin protruding from the front face translate([20, 0, 25]) difference() { // Outer bin shell translate([0, 0, 20]) cube([40, 50, 40], center=true); // Inner hollow space (2mm walls and floor) translate([0, 0, 22]) cube([36, 46, 40], center=true); } } }