[User]
Okay, I'm looking to design a parametric wall-mounted wrench holder, and I want to be able to customize it for different wrench sizes. I've got an idea of what it should look like, based on a design I found, but I need it to be fully parametric so I can easily make adjustments later.

Basically, the holder should be a long bar with a series of "hooks" that will hold the wrenches. Here's what I'm envisioning:

*   **Base Bar:** A rectangular bar, with rounded ends.  I need to be able to control the length, width, and thickness of this bar. I'd also like the rounded ends to be configurable by radius, so I could even have square ends if I wanted.
*   **Mounting Holes:** There should be mounting holes along the bar for attaching it to a wall. I want to specify the number of holes, their positions, diameter, and counterbore size and depth. The holes should be evenly spaced.
*   **Hooks:** The hooks are the parts that hold the wrenches. They should be semi-circular (or rather, a partial cylinder) with a small angled piece on the front to keep the wrench from sliding off. I need to be able to specify the hook's position along the bar, its height, diameter, and angle of the front lip. I also want to be able to slightly round off the top lip using minkowski and sphere functions for a finished look.
*   **Text Labels:** I'd like to be able to add text labels for the wrench sizes next to each hook. I need to control the text string, position, size, extrusion height and whether the text should be printed at all.

I want the whole thing to be parametric, meaning I can change these parameters:

*   Overall length of the bar.
*   Bar width and thickness.
*   Radius of the rounded ends of the bar.
*   Number, positions, diameter, counterbore diameter and depth for the mounting holes along the bar.
*   Number of hooks
*   Position of each hook along the bar.
*   Hook diameter and height.
*   Angle of the front lip of the hook.
*   Text size, position and extrusion height.
*   Whether to print text labels.

I need the final OpenSCAD code to include comments that explain what is happening in the code, and to make it easy to understand.

Could you generate the OpenSCAD code for this? I don't need any specific libraries, just vanilla OpenSCAD, please.

[Assistant]
wrench-wall-holder.scad:
```
/*
  Ringsleutelhanger.
	September 2022, auteur Guillaume Piaf

   * Op een 300x300 bed de sleutel onder 45 graden positioneren,
	   dan past het.
   * Materiaal: PLA, PETG, Nylon of ABS.
   * color("kleur",alpha) alleen zichtbaar in preview.

======================================================================

	- Afmeting plm. 315x24.5x24 mm
	- Printtijd PETG bij 80mm (123-3D PETG Jupiter profiel): 3h50m
	- Printtijd PETG bij 50mm (123-3D PETG Jupiter profiel): 4h38m
    50mm/s geeft een sterker en mooier resultaat, voorkeur.

*/

//Customizer variabelen
//False: korte rendertijd, zonder maten op het balkje.
tekst=true;
//Alle andere data fixed.

// ************  MODULES  ************

//**** bevestigingsgaten ****
module gat(positie){
		color("gold",0.7)
		translate([positie,0,0]){
			  cylinder(h=5.1,d=4.8,center=true);//shaft van de schroef + cilinder
			  translate([0,0,1.6])
			      cylinder(h=2,r1=2.4,r2=4,center=true);//cilinder,r1=bottom,r2=top
		}
}

//**** haak, halfrond met kleine hoek ****
module haakje(positie,topjeX,topjeY,topjeZ){
	color("lightgrey",0.8)
	translate([positie,5.7,9.48]){
		rotate([90,0,90]){
			difference()
			{
				difference(){
					  cylinder(h=5,d=24,center=true);
					  cylinder(h=5.1,d=14,center=true);
				}
				translate([-8,0,0])
				rotate([0,0,5])
				    cube([15,24,5.2],center=true);
			}
		}
	}
	//topje beetje afronden
	color("lightgrey")
	translate([positie,3,18.85])
	rotate([95,0,0])
			minkowski()
			{
				cube([topjeX,topjeY,topjeZ],center=true);
				sphere(d=2.5);
			}
		}
//**** tekstmodule: maten van de ringsleutels, ****
//**** 9" ontbreekt, ga ik niet doen.          ****
module maat(tekst,positie){
	color("lightgreen")
	translate([positie,2,3])
	rotate([0,0,180])
	linear_extrude(height=3,center=true)
	    text(tekst,size=8);
}

// ************  PRINT BUILD ************

//vanwege grootte gehele print 45 graden draaien op bed 300x300.
rotate([0,0,45])
{
	difference() //1
	{
		union(){
			// beginnen met latje - GEEN minkowski() gebruiken.
			cube([300,12.5,5],center=true);
			// 2x half rondje er aan.
				color("red",0.5){
				translate([-150.5,0,0])
				    cylinder(h=5,d=12.5,center=true);
				translate([150.5,0,0])
				    cylinder(h=5,d=12.5,center=true);
			}
		}
		//gaten voor cilinder flathead schroeven 4.5x?? mm.
		//difference()1 met union hierboven
		gat(130);
		gat(70);
		gat(0);
		gat(-45);
		// bij de grotere maten extra gaten.
		gat(-77.5);
		gat(-92.5);
		gat(-117.5);
		gat(-132.5);
}

//haakjes toevoegen, positie en afmetingen
haakje(-145,4,6,1.8);			//19"  iets dikkere ringsleutel
haakje(-105,4,6,1.8);			//17"  iets dikkere ringsleutel
haakje(-65,4,6,1.8);			//15"  iets dikkere ringsleutel
haakje(-25,3.8,3.8,1.2);	//14"
haakje(25,,3.8,3.8,1.2);  //13"
haakje(55,3.8,3.8,1.2);   //12"
haakje(85,3.8,3.8,1.2);   //11"
haakje(115,3.8,3.8,1.2);  //10"
haakje(145,3.8,3.8,1.2);	//8"

//extruded teksten, hier en daar wat uitgelijnd want de tekst
//is proportioneel, niet vector-based dus.
if(tekst){
	maat("19",-139);
	maat("17",-99);
	maat("15",-58);
	maat("14",-18.5);
	maat("13",32);
	maat("12",62);
	maat("11",91);
	maat("10",121);
	maat("8",148);
}
}

//Variabelen niet zichtbaar in Customizer.
$fn= $preview ? 50 : 100;
//bij preview 50 faces, < 0.1 sec rendertijd.
//bij render 100 --> plm. 5 minuten rendertijd ivm teksten.

```


[User]
I'd like to create a parametric Art Deco-style grill, kind of like the picture I saw. I have an existing OpenSCAD file that gets close, but it's a bit messy and I'd like to start fresh.

Here are the key features and parameters I need:

*   **Overall Frame:**
    *   `frame_width`: The total width of the grill.
    *   `frame_height`: The total height of the grill.
    *   `depth`: The overall thickness of the grill.
    *   `frame_thickness`: The thickness of the outer frame.

*   **Inner Grid:**
    *   `box_thickness`: The thickness of the lines that make up the inner grid of rectangles.
    *   `box_multiplier_rows`: The number of complete rows of "boxes" in the staggered pattern (see the illustrations from the previous example).
    *   `box_multiplier_cols`: The number of complete columns of "boxes" in the staggered pattern.
    *   `inner_box_lines`: A boolean flag. If true, also draw the internal lines of each box. If false, only draw the outer frame lines and staggered pattern.

*   **Staggered Pattern:** The grid should have the staggered pattern, so it alternates between rows where the interior squares are on different sides of the vertical bars.

I'm hoping for a clean, well-structured parametric design, and I'd like the code to use the `BOSL2` library, if possible, as I'm familiar with its syntax and think it would work well for this sort of thing. I'm not sure if this is all possible, but the code I shared is an example of what I'm trying to achieve if that helps.

[Assistant]
ArtDecoGrill.scad:
```
depth                   =       5;
frame_thickness         =       5;
frame_height            =       400;
frame_width             =       500;
box_thickness           =       3;
box_multiplier_rows     =       6;
box_multiplier_cols     =       7;
inner_box_lines         =       false;

box_multiplier_rows_2   =       box_multiplier_rows-2;
box_multiplier_cols_2   =       box_multiplier_cols-2;
frame_width_inner       =       frame_width-(frame_thickness*2);
frame_height_inner      =       frame_height-(frame_thickness*2);
frame_x_offset          =       (0-((frame_width/2))+(box_thickness/2));
frame_x_max             =       ((frame_width/2)-(box_thickness/2));
frame_y_max             =       (0-((frame_height/2))+(box_thickness/2));
frame_y_offset          =       ((frame_height/2)-(box_thickness/2));
vertical_line_spacing   =       (box_multiplier_cols+box_multiplier_cols_2+2);
vertical_line_width     =       ((frame_width-box_thickness)/vertical_line_spacing);
horizobtal_line_spacing =       (box_multiplier_rows+box_multiplier_rows_2+2);
horizobtal_line_width   =       ((frame_height-box_thickness)/horizobtal_line_spacing);

intersection()
{
    union(){
    difference()
        {
            cube([frame_width,frame_height,depth],true);
            cube([frame_width_inner,frame_height_inner,depth*2],true);
        };
    difference()
        {
            for (h =[0:1:(vertical_line_spacing)])
                for(w =[0:1:(horizobtal_line_spacing)])
                    {
                        translate([frame_x_offset+(h*vertical_line_width),0,0])
                        cube([box_thickness,frame_height,depth],true);
                        translate([0,frame_y_max+(w*horizobtal_line_width),0])
                        cube([frame_width,box_thickness,depth],true);

                        translate([frame_x_offset+(h*vertical_line_width),frame_y_max+(w*horizobtal_line_width),0])
                        if((h%2==1&&w%2==0)||(h%2==0&&w%2==1))
                            difference()
                                {
                                cube([vertical_line_width-(box_thickness),((horizobtal_line_width*2)-(box_thickness*2))-(box_thickness),depth],true);
                                cube([vertical_line_width-(box_thickness*3),((horizobtal_line_width*2)-(box_thickness*2))-(box_thickness*3),depth*2],true);
                                };
                    };
          if(inner_box_lines==false)
              for (h =[0:1:(vertical_line_spacing)])
                for(w =[0:1:(horizobtal_line_spacing)])
                    {
                        translate([frame_x_offset+(h*vertical_line_width),frame_y_max+(w*horizobtal_line_width),0])
                        if((h%2==1&&w%2==0)||(h%2==0&&w%2==1))
                                cube([vertical_line_width-(box_thickness*3),((horizobtal_line_width*2)-(box_thickness*2))-(box_thickness*3),depth*2],true);
                    };
        };};
     cube([frame_width,frame_height,depth*2],true);

};

```


[User]
I'm looking to create a customizable pegboard system that integrates with the Dave's Modular Organizer (DMO). I have a basic OpenSCAD file, but it's pretty basic and I'd like to make it more parametric and flexible.

Here's the gist: I want to be able to specify the overall width and height of the pegboard panel, the thickness of the panel, the diameter of the holes, the spacing between the holes, and the border width around the edges. The hole smoothness should also be adjustable via a number of facets. There should also be a base attached to the pegboard, and its height and thickness should be parametric as well.

