[User]
I'd like to design a small, laser-cut trinket box using OpenSCAD. I want it to be parametric, so I can easily adjust the dimensions later. I have some basic ideas and measurements in mind, but I'm not sure how best to structure the SCAD code to make it truly flexible.

The box will be a simple rectangular prism shape with a hinged lid. It should have tabbed connections for assembly. Here are some initial parameters I'm thinking of:

*   **Overall Dimensions:** I need to be able to control the outside height, width, and length of the box. Let's call these `H`, `W`, and `L`, respectively.
*   **Material Thickness:** I need a parameter `t` for the material thickness.
*   **Legs:** I want small legs on the bottom of the box, so we'll need parameters for the leg height `Hleg` and the leg length `Lleg` (the length touching the surface) and `LlegT` for the leg length at the top. The legs should have an arc cut out of them to make them a bit more decorative.
*   **Tabbed Connections:** The box should use tabbed connections for the sides and bottom. I also need a parameter `Ntabs` to control the number of tabs across the front or side.
*   **Hinge:** The lid will attach using a tab and slot hinge.
*   **Clearance:** I need a small interfearance factor to control how tightly the tabs fit together, let's call it `interfearance`.
*   **Explode factor:** I want the ability to move each of the sides apart in an "exploded" view for rendering purposes. Let's call that `explode_factor` and the units will be multiples of the thickness `t`.
*  **Display Options:** The final code should have a switch to display the flat pattern for cutting (`DISPLAY=1`) or the assembled view (`DISPLAY=0`).
*   **Color:** I would like to define colors for each of the pieces of the trinket box (front, back, side1, side2, bottom, and top)

I'm not sure how to calculate all the measurements, like tab widths or the radius for the decorative cuts on the legs, so it would be great if the OpenSCAD code could handle all of that. Can you help me generate a parametric OpenSCAD design that handles this?

[Assistant]
trinket_box.scad:
```

// Height (outside of box)
H     = 60;

// Width  (outside of box)
W     = 85;

// Length (outside of box)
L     = 85;

// Thickness of material
t     = 5;

// Height of legs
Hleg  = 9;

// Length of legs (length that touches surface)
Lleg  = 14;

// Length of legs at top of leg (greater than Lleg)
LlegT = 18;

//Number of tabs across the smaller of the front or side.
Ntabs = 5;

DISPLAY=1; //[1:Flat Pattern (2D), 0:Assembly (3D)]

// interfearance (bigger number makes tighter fit)
interfearance = 0;

//Explode Factor (multiple of thickness
explode_factor =0;

if (DISPLAY)
{
    box_flat_pattern();
}
else
{
    box_assembly();
}

/////////////////////
// END USER INPUTS //
/////////////////////

$fn=100;
echo("inside dimensions:",(W-2*t),(L-2*t),(H-2*t-Hleg));

Lavail_front = W-2*max(LlegT,Lleg);
Lavail_side  = L-2*max(LlegT,Lleg);
Lavail_min = min(Lavail_front,Lavail_side);
Wtab = Lavail_min/(Ntabs*2-1);
Wpin = Wtab; // Width of the tab used as a pin in the hinge joint

// Define colors components
gamma = 1; // transparency level (value between 0.0 and 1.0)
Color_front  = [1.0,0.5,0.5,gamma];
Color_back   = [0.5,1.0,0.5,gamma];
Color_side_1 = [0.5,0.5,1.0,gamma];
Color_side_2 = [1.0,1.0,0.5,gamma];
Color_bottom = [0.5,1.0,1.0,gamma];
Color_top    = [1.0,0.5,1.0,gamma];

// Calculate the Effective diameter of the pin tab
Dpin     = sqrt(Wtab*Wpin + t*t);

// Calculate the position of the pin tab hole
Xhole    = L/2-Dpin/2-t;

// dH is how muh needs to be cut off from the back to
// provide clearance for the lid to open
Rswing = sqrt( (L/2-Xhole)*(L/2-Xhole) + (t/2)*(t/2) );
xswing = L/2-Xhole-t;
yswing = Rswing*sin(acos(xswing/Rswing));
swing_fudge  = 1; //Additional clearance just to be sure
dH = yswing-t/2+swing_fudge;

Lavail_edge = H-2*(dH+t);

// Calculate the Radius and center location for
// the cut that make the arc in the legs
x1   = Wtab*(Ntabs*2-1)/2;   //Wtab*2.5;
y1   = Hleg;
x2   = ( min(W,L)-Lleg*2 )/2;
yc   = -(y1*y1 + x1*x1 - x2*x2) / (2*y1);
Rleg =  sqrt(x2*x2+yc*yc);

/////////////////////////////
//Start Module Definitions //
/////////////////////////////

module box_flat_pattern()
{
    fsep=1.05;
    Hsep1 = (H-t)*fsep;
    Hsep2 = L*fsep;
    Hsep3 = W*fsep;
    Hsep4 = (W/2)*fsep;
    color(Color_front) translate([ Hsep3*0 , 0       ]) front();
    color(Color_back)  translate([ Hsep3*1 , 0       ]) back();
    color(Color_side_1)translate([ 0       , Hsep1*1 ]) side(flip=false);
    color(Color_side_2)translate([ Hsep2*1 , Hsep1*1 ]) side(flip=true);
    color(Color_bottom)translate([ L/2     ,-Hsep4*1 ]) rotate(90) bottom();
    color(Color_top)   translate([ Hsep2*1 ,-Hsep4*1 ]) top();
}

module box_assembly()
{
    e = explode_factor*t;

    color(Color_front)
    translate([0,-L/2+t-e,0])rotate([90,0,0])linear_extrude(t)front();

    color(Color_back)
    translate([0, L/2-0+e,0])rotate([90,0,0])linear_extrude(t)back();

    color(Color_side_1)
    translate([W/2-t+e, 0,0])
        rotate([0,90,0])
            linear_extrude(t)
                rotate(90) side(flip=false);
    color(Color_side_2)
    translate([-W/2+t-e, 0,0])
        rotate([0,90,180])
            linear_extrude(t)
                rotate(90)side(flip=true);

    color(Color_bottom)
    translate([0, -L/2,Hleg])
        linear_extrude(t)
            bottom();

    color(Color_top)
    translate([0, 0,H-t])
        linear_extrude(t)
            rotate(-90)
            top();
}

module front()
{
    difference()
    {
        translate([-W/2,0]) square([W,H-t]);
        difference()
        {
            union()
            {
                delta = (W-min(W,L))/2;
                translate([ delta,-yc]) circle(r=Rleg);
                translate([-delta,-yc]) circle(r=Rleg);
                square([2*delta,Hleg*2],center=true);
            }
            translate([-W/2,Hleg]) square([W,H]);
        }
        translate([ W/2,H/2]) tabs(Length_in=Lavail_edge);
        translate([-W/2,H/2]) tabs(Length_in=Lavail_edge);
        rotate(90)
        {
            translate([Hleg,0]) slots(Length_in=Lavail_front);
        }
    }
}

module back()
{
    difference()
    {
        front();
        translate([0,H-t])square([W*2,dH*2],center=true);
    }
}

module side(flip=false)
{
    Xhole_loc=(flip?-Xhole:Xhole);

    difference()
    {
        union()
        {
            translate([-L/2,0]) square([L,H]);
            difference()
            {
                translate([Xhole_loc,H-t/2])circle(r=Rswing);
                translate([L/2,0])square([L,H]);
            }

        }
        difference()
        {
            union()
            {
                delta = (L-min(W,L))/2;
                translate([ delta,-yc]) circle(r=Rleg);
                translate([-delta,-yc]) circle(r=Rleg);
                square([2*delta,Hleg*2],center=true);
            }
            translate([-L/2,Hleg]) square([L,H]);
        }
        translate([-L/2,H/2]) slots(Length_in=Lavail_edge);
        translate([ L/2,H/2]) slots(Length_in=Lavail_edge);
        rotate(90)
        {
            translate([Hleg,0]) slots(Length_in=Lavail_side);
        }
        translate([Xhole_loc,H-t/2])circle(d=Dpin);
    }
}

module bottom()
{
    difference()
    {
        translate([-W/2,0]) square([W,L]);
        translate([ W/2,L/2]) tabs(Length_in=Lavail_side);
        translate([-W/2,L/2]) tabs(Length_in=Lavail_side);
        rotate(90)
        {
            translate([ 0,0]) tabs(Length_in=Lavail_front);
            translate([ L,0]) tabs(Length_in=Lavail_front);
        }
    }
}

module top()
{
    difference()
    {
        square([L,W],center=true);
        rotate(90)
        {
            translate([ W/2,Xhole]) top_tabs();
            translate([-W/2,Xhole]) top_tabs();
        }
        //rotate(90) heart_pattern(size=min(L,W)/2); //heart(5);
    }
}

module tabs(Length_in=0)
{
    Nt = floor(max((Length_in/Wtab+1)/2,1));
    start = -(Nt-1)/2;
    difference()
    {
        square([2*t,max(H,W,L)*1.1],center=true);
        for (i=[0:Nt-1])
        {
            pos = (start+i)*Wtab*2;
            translate([0,pos]) square([4*t,Wtab+interfearance*2],center=true);
        }
    }
}

module slots(Length_in=0)
{
    Nt = floor(max((Length_in/Wtab+1)/2,1));
    start = -(Nt-1)/2;
    for (i=[0:Nt-1])
    {
        pos = (start+i)*Wtab*2;
        translate([0,pos]) square([2*t,Wtab],center=true);
    }
}

module top_tabs()
{
    difference()
    {
        square([2*t,max(H,W,L)*2],center=true);
        translate([0,i*Wtab*2])
            square([4*t,Wtab],center=true);
    }
}

module heart(size=10)
{
    resize([size,size])
    {
        radius=100/8;
        w=radius*.8;
        h=radius*2.5;
        fn=10;
        Rsmall = .1;
        shift = -(radius-(h+Rsmall))/2;
        translate([0,shift])
        {
            hull()
            {
                translate([w,0])circle(r=radius);
                translate([0,-h])circle(r=Rsmall,$fn=fn);
            }
            hull()
            {
                translate([-w,0])circle(r=radius);
                translate([0,-h])circle(r=Rsmall,$fn=fn);
            }
        }
    }
}

module heart_pattern(size=10)
{
    difference()
    {
        heart(size);
        step = 20;
        for (i=[step:step:180-step])
            rotate(i)square([1,100],center=true);
        heart(size-5);
    }
}
```


[User]
I'm looking to create a customizable "WalletMan" figure in OpenSCAD, and I need your help generating the SCAD code. I'd like the figure to be somewhat abstract, resembling a stick figure, but with a few key features and customizable dimensions.

Here's a breakdown of what I'm envisioning:

**Core Body:**

*   The body will consist of a main rectangular section (the "body"), two cylinders for the pelvis/hips, and then rectangular legs extending down.
*   There should be two arms which are rotated cubes attached to the main body.
*   A head should be a cylinder.

**Customization:**

*   **`thickness`**:  The overall thickness of all parts should be controlled by this parameter.
*  **`bodyWidth`**: The width of the main body and head.
*  **`spread`**: How far the legs and pelvis extend from the main body.
*  **`cellphoneWidth`**: A key parameter that defines how wide the hands should be, effectively representing the width of a phone being held.
*  **`cellphoneThickness`**:  The thickness of the hands should be relative to this value, making it represent the thickness of the phone.
*   **`cellphoneThicknessFeet`**: This parameter should similarly control the depth of the feet, making them seem like they're supporting the figure.
* The arms are attached to the body at an angle. These angles should be configurable.

**Features:**

*   The "hands" should be essentially rectangular solids with a portion cut out, to look like they are holding something.
*   The "feet" should have a similar, but not exact, look, with cutouts to add detail.
*   There should be simple cylindrical "eyes".
*   A "mouth" should be an overlapping cylinder cutout.
*   There should be cylindrical attachment points on the side of the main body, presumably to attach additional elements later, though those details are not necessary.

**Constraints:**

*   The figure should be flat - effectively a 2D design with thickness.
*   The figure should be designed using unions and differences, and I'm not looking to see any non-standard or experimental code.
*   I'd prefer no magic numbers directly in the code, and instead want all dimensions to use the defined parameters.

Essentially, I need an OpenSCAD file or files, that can create this customizable "WalletMan" figure. I'm not including any other files, or code other than the basic idea here. I think having all the code in a single file would be best for now.

Could you generate this OpenSCAD file for me?

