[User]
I'm looking to design a customizable Christmas tree star topper, and I'd like to have it parameterized so I can easily change things. I was inspired by the design on codeandmake.com, but I want my own version.

Here are the main parameters I want to be able to adjust:

*   **Star Diameter:** The overall diameter of the star.
*   **Star Thickness:** The overall thickness of the star, excluding a possible middle extrusion.
*   **Middle Extrusion:** A flat section in the middle that can help with bed adhesion. This should be a flat cylinder shape.
*   **Points:** The number of points on the star.
*   **Inner Point Diameter Percentage:** The diameter of the inner points as a percentage of the outer points.
*   **Material Thickness:** The thickness of the material itself.
*   **Mount Hole Diameter:** The diameter of the hole where the star will attach to the tree.
*   **Half:** A boolean (true/false) to print either the whole star or just half of it, in which case it will need to be rotated for printing.

I would like the star to be built from the intersection of spheres, using `hull()` for the solid parts. It should have a center sphere and the outer points and inner points. The mount should also be solid and connected to the star, using a rotated extrude, and should have a hole in it that goes through the entire design. The middle extrusion should be a flat cylinder with a diameter that extends through the star. When the `Half` parameter is set to true, the design should cut in half along the y-axis for printing.

I don't have a specific library in mind, but if you think a particular one would help with this design, feel free to use it. I'm comfortable with pretty standard OpenSCAD, but would prefer code that is well-structured and easy to understand. Can you write the OpenSCAD for this?

[Assistant]
codeandmake.com_Christmas_Tree_Star_Topper_v1.0.scad:
```
/*
 * Copyright 2020 Code and Make (codeandmake.com)
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */

/*
 * Christmas Tree Star Topper by Code and Make (https://codeandmake.com/)
 *
 * https://codeandmake.com/post/christmas-tree-star-topper
 *
 * Christmas Tree Star Topper v1.0 (25 November 2020)
 */

// The overall diameter of the star
Star_Diameter = 150; // [50:1:300]

// The overall thickness of the star minus Middle_Extrusion
Star_Thickness = 40; // [0:1:100]

// Adds a flat section to the middle of the star which can improve support adhesion
Middle_Extrusion = 5; // [0:1:100]

// The number of points
Points = 5; // [3:1:12]

// The diameter of the inner points as a percentage of the outer points
Inner_Point_Diameter_Percent = 50; // [0:1:100]

// Thickness of the material
Material_Thickness = 2; // [1:1:5]

// The diameter at the bottom of the mount hole
Mount_Hole_Diameter = 30; // [10:1:100]

// Cut star in half (will also rotate for printing)
Half = false;

module star() {
  module middleExtrusionFace(solid) {
    hull() {
      // outer point
      translate([0, 0, (Star_Diameter - Material_Thickness) / 2]) {
        rotate([-90, 0, 0]) {
          cylinder(d = Material_Thickness, h = Middle_Extrusion, center = true);
        }
      }

      // inner point
      rotate([0, 360 / Points / 2, 0]) {
        translate([0, 0, (Star_Diameter - Material_Thickness) / 2 * (Inner_Point_Diameter_Percent / 100)]) {
          rotate([-90, 0, 0]) {
            cylinder(d = Material_Thickness, h = Middle_Extrusion, center = true);
          }
        }
      }

      if(solid) {
        // inner center
        rotate([-90, 0, 0]) {
          cylinder(d = Material_Thickness, h = Middle_Extrusion, center = true);
        }
      }
    }
  }

  module middleExtrusionFaces(solid) {
    middleExtrusionFace(solid);
    mirror([1, 0, 0]) {
      middleExtrusionFace(solid);
    }
  }

  module middleExtrusion(solid) {
    for (i=[1:Points]) {
      rotate([0, i * (360 / Points), 0]) {
        middleExtrusionFaces(solid);
      }
    }
  }

  module pointFace(solid) {
    translate([0, Middle_Extrusion / 2, 0]) {
      hull() {
        // outer center
        translate([0, max((Star_Thickness - Material_Thickness) / 2, 0), 0]) {
          sphere(d = Material_Thickness);
        }

        // outer point
        translate([0, 0, (Star_Diameter - Material_Thickness) / 2]) {
          sphere(d = Material_Thickness);
        }

        // inner point
        rotate([0, 360 / Points / 2, 0]) {
          translate([0, 0, (Star_Diameter - Material_Thickness) / 2 * (Inner_Point_Diameter_Percent / 100)]) {
            sphere(d = Material_Thickness);
          }
        }

        if(solid) {
          // inner center
          sphere(d = Material_Thickness);
        }
      }
    }
  }

  module pointFrontFaces(solid) {
    pointFace(solid);
    mirror([1, 0, 0]) {
      pointFace(solid);
    }
  }

  module pointFaces(solid) {
    pointFrontFaces(solid);
    mirror([0, 1, 0]) {
      pointFrontFaces(solid);
    }
  }

  module points(solid) {
    for (i=[1:Points]) {
      rotate([0, i * (360 / Points), 0]) {
        pointFaces(solid);
      }
    }
  }

  module mount(solid) {
    rotate_extrude(convexity=10) {
      hull() {
        translate([Material_Thickness / 2, 0, 0]) {
          circle(d = Material_Thickness);
        }

        intersection() {
          square(Material_Thickness);
          circle(d = Material_Thickness * 2);
        }

        translate([(Mount_Hole_Diameter + Material_Thickness) / 2, -(Star_Diameter - Material_Thickness) / 2, 0]) {
          circle(d = Material_Thickness);
        }

        if(solid) {
          translate([0, -(Star_Diameter - Material_Thickness) / 2, 0]) {
            intersection() {
              translate([0, -Material_Thickness / 2, 0]) {
                square([Material_Thickness / 2, Material_Thickness]);
              }
              circle(d = Material_Thickness);
            }
          }
        }
      }
    }
  }

  module starInside() {
    difference() {
      points(true);
      points();
    }
  }

  module mountInside() {
    difference() {
      mount(true);
      mount();
    }
  }

  module extrusionInside() {
    difference() {
      middleExtrusion(true);
      middleExtrusion();
    }
  }

  module wholeStar() {
    union() {
      difference() {
        points();
        mountInside();
      }

      difference() {
        mount();
        starInside();
        if (Middle_Extrusion > 0) {
          extrusionInside();
        }
      }

      if (Middle_Extrusion > 0) {
        difference() {
          middleExtrusion();
          mountInside();
        }
      }

    }
  }

  if (Half) {
    rotate([-90, 0, 0]) {
      intersection() {
        wholeStar();
        y = max((Star_Thickness + Middle_Extrusion) / 2, Mount_Hole_Diameter);
        translate([-Star_Diameter / 2, -y, -Star_Diameter / 2]) {
          cube(size=[Star_Diameter, y, Star_Diameter]);
        }
      }
    }
  } else {
    wholeStar();
  }
}

if ($preview) {
  echo("### PREVIEW MODE: Showing low-poly version ###");
  $fn = 20;
  star();
} else {
  echo("### RENDER MODE: Generating high-poly version (This may take some time) ###");
  $fn = 60;
  star();
}
```


[User]
I'm looking to create a customizable handle grip, similar to the one described on codeandmake.com. I need an OpenSCAD design that lets me control several aspects of the handle's shape.

Specifically, I need to be able to set:

*   The length of the main handle core.
*   The thickness of the handle core material (not including any bulges).
*   The diameter of a hole that runs through the handle.
*   The depth of this hole, expressed as a percentage of the handle's total length.
*   The length of a bulge along the handle, expressed as a percentage of the main handle core's length.
*   The width of the bulge.
*   The radius of a bevel used on the end caps.
*   How much the middle of the end caps extrude outwards.

The design should produce a solid handle with a core, an optional bulge, end caps that have beveled edges and a central extrusion, and a hole running through the handle (that may or may not be partially filled). Please generate a single .scad file for this. The design does not need any included libraries. I'd like to be able to control all the values mentioned above through customizable variables.

[Assistant]
codeandmake.com_General_Purpose_Handle_Grip_v1.0.scad:
```
/*
 * Copyright 2020 Code and Make (codeandmake.com)
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */

/*
 * General Purpose Handle Grip by Code and Make (https://codeandmake.com/)
 *
 * https://codeandmake.com/post/general-purpose-handle-grip
 *
 * General Purpose Handle Grip v1.0 (27 November 2020)
 */

/* [Handle] */

// Length of the handle core (the part you hold)
Handle_Core_Length = 100; // [10:1:200]

// Thickness of the handle core material (excludes the bulge)
Handle_Core_Thickness = 5; // [2:1:50]

/* [Hole] */

// Diameter of the hole inside the handle
Hole_Diameter = 6.2; // [0:0.1:50]

// Depth of the hole inside the handle as percentage of overall length
Hole_Depth_Percent = 80; // [0:1:100]

/* [Bulge] */

// Length of the bulge as percentage of Handle_Core_Length
Bulge_Length_Percent = 80; // [0:1:100]

// Width of the bulge
Bulge_Width = 3; // [0:1:50]

/* [End Caps] */

// The radius of the bevel used for the end caps
Cap_Bevel_Radius = 1; // [0:1:50]

// How much to extrude the middle of the end caps
Cap_Middle_Extrusion = 5; // [0:1:50]

module handle() {
  $fn = 80;

  handleCoreWidth = (Handle_Core_Thickness * 2) + max(Hole_Diameter, 0);
  bulgeLength = Handle_Core_Length * (Bulge_Length_Percent / 100);

  dimensionBulgeDiameterWidest = handleCoreWidth + (Bulge_Width * 2);
  dimensionCapDiameter = handleCoreWidth + (Cap_Bevel_Radius * 4);

  dimensionsXY = max(dimensionBulgeDiameterWidest, dimensionCapDiameter);
  dimensionsZ = Handle_Core_Length + (Cap_Bevel_Radius * 6) + (Cap_Middle_Extrusion * 2);

  echo(str("Dimensions: X: ", dimensionsXY, "mm, Y: ", dimensionsXY, "mm Z: ", dimensionsZ, "mm"));
  echo(str("Handle core diameter at thinnest point = ", handleCoreWidth, "mm"));
  echo(str("Handle core diameter at widest point = ", dimensionBulgeDiameterWidest, "mm"));

  module bulgeHalf() {
    xWidth = 1 - ((sin(45) * 2) - 1);
    yHeight = 1 + ((sin(45) * 2) - 1);

    scale([1 / xWidth, 2 / yHeight, 1]) {
      translate([-((sin(45) * 2) - 1), 0, 0]) {
        union() {
          intersection() {
            circle(r=1);

            translate([(sin(45) * 2) - 1, 0, 0]) {
              square([1 - ((sin(45) * 2) - 1), sin(45) * 2]);
            }
          }

          intersection() {
            difference() {
            square([sin(45), sin(45) * 2]);

            translate([sin(45) * 2, sin(45) * 2, 0]) {
              circle(r=1);
            }
          }

            translate([(sin(45) * 2) - 1, 0, 0]) {
              square([1 - ((sin(45) * 2) - 1), sin(45) * 2]);
            }
          }
        }
      }
    }
  }

  module cap() {
    translate([0, 0, (Handle_Core_Length / 2)]) {
      rotate_extrude(convexity=10) {
        hull() {
          translate([(handleCoreWidth / 2) + Cap_Bevel_Radius, Cap_Bevel_Radius * 2, 0]) {
            intersection() {
              circle(r=Cap_Bevel_Radius);
            }
          }

          translate([(handleCoreWidth / 2) + Cap_Bevel_Radius, (Cap_Bevel_Radius * 2) + Cap_Middle_Extrusion, 0]) {
            intersection() {
              circle(r=Cap_Bevel_Radius);
            }
          }
        }

        translate([0, Cap_Bevel_Radius, 0]) {
          square([(handleCoreWidth / 2) + Cap_Bevel_Radius, (Cap_Bevel_Radius * 2) + Cap_Middle_Extrusion]);
        }

        translate([handleCoreWidth / 2, 0, 0]) {
          difference() {
            square([Cap_Bevel_Radius, Cap_Bevel_Radius]);
            translate([Cap_Bevel_Radius, 0, 0]) {
              circle(r=Cap_Bevel_Radius);
            }
          }
        }

        square([(handleCoreWidth / 2), Cap_Bevel_Radius]);
      }
    }
  }

  module hole() {
    if(Hole_Depth_Percent > 0) {
      translate([0, 0, ((Handle_Core_Length / 2) + (Cap_Bevel_Radius * 3) + Cap_Middle_Extrusion) - ((Handle_Core_Length + (Cap_Bevel_Radius * 6) + (Cap_Middle_Extrusion * 2)) * (Hole_Depth_Percent / 100)) - 0.1]) {
        cylinder(d = Hole_Diameter, h = Handle_Core_Length + (Cap_Bevel_Radius * 6) + (Cap_Middle_Extrusion * 2) + 1);
      }
    }
  }

  module handleBody() {
    // core
    cylinder(d = handleCoreWidth, h = Handle_Core_Length, center = true);

    // bulge
    if (Bulge_Length_Percent > 0 && Bulge_Width > 0) {
      rotate_extrude(convexity=10) {
        translate([handleCoreWidth / 2, 0, 0]) {
          scale([Bulge_Width, bulgeLength / 2 / 2, 1]) {
            bulgeHalf();

            mirror([0, 1, 0]) {
              bulgeHalf();
            }
          }
        }
      }
    }

    // top cap
    cap();

    // bottom cap
    mirror([0, 0, 1]) {
      cap();
    }
  }

  difference() {
    handleBody();
    hole();
  }
}

handle();
```


