[User]
Hey, I'm looking to design some customizable brackets for drawer organizers. I've tinkered with some existing code and tried to make my own, but I'm hitting a wall with the tapering and clean intersections. I’d like your help designing a parametric OpenSCAD file (or files, if needed) to generate these brackets.

Here's what I need:

*   **Basic Bracket:** A 90-degree corner bracket, like an L-shape. I want to be able to use it in both right and left orientations just by flipping the model.
*   **Customizable Gaps:** I need to control the gap sizes on both sides of the bracket. There’ll be an “open” side that's meant for pass-through or thicker materials, and a “closed” side that would be thinner, meant for drawer sides or similar. I need to set the gap size for both separately.
*  **Wall Thickness:** The thickness of the bracket walls should be adjustable.
*   **Grip Lengths:**  The "grip" or length of the bracket arms should be separately adjustable for the "open" and "closed" sides.
*   **Height:** The overall height of the bracket should be customizable.
*   **Tapered Walls:** This is where I'm struggling. I need the walls to be tapered so they're thicker at the base and thinner at the top. I’d like it to be similar to how it's done in the "remixed_brackets_3way_v01.scad" and "remixed_bracketsv05.scad" files I've been playing with, but ideally with cleaner intersections. I'm fine with a solution using a hull between two cubes if necessary like in v05.
*   **Multiple Configurations:** Beyond just a basic 90-degree elbow, I’d like to generate three-way and four-way corner connectors too. I should have a single variable to choose between a two-way (elbow), three-way or a four-way connection.
*  **Reversible L:** It would also be nice to be able to "reverse" the L shape so that the base of the tapered wall starts at the inside rather than the outside of the corner, similar to how the "Reverse" variable functions in "remixed_brackets_3way_v01.scad". This should also be a simple switch to reverse.
* **Rounded Edges:** Similar to the files I've provided, I'd like the edges to have a small rounded over or chamfer applied to them. I think using a minkowski sum with a sphere should work.

I'm not attached to how the tapering is implemented - using cubes, cylinders, or any other method is fine as long as it gets the job done cleanly. I'd like to try and avoid using any external libraries (like BOSL) if possible.

I included the two files I've been using to give a general idea, but please do not attempt to improve upon this existing code. I would appreciate the final files being well-commented.

Thanks a bunch!

[Assistant]
remixed_brackets_3way_v01.scad:
```
//Remixed brackets customizable in Customizer

//Corner bracket, 3 way or 4 way connection?
sides = 4; //[2, 3, 4]

//How thick should the walls of the brackets be?
thickness = 1;

//How thick is the material being used on the open side or pass-through side?
open_gap_input = 13;

//Calculate combined width of gap and wall.
open_gap = open_gap_input + thickness;

//How thick is the material being used on the closed side?
closed_gap_input = 6.85;

//calculating combined width of gap and single wall
closed_gap = closed_gap_input + thickness;

//How long should the grip be on the open side?
grip_length_open = 30;

//How wide should the grip be on the closed side?
grip_length_closed = 31;

// How tall do you want the bracket to be?
bracket_h_input = 30;

//Reverse the L?
Reverse = "No"; //[Yes, No]

//translate ([14,14,0]){
//    color("Lavender"){
//        import("a-elbow-custom.stl");
//    }
//}

//Side wall module
module SideWall(a) {
    if (a ==2){
        rcube (thickness, open_gap+thickness, grip_length_open);
        translate([0, open_gap, grip_length_open-closed_gap-thickness]){
            rcube (thickness,grip_length_closed, closed_gap+thickness);
         }
     } else if(a ==3){
        rcube (thickness, open_gap+thickness, grip_length_open*2-closed_gap);
        translate([0, open_gap, grip_length_open-closed_gap-thickness]){
            rcube (thickness,grip_length_closed, closed_gap+thickness);
         }
     } else if(a ==4){
         rcube (thickness, open_gap+thickness, grip_length_open*2-closed_gap);
        translate([0, -grip_length_closed, grip_length_open-closed_gap-thickness]){
            #rcube (thickness,grip_length_closed*2+open_gap, closed_gap+thickness);
         }
     }

}

// rounded rectangle module
module rcube(x,y,z){
        minkowski(){
            cube ([x-0.5, y-0.5, z-0.5]);
            translate ([0.25, 0.25, 0.25]) sphere (0.25);
        }
}

//Tapered rectangle module using rectangles
module tcube(x, y, z) {
        hull(){
        if (Reverse == "Yes"){
            translate([bracket_h_input-thickness, 0, 0]) cube([1, y, z]);
            translate ([0, y-0.5, 0]) cube([1, y-0.5, z]);
        } else {
            translate([0,0,0]) cube([1, y, z]);
            translate ([bracket_h_input-thickness, 0, 0]) cube ([1, y-0.5, z]);
        }
    }
}

//tapered rectangle module using cylinder/cones
module tcc(x, y, z) {
    hull(){
        rotate ([0, 90, 0]) cylinder(r1 = 0.25, r2 = thickness, h = x);
            translate ([0, 0, z]) rotate ([0, 90, 0]) cylinder(r1 = 0.25, r2 = thickness, h = x);
    }
}

$fn = 50; //resolution or number of parts

//check which side side wall should be
if (Reverse == "Yes"){
    translate ([bracket_h_input-thickness, 0, 0]){
        SideWall(sides);
    }
} else {
    SideWall(sides);
    }

//Check for corner, three way or 4 way
if (sides == 4) {
    tcube (bracket_h_input, thickness, grip_length_open-closed_gap);
    translate([0,0, grip_length_open]) tcube (bracket_h_input, thickness, grip_length_open-closed_gap);

    translate([0, open_gap, 0]) {
        tcube (bracket_h_input, thickness, grip_length_open-closed_gap);
    }
    translate([0, open_gap, grip_length_open]) {
        tcube (bracket_h_input, thickness, grip_length_open-closed_gap);
    }
    translate([0, -grip_length_closed, grip_length_open-closed_gap-thickness]){
        rcube (bracket_h_input,grip_length_closed, thickness);
    }
    translate([0, -grip_length_closed, grip_length_open - thickness ]){
        rcube (bracket_h_input, grip_length_closed, thickness);
    }
    echo("4 sides");
} else if(sides == 3){
    tcube(bracket_h_input, thickness, grip_length_open*2-closed_gap);
    translate([0, open_gap, 0]) {
        tcube (bracket_h_input, thickness, grip_length_open-closed_gap);
    }
    translate([0, open_gap, grip_length_open]) {
        tcube (bracket_h_input, thickness, grip_length_open-closed_gap);
    }
} else if(sides == 2){
    tcube(bracket_h_input, thickness, grip_length_open);
    translate([0, open_gap, 0]) {
    tcube (bracket_h_input, thickness, grip_length_open-closed_gap);
}
    echo("two sides selected");
}

translate([0, open_gap, grip_length_open-closed_gap-thickness]){
    rcube (bracket_h_input,grip_length_closed, thickness);
}

translate([0, open_gap, grip_length_open - thickness ]){
    rcube (bracket_h_input, grip_length_closed, thickness);
}

```
remixed_bracketsv05.scad:
```
//Remixed customizable brackets

$fn = 50; //resolution or number of parts

//How thick should the walls of the brackets be?
thickness = 1;

//How thick is the material being used on the open side or pass-through side?
open_gap_input = 13;

//Calculate combined width of gap and wall.
open_gap = open_gap_input + thickness;

//How thick is the material being used on the closed side?
closed_gap_input = 6.85;

//calculating combined width of gap and single wall
closed_gap = closed_gap_input + thickness;

//How long should the grip be on the open side?
grip_length_open = 30;

//How wide should the grip be on the closed side?
grip_length_closed = 31;

// How tall do you want the bracket to be?
bracket_h_input = 30;

//Reverse the L?
Reverse = 1; //[-1:Yes, 1:No]

//Top wall

minkowski(){
        #cube([thickness, open_gap+thickness, grip_length_open]);
        #translate([0.25, 0.25, 0.25]) sphere (0.25);
    }
translate ([0, open_gap, grip_length_open-closed_gap-thickness]) minkowski(){
        #cube([thickness, grip_length_closed, closed_gap+thickness]);
        #translate([0.25, 0.25, 0.25]) sphere (0.25);
}

// rounded and tapered panel module
module rcube(x,y,z){
        //if reverse is true, change x to negative.
    xt = x*(Reverse);
    //if y is larger, create a new z which is 1/2 of original z for the tapered side.
    if (y>z) {
        y2 = y;
        z2 = z/2;
        yt = y*0;
        zt = z/2;
        taper(x, y, z, xt, yt, zt, y2, z2);
    } else if (z>y) {
        //if z is larger, create a new y which is 1/2 of the original y for the tapered side.
        y2 = y/2;
        z2 = z;
        yt = y/2;
        zt = z*0;
        taper(x, y, z, xt, yt, zt, y2, z2);
    }
}

module taper(x, y, z, xt, yt, zt, y2, z2){
    hull(){
        minkowski(){
            cube([1, y, z]);
            translate([0.25, 0.25, 0.25]) sphere (0.25);
        }
        translate ([xt,yt,zt]) cube([1, y2, z2]);
    }
}

rcube(bracket_h_input, thickness, grip_length_open);

translate([0, open_gap, 0]) {
    rcube (bracket_h_input, thickness, grip_length_open-closed_gap);
}
translate([0, open_gap, grip_length_open-closed_gap-thickness]){
    rcube (bracket_h_input,grip_length_closed, thickness);
}

translate([0, open_gap, grip_length_open - thickness ]){
    rcube (bracket_h_input, grip_length_closed, thickness);
}

```


[User]
I'm looking to create a parametric battery storage container, and I'd like to use OpenSCAD to do it. I have some specific requirements, and I want the design to be flexible enough that I can easily adjust the dimensions and layout later.

Here's what I need:

**General Layout:**

*   The container should have a bottom part and a top cover. I'd like to be able to generate just the bottom, just the top, or both as a combined piece.
*   The container will store batteries in a grid-like arrangement. I need to be able to specify the number of rows and columns.
*   I need to control the length, width, and height of each individual battery compartment.
*   I need to define the thickness of the outer walls of the container, the thickness of the top and bottom surfaces, and the thickness of the walls that separate the compartments within the container.
*   I want to be able to specify the radius of the rounded corners for the entire container.

**Top Cover Specifics:**

*   The top cover should fit over the bottom part. I need to define how much extra space is above the top of the battery compartments.
*   There needs to be a connecting wall around the edge of the top cover, which fits over the corresponding wall on the bottom piece. I need to specify the height of this wall.
*   I need to be able to specify an extra height for the top of the cover to make it a bit taller.
*  I need to define the thickness of the connecting wall, and also the tolerance between the top and bottom pieces to ensure a snug fit without being too tight.

**Other Details:**

*   I'm not sure what's best, but I would like to use a good number of segments for smooth curves, perhaps using `$fn = 180;` or something similar.

I'm not familiar with all of the OpenSCAD libraries. I'd just like for you to create the needed SCAD code from scratch for this project.

Could you generate the necessary OpenSCAD files for this? It would be great if the parameters are clearly defined and easy to change in the code.

