[User]
Hi, I'm looking for an OpenSCAD design for a bearing that can be used to stack two filament spools, which will then act as parts trays. I've already got the parts trays and stand designed, but I need this bearing to make them work. It needs to be fully parametric so that I can customize it to fit different spool sizes.

Here are the key requirements:

**General Structure:**

*   The bearing will sit between two spools. The bottom spool sits directly on the build plate, with the top spool placed above it on the bearing.
*   The design should include a rotating inner race that supports the top spool, and a stationary outer race that sits on the bottom spool.

**Parameters (all in millimeters):**

*   **Build Plate:**
    *   `X_Dimension`: Build plate width.
    *   `Y_Dimension`: Build plate depth.
*   **Spool Dimensions:**
    *   `Top_Spool_Height`: The height of the top spool measured at the inner diameter.
    *   `Top_Spool_Inner_Diameter`: The inner diameter of the top spool.
    *   `Bottom_Spool_Height`: The height of the bottom spool measured at the inner diameter.
    *   `Bottom_Spool_Inner_Diameter`: The inner diameter of the bottom spool.
*   **Bearing Specific:**
    *   `Wall_Thickness`: Thickness of all walls except for the tray and bearing.
    *   `Top_Spool_Tray`: Extra width added to the top of the bearing to hold the top spool.
    *   `Tray_Thickness`: Thickness of the tray that supports the top spool.
    *   `Spool_Gap`: The gap between the bottom spool and the top spool tray.
    *   `Race_Gap`: The gap between the inner and outer bearing race to allow for smooth rotation.
    *   `Bearing_Height`: The height of the bearing itself.
*   **Supports:**
    *   `Center_Supports`: Number of vertical supports between the top and bottom.
    *   `Bottom_Inside_Supports`: Number of supports inside the bottom spool sleeve originating from the build plate.
    *   `Bottom_Outside_Supports`: Number of supports outside the bottom spool sleeve originating from the build plate.
    *   `Support_Width`: Width of the supports.
    *   `Horizontal_Support_Gap`: Gap between supports and vertical walls to allow for easy removal.
    *   `Vertical_Support_Gap`: Gap between supports and layers above/below them.

**Functional Requirements:**

*   The bearing should have a smooth inner race that will allow the top tray to turn easily.
*   The design must be robust enough to support the weight of a full spool.
*   The design should be optimized for print time, meaning supports should be kept to a minimum.
*   The design should be adaptable to different heights, if the top spool has a different height than the bottom spool.

**Modules:**

I'd like the design to include modular components like:

*   `bearing_radius()`: Create the inner bearing race radius.
*   `inner_race()`: Creates the inner race of the bearing.
*   `outer_race()`: Creates the outer, stationary race of the bearing.
*   `bottom_sleeve()`: Create the cylindrical sleeve section of the bottom spool.
*   `spool_gap()`: Create the gap between the bottom spool and tray.
*   `tray()`: Create the tray that supports the top spool.
*    `top_sleeve()`: Creates the cylindrical sleeve section of the top spool.
*   `bearing_support()`: Adds supports under the bearing.
*   `center_supports()`: Adds supports between the bottom and top.
*   `bottom_outside_supports()`: Adds supports outside the bottom sleeve.
*   `bottom_inside_supports()`: Adds supports inside the bottom sleeve.
    *   `top_inside_supports()`: Adds supports inside the top sleeve.
    *   `top_outside_supports()`: Adds supports outside the top sleeve.

**Library:**

* I need this to use the `build_plate.scad` library.

I know it's a lot, but I think it will result in a useful and flexible design. Thanks so much!

[Assistant]
Bearing.scad:
```
////////NOTES///////

///////////INCLUDES/////////

include<utils/build_plate.scad>

//////////PARAMETERS////////////

/*[Build Plate Specifications]*/

//Build plate X dimension in mm.
X_Dimension=220;
//Build plate Y dimension in mm.
Y_Dimension=220;

/*[Spool Measurements]*/

//Total height of the top spool in mm, measured at the inner diameter.
Top_Spool_Height=60.3;
//Diameter of the hole in the middle of the top spool, measured in mm.
Top_Spool_Inner_Diameter=57.6;
//Total height of the bottom spool in mm, measured at the inner diameter.
Bottom_Spool_Height=60.3;
//Diameter of the hole in the middle of the bottom spool, measured in mm.
Bottom_Spool_Inner_Diameter=57.6;

/*[Hidden]*/

Build_Plate=3;
Bottom_Spool_Radius=Bottom_Spool_Inner_Diameter/2;
Bottom_Spool_Sleeve=Bottom_Spool_Height/2;
Top_Spool_Radius=Top_Spool_Inner_Diameter/2;
Top_Spool_Sleeve=Top_Spool_Height/2;
Bearing_Diameter=Bottom_Spool_Radius*.5;

$fn=360;

/*[Additional Specifications]*/

//Thickness of every wall except the the tray and bearing, measured in mm.
Wall_Thickness=2;
//Extra width added to hold the top spool, measured in mm.
Top_Spool_Tray=10;
//Thickness of the tray that supports the top spool, measured in mm.
Tray_Thickness=2;
//Gap between the bottom spool and the tray that supports the top spool, measured in mm.
Spool_Gap=3;
//A gap in the bearing to allow for movement, measured in mm.
Race_Gap=.5; //[.1:.05:.5]
//Height of the bearing, measured in mm.
Bearing_Height=10;

/*[Supports]*/

//Number of supports that hold the bottom tray away from the top tray.
Center_Supports=10;
//Number of supports inside the sleeve that originate on the build plate.
Bottom_Inside_Supports=8;
//Number of supports outside the sleeve that originate on the build plate.
Bottom_Outside_Supports=15;
//Width of the supports in mm.
Support_Width=.96;
//Distance between the bottom supports and the vertical walls to allow for easy removal. Measured in mm.
Horizontal_Support_Gap=.5;
//Distance between all supports and the layers above and/or below them. Should be a multiple of your layer height. Measured in mm.
Vertical_Support_Gap=.3;

//////////MODULES//////////////
module bearing_radius(diameter=Bearing_Height){ //Inner Race Radius
    translate([(Bearing_Height+Bearing_Diameter)/2,Bearing_Height/2,0])
        circle(d=diameter);
}
module inner_race(){
    union(){
        square([(Bearing_Height+Bearing_Diameter)/2,Bearing_Height]);
        bearing_radius();
    }
}
module outer_race(){
    difference(){
        square([Bottom_Spool_Inner_Diameter/2,Bearing_Height]);
        union(){
            square([Race_Gap,Bearing_Height]);
            translate([Race_Gap,-Race_Gap,0])
            scale([1,Race_Gap/(Bearing_Height/2)+1,1])
                inner_race();
                bearing_radius();
        }
    }
}

module bottom_sleeve(){
    translate([Bottom_Spool_Radius-Wall_Thickness,0,0])
        square([Wall_Thickness,Bottom_Spool_Sleeve]);
}

module spool_gap(){
    translate([(Bearing_Height+Bearing_Diameter)/2-Wall_Thickness,-Spool_Gap,0])
        square([Wall_Thickness,Spool_Gap]);
}

module tray(){
    translate([0,-Spool_Gap-Tray_Thickness,0])
        square([Top_Spool_Radius+Top_Spool_Tray,Tray_Thickness]);
}

module top_sleeve(){
    translate([Top_Spool_Radius-Wall_Thickness,-Spool_Gap-Top_Spool_Sleeve-Tray_Thickness,0])
        square([Wall_Thickness,Top_Spool_Sleeve]);
}

module bearing_support(){
    for(s=[0:1:Bearing_Diameter/2]){
        rotate([0,0,s*360/(Bearing_Diameter/2)]){
            translate([0,0,-Spool_Gap])
                cube([(Bearing_Height+Bearing_Diameter)/2-Wall_Thickness,Support_Width,Spool_Gap]);
        }
    }
}

module center_supports(){
    for(s=[0:1:Center_Supports]){
        rotate([0,0,s*360/Center_Supports]){
            difference(){
                translate([0,0,-Spool_Gap+Vertical_Support_Gap])
                    cube([Bottom_Spool_Radius,Support_Width,Spool_Gap-Vertical_Support_Gap*2]);
                translate([0,-.5,-Spool_Gap])
                    cube([(Bearing_Height+Bearing_Diameter)/2+Wall_Thickness,Support_Width+1,Spool_Gap+1]);
            }
        }
    }
}

module bottom_outside_supports(){
    for(s=[0:1:Bottom_Outside_Supports]){
        rotate([0,0,s*360/Bottom_Outside_Supports]){
            translate([Top_Spool_Radius+Horizontal_Support_Gap,0,-Top_Spool_Sleeve-Spool_Gap-Tray_Thickness])
                cube([Top_Spool_Tray-Horizontal_Support_Gap,Support_Width,Top_Spool_Sleeve-Vertical_Support_Gap]);
        }
    }
}

module bottom_inside_supports(){
    for(s=[0:1:Bottom_Inside_Supports]){
        rotate([0,0,s*360/Bottom_Inside_Supports]){
            translate([0,0,-Top_Spool_Sleeve-Spool_Gap-Tray_Thickness])
                cube([Top_Spool_Radius-Wall_Thickness-Horizontal_Support_Gap,Support_Width,Top_Spool_Sleeve-Vertical_Support_Gap]);
        }
    }
}

module top_inside_supports(){
    for(s=[0:1:Bottom_Inside_Supports]){
        rotate([0,0,s*360/Bottom_Inside_Supports]){
            translate([0,0,-Bottom_Spool_Sleeve])
                cube([Bottom_Spool_Radius-Wall_Thickness-Horizontal_Support_Gap,Support_Width,Bottom_Spool_Sleeve-Vertical_Support_Gap-Bearing_Height]);
        }
    }
}

module top_outside_supports(){
    for(s=[0:1:Bottom_Outside_Supports]){
        rotate([0,0,s*360/Bottom_Outside_Supports]){
            translate([Bottom_Spool_Radius+Horizontal_Support_Gap,0,-Bottom_Spool_Sleeve])
                cube([Bottom_Spool_Sleeve-Horizontal_Support_Gap,Support_Width,Bottom_Spool_Sleeve+Spool_Gap-Vertical_Support_Gap]);
        }
    }
}

/*module top_outside_supports(){
    for(s=[0:1:Bottom_Outside_Supports]){
        rotate([0,0,s*360/Bottom_Outside_Supports])
    }
}*/

//////////RENDERS//////////////

build_plate(Build_Plate,X_Dimension,Y_Dimension);

if (Top_Spool_Sleeve<=Bottom_Spool_Sleeve+Spool_Gap){
    translate([0,0,Spool_Gap+Bottom_Spool_Sleeve+Tray_Thickness]){
        union(){
            rotate_extrude(){
                inner_race();
                outer_race();
                bottom_sleeve();
                spool_gap();
                tray();
                top_sleeve();
            }
            bearing_support();
            center_supports();
            bottom_inside_supports();
            bottom_outside_supports();
        }
    }
}
else {
    translate([0,0,Bottom_Spool_Sleeve]){
        union(){
            rotate_extrude(){
                rotate([180,0,0]){
                    inner_race();
                    outer_race();
                    bottom_sleeve();
                    spool_gap();
                    tray();
                    top_sleeve();
                }
            }
            rotate([180,0,0]){
                bearing_support();
                center_supports();
            }
            top_inside_supports();
            top_outside_supports();
        }
    }
}

//////////GAUGES///////////////

/*
//Bearing height
color("blue")
    %cube([.5,Bearing_Height,.5]);
//Bottom Spool Sleeve Width
color("red")
    *cube([Bottom_Spool_Radius,.5,.5]);
//Bottom Spool Sleeve Height
color("green")
translate([Bottom_Spool_Radius,0,0])
    %cube([.5,Bottom_Spool_Sleeve,.5]);
//Top Spool Sleeve Height
color("orange")
translate([Top_Spool_Radius-Wall_Thickness,-Spool_Gap-Top_Spool_Sleeve-Tray_Thickness,0])
    %cube([.5,Top_Spool_Sleeve,.5]);
//Race Gap
color("purple")
translate([Bearing_Height+Bearing_Diameter/2,Bearing_Height/2-.25,0])
    %cube([Race_Gap,.5,5]);

*/

```


[User]
Hey, I'm looking to create a parametric peg solitaire game, but for marbles instead of pegs, like I used to play with as a kid. I've got a basic idea, and I even found an existing OpenSCAD file (Peg_Solitaire_For_Marbles_v1.01.scad) that gets the general idea across, but I'd like something built from the ground up, and maybe with a few improvements.

Here's what I'm thinking:

**Core Functionality:**
*   The design should have a base with a grid of holes to hold marbles, and a groove around the perimeter of the playable area. The groove should be slightly deeper than the base.
*   The game should support both the standard English style board and the European style with four extra holes, controlled by a variable.
*   The number of holes should be dynamically generated based on the selected board style, not hard-coded as it appears to be in the attached SCAD code.

**Parameters I'd like to control:**

