$fn = 64; // --- Parametric Dimensions --- holder_width = 120; // Total width of the holder body_depth = 86; // Depth of the slotted section holder_height = 40; // Height of the slotted section corner_radius = 8; // Radius for the front corners slot_depth = 30; // Depth of the slots (leaves a 10mm solid base) wall_thickness = 8; // Thickness of the backplate backplate_height = 60; // Total height of the wall mount backplate // Slot positions and widths [y_offset, slot_width] // y_offset is relative to the front of the backplate slots = [ [8, 2], // Thin metal ruler [18, 3], // Standard ruler [29, 4], // Thick ruler [41, 5], // Straight edge [54, 6], // Heavy straight edge [68, 10] // T-square blade ]; // --- Modules --- // Generic rail cleat (compatible with most 45-deg wall rail systems like ArtArsenal) module rail_cleat() { // Extrude the cleat profile along the X axis // rotate([90, 0, 90]) maps (Xp, Yp, Zp) to (Zp, Xp, Yp) rotate([90, 0, 90]) linear_extrude(height=holder_width) { polygon([ [wall_thickness, 0], [wall_thickness, backplate_height], [-8, backplate_height], // Hook extends 8mm back [-8, backplate_height - 8], // Hook straight down 8mm [0, backplate_height - 16], // 45 deg angle back to wall [0, 0] // Flat against wall down to 0 ]); } } // Main solid body before slot cuts module body_base() { hull() { // Overlap with backplate by 1mm to ensure manifold geometry translate([0, wall_thickness - 1, 0]) cube([holder_width, 1, holder_height]); // Front rounded corners translate([corner_radius, wall_thickness + body_depth - corner_radius, 0]) cylinder(r=corner_radius, h=holder_height); translate([holder_width - corner_radius, wall_thickness + body_depth - corner_radius, 0]) cylinder(r=corner_radius, h=holder_height); } } // Body with vertical slots removed module slotted_holder() { difference() { body_base(); // Cut out the slots for (s = slots) { y_offset = s[0]; slot_w = s[1]; // Oversize cuts slightly in X and Z to ensure clean subtraction translate([-5, wall_thickness + y_offset, holder_height - slot_depth]) cube([holder_width + 10, slot_w, slot_depth + 5]); } } } // --- Main Assembly --- union() { rail_cleat(); slotted_holder(); }