[User]
I'm trying to design a parametric snap-fit connector, similar to the ones used on the Snappy 3 Reprap. They're really strong and accurate, and I'd like to be able to generate them with OpenSCAD using adjustable dimensions.

Essentially, I need a connector that's extruded along its length, and has tabs that lock into matching slots. It would be great if the design could incorporate these features:

*   **Overall Dimensions:** I need to control the overall length (X), width (Y), and thickness (Z) of the connector.
*   **Tab Placement:** There should be tabs extruded from the main body along its Y direction.  Ideally, I want to control the width of each tab (in the X direction), the distance the tabs protrude in the Y direction, and the thickness of the tabs (in the Z direction) along with the number and spacing of the tabs. The spacing should be consistent along the length. I also need to define the number of tabs.
*   **Tab Geometry:** The tab profile should have a slight inward slope (towards the center of the connector) with a rounded edge. There's also a more complex profile at the far end of the tabs, with an upward slope and then a flat section.
*   **Landing Pads:** I need landing pads that are offset from the main body in the Y direction that match with the tab geometry. The landing pads should be located between each tab.
*   **Diamond Notches:** There should also be diamond-shaped notches on each side of the landing pads, for lateral locking.

I'm thinking the design should use a `linear_extrude` on a base profile to form the main body and the tabs. It would be great if the code was parameterized such that I could easily adjust all the critical dimensions: the overall XYZ dimensions, tab dimensions, landing pad size and position, and the size of the diamond notches. Also, it should be easy to adjust the spacing and number of tabs.

I would expect to call this with a series of variables for the overall connector dimensions, and then another set for the tabs. I think there should also be a variable that specifies the number of tabs.

I would like this to be done in OpenSCAD, without any custom functions. I would not like to use any external libraries like MCAD, BOSL, BOSL2, dotSCAD, NopSCADlib, or BOLTS - just the core OpenSCAD language.

Could you help me generate the OpenSCAD file for this?

[Assistant]
Snappy_Connector.scad:
```
x = 50;
y = 10;
z = 5;

SnappyClip(x,y,z);

module SnappyClip(OAX=50, OAY=10, OAZ=5) {
    clr = 0.26;
    tabX = OAX/6;
    tabY = (OAY-2*clr)/3;
    tabZ = tabX;
    tabLanding = OAY/sqrt(3);
    diamondNotchY = OAY/12;
    diamondNotchX = OAX/3.5;
    diamondNotchZ = tabZ/4.6;

    y1=0;           x1=0;           z1=0;
    y2=tabY;        x2=tabX;        z2=OAZ-tabZ/2;
    y3=y2+clr;      x3=x2+tabX;     z3=OAZ;
    y4=y3+tabY;     x4=x3+tabX;     z4=OAZ+tabZ/2;
    y5=y4+clr;      x5=x4+tabX;
    y6=y5+tabY;     x6=x5+tabX;
                    x7=x6+tabX;
    x25=(x2+x3)/2;
    x55=(x6+x5)/2;

    baseProfile =      [[x1,z1],
                        [x1,z3],
                        [x2,z2],
                        [x3,z2],
                        [x4,z3],
                        [x5,z2],
                        [x6,z2],
                        [x7,z3],
                        [x7,z1]];
    outsideProfile =   [[x1,z1],
                        [x1,z3],
                        [x2,z2],
                        [x3,z2],
                        [x4,z3],
                        [x5,z4],
                        [x6,z4],
                        [x7,z3],
                        [x7,z1]];
    insideProfile =    [[x1,z1],
                        [x1,z3],
                        [x2,z4],
                        [x3,z4],
                        [x4,z3],
                        [x5,z2],
                        [x6,z2],
                        [x7,z3],
                        [x7,z1]];

    difference() {
        union() {
            translate([0,OAY,0]) rotate([90,0]) {
                //through profile
                linear_extrude(OAY)
                    polygon(baseProfile);
                //front tab
                linear_extrude(tabY)
                    polygon(outsideProfile);
                //back tab
                translate([0,0,y5])
                linear_extrude(tabY)
                    polygon(outsideProfile);
                //middle tab
                translate([0,0,y3])
                linear_extrude(tabY)
                    polygon(insideProfile);
            }
            //landings
            translate([x25, y3, z2])
                resize([tabX, tabLanding-tabY, tabZ])
                cylinder($fn=4);
            translate([x25, y4, z2])
                resize([tabX, tabLanding-tabY, tabZ])
                cylinder($fn=4);
            //lateral locking diamonds
            translate([x25, y3, z3])
                resize([diamondNotchX, diamondNotchY, diamondNotchZ])
                rotate([0,90])
                cylinder($fn=4,center=true);
            translate([x25, y4, z3])
                resize([diamondNotchX, diamondNotchY, diamondNotchZ])
                rotate([0,90])
                cylinder($fn=4,center=true);
        }

        //landings
        translate([x55, y2, z2])
            resize([tabX, tabLanding-tabY, tabZ+0.01])
            cylinder($fn=4);
        translate([x55, y5, z2])
            resize([tabX, tabLanding-tabY, tabZ+0.01])
            cylinder($fn=4);
        //lateral locking diamonds
        translate([x55, y2, z3])
            resize([diamondNotchX+2*clr, diamondNotchY, diamondNotchZ])
            rotate([0,90])
            cylinder($fn=4,center=true);
        translate([x55, y5, z3])
            resize([diamondNotchX+2*clr, diamondNotchY, diamondNotchZ])
            rotate([0,90])
            cylinder($fn=4,center=true);
    }

    echo(OAX, OAY, OAZ);
}
```


[User]
I'd like to design a parametric key locker, similar to the "Magic Locker" but with some improvements and customizability.

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

**Core Structure:**

*   The locker will have a central rectangular cavity to hold a key. The cavity should have dimensions `keyLength`, `keyWidth`, and `keyThk` (for the key thickness).
*   The main body of the locker should be a rounded rectangle that is essentially a scaled cylinder with a `dBody` diameter and `zBody` height. The `eccentricity` will be derived from the relationship of the `dBody` and `OAThk` parameters.
*   There will be a hole, with diameter `dLock`, through the cylinder at the `keyLength` point to act as the locking mechanism. This hole should extend through the thickness of the cylinder.
*   The overall outer thickness of the locker should be defined by `OAThk`, derived from `keyThk` and `wallThk`.

**Key Parameters:**

*   `keyLength`: Length of the key cavity.
*   `keyWidth`: Width of the key cavity.
*  `keyThk`: Thickness of the key cavity.
*   `headLength`: Length of the portion of the key that sticks out.
*   `dLock`: Diameter of the hole for the lock.
*   `wallThk`: Thickness of the walls of the locker.
*   `note`: Text to be printed on the locker.
*   `noteHt`: Height of the text.
*   `$fn`: Fragmentation for curves

**Derived Parameters:**

*   `zBody`: Height of the main body; calculated from `keyLength`, `dLock`, and `wallThk`.
*   `dBody`: Diameter of the main body, based on `keyWidth` and `wallThk`.
*   `OAThk`: Overall thickness of the locker, based on `keyThk` and `wallThk`.
*   `eccentricity`: The ratio of `OAThk` to `dBody`, used to scale the main body cylinder in the y dimension.

**Features:**

*   The key cavity should extend a bit past the circular locker's wall in the front.
*   The locking mechanism hole should be perpendicular to the key cavity.
*   The specified text (`note`) should be imprinted on both the front and back of the locker.
*   I’d like to use the Liberation Sans Bold font.

Could you create a parametric OpenSCAD file that accomplishes this? Please make sure that it's well-commented. I'm not looking to use any external libraries for this.

[Assistant]
Key_Locker.scad:
```
keyLength = 40;
keyWidth = 10;
keyThk = 4.5;
headLength = 16;
dLock = 6;
wallThk = 4;
note = "FERRARI";
noteHt = 5;
$fn=60;
zBody = keyLength+dLock/2+wallThk;
dBody = keyWidth+2*wallThk;
OAThk = keyThk+2*wallThk;
eccentricity = OAThk/dBody;

difference() {
    // main outer
    scale([1,eccentricity,1])
    cylinder(h=zBody, d=dBody);
    union() {
        // key inner
        translate([0,0,zBody/2+1])
            cube(size=[keyWidth,keyThk,zBody*2+0.01],center=true);
        // top of key sticks out
        translate([-dBody/2,-keyThk/2,keyLength-headLength])
            cube(size=[dBody+0.01,keyThk,keyLength]);
         // hole for lock
        translate([0,0,keyLength])
        rotate([90,0,0])
            cylinder(h=dBody,d=dLock, center=true);
        //text, front
        translate([0,-OAThk/2,wallThk/2])
        rotate([0,-90,90])
        linear_extrude(0.4*2, center=true)
            text(note, font="Liberation Sans:style=Bold", size=noteHt, valign = "center");
        translate([0,OAThk/2,wallThk/2])
        rotate([0,-90,90])
        mirror([0,90,0])
        linear_extrude(0.4*2, center=true)
            text(note, font="Liberation Sans:style=Bold", size=noteHt, valign = "center");
    }
}
```


[User]
Hey, I'm looking to get a parametric OpenSCAD design for a bass guitar thumb rest. I've seen some designs that use rounded corners and screw holes for mounting, and I'd like to be able to adjust all of those dimensions.

Specifically, I need to control the overall width, length, and height of the rest. I'd also like to specify the radius for rounded corners on the top edges. I need two screw holes to attach the rest to the bass, and I need to be able to control the distance between those screw holes, as well as the radius of the screw holes and the radius and depth for the screw head cutout. Finally, I'd like to have optional offsets for the screw hole positions along the X and Y axes.

Ideally, the code should be easy to customize via parameters at the top of the file. I'm envisioning a main module that creates the basic shape with rounded corners and then adds the screw holes via difference operations. Could you generate the SCAD code for me? I'm not particular about which libraries are used, but please specify if they're needed.