*   **`base_shape`**: The overall shape of the base – it should support at least "square", "octagon" and "circle".
*   **`standard_board`**: A boolean or a string to toggle between the standard and European board layout.
*   **`base_z`**: The height (thickness) of the base.
*   **`hole_d`**: The diameter of the marble/ball to be used. This should control the hole size *and* the groove width.
*   **`hole_z`**: The depth of each marble hole.
*   **`hole_spacing`**: The center-to-center distance between adjacent holes.
*   **`groove_z`**:  The depth of the groove.
*   **`groove_inner_spacing`**: Distance between the innermost hole and the edge of the groove.
*   **`groove_outer_spacing`**:  Distance from the groove to the edge of the base.
*   **`bot_cr`**: The corner radius (diameter) of the base on the bottom side.
*   **`top_cr`**: The corner radius (diameter) of the base on the top side.
*    **`rendering_fragments`**: Number of fragments for rendering smooth curves. I'm okay with it being called `$fn` internally, but it'd be good to expose this to the user in some way.

**Additional Considerations:**

*   It would be really awesome if the base size could be automatically calculated based on the other parameters rather than needing a manual `base_x`/`base_y`. The attached file had a `base_auto` variable for this. That was handy.
*   It would also be nice if the groove was generated more reliably based on the `hole_d`, `groove_inner_spacing`, and `groove_outer_spacing` params, instead of using hard-coded calculations like it appears to be doing. This would be particularly helpful for different `base_shape` options.
*   The hole generation in the provided file is a bit hard to follow, I think it could be simplified.

I'm not using any special libraries at the moment, and I'd prefer if you didn't include any unnecessary dependencies. Just standard OpenSCAD functionality would be great.

Could you generate the necessary OpenSCAD file(s) based on this? I think it should be straightforward enough if you consider the parameters and features I've outlined. Thanks!

[Assistant]
Peg_Solitaire_For_Marbles_v1.01.scad:
```
/*---------------------------------------------------------
Parametric Peg Solitaire for Marbles/ Ball Bearings.
Design by Jon Frosdick em: jon@bee53.com on 17-Jan-2019.

licenced under Creative Commons :
Attribution-NonCommercial-ShareAlike 4.0 International (CC BY-NC-SA 4.0)
http://creativecommons.org/licenses/by-nc-sa/4.0/

Basic Instructions - OpenSCAD:
1. The parameters below can be adjusted, though not all need to be.
2. make any required changes then hit F5 to view the model.
3. Press F6 to render and then export to STL.
4. Slice in your favourite software and print.
5. How to play -> https://en.wikipedia.org/wiki/Peg_solitaire

disclaimer: This is my first design with openSCAD, please excuse inefficiencies and badly named variables, I ran out of time to optimise/tidy before heading to work, I'll try to update later.

v1.01 - Modified $fn variable to try to get it playing nicely with Customizer.
v1.0 - First upload
---------------------------------------------------------*/

//CUSTOMIZER VARIABLES
//these most likely should be changed

//Select the shape of the base of the solitaire game (note: octagon is slow to render).
base_shape = "circle"; //[square, octagon, circle]

//true for standard board, false for European variant (four extra holes).
standard_board = "true"; //[true,false]

//Select a height in mm for the base, around 12 is often good enough.
base_z = 12; //[6:25]

//Select the diameter of marble/ball you're going to use, this affects the diameter of the holes and groove, I used 14mm marbles. Increase this by 1 if you want the holes a little larger than the balls/marbles.
hole_d = 14; //[6:20]

//these most likely shouldn't need to be changed
//Optionally change the depth of each hole in mm
hole_z = 5.5; //[2:10]

//distance between the centres of each hole, note: must be greater than hole_d.
hole_spacing = 22; //[6:30]

//depth of the groove.
groove_z = 6.5; //[2:20]

//distance in mm between holes and groove note some of the base shapes have naturally ocurring inner space.
groove_inner_spacing = 2.5; //[0:10]

//distance in mm between groove and outside of the board.
groove_outer_spacing = 5; //[0:10]

//corner radius (actually diamter) of base bottom corners.
bot_cr = 3; //[0:10]

//corner radius (diameter) of base top corners.
top_cr = 6; //[0:10]

//Select number of fragments for rendering. This affects smoothness of curves but increases rendering time. OpenSCAD may handle larger numbers easier than Customizer.
rendering_fragments = 24; //[16:64]
//CUSTOMIZER VARIABLES END

//---------------------------------------------------------------------------------------

$fn = rendering_fragments;

//edits below this line may break the 3d model (or quite possibly they may improve it...)
base_auto = true; //if set to true, base size is calculated from ball size and spacing [true].
base_x = groove_outer_spacing * 2 + groove_inner_spacing * 2 + hole_d * 3 + hole_spacing * 6;

if (base_shape == "square") {
    make_square_base();
} else if (base_shape == "octagon") {
    make_octagon_base();
} else if (base_shape == "circle") {
    make_circle_base();
} else {
    echo ("Error - base_shape value incorrect");
}
base_y = base_x;

module make_square_base(){
    difference(){
        //board
        hull(){
            //upper corners
            ttemp_z = base_z-top_cr/2;
            tl = top_cr/2;
            tr = base_x - tl;
            tb = tl;
            tt = base_y-tb;
            translate([tr, tt, ttemp_z]) //rt
            sphere(d=top_cr);
            translate([tl, tt, ttemp_z]) //lt
            sphere(d=top_cr);
            translate([tr, tb, ttemp_z]) //rb
            sphere(d=top_cr);
            translate([tl, tb, ttemp_z]) //lb
            sphere(d=top_cr);

            //lower corners
            temp_z = bot_cr/2;
            l = bot_cr/2;
            r = base_x - l;
            b = l;
            t = base_y-b;
            translate([r, t, temp_z]) //rt
            sphere(d=bot_cr);
            translate([l, t, temp_z]) //lt
            sphere(d=bot_cr);
            translate([r, b, temp_z]) //rb
            sphere(d=bot_cr);
            translate([l, b, temp_z]) //lb
            sphere(d=bot_cr);
        }
        make_hole_pattern(base_x/2, base_y/2);
        //groove
        gl = groove_outer_spacing + hole_d/2;
        gt = base_y - hole_d/2 - groove_outer_spacing;
        gb = groove_outer_spacing + hole_d/2;
        gr = base_x - hole_d/2 - groove_outer_spacing;
        gz = base_z - groove_z + hole_d/2;

        hull(){
            translate([gl, gt, gz])
            sphere(d = hole_d);
            translate([gl, gb, gz])
            sphere(d = hole_d);
        }
        hull(){
            translate([gl, gt, gz])
            sphere(d = hole_d);
            translate([gr, gt, gz])
            sphere(d = hole_d);
        }
        hull(){
            translate([gr, gt, gz])
            sphere(d = hole_d);
            translate([gr, gb, gz])
            sphere(d = hole_d);
        }
        hull(){
            translate([gr, gb, gz])
            sphere(d = hole_d);
            translate([gl, gb, gz])
            sphere(d = hole_d);
        }
    }
}
module make_circle_base(){
    tmpx = base_x * 1.05; //modifier as circle needs a little more space than other shapes
    echo ("Total width is ", tmpx, " mm.");

    difference(){
        //board
        translate([tmpx/2, tmpx/2, 0])
        hull(){
            //upper donut
            translate([0,0, base_z-top_cr/2])
            rotate_extrude(convexity = 10, $fn = 100)
            translate([tmpx/2-top_cr/2, 0, 0])
            circle(d = top_cr, $fn = 100);

            //lower donut
            translate([0,0, bot_cr/2])
            rotate_extrude(convexity = 10, $fn = 100)
            translate([tmpx/2-bot_cr/2, 0, 0])
            circle(d = bot_cr, $fn = 100);
        }

        make_hole_pattern(tmpx/2, tmpx/2);

        //groove
        gz = base_z - groove_z + hole_d/2;

        translate([tmpx/2, tmpx/2, gz])
        rotate_extrude(convexity = 10, $fn = 100)
        translate([tmpx/2 - bot_cr/2 - groove_outer_spacing*2, 0, 0])
        circle(d = hole_d+1, $fn = 100);
        }//difference
}

module make_octagon_base(){
    difference(){
        //board
        hull(){
            //upper corners
            trad = ((base_x-top_cr)/2) / cos(22.5);
            translate([base_x/2, base_y/2, base_z-top_cr/2])
            for (i = [22.5: 45: 337.5]){
                translate([trad * cos(i), trad * sin(i), 0])
                sphere(d=top_cr);
            }

            //lower corners
            t2rad = ((base_x-bot_cr)/2) / cos(22.5);
            translate([base_x/2, base_y/2, bot_cr/2])
            for (i = [22.5: 45: 337.5]){
                translate([t2rad * cos(i), t2rad * sin(i), 0])
                sphere(d=bot_cr);
            }
        }
        make_hole_pattern(base_x/2, base_y/2);

        //groove
        gz = base_z - groove_z + hole_d/2;
        t3rad = ((base_x-bot_cr)/2-groove_outer_spacing*2) / cos(22.5);

        for (i = [22.5: 45: 337.5]){
            translate([base_x/2, base_y/2, gz])
            hull(){
                translate([t3rad * cos(i), t3rad * sin(i), 0])
                sphere(d=hole_d);
                translate([t3rad * cos(i+45), t3rad * sin(i+45), 0])
                sphere(d=hole_d);
            }
        }
    }
}

module make_hole_pattern(xx, yy){
    //xx, yy is centre point
    tz = base_z + hole_d/2 - hole_z;
    ty = yy - (4 * hole_spacing);

    for (b = [1: 7]) {
        if (b == 1 || b == 7 ){
            make_holes(3, xx, ty + (b * hole_spacing), tz);
        } else if ((b == 2 && standard_board=="true") || (b == 6 && standard_board=="true")) {
            make_holes(3, xx, ty + (b * hole_spacing), tz);
        } else if ((b == 2 && standard_board=="false") || (b == 6 && standard_board=="false")) {
            make_holes(5, xx, ty + (b * hole_spacing), tz);
        } else {
            make_holes(7, xx, ty + (b * hole_spacing), tz);
        }
    }
}

module make_holes(qty, px, py, pz){ //px, py, pz = centre point
    start_x = px - (round(qty / 2) * hole_spacing);

    for (a = [1: qty]) {
        translate([start_x + (hole_spacing * a), py, pz])
        sphere(d=hole_d);
    }
}

```


[User]
I'd like a parametric OpenSCAD design for an alien figure. It should have a configurable and random generation mode.

In configurable mode, I want to be able to set the following parameters:

*   **Resolution:** `$fn`
*   **Body:**
    *   `radio` (radius of the body)
    *   `long_cuerpo` (height of the body)
*   **Neck:**
    *   `cuello_r` (radius of the neck)
    *   `cuello_h` (height of the neck)
*   **Eyes:**
    *   `ojos_r` (radius of the eyes)
    *   `theta_ojos` (elevation angle of the eyes, relative to the horizontal plane)
    *   `phi_ojos` (separation angle of the eyes, in the horizontal plane)
*   **Arms:**
    *   `brazos_r` (radius of the arms)
    *   `brazos_h` (length of the arms)
    *   `theta_brazos` (elevation angle of the arms, relative to the horizontal plane)
    *   `phi_brazos` (separation angle of the arms, in the horizontal plane)
*   **Legs:**
    *   `piernas_r` (radius of the legs)
    *   `piernas_h` (length of the legs)
    *   `theta_piernas` (elevation angle of the legs, relative to the horizontal plane)
    *   `phi_piernas` (separation angle of the legs, in the horizontal plane)

In random mode, the design should use random values within specific ranges for the same parameters:

*   `radio`: 30 to 50
*   `long_cuerpo`: 10 to 50
*   `cuello_r`: 9 to 12
*   `cuello_h`: 0 to 40
*   `ojos_r`: 5 to 20
*   `theta_ojos`: 45 to 90
*   `phi_ojos`: 0 to 45, then divide the result by 2
*  `brazos_r`: 10 to 20
*  `brazos_h`: 10 to 20
*  `theta_brazos`: 20 to 75
*  `phi_brazos`: 60 to 90
*  `piernas_r`: 0 to 30
*  `piernas_h`: 10 to 60
*  `theta_piernas`: 150 to 170
*  `phi_piernas`: 70 to 110

The body should be made of two hulls to get a rounded bottom and top. The neck will be a cylinder. The head will be a hull of two spheres to have a round head that blends with the neck.  The eyes, arms and legs should be spheres, and cylinders for the legs. The positions of the eyes, arms, and legs should use the spherical coordinate calculations with `phi` as the angle between the x and y axes and `theta` as the angle between the z axis and the x-y plane. Make sure the arms have small spheres attached to the end of the arms and a cylinder for legs.

Finally, the design should have a variable named `tipo` that can be set to either "configurable" or "random" to switch between the two modes.