[Assistant]
WalletMan.scad:
```
$fn=120*1;

thickness = 4 * 1;

// Hand spread
cellphoneWidth = 90; // [50:1:200]

// Hand depth
cellphoneThickness = 18; // [8:1:50]

// Foot depth
cellphoneThicknessFeet = 15; // [8:1:50]

bodyWidth = 20 * 1;
spread = 1.5*2;
difference(){
union(){
difference()
{
union(){
	cube([80,bodyWidth,thickness]); //body

	translate([80,        0,0]) cylinder(h=thickness, r=(bodyWidth/2)+spread); //left pelvis
	translate([80,bodyWidth,0]) cylinder(h=thickness, r=(bodyWidth/2)+spread); //right pelvis

	translate([80,-10-spread,0]) cube([40,15,thickness]); //left leg
	translate([80,15+spread,0]) cube([40,15,thickness]); //right leg

	translate([bodyWidth, 10,0]) rotate(a=[0,0,205.1]) cube([15,200,thickness]); //left arm
	translate([6.5,bodyWidth,0]) rotate(a=[0,0,334.8]) cube([15,200,thickness]); //right arm

	translate([-(bodyWidth/2),(bodyWidth/2),0]) cylinder(h=thickness, r=bodyWidth); //head

}
# translate([85+spread/2,10,-1]) cylinder(h=thickness+2,r=5+spread); //trouser-clearer 1
# translate([85,5-spread,-1]) cube([10+spread*2,10+spread*2,thickness+2]); //trouser-clearer 2

translate([0,-400-(cellphoneWidth/2)+(bodyWidth/2),-1]) cube([400,400,thickness+2]); //arm-clearer 1

translate([0,(bodyWidth/2)+(cellphoneWidth/2),-1]) cube([400,400,thickness+2]); //arm-clearer 2

translate([-(bodyWidth/2)-5,(bodyWidth/2)-7,-1]) cylinder(h=thickness+2, r=5);//left eye
translate([-(bodyWidth/2)-5,(bodyWidth/2)+7,-1]) cylinder(h=thickness+2, r=5);//right eye

translate([-(bodyWidth/2),(bodyWidth/2),-1]) difference() //mouth
{
	cylinder(h=thickness+2,r=15);
	translate([-4,0,0]) cylinder(h=thickness+2,r=15);
}
}
translate([21-((75-cellphoneWidth)/4),-(cellphoneWidth/2)+(bodyWidth/2)-5,0]) hand(); //left hand
translate([21+15-((75-cellphoneWidth)/4),5+(cellphoneWidth/2)+(bodyWidth/2),0]) rotate(a=[0,0,180]) hand(); //right hand

translate([5+80+40-1,-10-spread,0]) rotate(a=[0,0,90]) foot();
translate([5+80+40-1,15+spread,0]) rotate(a=[0,0,90]) foot();
}
	translate([40,bodyWidth/2,3]) cylinder(h=thickness+2,r=2.75);
	translate([40+20,bodyWidth/2,3]) cylinder(h=thickness+2,r=2.75);
	translate([40,bodyWidth/2,-1]) cylinder(h=thickness+2,r=1.75);
	translate([40+20,bodyWidth/2,-1]) cylinder(h=thickness+2,r=1.75);
}

module hand()
{
	difference()
	{
		union()
		{
			cube([16.5,5,thickness+cellphoneThickness]);
			translate([0,0,thickness+cellphoneThickness]) cube([16.5,11.2,6.5]);
		}
		translate([-1,10,thickness+cellphoneThickness-5]) rotate(a=[45,0,0]) cube([16.5+2,10,5+2]);
	}
}

module foot()
{
	difference()
	{
		union()
		{
			cube([15,5,thickness+cellphoneThicknessFeet]);
			translate([0,0,thickness+cellphoneThicknessFeet]) cube([15,11.2,6.5]);
			translate([0,thickness+3,thickness-0.1]) rotate(a=[135,0,0]) cube([15,4,4]);
		}
		translate([-1,10,thickness+cellphoneThicknessFeet-5]) rotate(a=[45,0,0]) cube([15+2,10,5+2]);
	}
}
```


[User]
Hey, I'm looking for an OpenSCAD file to generate a custom firewall for mounting RC motors. I've got some specific parameters I need to be able to adjust, and I'd like it to be similar to the included design.

Specifically, I need to be able to specify:

*   **Overall dimensions:** The width and height of the main firewall plate.
*   **Thickness:** The overall thickness of the firewall plate.
*   **Center hole:** The diameter of a central hole in the firewall, for wires or access.
*   **Bolt holes:** The diameter of bolt holes for mounting the motor.
*   **Bolt hole spacing:** The horizontal and vertical spacing between the motor mounting bolt holes (center-to-center).
*   **Motor wire notch:** The width and height of a notch for motor wires on the side of the firewall.
*   **Mounting tabs:** Whether or not to include mounting tabs, and their length, height, thickness, position relative to the bottom of the firewall, and an offset to account for foam thickness.

I'd like to be able to customize all of those variables in the OpenSCAD file. I also want the design to include some beveling around the center hole and the motor wire notch, mostly for aesthetics. The beveling should extend on both sides of the firewall. The mounting tabs should also be generated as a single piece, not as two separate objects.

I'm expecting that the output would be a single firewall, with the option of tabs on the left and right sides of the firewall.

It would also be useful if the design used the `linear_extrude` function for the main firewall and tab elements, and `cylinder` for the beveling - makes it easier to understand. Let me know if you have any questions!

[Assistant]
firewall_customizer_tabs.scad:
```
// Firewall Customizer
// with optional mounting tabs
// written by Dave Halderman
// 2017-10-08

// Total width (mm)
width = 31;

//Total height (mm)
height = 25;

//Thickness (mm)
thickness = 4; //[2:0.5:6]

//Diameter of center hole (mm)
center_hole_dia = 8; //[0:0.5:16]

//Diameter of bolt holes
bolt_hole_dia = 3.3; //[2.2:M2, 3.3:M3, 4.4:M4]

//Spacing of left/right holes (mm - center to center)
horiz_hole_spacing = 19; //[12:1:19]

//Spacing of top-bottom holes (mm - center to center)
vert_hole_spacing = 16; //[12:1:19]

//Motor wire notch width (mm)
notch_width = 6; //[0:0.5:12]

//Motor wire notch height (mm)
notch_height = 4; //[0:0.5:8]

//Mounting tab length (mm) - set to 0 for no tabs
tab_length = 10; //[0:1:25]

//Mounting tab height (mm)
tab_height = 4; //[0:1:25]

//Mounting tab thickness (mm)
tab_thickness = 1.5; //[1:0.5:3]

//Mounting tab position (mm from bottom of firewall)
tab_pos = 5; //[0:1:20]

//Foam thickness (mm) - used to offset tabs from edge of firewall
foam_thickness = 5; //[0:0.5:10]

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

difference() {
    union() {
        firewall();
        tabs();
    }
    notch_bevel();
    hole_bevel();
}

module firewall() {
    linear_extrude(thickness) {
        difference() {
            square([width,height],center=true);
            circle(d=center_hole_dia);
            translate([horiz_hole_spacing/2,0,0]) circle(d=bolt_hole_dia);
            translate([-horiz_hole_spacing/2,0,0]) circle(d=bolt_hole_dia);
            translate([0,vert_hole_spacing/2,0]) circle(d=bolt_hole_dia);
            translate([0,-vert_hole_spacing/2,0]) circle(d=bolt_hole_dia);
            translate([((2/3)*width)-(width/2),(height/2)-notch_height,0]) square([notch_width,notch_height+1]);
        }
    }
}

module notch_bevel() {
    translate([((2/3)*width)-(width/2)+(notch_width/2),(height/2)-(notch_height/2)+0.25,thickness*0.5])
        union() {
            translate([0,0,thickness*0.2])
                linear_extrude(2,scale=1.75)
                    square([notch_width-1,notch_height], center=true);
            rotate([0,180,0])
                translate([0,0,thickness*0.2])
                    linear_extrude(2,scale=1.75)
                        square([notch_width-1,notch_height], center=true);
        }
}

module hole_bevel() {
    translate([0,0,thickness*0.5])
    union() {
        translate([0,0,(thickness*0.3)*1.5])
            cylinder(d1=center_hole_dia-1, d2=center_hole_dia*1.25, h=thickness*0.2, center=true);
        rotate([0,180,0])
            translate([0,0,(thickness*0.3)*1.5])
                cylinder(d1=center_hole_dia-1, d2=center_hole_dia*1.25, h=thickness*0.2, center=true);
    }
}

module tabs() {
    translate([(width/2)-tab_thickness-foam_thickness,tab_pos-(height/2),thickness]) cube([tab_thickness,tab_height,tab_length]);
    translate([foam_thickness-(width/2),tab_pos-(height/2),thickness]) cube([tab_thickness,tab_height,tab_length]);
    translate([foam_thickness-(width/2)+tab_thickness,tab_pos+(tab_height/2)+(tab_thickness/2)-(height/2),thickness]) rotate([90,0,0]) linear_extrude(tab_thickness) polygon([[0,0],[min(tab_height/2,5),0],[0,tab_length]]);
translate([-foam_thickness+(width/2)-tab_thickness,tab_pos+(tab_height/2)+(tab_thickness/2)-(height/2),thickness])rotate([90,0,0]) linear_extrude(tab_thickness) polygon([[0,0],[max(-tab_height/2,-5),0],[0,tab_length]]);
}
```


[User]
Hey, I'm looking to design a customizable USB case, and I'd like to do it parametrically in OpenSCAD. I have an existing design (see attached `usbCase.scad` which has the basics), but I want something a bit more robust and flexible.

Here are the core parameters I need:

*   **Overall Dimensions:** I need to be able to set the outer diameter (`diameter`) and the total height (`usbHeight`) of the main body of the case. Also, the height of the cap (`capHeight`).
*   **USB Circuit Dimensions:** I need parameters for the width (`usbCircuitWidth`), thickness (`usbCircuitThickness`), and depth (`usbCircuitDepth`) of the USB circuit board that will fit inside.
*   **USB Connector Dimensions:** I need parameters for the width (`usbWidth`), thickness (`usbThickness`), and insertion depth (`usbDepth`) of the metal USB connector that goes into the computer.
*   **Magnet:** There should be an option to add a magnet, controlled by `magnetSize` parameter.
*   **Shape Control:** I'd like to control the number of sides the case has (`facets`), add a twist to the shape (`twist`), and control the convexity of the shape (`convex`).
*   **Tolerance** A parameter should be added to set the tolerance of all the fitting parts, to be set in one place.

I’m not married to the exact approach taken in the example file. I'd like the case to have a separate bottom and top piece. The top piece (cap) should have the space for the magnet as well as the cut out for the USB connector. The bottom piece should have the cutout for the USB circuit.

I'd like the design to be robust and customizable, so I'm open to suggestions on the best way to structure the code.

[Assistant]
usbCase.scad:
```
/***********************************************************************
Name ......... : usbCase.scad
Description....: Customizable USB Case
Author ....... : Garrett Melenka
Version ...... : V1.0 2016/12/17
Licence ...... : GPL
***********************************************************************/

//Outer Diameter of Usb Case
diameter = 40;
//Height of Usb Case
usbHeight = 50;
//Height of Use Case Cap
capHeight = 25;

//Measure Dimensions of Usb circuit board
//Width of Circuit portion of usb
usbCircuitWidth = 14;
//Thickness of circuit portion of usb
usbCircuitThickness = 6;
//Length of Circuit Portion of USB
usbCircuitDepth = 38;

//Measure dimensions of USB/ PC connection
//Width of USB that connects to PC
usbWidth = 13.5;
//THickness of USB that connects to PC
usbThickness = 6;
//Depth USB will fit into cap
usbDepth = 10;

//Add magnet to cap
magnetSize = 5.3;

//Change the shape of the case
facets = 3; //[3:1:100]
//Add a degree of twist to case
twist = 20;
//Convexity
convex = 0;

module usbCaseBottom()
{
    difference(){

    linear_extrude(height = usbHeight, center = true, convexity =convex, twist = twist)
        circle(r=diameter*0.5, $fn=facets);

    //cylinder(r = diameter*0.5, h = height, center = true, $fn=facets);

    translate([0,0,usbHeight*0.5-usbCircuitDepth*0.5]){

    cube(size = [usbCircuitThickness, usbCircuitWidth, usbCircuitDepth], center = true);
    }
    }
}

module usbCaseTop()
{

    twistPerHeight = twist / usbHeight;

    echo(twistPerHeight);

    twistCap = twistPerHeight * capHeight;

    difference()
    {
    linear_extrude(height = capHeight, center = true, convexity = convex, twist = twist)     circle(r=diameter*0.5, $fn = facets);
    //cylinder(r = diameter*0.5, h = capHeight, center = true, $fn = facets);

    rotate([0,0,twist]){

    translate([0,0,-capHeight*0.5 + usbDepth*0.5]){
    cube(size = [usbThickness,usbWidth, usbDepth], center = true);
    }

    translate([0,0,capHeight*0.5-magnetSize*0.5-usbDepth]){
    cube(size = [magnetSize, magnetSize, magnetSize], center = true);
    }
    }

}

}

usbCaseBottom();

//translate([0,0,usbHeight*0.5+capHeight*0.5+10])
translate([0, diameter+10, -capHeight*0.5])
{

 rotate([180,0,0]){

 rotate([0,0,-twist])
    {
 //mirror([1,0,0])
     {
usbCaseTop();
 }
}
}
}
```


[User]
Okay, I'm trying to design a cageless roller bearing, and it's proving to be a bit tricky. I've got a basic design in OpenSCAD, but I'm having trouble dialing in the tolerances and making it truly parametric. I'd like to have an AI assistant generate the necessary SCAD files, including any needed libraries or modules. I'll describe the design, and you can ask for more info if needed.

Essentially, the bearing consists of:

*   **Rollers:** These are cylindrical, and the number, diameter, and length should all be adjustable parameters. For now, I'm using 6mm diameter and 14mm long dowel pins, but that needs to be a variable. They are arranged around a circle at an angle relative to the center.
*   **Inner Race:** This has a channel for the rollers to rest in. The diameter of the inner race is an important variable.
*   **Outer Race:** This encloses the rollers and also has a channel for them. The outer diameter is an important variable.
*   **Mounting Plate** This is a base, that also helps to place the rollers.