[Assistant]
bassthumbrest.scad:
```
//width
w = 13;
//length
l = 64;
//height
h = 12;
//border radius
r = h;
//screw hole distance
hd = 32;
//screw hole radius
hr = 2.5;
//screw head cutout depth and bottom/top radius
hr2 = [3.2,hr,4.75];
//optional screw offset x
smx = 0;
//optional screw offset y
smy = 0;

module sr_cube(size=[1,1,1],radius=0.5,corners=[1,1,1,1]) {
    difference(){
    cube(size);

        if(corners[0])
        translate([radius,radius,0])rotate([0,0,180])difference(){
                cube([radius*2,radius*2,size[2]]);
                cylinder(size[2],radius,radius);
        }
        if(corners[1])
        translate([size[0]-radius,radius,0])rotate([0,0,270])difference(){
                cube([radius*2,radius*2,size[2]]);
                cylinder(size[2],radius,radius);
        }
        if(corners[2])
        translate([size[0]-radius,size[1]-radius,0])rotate([0,0,0])difference(){
                cube([radius*2,radius*2,size[2]]);
                cylinder(size[2],radius,radius);
        }
        if(corners[3])
        translate([radius,size[1]-radius,0])rotate([0,0,90])difference(){
                cube([radius*2,radius*2,size[2]]);
                cylinder(size[2],radius,radius);
        }
        }

}

module screw_cutout() {
    cylinder(h,hr,hr,$fn=20);
    translate([0,0,h-hr2[0]]) cylinder(hr2[0],hr2[1],hr2[2],$fn=20);
}

difference(){
translate([0,w,0])rotate([90,0,0])sr_cube([l,h,w],corners=[0,0,1,1],radius=r,$fn=60);
translate([(l-hd)/2+smx,w/2+smy,0]) screw_cutout();
translate([l-(l-hd)/2+smx,w/2+smy,0]) screw_cutout();

}
```


[User]
Hey, I'm looking to get a custom cable comb designed in OpenSCAD, and I'm hoping you can help me out. I've got a basic idea from a design I saw, and I'll walk you through the parameters I'm looking for.

Essentially, it'll be a comb with slots to hold cables, mounted to a backplate. Here are the main parameters I need to control:

*   **Cable_Slots:** The number of slots, with a minimum of 2 and a maximum of 15.
*   **Slot_Width:** The width of each individual cable slot, from 1mm to 15mm, with 0.1mm increments.
*   **Comb_Depth:** The overall depth (projection from the wall), ranging from 20mm to 100mm, in 5mm increments.
*   **Screw_Hole_Diameter:** The diameter of the screw holes, and I'd like to switch between 4mm, 5mm, or 6mm.
*   **Edge_Screw_Holes:** A boolean to include or not include screw holes on the left and right edges of the backplate.
*   **Center_Screw_Hole:** A boolean to include or not include a screw hole in the center of the backplate.

Now, there are also some advanced parameters that might be good to expose. I'm not sure I'll need them, but flexibility is good.

*   **Back_Height:**  The height of the backplate, ranging from 20mm to 50mm, in 5mm increments.
*   **Comb_Thickness:** The thickness of the comb itself, from 2mm to 5mm.
*   **Lip_Depth:** The depth of the angled lip on the bottom of the comb, ranging from 5mm to 20mm.
*   **Lip_Angle:** The angle of that lip, from 0 to 90 degrees.
*   **Cutout_Margin:** The spacing between each slot, 5mm to 30mm.
*   **Chamfer_Depth:** The depth of the chamfer on the end of the cutouts, from 1mm to 4mm, in 0.5mm increments.

The whole thing should be parametric and modifiable through those variables, of course. I don't think I need any complex libraries for this, just the standard OpenSCAD functions should be fine.

Finally, it might be nice to have a few helper functions to generate the screw holes, the main body, and each of the cable slot cutouts. This will just make the main code cleaner. Let me know if you think you can do this, and if you have questions!

[Assistant]
ParametricCableComb.scad:
```
// Parametric Cable Comb
//
// Jason Milldrum
// 22 November 2020

/* [Parameters] */
// The number of slots to hold cables
Cable_Slots = 8; // [2:15]

// Width of the cable slot
Slot_Width = 5.0; // [1:0.1:15]

// Projection distance from the wall
Comb_Depth = 50; // [20:5:100]

// Size of screw
Screw_Hole_Diameter = 5; // [4, 5, 6]

// Include edge screw holes?
Edge_Screw_Holes = true;

// Include center screw hole?
Center_Screw_Hole = false;

/* [Advanced] */
Back_Height = 25; // [20:50]
Comb_Thickness = 3; // [2:5]
Lip_Depth = 10; // [5:20]
Lip_Angle = 20; // [0:90]
Cutout_Margin = 10; // [5:30]
Chamfer_Depth = 1; // [1:0.5:4]

// Calculated Parameter
Comb_Width = (Cable_Slots) * (Slot_Width + Cutout_Margin) + Cutout_Margin;

module screw_holes() {
    if (Edge_Screw_Holes == true) {
        translate([-(Comb_Width / 2 - Screw_Hole_Diameter * 2), Comb_Depth - Comb_Thickness / 2, Back_Height / 2])
            rotate([270, 0, 0])
                union() {
                    cylinder(d=Screw_Hole_Diameter, h=Comb_Thickness);
                    cylinder(d=Screw_Hole_Diameter * 2,h=Comb_Thickness / 2);
                }
        translate([Comb_Width / 2 - Screw_Hole_Diameter * 2, Comb_Depth - Comb_Thickness / 2, Back_Height/2])
            rotate([270, 0, 0])
                union() {
                    cylinder(d=Screw_Hole_Diameter, h=Comb_Thickness);
                    cylinder(d=Screw_Hole_Diameter * 2,h=Comb_Thickness / 2);
            }
    }
    if (Center_Screw_Hole == true) {
        translate([0, Comb_Depth - Comb_Thickness / 2, Back_Height/2])
        rotate([270, 0, 0])
            union() {
                cylinder(d=Screw_Hole_Diameter, h=Comb_Thickness);
                cylinder(d=Screw_Hole_Diameter * 2,h=Comb_Thickness / 2);
            }
    }
}

module body() {
    // Back
    translate([
        0,
        Comb_Depth,
        Back_Height / 2
    ])
        cube([Comb_Width, Comb_Thickness, Back_Height], center=true);
    // Comb
    translate([
        0,
        (Comb_Depth / 2),
        Comb_Thickness / 2
    ])
        cube([Comb_Width, Comb_Depth, Comb_Thickness], center=true);
    // Lip
    rotate([-Lip_Angle, 0, 0])
        translate([-Comb_Width / 2, -Lip_Depth, 0])
            rotate([0, 90, 0])
                rotate([0, 0, 90])
                    linear_extrude(height = Comb_Width)
                        union(){
                            polygon([
                                [1, 0],
                                [Lip_Depth, 0],
                                [Lip_Depth, Comb_Thickness],
                                [1, Comb_Thickness]
                            ]);
                            offset(r=+0.8,$fn=24) offset(delta=-0.8,$fn=24)
                                polygon([
                                    [0, 0],
                                    [Lip_Depth, 0],
                                    [Lip_Depth, Comb_Thickness],
                                    [0, Comb_Thickness]
                                ]);
                        }
}

module cutout() {
    Cutout_Depth = (Lip_Depth * cos(Lip_Angle)) + Comb_Depth - Cutout_Margin;
    Cutout_Height = Lip_Depth + Comb_Thickness + 2;
    // Slot
    translate([
        -Slot_Width / 2,
        0,
        0
    ])
        cube([Slot_Width, Cutout_Depth - (Lip_Depth * cos(Lip_Angle)), Cutout_Height]);
    // Rounded end
    translate([
        0,
        Cutout_Depth - (Lip_Depth * cos(Lip_Angle)),
        0
    ])
        cylinder(h=Cutout_Height, r=Slot_Width / 2);
    // Chamfered end
    linear_extrude(height = Cutout_Height)
        polygon(points=[
            [Slot_Width / 2, 0],
            [(Slot_Width / 2) + Chamfer_Depth, -(Lip_Depth * cos(Lip_Angle))],
            [-((Slot_Width / 2) + Chamfer_Depth), -(Lip_Depth * cos(Lip_Angle))],
            [-Slot_Width / 2, 0],
        ]);
}

$fa = 1;
$fs = 0.4;

difference() {
    body();
    if(Cable_Slots % 2 == 0) {
        for (i=[0:1:Cable_Slots - 1]){
            translate([i * (Slot_Width + Cutout_Margin) - ((Slot_Width + Cutout_Margin) * (Cable_Slots / 2) - ((Slot_Width + Cutout_Margin) / 2)), 0, 0])
                cutout();
        }
    }
    else {
        for (i=[0:1:Cable_Slots - 1]){
            translate([i * (Slot_Width + Cutout_Margin) - (Slot_Width + Cutout_Margin) * ((Cable_Slots - 1) / 2), 0, 0])
                cutout();
        }
    }
    screw_holes();
}

```


[User]
Hey, I'm looking for a way to generate customizable handles, specifically a dual-point mounting style. I'd like to be able to specify several parameters, such as:

*   **Screw Mounting:**
    *   Distance between the two screws (e.g., 100mm)
    *   Screw hole diameter (e.g., 5mm)
    *   Whether the screws should be mounted from the front or the rear.
*   **Front Screw Settings (if applicable):**
    *   Screw head hole diameter (e.g., 8.5mm)
    *   Material thickness between the screw head and the base (e.g., 5mm)
    *   Screw countersink angle (e.g., 90 degrees)
*   **Rear Screw Settings (if applicable):**
    *   Depth of the screw holes (e.g., 10mm)
*   **Handle Dimensions:**
    *   Thickness of the handle (both X and Y axis) (e.g., 10mm)
    *   Overall height of the handle (Z axis) (e.g., 18mm)
    *   Handle end length, which extends past the thickness of the handle material (e.g., 17.5mm).
*   **Hand Hole:**
    *   Width of the hand hole (X axis) (e.g., 65mm)
    *   Depth of the hand hole (Y axis) (e.g., 20mm)
*   **Bevel:**
    *   Radius of the bevel (e.g., 1.5mm)
    *   Whether the bevel should be rounded or not (true/false).

I need to be able to control all of these dimensions using parameters in OpenSCAD. Can you write a `.scad` file (or set of files if that makes sense) that can create this handle? I'd like a clear module called something like `handle()` that generates the entire handle based on these parameters. I also need that module to `echo` the overall dimensions (X, Y, Z).

I guess also, if you are generating multiple files, it would be useful if you did not rely on relative paths. Thank you!