[Assistant]
ET_rand1.scad:
```
/* Alien Configurable/Random
Version 1, Enero 2019
Escrito por Jorge Cifuentes (jorgecif at gmail dot com)*/

tipo="configurable"; //[configurable,random]

//Parametros de configuracion

//Resolution
$fn=10;
//Body radio
radio=40;
//Body height
long_cuerpo=30;

//Neck thickness
cuello_r=11;
//Neck lenght
cuello_h=30;

//Eyes size
ojos_r=10;
//Eyes elevation angle
theta_ojos=70;
//Eyes separation angle
phi_ojos=21;

//Arms thickness
brazos_r=10;
//Arms lenght
brazos_h=15;
//Arms elevation angle
theta_brazos=45;
//Arms separation angle
phi_brazos=70;

//Legs thickness
piernas_r=10;
//Arms lenght
piernas_h=30;
//Arms elevation angle
theta_piernas=160;
//Arms separation angle
phi_piernas=90;

/*
Coordenadas esfericas
phi=angulo entre x y y
theta=angulo entre z y el plano x-y - de 0 a 180
x = r*sin(theta)*cos(phi)
y = r*sin(theta)*sin(phi)
z = r*cos(theta)
*/

module alien(radio,long_cuerpo,cuello_r,cuello_h,ojos_r,theta_ojos,phi_ojos,brazos_r,brazos_h,theta_brazos,phi_brazos,piernas_r,piernas_h,theta_piernas,phi_piernas)
{
//Cuerpo
hull() {
 translate([0,0,long_cuerpo]) sphere(radio*1);
 sphere(radio*1.2);
 }

//Cuello
translate([0,0,(radio+long_cuerpo)*0.9])
cylinder(h=cuello_h,r=cuello_r);

//Cabeza
translate([0,0,radio+(cuello_h+long_cuerpo)*0.9])
hull() {
 translate([40,0,30]) sphere(radio*3/4);
 sphere(cuello_r);
 }

 //Ojos
xo = radio*sin(theta_ojos)*cos(phi_ojos);
yo = radio*sin(theta_ojos)*sin(phi_ojos);
z0 = radio*cos(theta_ojos);
translate([xo+40-cuello_r,yo+0,(z0+radio+cuello_h+30+long_cuerpo)*.9])
sphere(ojos_r);
translate([xo+40-cuello_r,(yo+0)*-1,(z0+radio+cuello_h+30+long_cuerpo)*.9])
sphere(ojos_r);

//Brazos
x = radio*sin(theta_brazos)*cos(phi_brazos);
y = radio*sin(theta_brazos)*sin(phi_brazos);
z = radio*cos(theta_brazos);
translate([x,y,z+long_cuerpo])

hull() {
 translate([brazos_h,brazos_h,brazos_h]) sphere(brazos_r);
 sphere(8);
 }
translate([x,-y,z+long_cuerpo])
hull() {
 translate([brazos_h,-1*brazos_h,brazos_h]) sphere(brazos_r);
 sphere(8);
 }
//Piernas
xp = radio*sin(theta_piernas)*cos(phi_piernas);
yp = radio*sin(theta_piernas)*sin(phi_piernas);
zp = radio*cos(theta_piernas);
translate([xp,yp,zp])
hull() {
 translate([0,15,-15]) cylinder(30,30,10);
 cylinder(8,8,8);
 }

translate([xp,-yp,zp])
hull() {
 translate([0,-15,-15]) cylinder(30,30,10);
 cylinder(8,8,8);
 }

}

module configurable_alien()
{
    alien(radio,long_cuerpo,cuello_r,cuello_h,ojos_r,theta_ojos,phi_ojos,brazos_r,brazos_h,theta_brazos,phi_brazos,piernas_r,piernas_h,theta_piernas,phi_piernas);
}

module random_alien()
{
    radio=rands(30,50,1)[0]; //40;
	long_cuerpo=rands(10,50,1)[0]; //30;
	cuello_r=rands(9,12,1)[0]; //11;
	cuello_h=rands(0,40,1)[0]; //30
	ojos_r=rands(5,20,1)[0]; //10
	theta_ojos=rands(45,90,1)[0]; //70
	phi_ojos=rands(0,45,1)[0]/2; //21
	brazos_r=rands(10,20,1)[0]; //10
	brazos_h=rands(10,20,1)[0];//30
	theta_brazos=rands(20,75,1)[0];//45
	phi_brazos=rands(60,90,1)[0]; //70
	piernas_r=rands(0,30,1)[0]; //10
	piernas_h=rands(10,60,1)[0];//30
	theta_piernas=rands(150,170,1)[0];//160
	phi_piernas=rands(70,110,1)[0];//90

	alien(radio,long_cuerpo,cuello_r,cuello_h,ojos_r,theta_ojos,phi_ojos,brazos_r,brazos_h,theta_brazos,phi_brazos,piernas_r,piernas_h,theta_piernas,phi_piernas);
}

if (tipo=="configurable")
{
    configurable_alien();
}

if (tipo=="random")
{
    random_alien();
}

```


[User]
I'd like to create a customizable stencil generator in OpenSCAD. I've been playing around with a design but it's not quite what I need. It should be able to handle multiple lines of text, let me adjust the font size and overall thickness of the stencil. Also, I want options for the outline shape, either as a convex hull around the text or a simple rectangle. The really tricky part is that I'd like to have an option to slant the text for better use with a pen but from what I understand that makes rendering really slow, so this would be an optional feature.

Here are the specific parameters I need:

*   **Text:** A string that can be split into multiple lines based on a specified separator. For example, I might enter "Line 1;Line 2;Line 3" and the script should display each on a separate line using the semicolon as a separator.
*   **Line Separator:** The string used to separate lines of text.
*   **Font Size:** An integer specifying the size of the text.
*   **Border:** An integer specifying the extra space around the text within the stencil.
*   **Height:** A floating-point value for the thickness of the stencil.
*   **Form:** A string, either "convex hull" or "rectangular", determining the overall shape of the stencil.
*   **Slanted:** A boolean flag. If true, the text is slanted.
*   The design should use the "Allerta Stencil" font. Please note this font needs to be installed to run locally.

I need the output to be a single `.scad` file. The rendering time should be reasonable for the non-slanted case.

Also, I'd like to specify these as comments in the code, to enable customization through Thingiverse's customizer, like so:

```
/* [Text] */
...
/* [Stencil] */
...
/* [Hidden] */
...
```

I'm not too concerned about the specific string manipulation functions, I'm really just interested in being able to customize the text entry from the Thingiverse customizer.

[Assistant]
custom_stencil.scad:
```
/* [Text] */

// Depending on your text, you may have to add spaces at beginning and end.
text_lines = "0 1 2;3 4 5 6;7 8 9";
//text_lines = " YOUR ;; STENCIL! ";
//text_lines = "I;am;so; CUSTOM! ";
//text_lines = "As;many;lines;as;you; want! ";
// Separator for text_lines; use something else, if you need a semicolon in your text
line_separator = ";";
fontsize = 30;

/* [Stencil] */

// Additional Border
border = 0;  // [0:30]
height = 1.5;
form = "convex hull"; // [convex hull,rectangular]

/* [Hidden] */

// Make text slanted for easier use with a pen. WARNING: causes very long rendering time!
slanted = 0;  // [0:no,1:yes]

lines = split_string(text_lines, line_separator);
rectangular = (form == "rectangular");
$fs = 0.1;
epsilon = 0.0001;
fontwidth = 0.7*fontsize;
fontheight = 1.5*fontsize;
cornerradius = fontwidth/2;

stencil();

module stencil() {
    difference() {
        stencil_body();
        if (slanted) {
            minkowski() {
                stencil_text(epsilon);
                cylinder(h=height, r1=0, r2=height/2, center=true);
            }
        } else {
            stencil_text(height);
        }
    }
}

module stencil_body() {
    minkowski() {
        hull() {
            totalwidth = max([for (line = lines) len(line)]);
            offset = 2*(border - cornerradius);
            for (i = [0:len(lines)-1]) {
                box_width = max(epsilon, (rectangular ? totalwidth : len(lines[i]))*fontwidth + offset);
                box_height = max(epsilon, fontheight + offset);
                translate([0, -i*fontheight, 0])
                    cube([box_width, box_height,height/2], center=true);
            }
        }
        cylinder(r=cornerradius, h=height/2, center=true);
    }
}

module stencil_text(height) {
    union() {
        for (i = [0:len(lines)-1]) {
            translate([0, -i*fontheight, 0])
                linear_extrude(height=height, center=true)
                text(lines[i], font="Allerta Stencil", "center", size=fontsize, valign="center", halign="center");
        }
    }
}

/*
 * NOTE: These super cool string manipulation functions are only needed,
 *       because the thingiverse customizer cannot create a form to enter
 *       a vector of strings.
 *       Anyway, it was fun implementing them =)
 */

// split a string with a given separator and return an array of sub strings
function split_string(s, separator, sub_strings=[]) =
    len(search(separator, s)) == 0
        ? concat(sub_strings, s)
        :  split_string(sub_string(s,-(len(s) - search(separator, s)[0]-1)),
                                 separator,
                                 concat(sub_strings, sub_string(s,search(separator, s)[0])));

/*
 * return sub string of given length.
 * for positive lengths, the sub string starts at the beginning of s
 * for negative lengths, the sub string is from the end of s
 */
function sub_string(s, length) =
    length > 0
        ? vector_to_string([for (i = [0:length-1]) s[i]])
        : length < 0
            ? vector_to_string([for (i = [len(s)+length:len(s)-1]) s[i]])
            : "";

// concatenate a vector of strings to a single string
function vector_to_string(v) =
    len(v) == 0
        ? ""
        : len(v) == 1
            ? v[0]
            : str(v[0], vector_to_string([for (i=[1:len(v)-1]) v[i]]));

```


[User]
I'm looking to design a customizable battery holder that can be adjusted for different battery sizes and the number of batteries it can hold. I've seen a design that does this, and I'd like to try and replicate it using OpenSCAD, but with a few changes to make it more suitable for my project.

The basic idea is that the batteries are stored in a zig-zag pattern, going up and then back down the 'layers'. So, each layer has two runs, one going up and one coming back down. Each 'run' is angled slightly. I need to be able to control the following:

*   **Battery Dimensions:** Specifically, the diameter and length of the batteries. I'd like to be able to use this for both AAA and AA batteries, so let's start with these as examples.
    *   AAA Diameter: 10.5mm, Length: 44.5mm
    *   AA Diameter: 14.5mm, Length: 50.5mm
*   **Number of Layers:** How many layers of the zig-zag we want, noting that each layer includes two runs, so it is the 'up and back' path length, this would then determine how many batteries it can hold.
*   **Run Length:** How long each angled run is. Note that there are returns at each layer, so it needs to account for these, perhaps with another parameter that accounts for the extra length these add.
*   **Part Type:** Whether it should generate a base part or a lid part - I intend to print one of each to glue together to form the final battery holder.
*   **Wall Thickness:** The thickness of the walls of the holder.
*   **Ramp Angle:** The angle of the zig-zag runs, I'm currently thinking of this in degrees from the horizontal plane.
*   **Curve Smoothness:** How smooth the curves are in the model, this can have a big effect on the render time, so I need to adjust this based on preview or final model rendering.

I need the following modules:

*   A module to generate each layer of the zig-zag, with the appropriate cutouts for the batteries and with support for the ramp angle.
*   A module to handle the rounded ends at each change in direction (where the ramp changes direction), with appropriate cutouts to maintain the battery paths.
*   A module to create a final 'hopper' section to allow for easy loading/unloading of batteries. This also needs screw holes at the back for mounting to a wall.
*   A base module for the bottom of the design, with cutouts for batteries and an opening to help with battery removal.
*   A trimming module to cut away a large section for the base or the lid, depending on the 'part type' selected.
*   A peg module to add locating pegs to the final design so the lid and base fit together properly when glued.

In terms of calculation, there are a number of trig calculations that will need to be completed to work out the appropriate offsets for the runs and the end sections. I need functions to calculate the offsets in the horizontal direction of the left side, offsets for the right side, and offsets in the vertical direction. There needs to be a function to work out the radius of the end caps and offsets to compensate for the ramp angle.

I’m fine with it not generating any code that uses a library, but if you happen to be aware of any that might help then please let me know.