[Assistant]
battery_case.scad:
```
/* [General] */
// Which part to display
part = "both"; // [bottom, top, both]
// Amount of rows
rows = 5;
// Amount of columns
cols = 4;

// Length of the compartment
length = 17.5;
// Width of the compartment
width = 14;
// Height of the compartment
height = 46.5;

// Outer thickness
outerWall = 3;
// Top and bottom thickness
bottomHeight = 1.25;
// Wall thickness between compartments
innerWalls = 0.8;

// Roundness of the corners
roundness = 2.5;

/* [Top Cover] */
// Height of above the height of the compartment
paddingTop = 17;
// Height of the connecting wall
outerWallTopHeight = 15;
// Extra height of the top piece
extraHeightTop = 7;

// Thickness of the conecting wall on bottom piece
outerWallTop = 1.5;
// Tollerance on the top piece
tolerance = 0.12;

/* [Hidden] */
$fn = 180;
totalWidthOuter = outerWall * 2 + rows * width + (rows -1) * innerWalls;
totalWidth = rows * width + (rows -1) * innerWalls;
totalLengthOuter = outerWall * 2 + cols * length + (cols -1) * innerWalls;
totalLength = cols * length + (cols -1) * innerWalls;

bottomHeightTotal = bottomHeight + height + paddingTop;

if (part == "bottom") {
  bottom();
}
if (part == "top") {
  top();
}
if (part == "both") {
  both();
}

module both() {
  bottom();
  translate([0, totalWidthOuter + 5, 0])
    top();
}

module top() {
  difference() {
    group() {
      //cube([totalLengthOuter, totalWidthOuter, bottomHeight + outerWallTopHeight + extraHeightTop]);
      hull() {
        translate([roundness, roundness, 0])
          cylinder(r = roundness, h = bottomHeight + outerWallTopHeight + extraHeightTop);
        translate([totalLengthOuter - roundness, roundness, 0])
          cylinder(r = roundness, h = bottomHeight + outerWallTopHeight + extraHeightTop);
        translate([totalLengthOuter - roundness, totalWidthOuter - roundness, 0])
          cylinder(r = roundness, h = bottomHeight + outerWallTopHeight + extraHeightTop);
        translate([roundness, totalWidthOuter - roundness, 0])
          cylinder(r = roundness, h = bottomHeight + outerWallTopHeight + extraHeightTop);
      }
    }
    translate([outerWall - outerWallTop - tolerance, outerWall - outerWallTop - tolerance, bottomHeight + extraHeightTop]) {
      //cube([totalLength + (outerWallTop + tolerance) * 2, totalWidth + (outerWallTop + tolerance) * 2, outerWallTopHeight + 1]);

      hull() {
        translate([roundness, roundness, 0])
          cylinder(r = roundness, h = bottomHeight + outerWallTopHeight + extraHeightTop);
        translate([totalLength + (outerWallTop + tolerance) * 2 - roundness, roundness, 0])
          cylinder(r = roundness, h = bottomHeight + outerWallTopHeight + extraHeightTop);
        translate([totalLength + (outerWallTop + tolerance) * 2 - roundness, totalWidth + (outerWallTop + tolerance) * 2 - roundness, 0])
          cylinder(r = roundness, h = bottomHeight + outerWallTopHeight + extraHeightTop);
        translate([roundness, totalWidth + (outerWallTop + tolerance) * 2 - roundness, 0])
          cylinder(r = roundness, h = bottomHeight + outerWallTopHeight + extraHeightTop);
      }
    }

    translate([outerWall, outerWall, bottomHeight]) {
      cube([totalLength, totalWidth, bottomHeightTotal]);
      /*
      hull() {
        translate([roundness, roundness, 0])
          cylinder(r = roundness, h = bottomHeight + outerWallTopHeight + extraHeightTop);
        translate([totalLength - roundness, roundness, 0])
          cylinder(r = roundness, h = bottomHeight + outerWallTopHeight + extraHeightTop);
        translate([totalLength - roundness, totalWidth - roundness, 0])
          cylinder(r = roundness, h = bottomHeight + outerWallTopHeight + extraHeightTop);
        translate([roundness, totalWidth - roundness, 0])
          cylinder(r = roundness, h = bottomHeight + outerWallTopHeight + extraHeightTop);
      }
      */
    }
  }
}

module bottom() {
  difference() {
    group() {
      //cube([totalLengthOuter, totalWidthOuter, bottomHeightTotal - outerWallTopHeight]);
      hull() {
        translate([roundness, roundness, 0])
          cylinder(r = roundness, h = bottomHeightTotal - outerWallTopHeight);
        translate([totalLengthOuter - roundness, roundness, 0])
          cylinder(r = roundness, h = bottomHeightTotal - outerWallTopHeight);
        translate([totalLengthOuter - roundness, totalWidthOuter - roundness, 0])
          cylinder(r = roundness, h = bottomHeightTotal - outerWallTopHeight);
        translate([roundness, totalWidthOuter - roundness, 0])
          cylinder(r = roundness, h = bottomHeightTotal - outerWallTopHeight);
      }
      translate([outerWall-outerWallTop, outerWall-outerWallTop, 0]) {
        //cube([totalLengthOuter - (outerWall-outerWallTop) * 2, totalWidthOuter - (outerWall-outerWallTop) * 2, bottomHeightTotal]);
        hull() {
          translate([roundness, roundness, 0])
            cylinder(r = roundness, h = bottomHeightTotal);
          translate([totalLength + outerWallTop * 2 - roundness, roundness, 0])
            cylinder(r = roundness, h = bottomHeightTotal);
          translate([totalLength + outerWallTop* 2 - roundness, totalWidth + outerWallTop * 2 - roundness, 0])
            cylinder(r = roundness, h = bottomHeightTotal);
          translate([roundness, totalWidth + outerWallTop * 2 - roundness, 0])
            cylinder(r = roundness, h = bottomHeightTotal);
        }
      }
    }

    translate([outerWall, outerWall, bottomHeight + height])
      cube([totalLength, totalWidth, bottomHeightTotal]);

    translate([outerWall, outerWall, bottomHeight]) {
      for(row=[0:1:(rows - 1)]) {
        for(col=[0:1:(cols - 1)]) {
          translate([(length+innerWalls) * col, (width + innerWalls) * row, 0])
            cube([length, width, bottomHeightTotal]);
        }
      }
    }
  }
}
```


[User]
Hey, I'm looking to get some custom filament plaques designed for my storage boxes, and I'd like them to be parametric so I can tweak the size and text easily. I saw this design online that was almost perfect, but I'd like to get something similar designed from scratch, but with a few improvements.

Here’s what I’m looking for:

**Overall Shape & Dimensions:**

*   The plaque should be a rectangular solid with rounded corners (fillets).
*   I need to be able to specify the width, height, and thickness of the plaque as parameters.
*   The fillet radius should be based on a "Border" parameter, which also controls how far the text sits from the edge.

**Text:**

*   There should be two lines for the filament color names, each with its own customizable text size.
*   There should be lines for the filament manufacturer, type (PLA, ABS, etc.), and diameter.
*   These should also have their own customizable text sizes, distinct from the color text sizes.
*   I’d like a parameter to control how deeply the text is extruded into the plaque.
*   I'd prefer the manufacturer text to be centered unless a parameter to show titles is used, in which case it should be left aligned.
*  The type and diameter text should be aligned to the right and left, respectively.
*   I don't need the text to be editable in terms of font itself, but should have a parameter to adjust text spacing.
*    All text should be bold Helvetica.

**Other Features:**

*   I want a parameter to optionally add a hole to the plaque for a key ring and to control the diameter of the hole. The hole should be placed in the upper right.
*   A parameter to control whether a second STL is generated for the text.
*   I want a "Show Titles" parameter that, when set to "yes", will show titles ("MFG:", "TYPE:", and "SIZE:") before the actual text on their respective lines.
*   I need a "Text Spacing" parameter to control the vertical spacing between each line of text.
*   I also need a "Border" parameter that controls the fillet radius and the text offset.

**Libraries:**

I don’t want to use any specific libraries for this project, keep it vanilla OpenSCAD if you can.

Basically, I want to recreate the functionality of that existing design, but in a way that’s more robust and easier to customize. I'm happy to work through the design with you if you have any questions.

[Assistant]
Customizable_Plaque_V2.scad:
```
// preview[view:south, tilt:top]

/* [Filament Information] */
// Color/Name of the Filament for Line 1
Filament_Color_Line_1 = "MIDNIGHT";
// Color/Name of the Filament for Line 2
Filament_Color_Line_2 = "BLACK";
// Name of the Filament Manufacturer
Manufacturer = "NINJAFLEX";
// Type of Filament
Filament_Type = "FLEX"; // [PLA,PLA+,PETG,ABS,NYLON,FLEX,TPU]
//Diameter of Filament
Filament_Size = "1.75"; // [1.75,3.0]
// Text Spacing between each field
Text_Spacing = 5; // Freeform Text Box

/* [Plaque Dimensions] */
// Width of the Plaque
Plaque_Width = 46; // [46:80]
// Height of the Plaque
Plaque_Height = 26; // [26:40]
// Thickness of the Plaque
Plaque_Thickness = 2; // [1:10]
// Color Text Size
Color_Text_Size = 4.5; // [3,3.5,4,4.5,5,5.5,6]
// Mfg Text Size
Mfg_Text_Size = 4; // [3,3.5,4,4.5,5,5.5,6]
// Filament Type Text Size
Type_Text_Size = 4; // [3,3.5,4,4.5,5,5.5,6]
// Filament Size Text Size
Size_Text_Size = 4; // [3,3.5,4,4.5,5,5.5,6]
// Depth of Text going into Plaque
Text_Depth = 0.4; // [0.4,0.6,0.8,1]

/* [Misc Settings] */
// Add Hole to Plaque?
Add_Hole = "no"; // [yes,no]
// Hole Diameter
Hole_Diameter = 4; // [3:8]
// Distance Text is from Edge, this also effects fillet radius. Keep in mind this will not make text wrap or keep it from going off the edge.
Border = 3; // [0:5]
// If you want multi-color files, you can choose to download the STL for the text
Second_Color = "no"; // [yes,no]

/* [Hidden] */
/***************************************/
/* Removed as an option to show Titles */
/* Show Titles for MFG, TYPE and SIZE? */
Show_Titles = "no"; // [yes:no]        */
/***************************************/
BorderOther = 14 + (Mfg_Text_Size * 1.1);
row1 = Plaque_Height / 3 - Border;
row2 = row1 - Text_Spacing;
row3 = row2 - Text_Spacing ;
row4 = row3 - Text_Spacing;
_Label_Text_Depth = Plaque_Thickness / 2 - Text_Depth;
textFont = "Helvetica:style=Bold";
textSpacing = 1.1;
mfgText = "MFG:";
typeText = "TYPE:";
sizeText = "SIZE:";
filletRight = Plaque_Width / 2 - Border;
filletLeft = -(Plaque_Width / 2) + Border;
filletUpper = (Plaque_Height / 2) - Border;
filletLower = -(Plaque_Height / 2) + Border;
filletHeight = -(Plaque_Thickness) + Plaque_Thickness / 2;

// Basic Text Creation
module _textColor1(label) {
    translate ([0, 0, _Label_Text_Depth])
    linear_extrude (height = Text_Depth)
    text(label, size = Color_Text_Size, spacing = textSpacing,valign = "baseline", halign = "center", font = textFont);
}

module _textColor2(label) {
    translate ([0, 0, _Label_Text_Depth])
    linear_extrude (height = Text_Depth)
    text(label, size = Color_Text_Size, spacing = textSpacing,valign = "baseline", halign = "center", font = textFont);
}

module _mfgText(label) {
    union(){
        if (Show_Titles == "yes") {
            translate ([-(Plaque_Width) / 2 + Border, 0,_Label_Text_Depth])
            linear_extrude (height = Text_Depth)
            text(label, size = Mfg_Text_Size, spacing = textSpacing, valign = "baseline", halign = "left", font = textFont);
            translate ([-(Plaque_Width) / 2 + BorderOther, 0,_Label_Text_Depth])
            linear_extrude (height = Text_Depth)
            text(Manufacturer, size = Mfg_Text_Size, spacing = textSpacing, valign = "baseline", halign = "left", font = textFont);
        }
        else if (Show_Titles == "no") {
            translate ([0, 0,_Label_Text_Depth])
            linear_extrude (height = Text_Depth)
            text(Manufacturer, size = Mfg_Text_Size, spacing = textSpacing, valign = "baseline", halign = "center", font = textFont);
        }

    }
}

module _typeText(label) {
    union(){
        if (Show_Titles == "yes") {
            translate ([-(Plaque_Width) / 2 + Border, 0,_Label_Text_Depth])
            linear_extrude (height = Text_Depth)
            text(label, size = Type_Text_Size, spacing = textSpacing, valign = "baseline", halign = "left", font = textFont);
            translate ([-(Plaque_Width) / 2 + BorderOther, 0,_Label_Text_Depth])
            linear_extrude (height = Text_Depth)
            text(Filament_Type, size = Type_Text_Size, spacing = textSpacing, valign = "baseline", halign = "left", font = textFont);
        }
        else if (Show_Titles == "no") {
            translate ([-(len(Filament_Type)), 0,_Label_Text_Depth])
            linear_extrude (height = Text_Depth)
            text(Filament_Type, size = Type_Text_Size, spacing = textSpacing, valign = "baseline", halign = "right", font = textFont);
        }
    }
}

module _sizeText(label) {
    union(){
        if (Show_Titles == "yes") {
            translate ([-(Plaque_Width) / 2 + Border, 0,_Label_Text_Depth])
            linear_extrude (height = Text_Depth)
            text(label, size = Size_Text_Size, spacing = textSpacing, valign = "baseline", halign = "left", font = textFont);
            translate ([-(Plaque_Width) / 2 + BorderOther, 0,_Label_Text_Depth])
            linear_extrude (height = Text_Depth)
            text(Filament_Size, size = Size_Text_Size, spacing = textSpacing, valign = "baseline", halign = "left", font = textFont);
        }
        else if (Show_Titles == "no") {
            translate ([len(Filament_Size), 0,_Label_Text_Depth])
            linear_extrude (height = Text_Depth)
            text(Filament_Size, size = Size_Text_Size, spacing = textSpacing, valign = "baseline", halign = "left", font = textFont);
        }
    }
}

module _textCreation() {
        union(){
            translate ([0, row1, 0]) _textColor1(Filament_Color_Line_1);
            translate ([0, row2, 0]) _textColor2(Filament_Color_Line_2);
            translate ([0, row3, 0]) _mfgText(mfgText);
            translate ([0, row4, 0]) _typeText(typeText);
            translate ([0, row4, 0]) _sizeText(sizeText);
    }
}

module _addHole() {
    translate ([(Plaque_Width / 2) - (Hole_Diameter + Border),-((Plaque_Height / 2) - (Hole_Diameter + Border)), -(Plaque_Thickness / 2)]) cylinder (r=Hole_Diameter, Plaque_Thickness, $fn=360);
}

// Plaque Creation
module _plaque() {
    intersection(){
        translate([0,0,0]) cube ([Plaque_Width, Plaque_Height, Plaque_Thickness], true);
        union(){
            translate([filletRight, filletUpper, filletHeight]) cylinder(h=Plaque_Thickness, r=Border, $fn=360);
            translate([filletRight, filletLower, filletHeight]) cylinder(h=Plaque_Thickness, r=Border, $fn=360);
            translate([filletLeft, filletUpper, filletHeight]) cylinder(h=Plaque_Thickness, r=Border, $fn=360);
            translate([filletLeft, filletLower, filletHeight]) cylinder(h=Plaque_Thickness, r=Border, $fn=360);
            translate([0,0,0]) cube ([Plaque_Width - (Border * 2), Plaque_Height, Plaque_Thickness], true);
            translate([0,0,0]) cube ([Plaque_Width, Plaque_Height - (Border * 2), Plaque_Thickness], true);
        }
    }
}

if (Second_Color == "yes") {_textCreation();}
    else if (Second_Color == "no") {
        difference(){
            _plaque();
            _textCreation();
            if (Add_Hole == "yes") _addHole();
        }
    }
```


[User]
Hey, I'm looking for some help designing a customizable enclosure for my electronics projects. I really like the idea behind this "Cheesy Electronics Enclosure," and want to make something similar, but from scratch.

