[User]
Okay, I'm looking to create a highly customizable propeller generator in OpenSCAD, and I've seen some really impressive designs out there, especially the one by Niels Odijk and Maarten van Schagen based on BouncyMonkeys' work. It's got a lot of the features I need, but I'd like to make sure my version covers all the bases with similar flexibility.

Basically, I need a parametric model that lets me tweak almost every aspect of the propeller design using customizable variables and formulas, and this needs to be very detailed and work well with a 3d printer. I need the generator to create the blade, hub, and everything necessary for printing. Here's a breakdown of what I have in mind:

**General Parameters:**
*   **Rotation Direction:** A simple boolean to toggle between clockwise and counterclockwise rotation.
*   **Number of Blades:** An integer to control how many blades the propeller has.

**Blade Parameters:**
*   **Pitch:** This needs to be settable in both inches *and* millimeters, with a preference to use the metric value when it's provided. So, if both are set, use the mm value.
*   **Diameter:** Same as the pitch: settable in inches and millimeters, with metric taking precedence.
*   **Sections:** An integer representing the number of sections along the blade's length for calculations. More sections = higher detail/resolution.
*   **Pitch Adjustment:** The pitch should be adjustable using separate factors at the hub and tip of the blade allowing for non-uniform pitch across the blade.
*   **Max Chord Length:** Specifies the maximum width of the blade.
*   **Blade Sweep:** An angle to sweep the blade, allowing it to curve forward or backward. This needs to have a limit on the angle (say, between -90 and 90 degrees).
*   **Thickness Factor:** A factor to control how thick the blades are overall.
*   **Blade Tip Height:** How much the blade is raised at the tip, which can be negative.
*   **Blade Curvature:** A parameter to shape the blade in the Z-axis, for example, to add a slight bowl shape, or dome.
*   **Centerline Position:** A percentage that determines the position of the blade's centerline in relation to the airfoil's chord.
*   **Airfoil:** An array of [x,y] points defining the cross-sectional shape of the blade. This data should be able to be adjusted by the user in the customizer and I need to be able to import airfoil data from other sources easily.

**Hub Parameters:**
*   **Screw Hole Diameter:** The diameter for a screw hole in the center of the hub.
*   **Hub Diameter:** The main diameter of the hub.
*   **Blade Connection Distance:** How far from the center the blades connect to the hub.
*   **Hub Cutout Diameter:**  An imaginary diameter used to guide the angle of the hub's cutout, which should be larger than the hub diameter itself.
*   **Hub Thickness:**  The thickness of the hub.
*   **Hub Sag:** A way to drop the hub slightly.
*   **Hub Pins:** Parameters for pins (if any) on the hub, a diameter, and a pitch circle diameter. If the pin diameter is set to zero, don't include pins.

**Formulas & Functions:**

I need the design to use customizable formulas for several key blade parameters based on 'r', where r = (length of the centerline to a point) / (total length of centerline). These formulas should be in the form of SCAD functions and I want to be able to modify these formulas directly in the code.

*   **CenterlineAngle(r):** Calculates the sweep (yaw) of the blade.
*  **CenterlineOffset(r):** Calculates the offset distance of the blade from the center of rotation.
*   **BladeThickness(r):** Calculates blade thickness at any given point using the thickness factor, airfoil height and width.
*   **BladeHeight(r):** Calculates the height of the blade at any given point.
*  **RolAngle(r):** Calculates the angle the blade is rolled upward or downward.
*   **ChordLength(r):** Defines the width of the blade.
*   **PitchAngle(r):** Calculates the pitch angle at any given point.

**Modules and Logic:**
*   I'll need a separate module for the `Hub` and `Hubcutout`.
*   The `BladeSlice` module should generate a cross-section of the blade at a given point 'r' along the centerline.
*   The `Blade` module should construct the full blade by either merging (using `hull`) or unioning the slices made by the `BladeSlice` module, based on a variable setting `mergeSlices`, which defaults to true.
*   A `main()` module for assembling the final design.

**Other Considerations**
* I want to make sure the design is easy to customize.
* The code should be well-commented, so that I can understand everything that's going on.
* It's really important to me that the generated parts will be 3D printable. So, make sure the model avoids printing issues.
* I do not need to use any external libraries for this.

I think that's everything. I'm excited to see what the AI can come up with!

[Assistant]
propeller_generator.scad:
```
// Cted by Hamish Trolove - Feb 2019
//www.techmonkeybusiness.com

// Heavily modified by Maarten van Schagen and Niels Odijk - Nov 2019 + Jun 2020

//Licensed under a Creative Commons license - attribution
// share alike. CC-BY-SA

//Airfoils:
// Points from naca4412.dat in the But dow archive: http://m-selig.ae.illinois.edu/ads/archives/coord_seligFmt.tar.gz
// Not necessarily in the same order as in: http://m-selig.ae.illinois.edu/ads/coord/naca4412.dat

//////////////////////////////////////////////////////
//////////////  CUSTOMIZABLE OPTIONS  ////////////////
//////////////////////////////////////////////////////

// * = formula adjustable below (which means, the value is adjustable for each calculated slice of the blade)
// ** = advanced formula

////////////////////
/*    [Blades]    */
////////////////////

//Rotation  --  1 is clockwise, 0 is counterclockwise
Clockwise = 1; // [0:false, 1:true]

//Number of blades
BladeNumber = 3;

//pitch* (inches)
PitchInches = 3;

//diameter (inches)
DiameterInches = 5;

//pitch* (mm)  --  Leave zero to use inches
PitchMM = 0;

//diameter (mm)  --  Leave zero to use inches
DiameterMM = 0;

//Number of sections calculated along the blade  -  Sets resolution
Sections = 50;

//Pitch adjustment factor hub end*
PitchAdjustmentHub = 1;

//Pitch adjustment factor tip end*
PitchAdjustmentTip = 1;

//Maximum chord length* (mm)  =  Blade width
MaxChordLength = 15;

//Blade sweep at the tip** (deg)  -  -90 < value < 90
BladeSweepFinalAngle = 20;

//Blade thickness* (factor)
ThicknessFactor = 1;

//Height of blade tip* (mm)  -  can be negative
BladeTipHeight = 3;

//Blade curvature in z direction*  -  Curve shape: z = x^BladeCurveHeight
BladeCurveHeight = 1.5;

//Position of blade centerline on chord (%)  -  You can see the effects best when bladesweep is set to zero
CenterlinePosition = 35;

//Blade airfoil profile
AirfoilPoints = [[1000,1.3],[950,14.7],[900,27.1],[800,48.9],[700,66.9],[600,81.4],[500,91.9],[400,98],[300,97.6],[250,94.1],[200,88],[150,78.9],[100,65.9],[75,57.6],[50,47.3],[25,33.9],[12.5,24.4],[0,0],[12.5,-14.3],[25,-19.5],[50,-24.9],[75,-27.4],[100,-28.6],[150,-28.8],[200,-27.4],[250,-25],[300,-22.6],[400,-18],[500,-14],[600,-10],[700,-6.5],[800,-3.9],[900,-2.2],[950,-1.6],[1000,-1.3]];  //(naca4412 design)
/* IGNORE ME */ AirfoilWidth = max([for(i=AirfoilPoints) i[0]]) - min([for(i=AirfoilPoints) i[0]]);
/* IGNORE ME */ AirfoilHeight = max([for(i=AirfoilPoints) i[1]]) - min([for(i=AirfoilPoints) i[1]]);

/* IGNORE ME */ Pitch = (PitchMM > 0)? (PitchMM):(PitchInches * 25.4);  //Turn pitch values into metric
/* IGNORE ME */ Diameter = (DiameterMM > 0)? (DiameterMM):(DiameterInches * 25.4);  //Turn pitch values into metric

////////////////////
/*     [Hub]      */
////////////////////

//Screw hole diameter (mm)
HubScrewHoleDiameter = 5;

//Hub circle diameter (mm)
HubDiameter = 12;

//Blade connection distance from center (mm)
BladeConnectionDistance = 15;

//Imaginary diameter for guiding hub cone cutting angle (mm)  -  This number should be larger then HubDiameter
HubCutoutDiameter = 20;

//Thickness of the hub (mm)
HubThickness = 5;

//Sag the hub down (mm)
HubSag = 0;

//Diameter of hub pins (mm)  -  Set zero to disable
HubPinDiameter = 0;

//Pitch circle diameter of hub pins (mm)  -  Set zero to disable
HubPinPitchCircleDiameter = 0;

//////////////////////////////////////////////////////
//////////  CUSTOMIZABLE FORMULAS advanced ///////////
//////////////////////////////////////////////////////

//  The formulas below are calculated for every slice of the blade
//  r = length of centerline to point / total length of centerline
//  Diameter = User defined propeller diameter
//  Pitch = User defined propeller pirch

//Function for slope of the centerline (Bladesweep, section yaw)
function CenterlineAngle(r) = BladeSweepFinalAngle*r; // Should be in sync with CenterlineDistance(r)

//Function for distance from the centerline
function CenterlineOffset(r) = BladeSweepFinalAngle != 0 ? -(ln(cos(BladeSweepFinalAngle*r)))/(BladeSweepFinalAngle*PI/180) : 0;  // Is integral of tan(CenterlineAngle(r))

/* IGNORE ME */ CenterlineLength = sqrt(pow(.5*Diameter, 2) / (pow(0.5 * CenterlineOffset(1),2)+.25))/2;

//////////////////////////////////////////////////////
///////////  CUSTOMIZABLE FORMULAS simple ////////////
//////////////////////////////////////////////////////

//  The formulas below are calculated for every slice of the blade
//  r = length of centerline to point / total length of centerline
//  CenterlineLength = Total centerline length = (radius when bladesweep = 0)
//  Pitch = User defined propeller pitch
//  AirfoilWidth = Width of unscaled airfoil shape
//  AirfoilHeight = Height of unscaled airfoil shape
//
//  To calculate total length of the centerline to a point use r * CenterlineLength

//Blade thickness (mm)
function BladeThickness(r) = ThicknessFactor * AirfoilHeight * (ChordLength(r)/AirfoilWidth); //Set height based on ChordLength and airfoil designed scaled by the ThicknessFactor

//Height of blade (mm)  //Make sure it goes through (0, 0) to connect it to the hub
function BladeHeight(r) = BladeTipHeight * pow(r, BladeCurveHeight) / CenterlineLength; // Should be in sync with CenterlineDistance(r)

//Blade rol angle (deg) = angle upwards or downwards //This has a very small effect, make this zero if you're not sure how to use this
function RolAngle(r) = atan(BladeTipHeight/CenterlineLength * BladeCurveHeight * pow(r, BladeCurveHeight - 1)); // atan(Derivative of BladeHeight(r))

//The following blade width shape is a function taken from an existing blade.
//It defines the centercord length (mm) (blade width)
function ChordLength(r) = (1.392*pow(r,4) -1.570*pow(r,3)-2.46*pow(r,2)+3.012*r+0.215) * MaxChordLength;

//Function to adjust the pitch angle to match manufactured blades (which are flatter), this function is only used in BladeAngle(r), so you can delete this function if you wish to edit PitchAngle(r) instead
function PitchAngleAdjustment(r) = (PitchAdjustmentTip-PitchAdjustmentHub)/CenterlineLength*r+PitchAdjustmentHub;

//Blade pitch (deg)
function PitchAngle(r) = atan(Pitch/(2*PI*r*CenterlineLength)) * PitchAngleAdjustment(r);

//The following variable is used as a message that is displayed in the customizer
//Want to customize the formulas used to indicate the shape? You can edit these in the source OpenSCAD code!
//CustomizeFormulas = 0;

//////////////////////////////////////////////////////
/////////////////  PROPELLER DESIGN  /////////////////
//////////////////////////////////////////////////////

// If you want to change the propeller, try editing the modules BladeSlice(r) or Blade()
mergeSlices = true; //Enable or disable merging of slices (helpfull for debugging, set to true for standard renders)

SectionLength =  CenterlineLength/Sections;  //Length of each section

module Hub()
{
    hull() // Attach hull cilinder to blade slice for extra strength
    {
        translate([0,0,-HubSag])cylinder (r = HubDiameter/2, h = HubThickness, center = true, $fn = 100);
       rotate([90,0,0])BladeSlice(BladeConnectionDistance/2 / CenterlineLength);
    }
}

module Hubcutout()
{
    union()
    {
        //Main cutting shape
        cylinder (r = HubScrewHoleDiameter/2, h = HubThickness*10, center = true, $fn = 100);
        translate([0,0,-1.5*HubThickness])cylinder (r2 = HubDiameter/2, r1 = HubCutoutDiameter/2, h = 2*HubThickness, center = true, $fn = 100);

        //Pins (if enabled)
        if(HubPinDiameter > 0 && HubPinPitchCircleDiameter > 0)
        {
            translate([0.5*HubPinPitchCircleDiameter,0,0])cylinder(r = 0.5*HubPinDiameter, h = HubThickness*3, center = true, $fn = 100);
            translate([-0.5*HubPinPitchCircleDiameter,0,0])cylinder(r = 0.5*HubPinDiameter, h = HubThickness*3, center = true, $fn = 100);
        }
    }
}

module BladeSlice(r)
{
    PitchAngle = PitchAngle(r);
    ChordLength = ChordLength(r); //Width of blade
    CenterlineAngle = CenterlineAngle(r); //Yaw angle
    Height = BladeHeight(r) * CenterlineLength;
    RolAngle = RolAngle(r);
    CenterlineOffset = CenterlineOffset(r) * CenterlineLength;
    BladeThickness = BladeThickness(r);
    Offset = r*CenterlineLength;

    translate([CenterlineOffset, Height, Offset])
    rotate([-RolAngle, CenterlineAngle, -PitchAngle])
    linear_extrude(height=0.00000001, slices = 0)  //Turn into 3d object so we can move and rotate it in 3d
    translate([-CenterlinePosition/100*ChordLength,0])  //Set the centerline in the correct position
    scale([ChordLength/AirfoilWidth, BladeThickness/AirfoilHeight]) //Scale to correct width and height (CentercordLength and BladeThickness are set in mm)
        polygon(points=AirfoilPoints);
}

module Blade()
{
    union()
    {
    for(i = [0:Sections-1])
        {
            if(mergeSlices){
                //For standard renders
                hull(){ //hull the blade slices to fill space in between
                    BladeSlice(i*SectionLength/CenterlineLength);     //Section start
                    BladeSlice((i+1)*SectionLength/CenterlineLength); //Section end
                }
            }else{
                //For debugging
                union(){ //union the blade slices to keep open space in between
                    BladeSlice(i*SectionLength/CenterlineLength);     //Section start
                    BladeSlice((i+1)*SectionLength/CenterlineLength); //Section end
                }
            }
        }
    }
}

// Main object
module main(){
    difference()
    {
        union()
        {
            for(i = [0:BladeNumber-1])
            {
                rotate([90,0,i*360/BladeNumber])Blade();
                rotate([0,0,i*360/BladeNumber])Hub();
                //A hub piece is generated for each blade, but they are all merged
            }
        }
        Hubcutout();
    }
}

//Start drawing, mirror if needed
if(!Clockwise){
    mirror([1, 0, 0])main();
}else{
    main();
}

```