[Assistant]
Customizable_Battery_Holder_r21.scad:
```
//Battery Holder Test File
//Uses trig to calculate offsets and hence should be scaleable easily

/*[Parameters]*/
//Battery Dimensions

//Battery Diameter AAA=10.5 AA=14.5
BD=10.5;
//Battery Length AAA=44.5 AA=50.5
BL=44.5;

//Holder Configuration

//Number of layers in holder - each layer is there and back
Q=6; //[1:10]

//How long to make each run - the diameter of the returns is added to this figure AAA=25 and AA=35 both work for me
L=25; //[25:200]

//Do you want a lid or a base, you need both to glue together for the final item
part=0; //[0:Base,1:Lid]

//Wall Thickness - how thick do you want the walls to be, suggest 1.5mm changing this may have odd effects
WT=1.5; //[1:0.25:3]

//Angle of ramps only tested at 5 degrees!
Ang=3; //[3:30]

//How smooth to make curves keep low for preview but make higher for final renders for nie smoot curves
$fn=25; //[25:150]

/*[Hidden]*/

//Variables - edit here to configure how you want you holder to be
W=(BL+(2*WT)+2); //Width of each run add on 2xwalls thickness and 2mm tollerance
H=(BD+(2*WT)+2); //Height of each run add 2xWall Thickness plus 2mm as above
//AAA= 10.5mm dia 44.5mm long

//Trig Calcs

function Off_HL()=(H*sin(Ang)); //Offset for LHS
function Off_HR()=((L*cos(Ang))-(H*sin(Ang))); //Offset for RHS
function Off_VL(N)=((N+1)*(L*sin(Ang)))+(N*(H*cos(Ang))); //Vert OS for LHS
function Off_VR(N)=N*((L*sin(Ang))+(H*cos(Ang))); //Vert offset for RHS to be multiplied by blocks
function R()=(H); //Radius to make joint spheres
function Drop(N)=(N*(sin(Ang)));

// Doing part
difference(){
    union(){
    for(i=[1:Q]){
        Do_Layer(i);
        Do_Sphere(i);
    }
    Do_Hopper(Q+1);
    Do_Base();
}
Trim(); //Trim off either lid or base depeding upon parameters
 }
Pegs(); //if modeling a base, add back in the pegs to use for location

//Modules

module Do_Layer(Z){
    //First layer from origin upwards
    difference(){
        translate([0,0,Off_VR((Z-1)*2)]) rotate([0,-Ang,0]) cube([L,W,H]);
        //Cut out centre
        translate([-3,WT,WT+Off_VR((Z-1)*2)-Drop(3)]) rotate([0,-Ang,0]) cube([L+6,W-(2*WT),H-(2*WT)]);

        }
    //Second layer running back to origin
    difference(){
        translate([-Off_HL(),0,Off_VL((Z*2)-1)]) rotate([0,Ang,0]) cube([L,W,H]);
        //Cut out center
    translate([-Off_HL()-1,WT,WT+Off_VL((Z*2)-1)+Drop(2)]) rotate([0,Ang,0]) cube([L+6,W-(2*WT),H-(2*WT)]);

    }
}

module Do_Sphere(X){

    if(X!=1) {
        difference(){
        translate([0,0,Off_VR((X-1)*2)]) rotate([-90,0,0]) cylinder(r=R(),h=W);
            //Carve out internals
        translate([0,WT,Off_VR((X-1)*2)]) rotate([-90,0,0]) cylinder(r=(R()-WT),h=(W-(WT*2)));

            //Clear out battery paths
         translate([-Off_HL(),WT,WT+Off_VL(((X-1)*2)-1)]) rotate([0,Ang,0]) cube([L+1,W-(WT*2),H-(WT*2)]);

            translate([-1,WT,WT+Off_VR((X-1)*2)]) rotate([0,-Ang,0]) cube([L+3,W-(2*WT),H-(2*WT)]);

        }
    translate([0,0,Off_VR((X-1)*2)]) rotate([-90,0,0]) cylinder(r=WT,h=W);
        }

    //Other side

        difference(){
    translate([Off_HR(),0,Off_VR((2*X)-1)]) rotate([-90,0,0]) cylinder(r=R(),h=W);
    //Carve out cylinder
    translate([Off_HR(),WT,Off_VR((2*X)-1)]) rotate([-90,0,0]) cylinder(r=R()-(WT),h=W-(2*WT));
                    //Clear out battery paths
         translate([-Off_HL(),WT,WT+Off_VL(((X)*2)-1)]) rotate([0,Ang,0]) cube([L+1,W-(2*WT),H-(2*WT)]);

            translate([-1,WT,WT+Off_VR((X-1)*2)]) rotate([0,-Ang,0]) cube([L+3,W-(2*WT),H-(2*WT)]);

        }
    translate([Off_HR(),0,Off_VR((2*X)-1)]) rotate([-90,0,0]) cylinder(r=WT,h=W);
}

module Do_Hopper(Z){
    //First layer from origin upwards
    difference(){
   union(){
    //Hopper Box
        translate([0,0,Off_VR((Z-1)*2)]) rotate([0,-Ang,0]) cube([L+2*R(),W,(H)]);

   }
        //Carve out main hopper
        translate([0,WT,WT+Off_VR((Z-1)*2)]) rotate([0,-Ang,0]) cube([2*R()+L,W-(2*WT),(2*(H+WT))]);

        //Add way through for batteries
        translate([-2,WT,(WT-Drop(2))+Off_VR((Z-1)*2)]) rotate([0,-Ang,0]) cube([(2*WT),W-(2*WT),H-(2*WT)]);

    //Trim back to fit wall (hopper box would othersie extend back, done for higher ramp angles)
           translate([((L+R())*cos(Ang)),-0.1,Off_VR((Z-1)*2)+((L+R())*sin(Ang))]) cube([(200*WT),W+0.2,(25*H)]);

        }
//Add back plate and screw holes for wall fixing
difference(){
     //Back section to tie to wall
        translate([((L+R())*cos(Ang))-(2*WT),0,Off_VR((Z-1)*2)+((L+R())*sin(Ang))]) cube([(2*WT),W,(1.25*H)]);

        //screw holes
        translate([((L+R())*cos(Ang))-5,(W*.66666),Off_VR((Z-1)*2)+((L+R())*sin(Ang))+(H*.75)]) rotate([0,90,0]) cylinder(r=2.5, h=20);
   translate([((L+R())*cos(Ang))-5,(W*.33333),Off_VR((Z-1)*2)+((L+R())*sin(Ang))+(H*.75)]) rotate([0,90,0]) cylinder(r=2.5, h=20);
    }
        //Connecting cylinder
            if(Z!=0) {
        difference(){
        translate([0,0,Off_VR((Z-1)*2)]) rotate([-90,0,0]) cylinder(r=R(),h=W);
            //Carve out internals
        translate([0,WT,Off_VR((Z-1)*2)]) rotate([-90,0,0]) cylinder(r=(R()-(WT+0.5)),h=(W-(WT*2)));

            //Clear out battery paths
         translate([-Off_HL(),WT,WT+Off_VL(((Z-1)*2)-1)]) rotate([0,Ang,0]) cube([L+1,W-(WT*2),H-(WT*2)]);

            translate([-1,WT,(WT+Off_VR((Z-1)*2))-Drop(1)]) rotate([0,-Ang,0]) cube([L+3,W-(2*WT),H-(2*WT)]);

        }
    translate([0,0,Off_VR((Z-1)*2)]) rotate([-90,0,0]) cylinder(r=WT,h=W);
        }
}

module Do_Base(){
    function Top_Cut()=(1.25*BD)+(3*WT); //How much top to cut away for battery removal
    function Out_Length()=R()+(3*WT)+BD; //How long to make the outlet tube so it is clear of the main body
    function Out_X()=Out_Length()*cos(Ang); //How far in X axis to move for hopper length

     //First layer from origin upwards
    difference(){
        translate([-Out_X(),0,-Drop(Out_Length())]) rotate([0,-Ang,0]) cube([Out_Length(),W,H]);
        //Cut out centre
        translate([(2*WT)-Out_X(),WT,WT-Drop((Out_Length()-(2*WT/cos(Ang))))]) rotate([0,-Ang,0]) cube([Out_Length()-(2*WT),W-(2*WT),H-(2*WT)]);

        //Cut out end at half battery diameter
        translate([-Out_X()-(H*sin(Ang)),-0.1,(H/2)-Drop(Out_Length())]) rotate([0,-Ang,0]) cube([Top_Cut()+WT,W+0.2,(H/2)]);

        //Cut out Top and sides for battery removal
        translate([-(Out_X()),WT,H-WT-Drop(Out_Length())]) rotate([0,-Ang,0]) cube([Top_Cut(),W,(3*WT)]);

        //Cut out to aid battery removal

        hull(){
            translate([-Out_Length(),(W/2),-H]) cylinder(r=(W/4), h=(H*3));
            translate([BD-Out_Length(),(W/2),-H]) cylinder(r=(W/4), h=(H*3));
        }

        }
        //Add a stand
        //Put the stand in the correct place
        difference(){
        translate([((L*cos(Ang))+R())-(2*WT)-(H*sin(Ang)),WT,-Drop(Out_Length())]) cube([(2*WT),(W-(2*WT)),((L+Out_Length())*sin(Ang))+H]);
            //recut the inner sphere to clear battery path
             //Carve out cylinder
    translate([Off_HR(),WT,Off_VR((1))]) rotate([-90,0,0]) cylinder(r=R()-(WT),h=W-(2*WT));
        }
    }

module Trim(){

//Cut off either main body (to give lid) or lid (to give body)
if((part==1)){
    translate([-(55+L),WT,-90]) cube([8*L,W,1000]);

    //use rounding cylinders as locating pegs)
     for(X=[1:Q]){
    translate([Off_HR(),0,Off_VR((2*X)-1)]) rotate([-90,0,0]) cylinder(r=WT+0.075,h=W);

        if((X!=1)){ //do not put a hole in the hopper!

    translate([0,0,Off_VR((X-1)*2)]) rotate([-90,0,0]) cylinder(r=WT+0.075,h=W);
        }
     }
    translate([0,0,Off_VR((Q)*2)]) rotate([-90,0,0]) cylinder(r=WT+0.075,h=W); //Final hole for hopper
 }

if((part==0)){
    translate([-(55+L),-1,-100]) cube([8*L,WT+1.1,1000]);
 }

translate([-(W/2.5),(W/2),H]) cylinder(r=(W/4), h=(H*Q*8));

}

module Pegs(){

if((part!=1)){
    //use rounding cylinders as locating pegs)
    for(X=[1:Q]){
    translate([Off_HR(),0,Off_VR((2*X)-1)]) rotate([-90,0,0]) cylinder(r=WT-0.075,h=W);

    if((X!=1)){ //do not put a peg in the base!
        translate([0,0,Off_VR((X-1)*2)]) rotate([-90,0,0]) cylinder(r=WT-0.075,h=W);
    }
     }
    translate([0,0,Off_VR((Q)*2)]) rotate([-90,0,0]) cylinder(r=WT-0.075,h=W); //Final hole for hopper
 }
 }

```


[User]
I'm looking to create a parametric spool holder, but I want it to double as a parts tray. I've got some specific measurements I need to be able to adjust, and I'm also aiming for something that can be printed quickly.

Here's what I'm thinking:

**Core Functionality:**
*   It needs to be able to hold a standard filament spool.
*   The spool will rest on a rotating bearing.
*   The entire assembly should sit on a base.

**Parameters I need to adjust:**

*   **Build Plate:** X and Y dimensions of the build plate (for safe printing).
*   **Spool:** Inner diameter and height of the filament spool.
*   **Base:** Diameter and thickness of the main base.
*   **Bearing:** A few of these are dependent on the Spool parameters;  specifically the inner diameter should be a fraction of the Spool Inner Diameter (Spool Inner Diameter * some fraction.5) and the height needs to be set in addition to a gap between the bearing elements.
*   **Spool Tray:** How much extra width is needed around the spool to act as a tray.
*   **Tray:** Thickness of the tray element that holds up the spool.
*  **Bearing Height:** The height of the bearing element.
* **Race Gap:** The gap between the inner and outer races of the bearing.
* **Spool Gap:** The gap between the bottom of the spool and the tray of the spool below.
*   **Wall Thickness:** The thickness of all the walls except for the tray and bearing (they have their own separate settings.)
*   **Supports:** Number of center supports, number of supports outside the bearing, width of supports, horizontal gap between support and vertical wall, vertical gap between supports and layer above/below.

**Structure:**
*   The design should have a base, a tray to hold the spool, and a bearing for the spool to rotate on. The bearing will consist of an inner and outer race with a gap.
*   There will need to be a vertical wall under the tray to keep it in place.
*   There should be supports both between the base and the tray, and also under the inner race of the bearing to keep it in place, these supports should have a variable width and gaps to allow for easy removal.
*   All of these elements should be parametric and changeable as outlined above.
*   The entire structure should be able to be mirror along the Z axis.
*  I'd like the design to be easily printable.

**Libraries:**
*   I'll need the `build_plate` module which I have been using; the module must take at least one parameter for the layer height of the first layer.

Could you generate the necessary OpenSCAD files to handle this? Let me know if you have any questions!

