$fn=64; // --- Parameters --- tile_size = 100; // Width and height of the modular tile tile_thickness = 15; // Total thickness of the tile rail_depth = 5; // Depth of the mounting rail cutout solid_mid_layer = 2; // Thickness of the solid layer between rails and grid grid_spacing = 4; // Spacing between pin holes grid_wall = 1; // Thickness of the walls between pin holes // Derived parameters hole_size = grid_spacing - grid_wall; grid_depth = tile_thickness - rail_depth - solid_mid_layer; start_offset = grid_wall / 2; module pinboard_tile() { difference() { // Main tile body cube([tile_size, tile_size, tile_thickness]); // Pinboard waffle grid // Subtracted from the front face to create a dense mesh for pins // Edges have exactly half a wall thickness so they tile seamlessly for(x = [start_offset : grid_spacing : tile_size - hole_size]) { for(y = [start_offset : grid_spacing : tile_size - hole_size]) { translate([x, y, rail_depth + solid_mid_layer]) cube([hole_size, hole_size, grid_depth + 1]); } } // Upper rail mount (ArtArsenal / French Cleat style) translate([0, tile_size - 30, 0]) rail_cutout(tile_size); // Lower rail mount for stability translate([0, 20, 0]) rail_cutout(tile_size); } } module rail_cutout(w) { // Creates a 45-degree upward-sloping cavity for wall rails hull() { // Opening at the back surface translate([-1, 0, -0.1]) cube([w + 2, 15, 0.1]); // Deepest part of the pocket, shifted UP by 5mm to create the locking hook translate([-1, 5, rail_depth]) cube([w + 2, 15, 0.1]); } } // Generate the model pinboard_tile();