[User]
I'm looking for an OpenSCAD design for a customizable SD and microSD card holder. I'd like to be able to specify the number of rows of slots, with each row containing one SD card slot and one microSD card slot. It should also let me choose whether the SD cards are stored horizontally or vertically. Finally, I want the option to generate just the box, just the lid, or both.

The design should include a box with rounded corners, and the lid should have a small lip that fits snugly into the box. The tolerances should be adjustable, specifically the gap between the base and lid sides and the fit of the cards within the slots.

I am not using any specialized libraries, and would like a single .scad file for the entire design.

[Assistant]
SD_and_MSD_card_holder_RC1.scad:
```
// SD and microSD card holder Customizer - by Robert Wallace - Oct 2019

// Generate a box (and corresponding lid) for storing SD cards
//   -- user-specified: number of card slots
//   -- user-specified: orientation of SD cards (horiz or vert)
//   -- user-specified: generate box or lid or both

// 1 - 50.  There will be one SD slot and one microSD slot per row
number_of_card_slot_rows = 7; //1:50

// Which way to cut the slots for SD card storage
SD_card_orientation = "Horizontal"; //[Horizontal,Vertical]

// make the storage box object
generate_box = "Yes"; //[Yes,No]

// Make a lid to fit the box
generate_lid = "Yes"; //[Yes,No]

module fake_news()  // encountering any module stops customizer from further customizing
{
}

// translate custimizer entries into parameters used in the code
num_sd = (number_of_card_slot_rows < 0 ||   // if out of range, give 'em 7
         number_of_card_slot_rows > 50) ?
         7 :
         number_of_card_slot_rows;    // number of sd card slots to cut (microsd, too)

sd_horiz = (SD_card_orientation == "Horizontal") ? 1 : 0; // set to 1 for horizontal
                                                     // placement of SD cards

make_box = (generate_box == "Yes" || generate_box == "YES") ? 1 : 0;   // slotted-box
make_lid = (generate_lid == "Yes" || generate_lid == "YES") ? 1 : 0;   // lid

if(make_box == 0 && make_lid == 0)
{
linear_extrude(height = 3)
text("Please choose box and/or lid.");
}
// Here be Dragons!
//
// Note there are almost more lines of parameter set-up than object generation code

// You can change these, but even I don't remember what they all do, so...

lid_tol = .1; // a little gap between base and lid sides so lid will fit
sdtol = 1;     // -- and so the cards will fit, too

//microSD slot dimensions -- exact card dim plus tolerance
msdx = 11 + sdtol;   // msd card width + tolerance
msdy = 15;           // cards always stored vertically - no tolerance needed
msdz = .76 + .75;    // msd card thickness + tolerance
msd_in = 11.5;       // msd slot depth - no tolerance needed

// SD dimensions - slot dimensions based on horizontal or vertical orientation
sdx = (sd_horiz) ? 32 + sdtol : 24 + sdtol;  // SD slot x dim placed vert or horiz
sdy = (sd_horiz) ? 24 : 32;     // Y has no tolerance -it's the open vertical direction
sdz = 2 + sdtol/2;              // thickness of SD card slot
sd_in = (sd_horiz) ? 19 : 25;   // depth of SD slot (horizontal or vertical orientation)

// SD placement parameters  (as tuned for my preference)
// Note: gap between SD and mSD slots is determined programatically - see msd_xoff
sdgap = 5.0;    // space between cards (vertical)
sd_xoff = 3;    // space between SD cards and left side of box
sd_yoff = 5;    // space between bottom card and bottom of box

msd_xoff = 3;  // msd slots will be offset from right side of box

msdgap = sdgap;// + msdz;

// box of slots - dimensions are for the part of the box "inside" the
//                base that forms the ledge for the lid to rest upon

box_x = sdx + msdx + sd_xoff + sd_yoff + 1;  // box x based on card widths and offsets
box_y = num_sd * (sdz + sdgap) + sd_yoff;    // box y based on num_sd (card count)
box_z = sd_in + 1.5;                         // box z based on card ht and floor thk
box_r = 2.2; //1.5;                          // 4 corners roundover radius

ledge_ht = 5;  // measured down from top of box
lid_z = ledge_ht + (sdy-sd_in) + 1;  // but needs to clear inserted cards by, min, 1mm
lid_thk = 1.5;

ledge_wid = .75 + lid_tol;  // the width of the ledge the lid sits on

orientation = (sd_horiz == 1) ? "horizontally" : "vertically";
echo("Card Slots",  num_sd, "SD Stored" ,orientation, "Box dimensions", x=box_x, y=box_y, z=box_z, r=box_r);

if(make_box)
 {
 difference()
  {
  // main box
  union()
   {
   box(box_x, box_y, box_z, box_r);
   base(box_x, box_y, box_z, box_r, ledge_wid);
   }  // end union

  // cut out slots
  for(sdc = [0 :  1 : num_sd - 1])
   {
   translate([sd_xoff,
              (sdc * (sdz + sdgap)) + sd_yoff,
              box_z - sd_in + .5])
    card_cutout(sdx, sdz, sd_in);
   translate([box_x - msd_xoff - msdx,
              (sdc * (sdz + msdgap)) + sd_yoff + (sdz/2 - msdz/2),
              box_z - msd_in + .5])
    card_cutout(msdx, msdz, msd_in);
   }  // end for(sdcount)
  }  // end difference
 }  // end if(make_box)

if(make_lid)
 {
 rotate([180,0,0]) // postions lid for printing
  translate([(box_x + 10) * make_box,-box_y,-(lid_z+lid_thk)]) // translate to azix for rotating
   lid(box_x, box_y, lid_z, box_r, ledge_wid, lid_thk);
 }  // end if(make_lid)

//** End of main generation

//**  Modules **//

// card_cutout() - generate a shape used to cut out the SD slots
//               -- there's also a wedge used to bevel the top leading and trailing edge
module card_cutout(ccx, ccy, ccz)
{
 // the block
cube([ccx, ccy, ccz - ccy/4]);

// the bevel
translate([0,ccy/2,ccz - (ccy) - .1])
 rotate([0,90,0])
rotate([0,0,90])
  linear_extrude(height = ccx)
   polygon([[0,0],[ccy+.35, ccy],[-ccy - .35, ccy],[0,0]]);
}

module box(x = 2,y = 3,z = 4,r = 3)
{
d=2*r;

translate([r,r,0])
hull()
 {
 translate([0, 0, 0]) cylinder(r=r, h=z-r, $fn=70);
 translate([x-d, 0, 0]) cylinder(r=r, h=z-r, $fn=70);
 translate([x-d, y-d, 0]) cylinder(r=r, h=z-r, $fn=70);
 translate([0, y-d, 0]) cylinder(r=r, h=z-r, $fn=70);

 translate([0, 0, z-r]) sphere(r=r, $fn=80);
 translate([x-d, 0, z-r]) sphere(r=r, $fn=80);
 translate([x-d, y-d, z-r]) sphere(r=r, $fn=80);
 translate([0, y-d, z-r]) sphere(r=r, $fn=80);
 }  // end hull()
}  // end module box()

module lid(x,y,z,r, edge, thk)  // currently a flat-topped lid
{
linear_extrude(height = z)
difference()
 {
 offset(r=edge)
  {
  projection()
   {
   box(x,y,z,r);
   }
  }

 offset(r=lid_tol/2)
  {
  projection()
   {
   box(x,y,z,r);
   }
  }  // end offset for lid tolerance
 } // end difference()

// stick on a lid
translate([0,0,z])
 linear_extrude(height = thk)  // parameterize the lid thickness
  offset(r=edge)
   {
   projection()
    {
    box(x,y,z,r);
    }
   }

// add inner rim to strengthen the connection between lid and walls
translate([0,0,z - 1.5])
 linear_extrude(height = 1.5)
  difference()
   {
   offset(r=edge)
    {
    projection()
     {
     box(x,y,z,r);
     }
    }

 offset(r=-1)
  {
  projection()
   {
   box(x,y,z,r);
   }
  }  // end offset for lid tolerance
 } // end difference()

}  // end module lid()

// base() -- generate base for box - a little larger than box so as to form ledge
module base(x,y,z,r, edge)
{
ledge_offset = 5;   // how far down from the top does the ledge appear

// make a projection of the box to offset for the lid and "base"
linear_extrude(height = z - ledge_offset)
 offset(r=edge)
  {
  projection()
   {
   box(x,y,z,r);
   }
  }
}
```


[User]
I'm looking to create some customizable plant markers, similar to those garden labels you can buy but 3D printable. I saw a cool design someone made, and I want to build off of that idea to make my own.

Essentially, I want a marker with a flat, somewhat rectangular body and a pointed spike at one end to stick into the soil. The marker should have text on the body itself. I'd like a few parameters for it:

*   **Body Length:**  The length of the flat, rectangular part of the marker, excluding the spike. I'd like to be able to adjust this.
*   **Width:** The width of the marker's body.
*   **Spike Length:** The length of the pointed spike part.
*   **Thickness:** The thickness of the overall marker.
*   **Text:** I need to be able to specify the text that appears on the marker.
*   **Font:** I'd like to specify the font used for the text. I'd like to use common fonts on my system - something like "Liberation Sans" but allow other options to be explored.
*   **Font Size:** A parameter to adjust the size of the text.
*   **Quantity:** It'd be awesome to specify how many markers get generated so I can print several at once, and specify a gap between each of the repeated markers.

So ideally, in OpenSCAD, I could set these values, and the program would produce that many markers with the specific measurements, text, and font. The text should be extruded out slightly from the main body. I'm hoping for a single file that handles all the generation for this.

[Assistant]
Markers2.scad:
```
$fn=90;
/* [Text] */
Custom_Text="Your Text Here"; //20
Preset_Text="Not Dead Yet"; //[Not Dead Yet,DEAD,Plant,No Idea,Not Sure,Still Alive,A Weed,Cheaper Than Therapy,Something Green,Did I Plant This?,Shit Show,Fuck If I Know]

/* [Size] */
Body_Length=100;
Width=12;
Spike_Length=20;
Thickness=2;

/* [Font] */
Font_Face="Liberation Sans:style=Bold Italic";
Font_Size=6; //[4:20]

/* [Quantity] */
Number_Of_Markers=1; //[1:10]

module build(){
    if (Custom_Text=="Your Text Here"){
        marker(Preset_Text);
    }else if (Custom_Text==""){
        marker(Preset_Text);
    }else {
        marker(Custom_Text);
    }
}

module marker(text){
    for (i=[0:1:(Number_Of_Markers-1)]) {
        translate([0,(i*15),0]) linear_extrude(height=Thickness,center=true) polygon([[0,0],[0,Width],[Body_Length,Width],[Body_Length+Spike_Length,Width/2],[Body_Length,0]]);
        translate([Thickness+.9,((i*15)+2),Font_Size-4.51]) linear_extrude(height=1,center=true) text(text=text,font=Font_Face,size=Font_Size);
    }
}

build();

```


[User]
I'd like a parametric OpenSCAD design for a print-in-place greeting card. It should have a slotted middle section to allow it to fold, similar to the design on Thingiverse by 10moralesa (thing:103755). The card needs to have customizable text on both the front and inside, as well as an optional heart on the back.

Specifically, here are the things I want to be able to customize:

*   **Card Dimensions:** I need to be able to set the card width, height, and thickness.
*   **Binding/Slotted Section:** I need to be able to set the thickness of the binding section and the number of slots it has.
*   **Front Text:** I need to be able to specify multiple lines of text for the front, the text size, starting position, line spacing, font, text thickness, and whether the text is debossed or embossed.
*   **Inside Text:** I need to be able to specify multiple lines of text for the inside, text size, starting position, line spacing, font, and depth of the cut/engraving.
*   **Rear Heart:** This is an optional feature I'd like to toggle, and be able to control it's position and embossment depth.

I also want to make sure the design includes the following:

*   The slotted binding section should reduce the card's thickness in that area to allow for easier folding, and use alternating slots to further assist in folding.
*   The text should be centered on the card, and be able to be modified from the customizer, and support the Nimbus Roman No9 L font with Regular Italic style.

Could you generate the OpenSCAD code for this? I don't need any pre-made STL files, just the parametric SCAD code. I'm not using any libraries in particular for this, just the base OpenSCAD primitives.

[Assistant]
greeting-card.scad:
```
// Customizable 3D Greeting Card
// by Mark Thompson

card_width = 100;
card_height = 170;
card_thickness = 2;

binding_thickness = 1;
binding_slots = 11;

front_text_debossed_vs_embossed = 0;
front_text_thickness = 1;

front_text_string_line1 = "Happy";
front_text_string_line2 = "Birthday!";
front_text_string_line3 = "";
front_text_string_line4 = "";
front_text_string_line5 = "";
front_text_string_line6 = "";
front_text_string_line7 = "";
front_text_string_line8 = "";
front_text_string_line9 = "";

front_text_strings = [ front_text_string_line1,front_text_string_line2,
                  front_text_string_line3,front_text_string_line4,
                  front_text_string_line5,front_text_string_line6,
                  front_text_string_line7,front_text_string_line8,
                  front_text_string_line9 ];

front_text_size = 10;
front_text_starting_position = 65;
front_text_spacing = 20;
front_text_font = "Nimbus Roman No9 L:style=Regular Italic";

inside_text_string_line1 = "Happy";
inside_text_string_line2 = "Birthday";
inside_text_string_line3 = "from";
inside_text_string_line4 = "You Know";
inside_text_string_line5 = "Who";
inside_text_string_line6 = "";
inside_text_string_line7 = "";
inside_text_string_line8 = "";
inside_text_string_line9 = "";

inside_text_depth = 1;
inside_text_strings = [ inside_text_string_line1,inside_text_string_line2,
                  inside_text_string_line3,inside_text_string_line4,
                  inside_text_string_line5,inside_text_string_line6,
                  inside_text_string_line7,inside_text_string_line8,
                  inside_text_string_line9];
inside_text_size = 9;
inside_text_starting_position = 45;
inside_text_spacing = 15;
inside_text_font = "Nimbus Roman No9 L:style=Regular Italic";

include_rear_heart = 1;
heart_position = 20;
heart_embossment = 1;

module blank_card() {
    difference() {
        // card stock, includes front & back
        translate([0,0,card_thickness/2])
            cube([card_width*2,card_height,card_thickness],true);

        // reduce card thickness to binding_thickness in binding region
        if (binding_thickness<card_thickness)
            translate([0,0,card_thickness-binding_thickness/2])
                cube([binding_slots*2,card_height+0.01,card_thickness-binding_thickness+0.01],true);

        // cut binding slits for foldability
        for (x=[0:binding_slots-1])
            for (y=[-card_height/2:card_height/10:card_height/2])
                translate([(x+0.5)*2-binding_slots,y+(x%2)*card_height/20,card_thickness/2])
                    cube([1,card_height/10-1,card_thickness+0.01],true);
    }
}

module front_text() {
    z = front_text_debossed_vs_embossed? -front_text_thickness/2 : front_text_thickness/2;

    color("blue")
    translate([card_width/2+binding_slots/2,0,card_thickness+z]) {
        linear_extrude(height=front_text_thickness+0.01,center=true) {
            for (i=[0:len(front_text_strings)-1]) {
                translate([0,front_text_starting_position-i*front_text_spacing,0])
                    rotate([0,0,0])
                        text(front_text_strings[i],size=front_text_size,valign="center",halign="center",font=front_text_font);
            }
        }
    }
}

module inside_text() {
    color("green")
    translate([0,0,inside_text_depth/2])
    linear_extrude(height=inside_text_depth+0.01,center=true) {
        for (i=[0:len(inside_text_strings)-1]) {
            translate([-card_width/2-binding_slots/2,inside_text_starting_position-i*inside_text_spacing,inside_text_depth/2])
                rotate([180,0,180])
                    text(inside_text_strings[i],size=inside_text_size,valign="center",halign="center",font=inside_text_font);
        }
    }
}

module heart_shape() {
    union() {
        hull() {
            translate([35,-30,0])
                circle(32);

            translate([-35,0,0])
                circle(0.01);
        }

        hull() {
            translate([35,30,0])
                circle(32);

            translate([-35,0,0])
                circle(0.01);
        }
    }
}

module rear_heart() {
    color("red")
    translate([-card_width/2-binding_slots/2,heart_position,card_thickness+heart_embossment/2])
        rotate([0,0,90])
            linear_extrude(height=heart_embossment,center=true)
                scale(0.5)
                    heart_shape();
}

difference() {
    union() {
        blank_card();

        if (!front_text_debossed_vs_embossed)
            front_text();

        if (include_rear_heart)
            rear_heart();
    }

    if (front_text_debossed_vs_embossed)
        front_text();

    inside_text();
}
```


[User]
I'd like to create a customizable plant tag using OpenSCAD. It should have a main, rectangular board with the plant's name written on it. Below the main board, there should be a stake to push into the ground.

Specifically, the main board should have dimensions that I can control (width and height) and also a thickness. The plant's name should be engraved on the top surface of the main board, and I should be able to set the size of the text as well as the thickness of the engraved text. Finally, the stake should have a specific height, and the width of the stake should also be adjustable. The stake should extend directly from the center bottom of the main board and should end in a triangular point, angled down. I think it should be easy to customize the colors of these things, too, at least the main board and the text.

I'd like to be able to specify all of these measurements in mm. Could you generate the OpenSCAD files for me? I don't have any custom libraries I'm using.

[Assistant]
Original_Tag2.scad:
```
tag_name = "Tomato";
name_size = 10;
writing_thickness = 0.6;
tag_thickness = 2;
stick_height = 60;
mainboard_height = 30;
mainboard_width = 64;

//main board
    color("lightgreen")
        cube([mainboard_width,mainboard_height,tag_thickness]);

//text
    translate([mainboard_width/2, mainboard_height/2, tag_thickness])
        color("black")
            linear_extrude(writing_thickness)
                text(tag_name, size=name_size, halign="center", valign="center");

//stick
stick_width = 15;
translate([(mainboard_width-stick_width)/2,-stick_height,0])
    color("lightgreen")
        cube([stick_width,stick_height,tag_thickness]);

//stick end
translate([(mainboard_width-stick_width)/2,-stick_height,0])
    color("lightgreen")
        linear_extrude(tag_thickness)
            polygon(points= [[0,0], [stick_width,0], [stick_width/2,-13] ]);

```


[User]
Okay, I'm looking to design a parametric tumbler, mostly for 3D-printed parts, but some off-the-shelf bits are fine too.  I want to be able to smooth 3D printed parts, though I'm realizing it's a slow process.  It needs to be adaptable to different size jars and motors, so I'd like it to be mostly parametric.  The basic design is that it has a motor that drives a pinion, which then drives a larger gear. This large gear then turns a small gear attached to the jar via a bar (and this small gear will essentially be a wheel with teeth) that has two support bars along the side of the jar and a support for the motor.

Here are the components I'm thinking:

**Motor Support:**
   -  A cylinder that holds the motor. This should have adjustable parameters for radius (`motor_r`), height (`motor_basket_h`), and thickness (`motor_basket_t`).
   -  The position of the motor will depend on the gears, and should be calculated automatically.

**Gears:**
   -  **Pinion:**  This is the small gear on the motor shaft.  It needs parameters for the number of teeth (`pinion_teeth`), the motor shaft radius (`motor_shaft_r`), and thickness (`pinion_t`).
    -  **Large Gear:** This gear meshes with the pinion.  It needs a parameter for the number of teeth (`large_gear_teeth`), and thickness (`large_gear_t`). It should also have a hole for a shaft. The library you use should handle pressure angle and tooth size.
     -   **Jar Gear:** This gear will be attached to the jar. Parameters include  thickness (`jar_gear_t`) and a number of teeth that's calculated from the jar radius (`jar_r`), plus a minimum clearance (`0.8`) around it. The jar gear should have a skirt that extends beyond the main part of the gear to prevent the jar from slipping, but this skirt should not have teeth.
     -  **Small Gear/Wheel:** This gear meshes with the jar gear. It needs a parameter for the number of teeth (`few_teeth`), and also uses `jar_gear_t`, with the additon of small gear side thickness (`small_gear_side_t`) and a small gear side play for clearance (`small_gear_side_play`).

**Jar Components:**
    - **Jar:**  This is just a placeholder cylinder for visualization, with parameters for radius (`jar_r`), thickness (`jar_t`), and height (`jar_h`).
    -  **Jar Paddle:**  This part goes inside the jar to help with the tumbling action.  It needs parameters for length (`jar_paddle_h`), angle (`jar_paddle_angle`), and width (`jar_paddle_w`).

**Support Structure:**
   - **Axial Bar:**  A long bar running along the side of the jar. It should have parameters for length (`axial_bar_l`), height (`axial_bar_h`), and width (`axial_bar_w`). It needs teeth to attach to the transversal bars.
    - **Transversal Bar:**  These attach to the axial bar and the support structure. They need parameters for length (`transversal_bar_l`), width (`transversal_bar_w`), and height, which should be the same as the small gear thickness (`transversal_bar_h`). It also needs teeth to attach to the support structure. It also needs a central height (`transversal_bar_center_h`).
    -   **Support:** This part is what connects to the transversal bar.  It needs parameters for width (`support_w`), thickness (`support_t`), and a distance to the bar center (`support_axis_to_bar_center`). The support needs to be split into two parts. One that is static and one that has the motor mount on the second support. The two parts should attach using teeth (or other suitable mechanism).

**Parameters:**
    - `tooth_size`, `pressure_angle`: For all gears
    -   `small_gear_side_play`: Clearance for small gear.
    -    `gears_angle`: Angle between jar and driving small gears.
    -     `bar_tooth_size` Tooth size of the bars.

**Libraries:**

Please use the `Getriebe` library that's on Thingiverse (I understand I can't include it directly in the prompt, you'll need to assume it exists) since it has a stirnrad module for creating gears. It seems to be a fairly standard gear library, so hopefully that is not a problem.

**Specific Requests:**

*   Make sure the motor position is calculated based on the gear sizes and the pinion and large gear distance.
*   The jar gear's tooth count should be based on the jar radius, with a clearance of 0.8, and also rounded up using the ceiling function to be an integer. The jar gear outer radius should be about 2.4 tooth widths larger than the inner radius, and 2.2 tooth widths smaller than the outer radius.
*   The small gear tooth count should be adjustable with the `few_teeth` parameter.
*   Include a parameter for the angle between the jar wheel and the motor wheel.
*  The support and connector system should be parametric, so that the supports can be moved along the bar as the jar diameter changes.
*   The parts should be designed to print without supports.
*   I would like to be able to view each of the individual parts by using a `part` parameter.  For example, `part="motor_support"` should only show the motor support, etc.

I think that covers it. Let me know if you have any questions.