[Assistant]
Base.scad:
```
///////////NOTES//////////

///////////INCLUDES/////////

include<utils/build_plate.scad>

///////////PARAMETERS/////////

/*[Build Plate Specifications]*/

//Build plate X dimension in mm.
X_Dimension=220;
//Build plate Y dimension in mm.
Y_Dimension=220;

/*[Spool Measurements]*/

//Inner diameter of the spool, measured in mm.
Spool_Inner_Diameter=57.6;
//Height of the spool, measured in mm.
Spool_Height=60.5;

/*[Base Specifications]*/

//Diameter of the base, measured in mm.
Base_Diameter=100;
//Thickness of the base, measured in mm.
Base_Thickness=4;

/*[Hidden]*/

Build_Plate=3;
Spool_Radius=Spool_Inner_Diameter/2;
Spool_Sleeve=Spool_Height/2;
Bearing_Diameter=Spool_Radius*.5;

$fn=360;

/*[Additional Specifications]*/

//Extra width added to hold the spool, measured in mm.
Spool_Tray=10;
//Thickness of the tray that will hold up the spool, measured in mm.
Tray_Thickness=2;
//Height of the bearing, measured in mm.
Bearing_Height=10;
//A gap in the bearing to allow for movement, measured in mm.
Race_Gap=.25; //[.1:.05:.5]
//Gap between the bottom spool and the tray that supports the top spool, measured in mm.
Spool_Gap=3;
//Thickness of every wall except the the tray and bearing, measured in mm.
Wall_Thickness=2;

/*[Supports]*/

//Number of supports that hold the bottom tray away from the top tray.
Center_Supports=15;
//Number of supports outside the bearing that originate on the base.
Outside_Supports=20;
//Width of the supports in mm.
Support_Width=.96;
//Distance between the bottom supports and the vertical walls to allow for easy removal. Measured in mm.
Horizontal_Support_Gap=.5;
//Distance between all supports and the layers above and/or below them. Should be a multiple of your layer height. Measured in mm.
Vertical_Support_Gap=.3;

///////////MODULES///////////

module bearing_radius(diameter=Bearing_Height){ //Inner Race Radius
    translate([(Bearing_Height+Bearing_Diameter)/2,Bearing_Height/2,0])
        circle(d=diameter);
}
module inner_race(){
    union(){
        square([(Bearing_Height+Bearing_Diameter)/2,Bearing_Height]);
        bearing_radius();
    }
}
module outer_race(){
    difference(){
        square([Spool_Inner_Diameter/2,Bearing_Height]);
        union(){
            square([Race_Gap,Bearing_Height]);
            translate([Race_Gap,-Race_Gap,0])
            scale([1,Race_Gap/(Bearing_Height/2)+1,1])
                inner_race();
                bearing_radius();
        }
    }
}

module spool_gap(){
    translate([(Bearing_Height+Bearing_Diameter)/2-Wall_Thickness,-Spool_Gap,0])
        square([Wall_Thickness,Spool_Gap]);
}

module tray(){
    translate([0,-Spool_Gap-Tray_Thickness,0])
        square([Spool_Radius+Spool_Tray,Tray_Thickness]);
}

module sleeve(){
    translate([Spool_Radius-Wall_Thickness,-Spool_Gap-Spool_Sleeve-Tray_Thickness,0])
        square([Wall_Thickness,Spool_Sleeve]);
}

module base(){
    mirror([0,1,0]){
        translate([0,-Bearing_Height])
            difference(){
                square([Base_Diameter/2,Base_Thickness]);
            union(){
                square([Race_Gap,Bearing_Height]);
                translate([Race_Gap,-Race_Gap,0])
                scale([1,Race_Gap/(Bearing_Height/2)+1,1])
                    inner_race();
                    bearing_radius();
            }
        }
    }
}

module bearing_support(){
    for(s=[0:1:Bearing_Diameter/2]){
        rotate([0,0,s*360/(Bearing_Diameter/2)]){
            translate([0,0,-Spool_Gap])
                cube([(Bearing_Height+Bearing_Diameter)/2-Wall_Thickness,Support_Width,Spool_Gap]);
        }
    }
}

module center_supports(){
    for(s=[0:1:Center_Supports]){
        rotate([0,0,s*360/Center_Supports]){
            difference(){
                translate([0,0,-Spool_Gap+Vertical_Support_Gap])
                    cube([Spool_Radius,Support_Width,Spool_Gap-Vertical_Support_Gap*2]);
                translate([0,-.5,-Spool_Gap])
                    cube([(Bearing_Height+Bearing_Diameter)/2+Wall_Thickness,Support_Width+1,Spool_Gap+1]);
            }
        }
    }
}

module outside_supports(){
    for(s=[0:1:Outside_Supports]){
        rotate([0,0,s*360/Outside_Supports]){
            translate([Spool_Radius+Horizontal_Support_Gap,0,-Spool_Gap+Vertical_Support_Gap])
                cube([Spool_Tray-Horizontal_Support_Gap,Support_Width,Bearing_Height-Vertical_Support_Gap*2+Spool_Gap-Base_Thickness]);
        }
    }
}

///////////RENDERS///////////

build_plate(Build_Plate,X_Dimension,Y_Dimension);

translate([0,0,Bearing_Height]){
        mirror([0,0,1]){
            union(){
                rotate_extrude(){
                    inner_race();
                    outer_race();
                    sleeve();
                    spool_gap();
                    tray();
                    base();
                }
                bearing_support();
                center_supports();
                outside_supports();
            }
        }
    }
```


[User]
I'm looking for a way to generate corner brackets, but instead of the kind that fit inside a corner, I need ones that fit *around* an external corner. I've got an example I've been working on, which I'll provide the link to in a moment, but I'm having a bit of trouble making it fully parametric, and I'd like it to be more robust.

Basically, the bracket needs to wrap around a 90-degree corner. I need to be able to specify the thickness of the bracket walls, the length of each side, the size of the screw holes, and how far those screw holes are from the edges. It also needs to cut a triangular shape from the interior so that it fits properly around an external corner.

I want to define a screw module that has two cylinders for the head and shaft, which are used in multiple places for screw holes.

Here's what I have, and what I want to be able to control:

*   **Wall thickness:** How thick the material of the bracket is.
*   **Side length:** How far each side extends from the corner.
*   **Screw size (diameter):** The diameter of the screw shaft.
*   **Screw length:** The length of the screw (this is only for the screw hole shape).
*  **Hole adjustment factor**: The distance from sides to screw hole relative to side_length.

I'd like the code to be in OpenSCAD. It's for 3D printing, and I need the screw holes to have proper clearance. It would also be helpful to have good defaults set. I would also like to be able to generate an external bracket based on specific measurements of my object. For example: I have a box that is 100mm wide by 100mm long. The corner of that box is my reference point, and the sides of my corner bracket should be 50mm in length with the wall thickness at 3mm and a 4mm screw hole with 20mm length and a hole adjustment factor of 2.7.

I'm hoping to get this working smoothly, so anything you can do to make it easy to change all these parameters would be great. I really appreciate your help!

[Assistant]
Corner_bracket_external.scad:
```
// thickness of wall
wall_thickness = 3;
// length of sides
side_length = 50;

// metric size of flat head screws, I have a box of 4 x 20mm screws
screw = 4;
// metric length of screws
screw_length = 20;

// Distance from sides to screw hole. 3 means 1/3 of side_length
hole_adjustment_factor = 2.7;

// customizable variables end here

module screw(d, l) {
    // head
    union() {
        cylinder(h=2.3, r1=d, r2=d/2);
        cylinder(h=l, r=d/2);
    }
}

difference() {
    cube([side_length, side_length, side_length], center=false);
    // cut away edges to make triangle shape with correct wall thickness
    translate([-side_length/2, -wall_thickness, 0]) rotate([45, 0, 0])
        cube([2*side_length, 2*side_length, 2*side_length], center=false);
    translate([-wall_thickness, -side_length/2, 0]) rotate([0, -45, 0])
        cube([2*side_length, 2*side_length, 2*side_length], center=false);
    translate([0, side_length-wall_thickness, -0.1])
        rotate([0, 0, -135])
        cube([2*side_length, 2*side_length, 2*side_length], center=false);
    // create cavity within
    translate([-wall_thickness, -wall_thickness, wall_thickness])
        cube([side_length, side_length, side_length]);
    // screw holes
    translate([side_length - (side_length/hole_adjustment_factor), side_length - (side_length/hole_adjustment_factor), -0.1])
            rotate([0, 0, 0]) screw(screw, screw_length);
    translate([side_length + 0.1, side_length - (side_length/hole_adjustment_factor), (side_length/hole_adjustment_factor)])
            rotate([0, -90, 0]) screw(screw, screw_length);
    translate([side_length - (side_length/hole_adjustment_factor),side_length + 0.1 ,(side_length/hole_adjustment_factor)])
            rotate([90, 0, 0]) screw(screw, screw_length);

}

$fs=0.2;
$fa=1;

```


[User]
Okay, I'd like to design a customizable weaving loom, and I'm hoping you can help me create the OpenSCAD files for it. I've seen a few designs online, and I have a specific idea in mind.

The loom should consist of a main frame with a rectangular base, and have some additional vertical supports along the length for stability, and a 'kamm' which I think is also sometimes called a heddle bar or a reed. I'd also like a basic shuttle.

Here are the specifics for the main frame:

*   **Overall Dimensions:** The loom should have parameters for `width`, `length`, and `height` to easily adjust its size.

*   **Base Frame:** The base should be a rectangular box with a specified `supportThickness` for the walls and also the internal supports. It should have cutouts to create pegs (for the yarn) at regular intervals along the width on both sides.

*   **Internal Supports:** I need to specify the number of internal supports via a `supports` parameter. These supports should run vertically between the top and bottom of the main frame. The vertical supports should be distributed evenly along the width of the loom.

*   **Side Width:** There should be an additional `sideWidth` parameter to control how wide the sides are.

*   **Yarn Pegs:** There should be pegs that stick out along the top and bottom of the loom frame, allowing me to wrap the warp yarn around them. They should be along the length of the loom on each side, evenly spaced apart.

Now, for the other pieces:

*   **Kamm/Heddle:** The kamm should be a separate piece that has pegs or slots matching the spacing of those on the loom frame. The kamm should be as wide as the main loom area between the yarn pegs on the sides of the main frame. The kamm should also have a thickness parameter. The teeth of the comb should be rounded.

*   **Shuttle:** The shuttle should be a simple, elongated shape, rounded at the ends, maybe like a stretched capsule or similar. It should have a way to hold a bit of yarn.

I'd like to have a parameter `show` that lets me choose whether to render `all` the parts, just the `loom` frame, just the `kamm`, or just the `nadel` (shuttle).

I imagine needing to use `linear_extrude`, `cube`, `translate`, `difference`, `union`, `for`, `minkowski`, `hull`, `cylinder`, `resize`, and `circle`, but you can use any other functions you think appropriate. I don't need any external libraries for this.

[Assistant]
customizeable_loom.scad:
```
//Author M. Dietz http://www.dietzm.de
//to render with F5, edit openscad preferences to allow more than 2000 objects

// Modified Jan 2019 by Richard Bateman to make customizeable

// Height of the loom
height=20;

// Width of the loom (default 100)
width=100;

// Length of the loom (default 180)
length=180;

// Thickness of the supports in mm (default 4mm)
supportThickness=4;

// The number of supports besides the end pieces to add
supports=0;

// Width of the sides (default 12)
sideWidth=12;

// What to show/render
show="all"; // [all:All parts, loom:Just the loom, kamm:Just the kamm, nadel:Just the nadel]

// [Hidden]

yarnInset=15;
yarnCount=(width-yarnInset) / 7.9 + 0.5;

$fn=90;

if (show == "all") {
    translate([0,40,0]) loom();
    translate([0,20,0]) kamm();
    nadel();
}
else if (show == "loom") {
    loom();
}
else if (show == "kamm") {
    kamm();
}
else if (show == "nadel") {
    nadel();
}

module loom(){
    difference() {
        union() {
            difference(){
                cube([width, length, height]);
                translate([supportThickness,sideWidth,-0.1]) cube([width - supportThickness*2, length-sideWidth*2, height]);

                for (i = [1:yarnCount]){
                    #translate([i*7.9+1,-1,height-5]) cube([2,length+3,5.5]);
                }
                translate([0,length-1,0]) cube([width,5,height-2]);
                translate([0,-4,0]) cube([width,5,height-2]);
            }
            if (supports > 0) {
                for (i = [1:supports]) {
                    pieceSize = width / (supports+1);
                    curPiece = pieceSize * i - supportThickness/2;
                    //echo("Current piece:", curPiece);
                    translate([curPiece, 5, 0]) cube([supportThickness, length-10, supportThickness]);
                }
            }
        }
        translate([-1,length/2, height]) rotate([0,90,0])
            linear_extrude(height=width+2) resize([height*1.25, length-sideWidth*2]) circle(d=length-sideWidth*2);
   }
}

kammWidth = yarnCount*7.9 - 6.5;

module kamm(){
    difference(){
        minkowski() {
            cube([kammWidth, 15, 3]);
            cylinder(r=2,h=1);
        }
        for (i = [1:yarnCount]) {
            #translate([i*7.9-6.5,-3,-0.1]) cube([2.5,10,5]);
        }
    }
}

module nadel(){
    difference() {
        hull() {
            translate([0,5,0])  cylinder(r=1,h=1);
            translate([50,0,0]) cube([41,10,2]);
            translate([95,5,0])  cylinder(r=5,h=2);
        }
        hull(){
            translate([89,5,-0.1])  cylinder(r=3.5,h=2.5);
            translate([83,5,-0.1])  cylinder(r=3.5,h=2.5);
        }
    }
}
```


[User]
Hey, I'm looking for an OpenSCAD design for a dice tray, specifically for the board game Pandemic: The Cure (and its expansion Experimental Meds).  I'd like it to be parametric so I can easily adjust the number of dice it holds.

Here's what I'm thinking:

*   **Dice Holes:**  It needs to have a row of holes for dice, with the number being a parameter. The base game uses 4 holes, and the expansion uses 5, so let's make a `holes` parameter that defaults to 4 but can be changed.
*   **Card Support:** It should have a slot or ledge at the back to hold a card, like the cured disease cards in the game. The card is about 22mm wide per hole plus some buffer space, and around 43mm high.
*   **Rounded Edges:**  I'd like the edges of the tray to have a nice, rounded bevel, not sharp corners.
*   **Dice Size:**  The dice are about 13.9mm in size, with some space around each one. I think 0.25mm on all sides should be good. I'd like the total size of the hole to be calculable as `die_size + (die_buffer * 2)`, where `die_size` and `die_buffer` are configurable as well.
*   **Dimensions:** The overall size of the tray should be based on the number of holes, with some additional border space. I'd like to be able to adjust the card slot, and the outside border, separately from the hole spacing. The depth of the tray should also be a parameter.

So, the basic idea is a rectangular base with the die holes and the card support, with rounded corners. The key parameters I need are:

*   `holes` (number of dice holes, default 4)
*   `die_size` (diameter of the dice, default 13.9)
*   `die_buffer` (buffer space around the dice, default 0.25)
*   `card_width` (width of the area the card sits behind, default of 22 * holes or calculated)
*   `card_height` (height of the area the card sits behind, default 43)
*   `depth` (depth of the tray, default 5)
*   `outside_border` (size of the border around the edges of the tray, default 10)
*   `buffer` (space between holes, default calculated based on `card_width`, `outside_border` and `hole_size`.)

Could you generate that for me?