I'm thinking that the holes should be created using a `cylinder()` function. The base should be a simple `cube()`. The pegboard panel should be a `cube()` with the holes subtracted from it using `difference()`. The current code calculates the number of holes based on other dimensions, and that should remain.

I'd really like for this to be parametric, so I can easily adjust any of these values. I’m aiming for something that fits well with DMO's 1.5 inch (38.5mm) grid, but also works as a standalone pegboard. I'm not sure if that would require any additional calculations beyond what I have now.

Could you provide an OpenSCAD file, or files, that allows me to easily control all of these parameters? I'm not using any external libraries currently, but if you think it would make the code cleaner or more efficient, I'm open to it. I'm not familiar with all the libraries available, but I'm not opposed to using them. Could you also explain which libraries, and their function, if you use them?

[Assistant]
Pegboard.scad:
```
// pegboard width (mm)
width = 154.0;

// pegboard height (mm)
height = 142.0;

// pegboard thickness (mm)
pegboardThickness = 3.175;

// hole diameter (mm)
holeDiameter = 6.35;

// spacing between holes (mm)
holeSpacing = 25.4;

//hole smoothness (number of facets)
holeFacets = 48;

// border width (mm)
borderWidth = 10.3;

// base height (mm)
baseHeight = 8.0;

numHolesWidth = floor((width-holeDiameter-borderWidth*2)/holeSpacing);
numHolesHeight = floor((height-holeDiameter-borderWidth*2)/holeSpacing);

// Function to create a hole
module createHole(x, y) {
    translate([x*holeSpacing+holeDiameter/2+borderWidth, y*holeSpacing+holeDiameter/2+borderWidth, 0])
    cylinder(r=holeDiameter / 2, h=pegboardThickness+1, $fn=holeFacets, center=false);
}

// Function to create pegboard
module createPegboard() {
    difference() {
        // Pegboard panel
        cube([width, height, pegboardThickness], center=false);

        // Pegboard holes
        for (x = [0 : 1 : numHolesWidth]) {
            for (y = [0 : 1 : numHolesHeight]) {
                createHole(x, y);
            }
        }
    }
}

// Function to create base
module createBase() {
    translate([0, height, 0]) cube([width,  baseHeight, 38.5], center=false);
}

// Call function to create pegboard
createPegboard();

// Call function to create base
createBase();

```


[User]
Okay, I'm looking to create some pegboard accessories, specifically screwdriver holders, that are compatible with my customizable pegboard system. I really like the design of the "Pegstr" screwdriver holder, and I've included the original SCAD file in case you need it. The design I'm going for is based on the compact square-grid approach that allows different sized screwdrivers to fit in the same holder.

I would like the OpenSCAD design to be parametric, allowing me to easily adjust the size and shape of the holder. Key parameters I'll want to control are:

*   **`holder_x_size`**: Width of the individual screwdriver orifice (around 6.35 mm).
*   **`holder_y_size`**: Depth of the orifice (around 25.4 mm).
*   **`holder_height`**: Height of the holder (around 14 mm).
*   **`wall_thickness`**: Thickness of the walls (around 2.75 mm).
*   **`holder_x_count`**: Number of orifices on the X axis (e.g., how many screwdrivers wide).
*   **`holder_y_count`**: Number of orifices on the Y axis (e.g., how many screwdrivers deep).
*   **`corner_radius`**: Radius of the corners of the orifice (around 3 mm).
*   **`holder_offset`**: Offset from the board surface (likely 0).
*  **`strength_factor`**: Ratio of the bottom of the holder to the plate (0-1)
*   **`holder_ratio`**:  Ratio to make the bottom of the holder narrower (0-1).
*   **`closed_bottom`**: Ratio to use for closing the bottom of the holder, if any (0-1).
*   **`holder_cutout_side`**: Percentage to cut out the front of the holder.
*   **`holder_angle`**: Angle the holder relative to the board surface.
*   **`hole_spacing`**: The spacing between the pegboard holes (should be 25.4 mm).
*   **`hole_size`**: The diameter of the pegboard holes (around 6.0035 mm).
*   **`board_thickness`**: The thickness of the pegboard panel (around 5 mm)

I would like a design that incorporates the pegboard mounting pins from that file as well, and can generate both the holder and the mounting pins. The mounting pin design should have a clip feature to engage the pegboard.

I intend to use this with a modular pegboard system, so it’s important that the mounting pins are correctly sized and spaced to fit the standard pegboard dimensions. The system should generate the pins to be located where they should fit in the pegboard holes. I think the mounting clips are needed on the bottom pins, so if you could add that in, that'd be great.

The holder should have an optional cutout on the front side to allow for inserting screwdrivers or for cable routing. This should be controlled via `holder_cutout_side`. The whole holder can be angled too, to improve the view or to prevent items from falling.

I don't need the `holder_sides` parameter, the $fn parameter can just be a global variable called `fn`.
Also, I’d like it if the code is structured in modules, to keep things organized, and uses `hull()` to make the connecting part of the pinboard.

Could you create this as an OpenSCAD design, please?

[Assistant]
PegBoard-Original.scad:
```
// PEGSTR - Pegboard Wizard
// Design by Marius Gheorghescu, November 2014
// Update log:
// November 9th 2014
//  - first coomplete version. Angled holders are often odd/incorrect.

// width of the orifice
holder_x_size = 6.35;

// depth of the orifice
holder_y_size = 25.4;

// hight of the holder
holder_height = 14;

// how thick are the walls. Hint: 6*extrusion width produces the best results.
wall_thickness = 2.75;

// how many times to repeat the holder on X axis
holder_x_count = 3;

// how many times to repeat the holder on Y axis
holder_y_count = 1;

// orifice corner radius (roundness)
corner_radius = 3;

// offset from the board
holder_offset = 0.0;

// what ratio of the holders bottom is reinforced to the plate [0.0-1.0]
strength_factor = 0.55;

// Use values less than 1.0 to make the bottom of the holder narrow
holder_ratio = 1.00;

// what ratio of wall thickness to use for closing the bottom
closed_bottom = 0.0;

// what percentage cu cut in the front (example to slip in a cable or make the tool snap from the side)
holder_cutout_side = 0.0;

// set an angle for the holder to prevent object from sliding or to view it better from the top
holder_angle = 0;

/* [Hidden] */

// what is the $fn parameter
holder_sides = max(60, min(20, holder_x_size*2));

// dimensions the same outside US?
hole_spacing = 25.4;
hole_size = 6.0035;
board_thickness = 5;

holder_total_x = wall_thickness + holder_x_count*(wall_thickness+holder_x_size);
holder_total_y = wall_thickness + holder_y_count*(wall_thickness+holder_y_size);
holder_total_z = round(holder_height/hole_spacing)*hole_spacing;
holder_roundness = min(corner_radius, holder_x_size/2, holder_y_size/2);

// what is the $fn parameter for holders
fn = 32;

epsilon = 0.1;

clip_height = 2*hole_size + 2;
$fn = fn;

module round_rect_ex(x1, y1, x2, y2, z, r1, r2)
{
	$fn=holder_sides;
	brim = z/10;

	//rotate([0,0,(holder_sides==6)?30:((holder_sides==4)?45:0)])
	hull() {
        translate([-x1/2 + r1, y1/2 - r1, z/2-brim/2])
            cylinder(r=r1, h=brim,center=true);
        translate([x1/2 - r1, y1/2 - r1, z/2-brim/2])
            cylinder(r=r1, h=brim,center=true);
        translate([-x1/2 + r1, -y1/2 + r1, z/2-brim/2])
            cylinder(r=r1, h=brim,center=true);
        translate([x1/2 - r1, -y1/2 + r1, z/2-brim/2])
            cylinder(r=r1, h=brim,center=true);

        translate([-x2/2 + r2, y2/2 - r2, -z/2+brim/2])
            cylinder(r=r2, h=brim,center=true);
        translate([x2/2 - r2, y2/2 - r2, -z/2+brim/2])
            cylinder(r=r2, h=brim,center=true);
        translate([-x2/2 + r2, -y2/2 + r2, -z/2+brim/2])
            cylinder(r=r2, h=brim,center=true);
        translate([x2/2 - r2, -y2/2 + r2, -z/2+brim/2])
            cylinder(r=r2, h=brim,center=true);

    }
}

module pin(clip)
{
	$fn = fn;
	cylinder(r=hole_size/2, h=board_thickness+wall_thickness+epsilon, center=true, $fn=24);

	if (clip) {
		//
		rotate([0,0,90])
		intersection() {
			translate([0, 0, hole_size-epsilon])
				cube([hole_size+2*epsilon, clip_height, 2*hole_size], center=true);

			// [-hole_size/2 - 1.95,0, board_thickness/2]
			translate([0, hole_size/2 + 2, board_thickness/2])
				rotate([0, 90, 0])
				rotate_extrude(convexity = 5, $fn=32)
				translate([5, 0, 0])
				 circle(r = (hole_size*0.95)/2);

			translate([0, hole_size/2 + 2 - 1.6, board_thickness/2])
				rotate([45,0,0])
				translate([0, -0, hole_size*0.6])
					cube([hole_size+2*epsilon, 3*hole_size, hole_size], center=true);
		}
	}
}

module pinboard_clips()
{
	rotate([0,90,0])
	for(i=[0:round(holder_total_x/hole_spacing)]) {
		for(j=[0:max(strength_factor, round(holder_height/hole_spacing))]) {

			translate([
				j*hole_spacing,
				-hole_spacing*(round(holder_total_x/hole_spacing)/2) + i*hole_spacing,
				0])
					pin(j==0);
		}
	}
}

module pinboard(clips)
{
	rotate([0,90,0])
	translate([-epsilon, 0, -wall_thickness - board_thickness/2 + epsilon])
	hull() {
		translate([-clip_height/2 + hole_size/2,
			-hole_spacing*(round(holder_total_x/hole_spacing)/2),0])
			cylinder(r=hole_size/2, h=wall_thickness);

		translate([-clip_height/2 + hole_size/2,
			hole_spacing*(round(holder_total_x/hole_spacing)/2),0])
			cylinder(r=hole_size/2,  h=wall_thickness);

		translate([max(strength_factor, round(holder_height/hole_spacing))*hole_spacing,
			-hole_spacing*(round(holder_total_x/hole_spacing)/2),0])
			cylinder(r=hole_size/2, h=wall_thickness);

		translate([max(strength_factor, round(holder_height/hole_spacing))*hole_spacing,
			hole_spacing*(round(holder_total_x/hole_spacing)/2),0])
			cylinder(r=hole_size/2,  h=wall_thickness);

	}
}

module holder(negative)
{
	for(x=[1:holder_x_count]){
		for(y=[1:holder_y_count]) {
			translate([
				-holder_total_y /*- (holder_y_size+wall_thickness)/2*/ + y*(holder_y_size+wall_thickness) + wall_thickness,

				-holder_total_x/2 + (holder_x_size+wall_thickness)/2 + (x-1)*(holder_x_size+wall_thickness) + wall_thickness/2,
				 0])
	{
		rotate([0, holder_angle, 0])
		translate([
			-wall_thickness*abs(sin(holder_angle))-0*abs((holder_y_size/2)*sin(holder_angle))-holder_offset-(holder_y_size + 2*wall_thickness)/2 - board_thickness/2,
			0,
			-(holder_height/2)*sin(holder_angle) - holder_height/2 + clip_height/2
		])
		difference() {
			if (!negative)
				scale([(holder_y_size + 2*wall_thickness)/holder_y_size,
					(holder_x_size + 2* wall_thickness)/holder_x_size, 1])
				round_rect_ex(
					holder_y_size, holder_x_size,
					holder_y_size*holder_ratio, holder_x_size*holder_ratio,
					holder_height,
					holder_roundness + epsilon,
					holder_roundness*holder_ratio + epsilon);

				translate([0,0,closed_bottom*wall_thickness])
				round_rect_ex(
					holder_y_size*(negative>1?holder_ratio:1),
					holder_x_size*(negative>1?holder_ratio:1),
					holder_y_size*holder_ratio,
					holder_x_size*holder_ratio,
					(negative>1?3*max(holder_height, hole_spacing):holder_height+2*epsilon),
					holder_roundness*(negative>1?holder_ratio:1) + epsilon,
					holder_roundness*holder_ratio + epsilon);

			if (!negative)
				if (holder_cutout_side > 0) {

					hull() {
						scale([holder_cutout_side, holder_cutout_side, 1.0])
		 					round_rect_ex(
							holder_y_size*(negative>1?holder_ratio:1),
							holder_x_size*(negative>1?holder_ratio:1),
							holder_y_size*holder_ratio,
							holder_x_size*holder_ratio,
							(negative>1?3*max(holder_height, hole_spacing):holder_height+2*epsilon),
							holder_roundness*(negative>1?holder_ratio:1) + epsilon,
							holder_roundness*holder_ratio + epsilon);

						translate([10-(holder_y_size + 2*wall_thickness), 0,0])
						scale([holder_cutout_side, holder_cutout_side, 1.0])
		 					round_rect_ex(
							holder_y_size*(negative>1?holder_ratio:1),
							holder_x_size*(negative>1?holder_ratio:1),
							holder_y_size*holder_ratio,
							holder_x_size*holder_ratio,
							(negative>1?3*max(holder_height, hole_spacing):holder_height+2*epsilon),
							holder_roundness*(negative>1?holder_ratio:1) + epsilon,
							holder_roundness*holder_ratio + epsilon);
					}
				}
			}
		} // positioning
	} // for y
	} // for X
}

module pegstr()
{
	difference() {
		union() {
			hull() {
				color([0,0,1])
					pinboard();

				intersection() {
						holder(0);

					translate([-holder_offset - (strength_factor-0.5)*holder_total_y - wall_thickness/4,0,0])
					cube([
						holder_total_y + 2*wall_thickness,
						holder_total_x + wall_thickness,
						2*holder_height
					], center=true);
					}
			}
			holder(0);

			color([1,0,0])
				pinboard_clips();
		}

		holder(1);

		if (closed_bottom*wall_thickness < epsilon) {
				holder(2);
		}
	}
}

//color([0.8,0.0,0.0])
rotate([180,0,0]) pegstr();
//holder(0);
//holder(1);
//holder(2);
//foo();
//holder(2);
```