[Assistant]
codeandmake.com_General_Purpose_Handle_Dual_Point_v1.2.scad:
```
/*
 * Copyright 2020-2022 Code and Make (codeandmake.com)
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */

/*
 * Fully Customizable General Purpose Handles by Code and Make (https://codeandmake.com/)
 *
 * https://www.thingiverse.com/thing:4643658
 *
 * General Purpose Handle Dual Point v1.2 (25 March 2022)
 */

/* [Screws] */

// Distance between the screws
Screw_Distance = 100; // [50:1:300]

// Screw hole diameter
Screw_Hole_Diameter = 5; // [2:0.5:10]

// Screw from front or rear
Screw_Direction = 0; // [0:Front, 1:Rear]

/* [Front Screws] */

// Screw head hole diameter
Screw_Head_Hole_Diameter = 8.5; // [2:0.5:15]

// Material thickness (between screw head and base)
Screw_Material_Thickness = 5; // [2:0.5:15]

// Screw countersink angle (82 and 90 are common)
Screw_Countersink_Angle = 90; // [1:0.5:180]

/* [Rear Screws] */

// Depth of screw holes
Screw_Hole_Depth = 10; // [1:1:50]

/* [Handle] */

// Thickness of handle (X and Y axis)
Handle_Material_Thickness = 10; // [10:0.5:50]

// Height of handle (Z axis)
Handle_Height = 18; // [10:0.5:50]

// Handle end length (in addition to Handle_Material_Thickness)
Handle_End_Length = 17.5; // [0:0.5:100]

/* [Hand Hole] */

// Width of hand hole (X axis)
Hand_Hole_Width = 65; // [50:0.5:150]

// Depth of hand hole (Y axis)
Hand_Hole_Depth = 20; // [10:0.5:50]

/* [Bevel] */

// Radius of bevel
Bevel_Radius = 1.5; // [0:0.5:5]

// Should bevel be rounded?
Bevel_Rounded = 0; // [0:false, 1:true]

module handle() {
  $fn = 100;

  dimensionsX = ((Hand_Hole_Width / 2) + Handle_Material_Thickness + Handle_End_Length) * 2;
  dimensionsY = Hand_Hole_Depth + Handle_Material_Thickness;
  dimensionsZ = Handle_Height;

  echo(str("Dimensions: X: ", dimensionsX, "mm, Y: ", dimensionsY, "mm Z: ", dimensionsZ, "mm"));

  rotate([90, 0, 0]) {
    handleHalf();
    mirror([1, 0, 0]) {
      handleHalf();
    }
  }

  module handleHalf() {
    difference() {
      // handle
      hull() {
        // upright profile
        mirror([1, 0, -1]) {
          linear_extrude(height = 1, convexity = 10) {
            handleProfile(0);
          }
        }

        // handle end
        translate([(Hand_Hole_Width) / 2, 0, 0]) {
          intersection() {
            cube([Handle_End_Length + Handle_Material_Thickness, Handle_Height, Hand_Hole_Depth + Handle_Material_Thickness]);

            hull() {
              // bottom profile
              mirror([0, 0, 1]) {
                linear_extrude(height = 1, convexity = 10) {
                  handleProfile(Hand_Hole_Depth - Handle_End_Length);
                }
              }

              translate([0, 0, Hand_Hole_Depth]) {
                intersection() {
                  cube([Handle_Material_Thickness, Handle_Height, Handle_Material_Thickness]);

                  rotate([-90, 0, 0]) {
                    rotate_extrude(convexity=10) {
                      handleProfile(Hand_Hole_Depth);
                    }
                  }
                }
              }
            }
          }
        }
      }

      // handle hole
      union() {
        r = min(Handle_Material_Thickness / 2, Hand_Hole_Depth, Hand_Hole_Width / 2);

        handHoleCorner(r);

        translate([0, 0, -0.5]) {
          linear_extrude(height = Hand_Hole_Depth - r + 0.5, convexity = 10) {
            projection() {
              handHoleCorner(r);
            }
          }
        }

        translate([(Hand_Hole_Width / 2) - r, 0, Hand_Hole_Depth - r]) {
          rotate([0, -90, 0]) {
            translate([-((Hand_Hole_Width / 2) - r), 0, 0]) {
              linear_extrude(height = (Hand_Hole_Width / 2) - r  + 0.5, convexity = 10) {
                projection() {
                  handHoleCorner(r);
                }
              }
            }
          }
        }

        translate([-0.5, -0.5, -0.5]) {
          cube([(Hand_Hole_Width / 2) - r  + 0.5, Handle_Height + 1, Hand_Hole_Depth - r + 0.5]);
        }
      }

      // screw hole
      translate([Screw_Distance / 2, Handle_Height / 2, 0]) {
        if (Screw_Direction == 0) {
            screwHole(Hand_Hole_Depth + Handle_Material_Thickness,
              Screw_Hole_Diameter,
              Screw_Head_Hole_Diameter,
              (Hand_Hole_Depth + Handle_Material_Thickness) - Screw_Material_Thickness,
              0,
              Screw_Countersink_Angle);
        }
        else if (Screw_Direction == 1) {
          translate([0, 0, -1]) {
            cylinder(d = Screw_Hole_Diameter, h = Screw_Hole_Depth + 1);
          }
        }
      }
    }
  }

  module screwHole(holeDepth, holeDiameter, headDiameter, boreDepth, aboveHoleBoreDepth, sinkAngle) {
    boreDiameter = (holeDiameter > 0 ? max(holeDiameter, headDiameter) : 0);
    countersinkAdjacent = (boreDiameter / 2) / tan(sinkAngle / 2);

    translate([0, 0, -0.001]) {
      // screw hole
      cylinder(holeDepth + 0.002, holeDiameter / 2, holeDiameter / 2, false);

      // countersink
      if (sinkAngle > 0) {
        translate([0, 0, holeDepth - countersinkAdjacent - boreDepth]) {
          cylinder(countersinkAdjacent + 0.002, 0, (boreDiameter / 2), false);
        }

        // above hole and bore
        translate([0, 0, holeDepth - boreDepth]) {
          cylinder(boreDepth + aboveHoleBoreDepth + 0.002, boreDiameter / 2, boreDiameter / 2, false);
        }
      } else {
        // full bore
        cylinder(holeDepth + aboveHoleBoreDepth + 0.002, boreDiameter / 2, boreDiameter / 2, false);
      }
    }
  }

  module handHoleCorner(r) {
    translate([(Hand_Hole_Width / 2) - r, -0.5, Hand_Hole_Depth - r]) {
      // corner
      rotate([-90, 0, 0]) {
        cylinder(r = r + 0.01, h = Handle_Height + 1);
      }

      // bevel
      translate([0, 0.5, 0]) {
        rotate([90, -90, 180]) {
          innerBevel(r);
        }

        translate([0, Handle_Height, 0]) {
          rotate([90, 0, 0]) {
            innerBevel(r);
          }
        }
      }
    }
  }

  module innerBevel(r) {
    translate([0, 0, -1]) {
      cylinder(r = r + Bevel_Radius, h = 1);
    }

    cylinder(r = r, h = Bevel_Radius);

    rotate_extrude(convexity=10) {
      translate([r, 0, 0]) {
        difference() {
          polygon([
            [0, 0],

            [0, Bevel_Radius],

            [Bevel_Radius, 0],
          ]);

          if (Bevel_Rounded) {
            translate([Bevel_Radius, Bevel_Radius, 0]) {
              intersection() {
                circle(r=Bevel_Radius);

                translate([-Bevel_Radius, -Bevel_Radius, 0]) {
                  square([Bevel_Radius, Bevel_Radius]);
                }
              }
            }
          }
        }
      }
    }
  }

  /**
   * xTrim - Amount to trim from 'flat' end
   */
  module handleProfile(xTrim) {
    translate([0, Handle_Height / 2, 0]) {
      handleHalfProfile(xTrim);
      mirror([0, 1, 0]) {
        handleHalfProfile(xTrim);
      }
    }
  }

  module handleHalfProfile(xTrim) {
    xLen = Hand_Hole_Depth + Handle_Material_Thickness;

    polygon([
      [0, 0],

      [0, Handle_Height / 2],

      [xLen - xTrim - Bevel_Radius, Handle_Height / 2],
      [xLen - xTrim, (Handle_Height / 2) - Bevel_Radius],

      [xLen - xTrim, 0],
    ]);

    translate([xLen - xTrim - Bevel_Radius, (Handle_Height / 2) - Bevel_Radius, 0]) {
      if (Bevel_Rounded) {
        intersection() {
          square([Bevel_Radius, Bevel_Radius]);
          circle(r = Bevel_Radius);
        }
      }
    }
  }
}

handle();

```


[User]
Hey, I'm looking for an OpenSCAD design for a customizable battery dispenser, and I've seen a few good concepts, but they're usually limited to a specific battery type or require a lot of tweaking for others. I'd really like something that can handle a variety of cylindrical batteries, and be easily expanded.

Essentially, the design should have a base unit that holds the batteries, and then extensions that can stack on top. It's important that the front face of the base and all extensions align, so they can all stand flush against a wall. I'm not worried about getting the highest density storage, I'm more concerned with easy access and removing jams, so a bin-style system is fine as long as it's easy to reach in and clear any blockages.

I need to be able to specify either a standard battery size from a preset list (like AA, AAA, AAAA, C, D, 9V, 18650), or provide custom dimensions for a length and diameter. There should also be a label area on the front, preferably something that can dynamically update with the selected or custom battery type.

Here are a few important features that I want included:
*   **Base & Extension**: The design should have two parts, a base, and extension.
*   **Parametric Battery Size**: I need to be able to select from preset battery sizes (AA, AAA, AAAA, C, D, 9v, 18650). Also, the option to input a custom length and diameter should exist.
*   **Stackable Extensions:**  The extensions should stack vertically on the base and each other.
*   **Aligned Front Face**: The front of both the base and extension should have equal depth. This way they can all align against a wall.
*   **Bin-Style Storage:** Rather than tracks, the batteries should sit in a bin.
*   **Clear Jam Access:** A cutout or slot in the front that allows a finger to remove any jams.
*   **Dynamic Label:** The label on the front face should display the selected or custom battery type.

I'd like the design to include the following parameters:

*   `part` - String to select either "base" or "extension"
*   `battery` -  String to select the standard battery, (e.g. "AA", "AAA", "AAAA", "C", "D", "9v", "18650"). Should default to "AAA".
*   `customLabel` -  String for the label on the face when using a custom size.
*   `customBatteryLength` - Custom length of the battery in mm.
*   `customBatteryDiameter` - Custom diameter of the battery in mm.

I think I can handle any additional modifications I might need on my end, so those are the most important. And it would be great if you could provide all of the code in one go, including any required libraries. I do prefer that each module be in its own module for readability. Thanks!