[Assistant]
Pandemic__The_Cure_Cured.scad:
```
// Number of dice holes
// 4 for regular Pandemic: The Cure
// 5 for Experimental Meds
holes = 5;

card_width = 22*holes;

card_height = 43;

die_size = 13.9;
die_buffer = 0.25;

depth = 5;

hole_size = die_size + (die_buffer * 2);

outside_border = 10;
buffer = (card_width - (outside_border * 2) - (hole_size * holes)) / (holes-1);

$fn = 100;

union() {
    difference() {
        cube([card_width, card_height, depth]);
        for (i = [0:(holes-1)]) {
            translate([outside_border + ((hole_size + buffer) * i), 10, 2])
                cube([hole_size, hole_size, depth]);
        }
        translate([-0.5, 35, 2])
            rotate([75, 0, 0])
                cube([card_width + 1, card_height, 1]);
    }

    // Bevel
    union() {
        translate([0,-depth/2,0])
            cube([card_width, depth/2, depth/2]);
        translate([card_width/2,0,depth/2])
            rotate([0, 90, 0])
                cylinder(card_width, depth/2, depth/2, true);

        translate([0,card_height,0])
            cube([card_width, depth/2, depth/2]);
        translate([card_width/2,card_height,depth/2])
            rotate([0, 90, 0])
                cylinder(card_width, depth/2, depth/2, true);
    }
}

```


[User]
Hey, I'm looking to design a rotary knob for a project, and I need some help generating the OpenSCAD code. It's a pretty specific design, but I'm hoping we can make it parametric.

Here’s what I have in mind:

**Overall Structure:** The knob will be in two main parts, a bottom and a top, that connect using M3 screws. The bottom part will have a hole for a 6mm diameter rotary encoder shaft and some spaces for M5 nuts for added weight. The top part will have screw holes for the M3 screws that connect the two parts and press-fit connections to mate with the bottom part.

**Specific Dimensions:**

*   **Shaft:**
    *   Diameter: 6.1 mm
    *   Smaller width (for a flat edge): 5.5mm
    *   Length: 10mm
    *   Total length (including the section that will be inserted): 12mm

*   **M3 Screws:**
    *   Thread Length: 17.6 mm
    *   Head Height: 2.2 mm
    *   Head Diameter: 6.5 mm
    *   Hole Diameter (for the thread): 3.8mm
    *   Tap Diameter: 2.8mm
    *   Nut diameter: 6.01mm
    *   Nut height: 2.4mm

*   **M5 Nuts:**
    *   Diameter: 8.79mm
    *  Height: 4.7mm
    *   Count: 7
    *   Rotation angle: 180 degrees

*   **Overall Knob:**
    *   Outer Diameter: This should be calculated so that the outer edge is flush with the heads of the M3 screws. (2*(M3_THREAD_LENGTH + M3_HEAD_HEIGHT) + SHAFT_DIA).
    *   Total Height: 25mm

*   **Bottom Part:**
    *   Height: SHAFT_LENGTH + 3mm
*   **Top Part:**
    *   Height: OUTER_HEIGHT - BOTTOM_HEIGHT

*   **Press-Fit:**
    *   Diameter: OUTER_DIA / 6
    *   Height: 0.75 * Top_Height
*   **Clearance:** 0.04mm should be added to all hole diameters and slots to account for tolerances.

**Other details:**

*   I'd like to have M5 nuts placed radially around a circle within the bottom part of the knob.
*   The connection between the two halves should be done with the M3 screws going into the top part and pressing against the bottom.
*   I need to be able to specify different colors for the top and bottom halves and the shaft for easier previewing.
*   I want to have a preview mode that just shows me the M3 screw and nut geometry as well as the M5 nut geometry.
*   The M3 screw holes in the top part should be tapped, meaning the holes will be smaller (using the M3 tap diameter).
* The M3 screw slots in the bottom will need to accommodate the nut to be inserted and should also be sized with clearance.
*  I'd like to use `hull` and `difference` for complex shapes as I did in my example, so that each part is a single printable item.
* I want a couple of press fit pins to connect the top and bottom pieces together for easier assembly. They should also be slightly flexible. I'd like to use a tapered design for the press fit pin. There should be two such press fit pins.
* The press fit connection in the top piece should have a corresponding channel to fit the pin, also with clearance.

I’m imagining a pretty detailed file with modules for each component (shaft, nuts, bottom, top, etc.) and then a way to assemble them all together. I'm not using any external libraries in my code. Can you help me create this?

[Assistant]
rotary_knob.scad:
```
$fs=0.5;
$fa=6;

BUILD_TYPE = "preview"; // [test, top, bottom, preview]

M3_THREAD_LENGTH = 17.6;
M3_HEAD_HEIGHT = 2.2;

SHAFT_DIA = 6.1;
SHAFT_SMALL_WIDTH = 5.5;
SHAFT_LENGTH = 10;
SHAFT_TOTAL_LENGTH = 12;

//Knob outer diameter - calculated to be flush with M3 screw head
OUTER_DIA = 2*(M3_THREAD_LENGTH + M3_HEAD_HEIGHT) + SHAFT_DIA;
OUTER_HEIGHT = 25;

M5_NUT_DIA = 8.79;

//M5_NUT_HOLE = 3.869;
M5_NUT_HEIGHT = 4.7;
M5_NUT_COUNT = 7;
M5_NUT_ROTATE = 180;

//M3_NUT_WIDTH = 5.5;
M3_NUT_DIA = 6.01;
M3_NUT_HEIGHT = 2.4;
M3_HEAD_DIA = 6.5;
M3_HOLE_DIA = 3.8;
M3_TAP_DIA = 2.8;

// length without head
M3_LENGTH = M3_THREAD_LENGTH;

BOTTOM_HEIGHT = SHAFT_LENGTH + 3;
TOP_HEIGHT = OUTER_HEIGHT - BOTTOM_HEIGHT;
PRESS_FIT_DIA = OUTER_DIA/6;
PRESS_FIT_HEIGHT = TOP_HEIGHT*0.75;

CLEARANCE = 0.04;

BOTTOM_COLOR = "green";
TOP_COLOR = "yellow";
SHAFT_COLOR = "gray";

echo("OUTER_DIA:", OUTER_DIA);

module shaft() {

  OFFSET = SHAFT_SMALL_WIDTH - (SHAFT_DIA/2);
  difference() {
   translate([0,0,SHAFT_TOTAL_LENGTH/2- (SHAFT_TOTAL_LENGTH - SHAFT_LENGTH)])
    cylinder(h=SHAFT_TOTAL_LENGTH, d=SHAFT_DIA, center=true);

  translate([OFFSET, -SHAFT_DIA/2, 0])
    cube([SHAFT_DIA, SHAFT_DIA, SHAFT_LENGTH+1]);
  }
}

module m5nut() {
  difference() {
    cylinder(h=M5_NUT_HEIGHT * (1+CLEARANCE), d=M5_NUT_DIA * (1+CLEARANCE), $fn=6, center=true);
    //cylinder(h=3*M5_NUT_HEIGHT, d=M5_NUT_HOLE, center=true);
  }

}

module m3nut_slot(h = 5*M3_NUT_HEIGHT) {

  module m3nut() {
    rotate([90,0,0])
     cylinder(h=M3_NUT_HEIGHT * (1+CLEARANCE), d=M3_NUT_DIA * (1+CLEARANCE), $fn=6, center=true);
  }

  hull() {
    translate([0,0,h]) m3nut();
    m3nut();
  }

}

function sinr(x) = sin(180 * x / PI);
function cosr(x) = cos(180 * x / PI);

module m5nuts()
{

  n = M5_NUT_COUNT;
  dia = OUTER_DIA/1.5;
  r = dia/2;

  delta = (2*PI)/n;
  rotate([0,0,M5_NUT_ROTATE])
    for (step = [0:n-1]) {
      translate([r * cosr(step*delta), r * sinr(step*delta), 0])
        m5nut();
    }

}

module m3mounts(h=3*OUTER_HEIGHT, d=M3_HOLE_DIA) {

  n = M5_NUT_COUNT;
  dia = OUTER_DIA/1.5;
  r = dia/2;

  delta = (2*PI)/n;
  rotate([0,0,M5_NUT_ROTATE])
    for (step = [0:n-1]) {
      translate([r * cosr(step*delta), r * sinr(step*delta), 0])
        cylinder(h=h, d=d, center=true);
    }

}

//!m3mounts();

module pin(d, h, t=0, $fn=$fn)
{
  base = h-t;
  translate([0,0,(base/2) - h/2])
   hull()
   {
      color("red",0.5)cylinder(d=d, h=base, center=true);
      translate([0,0,base/2 + t/2])
        color("blue", 0.5) cylinder(d=d/2, h=t, center=true);
    }

}

module bottom() {

  CLR = 1+CLEARANCE;

  difference() {
    hull() {
      translate([0,0,0.1*BOTTOM_HEIGHT]) cylinder(d=OUTER_DIA, h=0.9*BOTTOM_HEIGHT);
      cylinder(d=OUTER_DIA*0.97, h=0.1*BOTTOM_HEIGHT);
    }

    scale([CLR, CLR, CLR])shaft();
    translate([0,0,(-M5_NUT_HEIGHT/2) + SHAFT_LENGTH + 3.1]) scale([CLR, CLR, CLR]) m5nuts();
    m3mounts();

    union() {
      translate([OUTER_DIA/2,0,SHAFT_LENGTH/2])
        rotate([0, 90,0])
          cylinder(d=M3_HOLE_DIA, h= OUTER_DIA, center=true);
      translate([OUTER_DIA/2 + M3_LENGTH + (SHAFT_DIA/3), 0, SHAFT_LENGTH/2])
        rotate([0,90,0])
          cylinder(d=M3_HEAD_DIA, h = OUTER_DIA, center=true);

    }

    translate([SHAFT_DIA/2 + M3_LENGTH/3,0,SHAFT_LENGTH/2])
    rotate([0,0,90])
      m3nut_slot(2*OUTER_HEIGHT);

  }

  module press_fit() {
    h = PRESS_FIT_HEIGHT * (1-CLEARANCE);
    d = PRESS_FIT_DIA * (1-CLEARANCE);

    translate([0,0,BOTTOM_HEIGHT - 0.01 + (h/2)])
    pin(d=d, h=h, t=0.15*h, $fn=6);
  }
  hull() {
  translate([0,PRESS_FIT_DIA/2,0]) press_fit();
  translate([0,-PRESS_FIT_DIA/2,0]) press_fit();
  }

}

module press_fit_slot() {
  hull() {
      translate([0,PRESS_FIT_DIA/2,-0.01]) cylinder(d=PRESS_FIT_DIA, h=PRESS_FIT_HEIGHT*(1+CLEARANCE));
      translate([0,-PRESS_FIT_DIA/2,-0.01]) cylinder(d=PRESS_FIT_DIA, h=PRESS_FIT_HEIGHT*(1+CLEARANCE));

    //wider base
    translate([0,(PRESS_FIT_DIA*1.1)/2,-0.01]) cylinder(d=PRESS_FIT_DIA, h=0.1);
    translate([0,-(PRESS_FIT_DIA*1.1)/2,-0.01]) cylinder(d=PRESS_FIT_DIA, h=0.1);

  }

}

//!press_fit_slot();

module top() {

  translate([0,0,BOTTOM_HEIGHT*1.5])
    difference() {

       hull() {
         cylinder(d=OUTER_DIA, h=TOP_HEIGHT*0.8);
         cylinder(d=OUTER_DIA*0.9, h=TOP_HEIGHT);
      }

     press_fit_slot();

     translate([0,0,(TOP_HEIGHT*0.8)/2 - 0.01]) m3mounts(h=TOP_HEIGHT*0.8, d=M3_TAP_DIA);

    }

}

if ("test" == BUILD_TYPE) {
  H = 1.5*M5_NUT_HEIGHT;
  difference() {
    translate([0,0,-H/2 + (M5_NUT_HEIGHT/2) - 0.1])
      cylinder(d=2*M5_NUT_DIA, h=H, center=true);
    m5nut();
  }

  translate([1.8*M5_NUT_DIA,0,0]) difference() {
    translate([0,0,-H/2 + (M5_NUT_HEIGHT/2) - 0.1])
      cylinder(d=2*M5_NUT_DIA, h=H, center=true);
    translate([0,M5_NUT_DIA,0])rotate([0, 90,90])
          cylinder(d=M3_HOLE_DIA, h= 2*M5_NUT_DIA, center=true);
    translate([0,0,-M3_NUT_HEIGHT/2]) m3nut_slot(2*H);
  }

} else if ("bottom" == BUILD_TYPE) {
  color(BOTTOM_COLOR, 0.8) bottom();
  %top();
  %shaft();
} else if ("top" == BUILD_TYPE) {
  %bottom();
  color(TOP_COLOR, 0.8) top();
  %shaft();

} else {
  color(BOTTOM_COLOR, 0.6) bottom();
  color(TOP_COLOR, 0.6) top();
  color(SHAFT_COLOR, 0.6) shaft();

}

```


[User]
Hey, I'm looking to create a parametric finishing washer generator in OpenSCAD. I have a specific set of requirements based on the design I'm trying to achieve and I've also seen some nice features in a design I found.

Here's what I need:

*   **Washer Diameter:** This should be a variable, obviously. I want to be able to set the overall diameter of the washer.
*   **Washer Type:** I need to be able to choose between a few different washer profiles:
    *   CYLINDER: A standard flat washer.
    *   CONE: A conical washer.
    *   CHAMFER: A washer with a chamfered top edge.
    *   DOME: A washer with a domed top.