[User]
I'd like to design a tissue box holder that's highly customizable. I've seen some designs out there, but I want to be able to tweak things like the box dimensions, the size of the slot for accessing tissues, the mounting hole diameters, and even add some decorative elements. I'm thinking of using OpenSCAD.

Specifically, I need the following parameters to be adjustable:

*   **Box Dimensions:**
    *   `box_length` (mm)
    *   `box_width` (mm)
    *   `box_height` (mm)
    *   `wall_thickness` (mm)

*   **Slot Size:**
    *   `slot_length` (mm)

*   **Mounting Holes:**
    *   `hole_size` (diameter in mm)

*   **Decorations:**
    *   `decoration_shape` (number of sides for decorative holes - a value between 3 and 8, like a triangle, square, pentagon, up to an octagon).
    *   `big_fillet` (boolean, to use a large front fillet or a smaller one) - the fillet would round the top front corners.

The design should have:

*   A basic box shape with the specified dimensions and wall thickness.
*   A cutout on the top to allow access to tissues.
*   Mounting holes on the back for wall mounting, as well as mounting holes on the bottom for shelf mounting. The holes should be positioned appropriately for mounting and have the specified diameter.
*   Decorative holes on the ends of the holder, cylindrical in shape, arranged in a grid or array pattern, with the shape determined by `decoration_shape`.
*   Fillets on the top front corners, either large or small, determined by `big_fillet`.

Could you generate the OpenSCAD file or files for this? I'd like the code to be well-commented, so I can understand what's going on. Also, please, avoid the use of libraries if possible.

[Assistant]
Tissue_Box_Holder.scad:
```
// Tissue Box Holder
// Audi McAvoy
// 13 August 2023

/* [Box Size] */
// mm
box_length = 240;
// mm
box_width = 80;
// mm
box_height = 130;
// mm
wall_thickness = 3;

/* [Slot Size] */
// mm
slot_length = 130;

/* [Mount Hole Size] */
// diameter (in millimeters)
hole_size = 4;

/* [Decorations] */
// number of sides
decoration_shape = 6; // [3:8]
// use big radius for front fillet
big_fillet = true;

module mirror_copy(mirror_vector) {

    children(); // draw the original object(s)
    mirror(mirror_vector) children(); // then create a mirror of the objects
}

module rectangular_array(rows, cols, distance) {

    for (i = [0:1:rows-1]) {
        for (j = [0:1:cols-1]) {
            translate([i*distance, j*distance, 0]) children();
        }
    }
}

module holder(length, width, height, thickness, slot_len, dia, sides, big_radius) {

    $fn = 25;
    cut_len = slot_len+(length-slot_len)/2;
    fillet_dia = big_radius ? length-cut_len : length/10;
    fillet_x = big_radius ? length/-2 : (cut_len+fillet_dia)/-2;
    fillet_z = big_radius ? (height-fillet_dia)/2 - thickness : height/2-thickness-fillet_dia/2;

    difference() {
        // create a nice box
        minkowski() {
            cube([length, width, height], center = true);
            sphere(thickness);
        }
        // hollow it out
        cube([length, width, height], center = true);
        // chop off the top
        translate([0, 0, height-thickness]) cube([2*length, 2*width, height], center = true);
        // chop out the middle, leaving the ends
        cube([cut_len, 2*width, 2*height], center = true);
        // poke in some mounting holes on the back
        mirror_copy([1, 0, 0]) // make a horizontal copy of the set of holes
            mirror_copy([0, 0, 1]) // make a vertical copy of the original hole
                translate([(3*length+slot_len)/8, width/2, height/3]) rotate([90, 0, 0]) cylinder(h = 4*thickness, d = dia, center = true);
        // poke in some mounting holes on the bottom
        mirror_copy([1, 0, 0]) // make a horizontal copy of the set of holes
            mirror_copy([0, 1, 0]) // make a copy of the original hole
                translate([(3*length+slot_len)/8, width/4, -height/2]) cylinder(h = 4*thickness, d = dia, center = true);
        // fillet the top front corners
        mirror_copy([1, 0, 0])
            translate([fillet_x, (4*thickness+width)/-2, fillet_z])
                difference() {
                    cube([fillet_dia, 3*thickness, fillet_dia]);
                    rotate([90, 0, 0]) cylinder(h = fillet_dia, d = fillet_dia, center = true);
                }
        // decorate the ends
        cyl_size = width/5;
        array_n = height/(1.5*cyl_size); // number of cylinders high
        array_h = (array_n-1)*1.5*cyl_size; // array height minus one cylinder diameter
        translate([0, -1.5*cyl_size, (array_h-4*thickness)/2])
            rotate([0, 90, 0])
                rectangular_array(array_n, 3, 1.5*cyl_size) cylinder(h = 2*length, d = cyl_size, center = true, $fn = sides);
    }
}

holder(box_length, box_width, box_height, wall_thickness, slot_length, hole_size, decoration_shape, big_fillet);

```


[User]
I'd like to create a screw puzzle, and I'd like your help generating the OpenSCAD code.

The puzzle consists of three main parts: a bolt, a small screw piece that sits on top of the bolt, and a nut. The bolt will have a threaded section and a head with a filleted edge. The small screw piece will also be threaded and will sit on the bolt such that it is in the same orientation. This is important: the threads on both the bolt and small screw piece need to match up. Both the bolt and small screw piece also need a portion cut out so that they will only line up in a certain configuration. The nut needs to be threaded internally so that it will screw onto the other pieces. There should also be a clearance between all the parts so it is not too difficult to move.

Here are the specific parameters I'd like to control:

*   **Bolt Height (`h_bolt`):** The overall height of the bolt.
*   **Nut Height (`h_nut`):** The height of the nut.
*   **Bolt Radius (`r_bolt`):** The radius of the bolt's main body (excluding threads).
*   **Head Radius (`r_head`):** The radius of the bolt's head.
*   **Center Offset (`center_offset`):** How far off-center the cut on the bolt and small piece is. This will add more of a challenge to the puzzle since these pieces will have to be aligned in a very specific way.
*   **Head Fillet Radius (`r_fillet`):** The radius of the fillet at the edge of the bolt's head.
*   **Thread Height (`h_teeth`):** The height of the screw thread teeth.
*   **Thread Width (`w_teeth`):** The width of the screw thread teeth.
*   **Thread Pitch (`pitch`):** The vertical distance for one turn of the thread.
*   **Clearance (`cl`):** The extra space between parts to allow for easy movement.
*   **Double Thread (`useDoubleThread`):** A boolean that, if true, uses a double helix for the threads.

I'd like to make the puzzle with a relatively high level of detail, so please use `$fn = 100` for the circle resolution.

The code should define a `thread` module that I can use to generate the threads for the bolt, small screw piece, and nut. It should also define a `rotateZ` function that I can use when defining the thread module, but I believe these are relatively standard, so you can make assumptions about them.

Also, it is important that the threads line up. If the `useDoubleThread` parameter is set to true, make sure that the double thread is implemented correctly such that it works on the bolt, small piece, and nut correctly.

I believe all of this should be achievable in one file. I would like to avoid any external dependencies if possible.

