[User]
I'm looking to design a parametric pegboard mounting system in OpenSCAD, similar to the one I saw on Thingiverse but I'd like to have some more flexibility with the generated parts and how they fit together. I need it to work with standard 1/4 inch (6.35mm) pegboard holes spaced 1 inch (25.4mm) apart and accommodate pegboard thicknesses from 1/4 inch to 3/4 inch (6.35 to 19.05mm), although I'll primarily be using 4mm thick pegboard.

Here's a breakdown of what I need. The basic design idea is that there's a "Mounting Peg" that folds in half after printing, and then slides into the pegboard. Then, other accessories like bins or hooks slide onto the mounting peg.

**Core Components & Parametrization:**

1.  **Mounting Peg:**
    *   This is the key component, consisting of two halves connected by a thin hinge.
    *   It needs a tapered, angled section to interlock with a matching socket in other objects. The angle of the taper should be 45 degrees.
    *   The base should slot into a standard pegboard hole, so it needs the ability to adjust for tolerances with a `Peg_Tolerance` setting.
    *   The portion that inserts into the socket should also have a tolerance parameter `Mount_Tolerance`.
    *   It should include two peg components, one straight and one with a "hook" angled piece
    *   There should be a parameter for the pegboard thickness `Pegboard_Depth`.
    *   The peg diameter should be set with `Hole_Diameter`.
    *   The distance between peg holes is `Hole_Grid_Size`.

2.  **Mounting Socket:**
    *   This is the female part on all accessory items. It should have the same angled taper as the Mounting Peg. It should fit securely to the "Mounting Peg", using the `Mount_Tolerance` parameters from that section.
    *   There should be a `MountChute_Length` parameter which adds a length to the bottom of the mount for use when creating cutouts

3.  **Rounded Bin:**
    *   This is a basic bin that mounts to the pegboard.
    *   It should be fully customizable: `RoundedBin_WallThickness` for the wall thickness, `RoundedBin_Interior_X`, `RoundedBin_Interior_Y`, `RoundedBin_Interior_Z` for interior dimensions, `RoundedBin_CornerRoundness` for the corner roundness and `RoundedBin_Sections_L2R` and `RoundedBin_Sections_F2B` to add dividers.
    *   The mounting socket needs to be integrated.
    *   The top of the mount should also leave a `Mount_Slot_Top_Dist` gap above the top of the mount.

4.  **Scraper:**
    *   A narrow, flat bin to hold scrapers or other flat items.
    *   It needs parameters for wall thickness (`Scraper_WallThickness`), interior dimensions (`Scraper_Interior_X`, `Scraper_Interior_Y`, `Scraper_Interior_Z`), and an additional standoff distance from the pegboard with `Scraper_Extra_Y` in case handles stick out.
    *   It needs an integrated mounting socket.

5.  **Hook:**
    *   A simple hook for hanging objects.
    *   It needs parameters for hook thickness (`Hook_Thickness`), the length of the flat area (`Hook_FlatLength`), and the end cap bump (`Hook_RetainerThickness`).
    *   It needs an integrated mounting socket.

6.  **Twin Hook:**
     *   A double hook, very similar to the single hook.
     *   It needs parameters for hook thickness (`TwinHook_Thickness`), the length of the flat area (`TwinHook_FlatLength`), and the end cap bump (`TwinHook_RetainerThickness`), as well as `TwinHook_Gap` for the gap between the hooks
    *   It needs an integrated mounting socket.

7.  **Steel Sheet Holder:**
    *   A holder for thin steel sheets.
    *   It needs parameters for sheet thickness (`SSH_Thickness`), and how many sheets it will hold (`SSH_HowMany`).
    *   It needs an integrated mounting socket.

8.  **Mounting Cutout:**
    *   This is a separate piece which can be used to subtract the mounting system from other designs.
    *   It uses the same socket cutouts as the other models.
    *   It needs a `MountChute_Length` for the length of the added piece.
    *   It should use the `Mounting_Slot_Type` parameter for setting how many mounting points to include with "Only One", "Minimal", and "Maximum" settings.

**Global Parameters:**

*   `Hole_Diameter` (6.35mm) - Diameter of pegboard holes.
*   `Hole_Grid_Size` (25.4mm) - Center-to-center distance between pegboard holes.
*   `Mount_Tolerance` - How much to shave off the peg-side of the mount.
*   `Peg_Tolerance` - How much to shave from the diameter of the peg.
*   `Mounting_Slot_Type` - "Only One", "Minimal", "Maximum" for number of mounting slots on larger models
*   `Mount_Slot_Top_Dist` - Space left above top of mount, recommended 2

**Additional Requirements:**

*   The code should use `$fn = 32` for smooth curves.
*   Use a very small `eps` value to prevent Z-fighting or similar rendering issues.
*   The code should be parametric, allowing for easy modification of all parameters listed above.
*   The "Mounting Peg" part should print flat and be foldable.
*   The code should be well-commented for clarity.

I'm hoping you can generate the OpenSCAD code for all of this. I don't really need specific module names, but I'd prefer if the code was somewhat organized. I'm not using any external libraries. I think everything needed is in the core OpenSCAD language.