*   **Screw Gauge:** This will determine the diameter of the center hole. I should be able to specify this based on standard screw sizes (like #4, #6, #8, #9, #10, but using the actual diameter in mm - so 3, 3.5, 4, 4.5, 5).
*   **Screw Head Type:** I need to be able to choose how the top of the hole interacts with the screw head:
    *   FLUSH: A flat counterbore to accept a flat head screw.
    *   RECESSED: A conical countersink to accept a recessed head screw.

I’d really like the design to have the ability to define all of the parameters as configurable values for each of these options, and to automatically generate the shapes and sizes to match.

I'd like to keep it as one primary SCAD file if possible, and I'm not using any external libraries for this.

Thanks in advance!

[Assistant]
finish_washer.scad:
```
// finish_washer.scad
// library for parametric finishing washer, button, ring, pad, accent
// Author: Tony Z. Tonchev, Michigan (USA)
// last update: November 2018

// Washer diameter (in mm): 3x or larger than Screw Gauge.
Washer_Diameter = 20;

// General washer shape
Washer_Type = 1; //[1:CYLINDER, 2:CONE, 3:CHAMFER, 4:DOME]

// Screw shaft diameter (in mm): #4-3mm, #6-3.5mm, #8-4mm, #9-4.5mm, #10-5mm
Screw_Gauge = 4;

// General screw head type
Screw_Head_Type = 1; //[1:FLUSH, 2:RECESSED]

/* [Hidden] */

$fn=100;
TZT_Rad = Washer_Diameter/2;
TZT_Sad = Screw_Gauge/2;
TZT_Thk = Screw_Gauge;
TZT_Wty = Washer_Type;
TZT_Sty = Screw_Head_Type;

difference () {
    TZT_Washer ();
    TZT_Hole ();
}

//-----------------

module TZT_Washer () {
    translate ([0,0,-0.5]) cylinder (0.5, TZT_Rad, TZT_Rad);
    if (TZT_Wty==2) {
        cylinder (TZT_Thk, TZT_Rad, TZT_Sad*2);
    } else if (TZT_Wty==3) {
        cylinder (TZT_Thk*0.7, TZT_Rad, TZT_Rad);
        translate ([0,0,TZT_Thk*0.7]) cylinder (TZT_Thk*0.3, TZT_Rad, TZT_Rad-TZT_Thk*0.3);
    } else if (TZT_Wty==4) {
        difference () {
            scale ([1,1,TZT_Thk/TZT_Rad]) sphere (TZT_Rad);
            translate ([0,0,-TZT_Thk]) cylinder (TZT_Thk, TZT_Rad, TZT_Rad);
        }
    } else {
        cylinder (TZT_Thk, TZT_Rad, TZT_Rad);
    }
}

module TZT_Hole () {
    translate ([0,0,-1]) cylinder (TZT_Thk*9, TZT_Sad, TZT_Sad);
    if (TZT_Sty==2) {
        translate  ([0,0,TZT_Sad+0.1]) cylinder (TZT_Sad, TZT_Sad, TZT_Sad*2);
    } else {
        translate  ([0,0,TZT_Sad+0.1]) cylinder (TZT_Sad, TZT_Sad*2.2, TZT_Sad*2.2);
    }
}
```


[User]
I'm looking for an OpenSCAD design for a customizable LED matrix diffuser, specifically for WS2812/WS2812b LEDs. I've been trying to find something decent, but haven't had much luck. I want it to be parametric, so I can easily adjust it for different matrix sizes and LED spacing.

Here's what I need:

*   **Base Shape:** It should start with a rectangular prism that acts as the main diffuser body.
*   **LED Holes:** It needs to create cutouts (holes) in the prism that correspond to the locations of LEDs in a matrix.
*   **Parameters:** I want to be able to control these values:
    *   `PCB_HEIGHT`: The height of the PCB that the LEDs are mounted on (in mm).
    *   `PCB_WIDTH`: The width of the PCB that the LEDs are mounted on (in mm).
    *   `NUMBER_LEDS_HORIZONTAL`: Number of LEDs in a horizontal row.
    *   `NUMBER_LEDS_VERTICAL`: Number of LEDs in a vertical column.
    *   `DIFFUSER_HEIGHT`: The height of the diffuser itself.
    *   `LED_SIZE`: The size of the LED (assuming they are square, in mm).
    *   `DISTANCE_BETWEEN_LEDS`: The center-to-center distance between LEDs (in mm).
    *   `WALL_THICKNESS`: Thickness of the walls around the LED cutouts.
    *    `PCB_BORDER`: The distance of the first row/column of LEDs from the edge of the board.

I'd like the cutouts to be slightly larger than the LED size plus a buffer. This buffer should be defined as `DISTANCE_BETWEEN_LEDS-WALL_THINKESS`. I'm thinking that the cutouts should be a little taller than the diffuser itself, so they poke through the top. I want a difference() operation, so the base prism is the main body and then the LED cutouts are subtracted from the body.

Could you generate an OpenSCAD file for this? I'm not using any special libraries. I would like the OpenSCAD file to have comments, so I can understand what's going on.

[Assistant]
Diffuser.scad:
```
// WS2812 / WS2812b Led Matrix Diffuser by malebuffy

PCB_HEIGHT = 130; // Size of PCB in mm
PCB_WIDTH = 130; // Size of PCB in mm
NUMBER_LEDS_HORIZONTAL=16; // Number of Leds in a row
NUMBER_LEDS_VERTICAL=16;   // Number of Leds in a column
DIFFUSER_HEIGHT = 4; // Height of diffuser
LED_SIZE = 5; // Size of leds in mm
DISTANCE_BETWEEN_LEDS=3.12; // Distance between leds in mm
WALL_THINKESS=1; // Thinkess of walls
PCB_BORDER = 0.4;  // PCB Outer Boarder in mm

buffer=DISTANCE_BETWEEN_LEDS-WALL_THINKESS;

difference() {

cube([PCB_HEIGHT,PCB_WIDTH,DIFFUSER_HEIGHT]); // Create Main PCB Diffuser

for ( i = [0:NUMBER_LEDS_HORIZONTAL-1] ) {

    translate([PCB_BORDER,(LED_SIZE+DISTANCE_BETWEEN_LEDS)*i,-1])

    for ( j = [0:NUMBER_LEDS_VERTICAL-1] ) {

     translate([(LED_SIZE+DISTANCE_BETWEEN_LEDS)*j,PCB_BORDER,-1]) cube([LED_SIZE+buffer,LED_SIZE+buffer,DIFFUSER_HEIGHT+5]);

  }
 }
}
```


[User]
I'd like to create a squid-like design in OpenSCAD, and I'm looking for a parametric model that allows for both configurable and random generation. I've seen a design that does something similar and I want to replicate that and make it my own.

Here's what I have in mind:

**Core Structure:**

*   **Body:** The main body should be a sphere, though I'd like the ability to squash it along the z-axis to give it a less perfectly spherical look. I'd also like an additional section on the top of the body that's created using a hull between two spheres of different sizes.
*   **Legs:** There should be a variable number of legs radiating outwards from the bottom. I want to control their position and length and the overall "aperture" (how far they bend outwards from the center of the body).

**Eyes:**

*   The design should have two eyes, which are basically cylinders with a circular cross-section.
*   I want control over the x and y positions of the pupils within each eye.
*   The eye itself should be made of two cylinders: one outer and one inner, where the inner cylinder is subtracted from the outer cylinder.
*   The pupils should also be cylinders. The pupil size should be relative to the overall size of the eye, with a ratio that is configurable.

**Parametric Control:**

*   I want two modes: "configurable" and "random".
*   **Configurable Mode:** In this mode, I'd like to be able to set parameters like body size, the number of legs, leg aperture, leg length, eye offsets, and pupil ratio.
*   **Random Mode:** In this mode, all the parameters above should be randomly generated within a reasonable range.

**Specific Parameters (for Configurable Mode):**

*   `body_size`:  Radius of the main body sphere.
*   `n_leg`: Number of legs.
*   `aperture`: Controls how far out the legs spread (positive or negative angle).
*   `l_lenght`: Length of each leg.
*   `x_eyes_R`:  Horizontal offset for the right pupil.
*   `y_eyes_R`: Vertical offset for the right pupil.
*   `x_eyes_L`: Horizontal offset for the left pupil.
*   `y_eyes_L`: Vertical offset for the left pupil.
*   `pupila_ratio`: The ratio between the eye size and the pupil size.

**Specific Parameters (for Random Mode):**

*  All parameters should be randomized. I'm not picky about the specific range, but please use the ranges in the provided SCAD file for the parameters.

**General Requirements:**

*   The design should be done in a modular way.
*   Use `$fn=20;` for the circle resolution.

I don't have any specific OpenSCAD libraries in mind, so please use whatever you think is best for this design. I'm excited to see what you come up with!

[Assistant]
squid3d_random3.scad:
```
/* Squid 3D Configurable/Random
Version 1, Enero 2019
Escrito por Jorge Cifuentes (jorgecif at gmail dot com)*/

//Parametros de configuracion

/* Partes
Cabeza
- Ojos
- Posicion ojos
Torzo
Patas

*/

tipo="configurable"; //[configurable,random]

//Resolution
$fn=20;
//Body size (radio)
body_size=10;//[10:1:100]
//Leg n_leg
n_leg=7; //[3:1:12]
//Legs aperture
aperture=-10;//[-10:1:10]
//Lenght legs
l_lenght=10;//[-10:1:50]
//Right eye x desviation
x_eyes_R=2;
//Right eye y desviation
y_eyes_R=2;
//Left eye x desviation
x_eyes_L=-2;
//Left eye y desviation
y_eyes_L=2;

pupila_ratio=2;//[1.5:.1:5]

 module squid(body_size,n_leg,aperture,l_lenght, resize_scale, scale_hat1, scale_hat2, e_size, pupila_size,pupila_ratio, x_eyes_R, y_eyes_R, x_eyes_L, y_eyes_L)
{

 union(){
 scale([1, 1, resize_scale])
 rotate(a=90, v=[0,0,90]) sphere(body_size*2);
 rotate(a=90, v=[0,0,90]) #ojos();
 }

 translate([0,0,body_size])
 hull() {
 translate([0,0,body_size]) sphere(body_size*scale_hat1,center=true);
 scale([1, 1, resize_scale/2.5]) sphere(body_size*scale_hat2,center=true);
 }

 module ojos_ex(){
  translate([body_size-.4*body_size,body_size*2,-0.2*body_size])
 rotate(a=90, v=[1,0,0])
cylinder(e_size,e_size,e_size);
   translate([-(body_size-.4*body_size),body_size*2,-0.2*body_size])
 rotate(a=90, v=[1,0,0])
cylinder(e_size,e_size,e_size);
 }

 module ojos_in(){
  translate([body_size-.4*body_size,body_size*2,-0.2*body_size])
 rotate(a=90, v=[1,0,0])
cylinder(e_size-1,e_size-1,e_size-1);
   translate([-(body_size-.4*body_size),body_size*2,-0.2*body_size])
 rotate(a=90, v=[1,0,0])
cylinder(e_size-1,e_size-1,e_size-1);
 }

  module contorno_ojos(){
 difference() {
     ojos_ex();
     #ojos_in();
 }
 }

 module ojos(){
 union(){
    contorno_ojos();
     #pupilas();
 }

 }

  module pupilas(){
  translate([body_size-.4*body_size+x_eyes_R,body_size*2,-(0.2*body_size+y_eyes_R)])
 rotate(a=90, v=[1,0,0])
#cylinder(pupila_size,pupila_size,pupila_size);
   translate([-(body_size-.4*body_size+x_eyes_L),body_size*2,-(0.2*body_size+y_eyes_L)])
 rotate(a=90, v=[1,0,0])
#cylinder(pupila_size,pupila_size,pupila_size);
 }

 //Patas
 for(r = [1:n_leg]) {
      rotate(360/n_leg * r, [0, 0, 1]) translate([-body_size, -body_size*1.2, -body_size*1.8])
      hull(){
      translate([0,aperture,-l_lenght])  scale([1, 1, 1]) sphere(body_size);
     scale([1, 1, 1]) sphere(body_size);
          }
    }
}
/*
      for(r = [1:n_leg]) {
      rotate(360/n_leg * r, [0, 0, 1]) translate([-body_size, -body_size, -body_size])
      scale([1, 1, 0.7])
        sphere(body_size);
    }
*/

module configurable_squid()
{
     resize_scale=0.8;
     scale_hat1=1.2;
     scale_hat2=2.5;
     e_size=body_size*.8;//Eye size
     pupila_size=e_size/pupila_ratio;//Pulila size
     squid(body_size,n_leg,aperture,l_lenght, resize_scale, scale_hat1, scale_hat2, e_size,pupila_size, pupila_ratio, x_eyes_R, y_eyes_R, x_eyes_L, y_eyes_L);
}

module random_squid()
{
     resize_scale=0.8;//rands(0.5,0.2,5)[0];//0.8;
     scale_hat1=1.2;//rands(1,0.1,2)[0];//1.2;
     scale_hat2=rands(2.5,3.5,1)[0];//2.5;
     e_size=body_size*.8;//Eye size
     pupila_ratio=rands(1.5,4.5,1)[0];
    pupila_size=e_size/pupila_ratio;//Pulila size
    max_desviation=(e_size-2*pupila_size-1);
    x_eyes_R=rands(-max_desviation,max_desviation,1)[0];
    //Right eye y desviation
    y_eyes_R=rands(-max_desviation,max_desviation,1)[0];
    //Left eye x desviation
    x_eyes_L=rands(-max_desviation,max_desviation,1)[0];
    //Left eye y desviation
    y_eyes_L=rands(-max_desviation,max_desviation,1)[0];
    body_size=rands(10,15,1)[0];//10;//[10:1:100]
    //Leg n_leg
    n_leg=rands(3,12,1)[0];//7; //[3:1:12]
    //Legs aperture
    aperture=rands(-10,10,1)[0];//-10;//[-10:1:10]
    //Lenght legs
    l_lenght=rands(-10,50,1)[0];//10;//[-10:1:50]

	squid(body_size,n_leg,aperture,l_lenght, resize_scale, scale_hat1, scale_hat2, e_size,pupila_size, pupila_ratio, x_eyes_R, y_eyes_R, x_eyes_L, y_eyes_L);
}

    if (tipo=="configurable")
{
    configurable_squid();
}

if (tipo=="random")
{
    random_squid();
}

```


[User]
I'm looking to create a parametric snap-on hinge for a PVC pipe, similar to the one I found online (I've attached the .scad file for reference, it's called "SnapOnPvcPanelHinge.scad"). I need it to be highly customizable, so I can adapt it to different pipe sizes and panel thicknesses.

The core design should involve a clip that wraps around the PVC pipe with a snapping mechanism for easy attachment and removal, and a mounting block for attaching a panel or door. Key parameters I need to control are:

*   **Clip Diameter:** The inner diameter of the clip to match different PVC pipe sizes.
*   **Clip Height:** The height of the clip (top to bottom)
*   **Clip Wall Thickness:** The thickness of the clip's wall, which will impact its strength and snap-on/off tightness.
*   **Clip Wraparound:** The angle (in degrees) that the clip wraps around the pipe.
*   **Mounting Block Length:**  The length of the mounting block extending past the clip's outer diameter.
*   **Mounting Block Thickness:** The thickness of the mounting block (front to rear).
*   **Mounting Hole Diameter:**  The diameter of the mounting holes on the block.
*   **Mounting Hole Locations:** Horizontal inset distance from the end of the mounting block for one or two mounting holes.
*   **Ramp Configuration:** I'd like an optional ramp to prevent the edge of the panel from catching as it rotates. This should have adjustable offset and height.

I'd like to be able to adjust:
*   Ramp Offset: the distance from the center line of the hinge to the edge of the ramp.
*   Ramp Height: the height of the protective edge at the end of the ramp.

Could you generate the OpenSCAD code for this? I'd like it to be as clear and well-commented as possible, so I can easily understand how to adjust the parameters. I'd prefer to avoid libraries if possible; everything I need should be able to be built into the main .scad file.

[Assistant]
SnapOnPvcPanelHinge.scad:
```
/* [Clip Parameters] */
// Adjust to suit your PVC pipe diameter, and desired tightness of fit and ease of rotation
clip_inner_diameter = 22.1;
// Height of the hinge (top to bottom)
clip_height = 10;
// Thickness of clip wall. 5mm is a good value - thicker is stronger and will provide more aggressive snap on/off
clip_wall_thick = 5;
// How far around the pipe the clip should wrap. 220 is secure, but easily removable. Larger value is more secure, but will make it harder (or impossible) to snap on/off the pipe. Set to 360 for fully-enclosed hinge that would need to slide over end of pipe.
clip_wraparound_degrees = 220; // [180:360]

/* [Clip Ramp Parameters] */
// Optional ramp to prevent panel edge from catching on other side edges as the hinged panel is opened. Ramp Offset is distance in mm from center line of pipe/hinge to edge the ramp. Zero puts it in the middle of the clip, larger values move it toward the outside of the hinge. Set to 0 if no ramp desired.
ramp_offset = 8; // [0:25]
// Optional protective edge at end of ramp, to provide a smoother transition to edge of panel, if needed. Set to thickness of panel, or set to 0 if no additional ramp height needed. (Can also be useful for consistently aligning hinges relative to edge of panel...)
ramp_height = 3; // [0:25]

/* [Mounting Block Parameters] */
// The mounting block length *past the the outer diameter of the clip* (to allow space for a nut on the rear of the mounting block, if needed)
mounting_block_length = 25;
// Thickness of mounting block (front to rear)
mounting_block_thick = 10; // [0:25]

/* [Mounting Hole Parameters] */
// The diameter of the mounting hole(s) - recommend printing just slightly smaller than needed, then drill out to final desired size for through-hole or tapping. Holes will be vertically centered on the mounting block.
mouting_hole_diameter = 4.1;
// Horizontal distance *from the end of the mounting block farthest from the clip* at which to center the first mounting hole (no hole will be made, if set to zero)
mounting_hole_1_inset = 5;
// Horizontal distance *from the end of the mounting block farthest from the clip* at which to center the second mounting hole (no hole will be made, if set to zero)
mounting_hole_2_inset = 20;

/* [Hidden] */
//internal variables used by the program - feel free to play, but change at your own risk :-)
clipID = clip_inner_diameter;
clipWallThick = clip_wall_thick;
clipHt = clip_height;
clipWrapDeg = clip_wraparound_degrees;

connLen = mounting_block_length;       //length of connector block *beyond back-side contact point of block with clip OD*
connThick = mounting_block_thick;

rampHt = ramp_height;
rampOffset = ramp_offset;     //distance past tangent point connector contact, that ramp should start

mountHoleDia = 4.1;  //set appropriately to drill out and/or tap for desired bolt size

holeLocs = [mounting_hole_1_inset, mounting_hole_2_inset];

clipOD = clipID + 2*clipWallThick;

connBaseOffset = clipOD/2;//sqrt(pow(clipOD/2, 2) - pow(clipOD/2 - connThick, 2));

totconnLen = connBaseOffset + connLen;

connWrapDeg = .5*clipWrapDeg;

rampTotRad = clipOD/2 + rampHt;

diffTol = .005;

$fn=60;

rampStartX = rampTotRad*cos(connWrapDeg);
rampStartY = rampTotRad*sin(connWrapDeg);

rampOffsetX = rampOffset*sin(connWrapDeg);
rampOffsetY = rampOffset*cos(connWrapDeg);

rampEndX = rampStartX - rampOffsetX;
rampEndY = rampStartY + rampOffsetY;

rampStartDeg = 180 + rotFromXY(rampEndX, rampEndY);
rampStartRad = radFromXY(rampEndX, rampEndY);
rampRotDeg = clipWrapDeg - rampStartDeg;

clip();
connector();
ramp();

function radFromXY(x, y)  = sqrt(pow(x, 2) + pow(y, 2));
function rotFromXY(x, y) = atan(y/x);
function xFromRadRot(rad, rot) = rad*cos(rot);
function yFromRadRot(rad, rot) = rad*sin(rot);

module ramp() {
    rampRadDiff = rampStartRad - clipOD/2;
    rampRadDegDiff = rampRadDiff/rampRotDeg;
    clipWrapODPt = [xFromRadRot(clipOD/2, connWrapDeg), yFromRadRot(clipOD/2, connWrapDeg)];
    rampBasePt = [rampOffset*cos(connWrapDeg + 90) + clipWrapODPt[0], rampOffset*sin(connWrapDeg + 90) + clipWrapODPt[1]];

    rampArcPts = concat([[0, 0]], [clipWrapODPt], [rampBasePt],
        [for (r=[0:.1:rampRotDeg])
            let (rad = rampStartRad - r*rampRadDegDiff, rot = rampStartDeg + r)
            [xFromRadRot(rad, rot), yFromRadRot(rad, rot)]
        ]);

    difference() {
        linear_extrude(height=clipHt)
            polygon(rampArcPts);

        translate([0, 0, -diffTol])
            cylinder(d=clipID, h=clipHt + 2*diffTol);
    }
}

module clip() {
    difference() {
        //clip walls
        rotate_extrude(angle=clipWrapDeg) {
            translate([clipID/2, 0, 0])
                square([clipWallThick, clipHt]);
        }

        //Thingiverse Customizer runs an old version of OpenSCAD, which doesn't support rotate_extrude below 360 degrees, so chop out a chunk, if OpenSCAD version doesn't support proper rotate_extrude
        if (version_num() <= 20150399) {
            translate([0, 0, -diffTol])
                hull() {
                    for (r=[0, -(360-clipWrapDeg)/2, -(360-clipWrapDeg)])
                        rotate([0, 0, r])
                            cube([clipOD, .001, clipHt + 2*diffTol]);

                }
        }
    }

    //clip rounded ends
    for (r=[0, clipWrapDeg]) {
        rotate([0, 0, r])
            translate([clipID/2 + clipWallThick/2, 0, 0])
                cylinder(d=clipWallThick, h=clipHt);
    }
}

module connector() {
    rotate([0, 0, connWrapDeg]) {
        difference() {
            translate([clipOD/2 - connThick, -totconnLen, 0])
                cube([connThick, totconnLen, clipHt]);
            translate([0, 0, -diffTol])
                cylinder(d=clipID, h=clipHt + 2*diffTol);

            for (hl=holeLocs) {
                if (hl > 0)
                    translate([clipOD/2 - connThick - diffTol, -totconnLen + hl, clipHt/2])
                        rotate([0, 90, 0])
                            cylinder(d=mountHoleDia, h=connThick + 2*diffTol);
            }
        }
    }
}

```


[User]
I'd like to design a parametric trinket box with a lid, and I'd like the design to be flexible enough that I can easily adjust the dimensions and style. I envision it as a box with rounded corners, and a separate lid that fits snugly on top.

Specifically, I need to be able to control the following parameters:

*   **Box Length:** The overall length of the box's exterior.
*   **Box Width:** The overall width of the box's exterior.
*   **Box Depth:** The overall depth of the box's exterior.
*   **Corner Radius:** The radius of the rounded corners for both the box and the lid.
*   **Box Style:** A parameter that influences the thickness of the walls and the overall style of the connection between the box and lid. Maybe higher values make the fit between lid and box more snug, and also the internal cavity of the box smaller?
*   **Build Group:** Allows me to choose whether to generate only the box, only the lid, or both.

The design should automatically adjust the thickness of the box walls and the necessary offsets to ensure a proper fit between the box and lid. I'd also like a few small sphere-based "thumb grabs" on the sides of the box to make it easier to open.

I'd prefer if the design is implemented using OpenSCAD. Please provide a single .scad file that includes all the necessary code. It's important that this is a parametric design and it should be easy to change all of those parameters, and they should all be in millimeters. I'm hoping I can control all of those values as variables at the start of the file.

Thank you.

[Assistant]
trinket_box.scad:
```
// finish_washer.scad
// library for parametric Trinket Box, Container, Enclosure, Organizer, Storage
// Author: Tony Z. Tonchev, Michigan (USA)
// last update: January 2019

// Length of box exterior (in mm)
Box_Length = 100;

// Width of box exterior (in mm)
Box_Width = 80;

// Depth of box exterior (in mm)
Box_Depth = 50;

// Box sides and lid corner radius (in mm)
Box_Corner_Radius = 8; //[4:20]

// Box style/structure tune
Box_Style = 2; //[2:10]

// Group
Build_Group = 1; //[1:BOTH, 2:BOX, 3:LID]

/* [Hidden] */

TZT_X=Box_Length-2*Box_Corner_Radius;
TZT_Y=Box_Width-2*Box_Corner_Radius;
TZT_Z=Box_Depth;
TZT_R=Box_Corner_Radius;
TZT_W=TZT_R/Box_Style+1;
$fn=40;

//---------------

if (Build_Group!=3) translate ([0,Box_Width*0.55,0]) TZT_Container ();
if (Build_Group!=2) translate ([0,-Box_Width*0.55,TZT_W+TZT_R/2]) rotate ([0,180,0]) TZT_Lid ();

module TZT_Lid () {
    translate ([0,0,TZT_W]) TZT_Box ([TZT_X,TZT_Y,TZT_R/2,TZT_R,TZT_R/2]);
    TZT_Box ([TZT_X,TZT_Y,TZT_W,TZT_R,TZT_R]);
    translate ([0,0,-TZT_W]) TZT_Box ([TZT_X-2*TZT_W-1,TZT_Y-2*TZT_W-1,TZT_W,TZT_R-TZT_W-0.5,TZT_R-TZT_W-0.5]);
}

module TZT_Container () {
    difference () {
        TZT_Box ([TZT_X,TZT_Y,TZT_Z,TZT_R,TZT_R]);
        translate ([0,0,TZT_W]) TZT_Box ([TZT_X-2*TZT_W,TZT_Y-2*TZT_W,TZT_Z,TZT_R-TZT_W,TZT_R-TZT_W]);
        TZT_Thmb=TZT_W/10;
        for (x=[-1:2:1]) {
            translate ([0,(TZT_Y/2+TZT_R)*x,TZT_Z]) scale ([1,TZT_Thmb,1]) sphere (10);
            translate ([(TZT_X/2+TZT_R)*x,0,TZT_Z]) scale ([TZT_Thmb,1,1]) sphere (10);
        }
    }
}

module TZT_Box (TZT_Sz) {
    hull () {
        for (x=[-1:2:1]) for (y=[-1:2:1]) {
            translate ([TZT_Sz[0]/2*x,TZT_Sz[1]/2*y,0]) cylinder (TZT_Sz[2],TZT_Sz[3],TZT_Sz[4]);
        }
    }
}
```