The rollers are not held in place by a traditional cage, but rather by their shape. I would like to use a 45-degree angle for now to make sure the rollers do not cause a collapse in the constellation.

I would like to have these parameters to control the bearing:

*   `D`: Diameter of the rollers.
*   `h`: Length of the rollers.
*   `cnt`: Number of rollers.
*   `omega`: The angle at which the rollers are arranged relative to the center, should be kept close to 45 degrees
*   `d`: Inner diameter of the inner race.
*   `T`: Thickness of the outer race

The outer and inner diameters, as well as any additional tolerances will need to be calculated based on these values using trigonometric functions and spacing parameters. The mounting base should also be parametric. The thickness of the mounting base should also be variable.

I am currently using the following libraries `sc.scad` (for basic shapes and transforms), `thread.scad` (for adding threads to the bearing, although this part can be left for later if necessary), and `Naca_sweep.scad` (for creating more complex geometries). I am fine with you generating a completely new set of libraries as long as the generated files are able to perform all the necessary functions for this.

Could you please generate the necessary SCAD files to create this parametric bearing? I need to be able to adjust all of the parameters above. The outer ring and the inner ring should be designed to fit with some clearance over the rollers and the mounting base.

[Assistant]
thread.scad:
```
// Threading.scad - library for threadings
// Autor: Rudolf Huttary, Berlin 2016

use <Naca_sweep.scad> // http://www.thingiverse.com/thing:900137

// examples
//showexample = 4;   // choose your example number

//threading(pitch = 1.25, d=8, windings=20, full=true, steps = 512);

example(showexample)
{
// #1 ACME thread
  threading(pitch = 2, d=20, windings = 5, angle = 29);

// #2 threaded rod 20°
  threading(pitch = 2, d=20, windings = 30, angle = 20, full = true);

// #3 nut for threaded rod 20°
  Threading(pitch = 2, d=20, windings = 10, angle = 20, full = true);

// #4 nut for threaded rod 20°, own diameter 25 mm, hires
  Threading(D = 25, pitch = 2, d=20, windings = 10, angle = 20, full = true, step = 50, $fn=100);

// #5 triple helix threaded rod
  threading(pitch = 2, d=20, windings = 30, helices = 3, angle = 20, full = true);

// #6 toothed rod (no pitch)
   threading(helices = 0, angle = 20, full = true);

// #7 toothed cube (no pitch)
   threading(helices = 0, angle = 60, full = true, steps=4);

// #8 M8 hex bolt
   union(){
     threading(pitch = 1.25, d=8, windings=20, full=true); cylinder(d=14.6, h=4, $fn=6);}
// #9 M8 hex nut
   Threading(D=14.6, pitch = 1.25, d=8, windings=5, full=true, $fn=6);
// #10 M8 four socket nut
   Threading(D=16, pitch = 1.25, d=8, windings=5, full=true, $fn=4);
}

module example(number=0) if(number) children(number-1);

help();
module help()
{
  helpstr =
  "Thread library - Rudolf Huttary \n
    D = {0=auto};  // Cyl diameter Threading() \n
    d = 6;         // outer diameter thread() \n
    windings = 10; // number of windings \n
    helices = 1;   // number of threads \n
    angle = 60;    // open angle <76, bolts: 60°, ACME: 29°, toothed Racks: 20° \n
    steps = 40;    // resolution \n
    help();        // show help in console
    threading(pitch = 1, d = 6, windings = 10, helices = 1, angle = 60, steps=40, full = false) \n
    Threading(D = 0, pitch = 1, r = 6, windings = 10, helices = 1, angle = 60, steps=40) \n
  ";
  echo (helpstr);
}

//Threading(R=12, pitch = pitch, r=radius, windings= windings, angle = angle);

module Threading(D = 0, pitch = 1, d = 12, windings = 10, helices = 1, angle = 60, steps=40)
{
  R = D==0?d/2+pitch/PI:D/2;
  translate([0,0,-pitch])
  difference()
  { translate([0,0,pitch])
    cylinder (r=R, h =pitch*(windings-helices));
    threading(pitch, d, windings, helices, angle, steps, true);
  }
}

module threading(pitch = 1, d = 12, windings = 10, helices = 1, angle = 60, steps=40, full = false)
{  // tricky: glue two 180° pieces together to get a proper manifold
  r = d/2;
  Steps = steps/2;
  Pitch = pitch*helices;
  if(full) cylinder(r = r-1-pitch/PI, h=pitch*(windings+helices), $fn=steps);
  sweep(gen_dat());   // half screw
  rotate([0, 0, 180]) translate([0, 0, Pitch/2])
  sweep(gen_dat());   // half screw
echo(steps);
  function gen_dat() = let(ang = 180, bar = R_(180, -90, 0, Ty_(-r+1, vec3D(pitch/PI*Rack(windings, angle)))))
        [for (i=[0:Steps]) Tz_(i/2/Steps*Pitch, Rz_(i*ang/Steps, bar))];

  function Rack(w, angle) =
     concat([[0, 2]], [for (i=[0:windings-1], j=[0:3])
     let(t = [ [0, 1], [2*tan(angle/2), -1], [PI/2, -1], [2*tan(angle/2)+PI/2, 1]])
        [t[j][0]+i*PI, t[j][1]]], [[w*PI, 1], [w*PI, 2]]);
}

```
Naca_sweep.scad:
```
// Naca4_sweep.scad - sweep library
// Code: Rudolf Huttary, Berlin
// June 2015
// commercial use prohibited

use <naca4.scad>

//example1();
//rotate([80, 180, 130])
example();

// sweep from NACA1480 to NACA6480 (len = 230 mm, winding y,z = 80°
// sweeps generates a single polyhedron from multiple datasets
module example()
{
  N = 40;
  sweep(gen_dat(N=5, dz=1,N=N));

  // specific generator function
  function gen_dat(M=10,dz=.1,N=10) = [for (i=[1:dz:M])
    let( L = length(i))
    let( af = vec3D(
        airfoil_data([.1,.5,thickness(i)], L=length(i), N = N)))
    T_(-L/2, 0, (i+1)*2, af)];  // translate airfoil

  function thickness(i) = .5*sin(i*i)+.1;
  function length(i) = (60+sin(12*(i-3))*30);
}

module help()
{
  echo(str("\n\nList of signatures in lib:\n=================\n",
  "sweep(dat, convexity = 5, showslices = false, plaincaps = true)  // dat - vec of vec2, with vec1 = airfoil_data\n",
  "function vec3D(v, z=0)  // expand vec2 to vec3",
  "function rot(w=0, p) // rotate vec2",
  "function T_(x=0, y=0, z=0, v) // translates vec of vec3\n",
  "function R_(x=0, y=0, z=0, v) // rotates vec of vec3\n",
  "function Rx_(x=0, v) // x-rotates vec of vec3\n",
  "function Ry_(y=0, v) // y-rotates vec of vec3\n",
  "function Rz_(z=0, v) // z-rotates vec of vec3\n",
  "function T_(x=0, y=0, z=0, v) // translates vec of vec3\n",
  "function Tx_(x=0, v) // x-translates vec of vec3\n",
  "function Ry_(y=0, v) // y-translates vec of vec3\n",
  "function Rz_(z=0, v) // z-translates vec of vec3\n",
  "function S_(x=0, y=0, z=0, v) // scales vec of vec3\n",
  "function Sx_(x=0, v) // x-translates vec of vec3\n",
  "function Sy_(x=0, v) // y-translates vec of vec3\n",
  "function Sz_(x=0, v) // z-translates vec of vec3\n",
  "=================\n"));
}

// generate polyhedron from multiple airfoil_datasets
// dat - vec of vec1, with vec1 = simple polygon like airfoil_data, > 3 points per dataset expected
module sweep(dat, convexity = 5, showslices = false, plaincaps = true)
{
  n = len(dat);     // # datasets
  l = len(dat[0]);  // points per dataset
  if(l<=3)
    echo("ERROR: sweep() expects more than 3 points per dataset");
  else
  {
    if(n==1)
      polyhedron(points = dat[0], faces = [count(l-1, 0)]);
    else{
    first = plaincaps?[count(l-1, 0)]:
            faces_polygon(l, true);  // triangulate first dataset
    last = plaincaps?[count((n-1)*l,(n)*l-1)]:
            faces_shift((n-2)*l, faces_polygon(l, false)); // triangulate last dataset
    if (showslices)
      for(i=[0:n-1])
        sweep([dat[i]]);
    else
      if (n<2)  // this case is also used recursively for showslices
        polyhedron(points = flat(), faces  = last, convexity = 5);
      else
      {
        polyhedron(points = flat(),
                   faces  = concat(first, last, faces_sweep(l,n)), convexity = 5);
      }
    }
  }
  function count(a, b) = let(st = (a<b?1:-1))[for (i=[a:st:b]) i];
  function faces_shift(d, dat) = [for (i=[0:len(dat)-1]) dat[i] + [d, d, d]];
  function flat() = [for (i=[0:n-1], j=[0:l-1]) dat[i][j]];
}

function del(A, n) = [for(i=[0:len(A)-1]) if (n!=i)A[i]];

//// composition stuff for polyhedron
  function faces_sweep(l, n=1) = let(M = n*l)
      concat([[0,l,l-1]],   // first face
      [for (i=[0:l*(n-1)-2], j = [0,1])
        j==0? [i, i+1, (i+l)] : [i+1, (i+l+1), i+l]],
      [[n*l-1, (n-1)*l-1, (n-1)*l]]) // last face
      ;

  function faces_polygon(l, first = true) = let(odd = (l%2==1), d=first?0:l)
    let(res = odd?concat([[d,d+1,d+l-1]],
      [for (i=[1:(l-3)/2], j=[0,1])(j==0)?[d+i,d+i+1,d+l-i]:[d+i+1,d+l-i-1, d+l-i]]):
      [for (i=[0:(l-4)/2], j=[0,1])(j==0)?[d+i,d+i+1,d+l-i-1]:[d+i+1,d+l-i-2, d+l-i-1]])
    first?facerev(res):res;

  function facerev(dat) = [for (i=[0:len(dat)-1]) [dat[i][0],dat[i][2],dat[i][1]]];

//// vector and vector set operation stuff ///////////////////////
//// Expand 2D vector into 3D
function vec3D(v, z=0) = [for(i = [0:len(v)-1])
  len(v[i])==2?[v[i][0], v[i][1], z]:v[i]+[0, 0, z]];

// Translation - 1D, 2D, 3D point vector //////////////////////////
// vector along all axes
function T_(x=0, y=0, z=0, v) = let(x_ = (len(x)==3)?x:[x, y, z])
  [for (i=[0:len(v)-1]) T__(x_[0], x_[1], x_[2], p=v[i])];
/// vector along one axis
function Tx_(x=0, v) = T_(x=x, v=v);
function Ty_(y=0, v) = T_(y=y, v=v);
function Tz_(z=0, v) = T_(z=z, v=v);
/// point along all axes 1D, 2D, 3D allowed
function T__(x=0, y=0, z=0, p) = len(p)==3?p+[x, y, z]:len(p)==2?p+[x, y]:p+x;

//// Rotation - 2D, 3D point vector ///////////////////////////////////
// vector around all axes
function R_(x=0, y=0, z=0, v) =             // 2D vectors allowed
  let(x_ = (len(x)==3)?x:[x, y, z])
  len(v[0])==3?Rx_(x_[0], Ry_(x_[1], Rz_(x_[2], v))):
  [for(i = [0:len(v)-1]) rot(x_[2], v[i])];
// vector around one axis
function Rx_(w, A) = A*[[1, 0, 0], [0, cos(w), sin(w)], [0, -sin(w), cos(w)]];
function Ry_(w, A) = A*[[cos(w), 0, sin(w)], [0, 1, 0], [-sin(w), 0, cos(w)]];
function Rz_(w, A) = A*[[cos(w), sin(w), 0], [-sin(w), cos(w), 0], [0, 0, 1]];

//// Scale - 2D, 3D point vector ///////////////////////////////////
// vector along all axes
function S_(x=1, y=1, z=1, v) =
  [for (i=[0:len(v)-1]) S__(x,y,z, v[i])];
// vector along one axis
function Sx_(x=0, v) = S_(x=x, v=v);
function Sy_(y=0, v) = S_(y=y, v=v);
function Sz_(z=0, v) = S_(z=z, v=v);
// single point in 2D
function S__(x=1, y=1, z=1, p) =
  len(p)==3?[p[0]*x, p[1]*y, p[2]*z]:len(p)==2?[p[0]*x+p[1]*y]:[p[0]*x];

```
sc.scad:
```
// ShortCuts.scad
// Autor: Rudolf Huttary, Berlin 2015
//
//$fn = 100;

//show_examples();

module show_examples()
	place_in_rect(30, 30)
	{
		Cy(h = 10);
		CyH(h = 10);
		CyH(h = 10, w = 30);
		CyS(h = 10);
		CyS(h = 10, w1 = 25, w2 = 75);
		Cu(10);
		Ri(h = 10);
		RiH(h = 10);
		RiS(h = 10, w1 = 10);
		RiS(h = 10, w1 = 30, w2 = 300);
		Sp();
		SpH(10, 30, 30);
	}

module help()
{
echo("===============");
echo("help(): shows this help");
echo("show_examples(): shows some examples");
echo("place_in_rect(): places children objects in grid");
echo("Transformations:");
echo(" transform :  T(x=0, y=0, z=0), Tx(x=0) , Ty(y=0), Tz(z=0)");
echo(" rotate :  R(x=0, y=0, z=0), Rx(x=0) , Ry(y=0), Rz(z=0)");
echo(" scale :  S(x=1, y=1, z=1), Sx(x=1) , Sy(y=1), Sz(z=1)");
echo("Logical");
echo(" difference :  D()");
echo(" union :  U()");
echo(" intersection : *missing*");
echo("Primitives");
echo(" circle :  Ci(r=10)");
echo(" circle_half :  CiH(r=10, w=0)")
echo(" circle_segment :  CiS(r=10, w1=0, w2=90)")
echo(" square :  Sq(x=10, y=0, center=true))");
echo(" cylinder :  Cy(r=10, h=1, center=true)");
echo(" cylinder_half :  CyH(r=10, w=0)")
echo(" cylinder_segment: CyS(r=10, h=1, w1=0, w2=90,center=true)");
echo(" cylinder_segment: Pie(r=10, h=1, w1=0, w2=90,center=true)");
echo(" cube :  Cu(x=10, y=0, z=10, center=true)");
echo(" ring :  Ri(R=10, r=5, h=1, center=true)");
echo(" ring_half :  RiH(R=10, r=5, h=1, w=0 center=true)");
echo(" ring_segment :  RiS(R=10, r=5, h=1, w1=0, w2=90, center=true)");
echo(" sphere:  Sp(r=10))");
echo(" sphere_half:  SpH(r=10, w1 = 0, w2 = 0))");
echo("===============");
}

// Euclidean Transformations

module T(x=0, y=0, z=0){translate([x, y, z])children(); }
module Tx(x) { translate([x, 0, 0])children(); }
module Ty(y) { translate([0, y, 0])children(); }
module Tz(z) { translate([0, 0, z])children(); }

module R(x=0, y=0, z=0){rotate([x, y, z]) children();}
module Rx(x=90){rotate([x, 0, 0]) children();}
module Ry(y=90){rotate([0, y, 0]) children();}
module Rz(z=90){rotate([0, 0, z]) children();}

module S(x=1, y=1, z=1){scale([x, y, z]) children();}
module Sx(x=1){scale([x, 1, 1]) children();}
module Sy(y=1){scale([1, y, 1]) children();}
module Sz(z=1){scale([1, 1, z]) children();}

module D() difference(){children(0); children([1:$children-1]);}
module U() children([0:$children-1]);
// module I() intersection()children([0:$children-1]); // does not work for some reason

// primitives - 2D

module Sq(x =10, y = 0, center = true)
{
   if(y==0)
		square([x, x], center = center);
	else
		square([x, y], center = center);
}
module Ci(r = 10)
{
	circle(r = r);
}

// derived primitives - 2d
module CiH(r = 10, w = 0)
  circle_half(r, w);

module CiS(r = 10, w1 = 0, w2 = 90)
  circle_segment(r, w1, w2);

// primitives - 3d
module Cy(r = 10, h = 1, center = true)
{
	cylinder(r = r, h = h, center = center);
}
module Cu(x = 10, y = 0, z = 10, center = true)
{
  if (y==0)
	cube([x, x, x], center = center);
  else
	cube([x, y, z], center = center);
}

// derived primitives - 3d
module CyH(r = 10, h = 1, w = 0, center = true)
  cylinder_half(r, h, w, center);

module CyS(r = 10, h = 1, w1 = 0, w2 = 90, center = true)
  cylinder_segment(r, h, w1, w2, center);

module Ri(R = 10, r = 5, h = 1, center = true)
  ring(R, r, h, center);

module RiS(R = 10, r = 5, h = 1, w1 = 0, w2 = 90, center = true)
   ring_segment(R, r, h, w1, w2, center);

module RiH(r1 = 10, r2, h = 1, w = 0, center = true)
   ring_half(r1, r2, h, w, center);
module Pie(r = 10, h = 1, w1 = 0, w2 = 90, center = true)
  cylinder_segment(r, h, w1, w2, center);
module Sp(r = 10)
  sphere(r);
module SpH(r = 10, w1 = 0, w2 = 0)
  sphere_half(r, w1, w2);
module SpS(r = 10, w1 = 0, w2 = 90, w3 = 90)
  sphere_segment(r, w1, w2);

// clear text definitions
module circle_half(r = 10, w = 0)
{
	difference()
	{
		circle(r);
     rotate([0, 0, w-90])
     translate([0, -r])
		square([r, 2*r], center = false);
	}
}

module circle_segment(r = 10, w1 = 0, w2 = 90)
{
  W2 = (w1>w2)?w2+360:w2;
  if (W2-w1 < 180)
    intersection()
		{
       circle_half(r, w1);
       circle_half(r, W2-180);
 		}
	else
    union()
		{
       circle_half(r, w1);
       circle_half(r, W2-180);
 		}
}

module cylinder_half(r = 10, h = 1, w = 0, center = true)
{
  linear_extrude(height = h, center = center)
  circle_half(r, w);
}

module cylinder_segment(r = 10, h = 1, w1 = 0, w2 = 90, center = true)
{
  linear_extrude(height = h, center = center)
  circle_segment(r, w1, w2);
}

module ring(R = 10, r = 5, h = 1, center = true)
{
	difference()
	{
	cylinder(r = R, h = h, center = center);
   translate([0, 0, -2*h])
	cylinder(r = r, h = 4*h, center = false);
	}
}

module ring_half(R = 10, r = 5, h = 1, w = 0, center = true)
{
	difference()
	{
		ring(R, r, h, center);
     rotate([0, 0, w])
     translate([0, -R/2, 0])
		cube([2*R, R, 3*h], center = true);
	}
}

module ring_segment(R = 10, r = 5, h = 1, w1 = 0, w2 = 90, center = true)
{
  W2 = (w1>w2)?w2+360:w2;
  if (W2-w1 < 180)
    intersection()
		{
       ring_half(R, r, h, w1, center);
       ring_half(R, r, h, W2-180, center);
 		}
	else
    union()
		{
       ring_half(R, r, h, w1, center);
       ring_half(R, r, h, W2-180, center);
 		}
}

module sphere_half(r = 10, w1 = 0, w2 = 0)
{
	difference()
	{
   	sphere(r);
      rotate([-w1, -w2, 0])
     	translate([0, 0, r])
		cube(2*r, 2*r, r, center = true);
	}

}

// additional code
module place_in_rect(dx =20, dy=20)
{
  cols = ceil(sqrt($children));
  rows = floor(sqrt($children));
  for(i = [0:$children-1])
	{
	  T(dx*(-cols/2+(i%cols)+.5), dy*(rows/2-floor(i/cols)-.5))
		 children(i);
	}
}

```
Cageless_Roller_Bearing.scad:
```
use <sc.scad>
use <thread.scad>

D=6; // min/step/max: [1:0.1:15]
h=14; // min/step/max: [5:0.1:100]
cnt=12; // min/step/max: [0:1:100]
omega=63; // min/step/max: [0:0.1:90]
alpha=360/(cnt*2);
beta=180-omega;
gamma=180-alpha-beta;

r1= D*sin(gamma)/sin(alpha);
r2=r1*sin(beta)/sin(gamma);
echo(r1);
echo(r2);
echo("OD", 2*(r2+D/2)); //47.55
echo("delta", (47.55-2*(r2+D/2))/2);
$fn=128;
d=11;
q=0;
q1=0.2-0.1195;
ri=r2+D/2+q;
rii=r1-D/2-q;
T=2.8;
echo(r2+D/2+T);
case=4; // [1:mounting base, 2:outside, 3:inside, 4:rollers]

// if(case==1) {mount();}
// else if(case==2) {outside();}
// else if(case==3) {inside();}
// else           {rollers(0);}

//mount();
outside();
//inside();
//rollers(0);

module rollers(q){
        for(n=[0:cnt]){Rz((360/cnt)*n) {Tx(r1){Cy(h=h,r=D/2+q); Rz(omega)Tx(D)Cy(h=h,r=D/2+q);}}}
    }

module outside(){
    union(){ring(ri+q1,ri+q1+T,ri+q1,ri+q1+T,h);
    Tz(h/2-0.653)ring(ri+q1,ri+q1+T,ri+q1-0.1,ri+q1+T,1.3);
    Tz(h/2+0.5)ring(ri+q1-3,ri+q1+T,ri+q1-3,ri+q1+T,1);
    }}

module inside(){
    union(){Tz(h/2-0.65)ring(d,rii-q1,d,rii+0.15-q1,1.3);
    ring(d,rii-q1,d,rii-q1,h);
    Tz(h/2+0.5)ring(d,rii+5-q1,d,rii+5-q1,1);
    }}

module mount(){
    D(){
    Tz(-h/2+0.5+1)Cy(r=r2+D/2+2,h=5);
    Tz(-h/2+2.05)ring(r1-(D/2)/sqrt(3),r2+(D/2)/sqrt(3),r1-(D/2)/sqrt(3),r2+(D/2)/sqrt(3),4.1);
    Tz(-h/2+0.5)Cy(r=r1-D/2-2,h=8);
    rollers(0.3);}}

module ring(ri1,ra1,ri2,ra2,h){
    difference(){
        cylinder(r1=ra1,r2=ra2,h=h,center=true,$fn=511);
        cylinder(r1=ri1,r2=ri2,h=h+0.01,center=true,$fn=511);
        }
    }

//Tz(-7)threading(pitch = 1.25, d=8*(7/5.67), windings=20, full=true, steps = 256);
```