The basic idea is to have a two-part enclosure: a front panel and a box, that will screw together with some mounting blocks. The front panel will have mounting holes for attaching to a standard mounting rail (like Eurorack), and it should also have mounting holes for attaching it to the box itself using screws. I also want the option for a compartment to hold a 9V battery, and some cutouts on the front panel for aesthetics.

Here are the specifics:

**General Parameters:**

*   I need a way to select which part I want to generate: front panel, box, or battery clip.
*   The front panel should have parameters for height and width.
*   The enclosure depth will be a parameter, too.
*   There should be an option for including/excluding the battery compartment.

**Front Panel:**

*   The front panel needs mounting holes for attaching to a mounting rail. I'm using a 0.2" horizontal grid for that. I would like to specify the horizontal unit distance as a parameter. The mounting holes should be set back slightly from the edge.
*   There should also be mounting holes for attaching the front panel to the box.
*   I need to be able to set the panel thickness, as well as the thickness of any extra frame.
*   There should be options for cutouts on the front panel (the 'Chez holes'). It would be really cool if I could define the position and diameter of these cutouts.
*   If a battery compartment is included, it should be rectangular, have customizable width, height and depth, and be positioned to fit with the case design.
*   There needs to be a place to define the dimensions of the space for the actual front panel section (it's not just one whole rectangle.)

**Box:**

*   The box will need a parameter for enclosure wall thickness.
*   There needs to be an offset for the box to the rail (the "enclosureToRailTolerance").
*   I need to define the screw distance to the edge.
*   The box needs to include mounting blocks, positioned to line up with the mounting holes on the front panel, that are sized for the screw heads, and the screws themselves.
*   I also want to include some brackets for general mounting purposes, that have a slot in the center. These need to run all the way up the depth of the enclosure.
*   If I have the battery compartment option enabled, I'll need a "ledge" on the interior of the box to sit beneath the compartment on the front panel.

**Battery Clip:**

*   This should be a separate, optional part.
*  I need a way to define the depth of the battery clip, and how far the sides will extent outward towards the battery.
*   The clip needs to be designed to hold the battery firmly in the compartment.

I'm okay with working with multiple OpenSCAD files. I don't need any libraries included other than the standard OpenSCAD libraries. I am looking forward to seeing what you can put together.

[Assistant]
cheesy-enclosure.scad:
```
// "Cheesy Electronics Enclosure" provided by Stellar Innovation
// http://www.thingiverse.com/stellarinnovation/about
// under Creative Commons License, Attribution (BY)

// Select part to print
partToPrint = 1; // [1:front, 2:box, 3:battery clip]

// Panel height
panelHeight = 128.5;  // [40.0:0.5:240.0]

// Panel width
panelWidth = 70.5;  // [25.0:0.1:225.0]

// Enclosure depth
enclosureDepth = 40; // [25.0:0.5:65.0]

// With battery compartment
withBattery = "yes";  // [yes,no]

// Mounting screws on a 0.2" horizontal grid
horizontalUnit = 1*5.08;
mountingHoleHorizontalDistance = horizontalUnit*floor((panelWidth-14.5)/horizontalUnit);
mountingHoleVerticalDistance = panelHeight - 6;

// Panel thickness
mountingFrameThickness = 1*2;
chezPanelThickness = 1*4;

// Mounting holes (panel to mounting rail)
mountingHoleX = 0.5*mountingHoleHorizontalDistance;
mountingHoleY = 0.5*mountingHoleVerticalDistance;
mountingHoleDiameter = 1*3.4;
mountingHeadDiameter = 1*7;
mountingRailHeight = max(0, panelHeight - mountingHoleVerticalDistance);

// Box dimensions
enclosureWidth = panelWidth;
enclosureWallThickness = 1*2;
enclosureToRailTolerance = 1*1.0;
enclosureScrewDistance = 1*3;
enclosureHeight = panelHeight - 2*(mountingRailHeight + enclosureToRailTolerance);
enclosureScrewX = 0.5*enclosureWidth - enclosureWallThickness - enclosureScrewDistance;
enclosureScrewY = 0.5*enclosureHeight - enclosureWallThickness - enclosureScrewDistance;
enclosureScrewDiameter = 1*3.4;
enclosureScrewHeadDiameter = 1*7;

// Battery dimensions
batteryWidth = 1*47;
batteryHeight = 1*15.5;
batteryDepth = 1*26.5;
batterySlotWidth = 1*52;
batterySlotHeight = batteryHeight + 2;
battery_x0 = -0.5*batterySlotWidth;
battery_y0 = -enclosureScrewY + 0.5*enclosureScrewHeadDiameter + enclosureWallThickness + 1;
batteryClipWidth=1*10;

if (partToPrint==1)
  FrontPanelPart();
else if (partToPrint==2)
  BoxPart();
else if (partToPrint==3)
  BatteryClipPart();

module FrontPanelPart() {
  difference() {
    BoxWithRadius(panelWidth, panelHeight, chezPanelThickness, radius=2);

    MountingHoles();
    EnclosureScrews(chezPanelThickness);
    ChezHoles();

    // Battery compartment
    if (withBattery=="yes")
      translate([0, battery_y0+0.5*batterySlotHeight])
        BoxWithRadius(batterySlotWidth, batterySlotHeight, chezPanelThickness, radius=2);

    // actual front panel (lower part)
    panel_x1 = enclosureScrewX - enclosureScrewDistance;
    panel_y1 = enclosureScrewY - enclosureScrewDistance;
    panel_y0 = (withBattery=="yes")? battery_y0 + batterySlotHeight + 5 : -panel_y1;
    panel_y_mid = 0.5*(panel_y0 + panel_y1);
    w = 2*panel_x1;
    h = panel_y1 - panel_y0;

    translate([0, panel_y_mid, mountingFrameThickness])
      BoxWithRadius(w, h, chezPanelThickness, radius=2);
   }
}

module BoxPart() {
  z1 = enclosureDepth + enclosureWallThickness;

  difference() {
    union() {
      BasicBox();
      MountingBlocks(enclosureScrewHeadDiameter + 2*enclosureWallThickness, z1);
      BatteryClipLedger();
    }

    MountingBlocks(enclosureScrewHeadDiameter, enclosureDepth);
    EnclosureScrews(z1);
  }

  for (k = [-0.37, -0.17, +0.17, +0.37])
    translate([0, k*enclosureHeight])
      BracketWithSlot();
}

module BatteryClipPart() {
  clearance = 3;
  z2 = min(enclosureDepth-clearance, 0.6*batteryDepth);
  z1 = min(enclosureDepth-clearance - 5, 0.4*batteryDepth);
  z0 = enclosureDepth - clearance - z2;

  HalfABatteryClip(z0, z1, z2, batteryClipWidth);
  mirror([1, 0, 0])
     HalfABatteryClip(z0, z1, z2, batteryClipWidth);
}

module MountingHoles() {
   r = 0.5*mountingHeadDiameter;
   x1 = 0.5*panelWidth;
   y1 = max(0.5*panelHeight, mountingHoleY + r);
   z1 = mountingFrameThickness;
   dist_y = y1 - mountingHoleY;

   for (x=[-mountingHoleX, +mountingHoleX], y=[-mountingHoleY, +mountingHoleY]) {
     translate([x, y])
       cylinder(d=mountingHoleDiameter, h=mountingFrameThickness+chezPanelThickness, $fn=24);
     translate([x, y, z1])
       cylinder(d=mountingHeadDiameter, h=chezPanelThickness, $fn=48);
   }

   for (x=[-x1, mountingHoleX], y=[-y1, mountingHoleY - r])
     translate([x, y, z1])
       cube([x1-mountingHoleX, dist_y + r, chezPanelThickness]);

   x2 = mountingHoleX - r;
   for (x=[-mountingHoleX, x2], y=[-y1, mountingHoleY])
     translate([x, y, z1])
      cube([r, r, chezPanelThickness]);
}

module EnclosureScrews(length) {
  for (p = [[enclosureScrewX, 0], [-enclosureScrewX, 0], [0, enclosureScrewY], [0, -enclosureScrewY]])
    translate(p)
      cylinder(d=enclosureScrewDiameter, h=length, $fn=6);
}

module ChezHoles() {
   x0 = -0.5*panelWidth;

   ChezHole(x0+19, 10, 25);
   ChezHole(x0-1, 0.3*panelHeight, 16);
   ChezHole(-0.15*panelWidth, 0.5*panelHeight-4, 15);
   ChezHole(0.34*panelWidth, 0.15*panelHeight, 13);
   ChezHole(0.37*panelWidth, -0.05*panelHeight, 8);
   ChezHole(0.42*panelWidth, -0.13*panelHeight, 18);
   ChezHole(0.15*panelWidth, -0.45*panelHeight, 12);
   ChezHole(battery_x0, battery_y0 + 0.5*batterySlotHeight, 15);
   ChezHole(x0+10, -5.8, 10);
}

module ChezHole(x, y, diam) {
  dz = min(diam, 2*chezPanelThickness);
  z = mountingFrameThickness + chezPanelThickness;

  translate([x, y, z])
    scale([1, 1, dz/diam])
      sphere(d=diam);
}

module BoxWithRadius(width, height, depth, radius) {
  w = 0.5*width - radius;
  h = 0.5*height - radius;

  for (x=[-w, +w], y=[-h, +h])
    translate([x, y])
      cylinder(r=radius, h=depth, $fn=12);
  translate([-w, -0.5*height])
    cube([2*w, height, depth]);
  translate([-0.5*width, -h])
    cube([width, 2*h, depth]);
}

module BasicBox() {
  x1 = 0.5*enclosureWidth - enclosureWallThickness;
  y1 = 0.5*enclosureHeight - enclosureWallThickness;
  z1 = enclosureDepth + enclosureWallThickness;
  difference() {
    BoxWithRadius(enclosureWidth, enclosureHeight, z1, radius=enclosureWallThickness);

    translate([-x1, -y1, enclosureWallThickness])
      cube([2*x1, 2*y1, z1]);
  }
}

module MountingBlocks(diam, z1) {
  x0 = 0.5*enclosureWidth;
  y0 = 0.5*enclosureHeight;
  r = 0.5*diam;

  intersection() {
    for (p = [[enclosureScrewX, 0], [-enclosureScrewX, 0], [0, enclosureScrewY], [0, -enclosureScrewY]])
      translate(p)
        cylinder(r=r, h=z1, $fn=60);

    translate([-x0, -y0])
      cube([2*x0, 2*y0, z1]);
 }

  w = x0-enclosureScrewX;
  h = y0-enclosureScrewY;
  translate([-enclosureScrewX-w, -r]) cube([w, 2*r, z1]);
  translate([enclosureScrewX, -r]) cube([w, 2*r, z1]);
  translate([-r, -enclosureScrewY-h]) cube([2*r, h, z1]);
  translate([-r, enclosureScrewY]) cube([2*r, h, z1]);
}

module BracketWithSlot() {
  z1 = enclosureDepth + enclosureWallThickness;
  x1 = 0.5*enclosureWidth;
  bracket_w = enclosureWallThickness + 2.5;
  bracket_slot = 2;
  bracket_h = 2*enclosureWallThickness + bracket_slot;

  translate([0, -0.5*bracket_h])
    difference() {
      union() {
        translate([-x1, 0]) cube([bracket_w, bracket_h, z1]);
        translate([x1-bracket_w, 0]) cube([bracket_w, bracket_h, z1]);
      }

       translate([-x1+enclosureWallThickness, enclosureWallThickness, 0])
         cube([enclosureWidth - 2*enclosureWallThickness, bracket_slot, z1]);
    }
}

module BatteryClipLedger() {
  w = enclosureWidth - 2*enclosureWallThickness;
  x1 = 0.5*w;
  y1 = 0.5*enclosureHeight;
  h = y1 - (-battery_y0 - 0.5*batterySlotHeight + 15.5);
  t = 2*enclosureWallThickness;
  translate([-x1, -y1]) cube([w, h, t]);
  translate([-x1, y1-h]) cube([w, h, t]);
}

module HalfABatteryClip(z0, z1, z2, w) {
  t = 2;
  r = 0.5*t;
  x0 = r;
  y0 = z1;
  a=30;
  c = cos(a);
  s = sin(a);
  x1 = x0-r*c;
  y1 = y0-r*s;
  x2_bis = x1 + y1*s/c;
  x2_prim = x2_bis - r*s/c;
  x2 = x2_prim - r;
  y2 = r;
  x2_t = x2 + r*c;
  y2_t = y2 + r*s;
  x3_bis = x2_bis + t/c;
  y3_t = r*s;
  x3_t = x3_bis - y3_t*s/c;
  x3_c = x3_t - r*c;
  x3 = x3_c + r;

  x5 = x0 + 2*r/c;
  y5 = y0;

  x4 = x5 - r*c;
  y4 = y5 - r*s;
  x6 = x4;
  y6 = y5 + r*s;

  y7 = z2;
  x7 = x6 + (y7-y6)*s/c;
  x8 = x7 - t/c;
  y8 = y7;
  x9 = x1;
  y9 = y0 + r*s;

  minusTolerance = 0.5;
  h0 = 0.5*batteryHeight - minusTolerance;
  translate([h0, z0])
    linear_extrude(height=w)
      difference() {
        union() {
          translate([x0, y0])
            circle(d=t, $fn=24);
          translate([x3_c, 0])
            circle(d=t, $fn=24);
          polygon([[x0,y0], [x1,y1],
                   [x2_t, y2_t], [x2, y2], [x2,0],
                   [x3,0], [x3_t, y3_t],
                   [x4,y4], [x5,y5], [x6,y6],
                   [x7,y7], [x8,y8], [x9,y9]]);
        }

        translate([x2, y2])
          circle(d=t, $fn=24);
        translate([x5, y5])
          circle(d=t, $fn=24);
      }

  cube([x3 + h0, z0, w]);
}

```


[User] I need a parametric bracket design, something that can act as a holder, clip, grip, hook, or hanger. I'd like to be able to customize the diameter of the clip itself, the thickness of the whole bracket, and the screw gauge it uses. The idea is to be able to mount things like pipes or broomsticks securely. I'm looking for a design that uses a half-cylinder for the main clip, with a rectangular section extending out on one side. I would also like screw holes to be generated for mounting. It would be nice if the screw hole generation took into account the thickness of the part, ideally having screw holes on both sides if the part is thick enough. It needs to be parametric using OpenSCAD.

[Assistant]
bracket.scad:
```
// bracket.scad
// library for parametric Holder, Clip, Grip, Hook, Hanger, Bracket
// Author: Tony Z. Tonchev, Michigan (USA)
// last update: October 2018

// (in mm)
Clip_Diameter = 30;

// (in mm)
Clip_Thickness = 15;

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

/* [Hidden] */

$fn=100;
TZT_Rad=Clip_Diameter/2;
TZT_Thk=Clip_Thickness;
TZT_Scr=Screw_Gauge;

difference () {
    TZT_CLIP();
    if ((TZT_Thk/8)<TZT_Scr) {
        TZT_SCREW();
    } else {
        translate ([0,0,TZT_Thk/4]) {
            TZT_SCREW();
        }
        translate ([0,0,-TZT_Thk/4]) {
            TZT_SCREW();
        }

    }
}

module TZT_SCREW () {
    translate ([-TZT_Rad*.98,0,0]) {
        rotate ([0,-90,0]) {
            cylinder (TZT_Scr*1.1,TZT_Scr,0);
            cylinder (TZT_Rad*.6,TZT_Scr/2,TZT_Scr/2);
            translate ([0,0,-TZT_Scr]) {
                cylinder (TZT_Scr*1.1,TZT_Scr,TZT_Scr);
            }
        }
    }
}

module TZT_CLIP () {
    difference () {
        union () {
            translate ([-TZT_Rad*1.1,0,0]) {
                difference () {
                    cube ([TZT_Rad*.6,TZT_Rad*2.2,TZT_Thk],true) ;
                    translate ([TZT_Rad*.2,TZT_Rad*1.07,0]) {
                        cylinder (TZT_Thk*1.1,TZT_Rad*.2,TZT_Rad*.2,true);
                    }
                    translate ([TZT_Rad*.2,-TZT_Rad*1.07,0]) {
                        cylinder (TZT_Thk*1.1,TZT_Rad*.2,TZT_Rad*.2,true);
                    }

                }
            }
            cylinder (TZT_Thk,TZT_Rad*1.2,TZT_Rad*1.2,true);
        }
        cylinder (TZT_Thk*4,TZT_Rad,TZT_Rad,true);
        translate ([TZT_Rad*1.3,0,0]) {
            cylinder (TZT_Thk+1,TZT_Rad,TZT_Rad,true);
        }
    }
    for (TZT_i=[-50:100:50]) {
        rotate ([0,0,TZT_i]) {
            translate ([TZT_Rad*1.1,0,0]) {
                cylinder (TZT_Thk,TZT_Rad*.2,TZT_Rad*.2,true);
            }
        }
    }
}
```


[User]
I'd like to create a parametric keychain generator, and I'm looking for an OpenSCAD design that can do this. The core idea is to have an oval-shaped base, created by hulling two cylinders, with a hole at one end for a keyring. The text of the keychain will be variable based on the input, and it should be centered along the length of the oval.

Here are the specifics:

*   **Base Shape:** The base should be an oval created by using `hull()` on two `cylinder()` shapes. Both cylinders should have a height of 2, and a diameter of 22. The second cylinder should be translated along the X-axis to create the oval shape.
*   **Oval Length:** The length of the oval is determined by the text input; specifically it should be `len(text) * 8`. So if the text is "Test," the length should be 4 * 8 = 32. In terms of how the cylinders should be positioned, the first cylinder should be at [0,0,0] and the second cylinder should be translated [length+8,0,0] for the oval hulling.
*   **Hole:** A cylindrical hole needs to be cut out at the far end of the oval. It also needs to have a height of 2, and a diameter of 17. Its center should be at the same X coordinate as the center of the second cylinder.
*   **Text:** The text should be extruded using `linear_extrude()` with a height of 3. The text should be resized along the X-axis to fit within the oval, and it should be centered vertically on the oval.
*  **Text Positioning:** This part might be a little tricky. There's an adjustment that needs to happen when the input text includes "y", "g", "p", "q", or "j". In that case, the text needs to be moved down by 1 unit on the Y axis. Specifically, an additional `translate([-5,-1,0])` needs to occur before the `linear_extrude` when these characters are present, otherwise the `translate` before the linear extrude should just be `([-5,0,0])`.
*   **Parametric:** The design needs to be parametric, with the ability to change the text input to generate different keychains. We need to make sure the length of the oval scales appropriately with the text length.
*   **Rendering:** I'd like the base to be rendered as black so it's easy to visualize while the text should have its default render color.
*   **Resolution:** I'd like to set `$fn` to 360 for high quality curves

I think that should cover everything. Let me know if you need any more information.

[Assistant]
TextKeychainGenerator.scad:
```
/*
Text Keychain Generator
B_Layne
https://www.thingiverse.com/B_Layne/designs
*/

$fn=360; //resolution of curves

Text="Keychain";
length2=len(Text);

length = length2*8; //length of input text multiplied by 8

difference(){
    //Makes oval base and cuts a circle out at the far end
    hull(){
        cylinder(h=2, d=22);
        translate([length+8,0,0])
        cylinder(h=2, d=22);
    }
    translate([length+8,0,0]) //Positions the hole to cut
    cylinder(h=2, d=17);
    }
    color("black") //only for rendering
    //Moves all text down to center string when ygpqj are in input
    if(search("ygpqj", Text)){
        translate([-5, -1, 0])
            linear_extrude(3)
                resize([length, 0], auto = true)
                    text(Text, valign = "center");
    }
    else{
        translate([-5, 0, 0])
            linear_extrude(3)
                resize([length, 0], auto = true)
                    text(Text, valign = "center");
    }
```


[User]
I'm looking to create a wire shelf belt clip, and I'd like the design to be parametric so I can adjust it for different shelves and belts. I have a basic idea for the shape - it's essentially three rings stacked horizontally, with a gap in the top one and an opening in the bottom one, and they're connected.

Specifically, the top ring will be a simple circle with a gap cut out to allow the wire shelf to be inserted, with the gap being created by cutting out a square. The middle ring is just a solid circle intended to act as a spacer. The bottom ring is similar to the top one but needs to have a larger diameter and an opening to allow the belt to pass through. I'd like to create that opening by using a rotated rectangle cutout at the bottom of the ring.

Here's a breakdown of the parameters I think I need:

*   **`extrude`**: The thickness of the entire clip.
*   **`top_clip_inner`**: The inner diameter of the top ring.
*   **`mid_clip_inner`**: The inner diameter of the middle ring.
*   **`bot_clip_inner`**: The inner diameter of the bottom ring.
*   **`opening_scale`**: A multiplier (between 0 and 1) to scale the size of the opening on the bottom ring relative to its inner diameter.
*  **`tilt`**: The rotation of the opening on the bottom ring.
*   **`top_thickness`**: The thickness of the top ring.
*   **`mid_thickness`**: The thickness of the middle ring.
*   **`bot_thickness`**: The thickness of the bottom ring.

I think a single scad file should be sufficient. Could you generate the OpenSCAD code based on this? I don't need any libraries.

[Assistant]
WireShelfBeltClip.scad:
```

// Width of clip
extrude=6; // [3:25]

/* [Ring inside diameters] */
// Top
top_clip_inner=3; // [1:0.1:10]
// Middle
mid_clip_inner=6; // [1:25]
// Bottom
bot_clip_inner=14; // [1:50]

/* [Bottom Opening] */
// Size
opening_scale=0.75; // [0.4:0.05:1]
// Rotation
tilt=-15; //[-30:5:210]

/* [Wall Thickness] */
// Top ring
top_thickness=1.6; // [1:0.1:3]
// Middle ring
mid_thickness=1.6; // [1:0.1:3]
// Bottom ring
bot_thickness=1.6; // [1:0.1:5]

/* [Hidden] */
$fn=120; // control circle smoothness
top_outer=top_clip_inner + 2*top_thickness;
mid_outer=mid_clip_inner + 2*mid_thickness;
bot_outer=bot_clip_inner + 2*bot_thickness;
lip_out=bot_clip_inner*opening_scale; // opening size (relative to inner ring diameter)

translate([-(bot_outer+mid_outer)/2,0,0]) // center part on x-axis
linear_extrude(height=extrude) {

    // Top clip
    translate([-((top_outer/2)-top_thickness),0,0])
    difference()
    {
        circle(d=top_outer);
        circle(d=top_clip_inner); // wire diameter
        square(size=top_outer/2, center=false); // opening
    }

    // middle clip (spacer to allow easier access to bottom clip)
    translate([mid_outer/2,0,0])
    difference()
    {
        circle(d=mid_outer);
        circle(d=mid_clip_inner);
    }

    // Bottom clip
    translate([mid_outer+(bot_outer/2)-mid_thickness,0,0]) rotate(tilt)
    difference()
    {
        union () {
            circle(d=bot_outer);
            translate([0,-lip_out/2,0]) square([lip_out,lip_out], center=true);
        }
        circle(d=bot_clip_inner);
        translate([0,-lip_out/2,0]) square([lip_out-(2*bot_thickness),lip_out], center=true);
    }

}
```


[User]
Hey, I'm looking for a customizable label generator in OpenSCAD. I'd like to be able to set the label's width and height, and also the text, font, and font size. Basically, I'm trying to make something like those classic, utilitarian labels you see everywhere, you know?

The label should be a rectangular plate with rounded ends and some mounting holes. I'd like a few different mounting options - maybe a couple of small holes at each end and, since I'm using screws, have some cylinders around the mounting holes for countersinking to make it more durable.

The text should be centered on the label, and I need to be able to change the text itself, along with the font and size of that text. I'm aiming for a design that's easy to print, ideally good for dual extruders. I’m going to want to be able to use Google Fonts, so I need that flexibility built in.  It should be a parametric design, so I can adjust all of these values easily. Also, could we set a default height for the label? I'm thinking 1.5mm for the text and 3mm for the overall label, and I want the text recessed slightly.

Could you whip something up for me?

[Assistant]
label.scad:
```
// label.scad
// library for parametric Label, Tag, Sign, ID, Marker, Plaque
// Author: Tony Z. Tonchev, Michigan (USA)
// last update: November 2018

//
Message = "MESSAGE";

// (in mm)
Label_Width = 65;

// (in mm)
Label_Height = 20;

/* [Font Details] */

// Platform specific font name (In Customizer: http://www.google.com/fonts)
Font_Name="Alef"; //[ABeeZee,Abel,Abril Fatface,Aclonica,Acme,Actor,Adamina,Advent Pro,Aguafina Script,Akronim,Aladin,Aldrich,Alef,Alegreya,Alegreya Sans,Alegreya Sans SC,Alegreya SC,Alex Brush,Alfa Slab One,Alice,Alike,Alike Angular,Allan,Allerta,Allerta Stencil,Allura,Almendra,Almendra Display,Almendra SC,Amarante,Amaranth,Amatic SC,Amethysta,Amiri,Anaheim,Andada,Andika,Angkor,Annie Use Your Telescope,Anonymous Pro,Antic,Antic Didone,Antic Slab,Anton,Arapey,Arbutus,Arbutus Slab,Architects Daughter,Archivo Black,Archivo Narrow,Arimo,Arizonia,Armata,Artifika,Arvo,Asap,Asset,Astloch,Asul,Atomic Age,Aubrey,Audiowide,Autour One,Average,Average Sans,Averia Gruesa Libre,Averia Libre,Averia Sans Libre,Averia Serif Libre,Bad Script,Balthazar,Bangers,Basic,Battambang,Baumans,Bayon,Belgrano,Belleza,BenchNine,Bentham,Berkshire Swash,Bevan,Bigelow Rules,Bigshot One,Bilbo,Bilbo Swash Caps,Bitter,Black Ops One,Bokor,Bonbon,Boogaloo,Bowlby One,Bowlby One SC,Brawler,Bree Serif,Bubblegum Sans,Bubbler One,Buda,Buenard,Butcherman,Butterfly Kids,Cabin,Cabin Condensed,Cabin Sketch,Caesar Dressing,Cagliostro,Calligraffitti,Cambay,Cambo,Candal,Cantarell,Cantata One,Cantora One,Capriola,Cardo,Carme,Carrois Gothic,Carrois Gothic SC,Carter One,Caudex,Cedarville Cursive,Ceviche One,Changa One,Chango,Chau Philomene One,Chela One,Chelsea Market,Chenla,Cherry Cream Soda,Cherry Swash,Chewy,Chicle,Chivo,Cinzel,Cinzel Decorative,Clicker Script,Coda,Coda Caption,Codystar,Combo,Comfortaa,Coming Soon,Concert One,Condiment,Content,Contrail One,Convergence,Cookie,Copse,Corben,Courgette,Cousine,Coustard,Covered By Your Grace,Crafty Girls,Creepster,Crete Round,Crimson Text,Croissant One,Crushed,Cuprum,Cutive,Cutive Mono,Damion,Dancing Script,Dangrek,Dawning of a New Day,Days One,Dekko,Delius,Delius Swash Caps,Delius Unicase,Della Respira,Denk One,Devonshire,Dhurjati,Didact Gothic,Diplomata,Diplomata SC,Domine,Donegal One,Doppio One,Dorsa,Dosis,Dr Sugiyama,Droid Sans,Droid Sans Mono,Droid Serif,Duru Sans,Dynalight,Eagle Lake,Eater,EB Garamond,Economica,Ek Mukta,Electrolize,Elsie,Elsie Swash Caps,Emblema One,Emilys Candy,Engagement,Englebert,Enriqueta,Erica One,Esteban,Euphoria Script,Ewert,Exo,Exo 2,Expletus Sans,Fanwood Text,Fascinate,Fascinate Inline,Faster One,Fasthand,Fauna One,Federant,Federo,Felipa,Fenix,Finger Paint,Fira Mono,Fira Sans,Fjalla One,Fjord One,Flamenco,Flavors,Fondamento,Fontdiner Swanky,Forum,Francois One,Freckle Face,Fredericka the Great,Fredoka One,Freehand,Fresca,Frijole,Fruktur,Fugaz One,Gabriela,Gafata,Galdeano,Galindo,Gentium Basic,Gentium Book Basic,Geo,Geostar,Geostar Fill,Germania One,GFS Didot,GFS Neohellenic,Gidugu,Gilda Display,Give You Glory,Glass Antiqua,Glegoo,Gloria Hallelujah,Goblin One,Gochi Hand,Gorditas,Goudy Bookletter 1911,Graduate,Grand Hotel,Gravitas One,Great Vibes,Griffy,Gruppo,Gudea,Gurajada,Habibi,Halant,Hammersmith One,Hanalei,Hanalei Fill,Handlee,Hanuman,Happy Monkey,Headland One,Henny Penny,Herr Von Muellerhoff,Hind,Holtwood One SC,Homemade Apple,Homenaje,Iceberg,Iceland,IM Fell Double Pica,IM Fell Double Pica SC,IM Fell DW Pica,IM Fell DW Pica SC,IM Fell English,IM Fell English SC,IM Fell French Canon,IM Fell French Canon SC,IM Fell Great Primer,IM Fell Great Primer SC,Imprima,Inconsolata,Inder,Indie Flower,Inika,Irish Grover,Istok Web,Italiana,Italianno,Jacques Francois,Jacques Francois Shadow,Jim Nightshade,Jockey One,Jolly Lodger,Josefin Sans,Josefin Slab,Joti One,Judson,Julee,Julius Sans One,Junge,Jura,Just Another Hand,Just Me Again Down Here,Kalam,Kameron,Kantumruy,Karla,Karma,Kaushan Script,Kavoon,Kdam Thmor,Keania One,Kelly Slab,Kenia,Khand,Khmer,Khula,Kite One,Knewave,Kotta One,Koulen,Kranky,Kreon,Kristi,Krona One,La Belle Aurore,Laila,Lakki Reddy,Lancelot,Lateef,Lato,League Script,Leckerli One,Ledger,Lekton,Lemon,Liberation Sans,Libre Baskerville,Life Savers,Lilita One,Lily Script One,Limelight,Linden Hill,Lobster,Lobster Two,Londrina Outline,Londrina Shadow,Londrina Sketch,Londrina Solid,Lora,Love Ya Like A Sister,Loved by the King,Lovers Quarrel,Luckiest Guy,Lusitana,Lustria,Macondo,Macondo Swash Caps,Magra,Maiden Orange,Mako,Mallanna,Mandali,Marcellus,Marcellus SC,Marck Script,Margarine,Marko One,Marmelad,Martel Sans,Marvel,Mate,Mate SC,Maven Pro,McLaren,Meddon,MedievalSharp,Medula One,Megrim,Meie Script,Merienda,Merienda One,Merriweather,Merriweather Sans,Metal,Metal Mania,Metamorphous,Metrophobic,Michroma,Milonga,Miltonian,Miltonian Tattoo,Miniver,Miss Fajardose,Modak,Modern Antiqua,Molengo,Molle,Monda,Monofett,Monoton,Monsieur La Doulaise,Montaga,Montez,Montserrat,Montserrat Alternates,Montserrat Subrayada,Moul,Moulpali,Mountains of Christmas,Mouse Memoirs,Mr Bedfort,Mr Dafoe,Mr De Haviland,Mrs Saint Delafield,Mrs Sheppards,Muli,Mystery Quest,Neucha,Neuton,New Rocker,News Cycle,Niconne,Nixie One,Nobile,Nokora,Norican,Nosifer,Nothing You Could Do,Noticia Text,Noto Sans,Noto Serif,Nova Cut,Nova Flat,Nova Mono,Nova Oval,Nova Round,Nova Script,Nova Slim,Nova Square,NTR,Numans,Nunito,Odor Mean Chey,Offside,Old Standard TT,Oldenburg,Oleo Script,Oleo Script Swash Caps,Open Sans,Open Sans Condensed,Oranienbaum,Orbitron,Oregano,Orienta,Original Surfer,Oswald,Over the Rainbow,Overlock,Overlock SC,Ovo,Oxygen,Oxygen Mono,Pacifico,Paprika,Parisienne,Passero One,Passion One,Pathway Gothic One,Patrick Hand,Patrick Hand SC,Patua One,Paytone One,Peddana,Peralta,Permanent Marker,Petit Formal Script,Petrona,Philosopher,Piedra,Pinyon Script,Pirata One,Plaster,Play,Playball,Playfair Display,Playfair Display SC,Podkova,Poiret One,Poller One,Poly,Pompiere,Pontano Sans,Port Lligat Sans,Port Lligat Slab,Prata,Preahvihear,Press Start 2P,Princess Sofia,Prociono,Prosto One,PT Mono,PT Sans,PT Sans Caption,PT Sans Narrow,PT Serif,PT Serif Caption,Puritan,Purple Purse,Quando,Quantico,Quattrocento,Quattrocento Sans,Questrial,Quicksand,Quintessential,Qwigley,Racing Sans One,Radley,Rajdhani,Raleway,Raleway Dots,Ramabhadra,Ramaraja,Rambla,Rammetto One,Ranchers,Rancho,Ranga,Rationale,Ravi Prakash,Redressed,Reenie Beanie,Revalia,Ribeye,Ribeye Marrow,Righteous,Risque,Roboto,Roboto Condensed,Roboto Slab,Rochester,Rock Salt,Rokkitt,Romanesco,Ropa Sans,Rosario,Rosarivo,Rouge Script,Rozha One,Rubik Mono One,Rubik One,Ruda,Rufina,Ruge Boogie,Ruluko,Rum Raisin,Ruslan Display,Russo One,Ruthie,Rye,Sacramento,Sail,Salsa,Sanchez,Sancreek,Sansita One,Sarina,Sarpanch,Satisfy,Scada,Scheherazade,Schoolbell,Seaweed Script,Sevillana,Seymour One,Shadows Into Light,Shadows Into Light Two,Shanti,Share,Share Tech,Share Tech Mono,Shojumaru,Short Stack,Siemreap,Sigmar One,Signika,Signika Negative,Simonetta,Sintony,Sirin Stencil,Six Caps,Skranji,Slabo 13px,Slabo 27px,Slackey,Smokum,Smythe,Sniglet,Snippet,Snowburst One,Sofadi One,Sofia,Sonsie One,Sorts Mill Goudy,Source Code Pro,Source Sans Pro,Source Serif Pro,Special Elite,Spicy Rice,Spinnaker,Spirax,Squada One,Sree Krushnadevaraya,Stalemate,Stalinist One,Stardos Stencil,Stint Ultra Condensed,Stint Ultra Expanded,Stoke,Strait,Sue Ellen Francisco,Sunshiney,Supermercado One,Suranna,Suravaram,Suwannaphum,Swanky and Moo Moo,Syncopate,Tangerine,Taprom,Tauri,Teko,Telex,Tenali Ramakrishna,Tenor Sans,Text Me One,The Girl Next Door,Tienne,Timmana,Tinos,Titan One,Titillium Web,Trade Winds,Trocchi,Trochut,Trykker,Tulpen One,Ubuntu,Ubuntu Condensed,Ubuntu Mono,Ultra,Uncial Antiqua,Underdog,Unica One,UnifrakturCook,UnifrakturMaguntia,Unkempt,Unlock,Unna,Vampiro One,Varela,Varela Round,Vast Shadow,Vesper Libre,Vibur,Vidaloka,Viga,Voces,Volkhov,Vollkorn,Voltaire,VT323,Waiting for the Sunrise,Wallpoet,Walter Turncoat,Warnes,Wellfleet,Wendy One,Wire One,Yanone Kaffeesatz,Yellowtail,Yeseva One,Yesteryear,Zeyada]

// Character Height (in mm)
Font_Size = 8;

/* [Hidden] */

$fn=50;
TZT_Msg=Message;
TZT_Width=Label_Width;
TZT_Height=Label_Height;
TZT_Fnt=Font_Name;
TZT_Fsz=Font_Size;

TZT_PLATE ();
linear_extrude(height = 1.5) {
    text(TZT_Msg,size=TZT_Fsz,font=TZT_Fnt,halign="center",valign="center");
}

module TZT_PLATE () {
    difference () {
        union () {
            cube ([TZT_Width,TZT_Height,3],true);
            for (TZT_i=[-2:4:2]) {
                translate ([TZT_Width/TZT_i,0,0]) {
                    cylinder (3,TZT_Height/2,TZT_Height/2,true);
                }
                translate ([(TZT_Width+TZT_Height)/TZT_i,0,0]) {
                    cylinder (3,3,3,true);
                }
            }
        }
        translate ([0,0,1.5]) {
            union () {
                cube ([TZT_Width,TZT_Height-3,3],true);
                for (TZT_i=[-2:4:2]) {
                    translate ([TZT_Width/TZT_i,0,0]) {
                        cylinder (3,TZT_Height/2-1.5,TZT_Height/2-1.5,true);
                    }
                    translate ([(TZT_Width+TZT_Height+1)/TZT_i,0,0]) {
                        cylinder (10,1,1,true);
                    }
                }
            }
        }
    }
}

```


[User]
Okay, I'm trying to design a parametric ball bearing in OpenSCAD, and I'd like to be able to customize a few key features. I have a basic idea and some parameters I've been playing with, but I'd like a more flexible and robust design.

Here's what I'm thinking:

1.  **Type:** I want to be able to choose between generating a solid bearing for printing, a 270-degree view for easier inspection, or just a 2D profile view. So, I’d like to have a type parameter with options like "print", "270 degrees", and "profile".
2.  **Dimensions:** I need to control the overall dimensions like outer diameter (od), inner diameter (id), and the width of the bearing (w).
3.  **Roller Geometry:** The rollers are where things get a little complex. I want to independently adjust the outer width of the roller (b1w) and outer size (b1), as well as the inner width (b2w) and inner size (b2). I'm thinking these should be rectangular profiles.
4.  **Margins and Spacing:** I want to add margins to the roller placement. Specifically, I need an inner roller margin (m2) and an outer roller margin (m1). Also, I need a minimum distance between the rollers (bd).
5.  **Precision:** I need a way to control precision of the curves, so I should be able to adjust `fn` to control the number of fragments in a circular curve.
6.  **Roller Arrangement:**  The number of rollers should be calculated automatically based on the roller sizes, the ball center radius, and the `bd` parameter.
7. **Profiles:** I need to generate the outer and inner profiles separately so they can be extruded individually or used in rotation. Also, I need to create a roller profile that can be used to create the individual rollers.
8. **Extrusion:** The profile will be rotated for the printable bearing, while the profiles should be linear extruded when viewed individually.
9.  **Orientation:** The large part of the rollers should face outward.

I'm imagining a modular design using a few modules - one for the outer profile, one for the inner profile, one for the roller profile, and finally a main module to assemble the final bearing. I'm not concerned about any special libraries, but if you have some suggestions for generating the profiles, I’m all ears.

I'd love to see what you can come up with, and I'm happy to answer any questions to help clarify the design.

[Assistant]
ballbearing.scad:
```
// type
type="print"; // ["print","270 degrees","profile"]

// outer diameter
od=21;

// inner diameter (hole)
id=8;

// width
w=7;

// outer height/depth of roller
b1w=2.0;

// outer size of roller
b1=4.6;

// inner size of roller
b2=2.5;

// inner height/depth of roller
b2w=1.0;

// inner roller margin
m2=0.3;

// outer roller margin
m1=0.4;

// minimum distance between rollers (approximate)
bd=0.3;

// precision
fn=180;

// ---

// outer radius
or=od/2;

// inner radius
ir=id/2;

// ball center radius
bcr=(od+id)/4;

// number of rollers
drol=max(b1,b2)+bd;
nrol=floor((3.14159*bcr*2)/drol);

// angle for rollers
arol=360/nrol;

// ball center outer radii
bco1=bcr+b1/2+m1;
bco2=bcr+b2/2+m2;

// ball center inner radii
bci1=bcr-b1/2-m1;
bci2=bcr-b2/2-m2;

module parameters_stop_here() {}

// polygon height levels
h1=0;
h2=b1w;
h3=(w-b2w)/2;
h4=(w+b2w)/2;
h5=w-b1w;
h6=w;

hx1=(b1>b2?-1:1)*m2/8;
hx2=(b1>b2?-1:1)*m1/8;

module outer_profile()
{
   polygon( [[bco1,h1],
            [bco1,h2-hx1],
            [bco2,h3-hx2],
            [bco2,h4+hx2],
            [bco1,h5+hx1],
            [bco1,h6],
            [or,w],
            [or,0]] );
}

module inner_profile()
{
   polygon( [[bci1,h1],
            [bci1,h2-hx1],
            [bci2,h3-hx2],
            [bci2,h4+hx2],
            [bci1,h5+hx1],
            [bci1,h6],
            [ir,w],
            [ir,0]] );
}

module roller_profile()
{
   polygon( [[0,0],
            [b1/2,h1],
            [b1/2,h2],
            [b2/2,h3],
            [b2/2,h4],
            [b1/2,h5],
            [b1/2,h6],
            [0,h6]] );
}

module roller()
{
   rotate_extrude() roller_profile();
}

if (type=="profile")
{
   linear_extrude(height=5) outer_profile();
   linear_extrude(height=5) inner_profile();

   translate([bcr,0,0]) linear_extrude(height=5) roller_profile();
   translate([bcr,0,0]) mirror([1,0,0]) linear_extrude(height=5) roller_profile();
}
else
{
   rotate_extrude(angle=(type=="270 degrees")?270:360,$fn=fn)
   {
      outer_profile();
      inner_profile();
   }
   for (a=[0:arol:360-0.001])
      rotate([0,0,a])
         translate([bcr,0,0])
         roller($fn=fn);
}

```


[User]
Okay, I'm looking to create a parametric bottle cage in OpenSCAD, something that can lock onto a standard European glass bottle with a metal cap, like a Club Mate or similar. I've seen a few designs around, and I've got a basic concept in mind, but I need help getting it into a flexible, usable OpenSCAD model.

Essentially, it needs to have the following features:

*   **Main Body/Collar:** This is a cylindrical ring that goes around the bottle neck, slightly below the cap. It should have a split that allows it to be easily opened and then snap closed.
*   **Locking Mechanism:** There needs to be a place to attach a padlock, consisting of two tabs with holes for the padlock stem to go through. This part should extend out from the main body and have a bore for the padlock stem.
*   **Thumb Grips:** The sides of the opening should have a sort of grip area on each side, making it easier to open the split.
*   **Text Labels:** It would be nice to have text labels on the side, for example, a name and/or a little icon.

Here's some more detail about the sizing and such:

*   **Bottle:** The bottle neck is approximately 81mm in circumference and the lid is 94mm in circumference.
*   **Collar Height:** The main cylindrical collar portion should be about 21mm high, with a 16mm space for the cap.
*   **Material Thickness:**  Everywhere should be about 1.5mm thick.
*   **Grip Length:**  The grips on the side should extend about 40mm each.
*   **Split Gap:**  The gap between the split should be 1.5mm.
*   **Padlock Stem Bore:** The bore for the padlock stem should have a radius of 2mm.
*   **Padlock Stem Length:** The straight section of the padlock stem to accommodate is about 16mm.

I'm thinking we'll want to define variables for all these things so it's easy to modify the design later if needed. I'd like to have at least two text variables for the label, something like `Label1 = "YK42"` and `Label2 = ":-)"`.

I'd like to try and generate the model without using any external libraries if possible, though if a particular library will really simplify things that's fine too, as long as you're clear about which library it is and why. Could you generate the .scad file for me please?

[Assistant]
BottleCage.scad:
```
$fn=100;        //quality
H1 = 21;        //Collar height. Lid alone = 16mm
IR = 94/2/3.14; //Lid circumference = 94
RNeck = 81/2/3.14; //Neck circumference = 81 .:thk2 is perfect
Thk = 1.5;      //part thickness everywhere
LGrip = 40;     //length of thumb grips
Gap = 1.5 ;     //size of the collar split
RBore = 4/2;    //radius of the padlock stem
LStem = 16;     //striaght length of padlock = ~16mm
Label1 = "YK42";    //top text
Label2 = ":-)";     //bottom text

OR = IR + Thk;
H2 = 2*Thk;
LRSep = IR;

//main body
difference() {
    //Main body
    cylinder(r=OR, H1, center = true);
    //hollow out the main body
    cylinder(r=RNeck, H1, center = true);
    //hollow out a little more leaving the lock
    translate([0, 0, H2]) {
         cylinder(r=IR, H1, center = true);
    }
    //Below block reduces the locking collar circumference
    //This makes it much easier to apply/remove the cage.
    intersection() {
        cylinder(r=IR, H1, center = true);
        cube([2*IR, LRSep, H1], center = true);
    }
    //Split
    cube([LGrip*2, Gap, H1], center = true);
}

//lock portion (made slightly larger (+1) so it intersects the body)
X1Lock = OR +2*RBore +Thk; //outermost point on the lock
X2Lock = sqrt(IR*IR-pow(0.5*LStem-1.5*Thk,2)); //intersect point on IR
polygonVector1 = [[-X1Lock,LStem/2], [-X2Lock,LStem/2], [-X2Lock,LStem/2-1.5*Thk], [-X1Lock,LStem/2-1.5*Thk]];
translate([0,0,-H1/4]) {
    difference() {
        //padlock tabs
        linear_extrude(height = H1/2, center=true) {
            polygon(points=polygonVector1);
            mirror([0,1,0]) polygon(points=polygonVector1);
        }
        //padlock bore
        translate([-OR-RBore,0,0])
            rotate([90, 0,0])
                cylinder(r=RBore, LStem*2, center = true);
    }
}

//grip portion with text
polygonVector2 = [[0,OR], [LGrip-3*Thk,OR], [LGrip,OR+1*Thk], [LGrip,IR], [OR+5*Thk,IR], [OR+3*Thk,IR-2*Thk], [OR+3*Thk,0], [OR+2*Thk,0], [OR+2*Thk,IR], [0,IR]]; //half of the grip starting with the top left corner and working clockwise. Includes a grip.
difference(){
    //Grips
    translate([0,0,-H1/4]){
        linear_extrude(height = H1/2, center = true) {
            polygon(points=polygonVector2);
            mirror([0,1,0]) polygon(points=polygonVector2);
        }
    }
    //fillets
    translate([OR+5*Thk,IR-2*Thk,0]) cylinder(r=2*Thk, H1, center=true);
    translate([OR+5*Thk,-IR+2*Thk,0]) cylinder(r=2*Thk, H1, center=true);
    //Text
    translate([OR+3*Thk-0.3,0,-H1/4.5])
    rotate([90,0,90])
    linear_extrude(Thk) {
        text(Label1,font="courier",size=H1/6, halign="center");
        translate([0,-H1/5,0]) {
        text(Label2,font="courier",size=H1/6, halign="center");
        }
    }
}

```


[User]
Hi, I'm looking to create a parametric, print-in-place roller bearing design using OpenSCAD, and I'd like your help with the code. I've seen some existing designs, but I want to have full control over the parameters and create a robust design.

Here's what I'm after:

**Core Functionality:**

*   The design should be a print-in-place caged roller bearing, meaning the raceways, cage, and rollers print together and are functional after printing without assembly.
*   The design needs to support cylindrical and curved roller profiles.
*   It should have adjustable tolerances between the rollers and raceway, the rollers and cage, and the cage and raceway. It is also important to include a small tolerance between the cage and the top of the roller.
*   The cage needs to properly bridge over the rollers, and it would be good to have an option to slice the bridge area into concentric rings to aid printing.
*   There should be options for including a brim on the outer and inner diameters to help with print adhesion to the bed.
*   It should include an option for a loosening slot at the base of the rollers. The slots can either cut all the way through the roller base or be set slightly into the roller.

**Parameters:**

I want to control the following parameters, either directly or indirectly:

*   `inner_diameter`: The inner diameter of the bearing.
*   `outer_diameter`: The outer diameter of the bearing.
*   `bearing_width`: The total width of the bearing.
*   `roller_shape`:  A choice between "curved" and "cylindrical" roller profiles.
*   `brim`: A boolean value ("yes" or "no") to include a brim on the raceways.
*   `brim_thickness`: The thickness of the brim.
*   `outside_brim`: The width of the brim on the outside diameter.
*    `inside_brim`: The width of the brim on the inside diameter.
*   `roller_loosening_slot`: A choice between "no", "base slots", and "inset slots" for the loosening feature on the rollers.
*   `roller_raceway_tolerance`: The tolerance between the rollers and the raceway.
*   `cage_roller_tolerance`: The tolerance between the rollers and the cage.
*   `cage_raceway_tolerance`: The tolerance between the cage and the raceway.
*   `bridge_tolerance`: The tolerance gap above the rollers for the cage to bridge over them.
*   `cage_bridge_slice`: A boolean ("yes" or "no") to slice the cage bridge into concentric rings.
*   `raceway_mesh_refinement`: A multiplier for the mesh quality of the raceways.
*   `roller_mesh_refinement`: A multiplier for the mesh quality of the rollers.

**Advanced Parameters (these should have defaults but also be adjustable):**

*   `roller_diameter_override`: A parameter to manually set the roller diameter.
*   `R_override`: A parameter to manually set the radius of curvature for curved rollers.
*   `number_of_rollers_override`: A parameter to manually set the number of rollers.
*   `roller_slot_length_override`: A parameter to manually set the length of the loosening slot.
*   `roller_slot_width_override`: A parameter to manually set the width of the loosening slot.
*   `roller_slot_depth_override`: A parameter to manually set the depth of the loosening slot.
*   `roller_slot_inset_override`: A parameter to manually set the inset distance of the loosening slot.
*   `cage_width_override`: A parameter to manually set the minimum width of the cage.
*   `cage_pillar_thickness_override`: A parameter to manually set the minimum thickness of the cage pillars.
*  `cage_geometry_scale_override`: A parameter to scale the rest of the cage geometry.
*   `cage_roller_chamfer_override`: A parameter to add a chamfer between the cage and rollers.
*   `cage_raceway_chamfer_override`: A parameter to add a chamfer between the cage and raceway.
*   `outside_chamfer_override`:  A parameter to add a chamfer to the outer and inner edges of the bearing.
*   `cage_bridge_slice_gap`: The width of the gaps sliced into the cage bridging section.

**Additional Features:**

*   It would be excellent to have the option to generate separate STL files for the raceways, cage, and rollers, making it possible to do multi-material prints. There should be a `parts` parameter for this, with options for "all", "raceways", "cage", and "rollers".
*   I'd like a `cutaway` parameter ("yes" or "no") to generate a cutaway view of the bearing. This should only be used for preview and should not be included when generating an STL.

**Libraries:**

I don't believe any external libraries are necessary for this design.

The goal is to make the code as robust as possible and allow users to easily generate a custom print-in-place roller bearing for various applications. Can you help me build this design with OpenSCAD?

[Assistant]
Roller_Bearing_V3.scad:
```
//Variables

//preview[view:north east, tilt:top diagonal]

/*[Basic parameters]*/

//A cutaway view of the bearing (be sure to set to "no" if generating an STL)
cutaway="no";//[yes,no]

//For multi material printing you can generate just the raceways, cage or rollers to print in different materials. Select all for the whole bearing.
parts="all";//[all,raceways,cage,rollers]

inner_diameter=12;

outer_diameter=40;

bearing_width=12;

roller_shape="cylindrical";//[curved,cylindrical]

//A brim added on the outer and inner circumferences of the bearing to help the raceways stick to the printbed.
brim="yes";//[yes,no]
//The thickness of the brim.
brim_thickness=0.3;
//The width of the brim on the outside of the bearing.
outside_brim=2;
//The width of the brim on the inside of the bearing.
inside_brim=2;

//A slot included into the base of the rollers for flathead screwdrivers to twist and free up stuck rollers after printing. The 'Base Slots' cut right through the base of the roller, reducing contact area with the print bed slightly. The 'Inset Slots' are set into the roller slightly and do not cut into the first printing layer of the roller. This makes printing and sticking the first layer of the rollers to the print bed easier, while still making the loosening slots available by breaking through the thin first layer to access it. The default inset distance is 0.2mm .
roller_loosening_slot="inset slots";//[no,base slots,inset slots]

//Make sure the tolerance settings are suitable for your printer. A general rule of thumb for the tolerances is 'Roller Raceway Tolerance'<'Cage Roller Tolerance'<'Cage Raceway Tolerance'. 'Roller Raceway Tolerance' is the tolerance between the rollers and raceway. You can use a relatively low tolerance value here since the rollers and raceway only come close at a point on the roller circumference.
roller_raceway_tolerance=0.3;

//This is the tolerance between the rollers and cage. Set this to a value that just allows the rollers to turn easily in the cage.
cage_roller_tolerance=0.4;

//This is the tolerance between the cage and raceway. This should be a fair bit larger than the 'roller raceway tolerance', to prevent the bearing riding on the cage (causing sliding friction) and not on the rollers.
cage_raceway_tolerance=0.5;

//The tolerance gap above the rollers for the cage to bridge over them
bridge_tolerance=0.6;

//This is a bit of a hack to make the first cage bridging layer over the rollers consist of just concentric circles, which makes the bridging clean, without having to set the number of shells very high. It slices the bridging part of the cage into rings with a very small gap between them so that the slicer produces extra shells on the bridging section.
cage_bridge_slice="yes";//[yes,no]

//Raceway mesh quality multiplier (higher is more, default is 200 segments around). Important to increase if making very large bearings.
raceway_mesh_refinement=1;

//Roller mesh quality multiplier (higher is more, default is 60 segments around)
roller_mesh_refinement=1;

/*[Advanced Parameters]*/

//Diameter of the cylindrical part of the rollers, the actual diameter will extend out further if curved rollers are selected. Also avoid making the footprint of the roller too small, otherwise it may break away from the print bed.
roller_diameter_override=0;

//The radius of curvature on the curved part of the rollers (if selected) If the radius is less than half the raceway contact thickness,(Bearing Width - 6.4*Cage Geometry Scale), the model won't generate properly
R_override=0;

number_of_rollers_override=0;

//The length of the loosening slot cut into the roller
roller_slot_length_override=0;

//The width of the loosening slot cut into the roller
roller_slot_width_override=0;

//The depth of the loosening slot cut into the roller
roller_slot_depth_override=0;

//The the distance the loosening slot is inset into the roller.
roller_slot_inset_override=0;

//The cage tapers down to this minimum width in the centre of the bearing. 0.6*roller_diameter is a good value to start with.
cage_width_override=0;

//The minimum thickness of the cage pillars between the rollers.
cage_pillar_thickness_override=0;

//Scales the rest of the geometry defining the cage. A general rule of thumb is to increace this if you are using wider rollers or decrease it if you are using thinner rollers than the default bearing (on the defualt bearing, the default setting for this parameter is 1).
cage_geometry_scale_override=0;

//A chamfer that helps prevent the cage and rollers fusing together on the first few layers
cage_roller_chamfer_override=0;

//A chamfer that helps prevent the cage and raceway fusing together on the first few layers
cage_raceway_chamfer_override=0;

//Chamfer on the outer and inner diameter of the bearing
outside_chamfer_override=0;

//Width of the gaps sliced into the cage bridging section. If the gaps are too small sometimes the slicer will ignore them
cage_bridge_slice_gap=0.04;

/*[Hidden]*/

//Variable calculations

half_raceway_thickness=(outer_diameter-inner_diameter)/4;
middle_radius=(inner_diameter+outer_diameter)/4;

roller_diameter= roller_diameter_override==0 ? 1.2*half_raceway_thickness:roller_diameter_override;
roller_radius=roller_diameter/2;

cage_geometry_scale= cage_geometry_scale_override==0 ? roller_diameter/9:cage_geometry_scale_override;

cage_width= cage_width_override==0 ? 5*roller_diameter/9:cage_width_override;
half_cage_width=cage_width/2;

cage_pillar_thickness= cage_pillar_thickness_override==0 ? 0.09*roller_diameter:cage_pillar_thickness_override;

cage_roller_chamfer= cage_roller_chamfer_override==0 ? cage_geometry_scale/2:cage_roller_chamfer_override;

cage_raceway_chamfer= cage_raceway_chamfer_override==0 ? cage_geometry_scale/2:cage_raceway_chamfer_override;

outside_chamfer= outside_chamfer_override==0 ? 0.3*cage_geometry_scale:outside_chamfer_override;

half_rolling_contact=(bearing_width-6.4*cage_geometry_scale)/2;
curved_profile_width= (0.10*roller_diameter)/half_rolling_contact>0.414 ? 0.414*half_rolling_contact:0.10*roller_diameter;

scaleA= half_rolling_contact<0 ? bearing_width/6.4:cage_geometry_scale;

roller_type= half_rolling_contact<0 ? "cylindrical":roller_shape;

R= R_override==0 ? (half_rolling_contact*half_rolling_contact+curved_profile_width*curved_profile_width)/(2*curved_profile_width):R_override;

number_of_rollers= number_of_rollers_override==0 ? round(360/(2*asin((roller_radius+(roller_type=="curved" ? R-sqrt(R*R-half_rolling_contact*half_rolling_contact):0)+cage_roller_tolerance+cage_pillar_thickness/2)/middle_radius))-0.5):number_of_rollers_override;

roller_slot_length= roller_slot_length_override==0 ? roller_diameter:roller_slot_length_override;

roller_slot_width= roller_slot_width_override==0 ? 0.12*roller_diameter:roller_slot_width_override;

roller_slot_depth= roller_slot_depth_override==0 ? 0.1*roller_diameter:roller_slot_depth_override;

roller_slot_inset= roller_slot_inset_override==0 ? 0.2:roller_slot_inset_override;

inside_brim2= inside_brim>(inner_diameter/2)+outside_chamfer ? (inner_diameter/2)+outside_chamfer:inside_brim;

//Curved roller profile generator
x1=roller_radius;
y1=3.2*scaleA;
y2=bearing_width-3.2*scaleA;
nP=round(roller_mesh_refinement*12);
xc=x1-sqrt(R*R-half_rolling_contact*half_rolling_contact);
yc=(y1+y2)/2;
al=asin(half_rolling_contact/R);
th=2*al/nP;
pol=[for(i=[1:nP-1]) [R*cos(al-i*th)+xc,R*sin(al-i*th)+yc]];
curved_profile=concat([[x1,y2]],pol,[[x1,y1]]);

//Bearing half-profiles
raceway_profile=[[0,0],[half_raceway_thickness-outside_chamfer,0],[half_raceway_thickness,outside_chamfer],[half_raceway_thickness,bearing_width-outside_chamfer],[half_raceway_thickness-outside_chamfer,bearing_width],[0,bearing_width]];

cage_profile=[[0,0],[roller_radius-cage_raceway_chamfer+scaleA,0],[roller_radius-cage_raceway_chamfer+scaleA,cage_raceway_chamfer],[half_cage_width,roller_radius+scaleA-half_cage_width],[half_cage_width,bearing_width-roller_radius-scaleA+half_cage_width],[roller_radius-cage_raceway_chamfer+scaleA,bearing_width-cage_raceway_chamfer],[roller_radius-cage_raceway_chamfer+scaleA,bearing_width],[0,bearing_width]];

cage_cut_profile=[[0,0],[roller_radius+scaleA,0],[half_cage_width,roller_radius+scaleA-half_cage_width],[half_cage_width,bearing_width-roller_radius-scaleA+half_cage_width],[roller_radius+scaleA,bearing_width],[0,bearing_width]];

cylindrical_roller_profile=[[0,0],[roller_radius-1.2*scaleA,0],[roller_radius-1.2*scaleA,2*scaleA],[roller_radius,3.2*scaleA],[roller_radius,bearing_width-3.2*scaleA],[roller_radius-1.2*scaleA,bearing_width-2*scaleA],[0,bearing_width-2*scaleA]];

cylindrical_roller_raceway_cut_profile=[[0,0],[roller_radius-1.2*scaleA,0],[roller_radius-1.2*scaleA,2*scaleA],[roller_radius,3.2*scaleA],[roller_radius,bearing_width-3.2*scaleA],[roller_radius-1.2*scaleA,bearing_width-2*scaleA],[roller_radius-1.2*scaleA,bearing_width],[0,bearing_width]];

cylindrical_roller_cage_cut_profile=[[cage_roller_tolerance,0],[roller_radius-1.2*scaleA+cage_roller_chamfer,0],[roller_radius-1.2*scaleA,cage_roller_chamfer],[roller_radius-1.2*scaleA,2*scaleA],[roller_radius,3.2*scaleA],[roller_radius,bearing_width-2*scaleA-cage_roller_tolerance+bridge_tolerance],[cage_roller_tolerance,bearing_width-2*scaleA-cage_roller_tolerance+bridge_tolerance]];

outside_brim_profile=[[half_raceway_thickness-outside_chamfer,0],[half_raceway_thickness-outside_chamfer+outside_brim,0],[half_raceway_thickness-outside_chamfer+outside_brim,brim_thickness],[half_raceway_thickness-outside_chamfer,brim_thickness]];

inside_brim_profile=[[outside_chamfer-half_raceway_thickness,0],[outside_chamfer-half_raceway_thickness-inside_brim2,0],[outside_chamfer-half_raceway_thickness-inside_brim2,brim_thickness],[outside_chamfer-half_raceway_thickness,brim_thickness]];

//Bearing generator

//Raceways generator
if(parts=="raceways"||parts=="all"){
color("silver"){
    //Cut out inner profile from raceway
difference(){
        //Raceways
    rotate_extrude($fn=200*raceway_mesh_refinement,convexity=10){
        translate([middle_radius,0,0]){
                //Raceway profile
            union(){
                polygon(raceway_profile);
                mirror([1,0,0]){
                    polygon(raceway_profile);
                }
                if(brim=="yes"){
                polygon(outside_brim_profile);
                polygon(inside_brim_profile);
                }
    }}}
        //Inner shape to cut into raceway
    rotate_extrude($fn=200*raceway_mesh_refinement,convexity=10){
        translate([middle_radius,0,0]){
                //Total inner cut profile
            union(){
                    //Total cage profile to cut raceways
                offset(delta=cage_raceway_tolerance){
                    polygon(cage_cut_profile);
                    mirror([1,0,0]){
                        polygon(cage_cut_profile);
                }}
                    //Total roller profile to cut raceways
                offset(delta=roller_raceway_tolerance){
                    union(){
                        polygon(cylindrical_roller_raceway_cut_profile);
                        if(roller_type=="curved"){
                            polygon(curved_profile);
                        }
                        mirror([1,0,0]){
                            polygon(cylindrical_roller_raceway_cut_profile);
                            if(roller_type=="curved"){
                                polygon(curved_profile);
    }}}}}}}
if(cutaway=="yes"){
    translate([0,0,-0.1]){
        cube(outer_diameter);
}}}}}

    //Cage generator
if(parts=="all"||parts=="cage"){
color("deepskyblue"){
    //Cut holes for rollers into the cage
difference(){
        //Cage body
    rotate_extrude($fn=200*raceway_mesh_refinement,convexity=10){
        translate([middle_radius,0,0]){
                //Cage profile
            union(){
                polygon(cage_profile);
                mirror([1,0,0]){
                    polygon(cage_profile);
    }}}}
        //Roller holes
    for(i=[1:number_of_rollers]){
      rotate(i*360/number_of_rollers){
          translate([middle_radius,0,0]){
              rotate_extrude($fn=60*roller_mesh_refinement){
                  offset(delta=cage_roller_tolerance){
                          //Roller hole cutting profile
                      union(){
                          polygon(cylindrical_roller_cage_cut_profile);
                          if(roller_type=="curved"){
                              polygon(curved_profile);
    }}}}}}}
        //Cage bridge slice
    if(cage_bridge_slice=="yes"){
        bridge_thickness=2*scaleA-bridge_tolerance;
        half_bridge_width=roller_radius+scaleA-bridge_thickness;
        rotate_extrude($fn=200*raceway_mesh_refinement,convexity=10){
            for(i=[1,-1]){
                translate([middle_radius+i*half_bridge_width/3,bearing_width-0.001-3*bridge_thickness/4,0]){
                    square(size=[cage_bridge_slice_gap,bridge_thickness/2],center=true);
    }}}}
if(cutaway=="yes"){
    translate([0.001,0.001,bearing_width/2]){
    cube(outer_diameter);
}}}}}

    //Rollers generator
if(parts=="all"||parts=="rollers"){
color("yellow"){
for(i=[1:number_of_rollers]){
      rotate(i*360/number_of_rollers){
          translate([middle_radius,0,0]){
                  //Cut loosening slots from rollers
              difference(){
                      //Rollers
                  rotate_extrude($fn=60*roller_mesh_refinement){
                          //Roller profile
                      union(){
                          polygon(cylindrical_roller_profile);
                          if(roller_type=="curved"){
                              polygon(curved_profile);
                  }}}
                      //Loosening slots
                  if(roller_loosening_slot!="no"){
                      rotate(i*(-360/number_of_rollers)){
                          translate([0,0,roller_slot_depth/2-0.001+(roller_loosening_slot=="inset slots" ? roller_slot_inset:0)]){
                          cube(size=[roller_slot_length,roller_slot_width,roller_slot_depth],center=true);
}}}}}}}}}
```


[User]
I'm looking to design a parametric door knob or pull, and I'd like the design to be customizable in a few specific ways. I need an OpenSCAD design for this.

First, I need to be able to control the overall diameter of the knob. I should be able to set this as a parameter, say `Knob_Diameter`. Then, I need to be able to change the number of "corners" or lobes around the main body of the knob. I'd like this to be adjustable, maybe with a parameter called `Knob_Corners`. Also, I want the overall roundness of those lobes to be configurable; that should be a number that I can set, maybe `Knob_Roundness`. I am not planning to have a rectangular body at the base of the knob, so don't create that. The goal is to be able to create knobs with anywhere from very sharp corners to much more rounded ones.

Finally, I would like to add a raised monogram or character on the top of the knob. I should be able to specify the `Monogram` text and the `Font_Name`. It would also be very useful to be able to set the `Character_Rotation`, to rotate the character around the z axis. The font should come from the Google Fonts library. I don't need the AI to handle any fonts itself - just use the font name as specified in OpenSCAD.

I would also like the design to have a mounting hole at the back, along with a stepped hole to accommodate the screw head. Something similar to the way the example shows it would be great. It seems like the screw hole is created by using `TZT_Donut` in the example. I don't need any of the library functions from the provided code, just something that creates a nice place for a screw head.

So, to recap, I need:
*   `Knob_Diameter` parameter
*   `Knob_Corners` parameter
*   `Knob_Roundness` parameter
*   `Monogram` text parameter
*   `Font_Name` font parameter (from Google Fonts)
*   `Character_Rotation` parameter
*   A mounting hole with a stepped counterbore to allow the screw head to be recessed
*   The monogram to be raised up from the surface of the knob.

Please generate the OpenSCAD file for this.

[Assistant]
door_knob_a.scad:
```
// door_knob_a.scad
// library for parametric door pull, knob, handle - Style A
// Author: Tony Z. Tonchev, Michigan (USA)
// last update: November 2018

// (in mm)
Knob_Diameter = 40; //[25:80]

//
Knob_Corners = 5; //[3,4,5,6,7,8]

//
Knob_Roundness = 8; //[1:9]

/* [Monogram Details] */

//
Monogram = "T";

// Platform specific font name (In Customizer: http://www.google.com/fonts)
Font_Name="Marck Script"; //[ABeeZee,Abel,Abril Fatface,Aclonica,Acme,Actor,Adamina,Advent Pro,Aguafina Script,Akronim,Aladin,Aldrich,Alef,Alegreya,Alegreya Sans,Alegreya Sans SC,Alegreya SC,Alex Brush,Alfa Slab One,Alice,Alike,Alike Angular,Allan,Allerta,Allerta Stencil,Allura,Almendra,Almendra Display,Almendra SC,Amarante,Amaranth,Amatic SC,Amethysta,Amiri,Anaheim,Andada,Andika,Angkor,Annie Use Your Telescope,Anonymous Pro,Antic,Antic Didone,Antic Slab,Anton,Arapey,Arbutus,Arbutus Slab,Architects Daughter,Archivo Black,Archivo Narrow,Arimo,Arizonia,Armata,Artifika,Arvo,Asap,Asset,Astloch,Asul,Atomic Age,Aubrey,Audiowide,Autour One,Average,Average Sans,Averia Gruesa Libre,Averia Libre,Averia Sans Libre,Averia Serif Libre,Bad Script,Balthazar,Bangers,Basic,Battambang,Baumans,Bayon,Belgrano,Belleza,BenchNine,Bentham,Berkshire Swash,Bevan,Bigelow Rules,Bigshot One,Bilbo,Bilbo Swash Caps,Bitter,Black Ops One,Bokor,Bonbon,Boogaloo,Bowlby One,Bowlby One SC,Brawler,Bree Serif,Bubblegum Sans,Bubbler One,Buda,Buenard,Butcherman,Butterfly Kids,Cabin,Cabin Condensed,Cabin Sketch,Caesar Dressing,Cagliostro,Calligraffitti,Cambay,Cambo,Candal,Cantarell,Cantata One,Cantora One,Capriola,Cardo,Carme,Carrois Gothic,Carrois Gothic SC,Carter One,Caudex,Cedarville Cursive,Ceviche One,Changa One,Chango,Chau Philomene One,Chela One,Chelsea Market,Chenla,Cherry Cream Soda,Cherry Swash,Chewy,Chicle,Chivo,Cinzel,Cinzel Decorative,Clicker Script,Coda,Coda Caption,Codystar,Combo,Comfortaa,Coming Soon,Concert One,Condiment,Content,Contrail One,Convergence,Cookie,Copse,Corben,Courgette,Cousine,Coustard,Covered By Your Grace,Crafty Girls,Creepster,Crete Round,Crimson Text,Croissant One,Crushed,Cuprum,Cutive,Cutive Mono,Damion,Dancing Script,Dangrek,Dawning of a New Day,Days One,Dekko,Delius,Delius Swash Caps,Delius Unicase,Della Respira,Denk One,Devonshire,Dhurjati,Didact Gothic,Diplomata,Diplomata SC,Domine,Donegal One,Doppio One,Dorsa,Dosis,Dr Sugiyama,Droid Sans,Droid Sans Mono,Droid Serif,Duru Sans,Dynalight,Eagle Lake,Eater,EB Garamond,Economica,Ek Mukta,Electrolize,Elsie,Elsie Swash Caps,Emblema One,Emilys Candy,Engagement,Englebert,Enriqueta,Erica One,Esteban,Euphoria Script,Ewert,Exo,Exo 2,Expletus Sans,Fanwood Text,Fascinate,Fascinate Inline,Faster One,Fasthand,Fauna One,Federant,Federo,Felipa,Fenix,Finger Paint,Fira Mono,Fira Sans,Fjalla One,Fjord One,Flamenco,Flavors,Fondamento,Fontdiner Swanky,Forum,Francois One,Freckle Face,Fredericka the Great,Fredoka One,Freehand,Fresca,Frijole,Fruktur,Fugaz One,Gabriela,Gafata,Galdeano,Galindo,Gentium Basic,Gentium Book Basic,Geo,Geostar,Geostar Fill,Germania One,GFS Didot,GFS Neohellenic,Gidugu,Gilda Display,Give You Glory,Glass Antiqua,Glegoo,Gloria Hallelujah,Goblin One,Gochi Hand,Gorditas,Goudy Bookletter 1911,Graduate,Grand Hotel,Gravitas One,Great Vibes,Griffy,Gruppo,Gudea,Gurajada,Habibi,Halant,Hammersmith One,Hanalei,Hanalei Fill,Handlee,Hanuman,Happy Monkey,Headland One,Henny Penny,Herr Von Muellerhoff,Hind,Holtwood One SC,Homemade Apple,Homenaje,Iceberg,Iceland,IM Fell Double Pica,IM Fell Double Pica SC,IM Fell DW Pica,IM Fell DW Pica SC,IM Fell English,IM Fell English SC,IM Fell French Canon,IM Fell French Canon SC,IM Fell Great Primer,IM Fell Great Primer SC,Imprima,Inconsolata,Inder,Indie Flower,Inika,Irish Grover,Istok Web,Italiana,Italianno,Jacques Francois,Jacques Francois Shadow,Jim Nightshade,Jockey One,Jolly Lodger,Josefin Sans,Josefin Slab,Joti One,Judson,Julee,Julius Sans One,Junge,Jura,Just Another Hand,Just Me Again Down Here,Kalam,Kameron,Kantumruy,Karla,Karma,Kaushan Script,Kavoon,Kdam Thmor,Keania One,Kelly Slab,Kenia,Khand,Khmer,Khula,Kite One,Knewave,Kotta One,Koulen,Kranky,Kreon,Kristi,Krona One,La Belle Aurore,Laila,Lakki Reddy,Lancelot,Lateef,Lato,League Script,Leckerli One,Ledger,Lekton,Lemon,Liberation Sans,Libre Baskerville,Life Savers,Lilita One,Lily Script One,Limelight,Linden Hill,Lobster,Lobster Two,Londrina Outline,Londrina Shadow,Londrina Sketch,Londrina Solid,Lora,Love Ya Like A Sister,Loved by the King,Lovers Quarrel,Luckiest Guy,Lusitana,Lustria,Macondo,Macondo Swash Caps,Magra,Maiden Orange,Mako,Mallanna,Mandali,Marcellus,Marcellus SC,Marck Script,Margarine,Marko One,Marmelad,Martel Sans,Marvel,Mate,Mate SC,Maven Pro,McLaren,Meddon,MedievalSharp,Medula One,Megrim,Meie Script,Merienda,Merienda One,Merriweather,Merriweather Sans,Metal,Metal Mania,Metamorphous,Metrophobic,Michroma,Milonga,Miltonian,Miltonian Tattoo,Miniver,Miss Fajardose,Modak,Modern Antiqua,Molengo,Molle,Monda,Monofett,Monoton,Monsieur La Doulaise,Montaga,Montez,Montserrat,Montserrat Alternates,Montserrat Subrayada,Moul,Moulpali,Mountains of Christmas,Mouse Memoirs,Mr Bedfort,Mr Dafoe,Mr De Haviland,Mrs Saint Delafield,Mrs Sheppards,Muli,Mystery Quest,Neucha,Neuton,New Rocker,News Cycle,Niconne,Nixie One,Nobile,Nokora,Norican,Nosifer,Nothing You Could Do,Noticia Text,Noto Sans,Noto Serif,Nova Cut,Nova Flat,Nova Mono,Nova Oval,Nova Round,Nova Script,Nova Slim,Nova Square,NTR,Numans,Nunito,Odor Mean Chey,Offside,Old Standard TT,Oldenburg,Oleo Script,Oleo Script Swash Caps,Open Sans,Open Sans Condensed,Oranienbaum,Orbitron,Oregano,Orienta,Original Surfer,Oswald,Over the Rainbow,Overlock,Overlock SC,Ovo,Oxygen,Oxygen Mono,Pacifico,Paprika,Parisienne,Passero One,Passion One,Pathway Gothic One,Patrick Hand,Patrick Hand SC,Patua One,Paytone One,Peddana,Peralta,Permanent Marker,Petit Formal Script,Petrona,Philosopher,Piedra,Pinyon Script,Pirata One,Plaster,Play,Playball,Playfair Display,Playfair Display SC,Podkova,Poiret One,Poller One,Poly,Pompiere,Pontano Sans,Port Lligat Sans,Port Lligat Slab,Prata,Preahvihear,Press Start 2P,Princess Sofia,Prociono,Prosto One,PT Mono,PT Sans,PT Sans Caption,PT Sans Narrow,PT Serif,PT Serif Caption,Puritan,Purple Purse,Quando,Quantico,Quattrocento,Quattrocento Sans,Questrial,Quicksand,Quintessential,Qwigley,Racing Sans One,Radley,Rajdhani,Raleway,Raleway Dots,Ramabhadra,Ramaraja,Rambla,Rammetto One,Ranchers,Rancho,Ranga,Rationale,Ravi Prakash,Redressed,Reenie Beanie,Revalia,Ribeye,Ribeye Marrow,Righteous,Risque,Roboto,Roboto Condensed,Roboto Slab,Rochester,Rock Salt,Rokkitt,Romanesco,Ropa Sans,Rosario,Rosarivo,Rouge Script,Rozha One,Rubik Mono One,Rubik One,Ruda,Rufina,Ruge Boogie,Ruluko,Rum Raisin,Ruslan Display,Russo One,Ruthie,Rye,Sacramento,Sail,Salsa,Sanchez,Sancreek,Sansita One,Sarina,Sarpanch,Satisfy,Scada,Scheherazade,Schoolbell,Seaweed Script,Sevillana,Seymour One,Shadows Into Light,Shadows Into Light Two,Shanti,Share,Share Tech,Share Tech Mono,Shojumaru,Short Stack,Siemreap,Sigmar One,Signika,Signika Negative,Simonetta,Sintony,Sirin Stencil,Six Caps,Skranji,Slabo 13px,Slabo 27px,Slackey,Smokum,Smythe,Sniglet,Snippet,Snowburst One,Sofadi One,Sofia,Sonsie One,Sorts Mill Goudy,Source Code Pro,Source Sans Pro,Source Serif Pro,Special Elite,Spicy Rice,Spinnaker,Spirax,Squada One,Sree Krushnadevaraya,Stalemate,Stalinist One,Stardos Stencil,Stint Ultra Condensed,Stint Ultra Expanded,Stoke,Strait,Sue Ellen Francisco,Sunshiney,Supermercado One,Suranna,Suravaram,Suwannaphum,Swanky and Moo Moo,Syncopate,Tangerine,Taprom,Tauri,Teko,Telex,Tenali Ramakrishna,Tenor Sans,Text Me One,The Girl Next Door,Tienne,Timmana,Tinos,Titan One,Titillium Web,Trade Winds,Trocchi,Trochut,Trykker,Tulpen One,Ubuntu,Ubuntu Condensed,Ubuntu Mono,Ultra,Uncial Antiqua,Underdog,Unica One,UnifrakturCook,UnifrakturMaguntia,Unkempt,Unlock,Unna,Vampiro One,Varela,Varela Round,Vast Shadow,Vesper Libre,Vibur,Vidaloka,Viga,Voces,Volkhov,Vollkorn,Voltaire,VT323,Waiting for the Sunrise,Wallpoet,Walter Turncoat,Warnes,Wellfleet,Wendy One,Wire One,Yanone Kaffeesatz,Yellowtail,Yeseva One,Yesteryear,Zeyada]

// (in degrees)
Character_Rotation = 0; //[0:90]

/* [Hidden] */

$fn=30;
$TZT_Cct=Knob_Corners;
$TZT_Bnt=10-Knob_Roundness;
$TZT_Rad=Knob_Diameter/2;

TZT_Msg=Monogram;
TZT_Fnt=Font_Name;
TZT_Frt=Character_Rotation;

difference () {
    union () {
        TZT_Knob ();
        rotate ([0,0,TZT_Frt]) {
            linear_extrude($TZT_Rad*.2) {
                text(TZT_Msg,size=$TZT_Rad*.7,font=TZT_Fnt,halign="center",valign="center");
            }
        }
    }
    for (TZT_i=[0:120:360]) {
        rotate ([0,0,TZT_i]) {
            translate ([0,0,-$TZT_Rad]) {
                cube ([.7,5,$TZT_Rad*1.5],true);
            }
        }
    }
}

module TZT_Knob () {
    union () {
        difference () {
            hull () {
                translate ([0,0,-$TZT_Rad/10]) {
                    cylinder ($TZT_Rad*2,$TZT_Rad/4,$TZT_Rad/4,true);
                }
                for (TZT_i=[0:(360/$TZT_Cct):360]) {
                    rotate ([0,0,TZT_i]) {
                        translate ([$TZT_Rad-$TZT_Rad/$TZT_Bnt,0,0]) {
                            cylinder ($TZT_Rad/4,$TZT_Rad/$TZT_Bnt,$TZT_Rad/$TZT_Bnt,true);
                        }
                    }
                }
            }
            translate ([0,0,$TZT_Rad*2.3]) {
                sphere ($TZT_Rad*2.2);
            }
        }
        difference(){
            translate ([0,0,-$TZT_Rad*1.2]) {
                TZT_Donut($TZT_Rad/3,$TZT_Rad/4);
            }
            translate([0,0,-$TZT_Rad*1.15]) {
                TZT_Donut($TZT_Rad/2,$TZT_Rad/4);
            }
            translate([0,0,-$TZT_Rad/1.75]) {
                cylinder ($TZT_Rad,$TZT_Rad,$TZT_Rad,true);
            }
        }
        translate ([0,0,-$TZT_Rad*1.47]) {
            difference () {
                union () {
                    translate ([0,0,$TZT_Rad/2.1]) {
                        cylinder ($TZT_Rad,$TZT_Rad/4,$TZT_Rad/4,true);
                    }
                    cylinder ($TZT_Rad/10,$TZT_Rad/1.5,$TZT_Rad/1.5,true);
                    translate ([0,0,$TZT_Rad/10]) {
                        cylinder ($TZT_Rad/10,$TZT_Rad/1.5,$TZT_Rad/1.5-$TZT_Rad/10,true);
                    }
                }
            }
        }
    }
}

module TZT_Donut (TZT_Ra,TZT_Rb) {
    rotate_extrude() {
        translate([TZT_Ra, 0, 0])
        circle(TZT_Rb);
    }
}
```