$fn=64; // --- Parametric Dimensions --- cols = 5; // Number of bottles across rows = 3; // Number of tiers bottle_d = 25.5; // Diameter of Vallejo dropper bottle (24.5mm + 1mm clearance) pitch_x = 30; // Spacing between holes (X) pitch_y = 32; // Spacing between tiers (Y) tier_h = 25; // Height difference between tiers hole_depth = 18; // Depth of the bottle holes base_thick = 2; // Thickness of the floor under the bottles slot_width = 12; // Width of the front viewing slot // --- Calculated Dimensions --- width = cols * pitch_x; depth = rows * pitch_y; module vallejo_rack() { difference() { // Main Solid Body union() { // Tiered steps for(r = [0 : rows - 1]) { translate([0, r * pitch_y, 0]) cube([width, pitch_y, base_thick + hole_depth + (r * tier_h)]); } // Universal Mounting Cleat (ArtArsenal / French Cleat style) // Positioned at the top rear of the rack back_h = base_thick + hole_depth + ((rows - 1) * tier_h); translate([0, depth, back_h - 25]) rotate([90, 0, 90]) linear_extrude(width) polygon([ [0, 0], [0, 25], [6, 25], // Stick out 6mm [6, 10], // Drop down straight [2, 6], // 45-degree angle back in for easy printing [2, 0] // Drop to base of cleat ]); } // Bottle Holes and Viewing Slots for(r = [0 : rows - 1]) { for(c = [0 : cols - 1]) { x_pos = (pitch_x / 2) + (c * pitch_x); y_pos = (pitch_y / 2) + (r * pitch_y); z_pos = base_thick + (r * tier_h); // Main bottle hole translate([x_pos, y_pos, z_pos]) cylinder(h = hole_depth + 5, d = bottle_d); // Front viewing slot for paint color visibility translate([x_pos - (slot_width / 2), (r * pitch_y) - 1, z_pos]) cube([slot_width, (pitch_y / 2) + 2, hole_depth + 5]); } } } } // Render the model vallejo_rack();