[User]
Hey there, I'm looking to create a customizable 2D gimbal for my camera using OpenSCAD, and I'd like your help generating the necessary files. I want to be able to adjust it to fit different camera sizes and weights, as well as adjust for different types of cameras, like action cams and compact cameras.

Here's the general idea: the gimbal should have an arm that balances the camera with the weight of the motors. I've got a good idea of the different parts and how they should connect together, but I need help putting it all into parametric OpenSCAD files.

Here's what I'm looking for:
1.  **Main Arm Design (2D-Arm.scad):**
    *   The arm should connect to two motors and hold the camera.
    *   It needs to take into account the width and height of the camera (camWidth, camHeight) and the weight of the camera and motor (camWeight, motorWeight). Also, there should be some parameter to specify the weight of the other parts on the arm.
    *   There should be a way to calculate the optimal arm length for balance based on the weights and sizes.
    *   The arm should have mounting points for 2208 motors using a plate.
    *   There should be space for wires.
2.  **Controller Enclosure Cover (CntCover.scad):**
    *   A cover for the controller enclosure with adjustable width and height.
    *   Option to have an opening for LED lights, including an adjustable distance from the front left corner.
3.  **Flexible Controller Enclosure (2D-CntFlex.scad):**
    *   A controller box with adjustable width, height, and depth.
    *   It needs mounting points for a motor and an action cam (male connector type)
    *   Openings for cables and a joystick port
    *   Slide-in features for mounting
4. **Arm Cover (ArmCover.scad):**
    *   A cover for the arm, mainly for aesthetic purposes and cable management.
    *   It needs to be resizable and have a snapping feature for securing it to the arm.