[Assistant]
ScrewPuzzle.scad:
```
// The amount of edges per circle (resolution)
$fn = 100;

//* Size
// Height of the bolt
h_bolt = 33;
// Height of the nut
h_nut = 14;
// Radius of the bolt without the screw thread
r_bolt = 10;
// Size of the head (radius)
r_head = 20;
// How far the small piece is cut off center (more stall force)
center_offset = 3;
// The radius of the fillet at the head
r_fillet = 24; //r_head+4

//* Thread
// Height of the teeths
h_teeth = 3.6;
// Width of the teeths
w_teeth = 2;
// The increase in height for every turn
pitch = 13;
// Gives the height of the thread, Note if too large the tread comes out of the head
turns = h_bolt/pitch;

// Clearance
cl = 0.4;
// use double thread to allow for larger pitch values
useDoubleThread = true;

function rotateZ(vertex,angle) = [
     [cos(angle), -sin(angle), 0],
     [sin(angle),  cos(angle), 0],
     [    0     ,      0     , 1]
    ] * vertex;

// Bolt
translate([0,0,h_bolt+15])
rotate([180,0,0])
difference(){
    union() {
        cylinder(r = r_bolt+0.02, h = h_bolt, center = false);
        thread(h_teeth=h_teeth, w_teeth=w_teeth, pitch = pitch, turns = turns, r = r_bolt);
        if (useDoubleThread == true) rotate([0,0,180]) thread(h_teeth=h_teeth, w_teeth=w_teeth, pitch = pitch, turns = turns, r = r_bolt); // Double thread
        translate([0, 0, h_bolt])
        intersection(){  // Head
            translate([0,0,-1]) sphere(r=r_fillet);  // Add the rounded edges (You might want to change this if you change the size too much, both the sphere_r and the translate_z)
            cylinder(r=r_head, h=15, center=false, $fn = 6);
        }
    }
    // Remove part of the bolt
    translate([-center_offset,0,-h_nut/2])
    rotate_extrude(angle=-200) {
        square(size=[r_head+2, h_bolt]);
    }
    // Add some clearance
    translate([-30,-cl/2,0])
    cube(size=[60, cl, h_bolt-h_nut-2]);
}

// smalle piece
translate([0,0,h_bolt-h_nut-2])
rotate([180,0,0])
translate([-1.3*(r_head+r_bolt),0,0])
difference(){
    intersection(){
        union(){
            cylinder(r = r_bolt+0.02, h = h_bolt, center = false);
            thread(h_teeth=h_teeth, w_teeth=w_teeth, pitch = pitch, turns = turns, r = r_bolt);
            if (useDoubleThread == true) rotate([0,0,180]) thread(h_teeth=h_teeth, w_teeth=w_teeth, pitch = pitch, turns = turns, r = r_bolt);
        }
        translate([0,0,-h_nut-2])
        rotate_extrude(angle=-180) {
            square(size=[r_head+2, h_bolt]);
        }
    }
    // Add some clearance
    translate([-30,-cl/2,0])
    cube(size=[60, cl, h_bolt-h_nut-2]);
}

// nut
// translate([0,0,h_nut])
// rotate([0,180,0])
translate([0,2.3*r_head,0]) // Move out of the center
difference() {
    cylinder(r=r_head, h=h_nut, $fn = 6);
    translate([0, 0, -1]) cylinder(r=r_bolt+0.2+cl,h=h_nut+3);
    translate([0, 0, -2.2]) thread(h_teeth=h_teeth+cl, w_teeth=w_teeth+cl, pitch = pitch, turns = 7, r = r_bolt+cl);
    if (useDoubleThread == true) rotate([0,0,180]) translate([0, 0, -2.2]) thread(h_teeth=h_teeth+cl, w_teeth=w_teeth+cl, pitch = pitch, turns = 7, r = r_bolt+cl);
}

module thread(h_teeth = 3, w_teeth = 1.15, pitch, turns, r, taper_factor = 0.1, angleBottom = 45){
    steps = turns * $fn;
    angle = 360/$fn;
    points = [ for (i = [0:steps]) for (j = [0:3])
        (j == 0) ? rotateZ([r        ,0,pitch*i/$fn                                 ], angle*i) :
        (j == 1) ? rotateZ([r+w_teeth,0,pitch*i/$fn+h_teeth*taper_factor            ], angle*i) :
        (j == 2) ? rotateZ([r+w_teeth,0,pitch*i/$fn+h_teeth-tan(angleBottom)*w_teeth], angle*i) :
                   rotateZ([r        ,0,pitch*i/$fn+h_teeth                         ], angle*i)];

    face1 = [[3,2,1,0]];
    face2 = [for (i = [4:4:len(points)-1]) for (j = [0:3])
        (j == 0) ? [i+2, i+1, i-3, i-2] :  // Front
        (j == 1) ? [i+3, i+2, i-2, i-1] :  // Top
        (j == 2) ? [i-1, i-4, i, i+3] :    // Back
                   [i-4, i-3, i+1, i]     // bottom
                   ];
    face3 = [[len(points)-4, len(points)-3, len(points)-2, len(points)-1]];
    // faces = [[3,2,1,0], for (i = [4:4:len(points)-1]) for (j = [0:3])
    //     (j == 0) ? [i+2, i+1, i-3, i-2] :  // Front
    //     (j == 1) ? [i+3, i+2, i-2, i-1] :  // Top
    //     (j == 2) ? [i-1, i-4, i, i+3] :    // Back
    //                [i-4, i-3, i+1, i],     // bottom
    //          [len(points)-4, len(points)-3, len(points)-2, len(points)-1] ]; // Closing (last)

    faces = concat(face1,face2,face3);

    polyhedron(points=points, faces=faces);
}
```


[User]
Hi! I'm looking to design a set of flying platform miniatures for tabletop RPGs, and I'd like to use OpenSCAD to make them customizable. I have a rough idea of what I want, based on a design I saw, but I'd prefer to start from scratch so I can use my preferred library, BOSL2.

Here's what I'm envisioning:

*   **Platform Sizes:** I need two platform sizes: "medium" and "large." A medium platform should be roughly 1 inch in diameter, and the large should be about 2 inches in diameter. I want to make sure there's a little extra room on the platform for the minis to fit, so maybe a couple millimeters wider than the actual base. I'll be using the standard 1 inch = 5 feet scale.

*   **Platform Height:** The platforms need to be elevated by a central riser. I want the rise to be customizable in increments of 5 feet, from 5 to 30 in game-feet.

*   **Riser Shape:** The riser itself should have an interesting shape, not just a plain cylinder. I'm thinking of a polygonal shape that's thicker at the top and bottom to suggest a support structure and kind of tapers in the middle. I'd like it to be centered on the platform.

*  **Rounded Elements:** To make it printable I'd like the support structure to have rounded corners where the base and top supports meet the central riser.

*   **Labeling:** Each platform should have a label on the riser showing its height, in game-feet. This will make it easy to identify the altitude of the platforms. Something like "10 ft" for a 10 foot rise.

*   **BOSL2:** I want to use BOSL2 for this, as it provides a lot of useful functions and makes it easier to work with. I do not need a separate `use` for the library, I'm aware of the syntax.

*   **Printability:** I want the design to be printable without supports on FDM printers. I'm okay with bridging overhangs, but I'd like to minimize them.

Could you generate the necessary OpenSCAD file or files using BOSL2 based on these specifications? The design should be parametric so I can easily change the platform size and height. I think I'd also like to be able to adjust the number of sides on the polygon riser shape. Let me know if you have any questions!

[Assistant]
flying_base.scad:
```
//How many in-game feet platform will rise
rise_feet = 10; //[5, 10, 15, 20, 15, 30]
//Size of creature base (medium = 1", large = 2")
size = "medium"; //["medium", "large"]

/* [Hidden] */
inch_to_mm = 25.4;
platform_grids = (size=="large" || size=="\"large\"")?2:1;
platform_width = platform_grids*inch_to_mm+2;
riser_height = rise_feet/5*inch_to_mm;
label = str(rise_feet, " ft");

module complete_model() {
    fn = $preview?32:64;
    h = riser_height;
    w = platform_width;
    riser_w = 2*platform_grids+6;
    platform_depth = 1;
    riser_points = [
        [1, riser_w/2],
        [-3, riser_w/2-1],
        [-3, -riser_w/2+1],
        [1, -riser_w/2]
    ];
    echo("w", riser_w);

    linear_extrude(h+3)
        polygon(riser_points);

    //lower platform
    translate([0, 0, 0])
    difference(){
        hull()
        {
            linear_extrude(platform_depth+2)
                polygon(riser_points);
            translate([w/2+2, 0, 0])
                    cylinder(r=w/2+2, h=platform_depth+1, $fn=fn);
        }

        translate([w/2+2, 0, 1])
            cylinder(r=w/2+1, h=platform_depth+1, $fn=fn);
    }

    //upper platform
    translate([0, 0, h])
    difference(){
        hull()
        {
            linear_extrude(platform_depth+2)
                polygon(riser_points);
            translate([w/2+2, 0, 0])
                    cylinder(r=w/2+2, h=platform_depth+1, $fn=fn);
        }

        translate([w/2+2, 0, 1])
            cylinder(r=w/2+1, h=platform_depth+1, $fn=fn);
    }

    translate([-0.5, 3, 4])
    rotate([180, -90, 0])
    resize([0, 6])
    linear_extrude(2)
        text(label);
}

if($preview){
    complete_model();
}else{
    rotate([0, -90, 0])
        complete_model();
}
```


[User]
I want to design a customizable storage box with text on the front, and it should be able to be 3D printed. It needs to have a rounded top, a rectangular cutout on the bottom, and a circular cutout on the front. Also, I need a small hole for hanging, with a chamfered edge. It would be great if the text on the front was also customizable.

Specifically, the box itself should have a main body with a rounded top, kind of like a pill bottle but rectangular. The base of the body needs to be roughly 73mm x 31mm, and about 60mm high total, but the sides should only be 30 mm high before curving in. The top should have a curved or semi-circular profile that transitions smoothly into the sides. Inside this main body, I'd like the interior to be a rectangular cutout of 67mm x 25mm, reaching all the way down.

Then, on the bottom of the box, there should be a rectangular cutout that's 52mm x 10mm, and 3.2mm deep.

On the front of the box, I want a circular cutout that goes almost all the way through, but not quite. This should be about 4 mm deep, centered horizontally and aligned with the front. Finally, there should be a small hanging hole in the back of the top, with a diameter of 5 mm, chamfered with a larger diameter of 9mm.

For the text, I want to be able to specify two lines of text which will then be extruded on the front of the box. Let's say they are around 6mm tall, and be on the side without the large cutout.

The overall design should be parametric so I can change the box dimensions, cutout sizes, and text content. I want the whole thing to be generated by a single scad file.

[Assistant]
box2.scad:
```
line_1_text="Line 1";
line_2_text="Line 2";

box(line_1_text,line_2_text);

module box(txt1,txt2){
$fn=80;
difference(){
intersection(){
translate([-3,-3,0])
cube([73,31,60]);//exterior

translate([-3.5,31,15.5])//rounded top
rotate([0,90,0])
cylinder(r=45,h=74);
}
translate([0,0,3])
cube([67,25,60]);//interior

translate([7.5,7.5,-0.1])
cube([52,10,3.2]);//botton cutout

translate([33.5,0.5,66])//front cutout
rotate([90,0,0])
cylinder(r=37,h=4);

translate([33.5,24.5,45])//hanger hole
rotate([-90,0,0])
cylinder(r=2.5,h=4);

translate([33.5,24.5,45])//hole chamfer
rotate([-90,0,0])
cylinder(r1=4.5,r2=2.5, h=2.0);

if(len(txt1)>0)//text line 1
translate([0,-2.2,11.4])
rotate([90,0,0])
linear_extrude(height=1)
text(str(txt1),size=6,halign="left");

if(len(txt2)>0)//text line 2
translate([0,-2.2,3.4])
rotate([90,0,0])
linear_extrude(height=1)
text(str(txt2),size=6,halign="left");
}
}
```