[Assistant]
polisher.scad:
```
use <../Getriebe.scad>

/* [View] */
// Part(s) to display
part="motor_support"; //[motor_support:Motor support,pinion:Motor pinion,large_gear:Large gear,jar_gear:Jar gear,jar_paddle:Jar paddle]

/* [Pinion parameters] */

// Motor shaft (pinion hole) radius
motor_shaft_r=1.05;
// Number of teeth of the pinion (increase if the small part causes printing issues)
pinion_teeth=9;

/* [Large gear parameters] */
// Number of teeth of the large gear
large_gear_teeth=76;

/* [Motor mount parameters] */

// Motor mount inner radius (e.g. 0.1mm less than the actual motor radius for tight fit). The position of the motor is computed according to pinion_teeth, large_gear_teeth, and motor_r.
motor_r=11.8;
// Height of the motor support cylinder. Should be greater than the motor height, and than the distance between the bottom of the jar and the bottom of the jar gear (to avoid colision with the large gear)
motor_basket_h=20;

/* [Jar parameters] */
// Jar outer radius
jar_r=25;
// Jar thickness (used to compute the inner radius)
jar_t=2;
// Jar paddle length
jar_paddle_h=30;
// Jar paddle profile angle
jar_paddle_angle=60;
// Jar paddle width (from the tip of the triangle to the jar inner radius)
jar_paddle_w=5;

/* [Hidden] */

// Other motor parameters

motor_h=12;
motor_basket_t=1.2;

// Other gear parameters

// Large gear thickness
large_gear_t=3;
// Pinion thickness, (preferably larger than the large gear thickness, e.g. equal to shaft length)
pinion_t=5;
// Size of teeth (for all gears)
tooth_size=2;
pressure_angle=25;
// Jar gear thickness (small gear thickness is computed accordingly)
jar_gear_t=5;
// Number of teeth of the small gears
few_teeth=23;
// Small gears side thickness
small_gear_side_t=1;
// Clearance between the jar gear and small gears sides
small_gear_side_play=0.2;

// Size and position of the jar (for display only)

gears_angle=90;
jar_h=165;

// Axial / transversal bars parameters

axial_bar_l=150;
axial_bar_h=10;
axial_bar_w=15;
axial_bar_tooth_h=4;
transversal_bar_l=100;
transversal_bar_w=15;
transversal_bar_tooth_h=4;
transversal_bar_center_h=16;
bar_tooth_size=2;

// Support parameters

support_t=3;

/* should be increased if needed to be greater than
   jar_r+tooth_size+transversal_bar_w/2-(few_teeth*tooth_size/2/pi+jar_r)*cos(gears_angle/2)
   for all used jar_r/gears_angle combinations */
support_axis_to_bar_center=21;
support_w=16;

pi=3.14159;

$fn=180;

/* Computed */

small_gear_t=jar_gear_t+2*(small_gear_side_t+small_gear_side_play);
transversal_bar_h=small_gear_t;
support_half_h=transversal_bar_w/2+0.2+0.8+(bar_tooth_size+0.2)/2+0.5+1.6;

large_gear_center_t=large_gear_t+(pinion_t-large_gear_t)/2;

/* Inner circle radius is (jar_teeth-2.4)*tooth_size/2/pi */
/* Outer circle radius is (jar_teeth+2.2)*tooth_size/2/pi */
/* Ensure that (jar_teeth-2.4)*tooth_size/2/pi >= jar_r+0.8
   and (jar_teeth-2.4)*tooth_size/2/pi < jar_r+0.8+tooth_size/2/pi*/
jar_teeth=ceil(2*pi*(jar_r+0.8)/tooth_size+2.4);
/* Average distance between the jar and the pitch circle */
jar_to_pitch_r=0.8+(2.4+1/2)*tooth_size/2/pi;

wheel_r=few_teeth*tooth_size/2/pi+jar_to_pitch_r;

pinion_dist=(large_gear_teeth+pinion_teeth)*tooth_size/2/pi+0.2;
gears_dist=(jar_teeth+few_teeth)*tooth_size/2/pi;

motor_angle=
     min(asin((support_axis_to_bar_center+support_half_h-(motor_r+1+motor_basket_t))/pinion_dist),
	 acos((5+(motor_r+1))/pinion_dist));

module jar() cylinder(r=jar_r,h=jar_h);

module motor() cylinder(r=motor_r,h=motor_h);

module jar_gear() difference() {
     union() {
	  stirnrad
	       (modul=tooth_size/pi, zahnzahl=jar_teeth, breite=jar_gear_t,bohrung=0,
		eingriffswinkel=pressure_angle,schraegungswinkel = atan(tooth_size/jar_gear_t),
		optimiert = false);
	  cylinder(r=jar_r+0.8,h=10);
     }
     translate([0,0,1]) cylinder(r=jar_r,h=10);
     cylinder(r1=jar_r-1,r2=jar_r,h=1);
}

function spiral(r1,r2,a1,a2)=
     [for(i=[0:$fn]) let(r=(r2*i+r1*($fn-i))/$fn,a=(a2*i+a1*($fn-i))/$fn) [r*cos(a),r*sin(a)]];

module spiral(r1,r2,t,a1,a2)
     polygon(concat(spiral(r1,r2,a1,a2),spiral(r2+t,r1+t,a2,a1)));

module arc(r1,r2,t)
     let (r=(r1+r2)/2)
     translate([-r+r1,0]) difference() {
	  circle(r=r+t);
	  circle(r=r);
	  translate([-r2,-r2]) square([2*r2,r2]);
     }

module curved_beams(r1,r2,t,spiral=true,angle=180,n=3) difference() {
     circle(r2);
     circle(r1);
     for(i=[0:n-1])
	  rotate(360*i/n)
	       if(spiral)
		    spiral(r1-t,r2,t,0,angle);
	       else
		    arc(r1-t,r2,t);
}

module large_gear() {
     difference() {
	  stirnrad
	       (modul=tooth_size/pi, zahnzahl=large_gear_teeth, breite=large_gear_t,
		bohrung=4,eingriffswinkel=pressure_angle,optimiert = false);
	  linear_extrude(pinion_t)
	       curved_beams(5,large_gear_teeth*tooth_size/2/pi-2.3,0.8,spiral=false,n=3);
     }
     cylinder(r=5,h=large_gear_center_t);
     cylinder(r=2,h=0.2+motor_basket_h+0.2+large_gear_center_t+2.5);
     translate([0,0,0.2+motor_basket_h+0.2+large_gear_center_t])
	  cylinder(r=2,h=small_gear_t-2.5,$fn=4);
}

module small_gear(beams=true) difference() {
     union() {
	  stirnrad
	       (modul=tooth_size/pi, zahnzahl=few_teeth, breite=jar_gear_t+2*small_gear_side_play,
		bohrung=0,eingriffswinkel=pressure_angle,
		schraegungswinkel = -atan(tooth_size/jar_gear_t),optimiert = false);
	  for(z=[-small_gear_side_t,jar_gear_t+2*small_gear_side_play])
	       translate([0,0,z]) cylinder(r=(few_teeth+2.2)*tooth_size/2/pi,h=small_gear_side_t);
     }
     translate([0,0,-small_gear_side_t-1]) {
	  if(beams)
	       linear_extrude(small_gear_t+2)
		    curved_beams(3,(few_teeth-2.4)*tooth_size/2/pi-0.8,0.4,angle=360);
	  cylinder(r=2.2,h=1+2.5);
	  cylinder(r=2,h=small_gear_t+2,$fn=4);
     }
     translate([0,0,-small_gear_side_t+small_gear_t-2.5])
	  cylinder(r=2.2,h=2.5+1);
}

module wheel(beams=true) difference() {
     rotate_extrude()
	  intersection() {
	       small_r=small_gear_t*0.6;
	       translate([wheel_r-small_r,small_gear_t/2]) circle(small_r);
	       square([wheel_r,small_gear_t]);
     }
     translate([0,0,-1]) {
	  if(beams)
	       linear_extrude(small_gear_t+2)
		    curved_beams(3,wheel_r-2.5,0.4,angle=360);
	  cylinder(r=2.2,h=small_gear_t+2);
     }
}

module pinion()
     stirnrad(modul=tooth_size/pi, zahnzahl=pinion_teeth, breite=pinion_t, bohrung=2*motor_shaft_r,
	      eingriffswinkel=pressure_angle);

module tooth(tooth_size,tooth_h,angle=45)
     hull()
     intersection() {
          rotate([0,90])
	       linear_extrude(tooth_h,center=true)
	       polygon(
		    [[tooth_size/2,0],[-tooth_size/2,0],[tooth_size/2*tan(45-angle),-tooth_size/2]]);
	  cylinder(r=tooth_h/2,h=tooth_size,$fn=4,center=true);
}

module bar_hole(w,h,l,tooth_size,tooth_h,top_press_t=0.7) {
     difference() {
	  translate([-h/2,-w/2,-1]) cube([h,w,l+2]);
	  z=l/2;
	  for(a=[0,180])
	       rotate(a)
		    translate([0,w/2,z])
		    tooth(tooth_size,tooth_h);
	  intersection() {
	       translate([h/2+30-0.4,0,-1]) cylinder(r=30,h=l+2);
	       translate([h/2+40-0.6,0,l/2]) rotate([90,0]) cylinder(r=40,h=w,center=true);
	  }
     }
     for(a=[0,180])
	  rotate(a)
	       difference() {
	            translate([-h/2+1,w/2,1]) cube([h-2,0.8+tooth_size/2+0.5,l-2]);
		    notch_w=1;
		    translate([-h/2+1+notch_w,w/2]) cube([h-2-2*notch_w,0.8,l]);
	  }
     translate([h/2+0.8,1-w/2,-1]) cube([top_press_t,w-2,l+2]);
}

module toothed_bar(l,w,h,tooth_h) difference() {
     cube([h,w,l]);
     for(i=[-1,1])
	  for(j=[0:bar_tooth_size:l])
	       translate([h/2,(i+1)/2*w,j])
		    rotate((i-1)*90)
		    tooth(bar_tooth_size,j==0||j==l?h+2:tooth_h);
}

module transversal_bar() translate([-transversal_bar_w/2,0]) difference() {
     union() {
	  translate([0,-transversal_bar_l/2])
	       rotate([-90,-90])
	       toothed_bar(transversal_bar_l,transversal_bar_w,transversal_bar_h,
			   transversal_bar_tooth_h);
	  translate([0,-axial_bar_w/2-3.5])
	       cube([transversal_bar_w,axial_bar_w+7,transversal_bar_center_h]);
     }
     translate([transversal_bar_w/2,0])
	  bar_hole(axial_bar_w+0.4,axial_bar_h+0.4,transversal_bar_center_h,bar_tooth_size,
		   axial_bar_tooth_h-0.8);
}

module axial_bar()
     translate([-axial_bar_h/2,-axial_bar_w/2,-small_gear_side_t-0.1-5])
          toothed_bar(axial_bar_l,axial_bar_w,axial_bar_h,axial_bar_tooth_h);

module support_profile(motor,foot) difference() {
     hull() {
	  circle(5);
	  if(foot) {
	       w=motor?-5+pinion_dist*cos(motor_angle):0;
	       translate([support_axis_to_bar_center-support_half_h,-5-w])
		    square([2*support_half_h,support_w+w]);
	  }
	  if(motor)
	       rotate(motor_angle)
		    translate([0,-pinion_dist]) circle(motor_r+1+motor_basket_t);
     }
     if(motor) {
	  circle(2.1);
	  rotate(motor_angle)
	       translate([0,-pinion_dist]) {
	       difference() {
		    circle(motor_r+1);
		    for(a=[0,120,240]) rotate(a) translate([motor_r,-1]) square([2,2]);
	       }
	  }
     }
}

module connector(female=false) difference(){
     translate([0,0,female?-1.6:-1.4])
     linear_extrude(3)
     square([female?2:1.6,support_w-2*(female?1.6:1.8)],center=true);
     for(i=[-1,1])
     for(j=[-1,1])
     translate([i*(female?1:0.8),j*4,female?-0.5:-0.4])
	  rotate(-i*90) tooth(female?0.6:0.8,female?2:3,angle=20);
}

module support_1() translate([-support_axis_to_bar_center,0,-0.2]) {
     difference() {
	  linear_extrude(support_t+small_gear_t+0.4) support_profile(motor=false,foot=true);
	  translate([0,0,-1]) cylinder(r=10,h=small_gear_t+0.4+1);
	  /* -0.001: workaround 0 thickness wall* */
	  translate([support_axis_to_bar_center,-5,(transversal_bar_h+0.4)/2-0.001])
	       rotate([-90,-90])
	       bar_hole(transversal_bar_w+0.4,transversal_bar_h+0.4,support_w,bar_tooth_size+0.2,
			transversal_bar_tooth_h-0.8,top_press_t=1);
     }
     translate([0,0,small_gear_t+0.4-2]) cylinder(r=2,h=3);
     for(i=[-1,1])
	  translate([support_axis_to_bar_center+i*(transversal_bar_w/2+3.4-1.2),-5+support_w/2])
	       connector();
}

module support_2(motor=false) translate([-support_axis_to_bar_center,0,-0.2]) difference() {
     union() {
	  translate([0,0,-support_t])
	       linear_extrude(support_t)
	       support_profile(motor=motor,foot=true);
	  if(motor)
	       translate([0,0,-motor_basket_h])
		    linear_extrude(motor_basket_h-support_t)
		    support_profile(motor=true,foot=false);
	  else
	       cylinder(r=2,h=2);
     }
     for(i=[-1,1])
	  translate([support_axis_to_bar_center+i*(transversal_bar_w/2+3.4-1.2),
		     -5+support_w/2])
	       connector(female=true);
     if(motor)
	  translate([0,0,-motor_basket_h+2])
	       cylinder(r=2.3,h=motor_basket_h-4);
}

module jar_paddle() linear_extrude(jar_paddle_h) intersection() {
     translate([jar_paddle_w+jar_t-jar_r,0]) circle(jar_r-jar_t);
     rotate(-jar_paddle_angle/2) translate([-jar_r,0])square([2*jar_r,jar_paddle_w]);
     rotate(jar_paddle_angle/2) translate([-jar_r,-jar_paddle_w]) square([2*jar_r,jar_paddle_w]);
}

module motor_and_gears() translate([0,0,-0.2-motor_basket_h-0.2-large_gear_center_t]) {
     large_gear();
     rotate(motor_angle)
	  translate([0,-pinion_dist]) {
	       translate([0,0,(large_gear_t-pinion_t)/2]) pinion();
	       translate([0,0,(large_gear_t+pinion_t)/2+0.2]) motor();
     }
}

module polisher() {
     translate([0,0,-jar_gear_t/2]) {
	  jar_gear();
	  translate([0,0,-motor_basket_h]) jar();
     }
     translate([support_axis_to_bar_center+gears_dist*cos(gears_angle/2),0]) {
	  axial_bar();
	  for(z=[0,jar_h-2*motor_basket_h])
	       translate([0,0,z]) {
		    translate([0,0,-transversal_bar_h/2]) transversal_bar();
		    for(a=[0,180])
			 rotate([a,0])
			      translate([0,-gears_dist*sin(gears_angle/2),-transversal_bar_h/2]) {
			      support_1();
			      support_2(z==0&&a==0);
			      translate([-support_axis_to_bar_center,0])
				   if(z==0) {
					translate([0,0,small_gear_side_t])
					     rotate(180-gears_angle/2+180/few_teeth
						    +gears_angle/2*jar_teeth/few_teeth)
					     small_gear();
					if(a==0) motor_and_gears();
				   } else
					wheel();
			 }
	       }
     }
}

/* polisher(); */
/* motor_and_gears(); */

/* wheel(); */
/* small_gear(); */
/* large_gear(); */
/* pinion(); */
/* rotate([180,0]) support_1(); */
/* support_2(); */
/* rotate([180,0]) support_2(true); */
/* transversal_bar(); */
/* rotate([0,90,90]) axial_bar(); */
/* jar_gear(); */
/* rotate([90,-jar_paddle_angle/2]) jar_paddle(); */

if(part=="motor_support")
     rotate([180,0]) support_2(true);
else if(part=="pinion")
     pinion();
else if(part=="large_gear")
     large_gear();
else if(part=="jar_gear")
     jar_gear();
else
     rotate([90,-jar_paddle_angle/2]) jar_paddle();

```