[Assistant]
Customizable_Battery_Dispenser.scad:
```

/* [Part] */
part = "base"; // [base:Base,extension:Extension]

/* [Standard Sizes] */

// sizes for preset standard batteries. Chose custom if you want to create a new one.
battery = "AAA"; // [AA,AAA,AAAA,C,D,9v,18650]

/* [Custom Size] */

// the name of the battery, and the text that will appear on the face.
customLabel = "";

// the length of the battery in mm, including the positive nub.
customBatteryLength = 0;

// the diameter of the battery in mm. For rectangular, use the narrowest dimension.
customBatteryDiameter = 0;

batteries = [
    ["AA", 52, 15],
    ["AAA", 45, 11],
    ["AAAA", 43, 9],
    ["C", 50, 26],
    ["D", 61, 34],
    ["9v", 48, 17],
    ["18650", 69, 19]
];

/*[Hidden]*/
$fn=50;
useCustom = (customBatteryLength != 0 && customBatteryDiameter != 0);
index = search([battery], batteries, num_returns_per_match = 1);
standardValues = batteries[index[0]];
echo(standardValues);
label = useCustom ? customLabel : battery;
batteryLength = useCustom ? customBatteryLength : standardValues[1];
batteryDiameter = useCustom ? customBatteryDiameter : standardValues[2];

// constants
wallThickness=2;
wallHeight=108;
wallWidth=63;
shelfWidth=20;
slotWidth=16;
shelfStopHeight=14;
kickbackWidth = 6;
kickbackHeight = 10;

//draw model
translate([-batteryLength/2,wallWidth/2,0])
rotate([0,0,-90])
if (part == "base") {
    baseModel();
} else {
    extensionModel();
}

module baseModel() {
    sides();
    back();
    shelf();
    curve();
    kickbacks();
    difference() {
        front();
        label();
    }
}

module extensionModel() {
    difference() {
        translate([0,-wallThickness,0])
            cube([wallWidth,batteryLength + wallThickness * 2,wallHeight]);

        translate([wallThickness,0,-10])
            cube([wallWidth - wallThickness * 2,batteryLength,wallHeight + 20]);

        slotCutout();
    }

    tabWidth = 10;
    translate([0, 0, wallHeight - tabWidth/2])
        tab();
    translate([0,batteryLength - tabWidth, wallHeight - tabWidth/2])
        tab();
    translate([wallWidth, 0, wallHeight - tabWidth/2])
        mirror([1,0,0]) tab();
    translate([wallWidth,batteryLength - tabWidth, wallHeight - tabWidth/2])
        mirror([1,0,0]) tab();
}

module tab() {
    tabWidth = 10;
    translate([wallThickness, 0, 0])
        cube([wallThickness, tabWidth, tabWidth]);
    cube([wallThickness * 2, tabWidth, tabWidth / 2]);
}

module sides() {
    translate([0,-wallThickness,0]) side();
    translate([0,batteryLength,0]) side();
}

module side() {

    cutoutDiameter = shelfWidth * 2/3 + .5;
    bevel = 5;

    translate([0, wallThickness, 0])
        rotate([90, 0, 0])
            linear_extrude(height=wallThickness)
                offset(-bevel) offset(bevel)
                    polygon([
                        [0,0],
                        [0, wallHeight],
                        [wallWidth, wallHeight],
                        [wallWidth, batteryDiameter],
                        [wallWidth + 10, shelfStopHeight - cutoutDiameter / 2 + 1],
                        [wallWidth + shelfWidth - 4, shelfStopHeight - cutoutDiameter / 2 + 1],
                        [wallWidth + shelfWidth, shelfStopHeight],
                        [wallWidth + shelfWidth + wallThickness, shelfStopHeight],
                        [wallWidth + shelfWidth + wallThickness, 0],
                    ]);

}

module back() {
    cube([wallThickness,batteryLength,wallHeight]);
}

module front() {

    difference() {
        translate([wallWidth - wallThickness, 0, batteryDiameter + wallThickness])
            cube([wallThickness,batteryLength,wallHeight- batteryDiameter - wallThickness]);

        slotCutout();

        angleCutout();
    }
}

module slotCutout() {
    union() {
        translate([wallWidth, batteryLength / 2, wallHeight - slotWidth])
            rotate([0, 90, 0])
                cylinder(h=10, d=slotWidth, center=true);

        translate([wallWidth - 5, batteryLength / 2 - slotWidth / 2, slotWidth])
            cube([10, slotWidth, wallHeight - slotWidth * 2]);

        translate([wallWidth, batteryLength / 2, slotWidth])
            rotate([0, 90, 0])
                cylinder(h=10, d=slotWidth, center=true);
    }
}

module angleCutout() {
    translate([wallWidth - wallThickness - 1, 0,batteryDiameter])
        rotate([90,0,90])
            linear_extrude(height=wallThickness + 2)
                    polygon([
                        [0, 0],
                        [0, wallThickness],
                        [batteryLength / 2 - slotWidth / 2, batteryDiameter],
                        [batteryLength / 2 + slotWidth / 2, batteryDiameter],
                        [batteryLength , wallThickness],
                        [batteryLength , 0],
                    ]);
}

module shelf() {
    length = wallWidth + shelfWidth;

    // floor
    difference() {
        cube([length + wallThickness, batteryLength, wallThickness]);

        translate([length + wallThickness, batteryLength / 2, 0])
            cylinder(h=200, d=slotWidth, center=true);
    };

    // stops
    union() {
        // left
        translate([length, -wallThickness, 0])
            shelfStop();;

        //right
        translate([length, batteryLength + wallThickness, 0])
            mirror([0,1,0])
                shelfStop();
    }
}

module shelfStop() {

    width = batteryLength / 2 - slotWidth/2 + wallThickness;
    bevel = wallThickness * 2;

    rotate([90, 0, 90])
        linear_extrude(height=wallThickness)
        offset(bevel) offset(-bevel)
            square([width, shelfStopHeight]);

    cube([wallThickness,width,wallThickness*2]);

    cube([wallThickness,wallThickness*2,shelfStopHeight]);
}

module curve() {
    diameter = wallWidth * 2;

    difference() {

        cube([wallWidth, batteryLength, wallWidth]);

        translate([diameter/2, -10, diameter/2])
            rotate([-90,0,0])
                cylinder(d=diameter, h=batteryLength + 20);
    }
}

module kickbacks() {
    kickback();

    translate([0, batteryLength,0])
        mirror([0, 1, 0])
            kickback();

}

module kickback() {

    translate([-wallThickness, 0, wallThickness])
        polyhedron(
            points=[
                [wallWidth, 0, batteryDiameter],
                [wallWidth, 0, batteryDiameter + kickbackHeight],
                [wallWidth - 6, 0, batteryDiameter + kickbackHeight - 3],
                [wallWidth, kickbackWidth, batteryDiameter + kickbackHeight],
                [wallWidth - 6, kickbackWidth, batteryDiameter + kickbackHeight - 3],
            ],
            faces=[
                [0,2,1],
                [0,1,3],
                [1,2,4,3],
                [0,3,4],
                [0,4,2]
            ]
        );

}

module label() {
    translate([wallWidth - wallThickness + 1, (batteryLength / 2 - slotWidth / 2) / 2 - wallThickness / 2, wallHeight - slotWidth / 2])
        rotate([90, 0, 90])
                linear_extrude(wallThickness + 1)
                    text(label, direction="ttb");
}

```


[User]
I'd like to design a parametric snowflake generator in OpenSCAD. I need it to create thin, flat snowflake designs suitable for printing as decals.

Here are the key features I'm looking for:

*   **Basic Structure:** The snowflake should be built from a central point with a specified number of radiating branches.
*   **Branches:** Each branch should have a main trunk extending from the center and then a set of smaller sub-branches at random locations along its length, angled at 60 degrees to either side.
*   **Parametric Control:** I need to be able to control the following parameters:
    *   `Line_width`: The thickness of the line segments making up the snowflake.
    *   `Thickness`: The overall thickness of the snowflake for printing, likely very thin.
    *   `Radius`: The distance from the center to the end of each main branch.
    *   `Branch_count`: The number of primary branches radiating from the center.
    *   `Subbranch_count`: The number of sub-branches along each primary branch.
    *   `Random_seed`: A seed value to control the random generation of sub-branch positions and lengths so that I can generate the same snowflake multiple times. Use zero to generate a random snowflake.
*   **Output:** The output should be a 3D model suitable for exporting to STL for 3D printing.

I'm looking for a design where the sub-branches are limited in length so they don't grow out too far. It should result in a "skinny" or delicate look.

It would also be great if the code generated the random numbers based on the `Random_seed` and used a consistent set of random numbers for each branch, so each branch is the same. I'd like to avoid non-symmetrical snowflakes, so the number of branches should be even.

[Assistant]
snowflake-gen.scad:
```
// Width of all line segments (X axis)
Line_width = 1;

// Thickness of the snowflake (Z axis)
Thickness = 0.25;

// Snowflake's radius
Radius = 30;

// Number of branches. Odd numbers produce non-symmetrical snowflakes.
Branch_count = 6;

// Number of sub-branches on each branch
Subbranch_count = 4;

// Same seed produces same snowflake every time (0 means "no seed", random snowflake)
Random_seed = 123;

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

module line_segment(width, length, thickness) {
    union() {
        cylinder(r=width/2, h=thickness);
        translate([0, length-width/2, 0]) {
            cylinder(r=width/2, h=thickness);
        };
        translate([-width/2, 0, 0]) {
            cube([width, length-width/2, thickness]);
        };
    };
};

/* Our simple snowflake consists of *Branch_count* identical branches,
   radiating from the center at equal angles.
   Each branch consists of a "trunk" of length *Radius*
   and *Subbranch_cout* sub-branches of random length
   located at random points along the trunk
   and angled at 60 degrees to both sides of the trunk.
*/

module branch(width, length, thickness, subbranch_count, rand) {
    sbs = [
        for (i = [0:subbranch_count-1])
            let(
                seg_len = length / subbranch_count,
                seg_start = seg_len * i,
                // Make sure sub-branches don't cluster too much
                // by distributing them along the trunk
                subbranch_point = seg_start + rand[i*2] * seg_len,
                // The overall "simple and skinny" look of the snowflake comes from
                // this *len_lim* variable, which prevents long sub-branches from
                // growing along the trunk. Changing this limit
                // is the easiest way to tweak the visual style
                len_lim = min(length - subbranch_point, length/subbranch_count),
                subbranch_length = rand[i*2+1] * len_lim)
            [subbranch_point, subbranch_length]
    ];

    union() {
        // The trunk
        line_segment(width, length, thickness);

        // Sub-branches on the left side of the trunk
        for (sb = sbs) translate([0, sb[0], 0]) {rotate([0, 0, 60]){line_segment(width, sb[1], thickness);};};

        // Sub-branches on the right side of the trunk
        for (sb = sbs) translate([0, sb[0], 0]) {rotate([0, 0, -60]){line_segment(width, sb[1], thickness);};};
    };
}

module snowflake(branch_count) {
    for (i = [0:branch_count-1])
        rotate([0, 0, 360/branch_count * i]) children(0);
}

// Pre-generate a pool of random numbers based on the seed
// and pass it into the branch generator function to make sure
// all branches are identical
rand = Random_seed == 0 ? rands(0, 1, Subbranch_count*2) : rands(0, 1, Subbranch_count*2, Random_seed);

// Draw one branch along each of the angles around the circle
snowflake(Branch_count) {
    branch(Line_width, Radius, Thickness, Subbranch_count, rand);
}
```


[User]
I'd like to design some parametric buttons, and I'm thinking something like a button factory. I want to be able to control the number of eyelets, the type of rim, the button dimensions, eyelet dimensions, and chamfer angles.

Specifically, I need parameters for:
*   **Number of Eyelets:** An integer from 1 to 50.
*   **Rim Type:** A selection between "round" or "straight".
*   **Button Radius:**  The radius of the button.
*   **Button Thickness:** The total thickness of the button.
*   **Eyelet Radius:** The radius of each eyelet.
*  **Eyelet Placement**: The distance from the center of the button to the center of the eyelets.
*   **Rim Thickness:** The thickness of the rim around the button.
*   **Recess Depth:** The depth of a recess on the top of the button (set to 0 for flat surface).
*   **Recess Chamfer Angle:** The angle of the chamfer on the recess.
*  **Base Chamfer Angle**: The angle of the chamfer on the base of the button.

I'd also want it to include some tolerances to avoid printing issues:
*   **Edge Clearance:** Minimum distance between the edge of the eyelet and the button edge.
*   **Eyelet Clearance:** Minimum distance between two eyelets.
*   **Minimum Base Thickness**: The minimum thickness of the button's base.
*   **Minimum Wall Thickness:**  A minimum wall thickness to ensure printability.

I'd like the OpenSCAD file to be well-commented so I can understand how it works. Could you also include some warnings to catch obvious problems, like eyelets being too close to each other or the button edge, or if the recess is too deep?  I'm hoping it can also handle calculations for the recess and base diameters based on the chamfer angles. I'm not planning to use any libraries for this.