[User]
I'm looking to design a parametric strap clamp for holding down cables, hoses, or conduit. I'd like the design to be customizable through the OpenSCAD customizer, similar to the one I already have, but with some enhancements. I'm not attached to the specifics of the code I have, I'd prefer you just start from scratch with the specifications below.

First, the main clamp shape should be selectable between a full ellipse, a half ellipse, or a rectangle. Each shape should have a `cable_width` and a `cable_height` parameter. If `cable_height` is zero, the height should default to `cable_width` for full ellipse and rectangle shapes, and `cable_width / 2` for half ellipse shapes. The clamp will have a `strap_breadth`, which is the width of the clamp along the length of the thing being clamped. The `strap_thickness` is the thickness of the material over the thing being clamped (the "top" of the clamp).

On each side of the main clamp, there should be a tab for mounting, with configurable `tab_length` and `tab_thickness`, and a `tab_radius` to round the corners of the tabs. The tabs should have screw holes. The number of screws should be a configurable `number_screws`, and the hole `diameter` should be configurable. The screw head shape should be configurable between `round_head` and `flat_head`. For flat head screws, I'd like parameters for the `flathead_top_diameter` and `flathead_taper_height`.

I also want the parametric design to include some very slight tolerances, so I'd like you to define variables `e` and `e2` as tolerances of 0.05mm and 0.1mm respectively.

I don't have any specific library preferences, but I'm aware of a few that have useful functions. I'm fine with you using libraries like BOSL, BOSL2, or NopSCADlib if there's functionality you want to draw on, but please keep it relatively straightforward so it's easy for me to follow. Could you generate the full set of SCAD files needed?

[Assistant]
strap_clamp.scad:
```
// Parametric screw-down strap clamp

// In OpenSCAD, select Window->Customizer

// Notes:
//  1. the full/half/rectangle shapes calculate the height inconsistently when cable_height is set to zero.
//     Full & rect sets the height to the width, whereas half sets it to width/2

// rlb408 2020-06

/*[Strap Clamp Basics]*/

// Shape of the thing being clamped (mm)
shape = "full_ellipse";  // [full_ellipse, half_ellipse, rectangle]

// Strap breadth (mm)
strap_breadth = 16;  // [5:0.1:100]

/*[Cable Size]*/
// Strap clamp width (width of the thing being clamped, regardless of shape)
cable_width = 20; // [3:0.1:100]

// Strap clamp height  (height of the thing being clamped, regardless of shape); zero means same as the cable_width except cable_width/2 for half_ellpise
cable_height = 0; // [0:0.1:100]

// Strap (the part over the thing  being held down) thickness
strap_thickness = 3; // [1:0.1:10]

/*[End Tabs] */

// End tab length - how far is sticks out from the raised strap
tab_length = 16; //[5:0.5:50]

// End tab thickness
tab_thickness = 3; // [0:0.1:10]

// Curve radius on the ends of the tabs
tab_radius = 4; // [0:0.1:6]

/*[Screw parameters]*/

// Screw type
// Number of screws on each tab
number_screws = 1; //[0:5]

screw_type = "round_head"; //[round_head, flat_head]

// Screw hole diameter (mm)
hole_diameter = 3.3; //[1:0.1:12]

// If flat head, top diameter
flathead_top_diameter = 6; //[ 3:0.1:10]

// If flat head, taper length (head height)
flathead_taper_height = 2; //[1:0.1:8]

module __Customizer_Limit__ () {}
$fn = 90;
e = 0.05;
e2 = e*2;

// This does the full strap clamp, just cponmtrols the shape
module clamp(shape=shape)
{
    if ( shape == "full_ellipse" ) {
        center_part() full_ellipse_shape();
        tabs();
    } else if ( shape == "half_ellipse" ) {
        center_part() half_ellipse_shape();
        tabs();
    } else if ( shape == "rectangle" ) {
        center_part() rectangle_shape();
        tabs();
    } else {
        text("Shape name is unknown");
    }
}

// Make the center portion of the strap.
// The children() are the basic shape of the thing being strapped down.
module center_part()
{
    y = cable_height == 0 ? cable_width : cable_height;
    linear_extrude(strap_breadth)
    intersection() {
        translate([-(cable_width/2+strap_thickness),0])
        square([cable_width+2*strap_thickness,y+strap_thickness]);
        difference() {
            offset(strap_thickness) children();
            translate([0,-e]) children();
        }
    }
}

// Full circular clamp, half circle (or ellipse), just the 2d shape
module full_ellipse_shape()
{
    y = cable_height == 0 ? cable_width : cable_height;
    scale([1,y/cable_width]) {
        union() {
            translate([-cable_width/2,0])
            square([cable_width,cable_width/2]);
            translate([0,cable_width/2]) circle(d=cable_width);
        }
    }
}

// 2D shape for half circular things
module half_ellipse_shape()
{
    y = cable_height == 0 ? cable_width/2 : cable_height;
    scale([1,2*y/cable_width])
    circle(d = cable_width);
}

// 2D shape for the rectangular cable
module rectangle_shape()
{
    y = cable_height == 0 ? cable_width : cable_height;
    translate([-cable_width/2,0])
    square([cable_width,y]);
}

// Makes both tabs, positioned correctly
module tabs()
{
    translate([cable_width/2+strap_thickness,0,0]) one_tab();
    mirror([1,0,0])
    translate([cable_width/2+strap_thickness,0,0]) one_tab();
}

// Creates one end tab with a screw hole through it
module one_tab()
{
    translate([0,tab_thickness,0])
    rotate([90,0,0])
    difference() {
        union() {
            linear_extrude(tab_thickness)
            union() {
                offset(tab_radius)
                offset(-tab_radius)
                square([tab_length, strap_breadth]);
                translate([-strap_thickness/2,0,0])
                square([tab_length-tab_radius+strap_thickness/2,strap_breadth]);
            }
        }
        if ( number_screws > 0 ) {
            for ( h=[0:number_screws-1] ) {
                translate([tab_length/2,strap_breadth/(number_screws*2)+h*(strap_breadth/number_screws),-e]) {
                    cylinder(d=hole_diameter, h=tab_thickness+e2);
                    if ( screw_type == "flat_head" ) {
                        cylinder(d1=flathead_top_diameter, d2=hole_diameter,h=flathead_taper_height);
                    }
                }
            }
        }
    }
}

// just for the demo image for Thingiverse (2023-08-28)
module demo_clamp(shape=shape)
{
    rotate([90,0,0]) clamp(shape);
    translate([cable_width/2+tab_length+10,0,0])
    linear_extrude(1)
    translate([0,-strap_breadth/2])
    text(shape, valign="center",size=strap_breadth);
}

if ( true ) {
    clamp();
} else {
    gap = 20;
    demo_clamp("full_ellipse");
    translate([cable_width+tab_length,strap_breadth+gap,0]) {
        demo_clamp("half_ellipse");
        translate([cable_width+tab_length,strap_breadth+gap,0]) {
            demo_clamp("rectangle");
        }
    }
}

```


[User]
I'm looking to design a modular system of linear slide bearings, and I'd like to use OpenSCAD to make it parametric. I've got a basic idea of the different types I'd like, and some of the dimensions I'm thinking about.

Specifically, I want to have three different types of bearings:

1.  **Slide Bearing:** This is a simple cylinder with a bore for the shaft and a couple of bands at the ends to prevent the slide from moving axially. I'd like to be able to adjust the length, the outer diameter, the bore diameter, the band width, and the clearance between the shaft and the bore.

2.  **Block Bearing:** This is a block with a bore for the shaft. I'd also like it to have mounting features on the sides – basically, flanges that extend out with holes for screws. I need parameters for the length of the block, its overall width, the height from the base to the center of the shaft bore, the overall height of the block, the height and width of the flanges, and the depth of any detents on the base. I'd also like to be able to adjust the screw hole positions, diameters, and counterbore depths.

3.  **Cap Bearing:** This is a flat, circular plate with a bore for the shaft, designed to act as an end cap. It needs a diameter parameter for the plate itself, a thickness parameter, and parameters for the screw holes and counterbores around its perimeter.

For all three, I'd also need a parameter to set the shaft diameter itself, as well as the overall outer diameter and a clearance value. I'd like the screws to be parametric by diameter and head diameter. I'm also thinking of adding a parameter for the screw separation along the x and z axis for the block bearing.  For the cap bearing, I'd like to set the radius for the plate and screw placements.

It would be super helpful if the code was structured so I could select which of the three types I want to generate via a simple variable like `Mode = 0, 1, or 2`. I'd prefer to not rely on any external libraries, if possible, and would like the code to be very thoroughly commented so it's clear what each parameter does. If not possible, then please use MCAD.

Could you help me generate this OpenSCAD code?

