[User]
I'd like to have a cutting guide for my Dremel drill press stand, similar to the one I have, but I want to be able to generate it parametrically. It should have two cylindrical cutouts for mounting screws. It should have a main body, which is essentially a rectangle with those cylindrical cutouts removed. I'd like to be able to specify the length of this main body, the inner radius of the screw holes, the wall thickness, and the overall height of the guide. I also want to have the option to add a triangular guide along one side. This should have its own configurable width and height. I'd like to enable or disable this guide with a boolean. Finally, I'd like to have ruler indentations along the back, with configurable depth, inner and outer widths, and spacing between them, also enabled or disabled with a boolean. I also need the ability to specify `$fn`.

I would like all the parameters to be configurable via the customizer.

I'm thinking I could also use the "Nuts and Bolts customizer" from thingiverse to create any custom bolt/nut, but I don't need you to include any parts from that library, but it would be good to specify the correct size screw based on the user provided `inner` diameter.

Also, could you make sure to use the hull() function when making the main body so that the corners are rounded off nicely. Also, use a series of hulls to make the cylindrical cutouts as well.

I guess the overall structure would be a difference operation of the main body and the cylinder cutouts, as well as the ruler indentations.  Then there would be a separate conditional hull for the triangle guide.

I'm not really sure on the best way to structure the code, but it would be useful to have a comment above each configurable variable specifying what it refers to.

[Assistant]
cutting_guide.scad:
```
// Length of the cutting guide
length = 160;
// Inner cutout for the screws
inner = 8.5;
// Thickness of the walls
walls = 3.5;
// Height of the cutting guide
height = 5;

/* [Guide] */
// Enable guide
guide = "enabled"; // [enabled: Enabled, disabled: Disabled]
// Width of the triangular guide
guideWidth = 8;
// Height of the triangular guide
guideHeight = 2;

/* [Ruler] */
ruler = "enabled"; // [enabled: Enabled, disabled: Disabled]
// Depth of the intendation
indentationDepth = 1.2;
// Inner width of intendation
indentationInner = 1;
// Outer width of intendation
indentationOuter = 1;
// Space between intendations
steps = 5;

/* [Hidden] */
$fn = 64;
innerRadius = inner / 2;
outerRadius = innerRadius + walls;
offsetY = guideWidth / 2 + walls;
offsetY = innerRadius + guideWidth / 2 + walls / 2;

difference() {
    hull() {
        translate([0, length / 2 - outerRadius, 0])
            cylinder(r = outerRadius, h = height);

        translate([0, -length / 2 + outerRadius, 0])
            cylinder(r = outerRadius, h = height);
    }

    hull() {
        translate([0, length / 2 - innerRadius - walls, -1])
            cylinder(r = innerRadius, h = height + 2);

        translate([0, offsetY, -1])
            cylinder(r = innerRadius, h = height + 2);
    }

    hull() {
        translate([0, -offsetY, -1])
            cylinder(r = innerRadius, h = height + 2);

        translate([0, -length / 2 + outerRadius, -1])
            cylinder(r = innerRadius, h = height + 2);
    }

    if(ruler == "enabled") {
        for(i=[0:1:(length / 2 / steps - outerRadius / steps)]) {
            hull() {
                translate([-outerRadius + indentationDepth, steps * i - indentationInner / 2, -1])
                    cube([0.1, indentationInner, height + 2]);

                translate([-(outerRadius + indentationDepth), steps * i - indentationOuter / 2, -1])
                    cube([0.1, indentationOuter, height + 2]);
            }
        }

        for(i=[0:-1:-(length / 2 / steps - outerRadius / steps)]) {
            hull() {
                translate([-outerRadius + indentationDepth, steps * i - indentationInner / 2, -1])
                    cube([0.1, indentationInner, height + 2]);

                translate([-(outerRadius + indentationDepth), steps * i - indentationOuter / 2, -1])
                    cube([0.1, indentationOuter, height + 2]);
            }
        }
    }
}

if(guide == "enabled") {
    hull() {
        translate([-outerRadius, -guideWidth / 2, height - 0.1])
            cube([outerRadius * 2, guideWidth, 0.1]);

        translate([-outerRadius, 0.05, height + guideHeight - 0.1])
            cube([outerRadius * 2, 0.1, 0.1]);
    }
}
```


[User]
Hi, I'm looking for an OpenSCAD design for a specialized tool. It's basically an Allen wrench with a nut holder on the end, designed to help start locknuts in tight spots. I have a pretty good idea of what I need, but I'd like the design to be parametric so I can adjust it for different nuts and Allen wrench sizes.

Here are the parameters I need:

1.  **Allen Wrench Size Across Flats:** This will be the standard size of the Allen wrench, like 5mm, 6mm, etc.
2.  **Allen Wrench Handle Length:** This is the overall length of the wrench handle itself, probably in the 30-100mm range.
3.  **Handle Type:** I need an option for either a straight or curved handle.
4.  **Handle Curve Radius:** If the handle is curved, this parameter controls the radius of the bend.
5.  **Nut Flat Dimension:** This is the size across the flats of the nut that the tool will hold. I need to be able to specify this for different nut sizes (M3, M4, M5, M6, #4, #5, #6, #8, #10, etc).
6.  **Nut Socket Tolerance:** This allows me to add a little bit of clearance to the nut socket to ensure a good fit, something like -.4 to .4 mm.
7.  **Nut Socket Height:** The vertical height of the nut socket.
8.  **Socket-to-Wrench Transition Height:** This is the height where the nut socket transitions to the Allen wrench shaft.
9.  **Nut Socket Depth:** This is how far the nut is recessed into the socket.
10. **Added Height to Allen Wrench End:** This is extra height on the end of the Allen wrench.
11. **Socket Rotation:**  The option to rotate the socket head to a degree up to 60, if needed.
12. **Socket Wall Thickness:**  The wall thickness of the nut socket, ideally 1.65mm or more.
13. **Slice End Option:** An option to slice a bit of the socket away for clearance if needed.
14. **Socket On/Off:** I need the ability to turn off the socket so that I can use the design as just a plastic allen wrench.

I'm thinking this design could use a `hull()` for the transition from the socket to the wrench, and `difference()` operations for creating the nut socket. I'd like to use a `rotate_extrude()` for the curved handle, if possible. I think I will need the standard OpenSCAD `math.scad` library for some trig functions for this.

Could you provide a parametric OpenSCAD file for this?  Thanks!

[Assistant]
SpecialNutHoldingTool_Rev10.scad:
```
//Special Allen Wrench style Nut Holder
//This holds a locknut in place to get threads started
//8/24/2017 By: David Bunch
//
//CUSTOMIZER VARIABLES

//1. Allen Wrench Size across the Flats
Allen_Handle_Flat = 5;      //[4:4mm, 5:5mm, 6:6mm, 8:8mm, 10:10mm]

//2. Length of Allen Wrench Handle
Allen_Handle_Len = 50;      //[30:5:100]

//3. Straight or Curved Handle
Handle_Type = 1;            //[0:Straight, 1:Curved]

//4. Radius of Allen Wrench Handle
Allen_Curve_Rad = 19;       //[12:1:30]

//5. Dimension across Nut Flats
NutFlat = 6.86;             //[5.55:M3 Nut, 6.86:M4 Nut, 7.86:M5 Nut, 9.83:M6 Nut, 6.35:#4 Nut, 7.94:#5 Nut, 7.94:#6 Nut, 8.73:#8 Nut, 9.53:#10 Nut]

//6. Additional amount to add to Socket opening
Tolerance = .25;            // [-.4:.05:.4]

//7. Height of Socket
Socket_Ht = 5;              //[5:.5:10]

//8. Height of transition of socket to Allen Wrench
Sockt_T_Ht = 4;             //[0:.5:6]

//9. How far to recess Nut socket
Nut_Depth = 4;              //[1:.5:6]

//10. Added height to end of Allen Wrench
Add_Ht = 7;                 //[0:.5:30]

//11. Rotation amount of Socket head
Rot_Head = 45;              //[0:1:60]

//12. Thickness of Socket Wall
Thk = 2;                    //[1.8:.2:4]
                            //(1.65mm minimum recommended)

//13. Slice End for More Clearance
Slice_ON = 1;               //[0:NO, 1:YES]

//14. Add Socket (In case you only want an Allen Wrench)
Socket_ON = 1;               //[0:NO, 1:YES]
/* [Hidden] */

//#4 thru #10 Nut dimensions taken from:
//https://www.boltdepot.com/Hex_machine_screw_nuts_Zinc_plated_steel.aspx?nv=l

Al_C_Rad = Handle_Type * Allen_Curve_Rad;       //How to get 0 radius for straight handle
Allen_Handle_Flat_Rad = Allen_Handle_Flat / 2;
Allen_Handle_OD = ((Allen_Handle_Flat / 2) /cos(30)) * 2;
Allen_Handle_Rad = Allen_Handle_OD / 2;
Allen_Curve_Res = Allen_Curve_Rad * 3.14;
echo(Allen_Curve_Res = Allen_Curve_Res);

Nut_Flat_OD = NutFlat + Tolerance;      //Add Tolerance fit to OD across Flat sides of Nut
Out_Flat_OD = Nut_Flat_OD + Thk + Thk;  //Outside Diameter
Out_Flat_Rad = Out_Flat_OD / 2;
Flat_Rad = Nut_Flat_OD / 2;
Nut_OD = (Flat_Rad /cos(30)) * 2;       //Diameter of 6 sided Nut we are holding
Out_OD = (Out_Flat_Rad /cos(30)) * 2;   //Outside of Socket Diameter
Allen_Curve_OD = Allen_Curve_Rad * 2;
echo(Nut_Flat_OD = Nut_Flat_OD);
echo(Nut_OD = Nut_OD);
echo(Out_OD = Out_OD);
echo(Allen_Handle_OD = Allen_Handle_OD);
echo(Allen_Handle_Flat_Rad = Allen_Handle_Flat_Rad);
$fn=24;
//Transition of the Socket to the Allen Wrench
module Socket_Trans()
{
    hull()
    {
        rotate([-Rot_Head,0,0])
        rotate([0,0,30])
        cylinder(d=Out_OD,h=.1,$fn=6);
        translate([0,0,-Sockt_T_Ht-Add_Ht-.01])
        rotate([0,0,Handle_Type*30])
        cylinder(d=Allen_Handle_OD,h=Add_Ht+.01,$fn=6);
    }
}
//Create the Socket End
module Socket_End()
{
    difference()
    {
        union()
        {
            rotate([-Rot_Head,0,0])
            difference()
            {
                union()
                {
                    difference()
                    {
                        rotate([0,0,30])
                        cylinder(d=Out_OD,h=Socket_Ht,$fn=6);
                        translate([0,0,Socket_Ht-Nut_Depth])
                        rotate([0,0,30])
                        cylinder(d=Nut_OD,h=Nut_Depth+1,$fn=6);
                        translate([0,0,Socket_Ht-.6])
                        rotate([0,0,30])
                        cylinder(d1=Nut_OD,d2=Nut_OD+1,h=.61,$fn=6);
                    }
                }
            }
            Socket_Trans();
        }
        if (Rot_Head > 0)
        {
            if (Slice_ON == 1)
            {
                rotate([-Rot_Head,0,0])
                translate([-Out_OD/2,-Out_OD-(Allen_Handle_OD/2),-Sockt_T_Ht-1])
                cube([Out_OD,Out_OD,Socket_Ht+Sockt_T_Ht+2]);
            }
        }
    }
}
module SP_AllenWrench()
{
    difference()
    {
        union()
        {
//Draw the Allen Wrench Handle with the 90 degree curve
            rotate([-90,0,0])
            {
                rotate([0,90,0])
                cylinder(d=Allen_Handle_OD,h=Allen_Handle_Len,$fn=6);
                translate([Allen_Handle_Len,-Allen_Curve_Rad,0])
                if (Handle_Type == 1)
                {
                    difference()
                    {
                        rotate_extrude(angle=360, convexity=10,$fn=Allen_Curve_Res)
                        translate([Allen_Curve_Rad,0,0])
                        rotate([0,0,30])
                        circle(d=Allen_Handle_OD,$fn=6);
//workardound for Thingiverse customizer not liking partial rotate_extrudes
                        translate([-Allen_Curve_OD,-Allen_Curve_OD,-Allen_Handle_OD])
                        cube([Allen_Curve_OD,Allen_Curve_OD*2,Allen_Handle_OD*2]);
                        translate([-1,-Allen_Curve_OD,-Allen_Handle_OD])
                        cube([Allen_Curve_OD,Allen_Curve_OD,Allen_Handle_OD*2]);
                    }
                }
            }
            if (Socket_ON == 1)
            {
//Add the Socket end to the top of the Allen Wrench part
                {
                    if (Handle_Type == 1)
                    {
                        translate([Allen_Handle_Len+Al_C_Rad-.02,0,Al_C_Rad+Sockt_T_Ht+Add_Ht])
                        difference()
                        {
                            Socket_End();
//Cut again after rotating
                            if (Slice_ON == 1)
                            {
                                translate([-Out_OD/2,-Out_OD-(Allen_Handle_OD/2),-Sockt_T_Ht-Add_Ht-1])
                                cube([Out_OD,Out_OD,Socket_Ht+Sockt_T_Ht+Add_Ht+2]);
                            }
                        }
                    } else
                    {
                translate([Allen_Handle_Len+Sockt_T_Ht+Add_Ht,0,0])
                        rotate([0,90,0])
                        rotate([0,0,90])
                        difference()
                        {
                            Socket_End();
//Cut again after rotating
                            if (Slice_ON == 1)
                            {
                                translate([-Out_OD/2,-Out_OD-(Allen_Handle_OD/2),-Sockt_T_Ht-Add_Ht-1])
                                cube([Out_OD,Out_OD,Socket_Ht+Sockt_T_Ht+Add_Ht+2]);
                            }
                        }
                    }
                }
            } else
            {
                if (Handle_Type == 1)
                {
                    translate([Allen_Handle_Len+Allen_Curve_Rad-.02,0,Allen_Curve_Rad+Sockt_T_Ht+Add_Ht])
                    translate([0,0,-Sockt_T_Ht-Add_Ht])
                    rotate([0,0,30])
                    cylinder(d=Allen_Handle_OD,h=Add_Ht,$fn=6);
                }
            }

        }
        translate([0,0,-(Allen_Handle_Flat / 2)-5])
        cylinder(d=Allen_Handle_Len*4,h=5,$fn=12);
    }
}
//Move the wrench up to build platform
translate([0,0,Allen_Handle_Flat/2])
SP_AllenWrench();
```


[User]
Hi, I'm looking to create a customizable LEGO Technic perpendicular connector in OpenSCAD, similar to the included example. The core functionality will be generating a 90-degree angular beam with customizable hole counts along each axis.

Specifically, I need a parametric design where I can specify:

*   `NrOfHolesX`: The number of pin holes along the X-axis of the beam.
*   `NrOfHolesY`: The number of pin holes along the Y-axis of the beam.
*  All the other dimension variables should be easily customizable as well (like `Pitch`, `Radius`, `Height`, etc.).

The beam should consist of:

*   Two perpendicular beam segments.
* Each beam should have a rectangular base with a central reinforcing section.
* Each beam will also need the cylindrical pin holes with a stepped profile for Lego Technic axle compatibility (inner radius, outer radius and height and depth).

The provided example includes a module `drawBeam` for generating one beam segment which will be used twice in the main code to construct the 90 degree connector. It would be good to maintain this structure, using a similar module structure to simplify generating the main model.

I would like the code to be as clean and well-commented as possible, and should adhere to good OpenSCAD practices, using modules to help make it flexible and easy to understand.

Essentially, I want a fully parametric model that lets me easily generate different sizes of these perpendicular connectors, based on the number of holes in each direction, and the other dimensional parameters.

[Assistant]
Lego_Technic_-_Perpendicular_Connector_customizable.scad:
```
$fn=40;

eps = 0.05*1;

//Nuber of the holes
NrOfHolesX = 4;
NrOfHolesY = 2;

Pitch = 8*1;
Radius = 4.8;
Radius1 = Radius / 2;
Radius2 = 6.1 / 2;
Height = 7.8*1;
Depth = 0.8*1;
Width = 7.5*1;
MidThickness = 2*1;
MiniCubeOffset = 1.1*1; // was 0.9
MiniCubeWidth = Radius1 - MiniCubeOffset;
CrossInnerRadius = 1.5*1;

drawBeam(NrOfHolesX);
rotate([0,0,90])drawBeam(NrOfHolesY);
//translate([Pitch*(NrOfHoles/2-1),-Width/2,0])rotate([90,0,90])OneCross();

module drawBeam(NrOfHoles){
translate([0,-Width/2,0])union(){
{
	Length = (NrOfHoles - 1) * Pitch;
	Thickness = (Width - 2 * Radius2) / 2;

	difference()
	{
		union()
		{
			cube([Length, Thickness, Height]);
			translate([0, Width-Thickness,0]) cube([Length, Thickness, Height]);
			translate([0, 0, Height/2-MidThickness/2]) cube([Length, Width, MidThickness]);
			for (i = [1:NrOfHoles])
			{
				translate([(i-1)*Pitch, Width/2,0])
				{
					cylinder(r=Width/2, h=Height);
				}
			}
		}

		union()
		{
			for (i = [1:NrOfHoles])
			{
				translate([(i-1)*Pitch, Width/2,0])
				{
					translate([0,0,-eps]) cylinder(r=Radius2,h=Depth+eps);
					translate([0,0,-eps]) cylinder(r=Radius1,h=Height+2*eps);
					translate([0,0,Height-Depth]) cylinder(r=Radius2,h=Depth+eps);
				}
			}
		}
	}
}
}
}

```


[User]
I'd like to create a set of parametric aluminum extrusion brackets, similar to the ones described in the provided Thingiverse link.  I need to be able to generate L, T, and X shaped brackets, as well as straight brackets (I-shape), all with variable dimensions and hole configurations.  Specifically, I need to control the following parameters:

*   **Bracket Shape:** L, T, X, or I (straight)
*   **Bracket Type (for I-shape):** "tiny", "short", "normal", or "long" to indicate different lengths and edge positions.
*   **Bracket Type (for L,T,X shapes):** "short" for a smaller type or "uniform" for standard length and positions.
*   **Support Type (L, T, X shapes only):** "none", "half", or "full" to control the amount of support material.
*   **Extrusion Width:** The width of the extrusion being mounted, like 20mm for a 2020 profile or 40mm for the side of a 2040 profile.  I'd like to be able to select from common sizes, say 20, 25, 25.4, 30, 40, 45, 60, 80, 90, 120, and 160 mm.
*   **Bracket Length:**  The overall length of each side of the L-bracket (and the shorter sides of the T), with the I-shape length and long side of T/X shapes being calculated from that and extrusion width. I need this to be customizable.
*   **Bracket Height:** The thickness of the bracket.
*   **Number of Rails:**  The number of rails on the extrusion being mounted (1 for 2020, 1 or 2 for 2040, etc.).
*  **Screw Hole Diameter:** The diameter of the screw holes.
*  **Screw Head Offset Diameter:** The diameter of the recess for the screw head.
* **Screw Head Offset Height:** The depth of the screw head recess.
*   **Number of Extra Holes:** The number of extra screw holes along the length of the bracket arm (beyond the central mounting holes).
*   **Preview Color:** Allow setting a different color for each shape.
* **Center:** A Boolean variable that if set to true will center the bracket on origin.
*   **$fn:** standard OpenSCAD variable to set the number of facets.

I'd like to be able to use the generated file as a library, so it should be able to be called with parameters like: `aluminium_extrusion_bracket(shape="T", support="half", width_in_millimeter=40, length_in_millimeter=100);`. It would be great if the library included a module to show all bracket types at once, like the `all_parts()` module in the example.  I'd also like to be able to specify which individual bracket type I want using named string parameters, e.g. `part = "short_l_shape_full_support__"`, similar to the example, but with fewer options.  I expect this would result in a single .scad file that includes all the functionality.  I don't need it to use any external libraries other than what's built into OpenSCAD.

[Assistant]
customizable_aluminium_extrusion_plate_brackets.scad:
```
/*
 * Customizable Aluminium Extrusion Brackets - https://www.thingiverse.com/thing:2503622
 * by Dennis Hofmann - https://www.thingiverse.com/mightynozzle/about
 * created 2018-01-26
 * version v1.4
 *
 * Changelog
 * --------------
 * v1.4:
 *      - added tiny straight bracket
 * v1.3.1:
 *      - some fixes and some code cleaning. Thanks goes to Matt Stiegers (Miriax)!
 * v1.3:
 *      - added library feature. You can use this file in your OpenSCAD project to
 *        add a bracket with a simple call. More information below.
 *        Thanks goes to Matt Stiegers (Miriax) for this suggestion!
 * v1.2:
 *      - added 25mm width option for 25-2525 (80/20 Inc.) extrusions
 * v1.1:
 *      - added 25.4mm width option for qubelok and 1010 (80/20 Inc.) extrusions
 * v1.0:
 *      - final design
 * --------------
 *
 * This work is licensed under the Creative Commons - Attribution - Non-Commercial license.
 * https://creativecommons.org/licenses/by-nc/3.0/
 */

 /*

 Library instructions
 ####################

 Installation:
   - add this OpenSCAD file to the folder of your project
   - add "use <customizable_aluminium_extrusion_plate_bracket.scad>;"
     in the head of your file.
   - add "aluminium_extrusion_bracket();" below in your program section

 Usage:
    The module has several parameter to change the bracket. The first value is default:
      - shape = "L", "I", "T" or "X"
      - type = "uniform" (L, T, X type), "tiny" (I type) "short" (all types), "normal" (I type) or "long" (I type)
      - support = "full", "half" or "none" (support only applies to L, T, X type)
      - width_in_millimeter = 20
      - length_in_millimeter = 60
      - bracket_height_in_millimeter = 7.0
      - number_of_rails = 1
      - screw_hole_diameter_in_millimeter = 6.4
      - screw_head_offset_diamter_in_millimeter = 12.0
      - screw_head_offset_height_in_millimeter = 1.5
      - number_of_extra_holes = 1
      - preview_color = "HotPink"
      - center = false, true
      - $fn = 16

 Example:

     use <customizable_aluminium_extrusion_plate_bracket.scad>;
     aluminium_extrusion_bracket( shape = "T", support = "half", center = true );

     This creates a origin centered T-shape bracket with half support.

 */

 // Parameter Section //
//-------------------//

/* [Bracket Settings] */

// Which part do you want to see?
part = "all_parts__"; //[all_parts__:All Brackets,tiny_straight_bracket__:Tiny Straight Bracket,short_straight_bracket__:Short Straight Bracket,normal_straight_bracket__:Normal Straight Bracket,long_straight_bracket__:Long Straight Bracket,short_l_shape_none_support__:Short L-shape Bracket without support,short_l_shape_half_support__:Short L-shape Bracket with half support,short_l_shape_full_support__:Short L-shape Bracket with full support,uniform_l_shape_none_support__:Uniform L-shape Bracket without support,uniform_l_shape_half_support__:Uniform L-shape Bracket with half support,uniform_l_shape_full_support__:Uniform L-shape Bracket with full support,short_t_shape_none_support__:Short T-shape Bracket without  support,short_t_shape_half_support__:Short T-shape Bracket with half support,short_t_shape_full_support__:Short T-shape Bracket with full support,uniform_t_shape_none_support__:Uniform T-shape Bracket without support,uniform_t_shape_half_support__:Uniform T-shape Bracket with half support,uniform_t_shape_full_support__:Uniform T-shape Bracket with full support,short_x_shape_none_support__:Short X-shape Bracket without support,short_x_shape_half_support__:Short X-shape Bracket with half support,short_x_shape_full_support__:Short X-shape Bracket with full support,uniform_x_shape_none_support__:Uniform X-shape Bracket without support,uniform_x_shape_half_support__:Uniform X-shape Bracket with half support,uniform_x_shape_full_support__:Uniform X-shape Bracket with full support]

// Set the width of the aluminium extrusion. If you have e.g. a 2020 one, set 20mm. If you have e.g. a 2040 one, it depends on which side you want to mount the bracket --> set 20mm or 40mm
width_in_millimeter = 20; //[20,25,25.4,30,40,45,60,80,90,120,160]

// The length of the L-bracket and the short side of the T-bracket. The length of the straight bracket, the X-bracket and the longer side of the T-bracket equals two times of the L-bracket length minus the width of the aluminium extrusion.
length_in_millimeter = 60; //[1:200]

// The height/thickness of the bracket.
bracket_height_in_millimeter = 7.0; //[0.1:0.1:30]

// Set the number of rails/slots of the aluminium extrusion. A 2020 one has one rail per side, a 2040 have one rail or two rails.
number_of_rails = 1; //[1:1:4]

// Set 4.3 for M4, 5.3 for M5, 6.4 for M6, 8.4 for M8, 10.5 for M10 screws
screw_hole_diameter_in_millimeter = 6.4;

// If you want to use a ISO7009/DIN125 washer, set 9.5 for M4, 10.5 for M5, 12.5 for M5, 16.5 for M8, 20.5 for M10... Or if you don't want to use a washer, just measure the diameter of the screw head and type it in here.
screw_head_offset_diamter_in_millimeter = 12.0;

// If you want to cover the screw head completly, you can measure the height of the head of the screws and set it here. Don't forget to add the thickness of the washer! If you set a high value or maybe a higher value than the height of the bracket, you should also increase the bracket height.
screw_head_offset_height_in_millimeter = 1.5;

// If you need only the outer holes, then set 0. But it also makes the short type brackets unsuable.
number_of_extra_holes = 1; //[0:1:4]

 // Program Section //
//-----------------//

if(part == "tiny_straight_bracket__") {
    aluminium_extrusion_bracket(shape = "I", type = "tiny", support = "", preview_color = "YellowGreen");
} else if(part == "short_straight_bracket__") {
    aluminium_extrusion_bracket(shape = "I", type = "short", support = "", preview_color = "YellowGreen");
} else if(part == "normal_straight_bracket__") {
    aluminium_extrusion_bracket(shape = "I", type = "normal", support = "", preview_color = "YellowGreen");
} else if(part == "long_straight_bracket__") {
    aluminium_extrusion_bracket(shape = "I", type = "long", support = "", preview_color = "YellowGreen");
} else if(part == "short_l_shape_none_support__") {
    aluminium_extrusion_bracket(shape = "L", type = "short", support = "none", preview_color = "DimGray");
} else if(part == "short_l_shape_half_support__") {
    aluminium_extrusion_bracket(shape = "L", type = "short", support = "half", preview_color = "DimGray");
} else if(part == "short_l_shape_full_support__") {
    aluminium_extrusion_bracket(shape = "L", type = "short", support = "full", preview_color = "DimGray");
} else if(part == "uniform_l_shape_none_support__") {
    aluminium_extrusion_bracket(shape = "L", type = "uniform", support = "none", preview_color = "DeepSkyBlue");
} else if(part == "uniform_l_shape_half_support__") {
    aluminium_extrusion_bracket(shape = "L", type = "uniform", support = "half", preview_color = "DeepSkyBlue");
} else if(part == "uniform_l_shape_full_support__") {
    aluminium_extrusion_bracket(shape = "L", type = "uniform", support = "full", preview_color = "DeepSkyBlue");
} else if(part == "short_t_shape_none_support__") {
    aluminium_extrusion_bracket(shape = "T", type = "short", support = "none", preview_color = "HotPink");
} else if(part == "short_t_shape_half_support__") {
    aluminium_extrusion_bracket(shape = "T", type = "short", support = "half", preview_color = "HotPink");
} else if(part == "short_t_shape_full_support__") {
    aluminium_extrusion_bracket(shape = "T", type = "short", support = "full", preview_color = "HotPink");
} else if(part == "uniform_t_shape_none_support__") {
    aluminium_extrusion_bracket(shape = "T", type = "uniform", support = "none", preview_color = "DarkOrange");
} else if(part == "uniform_t_shape_half_support__") {
    aluminium_extrusion_bracket(shape = "T", type = "uniform", support = "half", preview_color = "DarkOrange");
} else if(part == "uniform_t_shape_full_support__") {
    aluminium_extrusion_bracket(shape = "T", type = "uniform", support = "full", preview_color = "DarkOrange");
} else if(part == "short_x_shape_none_support__") {
    aluminium_extrusion_bracket(shape = "X", type = "short", support = "none", preview_color = "Gold");
} else if(part == "short_x_shape_half_support__") {
    aluminium_extrusion_bracket(shape = "X", type = "short", support = "half", preview_color = "Gold");
} else if(part == "short_x_shape_full_support__") {
    aluminium_extrusion_bracket(shape = "X", type = "short", support = "full", preview_color = "Gold");
} else if(part == "uniform_x_shape_none_support__") {
    aluminium_extrusion_bracket(shape = "X", type = "uniform", support = "none", preview_color = "MediumPurple");
} else if(part == "uniform_x_shape_half_support__") {
    aluminium_extrusion_bracket(shape = "X", type = "uniform", support = "half", preview_color = "MediumPurple");
} else if(part == "uniform_x_shape_full_support__") {
    aluminium_extrusion_bracket(shape = "X", type = "uniform", support = "full", preview_color = "MediumPurple");
} else if(part == "all_parts__") {
    all_parts();
} else {
    all_parts();
}

 // Module Section //
//----------------//

module aluminium_extrusion_bracket(
    shape = "L", // I, L, T or X
    type = "uniform", // tiny (I type), short (I, L, T, X type), normal (I type), long (I type), uniform (L, T, X type)
    support = "full", // none, half, full (L, T, X type)
    width_in_millimeter = (width_in_millimeter != undef) ? width_in_millimeter : 20,
    length_in_millimeter = (length_in_millimeter != undef) ? length_in_millimeter : 60,
    bracket_height_in_millimeter = (bracket_height_in_millimeter != undef) ? bracket_height_in_millimeter : 7.0,
    number_of_rails = (number_of_rails != undef) ? number_of_rails : 1,
    screw_hole_diameter_in_millimeter = (screw_hole_diameter_in_millimeter != undef) ? screw_hole_diameter_in_millimeter : 6.4,
    screw_head_offset_diamter_in_millimeter = (screw_head_offset_diamter_in_millimeter != undef) ? screw_head_offset_diamter_in_millimeter : 12.0,
    screw_head_offset_height_in_millimeter = (screw_head_offset_height_in_millimeter != undef) ? screw_head_offset_height_in_millimeter : 1.5,
    number_of_extra_holes = (number_of_extra_holes != undef) ? number_of_extra_holes : 1,
    preview_color = "HotPink",
    center = false,
    $fn = 16
) {
    w = width_in_millimeter;
    l = length_in_millimeter;
    h = bracket_height_in_millimeter;
    hole_d = screw_hole_diameter_in_millimeter;
    hole_offset_d = screw_head_offset_diamter_in_millimeter;
    hole_offset_h = screw_head_offset_height_in_millimeter;
    holes = number_of_extra_holes + 1;
    rails = number_of_rails;
    translate_x = center ? -l + w / 2 : 0;
    translate_y = center ? -l + w / 2 : 0;

    color(preview_color) translate([translate_x, translate_y, 0]) {
        difference() {
            linear_extrude(height = h, convexity = 2){
                if(shape == "I" && type == "tiny") tiny_I_shape(w, l);
                if(shape == "I" && type == "short") short_I_shape(w, l);
                if(shape == "I" && type == "normal") normal_I_shape(w, l);
                if(shape == "I" && type == "long") long_I_shape(w, l);
                if(shape == "L" && type == "short" && support == "none") short_L_shape_none_support(w, l);
                if(shape == "L" && type == "short" && support == "half") short_L_shape_half_support(w, l);
                if(shape == "L" && type == "short" && support == "full") short_L_shape_full_support(w, l);
                if(shape == "L" && type == "uniform" && support == "none") uniform_L_shape_none_support(w, l);
                if(shape == "L" && type == "uniform" && support == "half") uniform_L_shape_half_support(w, l);
                if(shape == "L" && type == "uniform" && support == "full") uniform_L_shape_full_support(w, l);
                if(shape == "T" && type == "short" && support == "none") short_T_shape_none_support(w, l);
                if(shape == "T" && type == "short" && support == "half") short_T_shape_half_support(w, l);
                if(shape == "T" && type == "short" && support == "full") short_T_shape_full_support(w, l);
                if(shape == "T" && type == "uniform" && support == "none") uniform_T_shape_none_support(w, l);
                if(shape == "T" && type == "uniform" && support == "half") uniform_T_shape_half_support(w, l);
                if(shape == "T" && type == "uniform" && support == "full") uniform_T_shape_full_support(w, l);
                if(shape == "X" && type == "short" && support == "none") short_X_shape_none_support(w, l);
                if(shape == "X" && type == "short" && support == "half") short_X_shape_half_support(w, l);
                if(shape == "X" && type == "short" && support == "full") short_X_shape_full_support(w, l);
                if(shape == "X" && type == "uniform" && support == "none") uniform_X_shape_none_support(w, l);
                if(shape == "X" && type == "uniform" && support == "half") uniform_X_shape_half_support(w, l);
                if(shape == "X" && type == "uniform" && support == "full") uniform_X_shape_full_support(w, l);
            }
            short = (type == "short" || type == "tiny") ? 0 : 1;
            center_holes_cut(w, l, h, rails, hole_d, hole_offset_d, hole_offset_h, holes);
            if(shape == "X" || shape == "I") arm_holes_cut(0, 1, w, l, h, rails, hole_d, hole_offset_d, hole_offset_h, holes);
            if(shape == "T" || shape == "X") arm_holes_cut(90, short, w, l, h, rails, hole_d, hole_offset_d, hole_offset_h, holes);
                                             arm_holes_cut(180, 1, w, l, h, rails, hole_d, hole_offset_d, hole_offset_h, holes);
            if(shape != "I")                 arm_holes_cut(270, short, w, l, h, rails, hole_d, hole_offset_d, hole_offset_h, holes);
        }
    }
}

module all_parts() {
    pos0 = 0;
    pos1 = length_in_millimeter * 2 - width_in_millimeter + 5;
    pos2 = pos1 * 2;
    pos3 = pos1 * 3;
    pos4 = pos1 * 4;
    pos5 = pos1 * 5;
    translate([pos0, pos0, 0]) aluminium_extrusion_bracket(shape = "L", type = "short", support = "none", preview_color = "DimGray");
    translate([pos0, pos1, 0]) aluminium_extrusion_bracket(shape = "L", type = "short", support = "half", preview_color = "DimGray");
    translate([pos0, pos2, 0]) aluminium_extrusion_bracket(shape = "L", type = "short", support = "full", preview_color = "DimGray");
    translate([pos1, pos0, 0]) aluminium_extrusion_bracket(shape = "L", type = "uniform", support = "none", preview_color = "DeepSkyBlue");
    translate([pos1, pos1, 0]) aluminium_extrusion_bracket(shape = "L", type = "uniform", support = "half", preview_color = "DeepSkyBlue");
    translate([pos1, pos2, 0]) aluminium_extrusion_bracket(shape = "L", type = "uniform", support = "full", preview_color = "DeepSkyBlue");
    translate([pos2, pos0, 0]) aluminium_extrusion_bracket(shape = "T", type = "short", support = "none", preview_color = "HotPink");
    translate([pos2, pos1, 0]) aluminium_extrusion_bracket(shape = "T", type = "short", support = "half", preview_color = "HotPink");
    translate([pos2, pos2, 0]) aluminium_extrusion_bracket(shape = "T", type = "short", support = "full", preview_color = "HotPink");
    translate([pos3, pos0, 0]) aluminium_extrusion_bracket(shape = "T", type = "uniform", support = "none", preview_color = "DarkOrange");
    translate([pos3, pos1, 0]) aluminium_extrusion_bracket(shape = "T", type = "uniform", support = "half", preview_color = "DarkOrange");
    translate([pos3, pos2, 0]) aluminium_extrusion_bracket(shape = "T", type = "uniform", support = "full", preview_color = "DarkOrange");
    translate([pos4, pos0, 0]) aluminium_extrusion_bracket(shape = "X", type = "short", support = "none", preview_color = "Gold");
    translate([pos4, pos1, 0]) aluminium_extrusion_bracket(shape = "X", type = "short", support = "half", preview_color = "Gold");
    translate([pos4, pos2, 0]) aluminium_extrusion_bracket(shape = "X", type = "short", support = "full", preview_color = "Gold");
    translate([pos5, pos0, 0]) aluminium_extrusion_bracket(shape = "X", type = "uniform", support = "none", preview_color = "MediumPurple");
    translate([pos5, pos1, 0]) aluminium_extrusion_bracket(shape = "X", type = "uniform", support = "half", preview_color = "MediumPurple");
    translate([pos5, pos2, 0]) aluminium_extrusion_bracket(shape = "X", type = "uniform", support = "full", preview_color = "MediumPurple");
    translate([pos0, pos3, 0]) aluminium_extrusion_bracket(shape = "I", type = "tiny", preview_color = "YellowGreen");
    translate([pos1, pos3, 0]) aluminium_extrusion_bracket(shape = "I", type = "short", preview_color = "YellowGreen");
    translate([pos2, pos3, 0]) aluminium_extrusion_bracket(shape = "I", type = "normal", preview_color = "YellowGreen");
    translate([pos3, pos3, 0]) aluminium_extrusion_bracket(shape = "I", type = "long", preview_color = "YellowGreen");
}

module tiny_I_shape(w, l) {
    polygon( points = [[l * 2 - w - ((l - w) / 2), l - w], [l * 2 - w - ((l - w) / 2), l], [l - w, l], [l - w, l - w]]);
}

module short_I_shape(w, l) {
    polygon( points = [[l * 2 - w - ((l - w) / 2), l - w], [l * 2 - w - ((l - w) / 2), l], [(l - w) / 2, l], [(l - w) / 2, l - w]]);
}

module normal_I_shape(w, l) {
    polygon( points = [[l * 2 - w - ((l - w) / 2), l - w], [l * 2 - w - ((l - w) / 2), l], [0, l], [0, l - w]]);
}

module long_I_shape(w, l) {
    polygon( points = [[l * 2 - w, l - w], [l * 2 - w, l], [0, l], [0, l - w]]);
}

module short_L_shape_none_support(w, l) {
    polygon( points=[[l - w, (l - w) / 2], [l, (l - w) / 2], [l, l], [0, l], [0, l - w], [l - w, l - w]]);
}

module short_L_shape_half_support(w, l) {
    polygon( points=[[l - w, (l - w) / 2], [l, (l - w) / 2], [l, l], [0, l], [0, l - w], [(l - w) / 2, l - w], [l - w , (l - w) / 2]]);
}

module short_L_shape_full_support(w, l) {
    polygon( points=[[l - w, (l - w) / 2], [l, (l - w) / 2], [l, l], [0, l], [0, l - w]]);
}

module uniform_L_shape_none_support(w, l) {
    polygon( points=[[l - w, 0], [l, 0], [l, l], [0, l], [0, l - w], [l - w, l - w]]);
}

module uniform_L_shape_half_support(w, l) {
    polygon( points=[[l - w, 0], [l, 0], [l, l], [0, l], [0, l - w], [(l - w) / 2, l - w], [l - w , (l - w) / 2]]);
}

module uniform_L_shape_full_support(w, l) {
    polygon( points=[[l - w, 0], [l, 0], [l, l], [0, l], [0, l - w]]);
}

module short_T_shape_none_support(w, l) {
    polygon( points=[[l - w, (l - w) / 2], [l, (l - w) / 2], [l, l * 2 - w - ((l - w) / 2)], [l - w, l * 2 - w - ((l - w) / 2)], [l - w, l], [0, l], [0, l - w], [l - w, l - w]]);
}

module short_T_shape_half_support(w, l) {
    polygon( points=[[l - w, (l - w) / 2], [l, (l - w) / 2], [l, l * 2 - w - ((l - w) / 2)], [l - w, l * 2 - w - ((l - w) / 2)], [l - w, l + (l - w) / 2], [(l - w) / 2, l], [0, l], [0, l - w], [(l - w) / 2, l - w], [l - w , (l - w) / 2]]);
}

module short_T_shape_full_support(w, l) {
    polygon( points=[[l - w, (l - w) / 2], [l, (l - w) / 2], [l, l * 2 - w - ((l - w) / 2)], [l - w, l * 2 - w - ((l - w) / 2)], [0, l], [0, l - w]]);
}

module uniform_T_shape_none_support(w, l) {
    polygon( points=[[l - w, 0], [l, 0], [l, l * 2 - w], [l - w, l * 2 - w], [l - w, l], [0, l], [0, l - w], [l - w, l - w]]);
}

module uniform_T_shape_half_support(w, l) {
    polygon( points=[[l - w, 0], [l, 0], [l, l * 2 - w], [l - w, l * 2 - w], [l - w, l + (l - w) / 2], [(l - w) / 2, l], [0, l], [0, l - w], [(l - w) / 2, l - w], [l - w , (l - w) / 2]]);
}

module uniform_T_shape_full_support(w, l) {
    polygon( points=[[l - w, 0], [l, 0], [l, l * 2 - w], [l - w, l * 2 - w], [0, l], [0, l - w]]);
}

module short_X_shape_none_support(w, l) {
    polygon( points=[[l - w, (l - w) / 2], [l, (l - w) / 2], [l, l-w], [l * 2 - w, l - w], [l * 2 - w , l], [l, l], [l, l * 2 - w - ((l - w) / 2)], [l - w, l * 2 - w - ((l - w) / 2)], [l - w, l], [0, l], [0, l - w], [l - w, l - w]]);
}

module short_X_shape_half_support(w, l) {
    polygon( points=[[l - w, (l - w) / 2], [l, (l - w) / 2], [l, (l - w) / 2], [l * 2 - w - (l - w) / 2, l - w], [l * 2 - w, l - w], [l * 2 - w , l], [l + (l - w) / 2, l], [l, l + (l - w) / 2], [l, l * 2 - w - ((l - w) / 2)], [l - w, l * 2 - w - ((l - w) / 2)], [l - w, l + (l - w) / 2], [(l - w) / 2, l], [0, l], [0, l - w], [(l - w) / 2, l - w], [l - w , (l - w) / 2]]);
}

module short_X_shape_full_support(w, l) {
    polygon( points=[[l - w, (l - w) / 2], [l, (l - w) / 2], [l * 2 - w, l - w], [l * 2 - w , l], [l, l * 2 - w - ((l - w) / 2)], [l - w, l * 2 - w - ((l - w) / 2)], [0, l], [0, l - w]]);
}

module uniform_X_shape_none_support(w, l) {
    polygon( points=[[l - w, 0], [l, 0], [l, l-w], [l * 2 - w, l - w], [l * 2 - w , l], [l, l], [l, l * 2 - w], [l - w, l * 2 - w], [l - w, l], [0, l], [0, l - w], [l - w, l - w]]);
}

module uniform_X_shape_half_support(w, l) {
    polygon( points=[[l - w, 0], [l, 0], [l, (l - w) / 2], [l * 2 - w - (l - w) / 2, l - w], [l * 2 - w, l - w], [l * 2 - w , l], [l + (l - w) / 2, l], [l, l + (l - w) / 2], [l, l * 2 - w], [l - w, l * 2 - w], [l - w, l + (l - w) / 2], [(l - w) / 2, l], [0, l], [0, l - w], [(l - w) / 2, l - w], [l - w , (l - w) / 2]]);
}

module uniform_X_shape_full_support(w, l) {
    polygon( points=[[l - w, 0], [l, 0], [l * 2 - w, l - w], [l * 2 - w , l], [l, l * 2 - w], [l - w, l * 2 - w], [0, l], [0, l - w]]);
}

module center_holes_cut(w, l, bracket_h, number_of_rails, hole_d, hole_offset_d, hole_offset_h, number_of_holes) {
    translate([l - w / 2, l - w / 2, 0]) {
        translate([-w / 2, -w / 2, 0]) {
            for(middle_hole_x = [1 : number_of_rails]) {
                for(middle_hole_y = [1 : number_of_rails]) {
                    x_pos = w / number_of_rails * middle_hole_x - w / number_of_rails / 2;
                    y_pos = w / number_of_rails * middle_hole_y - w / number_of_rails / 2;
                    translate([ x_pos, y_pos, 0]) {
                        hole_shape(bracket_h, hole_d, hole_offset_d, hole_offset_h);
                    }
                }
            }
        }
    }
}

module arm_holes_cut(rotation, extra_hole, w, l, bracket_h, number_of_rails, hole_d, hole_offset_d, hole_offset_h, number_of_holes) {
    translate([l - w / 2, l - w / 2, 0]) {
        rotate([0, 0, rotation]) {
            translate([0, -w / 2, 0]) {
                for(hole = [1 : number_of_holes + extra_hole - 1]) {
                    for(rail = [1 : number_of_rails]) {
                        x_pos = (l - w) / (number_of_holes) * hole + w / 2 - w / number_of_rails / 2;
                        y_pos = w / number_of_rails * rail - w / number_of_rails / 2;
                        translate([x_pos, y_pos, 0]) {
                            hole_shape(bracket_h, hole_d, hole_offset_d, hole_offset_h);
                        }
                    }
                }
            }
        }
    }
}

module hole_shape(bracket_h, hole_d, hole_offset_d, hole_offset_h) {
    translate([0, 0, -1]) {
        cylinder(d = hole_d, h = bracket_h + 3);
    }
    translate([0, 0, bracket_h - hole_offset_h]) {
        cylinder(d = hole_offset_d, h = hole_offset_h + 1);
    }
}

```


[User]
Okay, I'd like to generate some miniature bases for tabletop gaming, and I'd like to be able to customize them pretty extensively. I'm picturing something with a few different shapes - circles, squares, and hexagons - and I need to be able to adjust the overall size. It would be great to have the option for "double-length" bases, maybe for some of my longer minis.

I also need some additional features for different needs. I'd love to be able to generate bases with a slot for mounting on a base clip, card holders to keep track of game states, and flying bases with a mount point for 1/8" plastic rod. And ideally, I can also choose to emboss numbers on them for easier tracking when I have a lot of the same mini.

A cool bonus would be to be able to apply textures to the bases using greyscale images, either cutting into the base or raising above the surface. And the bases should all have a beveled edge so it's easy to pick them up.

The bevels are the last detail - I want to be able to choose from a few styles, maybe a "nerd" style, a "hero" style, a completely custom profile, and no bevel at all. If I go with custom, it'd be great if I could supply the points and paths.

So, to recap, here’s the features:

*   **Shapes:** Circle, square, and hexagon
*   **Size:** Adjustable numeric value
*   **Ratio:** Standard or double-length
*   **Extras:** Slot, Card Holder, Flying Base, None
*   **Quantity:** Generate multiple bases in a grid arrangement.
*   **Label:** Ability to emboss a number on the base, using a font selector.
*   **Texture:** Ability to apply a texture from an image, either cutting into the base or raising above it.
*   **Bevel:** Choice of "nerd", "hero", custom, or no bevel; custom bevel defined by a profile of points and paths.
*   **Rounded corners:** Toggle for rounded or sharp corners on bevels

I think that covers everything. I need it all in OpenSCAD, and please don't include any libraries, I can use those myself if I need to. It should be parametric, so I can easily change these options.

[Assistant]
bases.scad:
```
/* [Settings] */
shape = "circle"; // [circle:Circle, square:Square, hex:Hex]
size = 25; // [15:60]
ratio = 0; // [0:Standard, 1:Double-Length]
extras = "none"; // [none:None, slot:Cut Slot, stand:Card Holder, flyer:Flying Base]
quantity = 1; // [1:25]

// Number multiple bases using this font.
label_font="None"; // [None, Almendra, Asset, Changa One, Dosis, Krona One, Orbitron, Palanquin Dark, Pirata One, Share, Squada One, Ultra, Unlock]
print_label = label_font != "None";

quality = 40; // [20:Draft, 40:Standard, 100:High]

/* [Advanced] */
// A custom bevel profile used instead of the default.
bevel_style = "nerd";  // [nerd:Nerdhaus, hero:Heroforge, custom:Custom, none:"None"]
bevel_profile = [[[-1,1],[0,0],[0,-1],[-1,-1],[-1,1],[-1,1]],[[0,1,2,3,4]] ]; // [draw_polygon:2x2]

// Apply a custom bump map to the surface of the base.
textured_surface = "none";  // [none:None, cut:Cut into base, cap:Raised above base]

// 300x300 pixel greyscale file. This will be .5mm tall, 60mm square, and scaled to the size of the base.
texture_file = "texture.dat"; // [image_surface:300x300]

/* [Hidden] */
rounded_corners = 1;  // [1:Yes, 0:No]
hide_logo = 0;  // [1:Yes, 0:No]
texture_override = ""; // When NOT using Customizer, set this variable to a local image file for texturing.

grid();
module grid() {
  gap = 10;
  rows=ceil(sqrt(quantity));
  offset = shape != "square" ? (size)/2 + (gap * 2) : 0;

  for (i = [0 : quantity - 1]) {
    x = i % rows;
    y = floor(i/rows);

    translate([x * (size + gap) + y%2 * (size + gap) / 2, y * (size * (ratio ? 2 : 1) + gap)])
    base(label_text = print_label ? i+1 : "");
  }
}

module base(label_text) {
  offset = ratio ? -size/2 : 0;
  difference() {
    createBlank();
    if (textured_surface == "cut") {
      translate([0,0,2.5]) cylinder(h=2, r=size, center=true);
    }

    if (extras == "slot") slot();
    if (!hide_logo) logo();
  }

  if (extras == "stand") card_holder();
  if (extras == "flyer") flying_base();

  if (textured_surface != "none") {
    intersection() {
      createBlank(textured_surface == "cap");

      textureSize = 60 + (shape == "hex" ? size/6 : 0); // Just a bit of padding to account for hex points.

      translate([-textureSize/2, -textureSize/2, (textured_surface == "cap") ? 2 : 1.5])
        resize([textureSize, textureSize, .5])
        surface(file=(texture_override ? texture_override : texture_file));
    }
  }

  color("Goldenrod", 1.0) translate([0, offset]) label(label_text);
}

module logo() {
  rotate([0, 180, 0])
  translate([0,0,-.5]) {
    nerdhaus(.75);
  }
}

module slot() {
  translate([0,0,-.5]) rotate([0,0,ratio ? 90 : 0])
  linear_extrude(height=3) {
    square(size = [18, 2], center=true);
  }
}

module card_holder() {
  // Two slight high-resolution arcs, extruded 5mm above the base surface.

  rotate([0,0,ratio ? 90 : 0])
  translate([0,-40,1.9])
  linear_extrude(height=5.1)

  intersection() {
    translate([0,40]) square(15, center=true);

    union() {
      difference() {
        offset(r = .75) {
          circle(40, center = true, $fn=100);
        }
        offset(r = 0) {
          circle(40, center = true, $fn=100);
        }
      }

      difference() {
        offset(r = 2.25) {
          circle(40, center = true, $fn=100);
        }
        offset(r = 1.5) {
          circle(40, center = true, $fn=100);
        }
      }
    }
  }
}

module flying_base() {
  // Mount point for a 1/8" plastic rod, roughly 3.2mm.
  rod_diameter = 3.2;

  translate([0,(label_font == "None" ? 0 : 2),2])
  difference() {
    union() {
      translate([0,0,2]) linear_extrude(height=.5, scale=.9) circle(r=rod_diameter-.5, $fn=quality);
      linear_extrude(height=2, scale=1) circle(r=rod_diameter-.5, $fn=quality);
    }
    linear_extrude(height=4.1) circle(r=rod_diameter/2, $fn=quality);
  }
}
module label(label_text) {
  translate([0,((size/-3)),1.5]) {
    linear_extrude(height=1)
    text(str(label_text), size=(min(7, size / 5)), font=label_font, valign="bottom", halign="center");
  }
}

module createBlank(straight = false) {
  difference() {
    if(shape=="hex") {
      createHexBlank(straight);
    }
    else if(shape=="square") {
      createSquareBlank(straight);
    }
    else {
      createCircleBlank(straight);
    }
  }
}

module createCircleBlank(straight = false) {
  offset = ratio ? size : 0;
  translate([0,offset/2])
  hull() {
    rotate_extrude(angle=180, convexity=10, $fn = quality)
    translate([size/2, 0])
    bevel_profile(straight);

    translate([0,-offset,0]) {
      rotate_extrude(angle=-180, convexity=10, $fn = quality)
      translate([size/2, 0])
      bevel_profile(straight);
    }
  }
}

module createHexBlank(straight = false) {
  offset = ratio ? size : 0;
  inner = size - 4;

  adj = size/2;
  hyp = (adj / cos(30));
  opp = (adj * tan(30));

  translate([0,offset/2])
  hull() {
    translate([-inner/2, opp-1])
    bevel_dot(straight);

    translate([0, (hyp)-2])
    bevel_dot(straight);

    translate([inner/2, opp-1])
    bevel_dot(straight);

    translate([-inner/2, -opp+1 - offset])
    bevel_dot(straight);

    translate([0, -(hyp)+2 - offset])
    bevel_dot(straight);

    translate([inner/2, -opp+1 - offset])
    bevel_dot(straight);
  }
}

module createSquareBlank(straight = false) {
  offset = ratio ? size : 0;
  inner = size - 4;

  translate([0,(inner+offset)/2])
  hull() {
    translate([-inner/2, 0])
    bevel_dot();

    translate([inner/2, 0])
    bevel_dot();

    translate([-inner/2, -(inner+offset)])
    bevel_dot();

    translate([inner/2, -(inner+offset)])
    bevel_dot();
  }
}

module bevel_profile(straight = false) {
  if (straight) {
    polygon(points=[[-1,0],[-1,2], [-2,0]]);
  }
  if (bevel_style == "none") {
    polygon(points=[[0,0],[0,2], [-2,0]]);
  }
  else if (bevel_style == "nerd") {
    hull() {
      translate([-.75,1.25])
      circle(r = .75, $fn = quality/2);

      translate([-.5,1])
      circle(r = .5, $fn = quality/2);

      polygon(points=[[0,1],[-.75,0],[-1.75,0],[-.75,2]]);
    }
  }
  else if (bevel_style == "hero") {
    hull() {
      translate([-1.175,1.775])
      circle(r = .125, $fn = quality/2);

      translate([-.125,.125])
      circle(r = .125, $fn = quality/2);
    }
  }
  else if (bevel_style == "custom") {
    translate([0,1]) polygon(points = bevel_profile[0], paths = bevel_profile[1]);
  }
}

/* Beveled dot with a radius of 2mm */
module bevel_dot(straight = false) {
  q = rounded_corners ? quality/2 : (shape == "hex" ? 6 : (shape == "square" ? 4 : 2));

  rotate_extrude(convexity=10, $fn = q)
  translate([2, 0, 0])
  bevel_profile(straight);
}

/* Standard Nerdhaus logo stamp */
module nerdhaus(h = 1) {
  linear_extrude(height=h)
    polygon([[1.894990,0.863885],[1.894990,-2.944385],[-1.915271,0.863885],[-2.867510,0.863885],[-2.867510,-4.292885],[-1.915010,-4.292885],[-1.910190,-0.487875],[1.896800,-4.292885],[2.847492,-4.292885],[2.847492,0.863885]]);
  linear_extrude(height=h)
    polygon([[1.882472,3.093735],[-0.016830,3.853585],[-4.915385,1.879915],[-4.559422,0.996435],[-0.015576,2.827185],[4.561582,0.995995],[4.915385,1.880355],[2.834972,2.712665],[2.834972,4.292885],[1.882472,4.292885]]);
}
```


[User]
Hi! I'm looking to create a collection of Euro coin holders, similar to the design I've seen on Thingiverse (linked in the description). I've got a basic OpenSCAD file that uses an imported STL for the coin holder base and then adds the country name as text, but I'd really like to make this fully parametric so I can generate any country's holder easily without needing a python script.

The current design uses a `v2_euro_cc.stl` file for the coin holder base, but I'd prefer if that could be generated directly in OpenSCAD. The key feature is the raised circles to hold the coins. It's crucial to maintain good dimensions to fit the coins correctly.

Here's what I need:

1.  **Parametric Coin Holder Base:** Replace the STL import with a fully parameterized OpenSCAD design. This should include the circular recesses for the coins and the overall shape of the base. I'd want to control the following:
    *   The radius of the individual coin recesses (e.g., the size of the 2 euro coin, 1 euro coin, etc.)
    *   The spacing between the coin recesses
    *   The overall dimensions of the base (e.g., width, length)
    *   The height of the base (the depth of the recessions)
    *   The overall height of the base
2.  **Country Name Text:**  A parameter to specify the country name that should be extruded onto the holder.
    *   A parameter for font size of the country text.
3.  **Positioning:** The country text should be positioned on the base in a specific location, above the top of the coin holder. I'd like to control the horizontal and vertical offset and height of the text.
4.  **Text Extrusion:** The text should be extruded, with control over the extrusion height.
5.  **Color:** It would be great to specify the text color too, though this is mainly for the preview in OpenSCAD.
6.  **Libraries:** It would be great if you could use the `MCAD` library for any 2D shapes it could simplify.

I'm not trying to improve on existing code, this is all new to me.

Could you generate the OpenSCAD files for me to achieve this? Ideally one file with all the parameters would be great. Thanks!

[Assistant]
eurocollectioncountries.scad:
```
/*

Country Euro coin holder collection

A derivative work based in the design of Jose Manuel Loureiro Vazquez

https://www.thingiverse.com/thing:2017447

License

CC-BY-NC-SA

Created by Julián Caro Linares

jcarolinares@gmail.com
*/

// Country name
country="España"; // ["Alemania","Austria","Bélgica","Chipre","Eslovaquia","Eslovenia","España","Estonia","Finlandia","Francia","Grecia","Irlanda","Italia","Letonia","Lituania","Luxemburgo","Malta","PaísesBajos","Portugal"]

// Size of the text
fontsize=4.5;

difference()
{
//Euro coin holder
scale([1.008,1.008,1]) //Scale to fit better the coins
translate([50,35,0])
{
import("v2_euro_cc.stl");
}

//Country text
translate([4,33.5,2.5])
{
color("red")
linear_extrude(height = 2, center = false, convexity = 10)
    text(country,size=fontsize);
    }
}

//// Euro coin
//translate([39,35.25,0]){
//color("blue")
//import("euro-coin.stl");
//}

```


[User]
Hey, I've got a project box design I'm trying to make parametric in OpenSCAD, and I'd love some help. I've got a basic idea, and I've got some specific requirements.

Basically, it's a rectangular box with a lid that screws on. I need to be able to adjust the internal dimensions of the box (width, length, and height), the wall thickness, the fillet radius for the edges, and the screw hole diameters for both the box and the lid.

Here are the specific parameters I want to control:

*   **`inside_width`**:  The internal width of the box.
*   **`inside_length`**: The internal length of the box.
*   **`inside_height`**: The internal height of the box.
*   **`thickness`**: The thickness of the box walls.
*   **`radius`**: The radius of the fillets on the corners. This should also be applied to the lid.
*   **`screw_dia`**: The diameter of the screw holes in the box itself, where the screws will thread in.
*   **`screw_loose_dia`**: The diameter of the screw holes in the lid, they should be slightly larger than the actual screws.
*   **`extra_lid_thickness`**: An optional parameter for adjusting the thickness of the lip on the lid, should you need a little more space or for adjusting for chamfers. Generally, this should be 0.

The box should have screw holes in the corners of the box that the lid screws into. The lip on the lid should fit inside of the box and hold it on. The lid has holes that align with the holes in the box. I need for the lip to take the `thickness` parameter into consideration. The lid and the base both have rounded corners, based on the radius parameter.

Could you generate the necessary OpenSCAD files for me? I don't need any external libraries.

[Assistant]
project_box_screws_r3.scad:
```
//Procedural Project Box Screws

//40mm x 60 board size

inside_width = 45;
inside_length = 70;
inside_height = 12.5;
//Wall thickness
thickness = 2;
//Fillet radius. This should not be larger than thickness.
radius = 1;
//Diameter of the holes that screws thread into.
screw_dia = 3;
//Diameter of the holes on the lid (should be larger than the diameter of your screws)
screw_loose_dia = 3.2;
//Only use this if the lip on your lid is detached from the lid! This is a hack to work around odd union() behaviour.
extra_lid_thickness = 0;        //Extra lid thickness above thickness.
                                //You may want to tweak this to account for large chamfer radius.

outside_width = inside_width + thickness * 2;
outside_length = inside_length + thickness * 2;
od = screw_dia * 2.5;

module box_screw(id, od, height){
    difference(){
        union(){
            cylinder(d=od, h=height, $fs=0.2);
            translate([-od/2, -od/2, 0])
                cube([od/2,od,height], false);
            translate([-od/2, -od/2, 0])
                cube([od,od/2,height], false);
        }
        cylinder(d=id, h=height, $fn=6);
    }
}

module rounded_box(x,y,z,r){
    translate([r,r,r])
    minkowski(){
        cube([x-r*2,y-r*2,z-r*2]);
        sphere(r=r, $fs=0.1);
    }
}

module main_box(){
    difference(){
        //cube([outside_width, outside_length, inside_height + thickness * 2]);
        difference(){
            rounded_box(outside_width, outside_length, inside_height + thickness + 2, radius);
            translate([0,0,inside_height + thickness])
            cube([outside_width, outside_length, inside_height + thickness * 2]);
        }
        translate([thickness, thickness, thickness])
        cube([inside_width, inside_length, inside_height + thickness]);
    }
    od = screw_dia * 2.5;

    translate([od/2+thickness,od/2+thickness, 0])
        box_screw(screw_dia, od, inside_height);

    translate([thickness+inside_width-od/2, od/2+thickness, 0])
        rotate([0,0,90])
            box_screw(screw_dia, od, inside_height);

    translate([thickness+inside_width-od/2, -od/2+thickness+inside_length, 0])
        rotate([0,0,180])
            box_screw(screw_dia, od, inside_height);

    translate([od/2 + thickness, -od/2+thickness+inside_length, 0])
        rotate([0,0,270])
            box_screw(screw_dia, od, inside_height);
}

module lid(){
    difference(){
        union(){
        //Lid.
        difference(){
            rounded_box(outside_width, outside_length, thickness * 4, radius);
            translate([0,0, thickness + extra_lid_thickness])
                cube([outside_width, outside_length, inside_height + thickness * 4]);
        }
        //Lip
        lip_tol = 0.5;
        lip_width = inside_width - lip_tol;
        lip_length = inside_length - lip_tol;
        translate([(outside_width - lip_width)/2,(outside_length - lip_length)/2, thickness * 0.99])
            difference(){
                cube([lip_width, lip_length, thickness]);
                translate([thickness, thickness, 0])
                    cube([lip_width-thickness*2, lip_length-thickness*2, thickness]);
        }

        intersection(){
            union(){
            translate([od/2 + thickness, od/2 + thickness, thickness])
                box_screw(screw_dia, od, thickness);
            translate([inside_width - od/2 + thickness, od/2 + thickness, thickness])
                rotate([0,0,90])
                    box_screw(screw_dia, od, thickness);
            translate([inside_width - od/2 + thickness, inside_length - od/2 + thickness, thickness])
                rotate([0,0,180])
                    box_screw(screw_dia, od, thickness);
            translate([od/2 + thickness, inside_length - od/2 + thickness, thickness])
                rotate([0,0,270])
                    box_screw(screw_dia, od, thickness);
            }
            translate([thickness + lip_tol, thickness + lip_tol, 0])
            cube([lip_width-lip_tol,lip_length-lip_tol, 200]);
        }

        }

        union(){
            translate([od/2 + thickness, od/2 + thickness, thickness])
                cylinder(h = thickness * 4, d = screw_loose_dia, center=true, $fs=0.2);
            translate([inside_width - od/2 + thickness, od/2 + thickness, thickness])
                cylinder(h = thickness * 4, d = screw_loose_dia, center=true, $fs=0.2);
            translate([inside_width - od/2 + thickness, inside_length - od/2 + thickness, thickness])
                cylinder(h = thickness * 4, d = screw_loose_dia, center=true, $fs=0.2);
            translate([od/2 + thickness, inside_length - od/2 + thickness, thickness])
                cylinder(h = thickness * 4, d = screw_loose_dia, center=true, $fs=0.2);
        }
    }
}

main_box();
translate([-outside_width-2,0,0])
    lid();

```


[User]
I'm looking to create a set of corner rounding templates, kind of like the ones you see for woodworking, but I need them to be easily customizable. I've got an idea of what I want, and I've even played around with OpenSCAD myself a bit, but I'd love for an AI to help me generate it cleanly.

Basically, the template will be a flat plate with two rounded corners. The main parameters I'd like to control are:

*   **Overall width:** This will determine the total size of the template.
*   **Plate thickness:** How thick the base of the template is.
*   **Wall thickness:** I want to be able to add walls to the top and bottom of the plate. This determines how thick the walls will be.
*   **Wall height:** The height of these added walls.
*   **Wall corner distance:** How far the walls are from the rounded parts of the template.
*   **Text depth:** If any text is included (see below), how deep it should be.
*   **Radius 1:** The radius of the first rounded corner.
*   **Radius 2:** The radius of the second rounded corner.

The template should have a square body with two rounded corners, with the first rounding in one corner and the second rounding in the opposite corner. I'd like to include text labels showing the radius of each rounding; for example, "← 16mm" near one corner. The text should be engraved, not just printed on the surface, and needs to be oriented in line with the corner edge and perpendicular to the line of the rounding. The text needs to be a single character "←" followed by the radius in mm. For example "←16mm".

I also need the option to add walls to the top and bottom of the template. These walls need to be square, offset from each edge by wallThickness, and should be extruded from the edges to create the walls.

Could you generate OpenSCAD files to do this?

[Assistant]
corner_template.scad:
```
/******************************************************************************
 *
 *  GLOBALS
 *
 ******************************************************************************/

// Overall width of template (with walls)
width = 100;
// Plate thickness
thickness = 4;
wallThickness = 6;
wallHeight = 10;
// Walls distance from rounding ends.
wallCornerDistance = 10;
textDepth = 1;
radius1 = 16;
radius2 = 24;

/* [Hidden] */
$fa = 1;
$fs = 0.5;

/******************************************************************************
 *
 *  EXECUTION
 *
 ******************************************************************************/

rotate([90, 0, 0])
{
    difference()
    {
        plate();
        descriptions();
    }
    walls();

}

/***************************************************************************
 *
 *  DIRECT MODULES
 *
 ******************************************************************************/

module plate()
{
    linear_extrude(thickness)
        _platePlane();
}

module walls()
{
    linear_extrude(wallHeight)
        _wallsPlane1();

    translate([0, 0, thickness - wallHeight])
        linear_extrude(wallHeight)
            _wallsPlane2();
}

module descriptions()
{
    translate([radius1 * sqrt(2) - radius1, radius1 * sqrt(2) - radius1, 1])
        rotate([180, 0, 45])
            linear_extrude(textDepth + 1)
                text(text = str("←", radius1, "mm"), size = radius1 / 2, valign = "center");

    translate([width - 2 * wallThickness - radius2 * sqrt(2) + radius2, width - 2 * wallThickness - radius2 * sqrt(2) + radius2, thickness - textDepth])
        rotate([0, 0, 225])
            linear_extrude(textDepth + 1)
                #text(str("←", radius2, "mm"), size = radius2 / 2, , valign = "center");

}

/******************************************************************************
 *
 *  HELPER AND COMPONENT MODULES
 *
 ******************************************************************************/

module _platePlane()
{
    difference()
    {
        square(width - 2 * wallThickness);
        _roundingsPlane();
    }
}

module _roundingsPlane()
{
    _cornerRoundingPlane(radius1);
    translate([width - 2 * wallThickness, width - 2 * wallThickness, 0])
        rotate([0, 0, 180])
            _cornerRoundingPlane(radius2);
}

module _cornerRoundingPlane(radius)
{
    translate([radius, radius, 0])
        rotate([0, 0, 180])
            difference()
            {
                square(radius + 1);
                circle(r = radius);
            }
}

module _wallsPlane1()
{
    translate([-wallThickness, radius1 + wallCornerDistance, 0])
        square([wallThickness, width - radius1 - wallCornerDistance - wallThickness ]);
    translate([radius1 + wallCornerDistance, -wallThickness, 0])
            square([width - radius1 - wallCornerDistance - wallThickness, wallThickness]);
}

module _wallsPlane2()
{
    translate([width - 2 * wallThickness, -wallThickness, 0])
            square([wallThickness, width - radius2 - wallCornerDistance]);
    translate([-wallThickness, width - 2 * wallThickness, 0])
            square([width - radius2 - wallCornerDistance, wallThickness]);
}

```


[User]
I'd like a design for a customizable guitar pick, please. The basic shape should be a standard guitar pick, with a pointed tip and a rounded end for holding. I've got some dimensions in mind: the pick should be 16mm long from tip to the center of the rounded end. The tip radius should be 2mm, and the hold radius should be 11mm.

I also want to add some text to the pick. This text should be placed on the rounded end. I would like to be able to control the text's size, font, and actual content through customizer variables, and the text should be embossed, not engraved.

Finally, I would like 6 equally spaced circular cutout features on the rounded end to go all the way through the pick. The distance from the center of the rounded end to the center of these cutouts should be a customizer variable. The radius of these cutouts should also be a customizer variable.

The design should be made in OpenSCAD and should use the `text()` module for the text feature. So, I expect that there will be an `text_str`, `text_size`, `text_font` parameters in addition to the radius and length parameters as well as the radius and distance parameters for the cutouts.

[Assistant]
NEWPICK.scad:
```

$fn = 37;
pick_length = 16;
tip_radius = 2;
hold_radius = 11;

module pick() {
  hull() {
    translate([0,0,0.0]) cylinder(r=tip_radius,h=0.5);
    translate([pick_length,0,0]) cylinder(r=hold_radius,h=0.5);
  }
}

difference() {
  pick();

  // Now decorate the pick with some features.

  translate([pick_length,0,]) {
    for (angle = [0:60:300]) {
      ;
    }
  }
}
```


[User]
I'm looking to create a tool for my Dremel drill press that helps me make round discs from square stock. I have a basic design in mind, but I need help getting it into OpenSCAD.

The tool will be a plug with two main cylindrical sections: a bottom plug that fits into the drill press, and a wider top support. It'll also have a hole through the center to mount the stock.

Here are the specific parameters I need to be able to adjust:

*   **`bottomDiameter`**: The diameter of the bottom plug that fits into the drill press.
*   **`topDiameter`**: The diameter of the top support, which should be slightly smaller than the final disc size.
*   **`holeDiameter`**: The diameter of the center hole, which will be used to mount the square stock. I'll be using a dowel or drill bit here.
*   **`topHeight`**: The height of the top support section.
*   **`bottomHeight`**: The height of the bottom plug section.

The design will be a single piece, created by combining two cylinders and subtracting the center hole. The bottom cylinder will be for the plug, while the second, wider one on top is the support for the stock. The center hole should go all the way through.

I'd like to be able to adjust these in the OpenSCAD Customizer. Can you generate the OpenSCAD code for this tool, including the ability to adjust all of these parameters? Please include comments in the code for clarity. The $fn for circles should be set to 128 for a smooth result.

[Assistant]
rounder.scad:
```
// Diameter of the hole the plug is plugged into
bottomDiameter = 19;
// Diameter of the top support, make this slightly smaller then the diameter of the circle you are trying to make
topDiameter = 30;
// Inner hole Diameter, adjust this to the dowel you will use for centering your material
holeDiameter = 2.8;
// Height of the top support, increase this if your tool needs more space on the bottom
topHeight = 5;
// Height of the bottom piece of the plug
bottomHeight = 10;

/* [Hidden] */
$fn = 128;
bottomRadius = bottomDiameter / 2;
topRadius = topDiameter / 2;
holeRadius = holeDiameter / 2;

totalHeight = topHeight + bottomHeight;

difference() {
  group() {
    cylinder(h = totalHeight, r = bottomRadius);
    cylinder(h = topHeight, r = topRadius);
  }

  cylinder(h = totalHeight + 2, r = holeRadius);
}
```


[User]
Hi! I'm looking to create a parametric design for Yokai Watch medals, specifically the English version, that will allow me to customize the notch pattern.

I'd like the design to be based on the provided OpenSCAD code, but I need to make it fully parametric so I can easily change the notch configuration. The core shape of the medal is a cylinder with some cutouts for the central rectangular area and the bottom triangle/circle. The notches are arranged in a 4x4 grid. Here's a breakdown of what I need:

*   **Base Medal Shape:** A cylinder with a diameter of 21 and a height of 3.6. I'd also like it to have a high number of `$fn` to make the circle nice and smooth.
*   **Center Cutout:** A rectangular cutout in the middle of the medal. This needs to be in two layers, with the top layer being slightly bigger than the lower one. The provided code is okay for dimensions.
*   **Triangle Cutout:** A triangular cutout that goes down into the base cylinder. I like how it's made by using a linear extrude of a polygon.
*   **Circle Cutout:** A circle/cylinder cutout that's scaled in the y direction. Also goes down into the base cylinder. The code's dimensions for this are fine.
*   **Notch Placement:** The notches are arranged in a 4x4 grid, each with a consistent shape made from a linear extrude of a polygon. I'd like to control this grid using a parameter, so it's not hardcoded like in the given code.
*   **Parametric Notch Control:** Instead of the `pegList`, I'd like to specify the notch pattern through a parameter. I’m imagining a 4x4 array/list of 0s and 1s, where 1 means the notch should be present and 0 means it's absent. It'd be great if this could be easily changeable through customizer.
*   **Consistent Notch Dimensions:** The individual notch shapes and their location in the grid should be the same as in the provided code (e.g. dimensions, rotation, etc.). The grid layout should also remain the same, so it looks proper.

I'm thinking I'll need a library to make handling lists easy, so you should probably include the `MCAD` library, since I know that has some useful functions. I don’t need a full breakdown on how to implement the parts that are already present, but I need the overall design to be fully customizable from a single file and the notch configuration to be specified through a single parameter. I’m okay with any necessary helper functions you need to add to make this work.

[Assistant]
YokaiWatchMedal.scad:
```
// YokaiWatchMedal.scad

pegList = [[1,1,1,1],[1,1,1,1],[1,1,1,1],[1,1,1,1]];

union() {
    difference() {
        cylinder(3.6,21,21,$fn=128);
        translate([7.5,0,3.6]) cube([19,60,3], center=true);
        translate([7.5,0,3.1]) cube([16,60,3], center=true);
        translate([0,13,-2])
            linear_extrude(height = 5, center = true, convexity = 10, twist = 0)
                polygon(points = [[5, 0], [-5, 0], [0, 5]]);
        translate([0,-16,-2]) scale([1,0.4,1]) cylinder(3,6,6,$fn=32);
    }
    startPos = [1.45,13.3,1.5];
    for (a=[1:4])
        for (b=[1:4])
            if ((pegList[b-1])[a-1])
                translate(startPos + [((a-1)*4),((b-1)*-6),0])
                    rotate([90,0,90])
                        linear_extrude(height = 4, center = true, convexity = 10, twist = 0)
                            polygon(points = [[1, 0], [-1, 0], [-0.3, 2.5], [0.3, 2.5]]);

}

```


[User]
I'm looking to create a configurable hook design for mounting sheet metal parts. I'd like to be able to adjust several parameters like the thickness of the sheet metal, the depth of the slot it fits into, the clip length, clip width, mounting plate dimensions, hook width, and even choose between having a single or double hook.

Specifically, I need:

1.  **Mounting Plate:** A rectangular plate with configurable width, thickness, and height.
2.  **Slot Clip:** A clip that extrudes from the mounting plate designed to fit into a slot in sheet metal. This clip needs adjustable length, width, and depth of the "tongue" that goes into the slot.
3.  **Support Structure (Optional):** I'd like the option to generate a custom support structure for the clip. Cura and other slicers aren't always great with that geometry.
4.  **Hook:** The actual hook geometry. It should be configurable to be either a single hook or a double hook design. The hook shape should be generated using a configurable set of points (a polygon), and it should have rounded edges. It should also be able to be adjusted in width.

Here's a breakdown of the parameters I'd like to control:

*   `metal_thickness`: Thickness of the sheet metal the hook is designed to work with.
*   `slot_depth`: How deep the clip needs to extend into the sheet metal slot.
*   `clip_length`: The length of the clip.
*   `clip_width`: The width of the clip.
*   `mountingplate_width`: The width of the mounting plate.
*   `mountingplate_thickness`: The thickness of the mounting plate.
*   `mountingplate_height`: The height of the mounting plate.
*   `hook_width`: The width of the hook.
*   `hook_type`: Either "single" (one hook) or "double" (two hooks).
*   `round_edge_radius`: The radius for the rounded edges of the hook.
*   `hook_data`: A list of 2D coordinates that define the profile of the hook polygon.
*   `custom_support`: Boolean value - `true` to generate the support structure, `false` to skip.

I'd like the output to be a single OpenSCAD file, but I would be okay with multiple files if that's easier. I don't need any libraries. Could you generate the necessary OpenSCAD code for this?

[Assistant]
hook.scad:
```
metal_thickness         = 1.2; //thickness of the sheet metal
slot_depth              = 1.2;
clip_length             = 15;
clip_width              = 14;
mountingplate_width     = 25;
mountingplate_thickness = 3;
mountingplate_height    = 25;
hook_width              = 10;
hook_type               = "single"; //"single" = ohne hook, "double" = two hooks in a row
round_edge_radius       = 1;
$fn                     = 50;
hook_data               = [[0,0],[10,3],[9,17],[9,15],[8,5],[0,3]];
custom_support          = false; //true = print a custom support structure for the clip. false = print no support.

//the mounting plate:
linear_extrude( mountingplate_width )
	translate([-metal_thickness-mountingplate_thickness,0,0])
		polygon( points=[[0,0],[0,mountingplate_height],[mountingplate_thickness,mountingplate_height],[mountingplate_thickness,0]] );

//the clip for the slot:
translate([0,0,(mountingplate_width-clip_width)/2])
	linear_extrude( clip_width )
		polygon( points=[[0,0],[0,clip_length],[slot_depth,clip_length],[slot_depth,0],[metal_thickness-mountingplate_thickness,0],[metal_thickness-mountingplate_thickness,2],[0,2]] );

//support structure for the clip (because cura does not handle the clip at all, and slic3r does not handle it to my complete satisfaction):
if ( custom_support )
{
	for(x = [0.5 : 1.0 : clip_length])
		translate([0.5,x,(mountingplate_width-clip_width)/2-2.8])
			rotate([90,0,0])
				linear_extrude( 0.5 )
					square([1.6,(mountingplate_width-clip_width)/2], center=true);
	translate([-0.8,1,(mountingplate_width-clip_width)/2-2.8])
		rotate([90,0,90])
			linear_extrude( 0.5 )
				square([2.5,(mountingplate_width-clip_width)/2], center=true);
}

//the hook:
if ( hook_type == "single" )
{
	translate([-metal_thickness-mountingplate_thickness,mountingplate_height-round_edge_radius,mountingplate_width/2-hook_width/2])
	rotate([180,180,0])
	linear_extrude(hook_width)
		minkowski()
		{
			//polygon( points=[[0,0],[8,3],[8,17],[5,15],[5,7],[0,5]] );
			polygon( points=hook_data );
			circle( r=round_edge_radius );
		}
}
else if ( hook_type == "double" )
{
	translate([-metal_thickness-mountingplate_thickness,mountingplate_height-round_edge_radius,0])
	rotate([180,180,0])
	linear_extrude(hook_width)
		minkowski()
		{
			polygon( points=hook_data );
			circle( r=round_edge_radius );
		}
	translate([-metal_thickness-mountingplate_thickness,mountingplate_height-round_edge_radius,mountingplate_width-hook_width])
	rotate([180,180,0])
	linear_extrude(hook_width)
		minkowski()
		{
			polygon( points=hook_data );
			circle( r=round_edge_radius );
		}
}
```


[User]
Hi! I need an OpenSCAD design for a stepper motor spacer, specifically for NEMA motors. I'm working on an Ultimaker-style printer and need to space the motor away from the frame so the belts don't rub. I've got a basic idea, but I need something that is fully parametric so I can adjust it easily.

Here's the breakdown of what I need:

*   **Overall Shape:**  The spacer should have a base plate, columns for spacing, and arms connecting the columns to the base. It's essentially a sort of platform with four legs. The base plate should be a roundish shape, created by a hull that connects some cylinder shapes on the bottom of the columns and also some "arms" that form bridges between the columns. These arms shouldn't run all the way to the middle of the design and will create a void in the middle of the base plate. A final hull should create the base around the columns themselves.
*   **Column Spacing:** The columns should be positioned according to the NEMA motor screw spacing, which I'd like to be a variable. We'll need to define the spacing between the screw holes using the NEMA standard. The columns should be cylindrical. The screw holes should pass through the full height of the design and the base.
*   **Dimensions:** I need to be able to specify the following as variables:
    *   `tower_h`:  The total height of the spacer (the distance it spaces the motor from the wall)
    *   `tower_d`:  The diameter of the support columns
    *   `base_h`:  The thickness of the base plate
    *   `screw_d`:  The diameter of the screw holes
    *   `screw_spacing`: The spacing of the NEMA mount holes.
*   **Hole Placement:** The screw holes should be centered in each column and should pass fully through.
*   **Void Creation:**  The arms connecting the columns will create a void area in the middle and I'd like to define the diameter of the space by calculating the space between the columns and subtracting the column diameter (variable `void_d = screw_spacing - tower_d`)
*   **Tolerance:** It should be possible to define a small tolerance, `tol`, that we can use to slightly offset things to ensure a good fit.
*   **Faceting:** Please be sure to have variables `$fs` and `$fa` to allow control over the curve resolution, and set some defaults, say 0.8.

Could you provide the OpenSCAD file or files for this design?  I don't need any special libraries, just core OpenSCAD functionality. Thanks!

[Assistant]
nema_spacer.scad:
```
//
// nema stepper motor spacer (rev 1) - 20170831-121947
//
// (c)Jeremie Francois (jeremie.francois@gmail.com)
//	http://www.thingiverse.com/MoonCactus
//	http://www.tridimake.com
//
// Licence: Attribution - Share Alike - Creative Commons
//

// Spacing with the wall (overall height)
tower_h= 15;

// Diameter of the columns
tower_d= 7;

// Thickness of the base plate
base_h= 2;

// Diameter of the screw holes
screw_d= 3.1;

// Nema stepper properties http://www.mosaic-industries.com/embedded-systems/microcontroller-projects/stepper-motors/specifications
screw_spacing= 31.0;

// Space between the arms
void_d= screw_spacing - tower_d;

// Size of facets (lower=finer)
$fs= 0+0.8;
$fa= 0+0.8;

difference()
{

    union()
    {
		// Baseplate
        hull()
			for(x=[-1,+1]) for(y=[-1,0]) scale([x,y,1])
				translate([screw_spacing/2,screw_spacing/2,0])
					cylinder(d= tower_d, h= base_h);
		// Rounded arms
		for(x=[-1,+1]) hull() for(y=[-1,+1]) scale([x,y,1])
			translate([screw_spacing/2,screw_spacing/2,-tol])
				cylinder(d= tower_d, h= base_h);

		// Columns
        for(x=[-1,+1]) for(y=[-1,+1]) scale([x,y,1])
            translate([screw_spacing/2,screw_spacing/2,0])
                cylinder(d= tower_d, h= tower_h);

		// Bottom wall
        hull()
			for(x=[-1,+1]) for(y=[-1]) scale([x,y,1])
				translate([screw_spacing/2,screw_spacing/2,0])
					cylinder(d= 2, h= tower_h);
    }

	// Screw holes
    for(x=[-1,+1]) for(y=[-1,+1]) scale([x,y,1])
        translate([screw_spacing/2,screw_spacing/2,-tol])
            cylinder(d= screw_d, h= tower_h+2*tol);

	// Void between the arms
    translate([0,0,-tol])
    hull()
    {
		for(t=[0,20])
			translate([0,t,0])
				cylinder(d=void_d,h=base_h+2*tol);
    }
}

tol=0.02;

```


[User]
I'm trying to design a custom tray, specifically for soap, and I'd like to be able to adjust several parameters. I need an OpenSCAD file that can handle this.

The main body of the tray should be a rounded rectangular box. I need to control the width, depth, and height of this box using parameters. I'd like to be able to optionally include ventilation fins on the sides, small holes in the bottom for drainage, and a tube mount on the back.

The tube mount should consist of a partial ring that can be used to clip onto a tube and should be configurable by the diameter of the tube. It would be great if the mounting had a partial clip system to fit around the tube.

Here's a breakdown of the parameters I'd like to control:

*   **`width`**: Width of the main box.
*   **`depth`**: Depth of the main box.
*   **`height`**: Height of the main box.
*   **`vents`**: Boolean (1 for Yes, 0 for No) to enable or disable ventilation fins.
*   **`holes`**: Boolean (1 for Yes, 0 for No) to enable or disable drainage holes.
*   **`mount`**: Boolean (1 for Yes, 0 for No) to enable or disable the tube mount.
*   **`d`**: Diameter of the tube for the tube mount.

I don't need to use any particular libraries for the core shapes (such as boxes), and I'd like for this to be as modular as possible, so that the shape and size of the drainage holes and fins are also parameterized as much as possible as well, but not necessarily exposed to the user.

[Assistant]
CustomTray_Fixed.scad:
```
// preview[view:north east, tilt:top]
//include <MCAD/boxes.scad>  // Include Boxes library to get easy rounded boxes

// Width of box
width = 72; // [24:12:144]

// Depth of box
depth = 48; // [24:12:144]

// Height of box
height = 20; // [8:80]

// Do you want ventilation fins? (your soap will last longer)
vents = 1; // [1:Yes,0:No]

// Do you want holes?
holes = 1; // [1:Yes,0:No]

// Do you want a tube mount?
mount = 1; // [1:Yes,0:No]

// Diameter of tube to mount this on
d = 25.1; // [6:0.1:40]

/* [Hidden] */

h = height+20;
r = d/2;
f = d/7;
t = d/6;
os = t;
a = 44;
detail = 40;

$fs = 0.5;
$fa = 5.1;
// Difference will construct a main shape and subtract cut outs
difference() {

  //***********
  // Main Shape
  //***********

  union() {

    // Main mount cylinder solid
    if (mount == 1) {
      translate([0,0,h/2]) {
        rcylinder(r+t,r+t,h,2,true);
      } // End translate
    } // End if mount

    // Soap cup
    difference() {

      // Soap cup solid
      translate([0,-width/2-t-os,height/2]) {
        roundedBox([depth, width, height], 4, false);
      }

      // Soap cup cut out
      translate([0,-width/2-t-os,(height/2)+width/25]) {
        roundedBox([depth-width/11, width-width/11, height], 4, false);
      }

      // Holes in the soap cup
      if (holes == 1) {
        for (spaceD =[-depth/2+12:12:depth/2-3]) {
          for (spaceW =[r+10:12:width-1]) {
            translate([spaceD,-spaceW+2.5-os,-1]) {
              cylinder(width/10, 3, 5, false);
            } // End translate
          } // End for spaceW
        } // End for spaceD
      } // End if holes

    } // End difference soap cup

    // Ventilation fins
    if ((vents==1) && (depth>=48) && (width>=48)) {
      difference() {

        union(){

          // Big fins
          rotate([90,0,180]) {
            for (spaceW =[r+10+4.5:12:width-5]) {
              translate([-depth/3.8,width/15,-spaceW+1-os]) {
                linear_extrude(height = 2, center = true, convexity = 10, twist = 0)
polygon(points=[[0,0], [0,-3], [depth/1.5,-3], [depth/1.5,40],[depth/1.5-5,40]]);
              } // End translate
            } // End for spaceW
          } // End rotate

          // Small fins
          rotate([90,0,0]) {
            for (spaceW =[r+10+4.5:12:width-5]) {
              translate([depth/7-1,width/15,spaceW-1+os]) {
                linear_extrude(height = 2, center = true, convexity = 10, twist = 0)
polygon(points=[[0,0],[0,-3],[depth/3.5,-3],[depth/3.5,15],[depth/3.5-5,15]]);
              } // End translate
            } // End for spaceW
          } // End rotate
        } // End union
    } // End difference
  } // End if vents

  } // End union

  // Cut outs from mounting cylinder

  if (mount==1) {
    // Cut out center cylinder
    translate([0,0,-1]) {
      cylinder(h+2, r, r, false);
    }

    // Cut out right wall
    rotate([0,0,a]) {
      translate([0,r,h/2]) {
        cube([t, d, h+2],true);
      }
    }

    // Cut out left wall
    rotate([0,0,-a]) {
      translate([0,r,h/2]) {
        cube([t, d, h+2],true);
      }
    }

    // Cut out center wall
    translate([0,r,h/2]) {
      cube([d/1.18, d, h+2],true);
    }
  }
} // End difference

  module rcylinder(r1=10,r2=10,h=10,b=2)
{translate([0,0,-h/2]) hull(){rotate_extrude() translate([r1-b,b,0]) circle(r = b); rotate_extrude() translate([r2-b, h-b, 0]) circle(r = b);}}

 module roundedBox(dimentions, radius, unknown) {
     depth = dimentions[0];
     width = dimentions[1];
     height = dimentions[2];

     translate([-depth/2, -width/2, -height/2+radius]) hull() {
         translate([0, width, height]) sphere(r=radius);
         translate([depth, 0, height]) sphere(r=radius);
         translate([0, 0, height]) sphere(r=radius);
         translate([depth, width, height]) sphere(r=radius);

         translate([0, width, 0]) sphere(r=radius);
         translate([depth, 0, 0]) sphere(r=radius);
         translate([0, 0, 0]) sphere(r=radius);
         translate([depth, width, 0]) sphere(r=radius);
     }
 }
```


[User]
I'd like to create a customizable Lego Technic double angular beam. I have an existing OpenSCAD file that I can provide as a reference, but I'd like a fresh implementation that's fully parametric from the ground up and a bit more flexible.

Here's what I need:

*   **Double Angular Beam Structure:** The design should generate a double angular beam with a 45-degree angle between the two arms. The arms themselves should be straight Lego Technic beams.
*   **Number of Holes:** The number of holes along each arm should be independently configurable. Let's call these `holes_x` and `holes_y`.
*  **Step:**  I want to configure the distance between the corner and the first pin hole on the first beam. Let's call this `step`. I'd like to be able to set this to 1, 2 or 3.
*   **Hole Dimensions:** The holes should be standard Lego Technic pin holes with two different diameters – a smaller diameter for the main hole and a slightly larger diameter for the outer edges, and depth variations. These diameters should be configurable as `diameter1` and `diameter2` respectively, also I'd like to specify the `depth`.
*   **Beam Dimensions:** I need to define the overall beam dimensions: height (`height`), width (`width`), and middle thickness (`mid_thickness`).
*  **Mini Cube Detail:** I'd like to have small cubes at each hole to replicate the real lego beam, that are defined by `mini_cube_offset` and `mini_cube_width`.
* **Cross Inner Radius:** I'd like to specify the inner radius of the cross section. This should be adjustable with `cross_inner_radius`.
*   **Parametric:**  All dimensions (hole spacing/pitch, radius of holes, beam dimensions, etc.) should be easily adjustable through parameters.  The pitch between holes should be a multiple of 8, let's call that `pitch`.
*   **No Specific Libraries:** I'd like to avoid relying on any specific external libraries (like BOSL or MCAD) for this design. We should be able to implement everything using basic OpenSCAD primitives.

Essentially, I want the equivalent of the attached code's functionality, but with a clean, from-scratch, fully parametric approach. The parameters should be able to set any dimensions of the beam, the hole dimensions and the angular section. I want to be able to specify the number of holes in both directions, and the step from the corner.

I have attached the original SCAD file as a reference.

[Assistant]
Lego_Technic_-_Double_Angular_Beam_Customizable.scad:
```
/*
        Customizable LEGO Technic Beam on Parametric LEGO Technic Beam
        by "projunk" www.thingiverse.com/thing:203935
        and Even More Customizable Straight Beam for LEGO Technic
        by "samkass" www.thingiverse.com/thing:1119651
        and Lego Technic: Perpendicular Beam Connector  Customizable
        by "shusy" www.thingiverse.com/thing:2503065
        Modified by Shusy
        September 2017
*/

$fn=40;

eps = 0.05*1;

//Nuber of the holes
NrOfHolesX = 7;
NrOfHolesY = 3;
Step = 2; // [1:3]
Diameter1 = 4.8;
Diameter2 = 6.1;

Pitch = 8*1;
Radius1 = Diameter1 / 2;
Radius2 = Diameter2 / 2;
Height = 7.8*1;
Depth = 0.8*1;
Width = 7.5*1;
MidThickness = 2*1;
MiniCubeOffset = 1.1*1;
MiniCubeWidth = Radius1 - MiniCubeOffset;
CrossInnerRadius = 1.5*1;

translate([Pitch*Step,0,0])drawBeam(NrOfHolesX);
translate([0,Pitch*Step,0])rotate([0,0,90])drawBeam(NrOfHolesY);

AngularDrawBeam(Step+1);

module drawBeam(NrOfHoles){
translate([0,-Width/2,0])union(){
{
	Length = (NrOfHoles - 1) * Pitch;
	Thickness = (Width - 2 * Radius2) / 2;

	difference()
	{
		union()
		{
			cube([Length, Thickness, Height]);
			translate([0, Width-Thickness,0]) cube([Length, Thickness, Height]);
			translate([0, 0, Height/2-MidThickness/2]) cube([Length, Width, MidThickness]);
			for (i = [1:NrOfHoles])
			{
				translate([(i-1)*Pitch, Width/2,0])
				{
					cylinder(r=Width/2, h=Height);
				}
			}
		}

		union()
		{
            for (i = [1:NrOfHoles-1])
			{
				translate([(i-1)*Pitch, Width/2,0])
				{
					translate([0,0,-eps]) cylinder(r=Radius2,h=Depth+eps);
					translate([0,0,-eps]) cylinder(r=Radius1,h=Height+2*eps);
					translate([0,0,Height-Depth]) cylinder(r=Radius2,h=Depth+eps);
				}
			}
            translate([(NrOfHoles-1)*Pitch, Width/2,0]) plus();
		}
	}

}
}
}

module AngularDrawBeam(NrOfHoles){
rotate([0,0,-45])
   translate([-(NrOfHoles-1)*Pitch*sqrt(2)/2,(NrOfHoles-1)*Pitch*sqrt(2)/2-Width/2,0])
    union(){
{
	Length = (NrOfHoles - 1) * Pitch*sqrt(2);
	Thickness = (Width - 2 * Radius2) / 2;

	difference()
	{
		union()
		{
			cube([Length, Thickness, Height]);
			translate([0, Width-Thickness,0]) cube([Length, Thickness, Height]);
			translate([0, 0, Height/2-MidThickness/2]) cube([Length, Width, MidThickness]);
				translate([0, Width/2,0])cylinder(r=Width/2, h=Height);
				translate([Length, Width/2,0])cylinder(r=Width/2, h=Height);
            hull(){
				translate([Pitch, Width/2,0])cylinder(r=Width/2, h=Height);
				translate([Length-Pitch, Width/2,0])cylinder(r=Width/2, h=Height);
            }

		}

		union()
		{
				translate([0, Width/2,0])
				{
					translate([0,0,-eps]) cylinder(r=Radius2,h=Depth+eps);
					translate([0,0,-eps]) cylinder(r=Radius1,h=Height+2*eps);
					translate([0,0,Height-Depth]) cylinder(r=Radius2,h=Depth+eps);
				}
				translate([Length, Width/2,0])
				{
					translate([0,0,-eps]) cylinder(r=Radius2,h=Depth+eps);
					translate([0,0,-eps]) cylinder(r=Radius1,h=Height+2*eps);
					translate([0,0,Height-Depth]) cylinder(r=Radius2,h=Depth+eps);
				}
                hull(){
					translate([Pitch,Width/2,-eps]) cylinder(r=Radius2,h=Depth+eps);
					translate([Length-Pitch, Width/2,-eps])cylinder(r=Radius2,h=Depth+eps);
                }
                hull(){
					translate([Pitch,Width/2,-eps]) cylinder(r=Radius1,h=Height+2*eps);
					translate([Length-Pitch, Width/2,-eps])cylinder(r=Radius1,h=Height+2*eps);
                }
                hull(){
					translate([Pitch,Width/2,Height-Depth]) cylinder(r=Radius2,h=Depth+eps);
					translate([Length-Pitch, Width/2,Height-Depth])cylinder(r=Radius2,h=Depth+eps);
                }

		}
	}
}
}
}

module plus() {
Plus_Width = 2.0*1.0;
Overhang = 0.05*1.0;
    union() {
        translate([-Plus_Width/2, -Radius1, -Overhang])
            cube([Plus_Width, Radius1*2, Height+Overhang*2]);
        translate([-Radius1, -Plus_Width/2, -Overhang])
            cube([Radius1*2, Plus_Width, Height+Overhang*2]);
    }
}

```