[User]
Hey, so I've been working on a minifig stand and I've got this basic OpenSCAD file that makes a tiered stand, but it's really rough. I'd like something more refined and parametric.

Here's the basic idea: I want a stand with multiple rows (or steps), each row being able to hold a number of minifigs. I'm using the standard 8mm x 8mm studs for the bases. The base itself I am happy with.

Here's what I'd like to be able to customize:

*   **Row Length:** How long each row is (in terms of number of stud positions).
*   **Row Height:** How tall each row is.
*  **Row Depth:** How deep each row should be.
*   **Number of Rows:**  How many rows or steps the stand will have.
*   **Spacing Between Rows:** The distance vertically between each row.
*   **Stud Size:** The stud diameter and height for different lego bases (mostly 8mm but i'd like to be able to customize this).
*   **Base Thickness:** The thickness of the base platform the studs rest on.

I'd like a separate module that is responsible for each row so it's easy to modify in the future. Ideally, I'd like the final output to be able to be put into a buildplate with several of the modules so it's easier to customize the stand length later on. This is so I can have, for example, 2 rows of 10, or 10 rows of 2, depending on my needs, or I can easily put several modules together to make a really long row.

It would be great if you could create an OpenSCAD file (or set of files) that achieves this, making good use of modules, and that uses the BOSL2 library. Thanks a lot!

[Assistant]
lego_minifig_stand.scad:
```
width=7*1;
height=4*1;
lenght=32*1;
//Number of steps
steps=5;//[1,2,3,4,5,6,7,8,9,10]
cube([lenght,width,height]);

for (i=[0:steps-1]) {
translate([lenght*i,0,0])
    cube([lenght,width,(height+11)*i]);
}

```


[User]
I need a parametric spacer with a crosshair centering helper. The spacer itself should be a ring, and the centering helper should be a cross shape with a hole in the center. I'd like to be able to control the following parameters:

*   **spacer_diameter:** The outer diameter of the entire spacer ring.
*   **spacer_thickness:** The wall thickness of the spacer ring.
*   **spacer_height:** The height of the spacer ring.
*   **helper_diameter:** The inner diameter of the hole in the center of the crosshair (for the screw).
*   **helper_thickness:** The thickness of the arms of the crosshair.
*   **helper_height:** The height of the crosshair.
*   **helper_z_offset:** The vertical offset of the crosshair from the bottom of the spacer. This should allow me to position the crosshair in the middle of the spacer height, or at the bottom, etc.

I'd like the code to be clean and well-commented, and to use a module for each part of the spacer (spacer ring, helper cross, helper ring) to keep things organized. It would be helpful if the preview used some colors to differentiate the parts, and also if there was some kind of small, invisible cutout to prevent z-fighting during rendering. I prefer using `$fn` to smooth curves. I don't need to use any external libraries.

I'm planning to use this for 3D printing.

[Assistant]
Spacer.scad:
```
/*
 * Spacer with centering helper (crosshair)
 *
 * Author: datag@Thingiverse <https://www.thingiverse.com/datag/about>
 * Date: 2020-06-16
 *
 * V1: Initial version
 */

// Outer diameter of the whole spacer (mm)
spacer_diameter = 25.0;

// Wall thinkness of the spacer (mm)
spacer_thickness = 2.0;

// Spacer height (mm)
spacer_height = 7.5;

// Inner diameter of the centering helper to fit screw (mm)
helper_diameter = 6.0;

// Wall thickness of the helper (mm)
helper_thickness = 2.0;

// Helper height; Lower values save material and might provide circulation (for full height use same as spacer_height) (mm)
helper_height = 2.0;

// Helper offset from the ground (for 3DP usually 0, for z-center use: spacer_height / 2 - helper_height / 2) (mm)
helper_z_offset = 0;

// Smoothing factor (number of fragments)
$fn = 100;

/* [Hidden] */

// Prevent z-fight in OpenSCAD preview (see https://en.wikibooks.org/wiki/OpenSCAD_User_Manual/FAQ)
cutout_amount = 0.1 + 0;

// preview[view:south, tilt:top]

// MAIN
spacer();

// MODULES
module spacer() {
    union() {
        spacer_ring();
        helper();
    }
}

module spacer_ring() {
    difference() {
        color("steelblue")
            cylinder(h=spacer_height, r=spacer_diameter/2);
        translate([0, 0, -cutout_amount])
            cylinder(h=spacer_height+cutout_amount*2, r=spacer_diameter/2-spacer_thickness);
    }
}

module helper() {
    translate([0, 0, +helper_z_offset])
    color("lightsteelblue")
        union() {
            helper_ring();
            helper_cross();
        }
}

module helper_ring() {
    difference() {
        color("red")
            cylinder(h=helper_height, r=helper_diameter/2+helper_thickness);
        translate([0, 0, -cutout_amount])
            cylinder(h=helper_height+cutout_amount*2, r=helper_diameter/2);
    }
}

module helper_cross() {
    difference() {
        color("blue")
            union () {
                translate([-helper_thickness/2, -spacer_diameter/2+spacer_thickness])
                    cube([helper_thickness, spacer_diameter-spacer_thickness*2, helper_height]);
                translate([-spacer_diameter/2+spacer_thickness, -helper_thickness/2])
                    cube([spacer_diameter-spacer_thickness*2, helper_thickness, helper_height]);
            }
        translate([0, 0, -cutout_amount])
            cylinder(h=helper_height+cutout_amount*2, r=helper_diameter/2);
    }
}

```


[User]
I'm looking to create a parametric cable holder in OpenSCAD. I'd like to be able to control a few key things:

First, the overall width of the holder needs to be adjustable. This width dictates the direction the cable runs *through* the holder. Let's call this `width`.

Secondly, I need to specify the number of cables the holder should accommodate, so a `cable_count` parameter.

The holder will have cutouts for each cable. I want to control the maximum size of this cutout, let's call that `max_cutout`.

I also need control over the vertical position of the cutout, specifically the height above the base, so `cutout_height` will be a parameter.

Additionally, the cutout should have a 'min' width at the top (the part of the cutout furthest from the base).  Let's call that `min_cutout`.

I'm aiming for a smooth, rounded shape for the main body of the holder, like a series of connected spheres. For multiple cables, these spheres would overlap to form a kind of rounded, elongated shape with cutouts for each cable.

Essentially, I want a series of spherical shapes, based on the `width`, that are connected to each other. I’d like to remove some material to create the opening for the cable(s) and remove the bottom part of each sphere so it sits flat on the surface.

I'd also want to be able to adjust the resolution using `$fn` like we do in OpenSCAD, with a default value of 50. I think you can assume a single 'base' for the holder when `cable_count=1`, but that base should be wide enough to accommodate the cutout.

Could you create an OpenSCAD file that achieves this functionality? I'm not looking to use any specific libraries for this at the moment, just vanilla OpenSCAD.

[Assistant]
Parametric_Cable_Holder.scad:
```
//Note: Cutout height + max cutout have to be < radius

//The width of the cable holder.  This is the direction the cable runs through the holder
width =  22;
//The number of cables in the holder
cable_count=2;
//the maximum size of the cutout
max_cutout = 7;
//How high above the surface you want the cutout in the holder
cutout_height=1;
//Width of the cutout at the top
min_cutout=1.75;
//hidden
$fn=50;
sphere_radius = width/2;
touch_point = sqrt(pow(sphere_radius,2)-((pow(min_cutout,2)/4)));
cutout_center_height = cutout_height+max_cutout/2;

//This is the main logic

difference(){
    create_base();
    translate([0,(width+1)/2,cutout_height])
    rotate([90,0,0])create_cutout();
}

//Creates the base shape for the holder
module create_base(){
    difference(){
        hull(){
            sphere(d=width);
            if(cable_count>1){
                translate([(sphere_radius)*(cable_count-1),0,0])sphere(d=width);
            }
        }
        if(cable_count>1)
          translate([-sphere_radius,-((sphere_radius)+1),-sphere_radius])
            cube([((sphere_radius)*(cable_count+1)),width+2,sphere_radius]);
        else
          translate([-sphere_radius,-((sphere_radius)+1),-sphere_radius])cube([width,width+2,sphere_radius]);
    }
}

//Creates the cutout shape
module create_cutout(){
    for(hole_count=[0:cable_count-1]){
        translate([(width/2)*(hole_count),0,0])
            linear_extrude(height=width+2){
                union(){
                    translate([0,cutout_center_height,0])circle(d=max_cutout, $fn=50);
                    polygon([[-max_cutout/2,cutout_center_height],[max_cutout/2,cutout_center_height],
                            [min_cutout/2,touch_point],[min_cutout/2,width/2+1],
                            [-min_cutout/2, width/2+1],[-min_cutout/2,touch_point]]);
                }
            }
       }
}
```


[User]
I'm looking to create a customizable power plate for an arcade cabinet, and I need an OpenSCAD file that will let me do that. I'd like the plate to be able to have a few common components, and I'd like to be able to specify the shape of the plate itself.

For the plate shape, I want to be able to define either a rectangle with 4 corners, or a more complex shape with 6 corners. The user should be able to set the x and y coordinates for each corner. This part is critical, since I need to be able to make the plate any arbitrary shape I need. I think I also want to be able to define a round plate shape, with adjustable diameter, # of facets, and x and y scale.

Then I need to place some cutouts on the plate. These should be positioned by x and y coordinates and rotation angle. I need a cutout for a standard PC power plug, a cutout for a circuit breaker, and a cutout for a standard PC power switch. I'd also like to have an option to enable a custom rectangular switch cutout which also has length, width and rotation parameters.

I also need to be able to add screw holes to the plate at each corner, with an offset from the corner, screw diameter, and collar width and height.

Finally, I need a "view mode" where the parts are rendered in place as complete objects, and also a "print mode" that will only render the plate and cutouts, ready for 3D printing. Ideally, I'd also like a "parts" mode for rendering each of the components in isolation. It should also be possible to set the thickness of the plate.

I expect to be able to move around the parts freely in the view mode, and for the cutouts to be generated based on these positions.

I want to make this project fully parametric so I can adjust the shapes and positions as needed to fit my particular arcade cabinet, and ideally I'd like this to be in a single file. I will also want all the units to be in millimeters. Could you do this for me? I'm not sure about libraries, but if it's helpful, go ahead and use what you think is best.

[Assistant]
CPA1up_power_plate.scad:
```
////////////////////////////////////////////////////
// CUSTOMIZER version:                            //
//    Arcade power panel                          //
//    by Cpayne3d   June 21, 2020                 //
//                                                //
// License:                                       //
//  Creative-commons Share alike, Non-commercial  //
//                                                //
////////////////////////////////////////////////////

/* [Plate Shape] */

// Rectangle - Bottom-left Corner A X_Pos
a_xpos = 1;  //[1:180]
// - Bottom-left Corner A Y_Pos
a_ypos = 1;  //[1:180]
// - Bottom-right Corner B X_Pos
b_xpos = 90; //[1:180]
// - Bottom-right Corner B Y_Pos
b_ypos = 1;  //[1:180]
// - Top-left Corner C X_Pos
c_xpos = 1;  //[1:180]
// - Top left corner C Y_Pos
c_ypos = 50; //[1:180]
// - Top-right Corner D X_Pos
d_xpos = 90; //[1:180]
// - Top-right Corner D Y_position
d_ypos = 50; //[1:180]
// - Make a plate with 6 corners?
6corners = "no"; //[yes,no]
// - 6th -right Corner E X_Pos
e_xpos = 1; //[1:180]
// - 6th -right Corner E Y_position
e_ypos = 85; //[1:180]
// - 6th -right Corner F X_Pos
f_xpos = 90; //[1:180]
// - 6th -right Corner F Y_position
f_ypos = 85; //[1:180]

/* [POWER PLUG details] */
// Plug Rotation
rot_plug = 0; //[0,22,45,90,112,135,157,180]
// Plug X pos
plug_x_pos = 15; //[0:180]
// Plug X pos
plug_y_pos = 1; //[1:180]

/* [BREAKER details] */
// Breaker barrel diameter
cct_diam = 10.9;
// Breaker rotation
rot_breaker = 90; //[1:180]
// Breaker X pos
breaker_x_pos = 45; //[1:180]
// Breaker Y pos
breaker_y_pos = 30; //[1:180]
// - Show breaker guides in View mode?
breaker_guides = "yes"; // [yes,no]

/* [PC SWITCH details] */
// Switch rotation
rot_switch = 0; //[0,22,45,90,112,135,157,180]
// Switch X pos
pc_switch_x_pos = 62; //[1:180]
// Switch Y pos
pc_switch_y_pos = 25; //[1:180]

/* [CUSTOM SWITCH details] */
// - Enable customize switch ?
enable_custom_switch = "no"; //[yes, no]
// - Customize Switch Width
csw_wid = 14;
// - Customize Switch length
csw_len = 25;
// - Custom Switch Rotation
csw_rot = 0; //[0,22,45,90,112,135,157,180]
// - Custom Switch X pos
csw_x_pos = 1; //[1:180]
// - Custom Switch X pos
csw_y_pos = 60; //[1:180]

/* [Extra Features] */
// - Viewing Mode
view_mode = "View"; //[View, Print, Parts]

// - Plate screw diameter mm
platescr = 3;

// - Offset screws from edge of plate
scroffset = 1;

// - Screw collar width
screw_collar_wide = 3;

// - Screw collar height
screw_collar_z = 1;

// - Thickness of plate
plate_thick = 3;

/* [Hidden] */
// preview[view:south, tilt:top]
// - Select plate Shape
PanelType = 10; //[10:Rectangle, 20:Round]
//// - Round plate dimensions
//r_diameter = 120; //[10:90]
//// - # of perimeter facets
//r_facets = 60; //[8:100]
//// - Scale up on the X axis (use decimal increments)
//rscale_x = 1.0;
//// - Scale up on the Y axis (use decimal increments)
//rscale_y = 1.0;
//// - Number of screw holes
//r_numscrews = 4; //[1:8]
//// rcollar_x_pos
//rcollar_x_pos = 10; //[0:180]
//// rcollar_y_pos
//rcollar_y_pos = 20; //[0:180]

if (view_mode == "View") {
 if (PanelType == 10)
     4axisPlate();

 if (PanelType == 20)
     roundplate();

translate([plug_x_pos, plug_y_pos, plate_thick *3.2 +0.5]) rotate([0, 0, rot_plug]) rotate([-90, 0, 0]) pc_plug();

translate([breaker_x_pos, breaker_y_pos, plate_thick *3.2]) rotate([0, 0, rot_breaker]) rotate([-90, 0, 0]) cct(breaker_guides);

translate([pc_switch_x_pos, pc_switch_y_pos, plate_thick *3.2]) rotate([0, 0, rot_switch]) rotate([-90, 0, 0]) switch_sm();

if (enable_custom_switch == "yes") {
translate([csw_x_pos, csw_y_pos, -10 + plate_thick]) rotate([0, 0, csw_rot]) cust_switch();
}
} // end if view

if (view_mode == "Print") {
  if (PanelType == 10)
     4axisPlate();

 if (PanelType == 20)
     roundplate();
// 4axisPlate();

} // end if view

if (view_mode == "Parts") {

translate([plug_x_pos, plug_y_pos, plate_thick *3.2 +0.5]) rotate([0, 0, rot_plug]) rotate([-90, 0, 0]) pc_plug();

translate([breaker_x_pos, breaker_y_pos, plate_thick *3.2]) rotate([0, 0, rot_breaker]) rotate([-90, 0, 0]) cct(breaker_guides);

translate([pc_switch_x_pos, pc_switch_y_pos, plate_thick *3.2]) rotate([0, 0, rot_switch]) rotate([-90, 0, 0]) switch_sm();

if (enable_custom_switch == "yes") {
translate([csw_x_pos, csw_y_pos, -10 + plate_thick]) rotate([0, 0, csw_rot]) cust_switch();
}

} // end if view

//////////////////////////////////
// custom switch
//////////////////////////////////
module cust_switch() {
swdeep =10;  // custom switch depth

union() {
translate([0, 0, 0]) color("darkgrey") cube([csw_wid, csw_len, swdeep]);  // swbody

if (view_mode == "View") {
translate([-2, -2, swdeep]) color("darkgrey") cube([csw_wid +4, csw_len +4, 2]);  // sw collar

translate([2, 3, swdeep * 0.6]) rotate([10, 0, 0]) color("green", 0.9) cube([csw_wid -4, csw_len -4, csw_len * 0.3]);  // sw rocker thingy
} // end if view
} // end union

} // end module - custom switch

//////////////////////////////////////
///// Round plate layout
//////////////////////////////////////
//PanelType = 10; //[10:Rectangle,20:Round]
//rdiameter = 20; //[10:90]
//rscale_x = 1.0;
//rscale_y = 1.0;
module roundplate() {

difference() {
 union() {
 scale([rscale_x, rscale_y, 1]) translate([r_diameter /2, r_diameter /2, 0]) cylinder(h=plate_thick, r=r_diameter /2, $fn=r_facets); // main plate body

   translate([rcollar_x_pos, rcollar_y_pos, plate_thick]) cylinder(h=plate_thick +screw_collar_z, r=platescr /2 +screw_collar_wide, $fn=25); //  screw collars
 }  // end union

// diff section
union() {

  } // end union
} // end diff

} // end module

//////////////////////////////////////
///// 4axis plate layout with 4 or 6 corners
//////////////////////////////////////
module 4axisPlate() {

difference() {
 union() {
hull() {
    // h=2.75
translate([a_xpos, a_ypos, 0]) cylinder(h=plate_thick, r=6, $fn=25);   // corner
translate([b_xpos, b_ypos, 0]) cylinder(h=plate_thick, r=6, $fn=25);   // corner
translate([c_xpos, c_ypos, 0]) cylinder(h=plate_thick, r=6, $fn=25);   // corner
translate([d_xpos, d_ypos, 0]) cylinder(h=plate_thick, r=6, $fn=25);   // corner
    if (6corners == "yes") {
      translate([e_xpos, e_ypos, 0]) cylinder(h=plate_thick, r=6, $fn=25);   // 5th corner
      translate([f_xpos, f_ypos, 0]) cylinder(h=plate_thick, r=6, $fn=25);   // 6th corner
    }  // end if

} // end hull

// View mode parts
if (view_mode == "View") {
translate([plug_x_pos, plug_y_pos, plate_thick *3.2 +0.5]) rotate([0, 0, rot_plug]) rotate([-90, 0, 0]) pc_plug();
translate([breaker_x_pos, breaker_y_pos, plate_thick *3.2]) rotate([0, 0, rot_breaker]) rotate([-90, 0, 0]) cct(breaker_guides);
translate([pc_switch_x_pos, pc_switch_y_pos, plate_thick *3.2]) rotate([0, 0, rot_switch]) rotate([-90, 0, 0]) switch_sm();

} // end if
translate([a_xpos + scroffset, a_ypos + scroffset, 0]) cylinder(h=plate_thick +screw_collar_z, r=platescr /2 +screw_collar_wide, $fn=25); //  screw collars
translate([b_xpos - scroffset, b_ypos + scroffset, 0]) cylinder(h=plate_thick +screw_collar_z, r=platescr /2 +screw_collar_wide, $fn=25); //  screw collars
translate([c_xpos + scroffset, c_ypos - scroffset, 0]) cylinder(h=plate_thick +screw_collar_z, r=platescr /2 +screw_collar_wide, $fn=25); //  screw collars
translate([d_xpos - scroffset, d_ypos - scroffset, 0]) cylinder(h=plate_thick +screw_collar_z, r=platescr /2 +screw_collar_wide, $fn=25); //  screw collars
 if (6corners == "yes") {
   translate([e_xpos + scroffset, e_ypos - scroffset, 0]) cylinder(h=plate_thick +screw_collar_z, r=platescr /2 +screw_collar_wide, $fn=25); //  5th screw collar
   translate([f_xpos - scroffset, f_ypos - scroffset, 0]) cylinder(h=plate_thick +screw_collar_z, r=platescr /2 +screw_collar_wide, $fn=25); //  6th screw collar

   }  // end if
} // end union

/////////////////////////
// diff section
/////////////////////////
union() {
translate([a_xpos + scroffset, a_ypos + scroffset, -1.2]) cylinder(h=plate_thick + 1.25 +screw_collar_z, r=platescr /2, $fn=25); //  screw holes
translate([b_xpos - scroffset, b_ypos + scroffset, -1.2]) cylinder(h=plate_thick + 1.25 +screw_collar_z, r=platescr /2, $fn=25); //  screw holes
translate([c_xpos + scroffset, c_ypos - scroffset, -1.2]) cylinder(h=plate_thick + 1.25 +screw_collar_z, r=platescr /2, $fn=25); //  screw holes
translate([d_xpos - scroffset, d_ypos - scroffset, -1.2]) cylinder(h=plate_thick + 1.25 +screw_collar_z, r=platescr /2, $fn=25); //  screw holes
 if (6corners == "yes") {
translate([e_xpos + scroffset, e_ypos - scroffset, -1.2]) cylinder(h=plate_thick + 1.25 +screw_collar_z, r=platescr /2, $fn=25); //  5th screw holes
translate([f_xpos - scroffset, f_ypos - scroffset, -1.2]) cylinder(h=plate_thick + 1.25 +screw_collar_z, r=platescr /2, $fn=25); //  6th screw holes

   }  // end if

//// parts
if (view_mode == "Print") {

translate([plug_x_pos, plug_y_pos, plate_thick *3.2 +0.5]) rotate([0, 0, rot_plug]) rotate([-90, 0, 0]) pc_plug();

translate([breaker_x_pos, breaker_y_pos, plate_thick *3.2 -1]) rotate([0, 0, rot_breaker]) rotate([-90, 0, 0]) cct(breaker_guides);

translate([pc_switch_x_pos, pc_switch_y_pos, plate_thick *3.2]) rotate([0, 0, rot_switch]) rotate([-90, 0, 0]) switch_sm();

if (enable_custom_switch == "yes") {
translate([csw_x_pos, csw_y_pos, -10 + plate_thick]) rotate([0, 0, csw_rot]) cust_switch();
}

} // end if print

} // diff union
} // end diff

// test - create polygon
// my_polygon_variable = [[[a_xpos, a_ypos],[b_xpos, b_ypos],[c_xpos, c_ypos],[d_xpos, d_ypos]],[[0,1,2,3, 1, 2]] ];
//translate([0, 0, 10]) polygon(points = my_polygon_variable[0], paths = my_polygon_variable[1]);
} // end module

//////////////////////////////////
////  little PS switch
//////////////////////////////////
module switch_sm() {
swwid = 13.10 ;
swdeep = 15;
swtall = 20.0;
swfacew = 14.8;   // swface wid
swfacet = 21;   // swface tall
swfacedeep = 2; // swface thick
swrockerw = 10.5;
swrockertall = 15.75;

translate([0, 3, 0])    // set part default start Z height
union() {
translate([(swfacew - swwid) /2, swfacedeep, (swfacet - swtall) /2]) color("Silver") cube([swwid, swdeep, swtall]);  // swbody

if (view_mode == "View") {
translate([0, 0, 0]) color("darkgrey") cube([swfacew, swfacedeep, swfacet]);  // sw collar

translate([(swfacew - swrockerw) /2, - swfacedeep * 0.3, (swfacet - swrockertall) /2 -0.75]) rotate([15, 0, 0]) color("grey") cube([swrockerw, swdeep /2, swrockertall]);  // sw rocker thingy
} // end if view
} // end union

} // end module - ps switch

//////////////////////////////////
///// circuit breaker
//////////////////////////////////
module cct(bodymarkers){
cct_d = 13.5 /2;      // cct diameter
barrel_d = cct_diam /2;  //[10.9] barrel hole for cct breaker
barrel = 9;           // barrel tallness
barr_shldr = 1.65;    // shoulder of barrel
bodytall = 30;
bodywid = 14;
bodythick = 22.6;

translate([0, 9, 0])    // set part default start Z height
difference() {
union() {

if (view_mode == "View") {
color("silver") cube([bodywid, bodythick, bodytall]);   // cct body

if (bodymarkers == "yes") {
translate([0, -2, 0]) color("lightgreen", 0.8) rotate([90, 0, 0]) cylinder(h=2, r=1);   // cct ghost body marker
translate([bodywid, -2, 0]) color("lightgreen", 0.8) rotate([90, 0, 0]) cylinder(h=2, r=1);   // cct ghost body marker
translate([bodywid, -2, bodytall]) color("lightgreen", 0.8) rotate([90, 0, 0]) cylinder(h=2, r=1);   // cct ghost body marker
translate([0, -2, bodytall]) color("lightgreen", 0.8) rotate([90, 0, 0]) cylinder(h=2, r=1);   // cct ghost body marker
}
} // end if view mode

//color("darkgrey") translate([bodywid /2, 0, bodytall /2]) rotate([0, -17, 0]) rotate([90, 0, 0]) cylinder(h=barr_shldr, r=cct_d, $fn=5);  // pentagon hole

color("silver") translate([bodywid /2, 0, bodytall /2]) rotate([0, -17, 0]) rotate([90, 0, 0]) cylinder(h=barrel, r=barrel_d, $fn=50);  // barrel hole
    color("darkgrey") translate([bodywid /2, 0, bodytall /2]) rotate([0, -17, 0]) rotate([90, 0, 0]) cylinder(h=barrel +1, r=(barrel_d -1), $fn=50);  // barrel hole
}

// diff union
union() {
translate([-barrel_d *0.5, -barrel -0.1, barrel_d - 0.5]) color("red") cube([barrel_d *1, barrel - barr_shldr, 1]);  // chamfer top of barrel

translate([-barrel_d *0.5, -barrel -0.1 , - barrel_d - 0.5]) color("red") cube([barrel_d *1, barrel - barr_shldr, 1]);  // chamfer bottom of barrel

} // end union
} // end diff
} // end module - CCT

//////////////////////////////////
///// PC Plug
//////////////////////////////////
module pc_plug() {
ear_d = 7.8 /2;     // diameter of screw post for HULL function
earoffset = 5.5;    // offset of each screw hole post
earthick = 3.4;     // thickness if plastic face plate
pcwid = 27.75;      // width of pc plug
pctall = 20;        // height of pc plug
earscr_d = 3 /2;    // screw diameter
pcindent = 2.9;     // indent of ears on face plate
facewid = 30.64;    // face plate wid
facetall = 22.5;    // face plate height
facethick = 3;   // thickness of face plate
union() { // BIG union
difference() {
union() {

translate([1.3, 2, 1.3]) color("silver") cube([pcwid, pctall, pctall]);    // pc plug rect body

if (view_mode == "View") {
// face lip object hull
color("darkgrey") hull() {
rotate([90, 0, 0]) translate([3, 3, -3])  cylinder(h=facethick, r=6/2, $fn=25);
rotate([90, 0, 0]) translate([3, 19, -3]) cylinder(h=facethick, r=6/2, $fn=25);
rotate([90, 0, 0]) translate([27, 19, -3]) cylinder(h=facethick, r=6/2, $fn=25);
 rotate([90, 0, 0]) translate([27, 3, -3]) cylinder(h=facethick, r=6/2, $fn=25);
} // end hull

color("grey") hull() {
translate([0, pcindent, 0]) color("green") cube([facewid, earthick, facetall]);    // pc face rect
translate([facewid + earoffset, pcindent *2, facetall /2]) rotate([90, 0, 0]) cylinder(h=earthick, r=ear_d, $fn=30);   // right screw hole post

translate([-earoffset, pcindent *2, facetall /2]) rotate([90, 0, 0]) cylinder(h=earthick, r=ear_d, $fn=30);   // left screw hole post
} // end hull
} // end if view

if (view_mode == "Print") {
translate([facewid + earoffset, pcindent *4, facetall /2]) rotate([90, 0, 0]) cylinder(h=earthick +10, r=earscr_d, $fn=30);   // right screw hole

translate([-earoffset, pcindent *4 , facetall /2]) rotate([90, 0, 0]) cylinder(h=earthick +10, r=earscr_d, $fn=30);   // left screw hole
} // end if print mode

} // end union

// diff union
union() {

translate([facewid + earoffset, pcindent *2.1, facetall /2]) rotate([90, 0, 0]) cylinder(h=earthick +2, r=earscr_d, $fn=30);   // right screw hole

translate([-earoffset, pcindent *2.1 , facetall /2 ]) rotate([90, 0, 0]) cylinder(h=earthick +2, r=earscr_d, $fn=30);   // left screw hole

if (view_mode == "View") {

difference() {
union() {
// hollow out plug insides
color("red") hull() {
rotate([90, 0, 0]) translate([4, 3, -facethick * 2])  cylinder(h=facethick *2 +1, r=1, $fn=25);
rotate([90, 0, 0]) translate([4, 12, -facethick *2]) cylinder(h=facethick *2 +1, r=1, $fn=25);
rotate([90, 0, 0]) translate([26, 3, -facethick *2])  cylinder(h=facethick *2 +1, r=1, $fn=25);
rotate([90, 0, 0]) translate([26, 12, -facethick *2]) cylinder(h=facethick *2 +1, r=1, $fn=25);
rotate([90, 0, 0]) translate([9, 18, -facethick *2])  cylinder(h=facethick *2 +1, r=1, $fn=25);
rotate([90, 0, 0]) translate([21, 18, -facethick *2]) cylinder(h=facethick *2 +1, r=1, $fn=25);
} //end hull
} // end local union

color("white") union() {
translate([8, -2, 5]) cube([2, pctall -1, 4]); // prong - left
translate([14, -2, 12]) cube([2, pctall -1, 4]); // prong - ground
translate([20, -2, 5]) cube([2, pctall -1, 4]); // prong - right
} // end local union
} // end if view

} // end local diff

} // end union
} // end diff
} // BIG union

} // end module PC_plug
```


[User]
Hey, I need a design for an ice cream sandwich jig! I've got the details, and I'm hoping you can generate the OpenSCAD files for me.

Essentially, it's a container with a square hole that holds a graham cracker, then you fill it with ice cream and top it with another graham cracker. The jig has a height, and some grab cutouts on the sides to help you lift it off the sandwich. Here's the breakdown:

*   **Overall Height:** Let's call this `jig_height`, and I'd like to be able to change this. Start with 25mm.
*   **Cookie Dimensions:** This will need to be parametric since crackers vary. I'll have variables `cookie_x` and `cookie_y`, the starting values should be 57mm each (this is slightly bigger than a standard graham cracker to give it some wiggle room).
*   **Cookie Corner Radius:** This should be a variable called `cookie_r`, make it 1mm to start. It should be used for all inside corners.
*   **Wall Thickness:** Let's call this `wall_thickness` and give it a default value of 6mm.
*   **Grab Slot Height:** There should be cutouts on each side for easier gripping; call this `grab_h`, start with a height that is `jig_height` minus 10mm.
*   **Grab Slot Inset:** This should control how deep those grab slots go into the wall - `grab_inset` at 4mm.
*   **Chamfers:** I'd like to have chamfers on both the inner and outer edges, so let's call those `outside_chamfer` (0.5mm) and `inside_chamfer` (1mm), respectively.

I think that covers all the core parameters. I'd really like this to be parametric so I can tweak it for different cookies.

I'm not too familiar with specific libraries but I guess I'm requesting that you design all the necessary files from scratch with no libraries needed. Thanks!

[Assistant]
ice_cream_sandwich_jig.scad:
```
// ice cream sandwich assembly jig
// june 2020, gmarsh23 @ thingiverse
// CC BY-SA V4.0

// height of jig
h = 25;
// cookie dimensions. Currently sized for No-Name brand graham crackers, measure and adjust to your cookie.
// add 1mm to what you measure so cookie doesn't get stuck.
cookie_x = 57;
cookie_y = 57;
// radius of inside corners. Makes cleaning a bit easier and this code breaks if you use r=0 anyway.
cookie_r = 1;

// wall thickness
wall_thickness = 6;

// height of grab slots
grab_h = h-10;
// and how deep they go into the walls
grab_inset = 4;

// chamfers on inside and outside edges.
outside_chamfer = 0.5;
inside_chamfer = 1;

// makes previews look good
nudge = 0.01;

difference() {
    outside();
    inside();
}

module outside() {

    $fn=48;

    outside_x = cookie_x + (wall_thickness*2);
    outside_y = cookie_y + (wall_thickness*2);
    outside_r = wall_thickness;

    dx = outside_x/2 - outside_r;
    dy = outside_y/2 - outside_r;

    end_h = (h-grab_h)/2 + grab_inset;

    // center (where grab inset is)
    hull() {
        translate([dx,dy,0]) chamfered_cylinder(d=(outside_r-grab_inset)*2,h=h,c1=0,c2=0,$fn=$fn);
        translate([-dx,dy,0]) chamfered_cylinder(d=(outside_r-grab_inset)*2,h=h,c1=0,c2=0,$fn=$fn);
        translate([dx,-dy,0]) chamfered_cylinder(d=(outside_r-grab_inset)*2,h=h,c1=0,c2=0,$fn=$fn);
        translate([-dx,-dy,0]) chamfered_cylinder(d=(outside_r-grab_inset)*2,h=h,c1=0,c2=0,$fn=$fn);
    }

    // bottom grab ring
    hull() {
        translate([dx,dy,0]) chamfered_cylinder(d=outside_r*2,h=end_h,c1=outside_chamfer,c2=grab_inset,$fn=$fn);
        translate([-dx,dy,0]) chamfered_cylinder(d=outside_r*2,h=end_h,c1=outside_chamfer,c2=grab_inset,$fn=$fn);
        translate([dx,-dy,0]) chamfered_cylinder(d=outside_r*2,h=end_h,c1=outside_chamfer,c2=grab_inset,$fn=$fn);
        translate([-dx,-dy,0]) chamfered_cylinder(d=outside_r*2,h=end_h,c1=outside_chamfer,c2=grab_inset,$fn=$fn);
    }

    // top grab ring
    translate([0,0,h-end_h])
    hull() {
        translate([dx,dy,0]) chamfered_cylinder(d=outside_r*2,h=end_h,c2=outside_chamfer,c1=grab_inset,$fn=$fn);
        translate([-dx,dy,0]) chamfered_cylinder(d=outside_r*2,h=end_h,c2=outside_chamfer,c1=grab_inset,$fn=$fn);
        translate([dx,-dy,0]) chamfered_cylinder(d=outside_r*2,h=end_h,c2=outside_chamfer,c1=grab_inset,$fn=$fn);
        translate([-dx,-dy,0]) chamfered_cylinder(d=outside_r*2,h=end_h,c2=outside_chamfer,c1=grab_inset,$fn=$fn);
    }
}

module inside() {
    $fn=24;

    dx = cookie_x/2 - cookie_r;
    dy = cookie_y/2 - cookie_r;

    for(part=[1:3]) hull() {
        translate([dx,dy,0]) chamfered_cylinder(d=cookie_r*2,h=h,c1=-inside_chamfer,c2=-inside_chamfer,$fn=$fn,nudge=nudge,part=part);
        translate([-dx,dy,0]) chamfered_cylinder(d=cookie_r*2,h=h,c1=-inside_chamfer,c2=-inside_chamfer,$fn=$fn,nudge=nudge,part=part);
        translate([dx,-dy,0]) chamfered_cylinder(d=cookie_r*2,h=h,c1=-inside_chamfer,c2=-inside_chamfer,$fn=$fn,nudge=nudge,part=part);
        translate([-dx,-dy,0]) chamfered_cylinder(d=cookie_r*2,h=h,c1=-inside_chamfer,c2=-inside_chamfer,$fn=$fn,nudge=nudge,part=part);
    }
}

// useful functions

module chamfered_cylinder(d=10,h=10,c1=1,c2=1,nudge=0,part=0,$fn=$fn) {
    rotate_extrude($fn=$fn) chamfered_cylinder_2d(d=d,h=h,c1=c1,c2=c2,nudge=nudge,part=part);
}

module chamfered_cylinder_2d(d=10,h=10,c1=1,c2=1,nudge=0,part=0) {
    c1a = abs(c1);
    c2a = abs(c2);
    c1d = d - (c1*2);
    c2d = d - (c2*2);

    if ((c1a > 0) && ((part == 0) || (part == 1)))
        polygon([[0,-nudge],[c1d/2,-nudge],[d/2,c1a+nudge],[0,c1a+nudge]]);
    if ((part == 0) || (part == 2))
        polygon([[0,c1a-nudge],[d/2,c1a-nudge],[d/2,h-c2a+nudge],[0,h-c2a+nudge]]);
    if ((c2a > 0) && ((part == 0) || (part == 3)))
        polygon([[0,h-c2a-nudge],[d/2,h-c2a-nudge],[c2d/2,h+nudge],[0,h+nudge]]);
}
```


[User]
I'm looking to design a parametric audio tape splicing block, and I need your help creating the OpenSCAD files. I'd like to be able to customize a few things.

First, I need to set the overall dimensions of the block: the length (`block_x`), width (`block_y`), and height (`block_z`). I'd like to be able to specify these in millimeters. For example, a default might be `block_x = 100`, `block_y = 30`, and `block_z = 10`.

Second, I need a channel for the tape to sit in. I'd like to control the `tape_channel_depth` and `tape_channel_width`, also in millimeters. The depth might typically be around 2mm, and the width might be 3.81mm for cassette tape or 6.35mm for reel-to-reel tape. The channel should have angled edges on each side that are 45 degrees.

Finally, I need several cut lines to guide the blade during splicing. These should be thin slots cut into the block that allow a blade to cleanly splice the tape. I want to set `cut_width` to be the width of these cuts, and have three slots. One cut should be straight, and two should be at angles of 22.5 degrees and 45 degrees relative to the straight cut line. The cut lines need to go down at least as deep as the tape channel. For the angled cuts, I need them to go down to the same level as the normal cuts. I think it would also be good to have a chamfered edge around these cut lines to help guide the blade, but I'm not sure what's the best way to do that.

Can you generate the necessary OpenSCAD code for this? I'd like all dimensions to be in millimeters. I think all of the code should be contained in a single file.

[Assistant]
splicing_block.scad:
```
/*[ Overall Dimensions in mm]*/
block_x = 100; // [50 : 10 : 200]
block_y = 30; // [10 : 5 : 100]
block_z = 10; // [5 : 1 : 20]

/*[ Tape Channel in mm ]*/
tape_channel_depth = 2.0;  // [1 : 1 : 5]
tape_channel_width = 3.81; // [3.81:Cassette 1/8 inch, 6.35:Reel-to-reel 1/4 inch]

/*[ Blade width in mm ]*/
cut_width = 0.2; // [0.1 : 0.1 : 1]

block();

module block() {
    $fn = 30;

    difference(){
        cube([block_x, block_y, block_z], true);

        translate([0,0,block_z/2.0 - tape_channel_depth/2.0]) channel();

        //rotate and place (z translation is already handled)
        translate([-block_x/4.0 ,0,0]) cut();
        translate([0 ,0,0]) rotate([0,0,22.5] )cut();
        translate([block_x/4.0 ,0,0]) rotate([0,0,45])cut();
    }
}

module channel() {
    channel_x = block_x * 1.1;
    union() {
        //the channel
        cube([channel_x, tape_channel_width, tape_channel_depth+.01], true);
        //angled edges
        rotate([45,0,0]) translate([0,0,tape_channel_depth])
            cube([channel_x, 1.5, tape_channel_depth], true);
        rotate([-45,0,0]) translate([0,0,tape_channel_depth])
            cube([channel_x, 1.5, tape_channel_depth], true);
    }
}

module cut() {
    cut_y = block_y * 3;
    cut_z = tape_channel_depth * 1.5;

    tans_z = block_z /2.0 - cut_z;

    union() {
        //the actual thin cut channel
        translate([0,0,tans_z]) cube([cut_width, cut_y, cut_z], true);
        //the cut champfer
        scale([1,cut_y/(cut_width/2.0),1])
            hull() {
                translate([cut_width*2.0, 0, block_z /2.0]) sphere(d=cut_width/1.5, true);
                translate([-cut_width*2.0, 0,block_z /2.0]) sphere(d=cut_width/1.5, true);
                translate([0,0,tans_z]) sphere(d=cut_width, true);
            }
    }
}
```


[User]
I'm looking to design a customizable studded wheel for my Worx Landroid robotic mower, and I'd like it to be parametric so I can tweak the dimensions easily. I've seen some designs on Thingiverse but want something from scratch in OpenSCAD.

The basic idea is a wheel with a central mounting area, an outer ring, and studs for extra traction. I need to be able to specify the outer diameter of the wheel (excluding the studs), the overall wheel depth, the depth of the mounting area where the washer sits, the thickness of the outer ring, and the number of studs per row around the circumference, as well as the stud's width and height. The spacing of the studs should be such that there are alternating rows, one with the specified number, and the next row with that number minus one.

The wheel should also have spokes connecting the central mounting area to the inner part of the outer ring. I need to be able to control the thickness of the spokes and the number of spokes. It would also be useful to control the diameter of the washer area. There is also a desire to make space for an additional weight disc if needed, so a setting that allows for some material to be removed from the center part of the wheel is needed (this is also where the washer goes) which will allow for this. Finally, "roundness" or resolution needs to be controllable.

Here are the specific parameters I'd like to be able to control:

*   `diameterOuter`: Diameter of the wheel, excluding studs.
*   `wheelDepth`: Thickness of the wheel on the outer ring.
*   `mountDepth`: Thickness of the wheel around the mount (where the washer goes). This will determine the depth of the recessed washer area.
*  `mountThickness`: this will be the thickness of the material for the mount itself.  It should be a bit less than `mountDepth`.
*   `ringThickness`: Thickness of the wheel's outer ring.
*   `studsPerRow`: Number of studs per row on the wheel (alternating rows will have this number minus one).
*   `studWidth`: Width of the studs near the outer ring.
*   `studHeight`: Height of the studs.
*   `spokesThickness`: Thickness of the spokes.
*   `noSpokes`: Number of spokes.
*   `washerDiameter`: Diameter of the washer for fastening the wheel.
*   `extraDiscDepth`: Allows the center part of the wheel to be thinner, to make room for an extra weight disc.
*   `roundness`: Number of sides to approximate a circle.

The mounting mechanism is based on a triangular shape with some added locks/bars. I need the code to create these mounts based on the following:
* `mountMainSize`:  The length of one side of the triangle that forms the core mount.
* `mountSideLength`:  Height of the triangle that forms the core mount.
* `mountLockLength`: The length of the side lock used to secure the mount, including the top lock.
* `mountLockWidth`: The width of the side lock.
* `mountShortLockLength`: The length of the short locking tab.
* `mountTopBarWidth`: The width of the bar that connects the mount to the wheel.
* `mountTopBarHeight`: The height of the bar that connects the mount to the wheel.
* `mountBoltDiameter`: The diameter of the bolt hole for the main wheel.

Can you generate an OpenSCAD file (or set of files) that implements this parametric design? I'm not looking for a solution that uses any specific OpenSCAD libraries, I'd like the code to be self contained without requiring external libraries. I'd appreciate it if you could include comments in the code explaining each step, so I can understand how it works.

[Assistant]
landroidWheelCustomizable.scad:
```
// Diameter of wheel, excluding studs
diameterOuter = 185;

// Thickness of wheel on the outer ring
wheelDepth = 40;

// Thickness of wheel around the mount (where the washer goes) - should probably not be changed
mountDepth = 28;

mountThickness = mountDepth - 20;

// Thickness of the wheel's outer ring
ringThickness = 3;
diameterInner = diameterOuter - 2 * ringThickness;
// Number of studs per row on wheel - half of the rows will have this number, the other half this number minus 1
studsPerRow = 3; //[2,3]
// Width of studs near the outer wheel ring
studWidth = 12;
// Height of studs
studHeight = 14;

// Thickness of spokes
spokesThickness = 2;
// Number of spokes
noSpokes = 12;

// Diameter of washer for fastening wheel - make this larger if you plan on mounting an extra disc for more weight
washerDiameter = 30;
// If you plan  on mounting an extra washer or disc for extra weight, you can make the wheel a bit thinner here
extraDiscDepth = 0; //[0:3]

// "Roundness" - number of sides in a circle - the higher the number, the longer it takes to generate the file
roundness = 100; //[30:100]

/* [Hidden] */

mountMainSize = 30.5;
mountSideLength = mountMainSize / sqrt(3);
mountLockLength = 38.5;
mountlockWidth = 6;
mountShortLockLength = 33.5;
mountTopBarWidth = 11;
mountTopBarHeight = mountThickness + 4;
mountDiameter = sqrt(pow(mountLockLength, 2) + pow(mountlockWidth, 2));

mountBoltDiameter = 17;

carveDepth = wheelDepth > mountDepth ? wheelDepth - mountDepth + extraDiscDepth : 0;

$fn = roundness;

difference() {
    union() {
        wheel();
        cylinder(d=mountDiameter + 4, h=mountTopBarHeight + 2);
    }
    carve();
    mount();
}

module carve() {
    if (carveDepth > 0) {
        carvingRadius = carveDepth / 2 + pow(diameterInner - washerDiameter, 2) / (8 * carveDepth);
        rotate_extrude() {
            union() {
                translate([0, mountDepth - extraDiscDepth]) square([washerDiameter / 2, carveDepth]);
                intersection() {
                    square([diameterInner, wheelDepth]);
                    translate([washerDiameter / 2, carvingRadius + mountDepth - extraDiscDepth])
                        circle(carvingRadius);
                }
            }
        }
    }
}

module wheel() {
    ring(diameterOuter, ringThickness, wheelDepth);
    ring(diameterOuter, 10, spokesThickness);
    ring(diameterOuter * 2 / 3, spokesThickness, wheelDepth);
    ring(diameterOuter * 2 / 3 + 10, 10, spokesThickness);
    cylinder(d=30, h=wheelDepth);
    studs();

    intersection() {
        for (i=[0:noSpokes / 2]) {
            rotate([0, 0, i * 360 / noSpokes]) {
                translate([0, 0, wheelDepth / 2])
                    cube([spokesThickness, diameterOuter, wheelDepth], true);
                translate([0, 0, spokesThickness / 2])
                    cube([10, diameterOuter, spokesThickness], true);
            }
        }
        cylinder(d=diameterOuter, h=wheelDepth);
    }
}

module ring(dOut, thickness, depth) {
    difference() {
        cylinder(d=dOut, h=depth);
        cylinder(d=dOut - 2 * thickness, h=depth);
    }
}

module studs() {
    nofStudLines1 = floor(diameterOuter * PI / (studWidth));
    nofStudLines = nofStudLines1 % 2 == 1 ? nofStudLines1 - 1 : nofStudLines1;
    radius = diameterOuter / 2 - 1;
    for (angleNo=[1:nofStudLines]) {
        angle = 360 / nofStudLines * angleNo;
        if (angleNo % 2 == 0) {
            rotate([0,0,-angle])
                for (i=[0:studsPerRow - 1]) {
                    translate([0, radius, wheelDepth * i / studsPerRow + wheelDepth / (studsPerRow * 2)])
                        stud();
            }
        } else {
            rotate([0,0,-angle])
                for (i=[1:studsPerRow - 1]) {
                    translate([0, radius, wheelDepth * i / studsPerRow])
                        stud();
            }
        }
    }
}

module stud() {
    rotate([-90,0,0]) cylinder(d1=studWidth,d2=1,h=studHeight, $fn=10);
}

module mount() {
    translate([-mountMainSize / 2, -mountSideLength / 2, 0]) cube([mountMainSize, mountSideLength, mountThickness]);
    translate([-mountLockLength / 2, -mountlockWidth / 2, 0]) cube([mountLockLength, mountlockWidth, mountThickness]);

    rotate([0, 0, 60]) {
        translate([-mountMainSize / 2, -mountSideLength / 2, 0]) cube([mountMainSize, mountSideLength, mountThickness]);
        translate([-mountLockLength / 2, -mountlockWidth / 2, 0]) cube([mountLockLength, mountlockWidth, mountThickness]);
    }
    rotate([0, 0, 120]) {
        translate([-mountMainSize / 2, -mountSideLength / 2, 0]) cube([mountMainSize, mountSideLength, mountThickness]);
        translate([-mountMainSize / 2, -mountTopBarWidth / 2, 0]) cube([mountMainSize, mountTopBarWidth, mountTopBarHeight]);
        translate([-mountShortLockLength / 2, -mountlockWidth / 2, 0]) cube([mountShortLockLength, mountlockWidth, mountTopBarHeight]);
    }

    cylinder(d=mountBoltDiameter, h=wheelDepth);
}

```


[User]
Hey, I'm looking for some help designing a customizable tape guide for making cassette tape loops. I've been messing around with the idea, and I've made a very rough version, but I'd love to have a version I can modify more easily.

Basically, it's a cylindrical guide that the tape wraps around. Here's what I need to be able to control:

*   **Inner Diameter:** The diameter of the main cylinder the tape wraps around (e.g., 10mm). I need to be able to set this precisely.
*   **Lip Overhang:** There should be a slight lip at the top and bottom edges of the guide so the tape doesn't slip off the sides. I need to specify how much extra radius this lip adds.
*   **Overall Height:** The total height of the guide.
*   **Tape Width:** The height of the flat, middle portion of the guide where the tape sits (this needs to be less than the overall height).
*   **Edge Height:** The height of the flat, cylindrical part of the lip (before it tapers down to the main cylinder).
*   **Number of Faces:** I need to make sure the cylinder is smooth, so this needs to be customizable, probably using `$fn`.

The guide should have a tapered edge leading down from the lip to the main cylinder. So the lip will be a short cylinder, then there will be a taper down to the main cylinder, then the flat part for the tape, then a taper up to the lip and a flat lip cylinder at the top. Does that make sense?

I'd love to have a parametric OpenSCAD file so I can easily adjust these dimensions and generate a new STL. I don't think I need any libraries, but if you think something from one would be helpful, let me know.

[Assistant]
tape_guide.scad:
```
/*[ center diamater ]*/
guide_inner_diameter = 10.0;  // [4 : 0.5 : 20]

/*[ additional radius at edges ]*/
guide_lip_overhang = 0.4; // [0 : 0.1 : 3]

/*[ total height ]*/
guide_height = 5.0; // [4 : 0.5 : 10]

/*[ height for tape ]*/
tape_width = 4.0; // [3 : 0.2 : 8]

/*[ non-tapered guide edge height ]*/
guide_edge_height = 0.4; // [0 : 0.1 : 1]

single_taper_height = (guide_height - tape_width) / 2.0;
single_taper_edge_height = single_taper_height + guide_edge_height;

/*[ number of faces (larger = smoother) ]*/
$fn=120; //make is smooth

edge();

cylinder(guide_height, d=guide_inner_diameter);

translate([0,0,guide_height]) mirror([0,0,1]) edge();

module edge() {
    guide_edge_diameter = guide_inner_diameter + (2 * guide_lip_overhang);

    cylinder(guide_edge_height, d=guide_edge_diameter);
    translate([0,0,guide_edge_height-0.01])
        cylinder(single_taper_height, d1=guide_edge_diameter, d2=guide_inner_diameter);
}
```