// -- OpenSCAD Mating Blocks & Drawer --
// This script creates mating plates, adapters, and a slidable drawer.
// All dimensions are controlled by the variables below for easy customization.
// -- Master View Control --
// Set to 'true' to see the drawer and plate housing assembly.
// Set to 'false' to see the original male and female mating parts.
show_drawer_assembly = false;
// -- View Control & Assembly --
// The distance between the male and female parts when shown together.
part_separation = 300;
// -- Male Block Dimensions --
// These variables define the original block with cylinders.
block_width = 100 ;
block_length = 100;
// -- Cylinder/Hole Dimensions --
// These are shared between both the male and female parts.
cylinder_radius = 5;
// This controls the protrusion height on the male part and the hole depth on the female part.
cylinder_protrusion_height = 10;
// A small amount to add to the hole radius for a looser fit, useful for 3D printing.
print_tolerance = 0.2;
block_height = 2 * cylinder_protrusion_height + cylinder_radius*2+1;
// -- Placement Controls --
// Distance from the edge of the block to the center of the cylinders/holes.
cylinder_offset_from_edge = (1/3)*block_width;
// -- Female Block Dimensions --
// These variables define the block with holes.
// The dimensions are based on the male part's cylinder height.
female_block_width = block_width;
female_block_length = 2 * cylinder_protrusion_height + cylinder_radius*2+1;
female_block_height = 2 * cylinder_protrusion_height + cylinder_radius*2+1;
// -----------------------------------------------------------------------------
// -- Drawer Dimensions --
// -----------------------------------------------------------------------------
drawer_length = block_length;
drawer_wall_thickness = 4;
// Tolerance for a smooth sliding fit between the drawer and the housing.
drawer_tolerance = 1;
// Radius for the handle cutout on the drawer face.
handle_radius = 20;
// Thickness of the front face of the drawer.
drawer_flange_thickness = 5;
// -- Main Logic --
// This decides whether to show the original parts or the new drawer assembly.
if (show_drawer_assembly) {
drawer_assembly();
} else {
male_part();
translate([0, part_separation, 0]) {
female_part();
}
}
// -----------------------------------------------------------------------------
// -- Drawer & Assembly Modules --
// -----------------------------------------------------------------------------
// -- Drawer Assembly Module --
module drawer_assembly() {
// The drawer is translated to sit flush with the housing's front face,
// and then pulled out an extra 80 units for visibility.
translate([0, block_length/2 + 80, 0]) {
color("CornflowerBlue")
drawer();
}
// Plate Assembly (Forms the housing for the drawer)
$fn=50;
// Left Plate
translate([-(block_width/2 + block_height/2), 0, 0]) rotate([0, 90, 0]) male_part();
// Right Plate
translate([(block_width/2 + block_height/2), 0, 0]) rotate([0, -90, 0]) male_part();
// Bottom Plate
translate([0, 0, -(block_width/2 + block_height/2)]) male_part();
// Top Plate
translate([0, 0, (block_width/2 + block_height/2)]) male_part();
}
// -- Drawer Module --
module drawer() {
drawer_body_width = block_width - drawer_tolerance;
drawer_body_height = block_width - drawer_tolerance;
drawer_flange_size = block_width + (4 * drawer_wall_thickness);
difference() {
union() {
// Front flange. Its front face is at Y=0.
translate([0, -drawer_flange_thickness / 2, 0]) {
cube([drawer_flange_size, drawer_flange_thickness, drawer_flange_size], center=true);
}
// Main body of the drawer, positioned behind the flange.
translate([0, -(drawer_length / 2) - drawer_flange_thickness, 0]) {
cube([drawer_body_width, drawer_length, drawer_body_height], center=true);
}
}
// -- FIX: OPEN TOP -- The subtraction cube is shifted up to cut open the top of the drawer.
// Subtract the inner hollow volume.
translate([
0,
-(drawer_length - drawer_wall_thickness)/2 - drawer_flange_thickness,
drawer_wall_thickness // Shift upward to leave bottom wall
]) {
cube([
drawer_body_width - 2*drawer_wall_thickness,
drawer_length,
drawer_body_height // Make cube tall enough to cut through the top
], center=true);
}
// Subtract a cylinder to create a handle.
translate([0, -drawer_flange_thickness/2, 0]) {
rotate([90,0,0]) {
cylinder(h=drawer_flange_thickness+2, r=handle_radius, center=true, $fn=100);
}
}
}
}
// -----------------------------------------------------------------------------
// -- Original Part Modules (Unchanged) --
// -----------------------------------------------------------------------------
// -- Male Part Module --
module male_part() {
union() {
cube([block_width, block_length, block_height], center = true);
for (i = [0, 1, 2, 3]) {
rotate([0, 0, i * 90]) {
place_cylinders_on_face();
}
}
}
}
// -- Female Part Module --
module female_part() {
difference() {
cube([female_block_width, female_block_length, female_block_height], center = true);
union() {
translate([0, 0, female_block_height/2]) rotate([180, 0, 0]) cutting_cylinders();
translate([0, 0, -female_block_height/2]) cutting_cylinders();
translate([0, female_block_length/2, 0]) rotate([90, 0, 0]) cutting_cylinders();
translate([0, -female_block_length/2, 0]) rotate([-90, 0, 0]) cutting_cylinders();
}
}
}
// -- Helper Module for Creating a Pair of Cutting Cylinders --
module cutting_cylinders() {
epsilon = 0.1;
x_offset = female_block_width / 2 - cylinder_offset_from_edge;
hole_radius = cylinder_radius + print_tolerance;
hole_depth = cylinder_protrusion_height;
translate([x_offset, 0, -epsilon])
cylinder(h = hole_depth + epsilon, r = hole_radius, $fn=50);
translate([-x_offset, 0, -epsilon])
cylinder(h = hole_depth + epsilon, r = hole_radius, $fn=50);
}
// -- Helper Module for Placing Cylinders (Male Part) --
module place_cylinders_on_face() {
translate([block_width / 2, block_length / 2 - cylinder_offset_from_edge, 0]) {
rotate([0, 90, 0]) {
cylinder(h = cylinder_protrusion_height, r = cylinder_radius, $fn = 50);
}
}
translate([block_width / 2, -(block_length / 2 - cylinder_offset_from_edge), 0]) {
rotate([0, 90, 0]) {
cylinder(h = cylinder_protrusion_height, r = cylinder_radius, $fn = 50);
}
}
}
to be clear, ts is slop generated by gemini, but it DOES work.
to use it, download openscad: https://openscad.org/downloads.html
then open it
then hit file in the top left
then hit new
then paste in the script
then hit the preview or render buttons, to see the rendered version of the walls. Hit export as stl to get the stl you would use to print.
i would like to come up with some standard size for them, though i don’t know what that size will be, and i have yet to print a FULL size version of this frame yet. I have only printed little miniature versions, and they do lock together, but quality is a little rough on them ( which is to be expected, as i have a ender 3 v3 se, and these are small items ).