include include use use $fa = 4; $fs = 0.25; /* [Shelf Size] */ // Width in gridfinity units grid_x = 1; // [2:1:8] // Depth in gridfinity units grid_y = 1; // [1:1:3] /* [Pegboard (1" standard)] */ peg_spacing = 25.4; peg_hole_dia = 6.35; board_thickness = 4.76; /* [Construction] */ peg_dia = 5.6; peg_behind = 10; backplate_thick = 4; gusset_thick = 1.6; /* [Options] */ enable_magnets = false; // Tilt shelf forward for bin visibility shelf_angle = 10; // [0:5:20] // === DERIVED === shelf_width = grid_x * 42; shelf_depth = grid_y * 42; // Peg layout: 1" intervals centered across shelf width num_pegs = floor(shelf_width / peg_spacing) + 1; peg_array_width = (num_pegs - 1) * peg_spacing; peg_x_start = (shelf_width - peg_array_width) / 2; // Z positions (shelf bottom = 0, shelf top = BASEPLATE_HEIGHT) top_peg_z = BASEPLATE_HEIGHT / 2; bottom_peg_z = top_peg_z - peg_spacing; // Backplate covers both peg rows with margin bp_z_bottom = bottom_peg_z - peg_dia; // Gusset geometry gusset_depth = shelf_depth; num_gussets = grid_x + 1; bp_clearance = BASEPLATE_HEIGHT * sin(shelf_angle); hole_options = enable_magnets ? bundle_hole_options(magnet_hole=true, crush_ribs=true, chamfer=true) : bundle_hole_options(); echo(str("Shelf: ", grid_x, "x", grid_y, " (", shelf_width, "x", shelf_depth, "mm)")); echo(str("Total depth from wall: ", backplate_thick + shelf_depth, "mm")); echo(str("Pegs per row: ", num_pegs, ", gussets: ", num_gussets)); // === ASSEMBLY === color("SteelBlue") union() { // Tilted shelf group: pivot at top-back edge of shelf translate([0, backplate_thick, BASEPLATE_HEIGHT]) rotate([-shelf_angle, 0, 0]) translate([0, -backplate_thick, -BASEPLATE_HEIGHT]) { // Gridfinity baseplate surface translate([shelf_width/2, backplate_thick + bp_clearance + shelf_depth/2, 0]) gridfinityBaseplate( [grid_x, grid_y], l_grid, [0, 0], 0, hole_options, 0 ); // Fill the clearance gap behind the baseplate translate([0, backplate_thick, 0]) cube([shelf_width, bp_clearance, BASEPLATE_HEIGHT]); } // Gussets (in world coords, bridging tilted shelf to vertical backplate) for (i = [0 : num_gussets - 1]) { gx = gusset_thick/2 + i * (shelf_width - gusset_thick) / max(1, num_gussets - 1); difference() { translate([gx, 0, 0]) gusset(); if (i == 0) baseplate_corner_cut(left=true); if (i == num_gussets - 1) baseplate_corner_cut(left=false); } } // Backplate wall translate([0, 0, bp_z_bottom]) cube([shelf_width, backplate_thick, BASEPLATE_HEIGHT - bp_z_bottom]); // Top row pegs (J-hooks, weight-bearing) for (i = [0 : num_pegs - 1]) translate([peg_x_start + i * peg_spacing, 0, top_peg_z]) j_hook(); // Bottom row pegs (anti-rotation) for (i = [0 : num_pegs - 1]) translate([peg_x_start + i * peg_spacing, 0, bottom_peg_z]) peg(board_thickness + 1); } // === MODULES === module peg(length) { rotate([90, 0, 0]) cylinder(d=peg_dia, h=length); translate([0, -length, 0]) sphere(d=peg_dia); } module j_hook() { shaft_behind = 2; shaft_length = board_thickness + shaft_behind; tip_length = 4; tip_angle = 20; // Straight shaft through the board peg(shaft_length); // Upward-angled tip translate([0, -shaft_length, 0]) hull() { sphere(d=peg_dia); rotate([tip_angle, 0, 0]) translate([0, 0, tip_length]) sphere(d=peg_dia); } } module gusset() { // Triangle in the Y-Z plane bridging tilted shelf to vertical backplate // rotate([0,90,0]) maps: polygon_x → -world_z, polygon_y → world_y // Front-bottom of tilted shelf (after tilt transform) by = backplate_thick + (bp_clearance + shelf_depth) * cos(shelf_angle) - BASEPLATE_HEIGHT * sin(shelf_angle); bz = BASEPLATE_HEIGHT * (1 - cos(shelf_angle)) - (bp_clearance + shelf_depth) * sin(shelf_angle); // Shelf underside projected back to the backplate face ay = backplate_thick; az = bz + (by - backplate_thick) * tan(shelf_angle) + BASEPLATE_OUTER_RADIUS + 0.1; // Bottom of backplate cy = backplate_thick; cz = bp_z_bottom; translate([-gusset_thick/2, 0, 0]) rotate([0, 90, 0]) linear_extrude(gusset_thick) polygon([ [-az, ay], [-bz, by], [-cz, cy] ]); } module baseplate_corner_cut(left) { R = BASEPLATE_OUTER_RADIUS; translate([0, backplate_thick, BASEPLATE_HEIGHT]) rotate([-shelf_angle, 0, 0]) translate([0, -backplate_thick, -BASEPLATE_HEIGHT]) translate([left ? 0 : shelf_width - R, backplate_thick + bp_clearance + shelf_depth - R, -1]) difference() { cube([R, R + 1, BASEPLATE_HEIGHT + 2]); translate([left ? R : 0, 0, -1]) cylinder(r=R, h=BASEPLATE_HEIGHT + 4); } }