[Assistant]
SlideBearings.scad:
```

  //---------------------//
 // Slide Bearings V1.0 //
//---------------------//

// Use the OpenScad customizer
// Public Domain Dedication

$fn=60;

/* [Block Body] */

Mode = 0; // [0:Slide,1:Block,2:Cap]
// Length
L=30;       // [10:100]

// Width
W=34;       // [20:50]

// Shaft to Base
H=11;       // [5:.01:30]

// Block Height
G=13;       // [5:70]

// Sholder Height
T=6;       // [2:30]

// Sholder Width
Sholder = 1.5;  // [0:.01:4]

// Base Detent depth
Detent = 1.5;   // [0:.01:4]

// Collar Band width
BandWid = 2;    // [1:5]

/* [Plate] */
Plate_R   = 30;  // [10:.01:60]

Plate_Thk = 4;   // [2:.01:8]

/* [Shaft] */

ShaftD     = 8.1; // [5:.01:12]
Shaft_Wall = 5;   // [5:.01:10]
Clearance  = 0.2; // [0:.01:1]

/* [Screws] */
ScrewD = 3;  // [2:.01:5]
HeadD  = 5;  // [3:.01:8]
// CounterBore Depth
L1 = 0;   // [0:8]

// B
ScrewSepX = 24;  // [15:.01:50]
// C
ScrewSepZ = 18;  // [5:.01:100]

PlateScrewR = 11; // [5:.02:30]

OuterD = ShaftD + Shaft_Wall;

Head   = (HeadD-ScrewD)/2;
Screw_Position = [ScrewSepX/2,-.5,ScrewSepZ/2];

if (Mode==0) Slide_Bearing();
if (Mode==1) Block_Bearing();
if (Mode==2) Cap_Bearing();

module MirrorCopy(M) {
   children();
   mirror(M) children();
}

module Cap_Bearing() {
   Base_Shape();

   difference() {
      linear_extrude(Plate_Thk,convexity=5)
      difference() {
            circle(d=Plate_R);
            circle(d=OuterD-1);
      }

      for (ang=[0,90,180,270])
      rotate(ang) {
         translate([PlateScrewR,0,-.5])
         cylinder(d=ScrewD,h=Plate_Thk+1);

         translate([PlateScrewR,0,Plate_Thk-Head+.01])
         cylinder(d1=ScrewD,d2=HeadD,h=Head);
      }
   }

   module Base_Shape() {
      linear_extrude(L,convexity = 5)
      difference() {
         circle(d=OuterD);
         circle(d=ShaftD+Clearance);
         f=360/5;
         for (i=[0:5])
            rotate(i*f)
            square([ShaftD+3.5,1],center=true);
      }
   }
}

module Block_Bearing() {

   difference() {
      Base_Shape();
      MirrorCopy([0,0,1])
      MirrorCopy([1,0])
      translate(Screw_Position) {
         rotate([-90,0])
         cylinder(d=ScrewD,h=G+2);

         if (L1==0) {
            translate([0,+Head+.49])
            rotate([90,0])
            cylinder(d1=ScrewD,d2=HeadD,h=Head);
         } else {
            translate([0,+Head-.51])
            rotate([-90,0])
            cylinder(d=HeadD+.3,h=L1);
         }
         translate([0,G+.51-Head])
         rotate([-90,0])
         cylinder(d1=ScrewD,d2=HeadD,h=Head);

      }
   }

   module Base_Shape() {
      translate([0,0,-L/2])
      linear_extrude(L,convexity = 5)
      difference() {

         union() {
            d=OuterD/2;
            W2=W/2;
            sh = Sholder;
            dt = Detent;
            polygon([[-W2+sh,G],[-W2+sh,T+sh],[-W2,T],[-W2,dt],[-W2+dt,0],[-d,0],[-d+dt,dt],
                     [d-dt,dt],[d,0],[W2-dt,0],[W2,dt],[W2,T],[W2-sh,T+sh],[W2-sh,G]]);
            translate([0,H])
            circle(d=OuterD+4,$fn=6);
         }

//         MirrorCopy([1,0])
//         translate([W/2-1.99,T])
//         polygon([[0,2],[2,0],[2,30],[0,30]]);

         translate([0,H]) {
            circle(d=ShaftD+Clearance);

            f=360/5;
            for (i=[0:5])
               rotate(i*f)
               square([ShaftD+3.5,1],center=true);
         }

      }

   }

}

module Slide_Bearing() {
   difference() {
      Base_Shape();
      translate([0,0,4])
      Band();
      translate([0,0,L-BandWid-4])
      Band();
   }

   module Band() {
      linear_extrude(BandWid,convexity=5)
      difference() {
         circle(d=OuterD);
         circle(d=OuterD-.5);
      }
   }

   module Base_Shape() {
      linear_extrude(L,convexity = 5)
      difference() {
         circle(d=OuterD);
         circle(d=ShaftD+Clearance);
         f=360/5;
         for (i=[0:5])
            rotate(i*f)
            square([ShaftD+3.5,1],center=true);
      }
   }

}

```


[User]
Hey, I'm looking to design a customizable token base for tabletop games, specifically for Magic the Gathering style tokens. I have a basic design in mind, but I want to make it parametric so it can be easily adjusted using OpenSCAD's customizer interface. The core of the design is a rounded rectangle, with recessed areas for text.

Here are the specific parameters and how they should be used:

**Overall Shape:**
*   The base should be a rounded rectangle, with a parameter controlling the rounding radius. The default radius I have in mind is 32.
*   The main dimensions should be adjustable; I'd like to set parameters for width and height. I want a default size of 62mm wide and 84mm tall.
*   The base should have a thickness that's also adjustable; a good default would be 3mm.
*   There should be a small lip or border around the edge of the base. I was using a minkowski difference to accomplish that but I'm open to other methods.

**Text Areas:**

*   **Token Name:** A text area near the top of the card should display the token name. This should be a single line of text, centered horizontally, and I want the ability to control the text size (default 5) as a parameter.
*   **Type Line:**  A text area should be placed below the token name for the type line. It should have adjustable text size (default 2), should also be a single line and align to the left edge of the rectangle. This should include the token's supertype, type, and creature type, like "Legendary Token Creature — Angel". All three should be individual parameters.
*   **Power/Toughness:** A power/toughness area should be on the bottom right of the base. This should also be single-line text that is centered, with adjustable text size (default 3). It will include something like "3/3". The power and toughness values should be separate parameters.
*   **Ability:** I need three different options for how to display abilities:
    *   **Vanilla:** No ability text is displayed, only the other text areas.
    *   **Short:** A single-line ability text area centered in the middle of the card. Adjustable text size (default 2) and a parameter for the text.
    *   **Multi-Line:** Instead of a single line ability text area it should have 6 lines to write abilities with, each having its own text parameter, with the text aligning to the left edge of the box. Adjustable text size (default 2).
*   The spacing and positioning of these text boxes should adapt to the overall dimensions of the base.

**Text Recesses:**

*   The text should be slightly recessed into the surface of the base, with the depth being a parameter.
*   To create the recessed effect for the text, I used a minkowski difference and a cylinder to create the groove. Open to other methods here as well.

**Customizer:**

*   I'd like to include some comments in the code describing each parameter.
*   I need to use OpenSCAD's customizer to change all parameters (base dimensions, rounding, text, etc.).

I'm not sure how to organize it all, but having one main file that handles all of the text output and an additional file that handles the rounded rectangle and text recess would be helpful. Let me know if you need any more info. I will be using OpenSCAD 2021.01 so you don't have to worry about any older versions. I am not using any special libraries for the time being.

[Assistant]
customizable_token_base.scad:
```

  //cube(size=[66,88,2], center=true);

  rounding= 32;
  token_name="name";
  creature_type="type";
  power="*";
  toughness="*";
  Super_type = "";
  typeline = str(Super_type, "Token Creature — ",creature_type);
   pt= str(power, " / ",toughness);
   ability_length = "Vanilla"; // [Vanilla, short, multi-line]

   ability = "Ability"; //for short ability
   abilityline1= "Ability Line 1";
   abilityline2= "Ability Line 2";
   abilityline3= "Ability Line 3";
   abilityline4= "Ability Line 4";
   abilityline5= "Ability Line 5";
   abilityline6= "Ability Line 6";

    $fn=rounding
    ;
    difference (){minkowski(){translate([0,0,-2])
        cube([62,84,3],center=true);
        rotate([0,0,0]) cylinder(h=0.1,r=2);

    }
    cube([62,84,3], center=true );
    };
;

translate([0,36,-2])
    difference (){minkowski(){translate([0,0,0])
        cube([53,1,3],center=true);
        rotate([0,0,0]) cylinder(h=0.5,r1=4, r2=3);}translate([0,-2,.11])linear_extrude(2)text( token_name ,size=5, halign = "center")
        ;}
        ;
if (ability_length=="Vanilla")
        {;
translate([0,-30,-2])
    difference (){minkowski(){translate([0,0,0])
        cube([53,1,3],center=true);
        rotate([0,0,0]) cylinder(h=0.5,r1=3, r2=2);}translate([-27.5,-1,.1])linear_extrude(2)text( typeline ,size=2)
        ;}

translate([24,-38,-2])
    difference (){minkowski(){translate([0,0,0])
        cube([8,1,3],center=true);
        rotate([0,0,0]) cylinder(h=0.5,r1=3, r2=2);}translate([0,-1.2,.1])linear_extrude(2)text( pt ,size=3, halign = "center")
        ;}

      }
      else if(ability_length=="short")
       {
     translate([0,-10,-2])
    difference (){minkowski(){translate([0,0,0])
        cube([53,1,3],center=true);
        rotate([0,0,0]) cylinder(h=0.5,r1=3, r2=2);}translate([-27.5,-1,.1])linear_extrude(2)text( typeline ,size=2)
        ;}

translate([24,-38,-2])
    difference (){minkowski(){translate([0,0,0])
        cube([8,1,3],center=true);
        rotate([0,0,0]) cylinder(h=0.5,r1=3, r2=2);}translate([0,-1.2,.1])linear_extrude(2)text( pt ,size=3, halign = "center")
        ;}
        ;
            translate([0,-26,-2])difference (){{translate([0,0,0])
        cube([58,27,3],center=true);        rotate([0,0,0]) linear_extrude(1.6)text( ability ,size=2, halign = "center",valign = "center")
        ;}
        ;
        } }
       ;
        if (ability_length=="multi-line")
        {;
translate([0,-10,-2])
    difference (){minkowski(){translate([0,0,0])
        cube([53,1,3],center=true);
        rotate([0,0,0]) cylinder(h=0.5,r1=3, r2=2);}translate([-27.5,-1,.1])linear_extrude(2)text( typeline ,size=2)
        ;}

translate([24,-38,-2])
    difference (){minkowski(){translate([0,0,0])
        cube([8,1,3],center=true);
        rotate([0,0,0]) cylinder(h=0.5,r1=3, r2=2);}translate([0,-1.2,.1])linear_extrude(2)text( pt ,size=3, halign = "center")
        ;}
        ;
            translate([0,-26,-2])difference (){{translate([0,0,0])
        cube([58,27,3],center=true);         translate([-27,8,0])linear_extrude(1.6)text( abilityline1 ,size=2, halign = "left");
     translate([-27,5,0])linear_extrude(1.6)text( abilityline2 ,size=2, halign = "left");translate([-27,2,0])linear_extrude(1.6)text( abilityline3 ,size=2, halign = "left");translate([-27,-1,0])linear_extrude(1.6)text( abilityline4 ,size=2, halign = "left");
     translate([-27,-4,0])linear_extrude(1.6)text( abilityline5 ,size=2, halign = "left");
       translate([-27,-7,0])linear_extrude(1.6)text( abilityline6 ,size=2, halign = "left");

        }

      }
  }
```


[User]
I'm looking to generate a finger-jointed box design suitable for laser cutting, but I want it to be fully parametric. I'd like the ability to control the following:

*   **Material Thickness:** The thickness of the material being used.
*   **Joint Proudness:** How far the fingers stick out past the edge of the joining piece (expressed as a multiplier of the material thickness).
*  **Split Point:** I'd like the box to be split into a top and bottom, and I want to be able to specify at what height that split happens. Specifically, I'd like to specify the split as the number of teeth from the top.
*   **Interior Dimensions:** The width, height, and depth of the box's interior.

The design should create all the necessary pieces for the box, including top, bottom, left, right, front, and back panels. The finger joints should be created automatically based on the material thickness and should be distributed evenly along the edges. The corners where the finger joints meet (where the horizontal and vertical teeth interact) should have little "corner tabs" as well, also based on the `proud` value, to ensure no gaps.

It'd be really cool if this could all be implemented in a way that's parametric, so I can change the dimensions and have the design update automatically. I'd prefer that the design generate *all* of the necessary parts and arrange them for laser cutting - for instance, it would be great if they could lay flat on the x/y plane. It'd also be helpful if the parts were arranged with enough spacing between them that they can easily be cut on the laser.