5.  **Camera Mount (2D-CamMount.scad):**
    *   A camera mount that can accommodate both action cams (using a belt) and compact cameras (using a 1/4" screw).
    *   Adjustable width and height of the camera.
    *   Parameter to specify the distance of the screw from the left of the camera (for compact cameras)
    *   Parameter to specify the width of the sensor platine (and add a cutout for it).
    *   Mounting point for 2208 motor.
    *   Support different camera types (action cam vs compact).

I think the different files should probably be separate, so it's easier to change only the part I need to adjust.

In terms of libraries, I am not using any external libraries for these files, but I have a few modules I need to re-use across the different parts:

*   `plate2208Back()`: creates the back plate for a motor, with screw holes and a hole for the axis.
*   `plate2208Front()`: creates the front plate for a motor, with screw holes and a hole for the axis.
*   `radialScrews(screwList, screwRadius, screwHeight)`: draws a series of cylinders arranged in a circle
*   `pipe(outerRadius, thickness, height)`: creates a hollow cylinder.
*   `quarterPipe(outerRadius, thickness, height)`: creates a quarter of a pipe.
*   `ring(r, th)`: creates a ring with a given radius and thickness.
*   `halfRing(r, th)`: creates a half ring.
*    `quaterRing(r, th)`: creates a quarter ring.
*   `roofTop(c, h, height)`: creates an isosceles triangle shape.
*   `ActionCamMale(l)`: action cam connector
*   `screwMask(headRadius, headHeight, threadRadius, threadHeight)`: Creates a screw mask for screw holes

Could you help me generate these OpenSCAD files? I'd really appreciate it!

[Assistant]
2D-Arm.scad:
```
// ****************************************************************************
// Arm between the two motors
// enter the width and height of the cam and the weight of the cam and one motor
// to get the camera balanced
// author: Peter Holzwarth
// ****************************************************************************

// Camera width in millimeters, e.g. ActionCam 60, GoPro Session 38, compact camera 110
camWidth= 60; // [5:350]

// Camera height in millimeters, e.g. ActionCam 42, GoPro Session 38, compact cam 60
camHeight= 42; // [20:170]

// cam weight in grams, e.g. ActionCam 63 or small camera 200
camWeight= 63; // [10:400]

// weight of one motor in grams, e.g. 2208 motor 39
motorWeight= 39; // [10:100]

// weight of left side except camera - weight of left part of arm, holder and screws
leftParts= 8; // [0:40]

$fn=150;

armRange= 12.5+16+camWidth/2;
// echo("arm range =", armRange);

leftWeight= motorWeight+leftParts;

shiftFactor= 0.5 -(leftWeight-camWeight)/2/(leftWeight+camWeight);
// echo("shiftFactor", shiftFactor);

armLen= shiftFactor * armRange +12.5+4-20-12.5;;
echo("arm x len", armLen);

leftMotorY= camHeight/2 +10 +10 +5;
echo("arm y len", leftMotorY-20-10);

// roll motor mount
translate([0,0,16]) rotate([-90,0,0]) plate2208Front();

// left arm - 1) strong start
difference() {
	hull() {
		translate([-12.5,0,6]) cube([0.1, 10, 20]);
		translate([0,0,12]) cube([0.1, 5, 8]);
	}
	translate([0,-0.1,16]) rotate([-90,0,0]) union() {
        // cut out the axis
		cylinder(r= 4.7, h= 3, $fn=50);
        // cut out two of the screw holes
		radialScrews([[0,6], [240,6]], 2, 10);
	}
    // space for wires in strong start
    translate([-13,10,5.5]) rotate([90, 0, 0]) quaterRing(10.5, 4.1);
}

// left arm - 2) middle of arm
translate([-12.5-armLen,0,6]) difference() {
    cube([armLen, 10, 20]);
    // space for wires in arm
    translate([0,10,10]) rotate([0,90,0]) cylinder(r=4.1, h=armLen);
}

// arm knick
translate([-12.5-armLen,20, 6]) difference() {
    rotate([0, 0, 180]) quarterPipe(20, 10, 20);
    // space for wires
    translate([0,0,10]) rotate([0, 0, 180]) quaterRing(10, 4.1);
}

// arm to the front
translate([-12.5-armLen-20,20,6]) difference() {
    // 10mm cube
	cube([10, leftMotorY-20-10, 20]);
    // space for motor
	translate([0, leftMotorY-20, 10]) rotate([0, 90, 0]) cylinder(r= 14, h= 10.1);
    // space for cable
    hull() {
        translate([10, 0, 10]) rotate([-90,0,0]) cylinder(r= 4.1, h=1);
        translate([4, leftMotorY-33, 4]) cube([6, 1, 12]);
    }
}

// tilt/pitch motor mount
translate([-12.5-armLen-20+4, leftMotorY,16]) difference() {
    rotate([0,-90,0]) union() {
        // plate
        rotate([0,0,-45]) plate2208Back();
        // ring around the motor
        translate([0,0,-6]) pipe(16, 2, 10);
    }
    // cable connector hole
    translate([0, -16, -6]) cube([6.1, 4, 12]);
    translate([0,11.5,8]) rotate([0, 90, 0]) roofTop(16, 7, 6.1);
}

// beauty box to improve print
translate([-12.5-armLen-20,leftMotorY+10,6]) difference() {
    // 10mm cube
	cube([10, 9, 20]);
    // space for motor
    translate([4,0,20]) rotate([0, 90, 0]) roofTop(20, 7, 6.1);
}

// create a back plate for a motor
module plate2208Back() {
    plate2208BackI(2, 1.75, false); // plate inner part
    translate([0,0,2]) plate2208BackI(2, 3, true); // plate outer part
}

module plate2208BackI(plateHeight, screwRadius, fillAxis) {
    difference() {
        cylinder(r= 14, h= plateHeight);
        radialScrews([[0,9.5], [90,8], [180,9.5], [270,8]], screwRadius, plateHeight); // holes for the screws
        if (!fillAxis) {
            cylinder(r= 4, h= plateHeight); // hole for the axis
        }
    }
}

// create a front plate for a motor
module plate2208Front() {
    plate2208FrontI(2, 1.1, false);
    translate([0,0,2]) plate2208FrontI(1, 1.1, true);
    translate([0,0,3]) plate2208FrontI(1, 2, true);
}

module plate2208FrontI(plateHeight, screwRadius, fillAxis) {
    difference() {
        cylinder(r= 12.5, h= plateHeight);
        // holes for the screws
        translate([0, 0, -0.1])
            radialScrews([[0,6], [120,6], [240,6]],
                screwRadius, plateHeight+0.2);
        if (!fillAxis) {
            // hole for the axis
            translate([0, 0, -0.1])
                cylinder(r= 4.7, h= plateHeight+0.2, $fn=50);
        }
    }
}

module radialScrews(screwList, screwRadius= 1, screwHeight= 1) {
    for (screw= screwList) {
        alpha= screw[0];
        c= screw[1];
        x= sin(alpha) * c;
        y= cos(alpha) * c;
        translate([x, y, 0]) cylinder(r= screwRadius, h= screwHeight, $fn=20);
    }
}

// a pipe - a hollow cylinder
module pipe(outerRadius, thickness, height) {
    difference() {
        cylinder(h=height, r=outerRadius);
        translate([0, 0, -0.1]) cylinder(h=height+0.2, r=outerRadius-thickness);
    }
}

// a quarter of a pipe
module quarterPipe(outerRadius, thickness, height) {
    difference() {
        pipe(outerRadius, thickness, height);
        translate([-outerRadius, -outerRadius, -0.1])
            cube([2*outerRadius, outerRadius, height+0.2], center=false);
        translate([-outerRadius, 0, -0.1])
            cube([outerRadius, outerRadius, height+0.2], center=false);
    }
}

// ////////////////////////////////////////////////////////////////
// a ring with a radius and a thickness
module ring(r, th) {
    rotate_extrude(convexity = r, $fn = 100)
    translate([r, 0, 0])
    circle(r = th, $fn = 100);
}

// ////////////////////////////////////////////////////////////////
// a half ring
module halfRing(r, th) {
    difference() {
        ring(r, th);
        translate([-r-th, -r-th, -th-0.1]) cube([2*r+2*th, r+th, 2*th+0.2]);
    }
}

// ////////////////////////////////////////////////////////////////
// a quater of a ring
module quaterRing(r, th) {
    difference() {
        halfRing(r, th);
        translate([-r-th, -0.01, -th-0.1]) cube([r+th, r+th+0.02, 2*th+0.2]);
    }
}

// ////////////////////////////////////////////////////////////////
// isosceles triangle
module roofTop(c, h, height) {
    translate([0,0,height/2])
        linear_extrude(height= height, center = true, convexity = 1)
            polygon(points = [[0,0], [c,0], [c/2,h]],
                paths = [[0, 1, 2]],
                convexity = 1);
}
```
CntCover.scad:
```
// ****************************************************************************
// Cover for the controller enclosure
// resize and add holes for LEDs as required...
// Author: Peter Holzwarth
// ****************************************************************************

// width of the controller box in mm
boxWidth= 74+4; // [20:100]

// height of the controller box in mm
boxHeight= 53+4; // [20:100]

// distance of the LED window from the front left corner, or 0 for no window
LedWindow= 28; // [0:100]

// controller cap
controllerCap([boxWidth, boxHeight], LedWindow);

module controllerCap(dimensions, LedWindow) {
    difference() {
        // outer box
        cube([dimensions[0]-3, dimensions[1]-2, 3.8]);
        // slide-in left
        translate([-0.1, -0.1, 1.8])
            cube([1.1, dimensions[1]-2+0.2, 2.1]);
        // slide-in right
        translate([dimensions[0]-3-1, -0.1, 1.8])
            cube([1.1, dimensions[1]-2+0.2, 2.1]);
        if (LedWindow) {
            // opening for LED lights
            translate([LedWindow, -0.1, -0.1]) cube([6, 8.1, 4.2]);
        }
    }
}
```
2D-CntFlex.scad:
```
// ****************************************************************************
// Sizeable controller cover
// resize as required, adapt holes for cables as required
// Author: Peter Holzwarth
// ****************************************************************************

// width of the controller box in mm, including the left and right walls
boxWidth= 74+4; // [20:100]

// height of the controller box in mm, including the upper and lower walls
boxHeight= 53+4; // [20:100]

// depth of the controller box in mm
boxDepth= 16; // [10:30]

$fn=150;

// controller enclosure
translate([-boxWidth/2, -boxHeight, 0])
    controllerFlex([boxWidth, boxHeight, boxDepth]);

// motor plate fixture for controller
difference() {
    translate([-10, -2, 0]) hull() {
        translate([0, 0, boxDepth-4]) cube([20, 6, 4]);
        translate([0, 0, boxDepth/2]) cube([20, 2, 1]);
    }
    // space for motor
    translate([0, 14, boxDepth/2]) cylinder(r= 14, h= boxDepth/2+0.1);
}

// motor plate
translate([0,14,boxDepth-4]) rotate([0,0,45]) plate2208Back();

// action cam mount
translate([-4.5,12+14-6,boxDepth+8]) rotate([90,0,0])
    ActionCamMale(4, true);

// action cam fixture
hull() {
    translate([-4.5, 8,boxDepth+8]) cube([9, 12, 1]);
    translate([-3, 6,boxDepth-1]) cube([6, 16, 1]);
}

module controllerFlex(dimensions) {
    difference() {
        // outer box
        cube([dimensions[0], dimensions[1], dimensions[2]]);
        // inner space for board
        translate([2, 2, 2])
            cube([dimensions[0]-4, dimensions[1]-4, dimensions[2]-2+0.1]);
        // opening for cables in upper left corner
        translate([dimensions[0]/5, dimensions[1]-4-9, -0.1])
            cube([9, 9, 2.2]);
        // opening for cables in bottom middle
        translate([dimensions[0]/2-1, -0.1, 4])
            cube([2, 2.2, dimensions[2]-4]);
        // opening for joytick port right to the cable opening
        translate([dimensions[0]-23-2, -0.1, 4])
            cube([6, 2.2, dimensions[2]-4]);
        // opening for cap
        translate([2, -0.1, dimensions[2]-4])
            cube([dimensions[0]-4, 2.2, 4.1]);
        // slide-in left
        translate([1, 0, dimensions[2]-4])
            cube([2, dimensions[1]-2, 2]);
        // slide-in right
        translate([dimensions[0]-3, 0, dimensions[2]-4])
            cube([2, dimensions[1]-2, 2]);
    }
}

// create a back plate for a 2208 motor
module plate2208Back() {
    // plate inner part
    plate2208BackI(2, 1.75, false);
    // plate outer part
    translate([0,0,2]) plate2208BackI(2, 3, true);
}

module plate2208BackI(plateHeight, screwRadius, fillAxis) {
    difference() {
        cylinder(r= 14, h= plateHeight);
        // holes for the screws
        radialScrews([[0,9.5], [90,8], [180,9.5], [270,8]],
                    screwRadius, plateHeight);
        if (!fillAxis) {
            // hole for the axis
            cylinder(r= 4, h= plateHeight);
        }
    }
}

module radialScrews(screwList, screwRadius= 1, screwHeight= 1) {
    for (screw= screwList) {
        alpha= screw[0];
        c= screw[1];
        x= sin(alpha) * c;
        y= cos(alpha) * c;
        translate([x, y, 0])
            cylinder(r= screwRadius, h= screwHeight, $fn=20);
    }
}

// ////////////////////////////////////////////////////////////////
// Action cam connector, camera side
module ActionCamMale(l) {
    for (i= [0, 6]) {
        translate ([i, 0, 0]) ActionCamOneRing(l);
    }
}

// helper
module ActionCamOneRing(l) {
    translate([0, 0, 6]) rotate([0, 90, 0]) difference() {
        hull() {
            translate([0, 6+l, 0]) cylinder(r=6, h=3);
            translate([-6, 0, 0]) cube([12,1,3]);
        }
        translate([0, 6+l, 0]) cylinder(r=2.5, h=3);
    }
}
```
ArmCover.scad:
```
// ****************************************************************************
// Arm cover, can be used to fix the cables in the arm
// resize as required
// Author: Peter Holzwarth
// ****************************************************************************

// length of one arm
len1= 18; // [5:180]

// length of other arm
len2= 20; // [5:180]

rotate([0,-90,0]) cover(len1);
translate([0, 20, 0]) rotate([0,-90,0]) cover(len2);

// an arm cover, 20mm wide
module cover(width) {
    difference() {
        cube([width,14,20+4]);
        // inner part
        translate([-0.1, 2, 2]) cube([width+0.2,10,20]);
        // snapping part
        translate([-0.1, 3, -0.1]) cube([width+.2,8,2.2]);
    }
}

```
2D-CamMount.scad:
```
// ****************************************************************************
// Arm for ActionCams using a belt and for compact cameras, using a 1/4 screw
// enter the width and height of the cam to get it balanced
// enter the width of the sensor platine to get a hole for it, or 0 for no hole
// Author: Peter Holzwarth
// ****************************************************************************

// Cam type, 1 action cam, 2 compact camera
camType= 1; // [1:ActionCam/Belt, 2:CompactCam/Screw]

// Camera width in millimeters, e.g. ActionCam 60, GoPro Session 38
camWidth= 60; // [5:350]

// Camera height in millimeters, e.g. ActionCam: 42, GoPro Session 38
camHeight= 42; // [20:170]

// For compact camera, ignore for action cam
boltFromLeftOfCamera= 15; // [8:340]

// width of the sensor platine in mm, e.g. 16
sensorWidth= 16; // [0:18]

$fn=150;

// roll motor mount
translate([0,0,12.5]) rotate([-90,30,0]) plate2208Front();

// length of the arm above the bow, needs to be positive
armLen= camHeight/2 -(16-10)-8;
echo ("Arm len ", armLen);

// strong start of arm
difference() {
    hull() {
        translate([-8-armLen,0,0]) cube([armLen, 10, 25]);
        translate([8.8-1,0,3.5+18]) rotate([90,90,90]) trapezoid(18, 10, 6, 1);
    }
    translate([0,-0.1,12.5]) rotate([-90,30,0])
        radialScrews([[0,6], [120,6], [240,6]], 2, 10);
    translate([0,-0.1,12.5]) rotate([-90,30,0]) cylinder(r= 4.7, 3);
}

// arm bow
translate([-8-armLen, 0, 0]) difference() {
    translate([0, 16, 0]) rotate([0,0,180])
        quarterPipe(16, 10, 25);
    translate([-16+3.5, 0, (25-sensorWidth)/2]) cube([3, 20, sensorWidth]);
}

// arm for camera
translate([-8-armLen-16,16,0]) difference() {
    cube([10,camWidth,25]);
    // hole for bolt
    if (camType == 1) {
        translate([3.5,0,-0.1]) cube([3,camWidth-10,25.2]);
    } else if (camType == 2) {
        translate([-0.1,boltFromLeftOfCamera,12.5]) rotate([0,90,0])
            screwMask(7.5,5,3,12);
    }
}

// translate([0,85,0]) rotate([0,0,-90]) trapezoid(30, 20, 5, 25);

// create a front plate for a motor
module plate2208Front() {
    plate2208FrontI(2, 1.1, false);
    translate([0,0,2]) plate2208FrontI(1, 1.1, true);
    translate([0,0,3]) plate2208FrontI(1, 2, true);
}

module plate2208FrontI(plateHeight, screwRadius, fillAxis) {
    difference() {
        cylinder(r= 12.5, h= plateHeight);
        // holes for the screws
        translate([0, 0, -0.1])
            radialScrews([[0,6], [120,6], [240,6]],
                screwRadius, plateHeight+0.2);
        if (!fillAxis) {
            // hole for the axis
            translate([0, 0, -0.1])
                cylinder(r= 4.7, h= plateHeight+0.2, $fn=50);
        }
    }
}

// draw cylinders around a center
module radialScrews(screwList, screwRadius= 1, screwHeight= 1) {
    for (screw= screwList) {
        alpha= screw[0];
        c= screw[1];
        x= sin(alpha) * c;
        y= cos(alpha) * c;
        translate([x, y, 0]) cylinder(r= screwRadius, h= screwHeight);
    }
}

// a pipe - a hollow cylinder
module pipe(outerRadius, thickness, height) {
    difference() {
        cylinder(h=height, r=outerRadius);
        translate([0, 0, -0.1]) cylinder(h=height+0.2, r=outerRadius-thickness);
    }
}

// a quarter of a pipe
module quarterPipe(outerRadius, thickness, height) {
    difference() {
        pipe(outerRadius, thickness, height);
        // lower half
        translate([-outerRadius, -outerRadius, -0.01])
            cube([2*outerRadius, outerRadius, height+0.02], center=false);
        // left quater
        translate([-outerRadius, -0.01, -0.01])
            cube([outerRadius, outerRadius+0.02, height+0.02], center=false);
    }
}

// a trapezoid
module trapezoid(w1, w2, h, height) {
    translate([0,0,height/2])
        linear_extrude(height= height, center = true, convexity = 1)
            polygon(points = [[0,0], [w1,0], [w1/2+w2/2,h], [w1/2-w2/2,h]],
                paths = [[0, 1, 2, 3]],
                convexity = 1);
}

module screwMask(headRadius, headHeight, threadRadius, threadHeight) {
    cylinder(r= headRadius, h= headHeight);
    translate([0,0,headHeight]) cylinder(r= threadRadius, h= threadHeight);
}
```


[User]
Hi, I'm looking to generate some custom bonsai pots and saucers. I've been using a slightly modified version of an existing script but I'm not happy with how it handles some of the more complex shapes and I think it could be more efficient. I would like you to generate a new set of OpenSCAD files for me that are fully parametric so I can easily adjust them.

Specifically, I'd like the following:

**Overall Design**

*   **Pot and Saucer Generation:** The script should be able to generate a pot only, a saucer only, or both a pot and a saucer together, based on a variable setting.
*   **Preview Mode:** A boolean variable (`preview`) to enable a faster, rough preview and a separate setting for speed (`mode` such as preview, fast, slow) with different rendering approaches.
*   **Base Dimensions:** The design should be controlled by `base_width`, `top_width`, and `depth` variables to set the base width, top width, and overall depth of the pot and saucer combination.
*  **Wall Thickness:**  The wall thickness of both pot and saucer should be controlled by a `thickness` variable.
*  **Base Shape:** The base shape of the pot and saucer should be configurable via a string (`shape`), with support for at least the following: "elliptical", "hexagonal", "round", "octagonal", "cloud", "cloud2", "ecloud", and "square".
*   **Profile:** The vertical profile of the pot and saucer should be configurable via string variables, `pot_profile` and `saucer_profile` and should support at least linear ('l'), c-shaped ('c'), and s-shaped ('s'). The 'j' profile should also be included for saucers only. The profile should be achieved by using `linear_extrude` and scaling.

**Pot-Specific Features**

*   **Pot Height:**  The pot's height should be set by a `pot_height` variable.
*   **Drainage:**  The pot should have two symmetrical drainage holes at the base. These should be generated using an intersection with a hex grid pattern for printability, and should scale in size with `pot_height`.
* **Engraving:** The option to engrave text on the front and back of the pot should be controlled by a boolean variable, `engrave`, with a `engrave_text` and `engrave_font` to control the engraving itself.

**Saucer-Specific Features**
*   **Saucer Height:** The saucer height should be controlled by a `saucer_height` variable.
*  **Ridge:** Include two small ridges on the saucer to lift the pot up slightly.

**Implementation Details**

*   The code should use modules to encapsulate the logic for each part of the design (e.g. `base_shape`, `shell_generator`, `pot_shell`, `saucer`, `pot` etc.
*   I'd prefer using `linear_extrude` with scaling for the main shape rather than minkowski where possible, but I also need the option to use minkowski for better quality, like in the old version.
*   I'd also like to be able to switch between using the `linear_extrude` or the `minkowski` for shell generation.
*   The profile functionality should be implemented as a `function`.
*   The hex grid functionality for the drain holes should be implemented as a `module`
*   The design should be easily configurable with well-commented variables.

I don't need any specific libraries, I'm just looking for a clean and well-structured parametric design in plain OpenSCAD. Thanks!

[Assistant]
bonchi-pot.scad:
```
// Copyright 2016 Luciano Montanaro <mikelima@cirulla.net>

/* [Global] */

// Generate pot, saucer or both
print="both"; // [pot:Pot only,saucer:Saucer only,both:Both Pot and Saucer]

mode = "fast"; // [preview: fast preview,fast:render faster,slow:use slow but nicer rendering]
// Preview mode avoids lengthy rendering
preview = true; // [false:Off, true:On]

// Width of the base
base_width = 115; // [50:200]

// Width at the top
top_width = 145;  // [50:200]

// Depth of the pot
depth = 81;      // [50:200]

// Wall thickness
thickness = 2.0;  // [1.0:5.0]

// Shape of the base
shape = "ecloud";  // [elliptical,hexagonal,round,octagonal,cloud,cloud2,ecloud,square]

/* [Pot] */
// Height of the pot
pot_height = 45;      // [5:200]

// Profile of the base: Linear, C shaped, S shaped
pot_profile = "s"; // [l:Linear,c:C shaped,s:S shaped]

/* [Saucer] */
// Saucer height
saucer_height = 8; // [5:20]

saucer_profile = "j"; // [l:Linear,c:C shaped,s:S shaped]

engrave = true; // [true:On, false:Off]

engrave_text="\u767B\u5C71"; // [\ut67b\u5c71,\u5730,\u6c34,\u706b,\u98a8,\u7a7a]
engrave_font="TakaoPMincho:style=Regular";

function profile(profile) =
profile == "c" ? [
[0.00, 1.00], [0.05, 1.03], [0.10, 1.04], [0.30, 1.05],
[0.70, 1.05], [0.90, 1.04], [0.96, 1.03], [1.00 ,1.00]
] :
profile == "s" ? [
[0.00, 1.00], [0.05, 1.025], [0.15, 1.05], [0.3, 1.05],
[0.70, 0.985], [0.85, 0.975], [0.95, 0.985], [1.00, 1.00]
] :
profile == "j" ? [
[0.0, 1.0], [0.07, 1.01], [0.2, 1.02], [0.5, 1.02], [1.0, 1.0]
] :
[[0, 1], [1, 1]];

module shaped_extrude(length, s, path)
{
    echo(length, s, len(path));
    for (i = [0: len(path) - 2]) {
        x0 = path[i][0];
        y0 = path[i][1];
        x1 = path[i + 1][0];
        y1 = path[i + 1][1];
        delta = length * (x1 - x0);
        h0 = length * x0;
        scale1 = y0 * (1 + (s - 1) * x0);
        scale2 = y1 * (1 + (s - 1) * x1) / scale1;
        translate([0, 0, h0]) linear_extrude(delta, scale=scale2) scale(scale1) children(0);
        // echo (x0, y0, x1, y1, ":", delta, h0, scale1, scale2);
    }
}

module hex_grid(width, height, spacing, hex_size)
{
    spacing_y = spacing * sqrt(3) / 2;
    x_count = floor(width / spacing);
    y_count = floor(height / spacing_y);
    /* Center the grid */
    x_offset = ((x_count  - 1) * spacing) / 2;
    y_offset = ((y_count  - 1) * spacing_y) / 2;

    grid_x = [for (i = [0 : spacing : width + spacing]) i];
    grid_y = [for (i = [0 : spacing : width + spacing]) i];

    for (i = [-1 : 1 : x_count]) {
        for (j = [-1 : 1 : y_count]) {
            translate([(-(j % 2)) * spacing / 2 + i * spacing - x_offset,
                    j * spacing * sqrt(3) / 2 - y_offset, 1 / 2]) {
                rotate([0, 0, 30]) cylinder(2 * thickness, d = hex_size, center = true, $fn = 6);
            }
        }
    }
}

module drain_hole(diameter)
{
    hex_size = diameter / 6;
    hex_spacing = hex_size + 1;
    intersection() {
        cylinder(2 * thickness, d = diameter, center=true);
        hex_grid(diameter, diameter, hex_spacing, hex_size);
    }
}

module base_shape(shape, w, h)
{
    if (shape == "elliptical") {
        resize([w, h]) circle(d=h, $fn=84);
    } else if (shape == "hexagonal") {
        hull() {
            translate([-(w - h) / 2, 0, 0]) circle(d=h, $fn=6);
            translate([(w - h) / 2, 0, 0]) circle(d=h, $fn=6);
        }
    } else if (shape == "round") {
        hull() {
            translate([-(w - h) / 2, 0, 0]) circle(d=h, $fn=42);
            translate([(w - h) / 2, 0, 0]) circle(d=h, $fn=42);
        }
    } else if (shape == "octagonal") {
        hull() {
            a = h / 10;
            translate([-w / 2 + 3 * a, h / 2 - a, 0]) circle(r=a, $fn=42);
            translate([-w / 2 + a, h / 2 - 3 * a, 0]) circle(r=a, $fn=42);
            translate([-w / 2 + 3 * a, -h / 2 + a, 0]) circle(r=a, $fn=42);
            translate([-w / 2 + a, -h / 2 + 3 * a, 0]) circle(r=a, $fn=42);

            translate([w / 2 - 3 * a, h / 2 - a, 0]) circle(r=a, $fn=42);
            translate([w / 2 - a, h / 2 - 3 * a, 0]) circle(r=a, $fn=42);
            translate([w / 2 - 3 * a, -h / 2 + a, 0]) circle(r=a, $fn=42);
            translate([w / 2 - a, -h / 2 + 3 * a, 0]) circle(r=a, $fn=42);
        }
    } else if (shape == "cloud") {
        union() {
            a = h / 12;
            hull() {
                translate([-w / 2 + 2 * a, h / 2 - a, 0]) circle(r=a, $fn=42);
                translate([-w / 2 + 2 * a, -h / 2 + a, 0]) circle(r=a, $fn=42);

                translate([w / 2 - 2 * a, h / 2 - a, 0]) circle(r=a, $fn=42);
                translate([w / 2 - 2 * a, -h / 2 + a, 0]) circle(r=a, $fn=42);
            }
            hull() {
                translate([-w / 2 + a, h / 2 - 2 * a, 0]) circle(r=a, $fn=42);
                translate([-w / 2 + a, -h / 2 + 2 * a, 0]) circle(r=a, $fn=42);

                translate([w / 2 - a, h / 2 - 2 * a, 0]) circle(r=a, $fn=42);
                translate([w / 2 - a, -h / 2 + 2 * a, 0]) circle(r=a, $fn=42);
            }
        }
    } else if (shape == "ecloud") {
        union() {
            a = h / 6;
            iw = w - 2 * a;
            ih = h - 2 * a;
            hull() {
                translate([0, -ih / 2, 0]) resize ([iw, 2* a]) circle(r=a, $fn=42);
                translate([0, ih / 2, 0]) resize ([iw, 2* a]) circle(r=a, $fn=42);
            }
            hull() {
                translate([-iw / 2, 0, 0]) resize ([2 * a, ih]) circle(r=a, $fn=42);
                translate([iw / 2, 0, 0]) resize ([2 * a, ih]) circle(r=a, $fn=42);
            }
        }
    } else if (shape == "cloud2") {
        union() {
            a = h / 12;
            hull() {
                translate([-w / 2 + 3 * a, h / 2 - a, 0]) circle(r=a, $fn=42);
                translate([-w / 2 + 3 * a, -h / 2 + a, 0]) circle(r=a, $fn=42);

                translate([w / 2 - 3 * a, h / 2 - a, 0]) circle(r=a, $fn=42);
                translate([w / 2 - 3 * a, -h / 2 + a, 0]) circle(r=a, $fn=42);
            }
            hull() {
                translate([-w / 2 + 2 * a, h / 2 - 2 * a, 0]) circle(r=a, $fn=42);
                translate([-w / 2 + 2 * a, -h / 2 + 2 * a, 0]) circle(r=a, $fn=42);

                translate([w / 2 - 2 * a, h / 2 - 2 * a, 0]) circle(r=a, $fn=42);
                translate([w / 2 - 2 * a, -h / 2 + 2 * a, 0]) circle(r=a, $fn=42);
            }
            hull() {
                translate([-w / 2 + a, h / 2 - 3 * a, 0]) circle(r=a, $fn=42);
                translate([-w / 2 + a, -h / 2 + 3 * a, 0]) circle(r=a, $fn=42);

                translate([w / 2 - a, h / 2 - 3 * a, 0]) circle(r=a, $fn=42);
                translate([w / 2 - a, -h / 2 + 3 * a, 0]) circle(r=a, $fn=42);
            }
        }
    } else if (shape == "square") {
        hull() {
            translate([-(w - h) / 2, 0, 0]) square(base_width, center=true);
            translate([(w - h) / 2, 0, 0]) square(base_width, center=true);
        }
    }
}

module shell_generator(shape, p, base_width, top_width, height, depth)
{
    v = profile(p);

    s = top_width / base_width;
    echo ("length:", len(v), s);
    if (mode == "fast") {
        union () {
            intersection() {
                shaped_extrude(depth, s, v) {
                    base_shape(shape, base_width, height);
                }
                cube([base_width, height, thickness], center=true);
            }
            difference() {
                shaped_extrude(depth, s, v) {
                    base_shape(shape, base_width, height);
                }
                translate([0, 0, -0.1]) {
                    shaped_extrude(depth + 0.2, s, v) {
                        offset(r = -thickness) base_shape(shape, base_width, height);
                    }
                }
            }
        }
    } else {
        difference() {
            shaped_extrude(depth, s, v) {
                base_shape(shape, base_width, height);
            }
            translate([0, 0, 0.1]) {
                shaped_extrude(depth - 0.05, s, v) {
                    base_shape(shape, base_width - 0.1, height - 0.1);
                }
            }
        }
    }
}

module pot_shell(shape, profile, base_width, top_width, height, depth, thickness)
{
    if (preview || mode == "preview") {
        shell_generator(shape, profile, base_width, top_width, height, depth);
    } else if (mode == "fast") {
        shell_generator(shape, profile, base_width, top_width, height, depth);
    } else {
        minkowski() {
            shell_generator(shape, profile, base_width, top_width, height, depth);
            sphere(d=thickness, $fn=4);
        }
    }
}

module ridge(height, thickness)
{
    cube([thickness, 9 / 10 * height,  thickness], center = true);
}

module ridges(width, height, thickness)
{
    translate([-width / 5, 0, thickness]) ridge(height, thickness);
    translate([width / 5, 0, thickness]) ridge(height, thickness);
}

module saucer(shape, profile, base_width, top_width, height, depth, thickness)
{
    union () {
        pot_shell(shape, profile, base_width, top_width, height, depth, thickness);
        ridges(base_width, height, thickness);
    }
}

module emboss(thickness)
{
    minkowski () {
        rotate(90, [1, 0, 0]) cylinder(thickness, thickness, 0, $fn=2);
        intersection () {
            translate([0, -thickness / 4, 0]) children(0);
            rotate(90, [1,0,0])
                linear_extrude(depth) scale(base_width / 750) children(1);
        }
    }
}

module pot(shape, profile, base_width, top_width, height, depth, thickness)
{
    if (engrave) {
        emboss(thickness / 2) {
            pot_shell(shape,
                profile, base_width, top_width, height, depth, thickness);
            translate([0, 150, 0])
                text( engrave_text,
                    font = engrave_font,
                    size = 120, valign = "center", halign = "center");
        }
        rotate(180, [0, 0, 1])
            emboss(thickness / 2) {
                pot_shell(shape,
                    profile, base_width, top_width, height, depth, thickness);
                translate([0, 150, 0])
                    text( engrave_text,
                        font = engrave_font,
                        size = 120, valign = "center", halign = "center");
            }
    }
    difference () {
        pot_shell(shape, profile, base_width, top_width, height, depth, thickness);
        translate ([-base_width / 5, 0, -thickness / 2]) scale([1, 1, thickness * 1.1]) drain_hole(3 * height / 7);
        translate ([base_width / 5, 0, -thickness / 2]) scale([1, 1, thickness * 1.1]) drain_hole(3 * height / 7);
    }
}

/* Note: with a 0.3 nozzle, 0.15 layer height, 1mm is too thin to have a watertight pot. 1.2 could be just enough */

// saucer("cloud", 116, 130, 72, 8, 1.5);
// translate([0, 0, 5]) pot("cloud", 110, 130, 68, 60, 1.8);

// saucer("elliptical", 116, 130, 72, 8, 1.5);
// translate([0, 0, 5]) pot("elliptical", 110, 130, 68, 40, 1.8);

// saucer("elliptical", 161, 183, 100, 8, 1.8);
// translate([0, 0, 5]) pot("elliptical", 155, 183, 96, 40, 1.8);

// saucer("elliptical", "c", 164, 180, 114, 8, 2);
// translate([0, 0, 5]) pot("elliptical", "c", 160, 185, 110, 50, 2);

if (print == "both" || print =="saucer") {
    saucer(shape, saucer_profile, base_width + 4 * thickness, top_width, depth + 4 * thickness, saucer_height, thickness);
}
if (print == "both" || print =="pot") {
    translate([0, 0, 5]) pot(shape, pot_profile, base_width, top_width, depth, pot_height, thickness);
}
// vi: set et sw=4:

```
bonchi-pot-old.scad:
```
// Copyright 2016 Luciano Montanaro <mikelima@cirulla.net>

// [Global]

// Generate pot, saucer or both
print="both"; // [pot:Pot only,saucer:Saucer only,both:Both Pot and Saucer]

// Preview mode avoids lengthy rendering
preview = 1; // [0, 1]

// Width of the base
base_width = 160; // [50:200]

// Width at the top
top_width = 185;  // [50:200]

// Depth of the pot
depth = 120;      // [50:200]

// Wall thickness
thickness = 1.5;  // [1.0:5.0]

// Shape of the base
shape = "elliptical";  // [elliptical,hexagonal,round,octagonal,cloud,square]

// [Pot]
// Height of the pot
pot_height = 60;      // [5:200]

// Profile of the base: Linear, C shaped, S shaped
pot_profile = "c"; // [l:Linear,c:C shaped,s:S shaped]

// [Saucer]
// Saucer height
saucer_height = 8; // [5:20]

saucer_profile = "l"; // Strings: [l,c,s]

function profile(profile) =
profile == "c" ? [[0.0, 1.0], [0.05, 1.03], [0.1, 1.04], [0.9, 1.04], [0.95, 1.03], [1.0 ,1.0]] :
profile == "s" ? [[0.0, 1.0], [0.05, 1.03], [0.1, 1.04], [0.9, 0.96], [0.95, 0.97], [1.0, 1.0]] :
[[0, 1], [1, 1]];

module shaped_extrude(length, s, path)
{
    echo(length, s, len(path));
    for (i = [0: len(path) - 2]) {
	x0 = path[i][0];
	y0 = path[i][1];
	x1 = path[i + 1][0];
	y1 = path[i + 1][1];
	delta = length * (x1 - x0);
	h0 = length * x0;
	scale1 = y0 * (1 + (s - 1) * x0);
	scale2 = y1 * (1 + (s - 1) * x1) / scale1;
	translate([0, 0, h0]) linear_extrude(delta, scale=scale2) scale(scale1) children(0);
	echo (x0, y0, x1, y1, ":", delta, h0, scale1, scale2);
    }
}

module hex_grid(width, height, spacing, hex_size)
{
    spacing_y = spacing * sqrt(3) / 2;
    x_count = floor(width / spacing);
    y_count = floor(height / spacing_y);
    /* Center the grid */
    x_offset = (x_count * spacing) / 2;
    y_offset = (y_count * spacing_y) / 2;

    grid_x = [for (i = [0 : spacing : width + spacing]) i];
    grid_y = [for (i = [0 : spacing : width + spacing]) i];

    for (i = [-1 : 1 : x_count]) {
	for (j = [-1 : 1 : y_count]) {
	    translate([(-(j % 2)) * spacing / 2 + i * spacing - x_offset,
		    j * spacing * sqrt(3) / 2 - y_offset, 1 / 2]) {
		rotate([0, 0, 30]) cylinder(1, d = hex_size, center = true, $fn = 6);
	    }
	}
    }
}

module drain_hole(diameter)
{
    intersection() {
	cylinder(1, d = diameter);
	hex_grid(diameter, diameter, diameter / 5, diameter / 6);
    }
}

module base_shape(shape, w, h)
{
    if (shape == "elliptical") {
	resize([w, h]) circle(d=h, $fn=42);
    } else if (shape == "hexagonal") {
	hull() {
	    translate([-(w - h) / 2, 0, 0]) circle(d=h, $fn=6);
	    translate([(w - h) / 2, 0, 0]) circle(d=h, $fn=6);
	}
    } else if (shape == "round") {
	hull() {
	    translate([-(w - h) / 2, 0, 0]) circle(d=h, $fn=42);
	    translate([(w - h) / 2, 0, 0]) circle(d=h, $fn=42);
	}
    } else if (shape == "octagonal") {
	hull() {
	    a = h / 10;
	    translate([-w / 2 + 2 * a, h / 2 - a, 0]) circle(r=a, $fn=42);
	    translate([-w / 2 + a, h / 2 - 2 * a, 0]) circle(r=a, $fn=42);
	    translate([-w / 2 + 2 * a, -h / 2 + a, 0]) circle(r=a, $fn=42);
	    translate([-w / 2 + a, -h / 2 + 2 * a, 0]) circle(r=a, $fn=42);

	    translate([w / 2 - 2 * a, h / 2 - a, 0]) circle(r=a, $fn=42);
	    translate([w / 2 - a, h / 2 - 2 * a, 0]) circle(r=a, $fn=42);
	    translate([w / 2 - 2 * a, -h / 2 + a, 0]) circle(r=a, $fn=42);
	    translate([w / 2 - a, -h / 2 + 2 * a, 0]) circle(r=a, $fn=42);
	}
    } else if (shape == "cloud") {
	union() {
	    a = h / 12;
	    hull() {
		translate([-w / 2 + 2 * a, h / 2 - a, 0]) circle(r=a, $fn=42);
		translate([-w / 2 + 2 * a, -h / 2 + a, 0]) circle(r=a, $fn=42);

		translate([w / 2 - 2 * a, h / 2 - a, 0]) circle(r=a, $fn=42);
		translate([w / 2 - 2 * a, -h / 2 + a, 0]) circle(r=a, $fn=42);
	    }
	    hull() {
		translate([-w / 2 + a, h / 2 - 2 * a, 0]) circle(r=a, $fn=42);
		translate([-w / 2 + a, -h / 2 + 2 * a, 0]) circle(r=a, $fn=42);

		translate([w / 2 - a, h / 2 - 2 * a, 0]) circle(r=a, $fn=42);
		translate([w / 2 - a, -h / 2 + 2 * a, 0]) circle(r=a, $fn=42);
	    }
	}
    } else if (shape == "square") {
	hull() {
	    translate([-(w -h) / 2, 0, 0]) square(base_width, center=true);
	    translate([(w -h) / 2, 0, 0]) square(base_width, center=true);
	}
    }
}

module shell_generator(shape, p, base_width, top_width, height, depth)
{
    v = profile(p);

    s = top_width / base_width;
    echo ("length:", len(v), s);
    difference() {
	shaped_extrude(depth, s, v) {
	    base_shape(shape, base_width, height);
	}
	translate([0, 0, 0.1]) {
	    shaped_extrude(depth - 0.05, s, v) {
		base_shape(shape, base_width - 0.1, height - 0.1);
	    }
	}
    }
}

module pot_shell(shape, profile, base_width, top_width, height, depth, thickness)
{
    if (preview) {
	shell_generator(shape, profile, base_width, top_width, height, depth);
    } else {
	minkowski() {
	    shell_generator(shape, profile, base_width, top_width, height, depth);
	    sphere(d=thickness);
	}
    }
}

module ridge(height, thickness)
{
    cube([thickness, 9 / 10 * height,  thickness], center = true);
}

module ridges(width, height, thickness)
{
# translate([-width / 5, 0, thickness]) ridge(height, thickness);
# translate([width / 5, 0, thickness]) ridge(height, thickness);
}

module saucer(shape, profile, base_width, top_width, height, depth, thickness)
{
    union () {
	pot_shell(shape, profile, base_width, top_width, height, depth, thickness);
	ridges(base_width, height, thickness);
    }
}

module pot(shape, profile, base_width, top_width, height, depth, thickness)
{
    difference () {
	pot_shell(shape, profile, base_width, top_width, height, depth, thickness);
	translate ([-base_width / 5, 0, -thickness / 2]) scale([1, 1, thickness * 1.1]) drain_hole(3 * height / 7);
	translate ([base_width / 5, 0, -thickness / 2]) scale([1, 1, thickness * 1.1]) drain_hole(3 * height / 7);
    }
}

/* Note: with a 0.3 nozzle, 0.15 layer height, 1mm is too thin to have a watertight pot. 1.2 could be just enough */

// saucer("cloud", 116, 130, 72, 8, 1.5);
// translate([0, 0, 5]) pot("cloud", 110, 130, 68, 60, 1.8);

// saucer("elliptical", 116, 130, 72, 8, 1.5);
// translate([0, 0, 5]) pot("elliptical", 110, 130, 68, 40, 1.8);

// saucer("elliptical", 161, 183, 100, 8, 1.8);
// translate([0, 0, 5]) pot("elliptical", 155, 183, 96, 40, 1.8);

// saucer("elliptical", "c", 164, 180, 114, 8, 2);
// translate([0, 0, 5]) pot("elliptical", "c", 160, 185, 110, 50, 2);

if (print == "both" || print =="saucer") {
    saucer(shape, saucer_profile, base_width + 3 * thickness, top_width, depth + 3 * thickness, saucer_height, thickness);
}
if (print == "both" || print =="pot") {
    translate([0, 0, 5]) pot(shape, pot_profile, base_width, top_width, depth, pot_height, thickness);
}

```


[User]
I'm looking to create a gyroscopic keyring, similar to the one described in the provided OpenSCAD file (GKRG_v2.scad), but I'd like a more flexible and customizable version.

Here's what I need:

*   **Core Structure:** The keyring should consist of a central sphere, a number of inner rings, and a final outer ring.
*   **Parametric Design:** I want all the key dimensions to be driven by parameters:
    *   `total_height`: The overall height of the model.
    *   `diam_central_sphere`: The diameter of the central sphere.
    *   `gap`: The gap between rings.
    *   `ring_thickness`: The thickness of the inner rings.
    *   `last_ring_thickness`: The thickness of the outer ring.
    *   `lug_ident`: The distance the lugs (or "protrusions") indent from the outer side of the last ring.
    *   `diam_central_cylinder`: The diameter of the hole through the central sphere.
    *  `lettering_text`: The text printed on the outer ring
     *   `letter_thickness`: The thickness of the letters on the outer ring.
    *   `number_of_rings`: The number of inner rings.
*   **Text on Outer Ring:** The design must include the ability to print text onto the outer ring. I'd like the text to follow the circumference of the ring. Also, allow for a space character in `lettering_text`, in order to leave sections of the ring blank.
*   **Lugs/Protrusions:** The outer ring should include lugs, symmetrically placed on the outer ring, that should extend out slightly and that have a rounded shape, something like half a cylinder. They should be on opposite sides of the ring, and should line up with the text to be used to rotate the rings.
*   **Font:** I'd like to be able to specify a monospaced font.
*   **Units:** All dimensions should be in millimeters.
*   **Fragment Size/Angle:** I'd like the equivalent of `$fs` and `$fa` to be parameters as well, so I can fine tune the mesh resolution. These should be global variables, not within any module.

Essentially, I need an OpenSCAD design that lets me easily adjust all of these parameters and regenerate the model, while not relying on the specific implementation in the given file. I don't need anything fancy with libraries, and I would rather not have to specify which library is being used, unless it is absolutely necessary.

[Assistant]
GKRG_v2.scad:
```

//Глобальный параметр - размера минимального фрагмента на поверхности. Зависит от 3Д принтера, обычно 0.3-1. Сильно влияет на скорость рендера модели.
//Global parameter - the minimum size of the fragment on the surface. Depends on the 3D printer, typically 0.3-1. Greatly affect the speed rendering model.
$fs = 1;

//Глобальный параметр - размер минимального угла для фрагмента. От этого зависит "гладкость" окружностей. Обычно 3-7. Сильно влияет на скорость рендера модели.
//Global parameter - the size of the minimum angle for the fragment. On this depends the "smoothness" of the circles. Usually 3-7. Greatly affect the speed rendering model.
$fa = 7;

// all size in mm
// все значения размеров в мм

//Общая высота модели
//Total model height
total_height = 14;

//Диаметр центральной сферы. Желательно делать немного больше чем total_height
//The diameter of the central sphere. It is advisable to do a little more than the total_height
diam_central_sphere = 16;

//Зазор между кольцами. Зависит от возможностей 3D принтера
//The gap between the rings. It depends on the capabilities of 3D printer
gap = 0.5;

//Толщина колец
//The thickness of the rings
ring_thickness = 1;

//Толщина последнего (внешнего) кольца
//The thickness of the latter (outer) ring
last_ring_thickness = 2;

//Отступ проушины от внешней стороны кольца
//Indentation lugs on the external side of the ring
lug_ident = 1;

//Диаметр внутреннего отверстия в центральной сфере
//The diameter of the inner hole in the central sphere
diam_central_cylinder = 5;

//Текст для вывода на внешний обод последнего кольца. Длина никак не контролируется, что может приводить в проблемам. Для генерации кольца без текста, переменная должна содержать символ "пробел". Можно "управлять" размещением символов с помощью пробелов в начале и конце текста. Желательно использовать только заглавные буквы.
//Text for printing on the outer rim of the last ring. The length is not controlled, it can lead to problems. To generate ring without text, should contain a "space" character. It is possible to "manage" the placement of symbols with the spaces at the beginning and end of the text. It is advisable to use only capital letters.
lettering_text = "Qwerty!_.";

//Толщина букв на внешем ободе последнего кольца
//The thickness of the letters on the outer rim of the last ring
letter_thickness = 1;

//Фонт по умолчанию. Желательно использовать моноширинные шрифты
//Default Font. Better use monospaced fonts.
//def_font = "Lucida Console:style=Regular";
def_font = "Liberation Mono:style=Regular";

//Количество внутренних колец, т.е. между центральной сферой и последним кольцом.
//The number of inner rings, ie, between the central sphere and the last ring.
number_of_rings = 5;

// Main geometry
CentralSphere();

for (i = [1 : number_of_rings]){
	SphereN(i);
}

SphereFinal(number_of_rings);

module CentralSphere() {
	difference(){
		intersection() {
			sphere(d = diam_central_sphere, center = true);
			cube([diam_central_sphere, diam_central_sphere, total_height], center = true);
		}
		cylinder(h = total_height+1, d = diam_central_cylinder, center = true);
	}
}

module SphereN(N) {
	cur_sphere_d = diam_central_sphere + gap*2*N + ring_thickness*2*N;
	cur_inner_sphere_d = cur_sphere_d - ring_thickness*2;

	echo("Ring:", N, ", sphere out d=", cur_sphere_d, ", in d=", cur_inner_sphere_d);

	intersection(){
		difference() {
			sphere(d = cur_sphere_d, center = true);
			sphere(d = cur_inner_sphere_d, center = true);
		}
		cube([cur_sphere_d, cur_sphere_d, total_height], center = true);
	}
}

module SphereFinal(N){
	cur_sphere_d = diam_central_sphere+ring_thickness*2*N+gap*2*N+last_ring_thickness*2+gap*2;
	cur_inner_sphere_d = cur_sphere_d-last_ring_thickness*2;
	lug_angle = (total_height/3+6)/(cur_sphere_d/2)*(180/PI);

	echo("Last ring:", cur_sphere_d, "/", cur_inner_sphere_d, "N:", N, lug_angle);
	union(){

		intersection(){
			difference(){
				sphere(d = cur_sphere_d, center=true);
				sphere(d = cur_inner_sphere_d, center=true);
			}
			cube([cur_sphere_d, cur_sphere_d, total_height], center = true);
		}

		WriteOnRing(lettering_text, cur_sphere_d/2, total_height-2, lug_angle);

		sym_seg = (360-lug_angle)/len(lettering_text);
		rotate([0,0,-(90+sym_seg/2+lug_angle/2)]){
			union(){
				translate([-total_height/3, cur_sphere_d/2+lug_ident, 0]){
					rotate([0, 90, 0])
					rotate_extrude(angle=180, convexity=10)
					translate([total_height/3, total_height/3, 0])
					scale([1, 2, 1])
					circle(d = total_height/3, center=true);
				}
				difference(){
					translate([0, 0, total_height/2-total_height/3/2]){
						rotate([-90, 90, 0])
						linear_extrude(height = cur_sphere_d/2+lug_ident)
						scale([1, 2, 1])
						circle(d = total_height/3, center = true);
					}
					sphere(d=cur_inner_sphere_d + last_ring_thickness*2);
				}
				difference(){
					translate([0, 0, -total_height/2+total_height/3/2]){
						rotate([-90, 90, 0])
						linear_extrude(height = cur_sphere_d/2+lug_ident)
						scale([1, 2, 1])
						circle(d = total_height/3, center = true);
					}
					sphere(d=cur_inner_sphere_d + last_ring_thickness*2);
				}
			}
		}
	}
}

module WriteOnRing(text, radius, h, lug_angle){

	text_len = len(text);
	sym_seg = (360-lug_angle)/(text_len);

	intersection(){
		for (i=[0:text_len-1]){
			curangle = sym_seg*i;
			echo(i, curangle, cos(curangle)*radius, sin(curangle)*radius);
			translate([cos(curangle)*radius, sin(curangle)*radius, -total_height/2+2])
				rotate([0,0,curangle])
				PrepareSymbol(text[i], h);
		}
		intersection(){
			difference(){
				sphere(d = radius*2+letter_thickness*2, center=true);
				sphere(d = radius*2-last_ring_thickness, center=true);
			}
				cube([radius*2+letter_thickness+5, radius*2+letter_thickness+5, total_height], center = true);
		}
	}
}

module PrepareSymbol(sym, sym_size){
	rotate(90,[0,0,1])
		rotate(90,[1,0,0])
		linear_extrude(height = 10, center=true)
		text(str(sym), size=sym_size, spacing=1, halign="center", valign="baseline", font=def_font);
}

```


[User]
I'm looking to create a phone-to-trombone bell adapter, like the one described here: [link to description]. Basically, it's a 3D-printed part that lets you connect your phone's speaker output to the bell of a trombone, making it play much louder.

The design should have a few main components: a phone holder, a connector to the trombone bell, and a channel connecting the phone's speaker to the trombone connector.

For the phone holder, I need it to be customizable to fit different phone models. I'd like to specify the phone's width, thickness, and possibly length (though the length can probably be a little flexible). The holder should have some extra margin on the sides and ends, maybe 5mm or so, to ensure the phone fits comfortably. I also need to be able to rotate the phone so it is angled towards the bell.

The trombone connector needs to be a frustum (truncated cone) shape that matches the bell's end. I need to define the smaller radius, the larger radius, and the length of this frustum. The inside needs to have a cylindrical bore that matches the trombone's bore size. The dimensions I know for a Bach 42 are: bell_connector_small_radius = 7.958 mm, bell_connector_large_radius = 8.706 mm, bell_connector_length = 31.5 mm, and bore_size = 13.7 mm. But it would be great if those were also customizable.

The channel between the phone speaker and the trombone connector doesn't need to be complicated; a simple cylindrical bore through the body of the adapter will work. We'll need to position this bore such that it aligns with the phone's speaker location and the center of the trombone connector. And it should have a straight shot through to the cone.

Could you generate a parametric OpenSCAD design for this? I'd like to be able to change the phone dimensions, the trombone connector dimensions, the channel position, and the margin values easily. I don't need any fancy features and am aiming for functional and easily printable.

[Assistant]
amp_42b_bell.scad:
```
pi = 3.14159265359;//TODO

// the radius of the small end of your bell connector
bell_connector_small_radius = 7.958;
// the radius of the large end of your trombone connector
bell_connector_large_radius = 8.706;
//the length of the bell connector, in mm */
bell_connector_length = 31.5;
//the bore size, 0.547 inch = 13.9mm
bore_size=13.7;

//the width of your phone
phone_width=67;
//the thickness of your phone
phone_thickness=6.9;
//the margin at the side of the model. You should not need to change it.
margin=5;

$fn=200;
rotate([-45-90,0,0])
difference() {
    union() {
        difference() {
            cube([phone_width+margin*2, 40, 35]);
            rotate([10,0,0])
            iphone_shape();
            translate([0,80+60,40])
            rotate([45+90,0,0])
            cube(100);
        }

        translate([20, 0, bell_connector_large_radius+4])
        bell_connector();
    }
    translate([20,18,12.7])
    rotate([90,0,0])
    cylinder(r=bore_size/2, h=40);

    translate([9.5,12,5])
    rotate([10,0,0])
    cube([20,10,3]);

    translate([0,25,0])
    cube(200);
}

module bell_connector() {
    rotate([90,0,0]) {
        union() {
            difference() {
                cylinder(r1=bell_connector_large_radius, r2=bell_connector_small_radius, h= bell_connector_length);
                cylinder(r=bore_size/2, h=bell_connector_length);
            }

        }
    }
}

module iphone_shape() {
    translate([margin, 15, 5])
    cube([phone_width+0.2, phone_thickness+0.2, 138.1]);
}
```