[Assistant]
button_factory.scad:
```
/* Button Factory*/
//Amany Azevedo Amin 02/12/2020
//v0: facility for round buttons. Rims: rounded or straight. Eyelets: round, 1 to 50. Surfaces: chamfered or flat top and bottom.

/* [Button Type] */

eyelets=4; // [1:50]
rim_type="round"; //["round","straight"]

/* [Button Dimensions - mm] */

//button diameter
button_radius=6; // [1:200]
button_diameter=button_radius*2;

//button thickness
button_thickness=5; // [1:50]

//eyelet_radius
eyelet_radius=1; // [1:20]
eyelet_diameter=eyelet_radius*2;

//Distance of the centre of the eyelet from the centre of the button
eyelet_placement=5;  //[1:50]
ep=eyelet_placement;
et=sqrt((ep*ep)/2);

//rim thickness
rim_thickness=1;// [0:10]

// Recess depth (set to 0 for flat surface)
recess_depth=1; //[0:10]

// Recess chamfer angle
recess_chamfer_angle=60; // [0:90]

// Base chamfer angle
base_chamfer_angle=35; // [0:60]

/*[Tolerances - mm]*/

//Edge Clearance - Clearance between the eyelet edge and button edge
edge_clearance=1; //[0:10]

//Eyelet Clearance - Clearance between the eyelets
eyelet_clearance=1; //[0:10]

//Mibimum Base Thickness
min_base_clearance=1; //[0:10]

//Minimum Wall Thickness - With the application of chamfers and recesses, wall thickness may be unacceptable;
min_wall_tolerated=1; //[0:10]

//// Computed Dimensions
recess_outer_diameter=button_diameter-rim_thickness;

recess_inner_diameter=recess_outer_diameter-(recess_depth/tan(-recess_chamfer_angle-90));

base_diameter=button_diameter-((button_thickness)/tan(-base_chamfer_angle-90));

//// Warnings

if (recess_inner_diameter<0)
{
    echo("WARNING: chamfer angle not possible with set recess depth, decrease depth or increase angle");
    echo("Flat surface will be generated");
}

if (base_diameter<0)
{
    echo("WARNING: base chamfer angle not possible with set button thickness, decrease depth or angle");
}

if ((-eyelet_diameter+eyelet_placement*sin(360/(2*eyelets)))<=eyelet_clearance)
{
    echo("WARNING: low clearance between eyelets");
}

if ((ep+eyelet_diameter)>=button_diameter-rim_thickness/2-edge_clearance)
{
    echo("WARNING: low clearance between eyelets and edge");
}

if (recess_depth>(button_thickness-min_base_clearance))
{
    echo("WARNING: recess depth too high");
}

// This section calculates the wall thickness between the base of the recess and the outer wall
recess_excess=recess_depth*tan(recess_chamfer_angle);

if (rim_type=="round" && rim_thickness/2>recess_depth)
{
    base_cutout=tan(base_chamfer_angle)*recess_depth;
    min_wall_thickness=recess_excess+rim_thickness/2+sqrt(pow((rim_thickness/2),2)-pow(recess_depth,2));

    if ((min_wall_thickness)<min_wall_tolerated)
    {
        echo("WARNING: minimum wall thickess is too low. Try lowering chamfer angles or increasing rim thickness.");
    }

}

else
{
    recess_excess=recess_depth*tan(recess_chamfer_angle);
    min_wall_thickness=recess_excess+rim_thickness-(tan(base_chamfer_angle)*recess_depth);

    if ((min_wall_thickness)<min_wall_tolerated)
    {
        echo("WARNING: minimum wall thickess is too low. Try lowering chamfer angles or increasing rim thickness.");
    }
}

//// Model Generation

if(rim_type=="round")
{
    difference()
    {
        //create the button, then slice the top to add a torus as the rim
        button(eyelets,button_diameter,button_thickness,eyelet_diameter,eyelet_placement,base_diameter,recess_depth,recess_outer_diameter,recess_inner_diameter);
        translate([0,0,button_thickness-rim_thickness/2])
        {
            difference()
            {
                cylinder(rim_thickness/2,button_diameter,button_diameter, $fn = 64);
                cylinder(rim_thickness/2,button_diameter-rim_thickness/2,   button_diameter-rim_thickness/2, $fn = 64);
            }
        }
    }
    // add torus as a rim
    rotate_extrude(convexity = 10, $fn = 64)
    translate([button_diameter-rim_thickness/2, button_thickness-rim_thickness/2])
    circle(r = rim_thickness/2, $fn = 64);
}

else
{
    button(eyelets,button_diameter,button_thickness,eyelet_diameter,eyelet_placement,base_diameter,recess_depth,recess_outer_diameter,recess_inner_diameter);
}

//Creates the button
module button(eyelets,button_diameter,button_thickness,eyelet_diameter,eyelet_placement,base_diameter,recess_depth,recess_outer_diameter,recess_inner_diameter)
{
    difference()
    {
        cylinder(button_thickness,base_diameter,button_diameter, $fn = 64);
        // recess at the top of the button
        translate([0,0,button_thickness-recess_depth+0.001])
        {
            cylinder(recess_depth,recess_inner_diameter,recess_outer_diameter,$fn = 64);
        }

        // Creates the eyelets
        for (i =[1:eyelets])
        {
            translate([eyelet_placement*cos(i*360/eyelets),ep*sin(i*360/eyelets),-0.01]) cylinder(3*button_thickness,eyelet_diameter,eyelet_diameter,$fn = 64);
        }
    }
}

```


[User]
Hey there, I'm looking to create a parametric Christmas tree in OpenSCAD, something similar to the one described in the text I've included, but I need it to be fully parametric from the start. I'm not looking for an exact copy; I'd rather have something built from scratch, but based on the concepts.

Essentially, I want to be able to adjust the following:

*   **Overall height of the tree:** I need to be able to set a height for the entire tree.
*   **Base radius:** I want to control how wide the tree is at its base.
*   **Number of branch layers:** The tree should have multiple levels of branches, and I want to be able to specify how many.
*   **Number of branches per layer:** Each layer will have branches equally spaced around the tree, and I'd like to specify how many branches are on each layer.
*   **Rounded top:** I want a boolean toggle to control whether or not the top of the tree is rounded, to make it safer.
*   **Polygon resolution:** I need to control the number of fragments to use to make the polygons look smooth.

The tree is essentially a cone with "cutouts" for branches. These cutouts are made by extruding circles and twisting them around the cone. So, it's more of a stylized tree than an accurate depiction of a pine tree.

Also, It is really important that all the parameters be fully exposed, I need to have all of those available for customization in the customizer. I intend to print this in "vase mode".

Can you generate OpenSCAD code for this?

[Assistant]
tree.scad:
```
// The height of the tree
height = 160; // [20:500]

// The radius of the base
baseRadius = 80; // [20:500]

// The number of branch layers
numberOfLayers = 5; // [2:10]

// The number of branches per layer
numberOfPoints = 5; // [2:10]

// Whether to round off the top, to make it somewhat safer for kids
isRounded = 0; // [0:false, 1:true]

// Lower fragment numbers yield less polygons
fragmentNumber = 30; // [10:100]

module buildCone(height, baseRadius, rounded) {
    if(rounded) {
        factor = 24;
        difference() {
            minkowski() {
                cylinder(height-(3*baseRadius/factor), baseRadius-(baseRadius/factor), 0);
                sphere(baseRadius/factor);
            }
            translate([0,0,-baseRadius]) cube(baseRadius*2, center=true);
        }
    } else {
        cylinder(height, baseRadius, 0);
    }
}

module tree(height, baseRadius, points, layers, rounded) {
    correction = 1.6;
    angle = 36 * layers;
    difference() {
        difference() {
            cutoutRadius = baseRadius*(5/6);
            buildCone(height, baseRadius, rounded);

            for (i=[1:points])  {
                linear_extrude(height=height, scale=-1, twist=angle, slices=20)
                translate([baseRadius*correction*cos(i*(360/points)),baseRadius*correction*sin(i*(360/points)),height])
                circle(cutoutRadius);

                linear_extrude(height=height, scale=-1, twist=-angle, slices=20)
                translate([baseRadius*correction*cos(i*(360/points)),baseRadius*correction*sin(i*(360/points)),height])
                circle(cutoutRadius);
            }
        }
    }
}

tree(height, baseRadius, numberOfPoints, numberOfLayers, isRounded, $fn = fragmentNumber);
```


[User]
I'd like to create a customizable, flexible Christmas tree ornament. I need a design where the tree is made of a series of horizontal lines connected by a central spine, allowing it to flex. I also want to have a customizable star at the top, with options for it to be solid, outlined, or not included at all. Also, I want the trunk of the tree to also be made of similar horizontal line segments, but there should be a toggle for the trunk to be solid instead, if I wish. Finally, a stand that can attach to the top of a cubicle wall would be nice as an option. The whole thing should be parametric, so I can easily change dimensions like the width and height of the tree, the thickness, the line width, and so on.

Here's a breakdown of the features and parameters I need:

**Basic Parameters:**
*   `treeWidth`:  The total width of the tree.
*   `treeHeight`: The height of the tree, excluding the trunk and star.
*   `treeThickness`: The thickness (Z-height) of the entire model.
*   `trunkIsSolid`:  A toggle to make the trunk solid or with cut-outs. Options "yes" or "no".
*  `trunkWidth`: Width of the trunk.
*   `trunkHeight`: Height of the trunk extending below the tree.
*   `lineWidth`: Width of the horizontal lines making the tree and star outline.
*   `spineWidth`: Width of the center spine.
*   `starType`: Type of star: "solid", "outline", or "none".
*   `starRadius`: Outer radius of the star.
*   `numberPoints`: Number of points on the star.

**Cubicle Parameters:**
*   `addCubicleStand`:  A toggle to add a cubicle wall stand: "yes" or "no".
*   `cubicleWalltopWidth`: Width of the cubicle wall top part of the stand.
*   `cubicleWalltopHeight`: Height of the cubicle wall top part of the stand.
*   `cubicleStandLinewidth`: Width/thickness of the cubicle stand.

The tree should be a triangle, constructed in OpenSCAD, and I would want it to be placed on the X/Y plane with its tip pointing up in the Y axis. The trunk should be a simple rectangular prism below the triangle. The flexible spine should run up the center and connect to the trunk. The horizontal "branches" should be made by cutting away horizontal segments from the tree shape.

The star should be created with the given parameters. If "outline" is selected, then an inner shape will be subtracted.

The cubicle stand should be a shape that is wider than the trunk, with a gap the size of the cubicle wall, and with rounded ends.

Could you generate the OpenSCAD code for this?