I don't have any code already written for this, so I'm hoping you could create this design entirely. I'm not looking to use any libraries for this design - just built-in OpenSCAD functions.

[Assistant]
big_box.scad:
```
/*[ Slider ]*/
// Material thickness
thickness=5; // [2:.1:8]
/*[ Slider ]*/
// The lenght of the join fingers = Thickness * Proud
proud=1.1; //[1:.1:2]
/*[ Slider ]*/
// Where the top splits from the bottom (# of teeth from the top)
split=10; //[10]
/*[ Slider ]*/
// Interior width
width=60; //[60]
/*[ Slider ]*/
// Interior height
height=70; //[70]
/*[ Slider ]*/
// Interior depth
depth=80; //[80]

width_tooth=width/floor(width/(thickness*2)+.5)/2;
height_tooth=height/floor(height/(thickness*2)+.5)/2;
depth_tooth=depth/floor(depth/(thickness*2)+.5)/2;

module net() {
//top and bottom
projection() {
   cube([width,depth,1]);
   for(y=[0:depth_tooth*2:depth-depth_tooth]) {
      translate([width-.0001,y,0])cube([thickness*proud,depth_tooth,1]);
   }
   for(x=[width-width_tooth:-width_tooth*2:0]) {
      translate([x,depth-.0001,0])cube([width_tooth,thickness*proud,1]);
   }
   for(y=[depth-depth_tooth:-depth_tooth*2:0]) {
      translate([-thickness*proud+.0001,y,0])cube([thickness*proud,depth_tooth,1]);
   }
   for(x=[0:width_tooth*2:width-width_tooth]) {
      translate([x,-thickness*proud+.0001,0])cube([width_tooth,thickness*proud,1]);
   }
}

//left and right
//projection()translate([width+4*thickness,0,0]) left_and_right();
translate([width+3*thickness*proud,0,0])projection() {
   intersection()
   {
      left_and_right();
      translate([-thickness*proud,-2*thickness*proud,-1])cube([thickness*proud+split*height_tooth,depth+4*thickness*proud,3]);
   }
}

translate([width+4*thickness*proud,0,0])projection() {
   intersection() {
      left_and_right();
      translate([split*height_tooth,-2*thickness*proud,-1])cube([height-split*height_tooth+thickness*proud,depth+4*thickness*proud,3]);
   }
}
module left_and_right() {
   cube([height,depth,1]);
   for(y=[0:depth_tooth*2:depth-depth_tooth]) {
      translate([height-.0001,y,0])cube([thickness*proud,depth_tooth,1]);
   }
   for(x=[height-height_tooth:-height_tooth*2:0]) {
      translate([x,depth-.0001,0])cube([height_tooth,thickness*proud,1]);
   }
   for(y=[depth-depth_tooth:-depth_tooth*2:0]) {
      translate([-thickness*proud+.0001,y,0])cube([thickness*proud,depth_tooth,1]);
   }
   for(x=[0:height_tooth*2:height-height_tooth]) {
      translate([x,-thickness*proud+.0001,0])cube([height_tooth,thickness*proud,1]);
   }
   translate([-proud*thickness+.0001,-proud*thickness+.0001,0])cube([proud*thickness,proud*thickness,1]);
   translate([height-.0001,depth-.0001,0])cube([proud*thickness,proud*thickness,1]);
}

//front and back
//projection()translate([0,depth+4*thickness,0]) front_and_back();
translate([0,depth+3*thickness*proud,0])projection() {
   intersection()
   {
      front_and_back();
      translate([-2*thickness*proud,-thickness*proud,-1])cube([width+4*thickness*proud,thickness*proud+split*height_tooth,3]);
   }
}

translate([0,depth+4*thickness*proud,0])projection() {
   intersection() {
      front_and_back();
      translate([-2*thickness*proud,split*height_tooth,-1])cube([width+4*thickness*proud,height-split*height_tooth+thickness*proud,3]);
   }
}
module front_and_back() {
   cube([width,height,1]);
   for(y=[0:height_tooth*2:height-height_tooth]) {
      translate([width-.0001,y,0])cube([thickness*proud,depth_tooth,1]);
   }
   for(x=[width-width_tooth:-width_tooth*2:0]) {
      translate([x,height-.0001,0])cube([width_tooth,thickness*proud,1]);
   }
   for(y=[height-height_tooth:-height_tooth*2:0]) {
      translate([-thickness*proud+.0001,y,0])cube([thickness*proud,height_tooth,1]);
   }
   for(x=[0:width_tooth*2:width-width_tooth]) {
      translate([x,-thickness*proud+.0001,0])cube([width_tooth,thickness*proud,1]);
   }
   translate([width-.0001,-proud*thickness+.0001,0])cube([proud*thickness,proud*thickness,1]);
   translate([-proud*thickness+.0001,height-.0001])cube([proud*thickness,proud*thickness,1]);
}
}
net();
translate([2*width+height+7*thickness*proud,2*depth+4*thickness*proud,0])rotate([0,0,180])net();

```


[User]
Hey, I'm looking to create some customizable Gridfinity bins, and I'd like to have an OpenSCAD file that lets me tweak all the main parameters. I've seen some good starting points, but I want full control over the features.

Specifically, I need to be able to define:

*   **Basic dimensions:**
    *   Width of the bin (in grid units, so like 1, 2, 3, etc.)
    *   Depth of the bin (also in grid units)
    *   Height of the bin (in gridfinity height units, where each unit is 7mm)
    *   The number of internal chambers/dividers inside the bin

*   **Optional features:**
    *   A label shelf (on or off)
    *   Finger slides at the bottom for easy part retrieval (on or off)
    *   Magnet holes in the bottom for mounting (on or off)
*   **Magnet parameters:**
    *   Magnet height (in mm)
    *   Magnet hole diameter (for press-fit, with a default of 6.1mm)

I’d also need the proper tolerances so that it works with the existing Gridfinity system, so assuming a 42mm grid pitch and 7mm height per unit. It should also include the stackable feature as is normally present in Gridfinity bins.  I don't need anything fancy but I'm not sure how to get all these options into a good user friendly system.

I would also like for the label, finger slides, and magnet features to be controlled by a numerical 0/1 input rather than a boolean since some customizer options seem to fail on true/false values for some reason. So when setting 'label' to '1' it is on, and '0' it is off.

[Assistant]
Gridfinity_Customizable_Divider_Bins_-_Enhanced_20230905_2.scad:
```
//File: Gridfinity Customizable Divider Bins - Enhanced_20230905_2.scad
//By: kheidolph
//Last modified: 20230905-2004

/* [Basics] */

// Width of the box
width = 1; //[1:20]

// Depth of the box
depth = 1; //[1:20]

// Height of the box in units of of 7mm
// Normally a full size box is 6 units high
height = 6; //[2:24]

// Number of chambers
chambers = 1; //[1:20]

// Should there be a shelf for a label
label = 1; //[1, 0]

// Finger slides at the bottom to help get small parts out
finger_slide = 1; //[1, 0]

/* [Magnets] */

// Should there be magnet holes?
magnets = 1; //[1, 0]

// Height of magnets in mm
magnet_height = 3; // [2, 3]

// Tune the diameter of magnet holes (in mm) for good press-fit tightness.  6.1mm usually works well
magnet_diameter = 6.1; //[5.9:0.02:6.3]

basic_cup(depth, width, height, chambers=chambers);

module basic_cup(num_x=1, num_y=1, num_z=2, bottom_holes=0, chambers=1) {
  difference() {
    grid_block(num_x, num_y, num_z, magnets ? magnet_height : 0);
    color("red") partitioned_cavity(num_x, num_y, num_z, chambers);
  }
}

module partitioned_cavity(num_x=2, num_y=1, num_z=2, chambers=3) {
  // cavity with removed segments so that we leave dividing walls behind
  gp = gridfinity_pitch;
  outer_wall_th = 1.8;  // cavity is this far away from the 42mm 'ideal' block
  inner_wall_th =1.2;

  bar_d = 1.2;
  zpoint = gridfinity_zpitch*num_z;

  yz = [[ (num_y-0.5)*gridfinity_pitch-14, zpoint-bar_d/2 ],
    [ (num_y-0.5)*gridfinity_pitch, zpoint-bar_d/2 ],
    [ (num_y-0.5)*gridfinity_pitch, zpoint-bar_d/2-10.18 ]
  ];

  cavity_xsize = gp*num_x-2*outer_wall_th;
  chamber_pitch = (cavity_xsize+inner_wall_th)/chambers;  // period of repeating walls

  difference() {
    basic_cavity(num_x, num_y, num_z);

    if (chambers >= 2) {
      for (i=[1:chambers-1]) {
        translate([-gp/2+outer_wall_th-inner_wall_th+i*chamber_pitch, -gp/2, 0])
        cube([inner_wall_th, gp*num_y, gridfinity_zpitch*(num_z+1)]);
      }
    }
    // this is the label
    if (label) {
      hull() for (i=[0,1, 2])
      translate([-gridfinity_pitch/2, yz[i][0], yz[i][1]])
      rotate([0, 90, 0]) cylinder(d=bar_d, h=num_x*gridfinity_pitch, $fn=24);
    }
  }
}

module basic_cavity(num_x=2, num_y=1, num_z=2) {
  eps = 0.1;
  q = 1.65;
  q2 = 2.15;
  zpoint = gridfinity_zpitch*num_z-1.2;
  facets = 13;

  difference() {
    union() {
      // cut downward from base
      hull() cornercopy(17, num_x, num_y) {
        translate([0, 0, zpoint-eps]) cylinder(d=2.3, h=1.2+2*eps, $fn=24);
      }

      hull() cornercopy(17, num_x, num_y) {
        // create bevels below the lip
        translate([0, 0, zpoint-0.1]) cylinder(d=2.3, h=0.1, $fn=24);
        translate([0, 0, zpoint-q-q2]) cylinder(d=2.3+2*q, h=q2, $fn=32);
        // create rounded bottom of bowl (8.3 is high enough to not expose gaps)
        translate([0, 0, 8.3]) sphere(d=2.3+2*q, $fn=32);
      }
    }

    // cut away from the negative to leave behind wall to make it easier to remove piece
    pivot_z = 11.6+2;
    pivot_y = -12+2;

    // rounded inside bottom
    if(finger_slide){
    for (ai=[0:facets-1]) translate([0, pivot_y, pivot_z])
      rotate([90*ai/(facets-1), 0, 0]) translate([0, -pivot_y, -pivot_z])
      translate([-gridfinity_pitch/2, -10-17-1.15, 0])
      cube([gridfinity_pitch*num_x, 10, gridfinity_zpitch*num_z+5]);
    }
  }
}
gridfinity_pitch = 42;
gridfinity_zpitch = 7;
gridfinity_clearance = 0.5;  // each bin is undersize by this much

// basic block with cutout in top to be stackable, optional holes in bottom
// start with this and begin 'carving'
module grid_block(num_x=1, num_y=1, num_z=2, bot_hole_depth=3.1, center=false) {
  bot_hole_extra = 0.1;
  corner_radius = 3.75;
  outer_size = gridfinity_pitch - gridfinity_clearance;  // typically 41.5
  block_corner_position = outer_size/2 - corner_radius;  // need not match center of pad corners

  totalht=gridfinity_zpitch*num_z+3.75;
  translate( center ? [-(num_x-1)*gridfinity_pitch/2, -(num_y-1)*gridfinity_pitch/2, 0] : [0, 0, 0] )
  difference() {
    intersection() {
      union() {
        // grid of pads
        gridcopy(num_x, num_y) pad_oversize();
        // main body will be cut down afterward
        translate([-gridfinity_pitch/2, -gridfinity_pitch/2, 5])
        cube([gridfinity_pitch*num_x, gridfinity_pitch*num_y, totalht-5]);
      }

      // crop with outer cylinders
      translate([0, 0, -0.1])
      hull()
      cornercopy(block_corner_position, num_x, num_y)
      cylinder(r=corner_radius, h=totalht+0.2, $fn=44);
    }

    // remove top so XxY can fit on top
      color("blue")
      translate([0, 0, gridfinity_zpitch*num_z])
      pad_oversize(num_x, num_y, 1);

    // add holes in bottom pads if requested
    if (bot_hole_depth > 0) {
      gridcopy(num_x, num_y) bottomholes(bot_hole_depth + bot_hole_extra);
    }
  }
}

// holes in the bottom of the pads (slightly short to allow deeper
module bottomholes(depth=3.1) {
  magnet_position = 13;
  magnet_od = magnet_diameter;
  magnet_thickness = depth;
  eps = 0.1;  // differences are annoying with coincident faces
  if (depth > 0) {
    cornercopy(magnet_position) {
      translate([0, 0, -eps])
            hull() {
                cylinder(d=magnet_od, h=magnet_thickness+eps, $fn=41);
                translate([0, 0, magnet_thickness]) cylinder(d1=magnet_od, d2=magnet_od/2, h=magnet_od/4, $fn=42);
            }
      cylinder(d=1, h=depth, $fn=28);
    }
  }
}

// unit pad slightly oversize at the top to be trimmed or joined with other feet or the rest of the model
// also useful as cutouts for stacking
module pad_oversize(num_x=1, num_y=1, margins=0) {
  pad_corner_position = 17; // must be 17 to be compatible
  bevel1_top = 0.8;     // z of top of bottom-most bevel (bottom of bevel is at z=0)
  bevel2_bottom = 2.6;  // z of bottom of second bevel
  bevel2_top = 5;       // z of top of second bevel
  bonus_ht = 0.2;       // extra height (and radius) on second bevel

  // female parts are a bit oversize for a nicer fit
  radialgap = margins ? 0.25 : 0;  // oversize cylinders for a bit of clearance
  axialdown = margins ? 0.1 : 0;   // a tiny bit of axial clearance present in Zack's design

  translate([0, 0, -axialdown])
  difference() {
    union() {
      hull() cornercopy(pad_corner_position, num_x, num_y) {
        cylinder(d=1.6+2*radialgap, h=0.1, $fn=24);
        translate([0, 0, bevel1_top]) cylinder(d=3.2+2*radialgap, h=1.9, $fn=32);
      }

      hull() cornercopy(pad_corner_position, num_x, num_y) {
        translate([0, 0, bevel2_bottom])
        cylinder(d1=3.2+2*radialgap, d2=7.5+0.5+2*radialgap+2*bonus_ht, h=bevel2_top-bevel2_bottom+bonus_ht, $fn=32);
      }
    }

    // cut off bottom if we're going to go negative
    if (margins) {
      translate([-gridfinity_pitch/2, -gridfinity_pitch/2, 0])
      cube([gridfinity_pitch*num_x, gridfinity_pitch*num_y, axialdown]);
    }
  }
}

// similar to quadtranslate but expands to extremities of a block
module cornercopy(r, num_x=1, num_y=1) {
  for (xx=[-r, gridfinity_pitch*(num_x-1)+r]) for (yy=[-r, gridfinity_pitch*(num_y-1)+r])
    translate([xx, yy, 0]) children();
}

// make repeated copies of something(s) at the gridfinity spacing of 42mm
module gridcopy(num_x, num_y) {
  for (xi=[1:num_x]) for (yi=[1:num_y]) translate([gridfinity_pitch*(xi-1), gridfinity_pitch*(yi-1), 0]) children();
}

```


