$fn=64; // --- Parameters --- columns = 5; // Number of columns (5x2 = 10 tubes) rows = 2; // Number of rows tube_diameter = 26; // Fits standard 20-25ml paint tubes/droppers hole_depth = 25; // How deep the tubes sit in the rack wall_thickness = 4; // Minimum plastic thickness between holes base_thickness = 3; // Thickness of the floor under the tubes step_height = 15; // Elevation difference between rows // --- Calculated Variables --- spacing = tube_diameter + wall_thickness; rack_width = (columns * spacing) + wall_thickness; row_depth = spacing + wall_thickness; // --- Geometry --- difference() { // Main solid body (stepped) union() { for (y = [0 : rows - 1]) { translate([0, y * spacing, 0]) cube([ rack_width, row_depth, hole_depth + base_thickness + (y * step_height) ]); } } // Subtract tube holder holes for (x = [0 : columns - 1]) { for (y = [0 : rows - 1]) { cx = wall_thickness + (tube_diameter / 2) + (x * spacing); cy = wall_thickness + (tube_diameter / 2) + (y * spacing); cz = base_thickness + (y * step_height); translate([cx, cy, cz]) cylinder(h = hole_depth + 1, d = tube_diameter); } } }