[Assistant]
FlexibleChristmasTree-v1.0.scad:
```
/* Flexible Christmas Tree
   by Lyl3

Make a flexible abstract Christmas tree
This code is published at:
https://www.thingiverse.com/thing:4674730
licensed under the Creative Commons - Attribution - Share Alike license (CC BY-SA 3.0)

V0.1 - working code to make the tree and trunk
V0.2 - added code to make the star
V0.3 - added code for cubicle wall stand
V1.0 - ready for publication
*/

fudge = 0.01 + 0;
bigfudge = 0.1 + 0;
$fn = 50 +0;

/* [Basic Parameters] */

// Enter the width of the tree (mm).
treeWidth =  70; // [30:5:300]

// Enter the height of the tree (mm), not including the trunk and star.
treeHeight = 90; // [30:5:300]

// Enter the thickness (Z-height) of the tree (mm). This is also the thickness of all other parts.
treeThickness = 3; // [2:0.5:30]

// The trunk below the triangular part of the tree can be either solid or with cut-out sections like the main part of the tree.
trunkIsSolid = "yes"; // [yes,no]

// Enter the width of the trunk (mm).
trunkWidth =  10; // [3:100]

// Enter the height of the trunk that extends below the tree (mm).
trunkHeight = 12; // [4:50]

// Enter the line width (mm). This is the width of the horizontal lines that make the tree and trunk and the width of the lines making the star outline.
lineWidth = 2; // [1.2:0.1:4]

// Enter the width of the trunk spine (mm). This is the skinny part that flexes.
spineWidth = 0.8; // [0.4:0.1:1.2]

// Enter the type of star to add to the top of the tree.
starType = "outline"; // [solid,outline,none]

// Enter the outer radius of the star (mm).
starRadius = 10; // [4:1:50]

// Enter the number of points on the star.
numberPoints = 5; // [5:15]

/* [Cubicle Parameters] */

// Do you want a stand added to the base for attaching to the top of a cubicle wall?
addCubicleStand = "no"; // [yes,no]

// Enter the width of the cubicle wall top (mm).
cubicleWalltopWidth = 50; // [20:100]

// Enter the height of the cubicle wall top (mm).
cubicleWalltopHeight = 7; // [4:40]

// Enter the line width of the cubicle wall stand (mm).
cubicleStandLinewidth = 3; // [1:10]

difference() {
  union() {
    difference() {
      union() {
        // add the tree
        color("Green") scale([treeWidth,treeHeight,1]) translate([0, 0, treeThickness/2]) triangle(1, 1, treeThickness);
        // add the trunk
        color("SaddleBrown") translate([-trunkWidth/2, -trunkHeight, 0]) cube([trunkWidth,trunkHeight,treeThickness]);
      }
      // cut away the horizontal sections from the tree
      for(cutY=[lineWidth:lineWidth*2:treeHeight]) {
        translate([-treeWidth/2,cutY,-bigfudge]) cube([treeWidth, lineWidth, treeThickness+2*bigfudge]);
      }
      // cut away the horizontal sections from the trunk
      if (trunkIsSolid=="no") {
        for(cutY=[lineWidth:lineWidth*2:trunkHeight]) {
          translate([-treeWidth/2,-cutY,-bigfudge]) cube([treeWidth, lineWidth, treeThickness+2*2*bigfudge]);
        }
      }
    }
    // add the flexible spine
    color("Sienna")translate([-spineWidth/2, -trunkHeight, 0]) cube ([spineWidth,treeHeight+trunkHeight,treeThickness]);
    // add the star
    if (starType!="none") {
      color("Gold") translate([0,treeHeight+starRadius/2-lineWidth,0])
        star(nPoints=numberPoints, hgt=treeThickness, innerRadius=starRadius/2, outerRadius=starRadius);
    }
  }
  // hollow out the star
  if (starType=="outline") {
    translate([0,treeHeight+starRadius/2-lineWidth,-bigfudge/2])
        star(nPoints=numberPoints, hgt=treeThickness+bigfudge, innerRadius=(starRadius-2*lineWidth)/2, outerRadius=starRadius-2*lineWidth);
  }
  // cut away any extra spine and horizontal section at the bottom of the trunk
  if (trunkIsSolid=="no") {
    translate([-treeWidth/2,-trunkHeight-lineWidth,-bigfudge]) cube([treeWidth, lineWidth+(trunkHeight%(lineWidth*2)), treeThickness+2*2*bigfudge]);
  }
}
// add the cubicle wall stand
if (addCubicleStand=="yes") {
  color("silver") translate([0,-trunkHeight+(trunkIsSolid=="no"?(trunkHeight%(lineWidth*2)):0)-(cubicleWalltopHeight)/2-cubicleStandLinewidth+fudge,0]) linear_extrude (treeThickness) {
    difference() {
      minkowski() {
        square ([cubicleWalltopWidth,cubicleWalltopHeight],center=true);
        circle (cubicleStandLinewidth);
      }
      translate([0,-cubicleStandLinewidth/2,0]) square ([cubicleWalltopWidth,cubicleWalltopHeight+cubicleStandLinewidth],center=true);
    }
    translate([cubicleWalltopWidth/2, -(cubicleWalltopHeight+cubicleStandLinewidth)/2, 0]) scale([0.5,1,1]) circle(cubicleStandLinewidth/2);
    translate([-cubicleWalltopWidth/2, -(cubicleWalltopHeight+cubicleStandLinewidth)/2, 0]) scale([0.5,1,1])circle(cubicleStandLinewidth/2);
  }
}

/****
*
* Create a triangle with the middle of the base at the origin (0, 0, 0) and centered along the Y axis.
*
****/
 module triangle(width=1, height=1, depth=1) {
   angle = atan(height / (width / 2));
   difference() {
     translate(v = [ 0, height / 2, 0 ]) {
       cube(size = [ width, height, depth ], center = true);
     }
     translate(v = [ width / 2, 0, 0 ]) {
       rotate(a = [ 0, 0, 90 - angle ]) {
         translate(v = [ width / 2, height, 0 ]) {
           cube(size = [ width, height * 2, depth+2*bigfudge ], center = true);
         }
       }
     }
     translate(v = [ -width / 2, 0, 0 ]) {
       rotate(a = [ 0, 0, 270 + angle ]) {
         translate(v = [ -width / 2, height, 0 ]) {
           cube(size = [ width, height * 2, depth+2*bigfudge ], center = true);
         }
       }
     }
   }
 }

/****
*
* Create an N-pointed star centered around the origin
* with the bottom on the XY plane
* and the top point centered on the Y axis
*
****/
module star(nPoints=5, hgt=1, innerRadius=1, outerRadius=2) {
  originXY = [0.0, 0.0];
  rotate([0,0,90]) linear_extrude(hgt)
  union() {
    for (i=[0:nPoints-1]) {
      inner1 = [innerRadius*cos(-360*i/nPoints+360/(nPoints*2)), innerRadius*sin(-360*i/nPoints+360/(nPoints*2))];
      inner2 = [innerRadius*cos(-360*(i+1)/nPoints+360/(nPoints*2)), innerRadius*sin(-360*(i+1)/nPoints+360/(nPoints*2))];
      outer1 = [outerRadius*cos(-360*i/nPoints), outerRadius*sin(-360*i/nPoints)];
      polygon([ originXY, inner1, outer1, inner2]);
    }
  }
}
```


[User]
I'm looking to design a shower shaver holder that can be customized for different pole and shaver sizes. The design should have a ring that clamps around the shower pole and one or two hooks to hold a shaver. I want to be able to control various dimensions and angles through parameters.

Specifically, I need:

*   **Material Parameters:**
    *   `Material_Thickness`:  Adjustable thickness of the material.
    *   `Material_Height`: Adjustable height of the material.

*   **Pole Parameters:**
    *   `Pole_Diameter`: Adjustable diameter of the shower pole.
    *   `Pole_Gap_Angle`: Adjustable angle of the gap in the ring.

*   **Hook Parameters:**
    *   `Hook_Gap`: Adjustable width of the gap between the hooks.
    *   `Curved_Hook_Gap`: A boolean to choose whether to curve the hook gap or not.
    *   `Hook_Straight_length`: Adjustable length of the straight part of the hook before the curve.
    *   `Hook_End_Curve_Radius`: Adjustable radius of the curve at the end of the hook.
     *  `Hook_End_Curve_Angle`: Adjustable angle of the curve at the end of the hook.

*   **Dual Hook Parameters:**
    *   `Dual_Hooks`: A boolean to enable or disable a second hook.
    *   `Dual_Hooks_Offset_Angle`: Adjustable offset angle for the second hook (if enabled).

I'd like to have these as parameters in OpenSCAD so I can easily tweak them. I don't need any libraries, just plain OpenSCAD. The design should be a single file, and you can assume that all values will be in millimeters.

Also, the license should be as follows: The .scad file is licensed under the MIT License and the generated STLs should be licensed under the CC BY license.

[Assistant]
codeandmake.com_Shower_Shaver_Holder_v1.0.scad:
```
/*
 * Copyright 2020 Code and Make (codeandmake.com)
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */

/*
 * Shower Shaver Holder by Code and Make (https://codeandmake.com/)
 *
 * https://codeandmake.com/post/shower-shaver-holder
 *
 * Shower Shaver Holder v1.0 (5 December 2020)
 */

/* [Material] */

// Thickness of the material
Material_Thickness = 3; // [2:1:10]

// Height of the material
Material_Height = 10; // [5:1:50]

/* [Pole] */

// The diameter of the pole
Pole_Diameter = 21; // [0:0.1:180]

// The angle of the gap
Pole_Gap_Angle = 100; // [0:1:180]

/* [Hook] */

// Width of the gap between the hooks
Hook_Gap = 13.5; // [0:0.1:25]

// Curve the gap between the hooks
Curved_Hook_Gap = 1; // [0:false, 1:true]

// Length of the straight section of the
Hook_Straight_length = 0; // [0:1:50]

// Radius of the end curve
Hook_End_Curve_Radius = 25; // [0:1:90]

// Angle of the end curve
Hook_End_Curve_Angle = 25; // [0:1:90]

/* [Dual Hooks] */

// Add a second hook
Dual_Hooks = 0; // [0:false, 1:true]

// Offset angle of the hooks
Dual_Hooks_Offset_Angle = 160; // [90:1:180]

module showerShaverHolder() {
  $fn = 60;
  hookEndCurveRadius = max(Material_Height / 2, Hook_End_Curve_Radius);

  module hook() {
      translate([(Material_Thickness + Hook_Gap) / 2, -Hook_Straight_length - (Curved_Hook_Gap ? (Hook_Gap / 2) : 0) - (Material_Thickness + Pole_Diameter / 2), Material_Height / 2]) {
        rotate([0, 90, 180]) {
          translate([-hookEndCurveRadius , 0, -Material_Thickness / 2]) {
            rotate_extrude(angle = Hook_End_Curve_Angle, convexity=10) {
              translate([hookEndCurveRadius - (Material_Height / 2), 0, 0]) {
                square([Material_Height, Material_Thickness]);
              }
            }

            rotate([0, 0, Hook_End_Curve_Angle]) {
              translate([hookEndCurveRadius, 0, 0]) {
                cylinder(d = Material_Height, h = Material_Thickness);
              }
            }
          }
        }

        translate([-Material_Thickness / 2, 0, -Material_Height / 2]) {
          cube([Material_Thickness, Hook_Straight_length + (Curved_Hook_Gap ? (Hook_Gap / 2) : 0) + (Material_Thickness + Pole_Diameter / 2), Material_Height]);
        }
      }
  }

  module hookCutout() {
    translate([0, 0, -0.5]) {
      cylinder(d = Pole_Diameter + (Material_Thickness * 1.99), h = Material_Height + 1);
    }
  }

  module hooks() {
    difference() {
      union() {
        hook();

        mirror([1, 0, 0]) {
          hook();
        }

        difference() {
          rotate([0, 0, 180]) {
            translate([-Hook_Gap / 2, 0, 0]) {
              cube(size=[Hook_Gap, (Pole_Diameter / 2) + Material_Thickness + (Curved_Hook_Gap ? (Hook_Gap / 2) : 0), Material_Height]);
            }
          }

          if (Curved_Hook_Gap) {
            translate([0, -(Pole_Diameter / 2) - (Hook_Gap / 2) - Material_Thickness, - 0.5]) {
              cylinder(d = Hook_Gap, h = Material_Height + 1);
            }
          }
        }
      }

      hookCutout();
    }
  }

  module ring() {
    rotate([0, 0, 90 + (Pole_Gap_Angle / 2)]) {
      rotate_extrude(angle = 360 - Pole_Gap_Angle, convexity=10) {
        translate([Pole_Diameter / 2, 0, 0]) {
          square([Material_Thickness, Material_Height]);
        }
      }
    }

    rotate([0, 0, Pole_Gap_Angle / 2]) {
      translate([0, (Pole_Diameter + Material_Thickness) / 2, 0]) {
        cylinder(d = Material_Thickness, h = Material_Height);
      }
    }

    rotate([0, 0, -Pole_Gap_Angle / 2]) {
      translate([0, (Pole_Diameter + Material_Thickness) / 2, 0]) {
        cylinder(d = Material_Thickness, h = Material_Height);
      }
    }
  }

  ring();

  if (Dual_Hooks) {
    rotate([0, 0, Dual_Hooks_Offset_Angle / 2]) {
      hooks();
    }

    rotate([0, 0, -Dual_Hooks_Offset_Angle / 2]) {
      hooks();
    }
  } else {
    hooks();
  }
}

showerShaverHolder();

```


[User]
Hey, I'm looking to design a tool for removing watch backs, and I'd like your help generating the OpenSCAD files.  It'll have a base with six protrusions (lugs) that grip the watch back, a ring around those lugs to provide some additional structure, and a handle extending out to make it easier to grip and turn. Here are the specific parameters I'd like to be able to adjust:

*   `base_height`: The height of the base of the tool.
*   `lug_width`: The width of each lug.
*   `lug_height`: The height of each lug.
*   `lug_inner_diameter`: The inner diameter of the circle formed by the lugs.
*   `lug_outer_diameter`: The outer diameter of the circle formed by the lugs.
*   `ring_thickness`: The thickness of the ring around the base.
*   `handle_length`: The length of the handle.
*   `handle_width`: The width of the handle.

The base should be a hexagonal prism, and the lugs should protrude from one of the faces. There should be six equally spaced lugs. Each lug should be a rectangular prism. The ring should be a cylinder with a hole in it that surrounds the lugs, and the handle should be a rectangular prism extending from the edge of the base. I'd like the base to be centered at the origin, with the handle extending along the positive y-axis. I'd also like the base to be sized such that the six edges of the hexagon intersect the outer diameter of the lugs; there's a bit of a formula needed to size the base correctly. Can you create the scad file for this?