[User]
Hey, I'm looking to create a stand for a radio, specifically the Retevis RT95. I've got a basic design in mind, but I need help generating the OpenSCAD files.

Essentially, the stand has two legs, each made from a few interconnected pieces, and two connecting bars. The legs should allow the radio to sit at an adjustable angle, let's say between 10 and 80 degrees. They also have a back support section that can be adjusted, this time with a smaller range from 0 to 80 degrees, that supports the radio's back.

The length of these supporting legs should be adjustable, too, somewhere between 50 and 240 mm. The bars connecting the two legs should also have adjustable lengths, in the range of 20-200 mm. Finally, I need to be able to adjust for the thickness of the radio, which would be controlled by a parameter that sets the "depth" of one section of the leg. Let's say that ranges from 0 to 200mm. There should also be a tolerance setting to tweak fit of the various parts.

I'd like to generate separate files for the leg (which should include the back support) and the bar components, but I need a way to also generate them all assembled together. So, I was thinking a parameter that controls which part to generate - "Assembled", "Side", or "Bar". The "Side" part should be a single leg with all the interconnected parts assembled.

I'd like the side pieces to have a notch at the top, so the radio sort of slides into it and rests there, and similarly, the bars should have small notches that fit into the "leg" pieces.

It'd be good to see how everything looks while using different view angles while I'm designing this, so I'd also want the preview window to be set to "south west" view, and "top diagonal" tilt angle.

I think that's everything, let me know if you have any questions. Oh, and I'd like the files to not rely on any libraries other than the built-in OpenSCAD ones.

[Assistant]
Retevis_RT95_Stand.scad:
```
// preview[view:south west, tilt:top diagonal]

// Angle of stand
Angle = 20; // [10:80]

// Angle of back support
BackAngle = 5; // [0:80]

// Length of support
SupportLength = 150; // [50:240]

// Length of connecting bars
BarLength = 120; // [20:200]

// How thick the device is
BraceDepth = 50; // [0:200]

Tolerance = 0.1; // [0, 0.1, 0.2, 0.3, 0.4, 0.5]

part = "Assembled"; // [Assembled: Assembled, Side: Side, Bar: Bar]

SubAngle = -(90-Angle);

SharedAngle = -SubAngle + BackAngle;
comp = (10/sin(SharedAngle));

truecomp = (SharedAngle > 90 ? comp : (SharedAngle == 90 ? 1 : 0));

echo(truecomp);

SubBackAngle = (90-BackAngle);

if(part=="Assembled")
{
	rotate([90, 0, 0]) Leg(Angle, BackAngle, SupportLength, Tolerance);

	translate([0, BarLength+10, 0])rotate([90, 0, 0]) Leg(Angle, BackAngle, SupportLength, Tolerance);
	rotate([-90, 0, 90]) translate([-10, -10, -10]) Bar(BarLength, Tolerance);
	rotate([-90, 0, 90]) translate([-10, -10, -10 - (cos(Angle)*SupportLength + sin(BackAngle)*(sin(Angle)*SupportLength)/cos(BackAngle)-10 + 10 - 10*tan(BackAngle))]) Bar(BarLength, Tolerance);
}
if(part=="Side")
{
	Leg(Angle, BackAngle, SupportLength, Tolerance);
}
if(part=="Bar")
{
	Bar(BarLength, Tolerance);
}

module Bar(BarLength, Tolerance)
{
	difference()
	{
		cube([BarLength+20, 10, 10]);
		translate([-0.5, 7 - Tolerance, -0.5]) cube([10.5+ Tolerance, 4 + Tolerance, 11]);
		translate([-0.5, -1 + Tolerance, -0.5]) cube([10.5+ Tolerance, 4, 11]);
		translate([-0.5, -0.5, 7 - Tolerance * 2]) cube([10.5+ Tolerance, 11, 4 + Tolerance * 2]);
		translate([BarLength+10 - Tolerance, 7 - Tolerance, -0.5]) cube([10.5 + Tolerance, 4 + Tolerance, 11]);
		translate([BarLength+10 - Tolerance, -1 + Tolerance, -0.5]) cube([10.5+ Tolerance, 4, 11]);
		translate([BarLength+10 - Tolerance, -0.5, 7 - Tolerance * 2]) cube([10.5+ Tolerance, 11, 4 + Tolerance * 2]);
	}
}

module Leg(Angle, BackAngle, SupportLength, Tolerance)
{
difference()
{
	union()
	{
		cube([10, 10, 10]);
		rotate([0, 0, SubAngle]) translate([-BraceDepth, 0, 0]) cube([BraceDepth, 10, 10]);
		rotate([0, 0, Angle]) translate([0, BraceDepth, 0]) cube([20, 5, 10]);
//		rotate([0, 0, SubAngle]) translate([-14, 10, 0]) %cube([10, 10, 10]);
		translate([10, 0, 0]) rotate([0, 0, Angle]) translate([0, 0, 0]) cube([SupportLength, 10, 10]);

		difference()
		{
			cube([cos(Angle)*SupportLength + sin(BackAngle)*(sin(Angle)*SupportLength)/cos(BackAngle) + 10 - 10*tan(BackAngle), 10, 10]);
//			translate([10, 0, 0]) rotate([0, 0, Angle]) translate([SupportLength, 0, 0]) rotate([0, 0, -Angle + BackAngle+90]) translate([(-sin(Angle)*SupportLength)/cos(BackAngle), -10, -0.5]) cube([(sin(Angle)*SupportLength)/cos(BackAngle), 10, 11]);
		}

		difference()
		{
			translate([10, 0, 0]) rotate([0, 0, Angle]) translate([SupportLength, 0, 0]) rotate([0, 0, -Angle + BackAngle+90]) translate([(-sin(Angle)*SupportLength)/cos(BackAngle), 0, 0]) cube([(sin(Angle)*SupportLength)/cos(BackAngle) + truecomp, 10, 10]);
			translate([0, -10, -0.5]) cube([cos(Angle)*SupportLength + sin(BackAngle)*(sin(Angle)*SupportLength)/cos(BackAngle) + 10*tan(SubBackAngle), 10, 11]);
		}
	}
	translate([3 + Tolerance, 3, -0.5]) cube([7, 4, 11]);
	translate([cos(Angle)*SupportLength + sin(BackAngle)*(sin(Angle)*SupportLength)/cos(BackAngle)- 7 + Tolerance + 10 - 10*tan(BackAngle), 3, -0.5]) cube([8, 4, 11]);
	translate([cos(Angle)*SupportLength + sin(BackAngle)*(sin(Angle)*SupportLength)/cos(BackAngle) + 10 - 10*tan(BackAngle), -10, -0.5]) cube([20, 20, 11]);
}
}
```