[Assistant]
Pegs_source_model.scad:
```
/*
pegboard vital statistics

hole diameters = 1/4 inch (6.35)
space between holes, center point to center point = 1 inch (25.4)
thickness = 1/4 - 3/4 inch (6.35 to 19.05)
*/

//////////////////////////////////////////
// Parameters - user-editable parameters
//////////////////////////////////////////

/* [Select Part] */
// The part to render
Part = "Mounting Peg"; //[Mounting Peg, Mounting Socket Test, Rounded Bin, Scraper, Hook, Twin Hook, Steel Sheet Holder, Mounting Cutout]

/* [Key Measurements (mm)] */
//Thickness of pegboard
Pegboard_Depth = 4;
//Diameter of the hole, changing this alters the mounting socket's size!
Hole_Diameter = 6.35;
//Spacing between all holes
Hole_Grid_Size = 25.4;

/* [Tolerances] */
//Amount shaved off of peg-side of mounting system (per side)
Mount_Tolerance = 0.35;
//Amount shaved from the diameter of the peg
Peg_Tolerance   = 0.35;

/* [Mounting] */
// Number of mounting slots. Minimal is 1-2, Maximum is as many as will fit.
Mounting_Slot_Type = "Minimal"; //[Only One, Minimal, Maximum]
//Space left above top of mount, I recommend never going below 2
Mount_Slot_Top_Dist = 2;

/* [Rounded Bin Settings] */
//Thickness of walls (not counting the back wall with the mount)
RoundedBin_WallThickness = 2;
//Interior of overall bin, left-to-right
RoundedBin_Interior_X = 50;
//Interior of overall bin, front-to-back
RoundedBin_Interior_Y = 50;
//Interior of overall bin, top-to-bottom, should be at least 1.5x larger than the Hole Grid Size
RoundedBin_Interior_Z = 70;
//Amount that the corners are rounded
RoundedBin_CornerRoundness = 5;
//How many sections to create with dividers, left-to-right
RoundedBin_Sections_L2R = 1;
//How many sections to create with dividers, front-to-back
RoundedBin_Sections_F2B = 1;

/* [Scraper Settings] */
//Thickness of walls
Scraper_WallThickness = 2;
//Interior of scraper slot, left-to-right
Scraper_Interior_X = 39;
//Interior of scraper slot, front-to-back
Scraper_Interior_Y = 1.2;
//Interior of scraper slot, top-to-bottom, should be at least 1.5x larger than the Hole Grid Size
Scraper_Interior_Z = 30;
//Extra distance from the pegboard (if bigger handles would hit
Scraper_Extra_Y = 5;

/* [Hook Settings] */
//Thickness of hook (width)
Hook_Thickness = 4;
//Length of the flat area of the hook
Hook_FlatLength = 35;
//Length of the endcap bump at the end
Hook_RetainerThickness = 5;

/* [Twin Hook Settings] */
//Thickness of hook (width)
TwinHook_Thickness = 2;
//Length of the flat area of the hook
TwinHook_FlatLength = 20;
//Length of the endcap bump at the end
TwinHook_RetainerThickness = 5;
//Gap between hooks
TwinHook_Gap = 7;

/* [Steel Sheet Holder Settings] */
//How thick the sheets you are holding will be
SSH_Thickness = 2;
//How many sheets to hold
SSH_HowMany = 2;

/* [Mounting Cutoff, to subtract from other models so you can mount them] */
// How long of a chute is added to the bottom of the mount. The default length is Hole_Grid_Size + Hole_Diameter
MountChute_Length = 0;

module endParams(){} endParams();

//////////////////////////////////////////
// Non-editable parameters - Dangerous or calculated parameters
//////////////////////////////////////////

// Facets of rounded edges
$fn=32;
// Epsilon, tiny measurement used to avoid overlapping edges during differences
eps = 0.007;
// Amount to make a super thin shape. Used to hull multiple shapes together
flatShape = 0.001;

//Size of peg
pegDiameter = Hole_Diameter - Peg_Tolerance;

//Mounting system is an 1 angled piece fitting into an angled slot
//These are the dimensions for the angle system, not counting tolerance changes
mount_angle        = 45;
mount_width_narrow = Hole_Diameter;
mount_width_wide   = Hole_Diameter + (Hole_Diameter * tan(90-mount_angle) * 2);
mount_depth        = Hole_Diameter;
mount_length       = Hole_Grid_Size + Hole_Diameter;

//Measurements for peg placement
peg_z_bottom = Hole_Diameter/2;
peg_z_top    = Hole_Diameter/2 + Hole_Grid_Size;

//////////////////////////////////////////
// Logic - what gets made
//////////////////////////////////////////

if (Part=="Mounting Peg"){
    part_mountingPeg();
}
else if (Part=="Mounting Socket Test"){
    part_testSocket();
}
else if (Part=="Rounded Bin"){
    part_roundedBin();
}
else if (Part=="Scraper"){
    part_scraper();
}
else if (Part=="Hook"){
    part_hook();
}
else if (Part=="Twin Hook"){
    part_twinHook();
}
else if (Part=="Steel Sheet Holder"){
    part_steelSheetHolder();
}
else if (Part=="Mounting Cutout"){
    part_mountingCutouts(mount_width_wide, MountChute_Length);
}

//////////////////////////////////////////
// Parts - objects that make up either a whole element, or parts of one
//////////////////////////////////////////

// Create either the socket for the mount, or the mounting bracket
module part_mount(type="socket", chuteLength=0){
    // Measurements without tolerance
    wide_wo   = mount_width_wide;
    narrow_wo = mount_width_narrow;
    depth_wo  = mount_depth;
    // Measurements with tolerance subtracted
    wide_w   = mount_width_wide   - Mount_Tolerance*2;
    narrow_w = mount_width_narrow - Mount_Tolerance*2;
    depth_w  = mount_depth        - Mount_Tolerance;
    // Select which measurement set to use from the above
    wide   = type=="socket" ? wide_wo   : wide_w;
    narrow = type=="socket" ? narrow_wo : narrow_w;
    depth  = type=="socket" ? depth_wo  : depth_w;

    // Create part
    union(){
        translate([0,0,chuteLength]){
            subpart_angledPiece();
            subpart_rectanglePiece();
        }
        subpart_straightChute();
    }

    // Subparts to help keep the part creating tidy
    module subpart_rectanglePiece(){
        translate([-narrow/2, -depth, 0])
        cube([narrow,depth,mount_length]);
    }
    module subpart_angledPiece(){
        hull(){
            //Top edge of triangle
            translate([0,flatShape/2,mount_length])
            linear_extrude(flatShape)
            square([narrow,flatShape], center=true);
            //Base of triange
            linear_extrude(flatShape)
            subpart_2dTrapazoid();
        }
    }
    module subpart_2dTrapazoid(){
        p1 = [-wide/2   , 0    ];
        p2 = [ wide/2   , 0    ];
        p3 = [ narrow/2 ,-depth];
        p4 = [-narrow/2 ,-depth];
        polygon([p1,p2,p3,p4]);
    }

    module subpart_straightChute(){
        linear_extrude(chuteLength)
        subpart_2dTrapazoid();
    }
}

//Create pegs that go into the pegboard. if not straight, it will be the curved hook
module part_peg(type="straight"){
    pegDepth = Pegboard_Depth;

    union(){
        subpart_horizontal();
        if (type!="straight") {
            subpart_diagonal();
            subpart_vertical();
        }

    }

    module subpart_horizontal(){
        cylinder(h=pegDepth, d=pegDiameter);
        translate([0,0,pegDepth])
        sphere(d=pegDiameter);
    }
    module subpart_diagonal(){
        translate([0,0,pegDepth])
        rotate([-45,0,0])
        subpart_horizontal();
    }
    module subpart_vertical(){
        translate([0,0,pegDepth])
        rotate([-45,0,0])
        subpart_diagonal();
    }
}

// The mounting peg piece, pegs & mount together
module part_mountingPeg(){
    difference(){
        //Main mountingPeg
        union(){
            //Left Half
            halfGap = 0.25;
            translate([-halfGap,0,0])
            rotate([-90,0,0])
            rotate([0,0,-90])
            subpart_halfPeg("left");
            //Right half
            translate([halfGap,0,0])
            rotate([-90,0,0])
            rotate([0,0,90])
            subpart_halfPeg("right");
            //Foldable connector between halves
            translate([-halfGap, 0,0])
            linear_extrude(0.2)
            square([halfGap*2,mount_length]);
        }
        //Removes pointy bit from mountingPeg
        translate([
            -Hole_Diameter/2,
            -eps,
            (mount_width_wide/2)-(Mount_Tolerance/2)-2
        ])
        cube([Hole_Diameter*2,Hole_Diameter*2,Hole_Diameter]);
    }

    //Create and position the whole peg shape as it will be once it is folded
    module subpart_wholePeg(){
        union(){
            part_mount(type="peg");

            translate([0,-(mount_depth-Mount_Tolerance),Hole_Diameter/2])
            rotate([90,0,0])
            part_peg(type="straight");
            translate([0,-(mount_depth-Mount_Tolerance),Hole_Diameter/2 + Hole_Grid_Size])
            rotate([90,0,0])
            part_peg(type="hook");
        }
    }
    //Take the wholePeg piece and cut it in half, allowing it to be printed flat
    module subpart_halfPeg(piece="left"){
        keeperCubeSize = [mount_width_wide/2+eps, mount_depth*4];
        xOffset = piece=="left" ? -keeperCubeSize.x : 0;

        difference(){
            subpart_wholePeg();

            translate([xOffset,-(keeperCubeSize.y-eps),-eps])
            linear_extrude(mount_length*mount_length)
            square(keeperCubeSize);
        }
    }
}

//Create a mounting system socket to do a test fit
module part_testSocket(){
    chuteLength = 0;
    x = mount_width_wide + 2;
    y = mount_depth + 2;
    z = mount_length + chuteLength + 2;

    translate([0,0,z])
    rotate([180,0,0])
    difference(){
        //Box
        translate([0,-2-eps, +eps])
        linear_extrude(z)
        square([x, y], center=true);
        //Cutout for mount
        part_mount(type="socket", chuteLength=chuteLength);
    }
}

//positions mounting cutouts to Y-aligned structures
module part_mountingCutouts(maxWidth, chuteLength){
    gapBetween = Hole_Grid_Size;
    maxThatCouldFit = floor(maxWidth/gapBetween);
    totalSpan = gapBetween * maxThatCouldFit;

    if (Mounting_Slot_Type=="Only One" || maxThatCouldFit<=1){
        subpart_cutout_centered();
    }
    else if (Mounting_Slot_Type=="Minimal"){
        x1 = gapBetween * 0;
        x2 = gapBetween * (maxThatCouldFit-1);
        xOffset = totalSpan/2 - gapBetween/2;
        translate([x1 - xOffset,0,0])
        subpart_cutout_centered();
        translate([x2 - xOffset,0,0])
        subpart_cutout_centered();
    }
    else if (Mounting_Slot_Type=="Maximum"){
        for (i=[0:maxThatCouldFit-1]){
            x = gapBetween * i;
            xOffset = totalSpan/2 - gapBetween/2;
            translate([x - xOffset,0,0])
            subpart_cutout_centered();
        }
    }

    //Single centered cutout
    module subpart_cutout_centered(){
        translate([0,-(mount_depth-eps),-eps])
        rotate([0,0,180])
        part_mount(type="socket", chuteLength=chuteLength);
    }
}

// Create a square bin with rounded front corners
module part_roundedBin(){
    //Walls
    wallThickness = RoundedBin_WallThickness;
    //Corners
    cornerRound = RoundedBin_CornerRoundness;
    //Interior measurements
    int_x = RoundedBin_Interior_X;
    int_y = RoundedBin_Interior_Y;
    int_z = RoundedBin_Interior_Z;
    //Exterior measurements
    ext_x = int_x + wallThickness*2;
    ext_y = int_y + wallThickness*2 + mount_depth;
    ext_z = int_z + wallThickness;
    //Mounting cutout additional length
    chuteLength = ext_z - mount_length - Mount_Slot_Top_Dist;
    //Sections counts (adds dividers if >1)
    dividersL2R = RoundedBin_Sections_L2R - 1;
    dividersF2B = RoundedBin_Sections_F2B - 1;

    union(){
        // Create bin with cutouts for its mounts and container
        difference(){
            //Exterior of body
            translate([0,-(ext_y/2),0])
            linear_extrude(ext_z)
            subpart_2dRoundedSquare([ext_x, ext_y]);
            //Interior Cutout of body
            translate([0,-(mount_depth+wallThickness),wallThickness]) //position within exterior shape
            translate([0,-(int_y/2),0]) //align to edge
            linear_extrude(int_z+eps)
            subpart_2dRoundedSquare([int_x, int_y]);
            //Mounting cutouts
            part_mountingCutouts(int_x, chuteLength);
        }
        // Add Left-to-Right dividers, if any
        if (dividersL2R > 0){
            for (i=[0:dividersL2R-1]){
                span = int_x;
                distPer = span/(dividersL2R+1);
                x = distPer * i;
                y = -(int_y/2 + wallThickness + mount_depth);
                z = wallThickness;
                xOffset = span/2 - distPer;
                translate([x-xOffset,y,z])
                subpart_divider(wallThickness, int_y);
            }
        }
        // Add Front-to-Back dividers, if any
        if (dividersF2B > 0){
            for (i=[0:dividersF2B-1]){
                span = int_y;
                distPer = span/(dividersF2B+1);
                x = 0;
                y = -(wallThickness + mount_depth + span/2) - (distPer * i);
                z = wallThickness;
                yOffset = -(span/2 - distPer);
                translate([x,y-yOffset,z])
                subpart_divider(int_x, wallThickness);
            }
        }
    }

    //Square with 2 corners rounded
    module subpart_2dRoundedSquare(size){
        difference(){
            //MainShape
            square([size.x, size.y], center=true);
            //Right corner cutout
            translate([size.x/2-cornerRound,-(size.y/2-cornerRound),0])
            subpart_2dCornerRounder();
            //Left corner cutout
            translate([-(size.x/2-cornerRound),-(size.y/2-cornerRound),0])
            rotate([0,0,-90])
            subpart_2dCornerRounder();
        }
    }
    //Shape used to round corners of a square
    module subpart_2dCornerRounder(){
        r = cornerRound+eps;
        difference(){
            mirror([0,-1,0])
            square([r,r]);
            circle(r=r);
            square([r,r]);
            mirror([-1,0,0])
            square([r,r]);
            mirror([-1,-1,0])
            square([r,r]);
        }
    }
    //Divider, used for L2R or F2B
    module subpart_divider(x,y){
        linear_extrude(int_z)
        square([x,y], center=true);
    }
}

// Create a square bin with rounded front corners
module part_scraper(){
    //Walls
    wallThickness = Scraper_WallThickness;
    //Corners
    cornerRound = Scraper_WallThickness;
    //Interior measurements
    int_x = Scraper_Interior_X;
    int_y = Scraper_Interior_Y;
    int_z = Scraper_Interior_Z;
    //Exterior measurements
    ext_x = int_x + wallThickness*2;
    ext_y = int_y + wallThickness*2 + mount_depth + Scraper_Extra_Y;
    ext_z = int_z;
    //Mounting cutout additional length
    chuteLength = ext_z - mount_length - Mount_Slot_Top_Dist;

    //Create body
    union(){
        difference(){
            //Exterior of body
            translate([0,-(ext_y/2),0])
            linear_extrude(ext_z)
            subpart_2dRoundedSquare([ext_x, ext_y]);
            //Interior Cutout of body
            translate([0,-(Scraper_Extra_Y),0]) //position extra Y
            translate([0,-(mount_depth+wallThickness),-eps/2]) //position within exterior shape
            translate([0,-(int_y/2),0]) //align to edge
            linear_extrude(int_z+eps)
            square([int_x, int_y], center=true);
            //Mounting cutouts
            part_mountingCutouts(int_x, chuteLength);
        }
    }

    //Square with 2 corners rounded
    module subpart_2dRoundedSquare(size){
        difference(){
            //MainShape
            square([size.x, size.y], center=true);
            //Right corner cutout
            translate([size.x/2-cornerRound,-(size.y/2-cornerRound),0])
            subpart_2dCornerRounder();
            //Left corner cutout
            translate([-(size.x/2-cornerRound),-(size.y/2-cornerRound),0])
            rotate([0,0,-90])
            subpart_2dCornerRounder();
        }
    }
    //Shape used to round corners of a square
    module subpart_2dCornerRounder(){
        r = cornerRound+eps;
        difference(){
            mirror([0,-1,0])
            square([r,r]);
            circle(r=r);
            square([r,r]);
            mirror([-1,0,0])
            square([r,r]);
            mirror([-1,-1,0])
            square([r,r]);
        }
    }
}

// Create a single hook
module part_hook(){
    //Walls, used around the mounting slot area
    wallThickness = 2;
    //Hook
    retainerThickness = Hook_RetainerThickness;
    hook_wide = Hook_Thickness;
    hook_deep_flat = Hook_FlatLength;
    hook_deep_withEnd = hook_deep_flat + retainerThickness;
    hook_tall = hook_deep_withEnd;
    //Mount
    mount_x = max(mount_width_wide + (wallThickness*2), hook_wide);
    mount_y = mount_depth + wallThickness;
    mount_z = max(mount_length + wallThickness, hook_tall);
    //Mounting cutout additional length
    chuteLength = mount_z - mount_length - Mount_Slot_Top_Dist;

    union(){
        difference(){
            //Body that surrounds mount
            translate([0,-(mount_y/2),0])
            linear_extrude(mount_z)
            square([mount_x, mount_y], center=true);
            //Mounting cutouts
            part_mountingCutouts(mount_x, chuteLength);
        }
        //Hook
        translate([0, -mount_y, 0])
        subpart_hook();
    }

    module subpart_hook(){
        //Position the hook so it is aligned to 0
        translate([hook_wide/2,0,0])
        rotate([-90,0,0])
        rotate([0,-90,0])
        translate([-hook_deep_withEnd,-hook_tall,0])
        union(){
            // Body of hook
            hull(){
                //cirle at front of hook
                linear_extrude(hook_wide)
                translate([retainerThickness/2, retainerThickness/2,0])
                circle(d=retainerThickness);
                //Surface where the hook meets the mounting plate
                linear_extrude(hook_wide)
                translate([hook_deep_withEnd,0,0])
                square([0.001, hook_tall]);
            }
            // Retainer at end of hook
            hull(){

                //cirle at front of hook
                linear_extrude(hook_wide)
                translate([retainerThickness/2, retainerThickness/2,0])
                circle(d=retainerThickness);
                //cirle at the tip of the retainer
                linear_extrude(hook_wide)
                translate([retainerThickness/2, -retainerThickness/2,0])
                circle(d=retainerThickness);
            }
        }
    }
}

// Create a single hook
module part_twinHook(){
    //Walls, used around the mounting slot area
    wallThickness = 2;
    //Gap between the hooks
    gap = TwinHook_Gap;
    //Hook
    retainerThickness = TwinHook_RetainerThickness;
    hook_wide = TwinHook_Thickness;
    hook_deep_flat = TwinHook_FlatLength;
    hook_deep_withEnd = hook_deep_flat + retainerThickness;
    hook_tall = hook_deep_withEnd;
    //Mount
    mount_x = max(mount_width_wide + (wallThickness*2), hook_wide*2 + gap);
    mount_y = mount_depth + wallThickness;
    mount_z = max(mount_length + wallThickness, hook_tall);
    //Mounting cutout additional length
    chuteLength = mount_z - mount_length - Mount_Slot_Top_Dist;

    union(){
        difference(){
            //Body that surrounds mount
            translate([0,-(mount_y/2),0])
            linear_extrude(mount_z)
            square([mount_x, mount_y], center=true);
            //Mounting cutouts
            part_mountingCutouts(mount_x, chuteLength);
        }
        //Hook L
        translate([-(hook_wide/2 + gap/2), -mount_y, 0])
        subpart_hook();
        //Hook R
        translate([(hook_wide/2 + gap/2), -mount_y, 0])
        subpart_hook();
    }

    module subpart_hook(){
        //Position the hook so it is aligned to 0
        translate([hook_wide/2,0,0])
        rotate([-90,0,0])
        rotate([0,-90,0])
        translate([-hook_deep_withEnd,-hook_tall,0])
        union(){
            // Body of hook
            hull(){
                //cirle at front of hook
                linear_extrude(hook_wide)
                translate([retainerThickness/2, retainerThickness/2,0])
                circle(d=retainerThickness);
                //Surface where the hook meets the mounting plate
                linear_extrude(hook_wide)
                translate([hook_deep_withEnd,0,0])
                square([0.001, hook_tall]);
            }
            // Retainer at end of hook
            hull(){

                //cirle at front of hook
                linear_extrude(hook_wide)
                translate([retainerThickness/2, retainerThickness/2,0])
                circle(d=retainerThickness);
                //cirle at the tip of the retainer
                linear_extrude(hook_wide)
                translate([retainerThickness/2, -retainerThickness/2,0])
                circle(d=retainerThickness);
            }
        }
    }
}

// Create a steel sheet holder
module part_steelSheetHolder(){
    //How many slots there will be
    howMany = SSH_HowMany;
    //Walls, used around the mounting slot area
    wallThickness = 4;
    //Roundness of corners
    cornerRound = 5;
    //Mount sizing
    mount_x = mount_width_wide + (wallThickness*2);
    mount_y = mount_depth + wallThickness;
    mount_z = mount_length + wallThickness;
    //Mounting cutout additional length
    chuteLength = mount_z - mount_length - Mount_Slot_Top_Dist;
    //Extra distance to place the first slot out from
    extra_y = (howMany-1) * (wallThickness + SSH_Thickness);
    //Sheet holder (same size as mount)
    ext_x = mount_x;
    ext_y = mount_y + extra_y + cornerRound + wallThickness;
    ext_z = mount_z;
    //Slot for sheet in sheet holder
    int_x = ext_x+eps;
    int_y = SSH_Thickness;
    int_z = ext_z-wallThickness;

    //Create body
    union(){
        difference(){
            //Exterior of body
            translate([0,-(ext_y/2),0])
            linear_extrude(ext_z)
            subpart_2dRoundedSquare([ext_x, ext_y]);
            //Interior Cutout of body
            for (i=[0:howMany-1]){
                translate([0,(wallThickness+SSH_Thickness) * i,0])
                subpart_slot();
            }
            //Mounting cutouts
            part_mountingCutouts(int_x, chuteLength);
        }
    }

    //Create and place cutout slot
    module subpart_slot(){
        translate([0,-(extra_y),0]) //position extra Y
        translate([0,-(mount_depth+wallThickness),wallThickness]) //position within exterior shape
        translate([0,-(int_y/2),0]) //align to edge
        linear_extrude(int_z+eps)
        square([int_x, int_y], center=true);
    }
    //Square with 2 corners rounded
    module subpart_2dRoundedSquare(size){
        difference(){
            //MainShape
            square([size.x, size.y], center=true);
            //Right corner cutout
            translate([size.x/2-cornerRound,-(size.y/2-cornerRound),0])
            subpart_2dCornerRounder();
            //Left corner cutout
            translate([-(size.x/2-cornerRound),-(size.y/2-cornerRound),0])
            rotate([0,0,-90])
            subpart_2dCornerRounder();
        }
    }
    //Shape used to round corners of a square
    module subpart_2dCornerRounder(){
        r = cornerRound+eps;
        difference(){
            mirror([0,-1,0])
            square([r,r]);
            circle(r=r);
            square([r,r]);
            mirror([-1,0,0])
            square([r,r]);
            mirror([-1,-1,0])
            square([r,r]);
        }
    }
}

```