[Assistant]
watch_back_tool.scad:
```
// watch_back_tool.scad

echo(version=version());

base_height        = 5;
lug_width          = 1.75;
lug_height         = 1.5;
lug_inner_diameter = 31.78;
lug_outer_diameter = 36.4;
ring_thickness     = 2.5;
handle_length      = 30;
handle_width       = 10;

	lugs();
	base();
	ring();
	handle();

module handle(){
    translate([0,(handle_length/2)+(lug_outer_diameter/2+ring_thickness)*2/2,base_height/2])
    cube([handle_width,handle_length,base_height], center=true);
}

module lugs() {
	difference(){
	union(){
		translate([0,0,base_height+lug_height/2])
		cube([lug_outer_diameter, lug_width, lug_height], center=true);
		translate([0,0,base_height+lug_height/2])
		rotate([0,0,60])
		cube([lug_outer_diameter, lug_width, lug_height], center=true);
		translate([0,0,base_height+lug_height/2])
		rotate([0,0,120])
		cube([lug_outer_diameter, lug_width, lug_height], center=true);
	}
	translate([0,0,base_height-.01])
	cylinder(lug_height+1, lug_inner_diameter/2, lug_inner_diameter/2);
	}
  }

module base() {
	linear_extrude(height = base_height)
    polygon(ngon(6, (lug_outer_diameter/2+ring_thickness)*2/1.732));
  }

module ring() {
	translate([0,0,base_height-.01])
	difference(){
		cylinder(lug_height, lug_outer_diameter/2+ring_thickness, lug_outer_diameter/2+ring_thickness);
		cylinder(lug_height+1, lug_outer_diameter/2, lug_outer_diameter/2);
	}
}

// Simple list comprehension for creating N-gon vertices
function ngon(num, r) =
  [for (i=[0:num-1], a=i*360/num) [ r*cos(a), r*sin(a) ]];

```


[User]
I'd like to create a personalized Christmas bauble decoration, and I want to use OpenSCAD to generate the model. I need it to be parametric so I can adjust different features. I want to be able to specify the text, the font (including the option to use a system font), and control the text's size, spacing, position, and rotation, with options to add an underline and/or overline with customizable thickness and offset.

The bauble itself should be a ring shape with a specified diameter and material thickness. It also needs a hanger hole and attachment. I'd like to control the diameter of the hole.

I also want to be able to add stars around the text, controlling their number, offset, and both inner and outer rotations. The stars should also have a customizable number of points, outer point diameter, inner point diameter as a percentage of the outer diameter, and a percentage for how much of the star to cut out.

I need to be able to control the material thickness for each component individually (bauble, text, underline/overline, stars, hanger), using an offset from a base material thickness. I'd also like the option to add a priming block for multi-filament prints, where I can specify the diameter, offset (as a percentage of distance from the center), and rotation.

Please generate the necessary OpenSCAD files for me. I'm not using any specific OpenSCAD libraries, just the standard functionality, so I don't think you'll need to include any additional libraries.

[Assistant]
codeandmake.com_Personalised_Christmas_Bauble_Decoration_v1.2.scad:
```
/*
 * Copyright 2020 Code and Make (codeandmake.com)
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */

/*
 * Personalised Christmas Bauble Decoration by Code and Make (https://codeandmake.com/)
 *
 * https://codeandmake.com/post/personalised-christmas-bauble-decoration
 *
 * Personalised Christmas Bauble Decoration v1.2 (15 December 2020)
 */

/* [Text] */

// The text
Text = "Codey";

// The font
Font = "Liberation Sans:style=Bold"; // ["Liberation Sans":Liberation Sans, "Liberation Sans:style=Bold":Liberation Sans Bold, "Liberation Serif":Liberation Serif, "Liberation Serif:style=Bold":Liberation Serif Bold, "Liberation Mono":Liberation Mono, "Liberation Mono:style=Bold":Liberation Mono Bold, "other": Other - Enter font name below]

// Enter a font name below and select 'Other' (above) to use this font. For a full list of fonts see: Help > Font List in OpenSCAD.
Other_Font = "";

// Font size
Font_Size = 20; // [8:1:72]

// Letter spacing
Letter_Spacing = 0.79; // [0.5:0.01:1]

// Horizontal text offset
Text_H_Offset = -2; // [-100:1:100]

// Vertical text offset
Text_V_Offset = 0; // [-100:1:100]

// Text Rotation
Text_Rotation = 0; // [-180:1:180]

// Add text underline?
Text_Underline = 0; // [0:False, 1:True]

// Thickness of underline
Text_Underline_Thickness = 3; // [1:1:20]

// Underline offset
Text_Underline_Offset = -6; // [0:1:100]

// Add text overline?
Text_Overline = 0; // [0:False, 1:True]

// Thickness of overline
Text_Overline_Thickness = 3; // [1:1:20]

// Overline offset
Text_Overline_Offset = 6; // [0:1:100]

/* [Stars] */

// Number of stars
Stars = 2; // [0:1:10]

// Star offset
Star_Offset = 20; // [0:1:100]

// Outer rotation of stars
Star_Outer_Rotation = -27; // [-180:1:180]

// Inner rotation of stars
Star_Inner_Rotation = 30; // [-180:1:180]

// Number of star points
Star_Points = 5; // [4:1:8]

// Outer diameter of star points
Star_Outer_Point_Diameter = 15; // [5:1:50]

// Inner diameter of star points as percentage of outer diameter
Star_Inner_Point_Diameter_Percent = 50; // [10:1:100]

// Percentage of star to cut out
Star_Cutout_Percent = 50; // [0:1:100]

/* [Bauble] */

// Diameter of bauble
Bauble_Diameter = 78; // [0:1:150]

// Thickness of bauble material
Bauble_Thickness = 7; // [5:1:20]

// Rotation of bauble
Bauble_Rotation = 0; // [-180:1:180]

/* [Hanger] */

// Diameter of the hole
Hanger_Hole_Diameter = 8; // [5:1:20]

/* [Material] */

// Base material thickness
Material_Thickness = 3;

// Material thickness of bauble relative to Material_Thickness
Bauble_Material_Thickness_Offset = 0;

// Material thickness of text relative to Material_Thickness
Text_Material_Thickness_Offset = 1;

// Material thickness of text underline relative to Material_Thickness
Text_Underline_Material_Thickness_Offset = -2;

// Material thickness of text overline relative to Material_Thickness
Text_Overline_Material_Thickness_Offset = -2;

// Material thickness of stars relative to Material_Thickness
Star_Material_Thickness_Offset = -1;

// Material thickness of hanger relative to Material_Thickness
Hanger_Material_Thickness_Offset = -1;

/* [Other] */

// Add a priming block (for multi-filament prints)
Priming_Block = 0; // [0:False, 1:True]

// Diameter of priming block
Priming_Block_Diameter = 15; // [10:1:50]

// Priming block offset as percentage of distance from center
Priming_Block_Offset_Percent = 70; // [0:1:100]

// Rotation of priming block
Priming_Block_Rotation = 180; // [-180:1:180]

module personalisedChristmasBaubleDecoration() {
  $fn = 100;

  starInnerPointDiameter = Star_Outer_Point_Diameter * (Star_Inner_Point_Diameter_Percent / 100);
  starCutoutScale = Star_Cutout_Percent / 100;

  baubleMaterialHeight = max(Material_Thickness + Bauble_Material_Thickness_Offset, 1);
  textMaterialHeight = max(Material_Thickness + Text_Material_Thickness_Offset, 1);
  textUnderlineMaterialHeight = max(Material_Thickness + Text_Underline_Material_Thickness_Offset, 1);
  textOverlineMaterialHeight = max(Material_Thickness + Text_Overline_Material_Thickness_Offset, 1);
  starMaterialHeight = max(Material_Thickness + Star_Material_Thickness_Offset, 1);
  hangerMaterialHeight = max(Material_Thickness + Hanger_Material_Thickness_Offset, 1);
  primingBlockMaterialHeight = max(baubleMaterialHeight, textMaterialHeight, textUnderlineMaterialHeight,
    textOverlineMaterialHeight, starMaterialHeight, hangerMaterialHeight);

  module ring(od, id, h) {
    difference() {
      cylinder(d = od, h = h);
      translate([0, 0, -0.5]) {
        cylinder(d = id, h = h + 1);
      }
    }
  }

  module star(height) {
    angles = [ for (i = [0:(Star_Points * 2) - 1]) i * ( 360 / (Star_Points * 2)) ];
    coords=[ for (i = [0:(Star_Points * 2) - 1]) [(i % 2 == 0 ? Star_Outer_Point_Diameter : starInnerPointDiameter) * cos (angles[i]),
                              (i % 2 == 0 ? Star_Outer_Point_Diameter : starInnerPointDiameter) * sin (angles[i])] ];

    rotate([0, 0, 90]) {
      linear_extrude(height = height, convexity = 10) {
        polygon(points=coords);
      }
    }
  }

  module cutoutStar() {
    difference() {
      star(starMaterialHeight);

      translate([0, 0, -0.5]) {
        scale([starCutoutScale, starCutoutScale, 1]) {
          star(starMaterialHeight + 1);
        }
      }
    }
  }

  // bauble
  ring(Bauble_Diameter,  Bauble_Diameter - (Bauble_Thickness * 2), baubleMaterialHeight);

  // hanger
  translate([0, (Bauble_Diameter / 2) + (Hanger_Hole_Diameter / 2) + Bauble_Thickness, 0]) {
    ring(Hanger_Hole_Diameter + (Bauble_Thickness * 2), Hanger_Hole_Diameter, hangerMaterialHeight);
  }

  // hanger attachmment
  intersection() {
    hull() {
      translate([-((Hanger_Hole_Diameter + Bauble_Thickness) / 2), (Bauble_Diameter / 2), 0]) {
        cylinder(d = Bauble_Thickness, h = hangerMaterialHeight);
      }

      translate([((Hanger_Hole_Diameter + Bauble_Thickness) / 2), (Bauble_Diameter / 2), 0]) {
        cylinder(d = Bauble_Thickness, h = hangerMaterialHeight);
      }

      translate([-((Hanger_Hole_Diameter + Bauble_Thickness) / 2), 0, 0]) {
        cylinder(d = Bauble_Thickness, h = hangerMaterialHeight);
      }

      translate([((Hanger_Hole_Diameter + Bauble_Thickness) / 2), 0, 0]) {
        cylinder(d = Bauble_Thickness, h = hangerMaterialHeight);
      }
    }
    ring(Bauble_Diameter + (Bauble_Thickness * 4) + (Hanger_Hole_Diameter * 2),  Bauble_Diameter - (Bauble_Thickness * 2), hangerMaterialHeight);
  }

  rotate([0, 0, -Bauble_Rotation]) {
    // text
    rotate([0, 0, -Text_Rotation]) {
      translate([Text_H_Offset, Text_V_Offset, 0]) {
        linear_extrude(height = textMaterialHeight, convexity = 10) {
          text(text = Text, font = (Font == "other" ? Other_Font : Font), size = Font_Size, valign ="center", halign ="center", spacing = Letter_Spacing);
        }
      }

      if(Text_Underline || Text_Overline) {
        intersection() {
          translate([0, Text_V_Offset, 0]) {
            if (Text_Underline) {
                translate([- Bauble_Diameter / 2, (- Text_Underline_Thickness / 2 + Text_Underline_Offset), 0]) {
                  cube([Bauble_Diameter, Text_Underline_Thickness, textUnderlineMaterialHeight]);
                }
            }

            if (Text_Overline) {
                translate([- Bauble_Diameter / 2, (- Text_Overline_Thickness / 2 + Text_Overline_Offset), 0]) {
                  cube([Bauble_Diameter, Text_Overline_Thickness, textOverlineMaterialHeight]);
                }
            }
          }
          cylinder(d = Bauble_Diameter, h = max(textUnderlineMaterialHeight, textOverlineMaterialHeight));
        }
      }
    }

    // stars
    for(i = [0:Stars - 1]) {
      angle = (360 / Stars) * i;

      rotate([0, 0, angle + -Star_Outer_Rotation]) {
        translate([0, Star_Offset, 0]) {
          rotate([0, 0, -Star_Inner_Rotation]) {
            cutoutStar();
          }
        }
      }
    }
  }

  if(Priming_Block) {
    rotate([0, 0, -Priming_Block_Rotation]) {
      translate([0, ((Bauble_Diameter / 2) + (Bauble_Thickness * 2) + Hanger_Hole_Diameter + (Priming_Block_Diameter / 2) + 10) * (Priming_Block_Offset_Percent / 100), 0]) {
        cylinder(d = Priming_Block_Diameter, h = primingBlockMaterialHeight);
      }
    }
  }
}

personalisedChristmasBaubleDecoration();

```