[User]
I'm looking to get a parametric 18650 battery box designed. I really like the style and functionality of this battery box for AA cells I found on Thingiverse, by a user named flummer, but I need it for 18650 batteries. Here's a breakdown of what I'm hoping to achieve:

**Core Functionality & Dimensions**

The design should be a box capable of holding a user-specified number of 18650 cells. Key dimensions for the 18650 are:

*   **Battery Length:**  65.1 mm (I'll need to account for contact length)
*   **Battery Width (including padding):** 18.21 mm
*   **Contact Length:**  A user-definable parameter (default to 2mm)
*   **Cell Count:** User defined, obviously!

**Key Features & Style**

I really like the style of flummer's box, so here are the features I would like to recreate:

*   **Rounded Edges:**  The design should have rounded edges on the box itself, especially on the top and sides. I am looking for something similar to what the `edge()` module does in flummer's design.
*   **Battery Cradles:** Each battery should have a cylindrical cradle to hold it securely.
*   **Spring Cutouts:**  There need to be cutouts at each end of the battery compartment for springs to make contact with the battery terminals.
*   **Solder Flange Cutouts:**  Cutouts are needed for soldering wires or tabs to the battery contacts.
*   **Polarity Markings:**  There should be "+" and "-" markings on the box, close to the terminals. I'd like them both on the top and the bottom.
*   **Mounting Flanges:** The box needs mounting flanges that protrude out from the sides, with holes for screws.
*   **Bottom Cutouts for Cell Connections:**  For multi-cell boxes, there should be cutouts on the bottom of the box connecting the battery cells for series connections.
*   **Bottom Cutouts for Output Wires:**  There needs to be a dedicated cutout on the bottom for output wires at both ends of the battery holder.
*   **Cutout to Ease Battery Removal:** I think the large cutout to ease battery removal is a nice touch that I'd like to keep as well.
*   **Parametric:** Everything needs to be parametric, so that I can easily change battery length, contact length, cell count, and mounting hole locations.

I'm not super picky about the exact dimensions of every feature – if you need to make some assumptions, that's okay, but the battery dimensions themselves are critical. I'm looking for a clean design that prints well and is functional. I also want to make sure that there is a library function `edge()` as shown in the original file.

I am _not_ asking you to improve upon already-existing code, I want you to make the code from scratch so I can evaluate its unique structure.

Could you create a parametric OpenSCAD file for this?

[Assistant]
battery_box_18650.scad:
```
/*
 * Variables for Thingiverse Customizer
 * ==================================================================
 *
 */

// The number of 18650 cells in your battery holder
Cell_Count = 2;

// The overall length of the contacts and battery
Contact_Length = 2;
Battery_Length = 65.1;

// The overall width of the battery, including padding
Battery_Width = 18.21;

/*
 * Library function: edge
 * ==================================================================
 *
 * Used to make roundes edges on objects
 *
 */
module edge(radius, height)
{
	difference()
	{
		translate([radius/2-0.5, radius/2-0.5, 0])
			cube([radius+1, radius+1, height], center = true);

		translate([radius, radius, 0])
			cylinder(h = height+1, r1 = radius, r2 = radius, center = true, $fn = 100);
	}
}

module battery_box(cells)
{
    cavity_length = Battery_Length + Contact_Length * 2;
    cavity_width = Battery_Width;

	difference()
	{
		union()
		{
			translate([0, 0, 10/2])
				cube(size=[cavity_length+8+8, cavity_width*cells, 10], center=true);

			translate([cavity_length/2+7+2/2, 0, 20/2])
				cube(size=[2, cavity_width*cells, 20], center=true);

			translate([-(cavity_length/2+7+2/2), 0, 20/2])
				cube(size=[2, cavity_width*cells, 20], center=true);

			translate([-(cavity_length/2+7-3/2), 0, 11.5/2+10/2])
				cube(size=[3, cavity_width*cells, 11.5], center=true);

			translate([(cavity_length/2+7-3/2), 0, 11.5/2+10/2])
				cube(size=[3, cavity_width*cells, 11.5], center=true);

			// mounting flanges
			translate([20, cells*cavity_width/2+4/2, 3/2])
				cube(size=[7, 4, 3], center=true);

			translate([20, cells*cavity_width/2+4, 3/2])
				cylinder(r=7/2, h=3, center=true, $fn = 60);

			translate([-20, cells*cavity_width/2+4/2, 3/2])
				cube(size=[7, 4, 3], center=true);

			translate([-20, cells*cavity_width/2+4, 3/2])
				cylinder(r=7/2, h=3, center=true, $fn = 60);

			translate([20, -(cells*cavity_width/2+4/2), 3/2])
				cube(size=[7, 4, 3], center=true);

			translate([20, -(cells*cavity_width/2+4), 3/2])
				cylinder(r=7/2, h=3, center=true, $fn = 60);

			translate([-20, -(cells*cavity_width/2+4/2), 3/2])
				cube(size=[7, 4, 3], center=true);

			translate([-20, -(cells*cavity_width/2+4), 3/2])
				cylinder(r=7/2, h=3, center=true, $fn = 60);
		}

		for (i=[0:cells-1])
		{
			// battery cradle
			translate([0, -cells*cavity_width/2+cavity_width/2+cavity_width*i, cavity_width/2+10/2])
			rotate(90, [0, 1, 0])
				cylinder(r=cavity_width/2, h=cavity_length+4+4, center=true, $fn = 100);

			// spring cut-out
			translate([cavity_length/2+7-1/2, -cells*cavity_width/2+cavity_width/2+cavity_width*i, cavity_width/2+10/2])
				cube(size=[1, 5.5, 30], center=true);

			translate([cavity_length/2+7-1.4/2, -cells*cavity_width/2+cavity_width/2+cavity_width*i, 11.5/2+10/2])
				cube(size=[1.4, 10.5, 11.6], center=true);

			translate([-(cavity_length/2+7-1/2), -cells*cavity_width/2+cavity_width/2+cavity_width*i, cavity_width/2+10/2])
				cube(size=[1, 5.5, 30], center=true);

			translate([-(cavity_length/2+7-1.4/2), -cells*cavity_width/2+cavity_width/2+cavity_width*i, 11.5/2+10/2])
				cube(size=[1.4, 10.5, 11.6], center=true);

			// solder flange cut-out
			translate([(cavity_length/2+7-7/2), -cells*cavity_width/2+cavity_width/2+cavity_width*i, 3/2])
				cube(size=[7, 5.5, 3.1], center=true);

			translate([(cavity_length/2), -cells*cavity_width/2+cavity_width/2+cavity_width*i, 3/2])
				cylinder(r=5.5/2, h=3.1, center=true, $fn = cavity_length);

			translate([-(cavity_length/2+7-7/2), -cells*cavity_width/2+cavity_width/2+cavity_width*i, 3/2])
				cube(size=[7, 5.5, 3.1], center=true);

			translate([-(cavity_length/2), -cells*cavity_width/2+cavity_width/2+cavity_width*i, 3/2])
				cylinder(r=5.5/2, h=3.1, center=true, $fn = cavity_length);

			// polarity marking (+)
			translate([20, -cells*cavity_width/2+cavity_width/2+cavity_width*i, 4/2+4.5])
				cube(size=[6, 2, 4], center=true);

			translate([20, -cells*cavity_width/2+cavity_width/2+cavity_width*i, 4/2+4.5])
				cube(size=[2, 6, 4], center=true);

			// polarity marking (-)
			translate([-20, -cells*cavity_width/2+cavity_width/2+cavity_width*i, 4/2+4.5])
				cube(size=[6, 2, 4], center=true);
		}

		if (cells>=2)
		{
			for (i=[0:cells-2])
			{
				// bottom cut-out for cell connections
				translate([0, -cells*cavity_width/2+cavity_width+cavity_width*i, 2.5/2])
				rotate(17, [0, 0, 1])
					cube(size=[cavity_length, 2, 2.6], center=true);
			}
		}

		// bottom cut-out for output wires
		translate([20, -cells*cavity_width/2+cavity_width/2+cavity_width*0, 2.5/2])
			cube(size=[cavity_length/2, 2, 2.6], center=true);

		translate([3/2, -cells*cavity_width/2+cavity_width/2+cavity_width*0+1, 2.5/2])
			edge(4, 2.6);

		translate([3/2, -cells*cavity_width/2+cavity_width/2+cavity_width*0-1, 2.5/2])
		rotate(-90, [0, 0, 1])
			edge(4, 2.6);

		translate([-40/2, -cells*cavity_width/2+cavity_width/2+cavity_width*(cells-1), 2.5/2])
			cube(size=[cavity_length/2, 2, 2.6], center=true);

		translate([-3/2, -cells*cavity_width/2+cavity_width/2+cavity_width*(cells-1)+1, 2.5/2])
		rotate(90, [0, 0, 1])
			edge(4, 2.6);

		translate([-3/2, -cells*cavity_width/2+cavity_width/2+cavity_width*(cells-1)-1, 2.5/2])
		rotate(180, [0, 0, 1])
			edge(4, 2.6);

		// bottom polarity marking (+)
		translate([7, -cells*cavity_width/2+cavity_width/2+cavity_width*0-6.0, 1.5/2])
			cube(size=[4, 1.5, 1.6], center=true);

		translate([7, -cells*cavity_width/2+cavity_width/2+cavity_width*0-6.0, 1.5/2])
			cube(size=[1.5, 4, 1.6], center=true);

		// bottom polarity marking (-)
		translate([-7, -cells*cavity_width/2+cavity_width/2+cavity_width*(cells-1)+6.0, 1.5/2])
			cube(size=[4, 1.5, 1.6], center=true);

		// mounting holes
		translate([20, cells*cavity_width/2+4, 3/2])
			cylinder(r=3.3/2, h=4, center=true, $fn = 30);

		translate([-20, cells*cavity_width/2+4, 3/2])
			cylinder(r=3.3/2, h=4, center=true, $fn = 30);

		translate([20, -(cells*cavity_width/2+4), 3/2])
			cylinder(r=3.3/2, h=4, center=true, $fn = 30);

		translate([-20, -(cells*cavity_width/2+4), 3/2])
			cylinder(r=3.3/2, h=4, center=true, $fn = 30);

		// bottom cut-out for output wire
		translate([0, 0, 2.5/2])
			cube(size=[3, cells*cavity_width+5, 2.6], center=true);

		// cutout to ease battery removal
		translate([0, 0, 20/2+10/2])
		rotate(90, [1, 0, 0])
			cylinder(r=20/2, h=cells*cavity_width+5, center=true, $fn = 100);

		// rounded corners on end plates
		translate([0, -cells*cavity_width/2, 20])
		rotate(90, [0, 1, 0])
			edge(4, cavity_length+8+8+5);

		translate([0, cells*cavity_width/2, 20])
		rotate(90, [0, 1, 0])
		rotate(-90, [0, 0, 1])
			edge(4, cavity_length+8+8+5);

		translate([0, -cells*cavity_width/2, 16.5])
		rotate(90, [0, 1, 0])
			edge(3, cavity_length+7+7);

		translate([0, cells*cavity_width/2, 16.5])
		rotate(90, [0, 1, 0])
		rotate(-90, [0, 0, 1])
			edge(3, cavity_length+7+7);
	}
}

battery_box(Cell_Count);
```


[User]
I'd like to create a set of circular fraction tiles for math learning, and I'd like them to be parametric so I can easily generate different fractions. I envision having two main parts: a receptacle (a base with a slightly raised edge) and the fraction pieces themselves that fit inside.

The receptacle should be a circular disk with a shallow well in the center, a raised lip around the well, and a couple of small rectangular cutouts at the edges to create indexing notches. The fraction pieces should also be circular, fitting snugly inside the well. Each fraction piece should have a number of segments representing the denominator of the fraction, and those segments should all be equal size. The numbers "1" and the denominator should be on each fraction piece. It would be nice to have a small raynure (a groove or channel) in the center of each piece, and around the edge of the receptacle.

I would like these parameters:

*   `finesse`:  (Integer, default 100, range 10-120) controls the smoothness of the curves.
*   `taille_disque`: (Integer, default 80, range 40-300) controls the diameter of the disk.
*   `epaisseur_fond`: (Float, default 0.6, range 0.2-1.4, step 0.2) controls the thickness of the base of the receptacle.
*   `hauteur_rebord`: (Float, default 1.6, range 0.4-2.0, step 0.2) controls the height of the lip around the well.
*   `hauteur_fraction`: (Float, default 3.6, range 1.0-10.0, step 0.2) controls the height of the fraction pieces.
*   `denominateur_fraction`: (Integer, default 5, range 1-20) controls the denominator of the fraction.
*   `piece`: (String, default "tous", options ["tous", "receptacle seul", "fraction seule"]) lets me specify if I want both, just the receptacle, or just the fraction piece.

Please generate an OpenSCAD file (or files) for me, using only the built in OpenSCAD functions (no external libraries). I expect the code to be well commented and readable. It should be easy to customize via the customizer interface.

[Assistant]
fractions.scad:
```
finesse = 100; // [10:120]
taille_disque = 80; // [40:300]

epaisseur_fond = 0.6; // [0.2:0.2:1.4]
hauteur_rebord = 1.6; // [0.4:0.2:2]

hauteur_fraction = 3.6; // [1:.2:10]
denominateur_fraction = 5; // [1:1:20]

hauteur_receptacle = epaisseur_fond + hauteur_rebord;

piece = "tous"; // ["tous", "receptacle seul", "fraction seule"]

if(piece == "tous" || piece == "receptacle seul") {
	Receptacle();
}
if(piece == "tous" || piece == "fraction seule") {
	Fraction(denominateur_fraction);
}

module Receptacle() {
	difference() {
		cylinder(h=hauteur_receptacle, d=taille_disque+2, center=false, $fn=finesse);
		translate([0, 0, epaisseur_fond]) cylinder(h=hauteur_receptacle, d=taille_disque+.2, center=false, $fn=finesse);
		difference() {
			translate([0, 0, -epaisseur_fond]) cylinder(h=hauteur_receptacle+epaisseur_fond*2, d=taille_disque/1.5, center=false, $fn=finesse);
			translate([0, 0, -epaisseur_fond]) cylinder(h=hauteur_receptacle+epaisseur_fond*2, d=taille_disque/4, center=false, $fn=finesse);
		}
	}
	translate([-taille_disque/10/2, -taille_disque/2, 0])
		cube([taille_disque/10, taille_disque, epaisseur_fond], center=false);
	translate([-taille_disque/2, -taille_disque/10/2, 0])
		cube([taille_disque, taille_disque/10, epaisseur_fond], center=false);
	Raynure(0);
}

module Fraction(denominateur) {
	difference() {
		intersection() {
			translate([0, 0, epaisseur_fond]) linear_extrude(hauteur_fraction)
				union() {
					for (angleDepart = [0:90:360/denominateur]) {
						angle = 360/denominateur-angleDepart;
						if(angle > 90) {
							angle = 90;
							pCentre = [0, 0];
							pDepart = [0, taille_disque/2];
							pMilieu = [taille_disque/2, taille_disque/2];
							pFin = [sin(angle)*taille_disque/2, cos(angle)*taille_disque/2];
							rotate([0, 0, -angleDepart]) polygon([pCentre, pDepart, pMilieu, pFin]);
						} else {
							pCentre = [0, 0];
							pDepart = [0, taille_disque/2];
							pMilieu = [taille_disque/2, taille_disque/2];
							pFin = [sin(angle)*taille_disque/2, cos(angle)*taille_disque/2];
							rotate([0, 0, -angleDepart]) polygon([pCentre, pDepart, pMilieu, pFin]);
						}
					}
				}
			translate([0, 0, epaisseur_fond]) cylinder(h=hauteur_fraction, d=taille_disque-.4, center=false, $fn=finesse);
		}
		translate([0, 0, epaisseur_fond+hauteur_receptacle])
		cylinder(h=hauteur_fraction, d=taille_disque-.4-1.6, center=false, $fn=finesse);
		translate([0, 0, epaisseur_fond])
		cylinder(h = hauteur_fraction, d=taille_disque/5, center=false, $fn=finesse/2);
		translate([0, 0, epaisseur_fond])
		cube([.4, taille_disque/2, hauteur_fraction], center=false);
		Raynure(.4);
	}
	TexteFraction(denominateur);
}

module Raynure(jeu = 0) {
	difference() {
		cylinder(h=hauteur_rebord+jeu/3, d=taille_disque/1.5+jeu, center=false, $fn=finesse);
		translate([0, 0, -.5]) cylinder(h=hauteur_rebord+1, d=taille_disque/1.5-2-jeu, center=false, $fn=finesse);
	}
}

module TexteFraction(denominateur) {
	hauteur = hauteur_fraction - epaisseur_fond - hauteur_rebord;
	deltaZ = epaisseur_fond + hauteur_rebord;
	rotate([0, 0, -360/denominateur/2]) {
		translate([-1.5, taille_disque/2-7, deltaZ]) linear_extrude(hauteur) text(text = "1", size = 5);
		if(denominateur != 1) {
			translate([-1.5, taille_disque/2-7, deltaZ]) linear_extrude(hauteur) text(text = "_", size = 5);
			if(denominateur > 9) {
				translate([-3.5, taille_disque/2-14, deltaZ]) linear_extrude(hauteur) text(text = str(denominateur), size = 5);
			} else {
				translate([-1.5, taille_disque/2-14, deltaZ]) linear_extrude(hauteur) text(text = str(denominateur), size = 5);
			}
		}
	}
}
```


[User]
Hi! I'd like to create a customizable screw cap in OpenSCAD, similar to a nut cap but designed to fully enclose a bolt head and any protruding threaded part. I've got some basic parameters in mind and a rough idea of the geometry.

The cap should be cylindrical, with a hexagonal inner recess to fit over a standard hex bolt head. I want the user to specify the following:

*   `Width_across_flat`: The width across the flats of the bolt head (in mm).
*   `Bolted_height`: The height of the bolt head plus any exposed threaded part we want to cover with the cap (in mm). This will determine the depth of the inner cavity.
*   `Shell_thickness`: The thickness of the cap's outer shell (in mm). This should be consistent for the cylinder and the top.

The overall structure is like a thick-walled cylinder, with a hexagonal extrusion cut out of the bottom to form the cavity. I'd like the top of the cap to be flat, forming the top of the cylinder and enclosing the bolt.

I'd like the OpenSCAD file to be fully parametric using those parameters, so a user could easily modify them using the Customizer. I don't need any extra bells and whistles, just a good, solid, functional bolt cap. Could you please generate the necessary OpenSCAD code? Thanks!

[Assistant]
Cap_that_Nut.scad:
```
$fn=100;

//in (mm)
Width_across_flat=13; // [0:1:100]

//in (mm)
Bolted_height=15; //[0:1:300]

//in (mm)
Shell_thickness=2; //[0:1:10]

difference(){
    {
    cylinder(h=Bolted_height+Shell_thickness,
    d=Shell_thickness*2+(Width_across_flat*1.155),center=false);
    }
    translate([0,0,Shell_thickness]) cylinder(h=Bolted_height,
    d=(Width_across_flat*1.155), $fn=6, center=false);
}
```


[User]
Hi, I'm looking to create a parametric model for a shoelace, and I've got some specific requirements in mind. It's a bit more complex than just a simple extrusion.

The basic shape of the shoelace will consist of a rectangular bar with rounded ends, and it should have a slightly curved cutout along the edge of the bar that runs lengthwise on both sides. The end pieces should be rounded with a circular profile at both of the ends of the bar as well as the ends of the cutouts. I need to be able to control the overall length of this middle bar section. The ends are where the metal aglet would attach, so these should be wider and have a rectangular profile with a wider base, as well as another smaller rectangualar extrusion on the outer edge.

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

*   **`resolution`**: For curve smoothness, probably using `$fn`. This should be a settable value like 32, 64, 128 or 256.
*   **`barLengths`**: This should be a list or vector of values representing the length of the bar section in mm. I want to be able to generate multiple laces of varying lengths using a for loop with this.
*   **`barWidth`**: The width of the rectangular bar section
*   **`barThickness`**: The thickness of the bar section
*   **`endWidth`**: The overall width of the end piece
*   **`endThickness`**: The thickness of the end piece.
*   **`endBaseWidth`**: The width of the rectangular base on the end piece
*   **`endBaseThickness`**: The thickness of the rectangular base on the end piece.
*   **`endRectWidth`**: The width of the smaller rectangualr section on the end piece.
*   **`endRectThickness`**: The thickness of the smaller rectangualr section on the end piece.
*   **`curver`**: The depth of the curved cutouts. This is calculated as 3.5 - (3.5 * sin(acos(1.5/3.5))), but should be able to be set manually.

I'd like to output multiple laces with all of these parameters, each spaced appropriately. It seems like it could be done pretty easily using a for loop. I'd also like to make sure that there is a way to make the preview faster when I'm changing parameters by using the `$preview` variable to set `$fn` to 0.

I think this will require some boolean operations, specifically `difference()` to make those curved cutouts, and `union()` to make the end and bar section.

Could you generate an OpenSCAD file for this? I don't need any external libraries.

[Assistant]
shoelace.scad:
```
// curve resolution
resolution = 128; // [32,64,128,256]

// band length in mm
barLengths = [40, 45, 50, 55, 60, 65, 70];

$fn = $preview ? 0 : resolution;

module drawLace (length) {
    linear_extrude(height=2) union(){
        difference(){
            translate([0, 2, 0]) circle(r=5);
            translate([-5, 0, 0]) square([10, 7]);
        }
        translate([-1.5, 0, 0]) square([3,4]);
        translate([0, 4, 0]) difference(){
            translate([0, 3.5-curver, 0]) circle(r=3.5);
            translate([-3.5, -curver, 0]) square([7, curver]);
            translate([-3.5, 3.5-curver, 0]) square([7, 3.5]);
        }
        translate([-3.5, 4 + 3.5 - curver, 0]) square([7, length - (2 * (3.5 - curver))]);
        translate([0, 4 + length - (3.5 - curver), 0]) difference() {
            circle(r=3.5);
            translate([-3.5, -3.5, 0]) square([7, 3.5]);
            translate([-3.5, 3.5 - curver, 0]) square([7, curver]);
        }
        translate([-1.5, 4 + length, 0]) square([3, 4]);
        translate([0, 8 + length, 0]) difference() {
            translate([0, -2, 0]) circle(r=5);
            translate([-5, -7, 0]) square([10, 7]);
        }
    }
};

for(i=[0 : len(barLengths) - 1]) {
    translate([12 * i, 0, 0]) drawLace(barLengths[i]);
}
/* [hidden] */
// smaller band offset
//curver = 0.5;
curver = 3.5 - (3.5 * sin(acos(1.5/3.5)));
```


[User]
I need a parametric OpenSCAD design for a holder for LED strips, specifically the kind that are about 10mm wide and have a small lip on the edge. I want to be able to customize the dimensions, but the key feature is that the walls of the holder should always be twice the specified line width. This makes it print more consistently, even with multiple parts next to each other.

Here are the parameters I want to control:

*   `line_width`: The width of a single printed line, used to ensure wall thickness is always consistent. Default should be 0.4.
*   `led_slot_width`: The width of the slot that the LED strip will sit in. Default 10mm.
*   `led_slot_height`: The height of the slot. Default 0.8mm.
*  `led_tabs_width`: The width of the small tabs on the side that help hold the strip in. Default should be 2mm
*   `foot_angle`: The angle of the "foot" that goes down to the base, in degrees. Default should be 45.
*   `height`: The extrusion height for the holder. Default should be 100.
* `slicer_helper_notch`:  A boolean to add a small notch for the slicer to handle the 3-way joint between the foot and the led slot. Default should be true

The design should be a 2D shape that gets linearly extruded up, so everything will be a consistent height. I need the inside slot to have two tabs and a rounded corner going into the support foot. The foot also has a rounded corner where it goes to the base. I also would like to have small circles at the corners to ensure consistency between different parts of the design.

The design should use only basic OpenSCAD functions; I don't want to use any external libraries like BOSL or MCAD. It needs to be a single file.

[Assistant]
main.scad:
```
line_width = 0.4;
led_slot_width = 10;
led_slot_height = 0.8;
led_tabs_width = 2;
foot_angle = 45;
height = 100;
slicer_helper_notch = true;

module ledHolder(){
    foot_length = led_slot_width+line_width;
    foot_x = foot_length*cos(foot_angle);
    foot_y = foot_length*sin(foot_angle);
    foot_x2 = line_width*2*sin(foot_angle);
    foot_y2 = line_width*2*cos(foot_angle);
    difference(){
        union(){
            polygon([
                [0,0],
                [led_slot_width,0],
                [led_slot_width,led_slot_height],
                [led_slot_width-led_tabs_width+line_width,led_slot_height],
                [led_slot_width-led_tabs_width+line_width,led_slot_height+line_width*2],
                [led_slot_width,led_slot_height+line_width*2],
                [led_slot_width+line_width*2,led_slot_height],
                [led_slot_width+line_width*2,0], //here should be an arc
                [led_slot_width,-line_width*2],
                [0,-line_width*2],
                [foot_x, -foot_y-line_width*2],// half circle here
                [foot_x-foot_x2, -foot_y-foot_y2-line_width*2],
                [-foot_x2, -foot_y2-line_width*2],// arc here
                [-line_width*2,-line_width*2],
                [-line_width*2, led_slot_height],
                [0, led_slot_height+line_width*2],
                [led_tabs_width-line_width, led_slot_height+line_width*2],
                [led_tabs_width-line_width, led_slot_height],
                [0, led_slot_height],
                [0,0]
            ]);
            //add arcs where needed
            translate([foot_x-foot_x2/2, -foot_y-foot_y2/2-line_width*2, 0]){
                circle(line_width, $fn=64);
            };
            render(){
                translate([led_slot_width, 0, 0]){
                    intersection(){
                        circle(line_width*2, $fn=64);
                        translate([0, -line_width*2, 0]){
                            square(line_width*2);
                        };
                    };
                };
            };
            render(){
                translate([0, -line_width*2, 0]){
                    intersection(){
                        circle(line_width*2, $fn=64);
                        translate([-line_width*2, -line_width*2, 0]){
                            square(line_width*2);
                        };
                    };
                };
            };
            render(){
                translate([0, led_slot_height, 0]){
                    intersection(){
                        circle(line_width*2, $fn=64);
                        translate([-line_width*2, 0, 0]){
                            square(line_width*2);
                        };
                    };
                };
            };
            render(){
                translate([led_slot_width, led_slot_height, 0]){
                    intersection(){
                        circle(line_width*2, $fn=64);
                        translate([0, 0, 0]){
                            square(line_width*2);
                        };
                    };
                };
            };
            translate([led_slot_width-led_tabs_width+line_width, led_slot_height+line_width, 0]){
                circle(line_width, $fn=64);
            };
            translate([led_tabs_width-line_width, led_slot_height+line_width, 0]){
                circle(line_width, $fn=64);
            };
        };
        if(slicer_helper_notch){
            slice_width = (1-sqrt(3)/2)*line_width*2;
            translate([-line_width*4+slice_width, -line_width, 0]){
                circle(line_width*2, $fn=64);
            };
        };
    }
}

linear_extrude(height=height){
    ledHolder();
}

```


[User]
I'd like to design a 3D-printed air filter using a standard 120mm PC fan and a circular HEPA filter. I'll need a few parts: a fan adapter plate, a funnel to direct air from the fan to the filter, and a bottom cap to hold the filter in place.

For the fan adapter, it should have a 120mm square outline with chamfered edges, mounting holes for a standard 120mm fan (around 105.2mm diagonally), and a circular cutout for the fan's airflow (about 115mm in diameter). I'd like to be able to adjust the chamfer width, screw hole diameter, and screw hole distance via parameters.

The funnel should transition from the fan cutout down to the filter. I'd like to be able to set the height of the funnel, wall thickness, and the inner diameter of the filter opening it connects to. There will be a small plug on the filter side of the funnel for the bottom cap to press into.

The bottom cap will be in two pieces: a plug that fits inside the filter and a rim that holds the filter in place. The plug should have an adjustable height, and the rim should have adjustable height, outer diameter, and rim edge width, as well as the option to add feet and to customize foot diameter and number of feet.

I'd like all the dimensions to be fully customizable via parameters in the OpenSCAD file. Let's use a $fa of around 1.5 for the fan adapter and funnel, and $fa of 6 for the bottom cap parts. I'd like it if you could split the design into multiple files, one for the fan adapter and funnel, and a second for the bottom cap. This'll make it easier to iterate on them individually.

I'd like to minimize dependencies, so please don't use any extra libraries.

[Assistant]
FanAdapter.scad:
```
fan_size = 120;
fan_diameter = 115;

chamfer_width = 4;

screw_hole_diameter = 4.5;
screw_hole_distance = 105.2;

funnel_height = 30;
funnel_wall_thickness = 2;

filter_inner_diameter = 87.5;
plug_height = 10;

$fa = 1.5;
$fs = 1;

module ChamferedSquare(size, chamfer_width)
{
    // Constant figured out experimentally
    delta = 1.207 * chamfer_width;
    offset(delta = delta, chamfer = true) square(size - 2 * delta, center = true);
}

module Plate()
{
    difference()
    {
        ChamferedSquare(fan_size, chamfer_width);

        circle(fan_diameter / 2);

        for (i = [-1, 1])
        {
            for (j = [-1, 1])
            {
                x = i * screw_hole_distance / 2;
                y = j * screw_hole_distance / 2;
                translate([x, y])
                circle(screw_hole_diameter / 2);
            }
        }
    }
}

module Funnel()
{
    translate([0,0,plug_height])
    difference()
    {
        cylinder(h = funnel_height,
                 r1 = filter_inner_diameter / 2,
                 r2 = fan_diameter / 2 + funnel_wall_thickness);

        translate([0, 0, -0.01])
        cylinder(h = funnel_height + 0.02,
                 r1 = filter_inner_diameter / 2 - funnel_wall_thickness,
                 r2 = fan_diameter / 2);
    }

    difference() {
        cylinder(h = plug_height, r = filter_inner_diameter/2);

        translate([0, 0, -0.01])
        cylinder(h = plug_height + 0.02, r = filter_inner_diameter/2 - funnel_wall_thickness);
    }
}

mirror([0,0,1]) {
    translate([0, 0, funnel_height + plug_height])
    linear_extrude(2)
    Plate();

    Funnel();
}
```
BottomCap.scad:
```

// Which of the two parts to generate
part = "both"; // [both, plug, rim]

// The inner diameter of the filter
inner_diameter = 87.5;

// The outer diameter of the filter
outer_diameter = 131;

// Height of the plug part
plug_height = 10;

// Height of the base rim
rim_height = 1;

// Width of the rim edge to join the parts neatly
rim_edge_width = 3;

// Diameter of a foot recess
foot_diameter = 14;

// Number of feet
number_of_feet = 6;

// Height of a single print layer
print_layer_height = 0.2;

module Cone(radius, height) {
    rotate_extrude()
    polygon([[0,0],[radius,0],[0,height]]);
};

$fa = 6;

module Plug() {
    ph = plug_height + (rim_height - print_layer_height);

    translate([0,0,print_layer_height]) {
        translate([0,0,ph])
        Cone(inner_diameter/2, inner_diameter/2);

        cylinder(h = ph, r = inner_diameter/2);
    }

    cylinder(h = print_layer_height, r = inner_diameter/2 + rim_edge_width);
}

module Rim() {
    mirror([0,0,1])
    difference() {
        cylinder(h = rim_height, r = outer_diameter/2);

        translate([0,0,-0.01])
        cylinder(h = rim_height + 0.02, r = inner_diameter/2);

        translate([0,0,-0.01])
        cylinder(h = print_layer_height + 0.01, r = inner_diameter/2 + rim_edge_width);

        for(i = [0:number_of_feet-1]) {
            a = 360 * i/number_of_feet;
            r = (outer_diameter + inner_diameter)/4;
            // The 0.01 here is just for better preview render
            translate([r * cos(a), r * sin(a),-0.01])
            cylinder(h = print_layer_height + 0.01, r = foot_diameter/2);
        }
    }
}

if(part == "plug") {
    Plug();
} else if(part == "rim") {
    Rim();
} else {
    translate([-(inner_diameter/2 + rim_edge_width + 1), 0, 0])
    Plug();

    translate([outer_diameter/2 + 1, 0, 0])
    Rim();
}
```


[User]
I'd like to design a can pusher with a helical groove. I'm thinking a cylindrical body with a helical channel cut out of it that could push cans along.

The basic design would be a cylinder, and then I need to cut out the helical channel. I want to be able to specify the length of the cylinder, the overall radius of the cylinder, the radius of the helix cut, and the offset of the helix from the cylinder's surface. Also, I'd like to control the total angle of the helix, meaning I can make it a single rotation, two rotations, etc.

It would be fantastic if the OpenSCAD code could be parametric using variables, as you see above. Also, I'd like a decent level of smoothness on the helix, perhaps using $fn to control the number of facets used to create the helical groove. Please use a high enough $fn to make the design look polished when rendered, but without causing OpenSCAD to run too slowly.

I think I'd want a `Length` parameter for the length of the main cylinder, a `Pusher_Radius` for the radius of the main cylinder, a `Pusher_Helix_Radius` parameter for the radius of the helix that's being cut out, a `Pusher_Helix_Offset` for the distance the center of the helix cut is away from the main cylinder radius, and an `angle` parameter that controls the total angle of the helix. Let's start with that. I don't have any specific preference for libraries, and would rather not use any if it is not necessary.

[Assistant]
can_pusher3.scad:
```
/*
 *Helix_extrude
 */

//Length of pusher
Length = 300; //[100:10:300]
// outer radius of the pusher
Pusher_Radius = 100;
// radius of the Can
Pusher_Helix_Radius = 60;
// offset of the helix
Pusher_Helix_Offset = 25;
// Angle of helix
angle = 360 * 2;

// Can Pusher
translate([0, 0, 0]) {

	difference() {
        cylinder(h=Length, r=Pusher_Radius, center=false);
        precision = 60;

		helix_extrude(angle=angle, height=Length+(2*Pusher_Helix_Radius), $fn=precision) {
			translate([Pusher_Radius+Pusher_Helix_Offset, -(Pusher_Helix_Radius), 0]) {
				circle(r=Pusher_Helix_Radius);

			}
		}

	}
}

module helix_extrude(angle=angle, height=Length) {
	precision = $fn ? $fn : 24;

	// Thickness of polygon used to create an helix segment
	epsilon = 0.001;

	// Number of segments to create.
	nbSegments = floor(abs(angle * precision / 360));

	module helix_segment() {
		// The segment is "render" (cached) to save (a lot of) CPU cycles.
		render() {
			//   thin shape (using linear_extrude) which represent
			//   our 2D polygon.
			hull() {
				rotate([90, 0, 0])
					linear_extrude(height=epsilon) children();

				translate([0, 0, height / nbSegments])
					rotate([90, 0, angle / nbSegments])
						linear_extrude(height=epsilon) children();
			}
		}
	}

	union() {
		for (a = [0:nbSegments-1])
			translate([0, 0, height / nbSegments * a])
				rotate([0, 0, angle / nbSegments * a])
					helix_segment() children();
	}
}

```


[User]
I'm looking to create a parametric design for an omega bracket using OpenSCAD. I'd like to be able to customize the bracket's dimensions and features.

Specifically, I need to control:

*   **Material Thickness:** The thickness of the material used for the bracket.
*   **Inner Width:** The distance between the two vertical legs of the omega shape.
*   **Depth:** The depth of the bracket.
*   **Total Height:** The overall height of the bracket.
*   **Leg Width:** The width of the legs extending from the sides.
*   **Leg Hole Diameter:** The diameter of the holes in the legs.
*   **Center Hole Diameter:** The diameter of the hole in the center of the bracket.
*   **Countersunk Depth:** The depth of the countersunk on the holes.
*   **Countersunk Diameter:** The upper diameter of the countersunk.
*   **Presence of Legs:** I want to be able to optionally include or exclude the left and/or right legs.
*   **Presence of Holes:** I want to be able to optionally include or exclude the holes on the legs and the center hole.
*   **Countersunk:** I want to optionally enable or disable the countersinking of the holes.

The bracket will be essentially an omega shape, with an optional hole in each leg and a center hole on the top of the bracket. I'd like to be able to specify whether the leg holes and center holes should be countersunk. Could you generate a .scad file that implements this functionality? I don't need any external libraries used for this one, just base OpenSCAD.

[Assistant]
OmegaBracketDesigner.scad:
```
//  Omega bracket designer - customizer
//  VERSION 1.05    2024-05-18
//  der.kotti@gmail.com

/* [Enable/Disable features] */
//add left leg? Linker Schenkel?
leftLeg="yes";//[yes,no]
//add right leg? Rechter Schenkel?
rightLeg="yes";//[yes,no]
//add legs hole?  Bohrloecher?
holes="yes";// [yes,no]
//add countersunks? Senkungen?
countersunk="yes";//[yes,no]

/* [Parameters] */
//thickness of material - Materialstaerke
thickness = 10;//[1:100]
//inner width  - Innenbreite
innerWidth = 40;//[10:400]
// depth / Tiefe
depth = 20; //[2:100]
// total height - Gesamthoehe
height = 40;//[2:100]
// width of legs - Schenkelbreite
legWidth = 40;//[2:100]
//diameter of leg holes - Bohrlochdurchmesser der Schenkel
legHoleDiameter = 5;//[1:30]
//diameter of center hole - Bohrlochdurchmesser in der Mitte
centerHoleDiameter = 5;//[1:30]
//depth of countersunk - Tiefe der Senkung
countersunkDepth = 2;//[1:30]
//upper width of countersunk - Obere Breite der Senkung
countersunkDiameter = 10;//[1:30]

/* [Hidden] */

//Resolution fs
$fs=0.5;
//Resulution fa
$fa=5;

createBracket();

/* Function to create a leg */
module leg(position) {
    translate(position) {
        cube([legWidth + thickness, thickness, depth], false);
    }
}

/* Function to create a hole */
module hole(position, diameter) {
    translate(position) {
        rotate([90, 0, 0]) {
            color("red",1) cylinder(h=thickness, d=diameter, center=true);
            if (countersunk=="yes") {
                translate([0,0, (thickness-countersunkDepth) / 2]) {
                    color("green",1) cylinder(h= countersunkDepth, d1=diameter,d2= countersunkDiameter, center=true);
                }
            }
        }
    }
}

module createBracket() {
    rotate([0, 180, 90]) {
        translate([legWidth + thickness, -height, 0]) {
            difference() {
                union() {
                    // Base horizontal part
                    cube([innerWidth + 2 * thickness, thickness, depth], false);

                    // Vertical parts
                    rotate([0, 0, 90])  {
                        cube([height, thickness, depth], false);
                        translate([0, -innerWidth - 2 * thickness, 0]) {
                            cube([height, thickness, depth], false);
                        }
                    }

                    // Legs
                    if (leftLeg=="yes") {
                        leg([-legWidth - thickness, height - thickness, 0]);
                    }
                    if (rightLeg=="yes") {
                        leg([innerWidth + thickness, height - thickness, 0]);
                    }
                }

                // Leg holes
                if (holes=="yes") {
                    hole([-(legWidth / 2) - thickness, height - (thickness / 2), depth / 2], legHoleDiameter);
                    hole([innerWidth + (legWidth / 2) + 2 * thickness, height - (thickness / 2), depth / 2], legHoleDiameter);
                    hole([(innerWidth + thickness) / 2  , thickness / 2, depth / 2], centerHoleDiameter);
                }
            }
        }
    }
}
```


[User]
Hey, I'm trying to design a parametric keyboard case and key plate generator in OpenSCAD, and I'm having a little trouble figuring out the best way to approach it from scratch. I’d like it to be relatively flexible, so I can easily create different sized macro pads or even small keyboard cases.

Essentially, I want to be able to specify the number of columns and rows, the size of the key switch cutouts, and other dimensions and have it generate the 3D model. I’m picturing a two part design with a base and a lid that fit together. I also want to be able to choose whether or not there’s a cutout for a USB-C port on the back, though that’s not a huge priority.

Here’s what I’m thinking in terms of parameters I would like to be able to change:

*   **`columns`**: Number of columns of keys.
*   **`rows`**: Number of rows of keys.
*   **`hole_diameter`**: Diameter for screw holes.
*   **`frame_width`**: Width of the frame between key switch cutouts.
*   **`plate_thickness`**: Thickness of the key switch plate.
*   **`wall_thickness`**: Thickness of the walls of the keyboard case.
*   **`cutout_width`**: X-axis width of the key switch hole.
*   **`cutout_depth`**: Y-axis height of the key switch hole.
*    **`body_thickness`**: Z-axis height of the keyboard base.
*   **`corner_radius`**: Corner radius for the keyboard case.
*   **`post_diameter`**: Diameter of the support posts inside the base.
*   **`lid_thickness`**: Thickness of the keyboard lid.
*   **`lid_lip`**:  Distance the lip of the lid inset into the base.
*   **`lid_tolerance`**: Clearance gap for lid fitment
*   **`USB_cutter_width`**:  Width of the USB-C cutout on the back.
*    **`USB_cutter_height`**: Height of the USB-C cutout on the back.

I would want the base to have a main body with rounded corners, a recessed area for the key plate, support posts for the key plate, and screw holes for mounting the lid. The key plate itself should have cutouts for standard MX key switches. The lid would fit into the recessed area of the base with screw holes that align with the ones in the base. I'd like for the screw holes to be through the whole base and lid.

I'd also like the key plate to sit flush with the top of the case when it's assembled.

I'm not using any libraries, so please generate all the necessary code from scratch. Could you provide the necessary OpenSCAD files to achieve this? Thanks!

[Assistant]
KEEB_2x2_KeyGen_w._USB.scad:
```
//Made mostly from code blatantly stolen from BaldGuyDIY on YouTube. Thanks for doing the hard part, bro.

//Important things you may want to change.

columns = 4; //"Width" of the keyboard. 5 = 5 columns wide. **WARNING** support posts will interfere with standard USB cutout size if less than 2. You'll need to comment out the support posts (lines 145-150) and remove '+post_diameter' the USB cutout x-translate.
rows = 1; //"Height" of the keyboard. 3 = 3 rows tall.
hole_diameter = 3; //Diameter of the screw holes. Change this to suit your needs.

//FOR THE USB CUTOUT - comment out line 169-173 to get rid of the cutout

//dimensions for individual key squares and other random stuff. I don't know what I'm doing. Stop asking questions.
$fn = 100;
frame_width = 5; //width of the frame rails between key switch cutouts
plate_thickness = 3.5; //Thickness of the key switch plate
wall_thickness = 4 ; //How thick do you want the walls of your keyboard to be? Is this thick enough for you?
cutout_width = 14 ; //X Axis width of the key switch hole
cutout_depth = 14 ; //Y Axis height of key switch hole
key_width = cutout_width + frame_width + wall_thickness/2; //Adds space around the key switch cutouts
key_depth = cutout_depth + frame_width + wall_thickness/2; //Adds space around the key switch cutouts
body_thickness = 30; // This is the Z Axis height of the keyboard
cylinder_rad = 1.5; // *Should* determine the corner radius of the enclosure
cylinder_height = body_thickness; //gfy
USB_cutter_width = 13; //this affects the width of the cablet cutout rectangle on the back of the keeb
USB_cutter_height = 4;//this affects the height of the cablet cutout rectangle on the back of el keeberino

//Extra parameters I might need but probably not so they'll sit right here until I do some cleaning up. Or not. Maybe I will. Maybe I won't. Maybe go stuff yourself.
corner_radius = 1; //Probably don't need this one.
post_diameter = 5; //thickness of the support posts
lid_thickness = 2;
lid_lip = 2; //to have the lid inset into the box. 0 is flush on bottom.
lid_tolerance = .25; //Clearance gap for lid fitment.

    //Module for building the body box
module posts(x, y, z, h, r){
    translate([0,0,0]){
        cylinder(r=cylinder_rad, h=body_thickness);
    }
    translate([x,y,0]){
        cylinder(r=cylinder_rad, h=body_thickness);
    }
    translate([0,y,0]){
        cylinder(r=cylinder_rad, h=body_thickness);
    }
    translate([x,0,0]){
        cylinder(r=cylinder_rad, h=body_thickness);
    }
    }
                                                    //end

    //Module for cutting the hollow in the body box
module cutters(x, y, z, h, r){
    //bottom left corner
    translate([0+wall_thickness,0+wall_thickness,z]){
        cylinder(r=cylinder_rad, h=body_thickness+plate_thickness+wall_thickness);
    }
    //top right corner
    translate([x-wall_thickness/2,y-wall_thickness/2,z]){
        cylinder(r=cylinder_rad, h=body_thickness+plate_thickness+wall_thickness);
    }
    //top left corner
    translate([0+wall_thickness,y-wall_thickness/2,z]){
        cylinder(r=cylinder_rad, h=body_thickness+plate_thickness+wall_thickness);
    }
    //bottom right corner
    translate([x-wall_thickness/2,0+wall_thickness,z]){
        cylinder(r=cylinder_rad, h=body_thickness+plate_thickness+wall_thickness);
    }
    }
                                                    //end

    //Module to build the lip inside the bottom of the enclosure
module lip(x, y, z, h, r){
    //bottom left corner
    translate([0+lid_lip,0+lid_lip,z]){
        cylinder(r=cylinder_rad, h=lid_thickness);
    }
    //top right corner
    translate([x-lid_lip-1,y-lid_lip-1,z]){
        cylinder(r=cylinder_rad, h=lid_thickness);
    }
    //top left corner
    translate([0+lid_lip,y-lid_lip-1,z]){
        cylinder(r=cylinder_rad, h=lid_thickness);
    }
    //bottom right corner
    translate([x-lid_lip-1,0+lid_lip,z]){
        cylinder(r=cylinder_rad, h=lid_thickness);
    }
    }
                                                    //end

    //Module for building the support posts inside the enclosure
module support_posts(x, y, z, h, r){
    //bottom left corner
    translate([0+wall_thickness+lid_lip,0+wall_thickness+lid_lip,z]){
        cylinder(r=post_diameter, h=body_thickness/2);
    }
    //top right corner
    translate([x-wall_thickness-lid_lip,y-wall_thickness-lid_lip,z]){
        cylinder(r=post_diameter, h=body_thickness/2);
    }
    //top left corner
    translate([0+wall_thickness+lid_lip,y-wall_thickness-lid_lip,z]){
        cylinder(r=post_diameter, h=body_thickness/2);
    }
    //bottom right corner
    translate([x-wall_thickness-lid_lip,0+wall_thickness+lid_lip,z]){
        cylinder(r=post_diameter, h=body_thickness/2);
    }
}
                                                    //end

//Module for the screw holes
module screw_holes(x, y, z, h, r){
    //bottom left corner
    translate([0+wall_thickness+lid_lip,0+wall_thickness+lid_lip,z]){
        cylinder(r=hole_diameter, h=body_thickness/2+2);
    }
    //top right corner
    translate([x-wall_thickness-lid_lip,y-wall_thickness-lid_lip,z]){
        cylinder(r=hole_diameter, h=body_thickness/2+2);
    }
    //top left corner
    translate([0+wall_thickness+lid_lip,y-wall_thickness-lid_lip,z]){
        cylinder(r=hole_diameter, h=body_thickness/2+2);
    }
    //bottom right corner
    translate([x-wall_thickness-lid_lip,0+wall_thickness+lid_lip,z]){
        cylinder(r=hole_diameter, h=body_thickness/2+2);
    }
}
                                                    //end

//build main body with USB cutout and key switch plate
union(){
    difference(){
        difference(){
        //box
            hull(){
                posts(
                    x = (key_width*columns),
                    y = (key_depth*rows),
                    z = (lid_lip),
                    r = (corner_radius));
             }
                //hollow
              hull(){
                cutters(
                    x = (key_width*columns-wall_thickness/2),
                    y = (key_depth*rows-wall_thickness/2),
                    z = -wall_thickness,
                    r = corner_radius);

              }
              //lip inside enclosure bottom
              hull(){
                lip(
                    x = (key_width*columns+lid_lip/2),
                    y = (key_depth*rows+lid_lip/2),
                    z = (-0.001),
                    h = (lid_thickness),
                    r = (corner_radius)
              );
              }
        }

            //USB cutout.
                 /* translate([key_width*columns/2-USB_cutter_width/2,key_depth*rows-3,body_thickness/4-USB_cutter_height/2]){
                    cube([USB_cutter_width,wall_thickness+4,USB_cutter_height]);*/
        }
    }
    //this is where we make a sweet-ass KEY SWITCH PLATE
    translate([0,0,body_thickness-plate_thickness])
        for(i=[0:key_depth:key_depth*rows-key_depth]){
            translate([0,i,0])
                difference(){
                // Body of key square
                    for(i=[0:key_width:key_width*columns-key_width]){
                        translate([i,0,0])
                            difference(){
                                cube([key_width, key_depth, plate_thickness]);
                //Cutout for key switch
                    translate([frame_width/2+1,frame_width/2+1,-1])
                    cube([cutout_width, cutout_depth, plate_thickness +2]);
                    }
                }
            }
        }
                                                    //end

//support posts
difference(){
support_posts(
        x = (key_width*columns),
        y = (key_depth*rows),
        z = lid_thickness,
        r = post_diameter);
screw_holes(
        x = (key_width*columns),
        y = (key_depth*rows),
        z = lid_thickness-1,
        r = hole_diameter);
}
                                                    //end

//lid (on the bottom)
module lid(x, y, z, h, r){
    //bottom left corner
    translate([0+lid_lip+lid_tolerance,0+lid_lip+lid_tolerance,z]){
        cylinder(r=cylinder_rad, h=lid_thickness);
    }
    //top right corner
    translate([x-lid_lip-1-lid_tolerance,y-lid_lip-1-lid_tolerance,z]){
        cylinder(r=cylinder_rad, h=lid_thickness);
    }
    //top left corner
    translate([0+lid_lip+lid_tolerance,y-lid_lip-1-lid_tolerance,z]){
        cylinder(r=cylinder_rad, h=lid_thickness);
    }
    //bottom right corner
    translate([x-lid_lip-1-lid_tolerance,0+lid_lip+lid_tolerance,z]){
        cylinder(r=cylinder_rad, h=lid_thickness);
    }
    }
                                                    //end

//lid and screw holes
   difference(){
    //lid body
   hull(){
     lid(
        x = (key_width*columns+lid_lip/2),
        y = (key_depth*rows+lid_lip/2),
        z = (-5),
        h = (lid_thickness),
        r = (corner_radius));
    }

   //screw holes in the lid
    screw_holes(
        x = (key_width*columns),
        y = (key_depth*rows),
        z = -10,
        h = (lid_thickness),
        r = hole_diameter+1);
}
    //end
                                                    //end
```


[User]
Okay, I'm looking to design a bumper wheel for a robot, and I'd like an OpenSCAD file for it. The wheel itself is cylindrical, and it's got a thicker, softer outer layer for the actual bumping. I need to be able to control several things with parameters, like the overall diameter of the wheel, the width, the size of the axle hole, and the thickness of the outer bumper layer. I'm thinking of using a `linear_extrude` and `rotate_extrude` for the outer layer, if that's a good idea, to make it really easy to customize the surface pattern. I'm currently imagining a simple "lines" pattern for the outer surface, but I'd like the flexibility to have different patterns in the future.

Here's a more detailed breakdown of what I need:

*   **Overall Wheel:** This needs to be a cylinder.
*   **Bumper Layer:** This is a layer of softer material around the wheel itself. I'll need to control its thickness.
*   **Axle Hole:** I need a central hole for an axle. I should be able to control its size.
*   **Parameters:**
    *   `Wheelsize`: The overall diameter of the wheel.
    *   `Wheelwidth`: The width of the wheel.
    *   `Axlesize`: The diameter of the axle hole.
    *   `Tyresurfacethickness`: The thickness of the outer bumper layer.
    *   `Tyresurfacekind`: A variable that lets me chose the kind of pattern to use for the outer bumper.
*   **Module:** I'd like a "Tyre" module that represents the core of the wheel with an axle hole, and a "TyreSurface" module that makes the outer surface of the wheel. The user could then chose which parts of the wheel to render (the core, the surface, or both).
*   **Default pattern:** When `Tyresurfacekind` is set to "lines" the bumper surface should be textured with thin lines running around the wheel. The spacing of these lines should be variable, so that can be added as a parameter. Let's start with a spacing of 5mm for now.
*   **Module calls:** I need the file to iterate over an array, called `modules`, and to call a `select()` module. For now, `modules = [0,1]`, and that module should call `Tyre()` if `m=0`, and call `TyreSurface()` if `m=1`. This might sound a little strange, but I'm trying to make the most modular and flexible file possible. It should also call "module2", "module3", and "module4". These modules don't need to do anything right now, they're placeholders for future functionality.

I'd also like the `TyreSurface` to be colored black.

I'm not requesting that you use any particular libraries. Can you help me with this?

[Assistant]
bumperwheel2.scad:
```
// Diameter of the BumperWheel
Wheelsize = 100;
// Width of the Bumperwheel
Wheelwidth = 60;
// Size of the bearing Axle
Axlesize = 20;
// Thickness of the Bumper Surface
Tyresurfacethickness = 5;
// Tipe of Bumper Surface
Tyresurfacekind = "lines";
// choose which part to render
modules = [0,1];

module Tyre() {
    Wheeldiam = Wheelsize/2;
    echo("Tyre");
difference() {
 	cylinder (h = Wheelwidth, r=Wheeldiam-Tyresurfacethickness, center = true, $fn=100);
 	translate([0,0,-1]) cylinder (h = Wheelwidth+3, r=Axlesize, center = true, $fn=100);
 }
 }

 module TyreSurface() {
     Wheeldiam = Wheelsize/2;
     echo("TyreSurface");
difference() {
    color ("Black")
 	cylinder (h = Wheelwidth+1, r=Wheeldiam, center = true, $fn=100);
 	translate([0,0,-1]) cylinder (h = Wheelwidth+4, r=Wheeldiam-Tyresurfacethickness, center = true, $fn=100);
 }
 }

for(m = modules) {
    select(m) {
        Tyre();
        TyreSurface();
        module2();
        module3();
        module4();
    }
}
module select(m) {
    children(m);
}

// your modules

module module2() {
    echo("module 2");
}

module module3() {
    echo("module 3");
}

module module4() {
    echo("module 4");
}

```


[User]
Hey, I'm looking to design a customizable funnel in OpenSCAD and need some help. I've already got a basic idea, but I need the ability to adjust a bunch of parameters and maybe some extra features.

Here's what I'm thinking:

**Basic Funnel Shape:**

*   It should have a top cylindrical part, a conical middle, and a cylindrical stem at the bottom.
*   I need to be able to control the outside diameter of the top cylinder, its height, the outside diameter at the bottom of the cone (where it meets the stem), and the height of the cone itself.
*   Then, I need to control the bottom stem's outside diameter and height.
*   All parts will have the same wall thickness.
*   I want a variable, $fn, to control the number of segments used in the cylinders and cones.

**Optional Hanging Tab:**

*   I would like to add an optional hanging tab to the top.
*   The tab should be a rectangle coming off the side, ending in a semi-circle on the outside edge.
*   I'd need to be able to control the width of the rectangular part of the tab, the total length (from the funnel edge to the center of the hole) and the diameter of the hole at the end for hanging.
*   I'd also like to be able to turn the tab on or off, not just by setting width to zero.

**Optional Collar:**

*   I want to add an optional collar around the stem.
*   The collar should sit on top of the bottle.
*   I need to specify the inside diameter (the outside diameter of the bottle) and how far down it comes from the bottom of the cone.
*   I'd also like to be able to turn this on or off.

I think that's everything. The parameters for each of these are listed again below with some variable names that I'd prefer.

**Parameters:**

*   `top_upper_diameter`: Top cylinder outer diameter.
*   `top_untapered_height`: Height of the top cylinder.
*  `top_lower_diameter`: Cone bottom outer diameter.
*   `top_height`: Height of the cone.
*   `bottom_lower_diameter`: Bottom stem outer diameter.
*   `bottom_height`: Height of the bottom stem.
*   `thickness`: Wall thickness for the whole thing.
*   `do_tab`: Boolean, true to add the tab.
*  `tab_width`: Width of the tab.
*   `tab_length`: Length of the tab from the edge of the main body to the center of the hole.
*   `tab_hole`: Diameter of the tab hole.
*  `do_collar`: Boolean, true to add the collar.
*   `collar_inside_diameter`: Collar inside diameter.
*   `collar_recess`: Recess of the collar, the distance it extends down from the bottom of the cone.
*   `$fn`: Number of segments for the curves.

Could you generate the OpenSCAD code for this? I don't need any fancy libraries. Thanks!

[Assistant]
basic-funnel.scad:
```
// Basic Funnel, optional hanging tab and collar

// rlb408 2024-05

/*[Basic Funnel Parameters - top part]*/

// Top portion outside diameter at the very top
top_upper_diameter = 90;

// Untapered height on the very top
top_untapered_height = 15;

// Top portion outside diameter at the bottom of the cone
top_lower_diameter = 20;

// Height of the top tapered portion
top_height = 50;

/*[Basic Funnel Parameters - bottom (stem) part]*/

// Top outside diameter, bottom of the cone
bottom_lower_diameter = 16;

// Height of the top portion
bottom_height = 30;

/*[Common parameters]*/

// Thickness of the sides
thickness = 2.4;

/*[Optional tab for hanging]*/

// Do a tab on the top for hanging on a hook?
do_tab = true;

// Optional tab width, set to zero turns off the tab
tab_width = 20;

// Tab length, to the center of the hole
tab_length = 16;

// Diameter of the hole in the tab
tab_hole = 6;

/*[Collar parameters]*/

// Do an optional collar for setting on top of a bottle?
do_collar = true;

// Inside diameter of the collar (outside diameter of the top of the bottle). Set to zero for no collar.
collar_inside_diameter = 0;

// Recess in the collar bottom, for setting securely on top of the bottle
collar_recess = 6;

/*[Miscellaneous parameters]*/

// Segments in circles.  Set really small (4-8) for cool polygonal funnels)
$fn = 100;

module __Customizer_Limit__ () {}

e = 0.05;
e2 = e*2;

// Outer shell of a cone
//   phase == 0 -- the whole cone, hollowed out
//   phase == 1 -- the outer shape
//   phase == 2 -- the inner shape

module cone(phase=0,top,bottom,h,t)
{
    difference() {
        if ( phase == 0 || phase == 1 ) cylinder(d1=bottom, d2=top, h=h);
        if ( phase == 0 || phase == 2 ) {
            translate([0,0,-e])
            cylinder(d1=bottom-2*thickness, d2=top-2*thickness, h=h+e2);
        }
    }
}

// The basic funnel shape
//    phase ... see "cone" above

module shape(phase)
{
    cone(phase=phase,top=top_upper_diameter, bottom=top_upper_diameter, h=top_untapered_height, t=thickness);
    translate([0,0,top_untapered_height]) {
        cone(phase=phase,top=top_lower_diameter, bottom=top_upper_diameter, h=top_height, t=thickness);
        translate([0,0,top_height]) {
            cone(phase=phase,top=bottom_lower_diameter, bottom=top_lower_diameter, h=bottom_height, t=thickness);
        }
    }
}

// Tab on the funnel
//  Same "phase" arg as above, only 1 and 2 supported

module tab(phase)
{
    if ( do_tab ) {
        mirror([1,0,0]) // so that thingiverse images show the tab
        if ( phase==1 ) {
            translate([0,-tab_width/2,0])
            cube([top_upper_diameter/2+tab_length,tab_width,thickness]);
            translate([top_upper_diameter/2+tab_length,0,0]) cylinder(d=tab_width,h=thickness, $fn=60);
        } else if (phase==2) {
            translate([top_upper_diameter/2+tab_length,0,-e]) cylinder(d=tab_hole,h=thickness+e2, $fn=60);
        }
    }
}

// Collar on the funnel
//  Same "phase" arg as above, only 1 and 2 supported

module collar(phase )
{
    if ( do_collar ) {
        if ( phase==1 ) {
            cylinder(d=2*thickness+collar_inside_diameter,h=top_untapered_height+top_height+collar_recess);
        } else if ( phase==2 ) {
            translate([0,0,top_untapered_height+top_height])
                cylinder(d=collar_inside_diameter, h=bottom_height);
        }
    }
}

difference() {
    union() {
        shape(1);
        tab(1);
        difference() {
            collar(1);
            collar(2);
        }
    }
    shape(2);
    tab(2);
}

```


[User]
Hey, I'm looking for help designing a customizable storage box for my wife's cosmetics. I've got some dimensions that seem to work well for various sized items, and I want to be able to easily change the size of the box and still have all the features I like.

The basic idea is a rectangular box with rounded corners and a handle on one of the short sides (that's the "front" for these). I also want some circular holes cut out of the sides, mainly for aesthetic purposes, but they do help see what's inside. The handle should be a cutout, not a separate piece, and should be made with a couple of circles joined by a hull and then extruded.

Here's a breakdown of what I'm looking for:

**Overall Box:**

*   **Parametric Dimensions:** I need to be able to control the width, height, and depth of the box using variables.
*   **Wall Thickness:**  The wall thickness needs to be variable as well.
*   **Rounded Corners:**  All the corners of the box need to be rounded; I was using small spheres for the rounding with hulling.
*   **Open Top:** The top of the box should be open to allow access.

**Handle:**

*   **Placement:** The handle is located on the front face (width x height) of the box, and it should be centered along the width but offset a bit from the top.
*   **Shape:**  It should be formed by creating two circles, joining them using `hull()`, and then extruding the shape through the depth of the box.
*   **Size:** I need a variable to control the height of the circular parts of the handle and a margin variable to position the circles. The width between the circular parts should be calculated based on the box width and other handle dimensions.

**Side Holes:**

*   **Shape:** Circular holes evenly spaced out across the depth and height of the side walls.
*   **Size:**  I need to be able to control the diameter of these circles.
*   **Spacing:** The spacing between the holes is also important, and needs to be parametric.
*   **Placement:** The holes should not be flush to the outside of the box, they should be inset from the sides. Also, they should be aligned such that they aren't split by the sides.

Could you generate an OpenSCAD file (or files) for this design? I don't use any special libraries at the moment, so if you use any, make sure to mention them. Let me know if you have any questions.

[Assistant]
organizer.scad:
```
/** [ Dimensions ] **/
// Box width (mm)
width = 90;
// Box height (mm)
height = 100;
// Box depth (mm)
depth = 270;

// Wall thickness (mm)
wall = 3;

/** [Hidden] **/
handle_height = 25;
handle_margin = 8;
handle_width = width - handle_margin*2 - handle_height;
corner_width = 2;

module handle(width, depth, height) {
    offset_x = handle_height/2 + handle_margin;
    offset_y = height - handle_margin - handle_height/2;
    offset_z = -depth-wall;

    rotate([90, 0, 0])
    translate([offset_x, offset_y, offset_z])
    linear_extrude(height=depth+3*wall)
    hull() {
        circle(d=handle_height);
        translate([handle_width, 0, 0])
            circle(d=handle_height);
    }
}

module decoration(width, depth, height) {
    decor_diameter = 12;
    spacing = 4;

    // Avoid half circles
    inner_depth = depth - 2*wall;
    inner_height = height - 2*wall;

    cols = floor((inner_depth)/ (decor_diameter+spacing));
    rows = floor((inner_height-spacing)/ (decor_diameter+spacing));

    yused = (cols*decor_diameter + (cols-1)*spacing);
    zused = (rows*decor_diameter + (rows-1)*spacing);

    // Center the decoration with an added offset
    yoffset = (inner_depth  - yused)/2 - spacing;
    zoffset = (inner_height - zused)/2 - spacing;

    union() {
        for(y = [1:cols]) {
            for (z = [1:rows]) {
                translate([
                    -wall,
                    yoffset + y*decor_diameter + (y-1)*spacing,
                    zoffset + z*decor_diameter + (z-1)*spacing
                ])
                //cube([width+2*t, decor_diameter, decor_diameter]);
                rotate([0, 90, 0])
                cylinder(h=width+2*wall, d=decor_diameter, center=false, $fn=36);
            }
        }
    }
}

module corner() {
    sphere(r=corner_width, $fn=8);
}

module filleted_cube(width, depth, height) {
    x = width - 2*corner_width;
    y = depth - 2*corner_width;
    z = height - 2*corner_width;

    translate([corner_width, corner_width, corner_width])
    hull() {
        // front face
        translate([0, 0, 0]) corner();
        translate([x, 0, 0]) corner();
        translate([x, 0, z]) corner();
        translate([0, 0, z]) corner();
        // back face
        translate([0, y, 0]) corner();
        translate([x, y, 0]) corner();
        translate([x, y, z]) corner();
        translate([0, y, z]) corner();
    }
}

module box(width, depth, height) {
    delta = 2*wall;
    difference() {
        difference() {
            // Outer
            filleted_cube(width, depth, height);
            // -Inner
            translate([wall, wall, wall])
                filleted_cube(width-delta, depth-delta, height-wall+corner_width);
        }
        // -Handle
        handle(width, depth, height);
        // Decoration
        decoration(width, depth, height);
    }
}

echo("Generating box", width, "x", height, "x", depth, "\n");
box(width, depth, height);

```


[User]
Okay, I need to design a test piece for figuring out the best hole size to use for threading bolts directly into 3D prints. I want a parametric design that lets me easily adjust the hole sizes, number of holes, and the spacing between them.

Here’s what I’m envisioning:

*   **Basic Shape:** A rectangular block, the thickness of which I want to be able to set parametrically.
*   **Holes:** A series of cylindrical holes running through the block. The holes should increase in size incrementally, and I need to control:
    *   The number of holes
    *   The starting diameter of the smallest hole
    *   The increment between hole sizes
    *   The minimum gap between holes

*   **Orientation:** I need to be able to choose whether the holes are arranged vertically (along the length of the block) or horizontally (across the width). I guess if there are multiple horizontal rows it would stack them along the length, but all of those holes should be the same diameter within a given row.
*   **Text Labels:** Each hole should have its diameter printed next to it as text, so I know which one I'm testing, and there should be a "bottom" label on the bottom face of the block, so I can always orient myself. I will probably want a specific font to make it look good.
*   **Parametric Control:** I want to be able to change all of these values easily through parameters in the customizer.

For libraries, I think just the standard OpenSCAD functions are fine. I don't anticipate needing anything special.

Could you generate the OpenSCAD files for this? I'm thinking it would be good to have all the configurable parameters at the top of the file as variables.

[Assistant]
hole_tester.scad:
```
num_holes=11;
// minimum hole diameter
min_d = 1.5;
// how much to increment hole size by
step = 0.1;
// minimum space between holes
min_gap=2;
font="Arial Narrow:style=Bold";
// orientation of the holes
orientation = "vertical"; // [vertical,horizontal]
vertical=(orientation == "vertical");
// thickness of the block in mm
h = 6;

max_d = min_d+(num_holes-1)*step;
gap = min_gap+max_d;

l = gap*(num_holes+1.5);
font_size=gap*0.4;

xrot = vertical ? 0 : 90;

/* [Hidden] */
$fn = 120;

difference(){

rotate([xrot, 0, 0])
difference(){
  translate([-gap*3/4, -gap*3/4,-h/2])
  cube([l, gap*2.5, h]);
  for (i = [0:num_holes-1]){
    d=min_d+i*step;
    translate([i*5,0,0]){
    cylinder(h=h*2+1,d=d, center=true);
    translate([0, gap, h/2])
    linear_extrude(2, center=true)
    text(str(d), size=font_size, font=font, halign="center", valign="center");
    }
  }
}

translate([l/2-gap*3/4,vertical ? gap : 0,-h/2])
rotate([180,0,0])
#linear_extrude(2, center=true)
    text("bottom", size=gap, font=font, halign="center", valign="center");

}
```