[User]
Okay, I'm looking to create a customizable 3D printable Jack-o'-Lantern. I've seen some great designs out there, and I want something that's parametric so I can easily tweak it.

Here's what I'm hoping to accomplish:

**Overall Shape:**

*   I want two main pumpkin style options: an "8-bit" style built with rounded sections, and an "organic" style that's more rounded and lumpy. The user should be able to easily switch between these.

**Customizable Features (with dropdown options):**

*   **Eyes:**
    *   "None" (no eyes)
    *   "Oval Eyes"
    *   "Rectangular Eyes"
    *   "Round Eyes"
    *   "Square Eyes"
    *   "Triangular Eyes"
*   **Nose:**
    *   "None" (no nose)
    *   "Oval Nose"
    *   "Rectangular Nose"
    *   "Round Nose"
    *   "Square Nose"
    *   "Triangular Nose"
*   **Mouth:**
    *   "None" (no mouth)
    *   "Oval Mouth"
    *   "Rectangular Mouth"
    *   "Round Mouth"
    *   "Square Mouth"
    *   "Teeth" (a row of blocky teeth)
	*  "Triangular Mouth"
    *   "Underbite" (a protruding bottom "lip" with blocky teeth)
*   **Bottom Opening:**
    *   "Yes" (an open bottom for inserting lights)
    *   "No" (a closed bottom)

**General Requirements:**

*   The design should be relatively easy to print.
*   It should be able to have text "TNH" (The New Hobbyist) removed from the inside in the final version.
*   The code should be clean and well commented.
*   I would like to use the "write/Write.scad" library.

Let me know if you need more information. Thanks!

[Assistant]
Customizable_Jack-O-Lantern_TNH.scad:
```
// Customizable Jack-O-Lantern v1.2
// by TheNewHobbyist 2014 (http://thenewhobbyist.com)
// http://www.thingiverse.com/thing:162641
//
// I wanted to make a couple 3D printed Halloween dectorations.
// It seemed like a waste not to make to customizable as well.
//
// Change Log:		                                            ,_   .-.
//                                                              \ `\/ '`
// v1.0                                                    _.--"|  |"--._
// Initial Release                                       .' /  /`--`\  \ '.
//                                                      /  ;  /\    /\  ;  \
// v1.1                                                ;  |  /o_\  /o_\  |  ;
// ADDED additoinal some toothy                        |  |   |  /\  |   |  |
//     grins for ramai                                 ;  | /\; '--' ;/\ |  ;
//                                                      \  ;\ \/\/\/\/ /;  /
// v1.2                                                  '._\\_/\__/\_//_.'
// ADDED Kayla078's "organic" pumpkin design        jgs     `'--'--'--'`
// http://www.thingiverse.com/Kayla078
// http://www.thingiverse.com/thing:477836
//

/////////////////////////
//  Customizer Stuff  //
///////////////////////

/* [Happy Halloween!] */

pumpkin_style = "Organic"; // [8-Bit:8-Bit,Organic:Organic]
select_eyes = "None"; // [None:None,oval_eyes:Oval Eyes,rectangular_eyes:Rectangular Eyes,round_eyes:Round Eyes,square_eyes:Square Eyes,triangular_eyes:Triangular Eyes]
select_nose = "None"; // [None:None,oval_nose:Oval Nose,rectangular_nose:Rectangular Nose,round_nose:Round Nose,square_nose:Square Nose,triangular_nose:Triangular Nose]
select_mouth = "None"; // [None:None,oval_mouth:Oval Mouth,rectangular_mouth:Rectangular Mouth,round_mouth:Round Mouth,square_mouth:Square Mouth,teeth:Teeth,triangular_mouth:Triangular Mouth,underbite:Underbite]
// Leave the bottom open for lighting?
open_bottom = "yes"; // [yes:Yes,no:No]

/////////////////////////
// Beat it Customizer //
///////////////////////

/* [Hidden] */

use <write/Write.scad>
// preview[view:south, tilt:side]
$fn=32;

///////////////////////
// The Pumpkin Guts //
/////////////////////

module wall(rad1, rad2, height){
	translate([13,0,0]) cylinder(r1=rad1/2, r2=rad2/2, h=height, center=true);
}

module pumpkin(rad1, rad2, height){
	rotate([0,0,0]) wall(rad1, rad2, height);
	rotate([0,0,45]) wall(rad1, rad2, height);
	rotate([0,0,90]) wall(rad1, rad2, height);
	rotate([0,0,45*3]) wall(rad1, rad2, height);
	rotate([0,0,45*4]) wall(rad1, rad2, height);
	rotate([0,0,45*5]) wall(rad1, rad2, height);
	rotate([0,0,45*6]) wall(rad1, rad2, height);
	rotate([0,0,45*7]) wall(rad1, rad2, height);
}

module full_pumpkin(){
	pumpkin(10.9,13.1, 2);
	cylinder(r=10, h=2, center=true);
	translate([0,0,2]) pumpkin(13.1,17.1, 2);
	translate([0,0,2*2]) pumpkin(17.1,22.2, 2);
	translate([0,0,2*3]) pumpkin(22.2,27.8, 2);
	translate([0,0,2*4]) pumpkin(27.8,32, 2);
	translate([0,0,2*5]) pumpkin(32,33.6, 2);
	translate([0,0,2*6]) pumpkin(33.6,33.9, 2);
	translate([0,0,2*7+15]) pumpkin(33.9,33.9, 34);
	translate([0,0,2*23.5]) pumpkin(33.9,30.5, 2);
	translate([0,0,2*24.5]) pumpkin(30.5,24.7, 2);
	translate([0,0,2*25.5]) pumpkin(24.7,19.8, 2);
	translate([0,0,2*26.5]) pumpkin(19.8,15.8, 2);
	translate([0,0,2*27+.5]) pumpkin(15.8,7, 1);
}

module hollow_pumpkin(){
	union(){
		color("Brown") translate([0,0,2*27.2]) cylinder(r1=2,r2=3, h=10, center=true);
		difference(){
			color("Orange") full_pumpkin();
			translate([0,0,25]) sphere(r=25);
			translate([0,-15,-1]) rotate([0,0,180]) write("T",h=4,t=2,font="write/orbitron.dxf", space=1, center=true);
			rotate([0,0,45]) translate([0,-15,-1]) rotate([0,180,0]) write("N",h=4,t=2,font="write/orbitron.dxf", space=1, center=true);
			rotate([0,0,90]) translate([0,-15,-1]) write("H",h=4,t=2,font="write/orbitron.dxf", space=1, center=true);
		}
	}
}

module bottom(){
	if (open_bottom == "yes"){
		cylinder(r=12, h=10, center=true);
		translate([0,20,0]) rotate([90,0,0]) cylinder(r=2, h=20, center=true);
	}
}

module eyes(){
	if (select_eyes == "oval_eyes"){
		translate([-10,-25,38]) scale([1.4,1.2,.9]) rotate([90,0,0]) cylinder(r=5, h=30, center=true);
		translate([10,-25,38]) scale([1.4,1.2,.9]) rotate([90,0,0]) cylinder(r=5, h=30, center=true);
	}
	else if (select_eyes == "rectangular_eyes"){
		translate([-10,-25,38]) cube([15, 40, 8], center=true);
		translate([10,-25,38]) cube([15, 40, 8], center=true);
	}
	else if (select_eyes == "round_eyes"){
		translate([10,-20,38]) rotate([90,0,0]) cylinder(r=5, h=25, center=true);
		translate([-10,-20,38]) rotate([90,0,0]) cylinder(r=5, h=25, center=true);
	}
	else if (select_eyes == "square_eyes"){
		translate([10,-20,38]) cube([10, 25, 10], center=true);
		translate([-10,-20,38]) cube([10, 25, 10], center=true);
	}
	else if (select_eyes == "triangular_eyes"){
		translate([10,-20,38]) rotate([90,30,0]) cylinder(r=7, h=25, center=true, $fn=3);
		translate([-10,-20,38]) rotate([90,30,0]) cylinder(r=7, h=25, center=true, $fn=3);
	}
}

module nose(){
	if (select_nose == "oval_nose"){
		translate([0,-25,27]) scale([1,1.2,.7]) rotate([90,0,0]) cylinder(r=5, h=14, center=true);
	}
	else if (select_nose == "rectangular_nose"){
		translate([0,-25,27]) cube([10,17, 5], center=true);
	}
	else if (select_nose == "round_nose"){
		translate([0,-20,27]) rotate([90,0,0]) cylinder(r=4, h=28, center=true);
	}
	else if (select_nose == "square_nose"){
		translate([0,-20,27]) cube([6, 28, 6], center=true);
	}
	else if (select_nose == "triangular_nose"){
		translate([0,-20,27]) rotate([90,30,0]) cylinder(r=4, h=28, center=true, $fn=3);
	}
}

module mouth(){
	if (select_mouth == "oval_mouth"){
		translate([0,-25,15]) scale([2,1.2,1]) rotate([90,0,0]) cylinder(r=5, h=14, center=true);
	}
	else if (select_mouth == "round_mouth"){
		translate([0,-20,15]) rotate([90,0,0]) cylinder(r=5, h=25, center=true);
	}
	else if (select_mouth == "rectangular_mouth"){
		translate([0,-25,15]) cube([20, 15, 10], center=true);
	}
	else if (select_mouth == "square_mouth"){
		translate([0,-20,15]) cube([10, 25, 10], center=true);
	}
	else if (select_mouth == "teeth"){
		translate([-10,-20,15]) cube([4, 25, 5], center=true);
		translate([0,-20,15]) cube([4, 25, 5], center=true);
		translate([10,-20,15]) cube([4, 25, 5], center=true);
		translate([5,-20,20]) cube([4, 25, 5], center=true);
		translate([-5,-20,20]) cube([4, 25, 5], center=true);
		translate([-15,-20,20]) cube([4, 25, 5], center=true);
		translate([15,-20,20]) cube([4, 25, 5], center=true);

	}
	else if (select_mouth == "triangular_mouth"){
		translate([0,-20,16]) scale([2.2,1,.8]) rotate([90,-30,0]) cylinder(r=6, h=25, center=true, $fn=3);
	}
	else if (select_mouth == "underbite"){
		difference(){
			translate([0,-25,15]) scale([2.5,1.2,.8]) rotate([90,0,0]) cylinder(r=5, h=15, center=true);
			translate([0,-20,10]) cube([4, 20, 10], center=true);
			translate([6,-20,10]) cube([4, 20, 10], center=true);
			translate([-6,-20,10]) cube([4, 20, 10], center=true);
		}
	}
}

module organic_pumpkin(){
	color("orange") union() {
		scale([1.15, 1, 1.25]) translate([9, 0, 0]) sphere(r=20);
		scale([1.15, 1, 1.25]) translate([-9, 0, 0]) sphere(r=20);
	}

	color("orange") rotate([0,0,55]) scale([1.15, 1, 1.25]) translate([9, 0, 0]) sphere(r=20);
	color("orange") rotate([0,0,-50]) scale([1.15, 1, 1.25]) translate([9, 0, 0]) sphere(r=20);
	color("orange") rotate([0,0,-100]) scale([1.15, 1, 1.25]) translate([9, 0, 0]) sphere(r=20);
	color("orange") rotate([0,0,-80]) scale([1.15, 1, 1.25]) translate([-9, 0, 0]) sphere(r=20);
	color("orange") rotate([0,0,-35]) scale([1.15, 1, 1.25]) translate([-9, 0, 0]) sphere(r=20);
	color("orange") rotate([0,0,45]) scale([1.15, 1, 1.25]) translate([-9, 0, 0]) sphere(r=20);

	color("brown") linear_extrude(height = 32, convexity = 2, twist = -400)
	translate([1, -1, 0])
	circle(r = 3.5);
}

module organic_cutout(){
		union() {
		scale([1.15, 1, 1.25]) translate([9, 0, 0]) sphere(r=20);
		scale([1.15, 1, 1.25]) translate([-9, 0, 0]) sphere(r=20);
	}

	rotate([0,0,55]) scale([1.15, 1, 1.25]) translate([9, 0, 0]) sphere(r=20);
	rotate([0,0,-50]) scale([1.15, 1, 1.25]) translate([9, 0, 0]) sphere(r=20);
	rotate([0,0,-100]) scale([1.15, 1, 1.25]) translate([9, 0, 0]) sphere(r=20);
	rotate([0,0,-80]) scale([1.15, 1, 1.25]) translate([-9, 0, 0]) sphere(r=20);
	rotate([0,0,-35]) scale([1.15, 1, 1.25]) translate([-9, 0, 0]) sphere(r=20);
	rotate([0,0,45]) scale([1.15, 1, 1.25]) translate([-9, 0, 0]) sphere(r=20);

}

module organic_flat(){
	difference(){
		organic_pumpkin();
		translate([0,0,-34]) cube([100, 100, 20], center=true);
	}
}

module organic_hollow(){
	difference(){
		organic_cutout();
		translate([0,0,-30]) cube([100, 100, 20], center=true);
	}
}

////////////////////////
//          /))       //
//       __(((__      //
//    .' _`""`_`'.    //
//   /  /\\  /\\  \   //
//  |  /)_\\/)_\\  |  //
//  |  _  _()_  _  |  //
//  |  \\/\\/\\//  |  //
//   \  \/\/\/\/  /   //
//    '.___..___.'    //
//                    //
// Jackolantern Time! //
////////////////////////

if (pumpkin_style == "8-Bit"){
	union(){
		difference(){
			hollow_pumpkin();
			eyes(select_eyes);
			nose(select_nose);
			mouth(select_mouth);
			bottom(open_bottom);
		}
	}
}
else {
	difference(){
		translate([0,0,28]) organic_flat();
		scale(.85) translate([0,0,28]) organic_hollow();
		eyes(select_eyes);
		nose(select_nose);
		mouth(select_mouth);
		translate([0,0,4]) bottom(open_bottom);
	}
}

```


[User]
Okay, I'd like to design a parametric model of the Antilia building in Mumbai, similar to the existing one I found but with more flexibility and easier customization. I'm using OpenSCAD, and I'd like the design to be generated as a single parametric file.

Here's what I need:

**Core Structure:**

*   The building should generally follow the complex layered structure seen in the existing "antilia_A.scad" file. It has a core rectangular shape with several setbacks, some vertical tower-like elements (cylinders), and some cantilevered sections. I'm not looking for an *exact* replica, but I'd like the general form to be preserved.
*   The base of the building needs a large rectangular footprint. This is a primary dimension for the entire design.
*   There are distinct "wall" sections on the model. These should be constructed based on a polygon defined in the existing file, but I need a variable to allow changing the thickness.
*   The internal structure has various "building" sections which should be extruded rectangles with various heights.

**Parametric Features:**

*   **Overall Height:**  I need a `buildingHeight` variable to control the overall height of the entire model (like the existing `Height`).
*   **Base Dimensions:**  I'd like `baseWidth` and `baseDepth` variables to control the overall X and Y dimensions of the building's footprint.
*   **Layer Heights:** I need variables for height of various building sections, such as `layer1Height`, `layer2Height`, etc. or a list of such heights. These should allow me to adjust each level.
*   **Wall Thickness:** I need `wallThickness` variable to control the thickness of the walls, allowing for changes for different types of builds.
*   **Tower Diameters/Radii:** The cylindrical tower sections should be adjustable in radius and height, using variables like `towerRadius` and `towerHeight`.
*   **Setback Depths/Offsets:** Variables to control the setback or offset of each layer, such as `layer1SetbackDepth`, `layer2SetbackDepth`, etc.
*   **Column/Tower Placement:** If possible, I'd like to be able to adjust the number and/or spacing of the "tower" or "column" elements.
*   **Text Options:** I'd still like the ability to add text on the model like in the original. Instead of the individual Bottom/Top texts from the existing file, I'd like a more generic function that can add text to a specified face or region of the model with parameters for font and size.
*   **Output Options:** Similar to the existing model I'd like to have an output parameter that can change whether the building is output flat for printing or upright for pictures. `part = "ForPrinting"; // [ForPrinting,UprightForPics]`

**General Requirements:**

*   The code should be well-commented and easy to understand, using clear variable names.
*   I'm using the `write/Write.scad` library from the original file for text, so make sure to include that and call the necessary text functions within the parametric model. I would like to keep the ability to use the `writecube()` function.

Essentially, I'm looking for a more user-friendly and adaptable version of the Antilia model, where I can tweak the dimensions and features easily through parameters. Let me know if you need any clarification!

[Assistant]
antilia_A.scad:
```
//Select the way the STL should be rendered
part = "ForPrinting"; // [ForPrinting,UprightForPics]

//Choose a text or an empty string if not text is needed.
Bottom_Front_Text="";

//Choose a text or an empty string if not text is needed.
Top_Side_Text="";

//Choose a text or an empty string if not text is needed.
Top_Front_Text="";

//Height of the building in mm
Height=130;

/* [Hidden] */

/*
Antilia Building in Mumbai
Version A, May 2014
Written by MC Geisler (mcgenki at gmail dot com)

Antilia Building in Mumbai, roughly built after a photograph.
You can change/remove the default text using OpenSCAD.
Thanks go to Harlan Martin for the write library and to Victor Engmark (l0b0) for the inkscape to openSCAD converter.

Sorry for the use of some German in the openSCAD comments.

Have fun!

License: Attribution-NonCommercial-ShareAlike 4.0 International (CC BY-NC-SA 4.0)
You are free to:
    Share - copy and redistribute the material in any medium or format
    Adapt - remix, transform, and build upon the material
Under the following terms:
    Attribution - You must give appropriate credit, provide a link to the license, and indicate if changes were made.
    You may do so in any reasonable manner, but not in any way that suggests the licensor endorses you or your use.
    NonCommercial - You may not use the material for commercial purposes.
    ShareAlike - If you remix, transform, or build upon the material, you must distribute your contributions under the same license as the original.
*/

use <write/Write.scad>

// ----------------- Waende

fudge = 0.1;

//neu kein buckel
module poly_rect38017(h)
{
  scale([25.4/90, -25.4/90, 1]) union()
  {
    difference()
    {
       linear_extrude(height=h)
         polygon([[-77.803585,-410.270195],[-77.803585,-400.145195],[110.602615,-400.145195],[110.602615,-318.832695],[-77.803585,-318.832695],[-77.803585,-308.738945],[-77.803585,-273.645195],[-77.803585,-269.332695],[110.602615,-269.332695],[110.602615,-132.957695],[-130.397335,-132.957695],[-130.397335,-129.176445],[-131.334835,-129.176445],[-131.334835,-89.801445],[-130.397335,-89.801445],[-130.397335,-84.488945],[110.602615,-84.488945],[110.602615,3.917305],[-77.803585,3.917305],[-77.803585,9.698555],[-77.803585,14.011055],[-77.803585,102.386055],[-77.803585,110.729805],[-77.803585,112.511055],[110.602615,112.511055],[110.602615,202.354805],[110.602615,224.636055],[-126.772335,224.636055],[-126.772335,234.729805],[-126.772335,463.761055],[-126.772335,463.792305],[110.602615,463.792305],[115.165215,463.792305],[120.696415,463.792305],[120.696415,213.167305],[120.696415,202.354805],[120.696415,108.198555],[120.696415,102.386055],[-67.678585,102.386055],[-67.678585,14.011055],[120.696415,14.011055],[120.696415,3.917305],[120.696415,-88.770195],[120.696415,-94.582695],[-121.241085,-94.582695],[-121.241085,-122.863945],[120.696415,-122.863945],[120.696415,-132.957695],[120.696415,-274.145195],[120.696415,-279.457695],[-67.678585,-279.457695],[-67.678585,-308.738945],[110.602615,-308.738945],[120.696415,-308.738945],[120.696415,-318.832695],[120.696415,-405.207695],[120.696415,-410.270195],[-77.803585,-410.270195]]);
       translate([0, 0, -fudge])
         linear_extrude(height=h+2*fudge)
           polygon([[-116.678585,234.729805],[110.602615,234.729805],[110.602615,453.667305],[-116.678585,453.667305],[-116.678585,234.729805]]);
    }
  }
}

//alt (buckel hinten)
module poly_rect3801(h)
{
  scale([25.4/90, -25.4/90, 1]) union()
  {
    difference()
    {
       linear_extrude(height=h)
         polygon([[-77.792605,-410.268375],[-77.792605,-400.143375],[110.613645,-400.143375],[110.613645,-318.830875],[-77.792605,-318.830875],[-77.792605,-308.737125],[-77.792605,-273.643375],[-77.792605,-269.330875],[110.613645,-269.330875],[110.613645,-132.955875],[-130.386355,-132.955875],[-130.386355,-129.174625],[-131.323855,-129.174625],[-131.323855,-89.799625],[-130.386355,-89.799625],[-130.386355,-84.487125],[110.613645,-84.487125],[110.613645,3.919125],[-77.792605,3.919125],[-77.792605,9.700375],[-77.792605,14.012875],[-77.792605,102.387875],[-77.792605,110.731625],[-77.792605,112.512875],[110.613645,112.512875],[110.613645,224.637875],[-126.761355,224.637875],[-126.761355,234.731625],[-126.761355,463.762825],[-126.761355,463.794125],[133.332395,463.794125],[133.332395,453.669125],[133.332395,228.919125],[133.332395,224.637875],[120.707395,224.637875],[120.707395,108.200375],[120.707395,102.387875],[-67.667605,102.387875],[-67.667605,14.012875],[120.707395,14.012875],[120.707395,3.919125],[120.707395,-88.768375],[120.707395,-94.580875],[-121.230105,-94.580875],[-121.230105,-122.862125],[120.707395,-122.862125],[120.707395,-132.955875],[120.707395,-274.143375],[120.707395,-279.455875],[-67.667605,-279.455875],[-67.667605,-308.737125],[110.613645,-308.737125],[120.707395,-308.737125],[120.707395,-318.830875],[120.707395,-405.205875],[120.707395,-410.268375],[-77.792605,-410.268375]]);
       translate([0, 0, -fudge])
         linear_extrude(height=h+2*fudge)
           polygon([[-116.667605,234.731625],[123.238645,234.731625],[123.238645,453.669125],[-116.667605,453.669125],[-116.667605,234.731625]]);
    }
  }
}

// ---------------- GEBAEUDE

module poly_rect4597(h)
{
  scale([25.4/90, -25.4/90, 1]) union()
  {
    linear_extrude(height=h)
      polygon([[-136.370605,-463.660035],[136.370605,-463.660035],[136.370605,463.660035],[-136.370605,463.660035]]);
  }
}

module poly_rect38010761(h)
{
  scale([25.4/90, -25.4/90, 1]) union()
  {
    linear_extrude(height=h)
      polygon([[45.684905,44.510795],[112.108794,44.510795],[112.108794,14.052127],[45.684905,14.052127]]);
  }
}

module poly_rect3801076927(h)
{
  scale([25.4/90, -25.4/90, 1]) union()
  {
    linear_extrude(height=h)
      polygon([[-77.807975,-132.453495],[111.401285,-132.453495],[111.401285,-248.983595],[-77.807975,-248.983595]]);
  }
}

module poly_rect38010769279(h)
{
  scale([25.4/90, -25.4/90, 1]) union()
  {
    linear_extrude(height=h)
      polygon([[-54.057955,-248.167765],[110.865585,-248.167765],[110.865585,-269.697863],[-54.057955,-269.697863]]);
  }
}

module poly_rect380107692(h)
{
  scale([25.4/90, -25.4/90, 1]) union()
  {
    linear_extrude(height=h)
      polygon([[-0.307955,-55.667795],[110.687025,-55.667795],[110.687025,-84.340748],[-0.307955,-84.340748]]);
  }
}

module poly_rect380107692795(h)
{
  scale([25.4/90, -25.4/90, 1]) union()
  {
    linear_extrude(height=h)
      polygon([[-67.986515,-279.571515],[111.579875,-279.571515],[111.579875,-308.601613],[-67.986515,-308.601613]]);
  }
}

module poly_rect38010763(h)
{
  scale([25.4/90, -25.4/90, 1]) union()
  {
    linear_extrude(height=h)
      polygon([[-6.736515,225.225095],[111.044175,225.225095],[111.044175,111.909285],[-6.736515,111.909285]]);
  }
}

module poly_rect3801076923(h)
{
  scale([25.4/90, -25.4/90, 1]) union()
  {
    linear_extrude(height=h)
      polygon([[-121.379385,-94.239205],[111.758445,-94.239205],[111.758445,-122.912158],[-121.379385,-122.912158]]);
  }
}

module poly_rect380107634(h)
{
  scale([25.4/90, -25.4/90, 1]) union()
  {
    linear_extrude(height=h)
      polygon([[-116.915105,453.796515],[123.008445,453.796515],[123.008445,234.409275],[-116.915105,234.409275]]);
  }
}

module poly_rect380107638(h)
{
  scale([25.4/90, -25.4/90, 1]) union()
  {
    linear_extrude(height=h)
      polygon([[-66.200825,188.796505],[112.294155,188.796505],[112.294155,176.194980],[-66.200825,176.194980]]);
  }
}

module poly_rect380107(h)
{
  scale([25.4/90, -25.4/90, 1]) union()
  {
    linear_extrude(height=h)
      polygon([[-69.210325,104.332205],[112.133825,104.332205],[112.133825,73.873537],[-69.210325,73.873537]]);
  }
}

module poly_rect3801076(h)
{
  scale([25.4/90, -25.4/90, 1]) union()
  {
    linear_extrude(height=h)
      polygon([[4.934265,75.225095],[112.279315,75.225095],[112.279315,44.766427],[4.934265,44.766427]]);
  }
}

module poly_rect38010769(h)
{
  scale([25.4/90, -25.4/90, 1]) union()
  {
    linear_extrude(height=h)
      polygon([[-28.879365,4.153675],[112.115615,4.153675],[112.115615,-55.947849],[-28.879365,-55.947849]]);
  }
}

module poly_rect3801076927954(h)
{
  scale([25.4/90, -25.4/90, 1]) union()
  {
    linear_extrude(height=h)
      polygon([[24.334895,-318.703485],[110.686999,-318.703485],[110.686999,-399.876443],[24.334895,-399.876443]]);
  }
}

// ---------------- Saeulen
saeulenfaktor=2;

module cylYbig(x1,y1,x2,y2,x3,y3)
{
//	 linear_extrude(height=50)
//		polygon([[x1,y1],[x2,y2],[x3,y3]]);
rr=abs(x1-x3)/2;
hh = abs(y1-y2);
echo("r=",rr," h=",hh);
	translate([(x1+x3)/2,(y1+y2)/2])
		rotate([90,0,0])
			cylinder(r=rr*saeulenfaktor, h=hh , center = true);
	//cylinder(r = 5, h = 66, center = true);
}

module poly_rect4597(h)
{
  scale([25.4/90, -25.4/90, 1]) union()
  {
    linear_extrude(height=h)
      polygon([[-136.370605,-463.660035],[136.370605,-463.660035],[136.370605,463.660035],[-136.370605,463.660035]]);
  }
}

module poly_rect38019248(h)
{
//  scale([25.4/90, -25.4/90, 1])
  scale([25.4/90, -25.4/90, 25.4/90])
	union()
  {
//    linear_extrude(height=h)
//      polygon([[-33.789795,9.845265],[-33.789795,75.860524],[-23.688270,75.860524],[-23.688270,9.845265]]);
      cylYbig(-33.789795,9.845265,-33.789795,75.860524,-23.688270,75.860524);
  }
}

module cylrot(x1,y1,x2,y2,x3,y3)
{
//	 linear_extrude(height=50)
//		polygon([[x1,y1],[x2,y2],[x3,y3]]);
rr=5;
hh = abs(y1-y2);
echo("r=",rr," h=",hh);
	translate([(x1+x3)/2-50,(y1+y2)/2-25,0])
		rotate([90,0,0])
			cylinder(r=rr*saeulenfaktor, h=hh , center = true);
	//cylinder(r = 5, h = 66, center = true);
}
module poly_rect38019223(h)
{
//  scale([25.4/90, -25.4/90, 1])
  scale([25.4/90, -25.4/90, -25.4/90])
	union()
  {
//    linear_extrude(height=h)
//      polygon([[-73.432652,108.475767],[-32.718367,226.158544],[-22.616842,226.158544],[-63.331127,108.475767]]);
//  		rotate([27,0,0])
	translate([0,2,0])
  		rotate([0,0,-19])
			cylrot(-73.432652,99.475767,-32.718367,226.158544,-22.616842,226.158544);
	}
}

module poly_rect380192483(h)
{
  scale([25.4/90, -25.4/90,  1])
	union()
  {
    linear_extrude(height=h)
      polygon([[-33.075505,109.845265],[-33.075505,226.574815],[-22.973980,226.574815],[-22.973980,109.845265]]);
	}

}

module poly_rect380192483_2(h)
{
  scale([25.4/90, -25.4/90,  -25.4/90]) union()
  {
	translate([50,77,-10])
  		//rotate([0,0,+19])
			cylrot(-33.075505,88.845265,-33.075505,226.574815,-22.973980,226.574815);
  }
}
module poly_rect380192483_3(h)
{
  scale([25.4/90, -25.4/90,  -25.4/90]) union()
  {
	translate([50,25,-0])
  		//rotate([0,0,+19])
			cylrot(-33.075505,88.845265,-33.075505,226.574815,-22.973980,226.574815);
  }
}
module poly_rect380192232(h)
{
  scale([25.4/90, -25.4/90, -25.4/90]) union()
  {
//    linear_extrude(height=h)
//      polygon([[19.525955,108.475767],[-21.188331,226.158544],[-31.289856,226.158544],[9.424430,108.475767]]);
	translate([90,53,0])
  		rotate([0,0,+19])
			cylrot(19.525955,108.475767,-21.188331,226.158544,-31.289856,226.158544);
  }
}

module poly_rect3801922321(h)
{
  scale([25.4/90, -25.4/90, -25.4/90]) union()
  {
//    linear_extrude(height=h)
//      polygon([[5.495935,108.475767],[46.210221,226.158544],[56.311746,226.158544],[15.597460,108.475767]]);
	translate([4,35,0])
  		rotate([0,0,-19])
			cylrot(5.495935,98.475767,46.210221,226.158544,56.311746,226.158544);
  }
}

module poly_rect3801922326(h)
{
  scale([25.4/90, -25.4/90, -25.4/90]) union()
  {
    linear_extrude(height=h)
      polygon([[98.454605,108.475767],[57.740319,226.158544],[47.638794,226.158544],[88.353080,108.475767]]);
	translate([100,31,0])
  		rotate([0,0,+19])
			cylrot(98.454605,100.475767,57.740319,226.158544,47.638794,226.158544);
  }
}

module poly_rect38019245(h)
{
  scale([25.4/90, -25.4/90, -25.4/90])
	union()
  {
 //   linear_extrude(height=h)
//      polygon([[8.710205,9.130975],[8.710205,45.146234],[18.811730,45.146234],[18.811730,9.130975]]);
		cylYbig(8.710205,9.130975,8.710205,45.146234,18.811730,45.146234);
  }
}

module poly_rect380192488(h)
{
  scale([25.4/90, -25.4/90, -25.4/90])
	union()
  {
//    linear_extrude(height=h)
//      polygon([[-70.575515,-84.797585],[-70.575515,4.431961],[-60.473990,4.431961],[-60.473990,-84.797585]]);
  cylYbig(-70.575515,-84.797585,-70.575515,4.431961,-60.473990,4.431961);
	}
}

module poly_rect3801924883(h)
{
  scale([25.4/90, -25.4/90, -25.4/90]) union()
  {
//    linear_extrude(height=h)
//      polygon([[-67.718375,-401.047585],[-67.718375,-318.603753],[-57.616850,-318.603753],[-57.616850,-401.047585]]);
cylYbig(-67.718375,-401.047585,-67.718375,-318.603753,-57.616850,-318.603753);
  }
}

module poly_rect38019248831(h)
{
  scale([25.4/90, -25.4/90, -25.4/90]) union()
  {
//    linear_extrude(height=h)
//      polygon([[-30.575535,-400.511875],[-30.575535,-318.068043],[-20.474010,-318.068043],[-20.474010,-400.511875]]);
cylYbig(-30.575535,-400.511875,-30.575535,-318.068043,-20.474010,-318.068043);
  }
}

module poly_rect38019248832(h)
{
  scale([25.4/90, -25.4/90, -25.4/90]) union()
  {
//    linear_extrude(height=h)
//      polygon([[9.067345,-400.511875],[9.067345,-318.068043],[19.168870,-318.068043],[19.168870,-400.511875]]);
cylYbig(9.067345,-400.511875,9.067345,-318.06804,19.168870,-318.068043);
  }
}

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

module antilia()
{

BreiteWaende=70;
BreiteGebaeude=BreiteWaende*.9;
AbstandWaende=(BreiteWaende-BreiteGebaeude)/2;

BreiteSaeulen=0;

//Saeulen
module saeulengerade()
{
	poly_rect3801924883(BreiteSaeulen);
	poly_rect38019248831(BreiteSaeulen);
	poly_rect38019248832(BreiteSaeulen);

	poly_rect380192488(BreiteSaeulen);

	poly_rect38019248(BreiteSaeulen);
	poly_rect38019245(BreiteSaeulen);
}
module saeulenschraeg()
{
	poly_rect38019223(BreiteSaeulen);
	poly_rect380192232(BreiteSaeulen);
	poly_rect3801922321(BreiteSaeulen);
	poly_rect3801922326(BreiteSaeulen);

}
module saeulegeradeschraeg()
{
	//poly_rect380192483(BreiteSaeulen);
	poly_rect380192483_2(BreiteSaeulen);
}

for (i=[1,3,5])
{
	translate([0,0,BreiteWaende/6*i-BreiteSaeulen/2])
		saeulengerade();
}

for (i=[1,6,11])
{
	translate([0,0,BreiteWaende/12*i-BreiteSaeulen/2])
	{
		saeulenschraeg();
	}
}
winkel=19;
for (i=[6,11])
{
	translate([0,8,BreiteWaende/12*i-BreiteSaeulen/2-7])
	{
		rotate([winkel,0,0])
			poly_rect380192483_2();
	}
}
for (i=[1,6])
{
	translate([0,-6,BreiteWaende/12*i-BreiteSaeulen/2+9])
	{
		rotate([-winkel,0,0])
			poly_rect380192483_3();
	}
}

//Gebaeude
Topwidth=BreiteGebaeude/2;
Width2nd=BreiteGebaeude*.8;
Width3rd=BreiteGebaeude*.75;
WidthZwischen=BreiteGebaeude/5;

translate([0,0,AbstandWaende])
{//poly_rect4597(BreiteGebaeude);

	poly_rect3801076927954(BreiteGebaeude);
	translate ([-20,0,Topwidth/2])
			poly_rect3801076927954(Topwidth);

//to close gaps
translate([0,1,0])
{
	poly_rect3801076927954(BreiteGebaeude);
	translate ([-20,0,Topwidth/2])
			poly_rect3801076927954(Topwidth);
}
//to close gaps
translate([0,-1,0])
{
	poly_rect3801076927954(BreiteGebaeude);
	translate ([-20,0,Topwidth/2])
			poly_rect3801076927954(Topwidth);
}

	poly_rect380107692795(BreiteGebaeude);
//to close gaps
	translate ([0,1,0]) poly_rect380107692795(BreiteGebaeude);
	translate ([0,-1,0]) poly_rect380107692795(BreiteGebaeude);

	translate ([0,0,-(Width2nd-BreiteGebaeude)/2])
		poly_rect38010769279(Width2nd);
   poly_rect3801076927(BreiteGebaeude);
//to close gaps
	translate ([0,-1,0]) poly_rect3801076927(BreiteGebaeude);

	poly_rect3801076923(BreiteGebaeude);
//to close gaps
	translate ([0,-1,0]) poly_rect3801076923(BreiteGebaeude);
//to close gaps
	translate ([0,1,0]) poly_rect3801076923(BreiteGebaeude);

	translate ([0,0,-(Width2nd-BreiteGebaeude)/2])
		poly_rect380107692(Width2nd);
//to close gaps
	translate ([0,1,0])translate ([0,0,-(Width2nd-BreiteGebaeude)/2]) poly_rect380107692(Width2nd);
	translate ([0,-1,0])translate ([0,0,-(Width2nd-BreiteGebaeude)/2]) poly_rect380107692(Width2nd);
	poly_rect38010769(BreiteGebaeude);
//to close gaps
	translate ([0,-1,0])poly_rect38010769(BreiteGebaeude);

	translate ([0,0,-(Width2nd-BreiteGebaeude)/2])
		poly_rect38010761(Width2nd);
//to close gaps
	translate ([0,-2,0])translate ([0,0,-(Width2nd-BreiteGebaeude)/2]) poly_rect38010761(Width2nd);
	translate ([0,1,0])translate ([0,0,-(Width2nd-BreiteGebaeude)/2]) poly_rect38010761(Width2nd);
	poly_rect3801076(BreiteGebaeude);
//to close gaps
	translate ([0,-1,0]) poly_rect3801076(BreiteGebaeude);
	poly_rect380107(BreiteGebaeude);
//to close gaps
	translate ([0,-1,0]) poly_rect380107(BreiteGebaeude);

	translate ([0,0,-(Width3rd-BreiteGebaeude)/2])
		poly_rect38010763(Width3rd);

	translate ([0,0,WidthZwischen])
		poly_rect380107638(WidthZwischen); //zwischenschicht
	translate ([0,0,3*WidthZwischen])
		poly_rect380107638(WidthZwischen); //zwischenschicht

	translate ([-1,0,0])
	poly_rect380107634(BreiteGebaeude); //basis
}

//Waende
//alt:
//poly_rect3801(BreiteWaende);
//neu:
poly_rect38017(BreiteWaende);
}

module antilia_with_text()
{
	//rotate([0,90,90])
	difference()
	{
		//translate([0,0,30]) cube(200,center=true);
		union()
		{
			antilia();
		}
	#	writecube(Bottom_Front_Text,[-10,-100,38],0,face="left", t=60,h=24,space=1.5, rotate=-90, font="orbitron.dxf");
	#	writecube(Top_Side_Text,[5,54,4],0,face="bottom", t=10,h=15,space=1.5, rotate=180, font="orbitron.dxf");
	#	writecube(Top_Front_Text,[-20,54,38],0,face="left", t=10,h=18,space=1.5, rotate=-90, font="orbitron.dxf");
	}
}

//-------------------------
scalefactor=Height/246.68;

if (part == "ForPrinting")
{
	scale(scalefactor)
		rotate([0,90,0])
			antilia_with_text();
}

if (part == "UprightForPics")
{
	scale(scalefactor)
		rotate([90,0,90])
			antilia_with_text();
}

```


[User]
Okay, I've got a cool idea for a 3D printable structure, and I'd like you to help me design it in OpenSCAD.

It's based on a fractal pattern using hexagons. Imagine a main hexagon, and then each corner of that hexagon sprouts its own smaller hexagon, and then the corners of those sprout even smaller hexagons, and so on. It's a bit like a recursive structure, but I think we can handle the recursion manually in the code since OpenSCAD doesn't support it directly.

Here are the specifics:

1.  **Basic Structure:**
    *   The core element is a hexagon, and we'll need a module to generate this.
    *   We'll use a *linear_extrude* of a 2D hexagon to create the base hexagon shape with a specified height.
    *   Also, we'll need a module to generate a *hexcone*. A *hexcone* will be a hexagonal base that converges to a point. This cone shape will become smaller, and nested.
    *   A *hexconehole* module, which is based on the *hexcone* module, should create a hollowed hexcone that includes walls with adjustable thickness. The module should use a *difference()* operation to cut out the internal shape from the external. A simple *linear_extrude* of two rotated rectangles, and combined with the outer cone, should form the walls, allowing the user to specify a thickness of the walls.

2.  **Fractal Recursion (Manual):**
    *   We need to be able to define the depth of the fractal structure. Let's start with depths 1 to 4.
    *   A module called *hexconefractal*, will generate a single level of hexagonal 'branches' off of a base hexagon. It will contain a loop to place hexconehole structures in their appropriate positions.
    *   Modules *hexconefractal2*, *hexconefractal3*, and *hexconefractal4* will generate levels 2,3, and 4, respectively. These modules will all be based on the same underlying *hexconefractal* module. They will all call the module for the previous level in their main loop.
    *   A module called *hexconefractaln* will generate the model based on a user-specified level integer, using a conditional statement rather than recursion to call the appropriate fractal generator.
    *   Each new level of hexagons will be smaller than the last, and offset appropriately to create the fractal branching pattern.

3.  **Parameters:**
    *   `sidelength`: The length of the side of the root hexagon (adjustable, let's say between 1 and 100).
    *   `height`: The total height of the model (adjustable, let's also say between 1 and 100).
    *   `thickness`: The thickness of the walls of the hexcone (adjustable, let's say between 1 and 20).
    *   `level`:  The level of recursion depth (integer, 1-4).
    *   `tree_or_hex`: A toggle which constrains the model within the bounds of the root hexagon ("hex") or allows it to branch outwards as a "tree"
    *   `bottom`: A toggle indicating whether the fractal should have a hexcone bottom ("yes") or not ("no").

4.  **Constraints:**
    *   If the user specifies `tree_or_hex` as "hex" then the outer dimensions of the model should not extend beyond the boundaries of a hexagon.
    *   If the user specifies `bottom` as "no" then the base hexcone should be removed.

5. **Main Module:**
    * A main module, called *parseoptions* should be made. This module should parse all options and call the correct modules based on the options selected.

I'm not using any special libraries for this, so it should be fairly straightforward. The goal here is to create a parametric design so that I can tweak the dimensions, level of fractal branching, and overall shape. It would be great if the final code included comments.

Let me know if you need any clarification!

[Assistant]
honeycomb.scad:
```
// The length of the side of the root hexagon.
sidelength = 20; // [1:100]
//The total height of the model.
height = 30; // [1:100]
//The cross-sectional wall thickness.
thickness = 1; // [1:20]
//The level of recursion depth
level = 2;	// [1,2,3,4]
//Should this be a tree, or constrained to a hexagonal shape?
tree_or_hex = "tree"; // [tree,hex]
//Should the model have a hexagon cone bottom?
bottom = "yes"; // [yes,no]

module hex(s, height){
	linear_extrude(height = height)polygon( points=[[s/2,sqrt(3)/2*s],[s,0],[s/2,-sqrt(3)/2*s],[-s/2,-sqrt(3)/2*s],[-s,0],[-s/2,sqrt(3)/2*s]] );
}
module hexcone(s, h){
	polyhedron(
  		points=[[s/2,sqrt(3)/2*s,h],[s,0,h],[s/2,-sqrt(3)/2*s,h],[-s/2,-sqrt(3)/2*s,h],[-s,0,h],[-s/2,sqrt(3)/2*s,h],[0,0,0]],
  		triangles=[[0,6,1],[1,6,2],[2,6,3],[3,6,4], [4,6,5], [5,6,0]  ,      // each triangle side
              			[0,1,2],[0,2,3],[0,3,4],[0,4,5] ]                         // four triangles for hex base
	);
}

module hexconehole(s,h,thickness,walls=true){
	hdiff = h/(s*sqrt(3)/2)*thickness;
	difference(){
		union(){
			hexcone(s,h);
			if(walls){
				rotate(30)translate([-thickness/2/sqrt(3),-thickness/2,0])cube([s*sqrt(3)/2+thickness/2/sqrt(3),thickness,h]);
				rotate(150)translate([-thickness/2/sqrt(3),-thickness/2,0])cube([s*sqrt(3)/2+thickness/2/sqrt(3),thickness,h]);
			}
		}
		translate([0,0,hdiff])hexcone(s,h);
	}
}

module hexconefractal(sidelen,height,width,walls=true,bottom=true){
	bs = sidelen-width/sqrt(3);
	smalllen = (bs+width)/sqrt(3);
	smallheight = height/2;
	smallwidth = width;
	for (i=hexpoints){
		translate([0,0,height*1/2])rotate(30)translate([i[0]*bs,i[1]*bs,i[2]*bs])rotate(i[3])hexconehole(smalllen,smallheight,width);
	}
	if (bottom){
		hexconehole(sidelen,height/2,width);
	}
}

module hexconefractal2(sidelen,height,width,walls=true,bottom=true){
	bs = sidelen-width/sqrt(3);
	smalllen = (bs+width)/sqrt(3);
	smallheight = height/2;
	smallwidth = width;
	for (i=hexpoints){
		translate([0,0,height*1/2])rotate(30)translate([i[0]*bs,i[1]*bs,i[2]*bs])rotate(i[3])hexconefractal(smalllen,smallheight,width);
	}
	if (bottom){
		hexconehole(sidelen,height/2,width,walls);
	}
}

module hexconefractal3(sidelen,height,width,walls=true,bottom=true){
	bs = sidelen-width/sqrt(3);
	smalllen = (bs+width)/sqrt(3);
	smallheight = height/2;
	smallwidth = width;
	for (i=hexpoints){
		translate([0,0,height*1/2])rotate(30)translate([i[0]*bs,i[1]*bs,i[2]*bs])rotate(i[3])hexconefractal2(smalllen,smallheight,width);
	}
	if (bottom){
		hexconehole(sidelen,height/2,width,walls);
	}
}

module hexconefractal4(sidelen,height,width,walls=true,bottom=true){
	bs = sidelen-width/sqrt(3);
	smalllen = (bs+width)/sqrt(3);
	smallheight = height/2;
	smallwidth = width;
	for (i=hexpoints){
		translate([0,0,height*1/2])rotate(30)translate([i[0]*bs,i[1]*bs,i[2]*bs])rotate(i[3])hexconefractal3(smalllen,smallheight,width);
	}
	if (bottom){
		hexconehole(sidelen,height/2,width,walls);
	}
}

module hexconefractaln(sidelen,height,width,n,tree,walls=true,bottom=true){
	//manually unrolling the recursion because openscad doesn't support recursion.
	if(n==1){
		hexconefractal(sidelen,height,width,walls,bottom);
	}else if (n==2){
		hexconefractal2(sidelen,height,width,walls,bottom);
	}else if (n==3){
		hexconefractal3(sidelen,height,width,walls,bottom);
	}else if (n==4){
		hexconefractal4(sidelen,height,width,walls,bottom);
	}else{
		hexconefractal(sidelen,height,width,walls,bottom);
	}

}

module parseoptions(sidelen,height,width,n,tree,bottom){
	intersection(){
		if (bottom== "yes"){

			translate([0,0,height])rotate(180,[0,1,0])hexconefractaln(sidelen,height,width,n,tree,walls=false,bottom=true);
		} else {
			translate([0,0,-height/2])hexconefractaln(sidelen,height,width,n,tree,walls=false,bottom=false);
		}
		if(tree == "hex")
			hex(sidelen,height);

	}
}
hexpoints = [[sqrt(3)/2,1/2,0,120],[0,1,0,180],[-sqrt(3)/2,1/2,0,-120],[-sqrt(3)/2, -1/2,0,-60],[0,-1,0,0],[sqrt(3)/2, -1/2,0,60]];
parseoptions(sidelength,height,thickness,level,tree_or_hex,bottom);
```


[User]
Okay, I'm looking to create a customizable S-hook, but I want it to be really flexible. I need to be able to adjust the inner diameters of both rings individually. I'd also like to control the distance between the rings in a couple of ways: either by setting a specific manual distance, or by having them as close as possible given their sizes and ring thicknesses.

Speaking of thickness, I need to be able to control how thick the rings are as a percentage of the larger diameter. Basically, if I make the rings bigger they should be proportionally thicker.

Also, I want to have the option to make the hook into a "3" shape as well as an "S" shape. So basically the second ring would be on the same side as the first one when the hook is vertical.

Finally, it would be great if I could add vents to both rings. I need to be able to control their size as a percentage of the appropriate diameter (the first vent as a percentage of the larger diameter and the second as a percentage of the smaller diameter) and also their rotation angle. The second vent angle should be able to have its rotation relative to the hook when the shape is 'S' or '3'. It needs to be reflected along the vertical axis if the shape is an S shape and stay the same when the shape is a 3.

So, to recap, here are the parameters I want to control:

*   **Diameter 1:** Inner diameter of the first ring.
*   **Diameter 2:** Inner diameter of the second ring.
*   **Distance Type:** Option for either a manual distance or the closest distance between rings.
*   **Manual Distance:** Only used if the distance type is set to "Manual distance".
*   **Ring Strength:** Thickness of the rings as a percentage of the larger diameter.
*   **Shape:** Option for either an "S" shape or a "3" shape.
*   **Vent 1 Rotation:** Angle of rotation for the first vent.
*   **Vent 2 Rotation:** Angle of rotation for the second vent (needs to reflect if the shape is 'S' relative to a vertical axis).
*   **Vent 1 Strength:** Size of the first vent as a percentage of the larger diameter.
*  **Vent 2 Strength:** Size of the second vent as a percentage of the smaller diameter.

I'm looking for a single OpenSCAD file that handles all of this and I'm not using any libraries, so please don't use `use <>` or `include <>`. Thanks!

[Assistant]
highly-customizable-s-hook.scad:
```
// A highly customizable S-Hook
// http://6brueder.wordpress.com
// October 2013
// Public Domain - Creative Commons CC0 1.0

// Inner diameter of the first ring
diameter_1              = 20;	// [1:200]

// Inner diameter of the second ring
diameter_2              = 15;	// [1:200]

// Distance between both rings
distance_type           = 1;	// [1:Manual distance,2:Closest distance]

// Only be used when "Distance Type = Manual distance"
manual_distance         = 30;	// [1:300]

// Strength of the rings, % in relation to the larger diameter
ring_strength           = 25;	// [1:100]

shape                   = 1;	// [1:S-Shape,2:3-Shape]

/* [Vents] */
vent_1_rotation         = 0;	// [-90:45]
vent_2_rotation         = 45;	// [-90:45]

// Size of the first vent in % in relation to the larger diameter
vent_1_strength         = 66;	// [1:100]

// Size of the second vent in % in relation to the smaller diameter
vent_2_strength         = 66;	// [1:100]

// Calculations
large                   = diameter_1 > diameter_2 ? diameter_1 : diameter_2;
small                   = diameter_1 > diameter_2 ? diameter_2 : diameter_1;
ring_strength_normalized= ring_strength / 100;
global_height           = large * ring_strength_normalized;

// Distance
real_manual_distance    = manual_distance + diameter_1 / 2 + diameter_2 / 2;
closest_distance			= large / 2 + small / 2 + global_height;
distance_normalized     = distance_type == 1 ? real_manual_distance : closest_distance;

// Vents
vent_size_1             = large * (vent_1_strength / 100);
vent_size_2             = small * (vent_2_strength / 100);

shape_normalized        = shape;

vent_2_rotation_calc    = (shape_normalized == 1) ? (-vent_2_rotation + 180) : vent_2_rotation;

// Ring module
module ring(inner_diameter) {
    ring_size = inner_diameter * ring_strength_normalized;

    difference() {
        cylinder(h = global_height, r = (inner_diameter/2) + ring_size);
        translate([0,0,-0.1]) cylinder(h = global_height + 0.2, r = (inner_diameter/2));
    }
}

translate([-distance_normalized/2,0,0]) {
	difference() {
	    union() {
	        // First ring
	        ring(large);

	        // Second ring
	        translate ([distance_normalized,0,0]) ring(small);

	        difference() {
	            // Connection bar
	            translate([0,-global_height * 1.6/2,0]) cube([distance_normalized, global_height * 1.6, global_height]);

	            // The holes
	            union() {
	                translate([0,0,-0.1]) cylinder(h = global_height + 0.2, r = (large/2));
	                translate([distance_normalized,0,-0.1]) cylinder(h = global_height + 0.2, r = (small/2));
	            }
	        }
	    }

	    // Vents
	    union() {
	         rotate(-vent_1_rotation) translate([-vent_size_1/2,0,-0.1]) cube([vent_size_1, large/2 + global_height + 1, global_height + 0.2]);

	        translate ([distance_normalized,0,0]) {
	            rotate(vent_2_rotation_calc) translate([-vent_size_2/2,0,-0.1]) cube([vent_size_2, small/2 + global_height + 1, global_height + 0.2]);
	        }
	    }
	}
}

//preview[view:east,tilt:top]
$fn = 90;
```


[User]
Okay, I need a parametric OpenSCAD file for a simplified Minecraft Steve figure, designed for single-piece 3D printing.  I want to be able to easily customize it for a diorama.

Here's what I need:

**Core Design:**

*   **Single Piece:** The entire Steve figure should be designed to print as a single, connected piece. No separate head, arms, or legs that need to be assembled.
*   **Simplified Blocky Style:**  Maintain the blocky Minecraft aesthetic using cubes, but no cylinders.
*   **Feet for Orientation:** Steve should have clear "feet" so that it's obvious which way he's facing, adding a bit of depth to the base.
*   **Supports:**  I'll be trimming off the supports generated under the shoulders after printing, so the design needs to accommodate this.  I am okay with supports under the arms, so make sure they don't become a problem to print.

**Customization Parameters:**

*   **`scale` (Number):** A global scale factor to adjust the size of the entire figure.  A scale of 1 should be roughly the default size for a Steve model.
*   **`hturn` (Number):**  A rotation value in degrees around the Z-axis (vertical) to turn Steve's head.  The body should follow the head to a point. Limit this parameter to (-45, 45).
*   **`part` (String, Enum):**  A string parameter to choose between predefined poses.  Allowed values are:
    *   `"work"`:  Arms in a working position - one straight down, the other angled slightly forward and lower. Legs straight down (standing).
    *   `"run"`:  Arms angled forward and backward, and legs in a running stance.
    *   `"custom"`: Arms and legs are posed based on other parameters.
*    **`langle` (Number):** A custom angle value in degrees ( -45 to 45)  for the left arm, when `part` is set to "custom".  0 is straight down, positive values move forward, negative moves backward.
*    **`rangle` (Number):** A custom angle value in degrees ( -45 to 45)  for the right arm, when `part` is set to "custom".  0 is straight down, positive values move forward, negative moves backward.
*    **`legAngle` (Number):** A custom angle value in degrees ( -45 to 45) for the legs when `part` is set to "custom". 0 is straight down, positive values move forward, negative moves backward.

**Additional Notes:**

*   I'm already using the `build_plate.scad` from the utils library for my existing files to show the build plate in the preview. Please make sure to include that.
*   The default "work" position should be with arms at 0 and 45, and legs at 0. The "run" position should be with arms at 45 and -45, and legs at 45 and -45.

I need the full OpenSCAD file, with all the parameters built in.  I don't need any separate files.

[Assistant]
ParametricSteve.scad:
```
use <utils/build_plate.scad>

//Declare the scale that will be used for the model. This scale is used to calculate the pixel to mm scale. EX. scale of 5 means 1pixel on skin = 5mm.

scale=1.5;
hturn=0; // (-45,45)
part="work"; // [work, run, custom]

langle=-15; // Custom left arm angle, 0 is straight down, 45 is forward, -45 is back
rangle=45; // Custom right arm angle, 0 is straight down, 45 is forward, -45 is back
legAngle=15; // Custom angle of legs, 0 = standing, 45 = running

//for display only, doesn't contribute to final object
build_plate_selector = 0; //[0:Replicator 2,1: Replicator,2:Thingomatic,3:Manual]

//when Build Plate Selector is set to "manual" this controls the build plate x dimension
build_plate_manual_x = 100; //[100:400]

//when Build Plate Selector is set to "manual" this controls the build plate y dimension
build_plate_manual_y = 100; //[100:400]

//Create the head of guy

module head()
{
difference()
{
cube(size = scale * 8, center=true);
//translate([0,0,scale*4])cylinder(r=scale*1,h=8, center=true,$fn=100);
}
}

//create the connector hole for use to connect the leg to body with a piece of filament

module leg_connector()
{
//translate([scale*2,scale*1,0])cylinder(r=1.5,h=scale*2, center=true,$fn=100);
//translate([scale*2,scale*2,0])cylinder(r=1.5,h=scale*2, center=true,$fn=100);
}

//Create the body of guy

module body()
{
difference()
{
union()
{
translate([0,0,scale*10])cube([scale*8,scale*4,scale*12], center=true);
//translate([0,0,scale*4])cylinder(r=scale*1-0.25,h=8, center=true,$fn=100);
}
translate([0,scale*-1.5,scale*16])leg_connector();
translate([scale*-4,scale*-1.5,scale*16])leg_connector();
//translate([scale*4,0,scale*6])rotate(a=[90,0,90])cylinder(r=1.5,h=scale*2, center=true,$fn=100);
//translate([scale*-4,0,scale*6])rotate(a=[90,0,90])cylinder(r=1.5,h=scale*2, center=true,$fn=100);
}
}

//Create the legs of the guy

module legs(llangle,rlangle)
{
difference()
{
union()
{
// leg and foot
translate([0,0,scale*16]) rotate([llangle,0,0]) translate([0,0,-scale*16]) {
	translate([scale*2.015+1/2,0,scale*22])cube([scale*3.97-1,scale*4,scale*12], center=true);
	translate([scale*2.015+1/2,scale/2,scale*(12+22-7)])cube([scale*3.97-1,scale*5,scale*2], center=true);
	}

// other leg and foot
translate([0,0,scale*16]) rotate([rlangle,0,0]) translate([0,0,-scale*16]) {
	translate([scale*-2.015-1/2,0,scale*22])cube([scale*3.97-1,scale*4,scale*12], center=true);
	translate([scale*-2.015-1/2,scale/2,scale*(12+22-7)])cube([scale*3.97-1,scale*5,scale*2], center=true);
	}

}
//translate([0,scale*-1.5,scale*16])leg_connector();
//translate([scale*-4,scale*-1.5,scale*16])leg_connector();
}
}

//Create the tools arm of guy

module toolarm(rangle)
{
translate([0,0,6*scale]) rotate([90-rangle,0,0]) translate([0,0,-6*scale]) difference()
{
translate([-5.75*scale,4*scale,6*scale])rotate([90,0,0])cube([3.5*scale,3.5*scale,12*scale],center=true);
translate([-5.75*scale,8.5*scale,6*scale])rotate([0,90,0])cube([5*scale+0.5,1.4*scale+0.5,1*scale+0.5],center=true);
//translate([scale*-4,0,scale*6])rotate(a=[90,0,90])cylinder(r=scale*0.2,h=scale*2, center=true,$fn=100);
}
}

//Create the normal arm of guy

module freearm(langle)
{
translate([0,0,6*scale]) rotate([90-langle,0,0]) translate([0,0,-6*scale]) difference()
{
translate([5.75*scale,4*scale,6*scale])rotate([90,0,0])cube([3.5*scale,3.5*scale,12*scale],center=true);
//translate([scale*4,0,scale*6])rotate(a=[90,0,90])cylinder(r=scale*0.2,h=scale*2, center=true,$fn=100);
}
}

w = scale * (8 + 3.5 + 3.5);
h = sqrt(w*w/2);
echo(w,h);

module supportarms() {
	translate([0,0,4*scale]) rotate([90,0,0]) rotate([0,0,45]) cube([h,h,0.5], center=true);
	}

module drawSteve(hturn,langle,rangle,llangle,rlangle) {
	rotate([0,0,180]) translate([0,0,scale * 4]) {
		rotate([0,0,hturn]) head();       //Call to generate the guy's head
		body();       //Call to generate the guy's body
		legs(llangle,rlangle);         //Call to generate the guy's legs
		toolarm(rangle);   //Call to generate the guy's tool arm
		freearm(langle);  //Call to generate the guy's free arm
		supportarms();
		}
	}

if (part=="run") drawSteve(hturn,45, -45, 45, -45);
if (part=="work") drawSteve(hturn,0,45,0,0);
if (part=="custom") drawSteve(hturn,langle,rangle,legAngle,-legAngle);

build_plate(build_plate_selector,build_plate_manual_x,build_plate_manual_y);
```


[User]
Okay, I'd like to design a parametric heart-shaped box in OpenSCAD.

The basic idea is that it's a 3D heart shape with a hollowed-out interior, like a small trinket box. The box is formed by creating two hearts, the second of which is smaller and slightly shifted up, and then subtracting the second heart from the first. The basic heart is made from a square with two circles attached to it.

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

*   **`size`**: This will be the overall size of the heart. It is used to generate the initial square and circles that form the heart shape. The heart will be a rough square when looked at from the top with rounded corners where the circles merge into the square.
*   **`height`**: The total height of the box.
*   **`thickness`**: The thickness of the walls of the box. This will also be the distance the inner heart is translated from the base heart.

I'd like to have a modular design, with the following functions:

*   **`heart_shape(size)`**: This function should generate the 2D heart shape from the square and two circles.
*   **`heart(size, thickness, height)`**: This function should take the output of `heart_shape` and extrude it to the specified `height`. The `thickness` should then be applied using minkowski and a circle of diameter `thickness`. Note that `thickness` is also used by the `heart_box` module, and its usage here does not affect the thickness of the wall.
*   **`heart_box(size, height, thickness)`**: This function should create the box by subtracting a slightly translated `heart` shape from a base `heart` shape.

I would like to see the `heart_box` with the following values: `size` of 20, a `height` of 10, and `thickness` of 3.

I'm not using any specific libraries, just the core OpenSCAD functionality.

[Assistant]
heartbox.scad:
```
module heart_shape(size) {
     union() {
        square(size,size);
        translate([size/2,size,0]) circle(size/2);
        translate([size,size/2,0]) circle(size/2);
    }
}

module heart(size,thickness,height) {
   linear_extrude(height=height)
          minkowski() {
               heart_shape(size);
               circle(thickness+0.1);
        }
}

module heart_box(size,height,thickness) {
    difference() {
         heart(size,thickness,height);
         translate([0,0,thickness]) heart(size,0,height);
    }
}

heart_box(20,10,3);
```


[User]
Okay, I need a custom-designed cover for a power supply, and I'm hoping you can help me generate an OpenSCAD file for it. I’ve got a basic design in mind, but I need it to be parametric so I can adapt it to different power supplies and mounting situations.

Here's the basic idea: The cover should mount in the corner where two walls meet and extend out to enclose the exposed terminals on my power supply. It's basically a corner bracket with an enclosure extending outwards.

Here are the specific design requirements and the parameters I want to be able to adjust:

1.  **Wall Thickness:** I need to be able to control the thickness of the walls of the cover. I want this to be a variable so I can adjust for printing strength.

2.  **Power Supply Dimensions:** The cover should be sized to fit a rectangular "brick" type power supply. I need to be able to set the width and height of the power supply.

3.  **Distance to Wall:** I need a parameter to set how far the cover extends out from the wall to meet the edge of the power supply.

4.  **Cover Height Above PS:** I need to be able to specify how much the cover goes "up" the wall above the top of the power supply. This will provide some extra safety coverage.

5.  **Corner Attachment:** The design should include a corner bracket to mount the cover to the walls. I'm imagining a simple "L" shaped bracket that is integral to the cover. It should connect to the wall at two perpendicular surfaces and extend out along the edges of the power supply on the vertical and horizontal planes. It also needs to include a cylinder on the inside corner to help with printing.

6.  **Power Supply Cutout:** The inside of the cover needs to have a cutout that matches the dimensions of the power supply so the power supply can sit inside it, like it's in a box with one side missing.

7.  **Air Holes:** The cover should include a pattern of air holes on the top to allow for some ventilation. I would like the pattern to be rows of small cylindrical holes. The number of holes should vary based on the cover's dimensions, automatically. The holes should also be close to, but not touching, the front walls of the cover.

8.  **Screw Holes:** The cover should have 3 screw holes for mounting the cover. Two should be on the horizontal wall, and one on the vertical wall. Ideally the holes should be a countersunk design so the head of the screw is flush with the wall of the bracket.

9.  **Wire Cutouts:** There needs to be some cutouts for wires to pass. One cutout should be a 45-degree cut on the corner nearest the horizontal wall, and the other should be a round cutout near the distal end of the cover on the vertical wall.

So, in summary, I'm looking for a parametric OpenSCAD file that allows me to adjust: `wallThickness`, `PSwidth`, `PSHeight`, `DistToWall`, and `coverHeight`. It should build the L bracket, the surrounding cover, the air holes, the mounting screw holes, and the wire cutouts based on the dimensions and parameters described above. It also needs to use `cylinder` shapes for the interior corners so that they can print well. I do not need any custom modules.

I expect that it may be a useful feature of the code to be able to specify the center of the power supply instead of the corners, so I think it would be a good idea if the code took in the distance from the walls to the power supply's side.

Please let me know if you have any questions.

[Assistant]
ps_cover.scad:
```
// Power Supply end cover.
// Mounts on a corner the power supply is near to cover exposed screw terminals.
// Better than tape!

//CUSTOMIZER VARIABLES

//How thick your walls are (in mm)
wallThickness = 5;

// The "width" of your power supply
PSwidth = 112;

// The "height" of your power supply
PSHeight = 50;

// The lenght you want the cover to extend from the wall (to the PS)
DistToWall = 42;

//The amount of cover you want to go "up" the wall above the PS height
coverHeight=30;

//CUSTOMIZER VARIABLES END

$fn=60;

cornerCutoutSize = 20;
roundCutoutSize=15;

difference() {
  union() {
   // Wall plate 1
   color([0,0.75,0])  // Green
   translate([-wallThickness,-coverHeight,0])
   cube([PSwidth+wallThickness,coverHeight,wallThickness]);

   //Wall Plate 2
   color([0.5,0,0]) // Red
   translate([PSwidth-wallThickness,-coverHeight,0])
   cube([wallThickness,coverHeight,DistToWall] );

   // Wall Plate 3
   color([0,0,0.5]) // Blue
   translate([0,-wallThickness,0])
   cube([PSwidth,wallThickness,DistToWall]);

  // Wall Plate 4
   translate([-wallThickness,0,0])
   #cube([wallThickness,PSHeight,DistToWall]);

  // Outside cylinder:
   cylinder(r=wallThickness, h=DistToWall);

  // Inside cylinder 1:
   translate([PSwidth-wallThickness,-wallThickness,0])
   cylinder(r=wallThickness, h=DistToWall);

  // Inside cylinder 2:
   translate([PSwidth-wallThickness,0,wallThickness])
   rotate([90,0,0])
   cylinder(r=wallThickness, h=coverHeight);

  // Inside cylinder 3:
   translate([-wallThickness,-wallThickness,wallThickness])
   rotate([0,90,0])
   cylinder(r=wallThickness, h=PSwidth+wallThickness);

   //Acompanying sphere.. (make ins cyl 3 wallThickness less)
   //translate([0,-wallThickness,wallThickness])
  // sphere(r=wallThickness);
  }

  // Cut this cube representing the power supply out of everything that needs it...(the outside cylinder...)
  color([0.85,0.85,-0.1])
   #cube([PSwidth,PSHeight,DistToWall+0.2]);

  // Air holes
 for ( x = [ wallThickness : 9: PSwidth-wallThickness*2],
         z = [ wallThickness : 9 : coverHeight - wallThickness]  ){

  translate([x+1, 0.1,wallThickness*2.5+z])
     rotate([0,270,0])
     rotate([90,0,0])
    cylinder(h=wallThickness+0.2, r=3, $fn=4);
 }

 // Screw Hole 1
 translate([PSwidth / 4,-coverHeight/1.5,-0.1])
   cylinder(r1=2,r2=3, h=wallThickness+0.2);

 // Screw Hole 2
 translate([PSwidth/1.5,-coverHeight/1.5,-0.1])
   cylinder(r1=2, r2=3,h=wallThickness+0.2);

 // Screw Hole 3
 translate([PSwidth-wallThickness-0.1,-coverHeight/1.5,DistToWall/2+wallThickness])
   rotate([0,90,0])
   cylinder(r1=3, r2=1, h=wallThickness+0.2);

  //45-deg bottom wire cutout
 translate([-wallThickness-0.1,PSHeight,0])
 rotate([0,90,-0])
 cylinder(r=cornerCutoutSize,h=wallThickness+0.2, $fn=4);

  //Round Wire cutout
 translate([-wallThickness-0.1,PSHeight/2,DistToWall])
  rotate([0,90,-0])
   cylinder(r=roundCutoutSize,h=wallThickness+0.2);

} // end diffeerence

```


[User]
Okay, I'm looking to design a dual fan mount with some specific features, and I'd like to use OpenSCAD to make it parametric. I really like the idea behind the "Dual Articulated Ball Joint Fan Mount with Twist-Lock Base" but want to generalize it so it works for any fan size and to have a better way to attach the second fan.

Here's what I'm envisioning:

**Core Functionality:**

*   **Dual Articulated Ball Joints:**  I need two ball joints, each with a clamp mechanism to hold it at the desired angle.  I'd prefer the clamping action to use a screw and nut, just like in the example.
*   **Twist-Lock Base:** I want a base that can be quickly attached and detached using a twist-lock mechanism.  I don't need it to be compatible with the existing design though, so we can redesign that.
*   **Parametric Fan Mounting:** The mount should be adaptable to different sized fans, with parametric screw hole placement.
*   **Ducts:** Each fan should have an integrated duct to direct airflow. These should also be parametric and optionally allow for a narrowing of the duct.
*   **Dual Fan Configuration:** Instead of the second fan just being mounted on an arm, I'd like to mount the second fan with a second ball joint as well, so it can be adjusted independently. Both fans should mount in a way that the airflow is towards the center of the assembly.
*   **General Parametricity:** All key dimensions (ball joint sizes, screw sizes, material thicknesses, base dimensions) should be parametric variables that are easily changed.
* **Standard Screw sizes:** I want to use standard screw sizes, and be able to define a single screw size (e.g. M3) and have all screw holes and nut recesses use the corresponding sizes. The nut recesses can use standard hex nuts, but can also accommodate for captured nuts.
* **Printability:** The design should be printable without needing supports.

**Detailed Design Elements:**

1.  **Base:**
    *   The base should have a twist-lock mechanism that securely attaches to a mating base on another part. This twist-lock should be parametric, controlling the angle of the twist and the overall size of the base.
    *   The base should have mounting holes for attaching it to a surface.
    *   The twist-lock should be printable without supports.
2.  **Ball Joints:**
    *   Each ball joint should have a spherical ball and a corresponding clamp mechanism.
    *   The clamp should use a screw and nut (or captured nut) to tighten around the ball.
    *   The clamping mechanism needs to have clearance to easily rotate on the ball, but also be rigid enough to hold position.
    *   All components for the ball joint mechanism should be printable without supports.
3.  **Fan Mounts:**
    *   Each fan mount should have integrated screw holes for mounting the fan. The size of these holes should be parametric with standard sizes.
    *   The placement of the mounting holes should be parametric based on the fan size.
    *   Each fan mount should integrate a duct that guides airflow.
    *   The duct shape should also be parametric. I'd like a cylindrical duct but with the option to make it slightly conical or have a narrower portion.
4.  **Second Fan Joint:**
    *   The second fan should attach to a duplicate of the same ball joint used on the base.
    *   This second ball joint should also be rotatable and clampable independently.
5.  **Parameterization:**
    *   I need variables for:
        *   All dimensions for the fan size, like the fan size, screw hole diameters, and distances between screw holes.
        *   The overall length of each duct.
        *   The narrowing or the angle of each duct
        *   Ball joint diameters.
        *   Ball joint clamp screw and nut sizes (using standard naming conventions).
        *   Screw hole diameters for mounting the base.
        *   Base twist-lock size and twist angle.
        *   Material thicknesses.
        *   Clearances for moving parts.
        *   Height of the entire assembly.
        *   Wall thickness of each component.
        *   Fillet radius for the second fan arm
*   **Library Requirements:**
        * I would prefer to use BOSL2 for standard functions such as `nut()` and `screw_hole()`.
*   **Code Style:**
    *   Comments describing the purpose of variables and modules would be very helpful.
    *   I would also like to be able to change the detail of the final render ( `$fn`, `$fa`, and `$fs`).

I think that's everything. Let me know if you need any clarification. I'm excited to see what you come up with!

[Assistant]
Dual_Articulated_Ball_Joint_Fan_Mount_Twist-Lock_101113.scad:
```
//Dual Articulated Ball Joint Fan Mount with Twist-Lock Base by John Davis (ei8htohms) 8-24-13

// Which part would you like to make?
part = "All"; // [Base,Clip1,Clip2,Clips,Duct,All]

/*[Dimensions of Base]*/
//Ratio of material around screws
Screw_Base_Multiplier = 1.8;
//Ratio of material around central base
Central_Base_Multiplier = 1;
//Height of mount base including sphere
Height = 24;
//Thickness of mount base
Thickness = 2;
//Sphere diameter
Sphere_Diameter = 16;
//How far are the mounting screws from the center?
Screw_Distance = 15;
//The angle of the base connection to the sphere (larger angle means fatter "neck")
Angle=45;
//Angle of cut out for twist lock
Cut_Sweep=15;

/*[Base Mounting Screw Dimensions]*/
//Screw shaft diameter
Screw_Shaft_Diameter = 2.5;
//Screw head diameter
Screw_Head_Diameter = 4.3;
//Length of screw hole
Screw_Length = Thickness;
//Screw head thickness or depth of head recesss for countersunk
Screw_Head_Height = 0.3;
//Countersunk (1) or flat head (0)?
Countersink = 1; //[0,1]

/*[Dimensions of Clips]*/
//Space between inside of clip and ball joint
Clip_Clearance=0.2;
//Clip thickness (also determines duct wall thickness)
Clip_Thickness=1;
//Clip height
Clip_Height=8;
//Opening for clip compression
Opening=1.6;
//How far out does the clamp screw extend from the ball?
Clamp_Extension=3;
//How far out does the elbow extend from the ball?
Mount_Extension=12;
//How far above or below center should the clips be (to clear each other)?
Clip_Offset=2;
//Angle of rotation of cut for second clip
Tilt_Rotation=30;
//How tilted is the 2nd clip?
Tilt=25;

/*[Clamping Screw and Nut Dimensions]*/
//Clamping screw diameter
Clamping_Screw_Diameter=2.9;
//Nut width across flats
Nut_Width=4.7;
//Nut height
Nut_Height=1.6;
//Additional clearance for nut
Nut_Clearance=0.2;
//Vertical nut correction (to make it align with screw hole when printed)
Nut_Correction=-0.5;

/*[Arm with Duct Dimensions]*/
//Small Sphere Diameter
Small_Sphere_Diameter=11.8;
//Fan size
Fan_Size=30;
//Fan screw diameter
Fan_Screw_Diameter=2.8;
//Clearance for fan screw head diameter
Fan_Screw_Head_Diameter=8;
//Duct height
Duct_Height=25;
//Duct scaling - how restrictive is the duct
Duct_Scaling=0.45;
//Duct wall thickness
Duct_Wall=0.52;

/*[Printer Settings]*/
//To control the number facets rendered, fine ~ 0.1 coarse ~1.0. 0.3 is fine for home printers.
$fs = 0.5;

/*[Hidden]*/
//leave $fn disabled, do not change
$fn = 0;
//leave $fa as is, do not change
$fa = 0.01;
//padding to insure manifold, ignore
Padding = 0.01;

print_part();

module print_part() {
	if (part == "Base") {
		Base();
	} else if (part == "Clip1") {
		Clip1();
	} else if (part == "Clip2") {
		Clip2();
	} else if (part == "Clips") {
		Clip1();
		Clip2();
	} else if (part == "Duct") {
		Duct();
	} else {
		Base();
		Clip1();
		Clip2();
		Duct();
	}
}

module Duct()

//uncomment for assembled view
//translate([Sphere_Diameter/2+Clip_Clearance+Clip_Thickness+Mount_Extension,0,Height-Sphere_Diameter/2-Small_Sphere_Diameter/2+Clip_Offset])

//uncomment for printable view
translate([Fan_Size/2,min(-Sphere_Diameter-Clip_Clearance*2-Clip_Thickness*2-Small_Sphere_Diameter*2,-Sphere_Diameter/2-Clip_Clearance-Clip_Thickness*3-Fan_Size/2),0])
rotate([0,0,180])

difference(){
	union(){
		translate([0,0,Small_Sphere_Diameter/2])
		sphere(r=Small_Sphere_Diameter/2);

		difference(){
			translate([0,0,Small_Sphere_Diameter/2])
			rotate([0,135,0])
			cylinder(r=sqrt(pow(Small_Sphere_Diameter/2,2)/2),h=sqrt(pow(Small_Sphere_Diameter/2,2)*2));
			translate([0,0,Small_Sphere_Diameter/2])
			rotate([0,135,0])
			translate([0,0,3*sqrt(pow(Small_Sphere_Diameter/2,2)/2)/2])
			rotate_extrude()
			translate([3*sqrt(pow(Small_Sphere_Diameter/2,2)/2)/2,0,0])
			circle(r=3*sqrt(pow(Small_Sphere_Diameter/2,2)/2)/4);

			translate([Small_Sphere_Diameter/2,0,-Small_Sphere_Diameter/2])
			cylinder(r=Small_Sphere_Diameter/2,h=Small_Sphere_Diameter/2);
		}

		minkowski(){
			translate([Small_Sphere_Diameter/2+Fan_Size/2,0,Thickness/2-0.5])
			cube([Fan_Size-Fan_Size/5,Fan_Size-Fan_Size/5,Thickness-1],center=true);
			cylinder(r=Fan_Size/10,h=1);
		}

		difference(){
			translate([Small_Sphere_Diameter/2+Fan_Size/2,0,Thickness-Padding])
			cylinder(r1=Fan_Size/2,r2=Fan_Size/2*Duct_Scaling,h=Duct_Height);
			translate([0,0,Small_Sphere_Diameter/2])
			sphere(r=Small_Sphere_Diameter/2+Clip_Thickness*2);
		}

	}

	translate([Small_Sphere_Diameter/2+Fan_Size/10,-Fan_Size/2+Fan_Size/10,-Padding])
	polyhole(Thickness+Padding*2+Duct_Height,Fan_Screw_Diameter);

	translate([Small_Sphere_Diameter/2+Fan_Size/10,Fan_Size/2-Fan_Size/10,-Padding])
	polyhole(Thickness+Padding*2,Fan_Screw_Diameter);

	translate([Small_Sphere_Diameter/2+Fan_Size-Fan_Size/10,-Fan_Size/2+Fan_Size/10,-Padding])
	polyhole(Thickness+Padding*2,Fan_Screw_Diameter);

	translate([Small_Sphere_Diameter/2+Fan_Size-Fan_Size/10,Fan_Size/2-Fan_Size/10,-Padding])
	polyhole(Thickness+Padding*2,Fan_Screw_Diameter);

//

	translate([Small_Sphere_Diameter/2+Fan_Size/10,-Fan_Size/2+Fan_Size/10,Thickness+Padding])
	cylinder(r=Fan_Screw_Head_Diameter/2, h=Duct_Height);

	translate([Small_Sphere_Diameter/2+Fan_Size/10,Fan_Size/2-Fan_Size/10,Thickness+Padding])
	cylinder(r=Fan_Screw_Head_Diameter/2, h=Duct_Height);

	translate([Small_Sphere_Diameter/2+Fan_Size-Fan_Size/10,-Fan_Size/2+Fan_Size/10,Thickness+Padding])
	cylinder(r=Fan_Screw_Head_Diameter/2, h=Duct_Height);

	translate([Small_Sphere_Diameter/2+Fan_Size-Fan_Size/10,Fan_Size/2-Fan_Size/10,Thickness+Padding])
	cylinder(r=Fan_Screw_Head_Diameter/2, h=Duct_Height);

	difference(){
		union(){
			translate([Small_Sphere_Diameter/2+Fan_Size/2,0,Thickness-Padding])
			cylinder(r1=Fan_Size/2-Duct_Wall,r2=(Fan_Size/2*Duct_Scaling)-Duct_Wall,h=Duct_Height+Padding);

			translate([Small_Sphere_Diameter/2+Fan_Size/2,0,-Padding])
			cylinder(r=Fan_Size/2-Duct_Wall,h=Thickness+2*Padding);
		}

		translate([0,0,Small_Sphere_Diameter/2])
		sphere(r=Small_Sphere_Diameter/2+Clip_Thickness*3);

		translate([Small_Sphere_Diameter/2+Fan_Size/10,-Fan_Size/2+Fan_Size/10,-Padding])
		cylinder(r=Fan_Screw_Head_Diameter/2+Duct_Wall, h=Duct_Height);

		translate([Small_Sphere_Diameter/2+Fan_Size/10,Fan_Size/2-Fan_Size/10,-Padding])
		cylinder(r=Fan_Screw_Head_Diameter/2+Duct_Wall, h=Duct_Height);

		translate([Small_Sphere_Diameter/2+Fan_Size-Fan_Size/10,-Fan_Size/2+Fan_Size/10,-Padding])
		cylinder(r=Fan_Screw_Head_Diameter/2+Duct_Wall, h=Duct_Height);

		translate([Small_Sphere_Diameter/2+Fan_Size-Fan_Size/10,Fan_Size/2-Fan_Size/10,-Padding])
		cylinder(r=Fan_Screw_Head_Diameter/2+Duct_Wall, h=Duct_Height);
	}
}

module Clip1(){

//uncomment for assembled view
//translate([0,0,2*(Height-Sphere_Diameter/2-Clip_Height/2)-Clip_Offset])
//mirror([0,0,1])

//uncomment for printable view
mirror([0,1,0])
rotate([0,0,180])
translate([-Fan_Size/2,-Sphere_Diameter,0])

difference(){
	union(){
		intersection(){
			translate([0,0,Clip_Height/2+Clip_Offset])
			sphere(r=Sphere_Diameter/2+Clip_Clearance+Clip_Thickness);
			cylinder(r=Sphere_Diameter/2+Clip_Clearance+Clip_Thickness+Padding,h=Clip_Height);
		}

		translate([0,Opening/2,0])
		cube([Sphere_Diameter/2+Clip_Clearance+Clip_Thickness+Mount_Extension,Clip_Thickness*3,Clip_Height]);

		intersection(){
			translate([Sphere_Diameter/2+Clip_Clearance+Clip_Thickness+Mount_Extension,0,Clip_Height/2])
			sphere(r=Small_Sphere_Diameter/2+Clip_Clearance+Clip_Thickness);
			translate([Sphere_Diameter/2+Clip_Clearance+Clip_Thickness+Mount_Extension,0,0])
			cylinder(r=Small_Sphere_Diameter/2+Clip_Clearance+Clip_Thickness+Padding, h=Clip_Height);
		}

		translate([0,-Opening/2-Nut_Height*3,0])
		cube([Sphere_Diameter/2+Clip_Clearance+Clip_Thickness+Mount_Extension,Nut_Height*3,Clip_Height]);

	}

	translate([Sphere_Diameter/2+Clip_Clearance+Clip_Thickness+Clamp_Extension,-Opening/2-2*Nut_Height-Nut_Clearance,Clip_Height/2+Nut_Correction])
	rotate([-90,0,0])
	nut();

	translate([Sphere_Diameter/2+Clip_Clearance+Clip_Thickness+Clamp_Extension-(Nut_Width/2+Nut_Clearance)/cos(30),-Opening/2-2*Nut_Height-Nut_Clearance,Clip_Height/2+Nut_Correction])
	cube([(Nut_Width/2+Nut_Clearance)/cos(30)*2,Nut_Height+2*Nut_Clearance,Nut_Width/2+Nut_Clearance]);

	translate([Sphere_Diameter/2+Clip_Clearance+Clip_Thickness+Clamp_Extension,-Opening/2-Nut_Height*3-Padding,Clip_Height/2])
	rotate([-90,0,0])
	cylinder(h= Nut_Height*3+Opening+Clip_Thickness*3+Padding*2, r=Clamping_Screw_Diameter/2);

	translate([0,-Opening/2,-Padding])
	cube([Sphere_Diameter/2+Clip_Clearance+Clip_Thickness+Padding+Mount_Extension+Small_Sphere_Diameter/2+Clip_Clearance+Clip_Thickness,Opening,Clip_Height+Padding*2]);

	translate([0,0,Clip_Height/2+2])
	sphere(r=Sphere_Diameter/2+Clip_Clearance);

	translate([Sphere_Diameter/2+Clip_Clearance+Clip_Thickness+Mount_Extension,0,Clip_Height/2])
	sphere(r=Small_Sphere_Diameter/2+Clip_Clearance);

	difference(){
		translate([Sphere_Diameter/2+Clip_Clearance+Clip_Thickness+Mount_Extension,-Small_Sphere_Diameter/2-Clip_Clearance-Clip_Thickness-Padding,-Padding])
		cube([Small_Sphere_Diameter/2+Clip_Clearance+Clip_Thickness+Padding,2*(Small_Sphere_Diameter/2+Clip_Clearance+Clip_Thickness+Padding),Clip_Height+2*Padding]);
		translate([Sphere_Diameter/2+Clip_Clearance+Clip_Thickness+Mount_Extension,-Small_Sphere_Diameter/2-Clip_Clearance-Clip_Thickness-Padding,Clip_Height/2])
		rotate([-90,0,0])
		cylinder(r=Clip_Height/2,h=2*(Small_Sphere_Diameter/2+Clip_Clearance+Clip_Thickness+Padding));
	}
}
}

module Clip2(){

//uncomment for assembled view
//rotate([0,0,140])
//translate([2,0,Height-Sphere_Diameter/2-Clip_Height/2-1.5])
//rotate([0,-15,0])
//mirror([0,1,0])

//uncomment for printable view
translate([-Fan_Size/2,0,0])
mirror([0,1,0])

difference(){
	union(){
		intersection(){
			translate([0,0,Clip_Height/2+Clip_Offset])
			sphere(r=Sphere_Diameter/2+Clip_Thickness*2+Clip_Clearance*2);
			difference(){
				cylinder(r=Sphere_Diameter/2+Clip_Thickness*2+Clip_Clearance*2+Padding,h=Clip_Height*3);
				rotate([0,0,-Tilt_Rotation])
				rotate([0,-Tilt,0])
				translate([0,0,Clip_Height])
				cylinder(r=Sphere_Diameter, h=Clip_Height*3);
			}
		}

		translate([0,Opening/2,0])
		cube([Sphere_Diameter/2+Clip_Clearance+Clip_Thickness+Mount_Extension,Clip_Thickness*3,Clip_Height]);

		intersection(){
			translate([Sphere_Diameter/2+Clip_Clearance+Clip_Thickness+Mount_Extension,0,Clip_Height/2])
			sphere(r=Small_Sphere_Diameter/2+Clip_Clearance+Clip_Thickness);
			translate([Sphere_Diameter/2+Clip_Clearance+Clip_Thickness+Mount_Extension,0,0])
			cylinder(r=Small_Sphere_Diameter/2+Clip_Clearance+Clip_Thickness+Padding, h=Clip_Height);
		}

		translate([0,-Opening/2-Nut_Height*3,0])
		cube([Sphere_Diameter/2+Clip_Clearance+Clip_Thickness+Mount_Extension,Nut_Height*3,Clip_Height]);

	}

	translate([Sphere_Diameter/2+Clip_Clearance+Clip_Thickness+Clamp_Extension,-Opening/2-2*Nut_Height-Nut_Clearance,Clip_Height/2+Nut_Correction])
	rotate([-90,0,0])
	nut();

	translate([Sphere_Diameter/2+Clip_Clearance+Clip_Thickness+Clamp_Extension-(Nut_Width/2+Nut_Clearance)/cos(30),-Opening/2-2*Nut_Height-Nut_Clearance,Clip_Height/2+Nut_Correction])
	cube([(Nut_Width/2+Nut_Clearance)/cos(30)*2,Nut_Height+2*Nut_Clearance,Nut_Width/2+Nut_Clearance]);

	translate([Sphere_Diameter/2+Clip_Clearance+Clip_Thickness+Clamp_Extension,-Opening/2-Nut_Height*3-Padding,Clip_Height/2])
	rotate([-90,0,0])
	cylinder(h= Nut_Height*3+Opening+Clip_Thickness*3+Padding*2, r=Clamping_Screw_Diameter/2);

	translate([0,-Opening/2,-Padding])
	cube([Sphere_Diameter/2+Clip_Clearance+Clip_Thickness+Padding+Mount_Extension+Small_Sphere_Diameter/2+Clip_Clearance+Clip_Thickness,Opening,Clip_Height*3+Padding*2]);

	translate([0,0,Clip_Height/2+2])
	sphere(r=Sphere_Diameter/2+Clip_Thickness);

	translate([Sphere_Diameter/2+Clip_Clearance+Clip_Thickness+Mount_Extension,0,Clip_Height/2])
	sphere(r=Small_Sphere_Diameter/2+Clip_Clearance);

	difference(){
		translate([Sphere_Diameter/2+Clip_Clearance+Clip_Thickness+Mount_Extension,-Small_Sphere_Diameter/2-Clip_Clearance-Clip_Thickness-Padding,-Padding])
		cube([Small_Sphere_Diameter/2+Clip_Clearance+Clip_Thickness+Padding,2*(Small_Sphere_Diameter/2+Clip_Clearance+Clip_Thickness+Padding),Clip_Height+2*Padding]);
		translate([Sphere_Diameter/2+Clip_Clearance+Clip_Thickness+Mount_Extension,-Small_Sphere_Diameter/2-Clip_Clearance-Clip_Thickness-Padding,Clip_Height/2])
		rotate([-90,0,0])
		cylinder(r=Clip_Height/2,h=2*(Small_Sphere_Diameter/2+Clip_Clearance+Clip_Thickness+Padding));
	}

}
}

module Base(){

Base_Rad=(Height-Sphere_Diameter/2-(Sphere_Diameter/2*cos(Angle))-Thickness)/(1+cos(Angle));

//uncomment for printable view
translate([0,(Sphere_Diameter/2*sin(Angle)+sin(Angle)*Base_Rad)*Central_Base_Multiplier*2+2,0])

//Base with ball pivot
union(){
	//ball for clip
	translate([0,0,Height-Sphere_Diameter/2])
	sphere(r=Sphere_Diameter/2);

	//post for ball
	difference(){
		translate([0,0,Thickness-Padding])
		cylinder(r1=Sphere_Diameter/2*sin(Angle)+sin(Angle)*Base_Rad, r2=Sphere_Diameter/2*sin(Angle), h=Height-Sphere_Diameter/2-(Sphere_Diameter/2*cos(Angle))-Thickness+Padding*2);
		rotate_extrude()
		translate([Sphere_Diameter/2*sin(Angle)+sin(Angle)*Base_Rad,Base_Rad+Thickness+Padding,0])
		//rotate([90,0,0])
		circle(r=Base_Rad+Padding);
	}

	//base
	difference(){
		hull(){
			rotate([0,0,Cut_Sweep/2])
			translate([Screw_Distance-Screw_Head_Diameter/2,0,0])
			cylinder(r=(tan(Cut_Sweep)*Screw_Distance)/2+Screw_Head_Diameter/2*Screw_Base_Multiplier,h=Thickness);
			cylinder(r=(Sphere_Diameter/2*sin(Angle)+sin(Angle)*Base_Rad)*Central_Base_Multiplier,h=Thickness);
			rotate([0,0,Cut_Sweep/2])
			translate([-Screw_Distance+Screw_Head_Diameter/2,0,0])
			cylinder(r=(tan(Cut_Sweep)*Screw_Distance)/2+Screw_Head_Diameter/2*Screw_Base_Multiplier,h=Thickness);
		}

		//screws
		translate([-Screw_Distance,0,Thickness])
		rotate([180,0,0])
		screw_hole(Thickness);
		translate([Screw_Distance,0,Thickness])
		rotate([180,0,0])
		screw_hole(Thickness);

		//cut out for sliding screws
		intersection(){
			translate([0,0,-Padding])
			linear_extrude(height=Thickness+2*Padding)
			polygon(points=[[0,0],[Screw_Distance+Screw_Head_Diameter/2+Padding,0],[Screw_Distance+Screw_Head_Diameter/2+Padding,tan(Cut_Sweep)*(Screw_Distance+Screw_Head_Diameter/2+Padding)]]);
			rotate([180,0,0])
			rotate_extrude()
			translate([Screw_Distance,Padding,0])
			polygon(points=[[-Screw_Shaft_Diameter/2,0],[-Screw_Shaft_Diameter/2,-(Thickness-Screw_Head_Height-Screw_Head_Diameter/2+Screw_Shaft_Diameter/2+Padding)],[-Screw_Head_Diameter/2,-(Thickness-Screw_Head_Height)],[-Screw_Head_Diameter/2,-Thickness-Padding*2],[Screw_Head_Diameter/2,-Thickness-Padding*2],[Screw_Head_Diameter/2,-(Thickness-Screw_Head_Height)],[Screw_Shaft_Diameter/2,-(Thickness-Screw_Head_Height-Screw_Head_Diameter/2+Screw_Shaft_Diameter/2+Padding)],[Screw_Shaft_Diameter/2,0]]);
		}
		rotate([0,0,Cut_Sweep])
		translate([Screw_Distance,0,-Padding])
		cylinder(h=Thickness+2*Padding, r=Screw_Head_Diameter/2+2*Padding);
		intersection(){
			translate([0,0,-Padding])
			linear_extrude(height=Thickness+2*Padding)
			polygon(points=[[0,0],[-Screw_Distance-Screw_Head_Diameter/2-Padding,0],[-Screw_Distance-Screw_Head_Diameter/2-Padding,-tan(Cut_Sweep)*(Screw_Distance+Screw_Head_Diameter/2+Padding)]]);
			rotate([180,0,0])
			rotate_extrude()
			translate([Screw_Distance,Padding,0])
			polygon(points=[[-Screw_Shaft_Diameter/2,0],[-Screw_Shaft_Diameter/2,-(Thickness-Screw_Head_Height-Screw_Head_Diameter/2+Screw_Shaft_Diameter/2+Padding)],[-Screw_Head_Diameter/2,-(Thickness-Screw_Head_Height)],[-Screw_Head_Diameter/2,-Thickness-Padding*2],[Screw_Head_Diameter/2,-Thickness-Padding*2],[Screw_Head_Diameter/2,-(Thickness-Screw_Head_Height)],[Screw_Shaft_Diameter/2,-(Thickness-Screw_Head_Height-Screw_Head_Diameter/2+Screw_Shaft_Diameter/2+Padding)],[Screw_Shaft_Diameter/2,0]]);
		}
		rotate([0,0,Cut_Sweep])
		translate([-Screw_Distance,0,-Padding])
		cylinder(h=Thickness+2*Padding, r=Screw_Head_Diameter/2+2*Padding);
	}
}
}

module nut(){
	cylinder(r=(Nut_Width/2+Nut_Clearance)/cos(30),h=Nut_Height+2*Nut_Clearance,$fn=6);
}

module screw_hole(L){
 	translate([0,0,-Padding])
	union() {
   	cylinder(h=L+Padding*2, r=Screw_Shaft_Diameter/2);
      cylinder(h=Screw_Head_Height, r=Screw_Head_Diameter/2);
		if (Countersink == 1)
			{translate([0,0,Screw_Head_Height-Padding])
			cylinder(h=Screw_Head_Diameter/2-Screw_Shaft_Diameter/2+Padding, r1=Screw_Head_Diameter/2, r2=Screw_Shaft_Diameter/2);
			}
    }
};

module polyhole(h, d) {
    n = max(round(2 * d),3);
    rotate([0,0,180])
        cylinder(h = h, r = (d / 2) / cos (180 / n), $fn = n);
}

module polycone(h, d1, d2) {
    n = max(round(2 * d1),3);
    rotate([0,0,0])
        cylinder(h = h, r1 = (d1 / 2) / cos (180 / n), r2 = (d2 / 2) / cos (180 / n),$fn = n);
}

```


[User]
Okay, I'm looking to create a cable clip that attaches to the underside of a table to manage cables. I've got a rough idea and a starting point with a simple OpenSCAD file, but I need something more robust and parametric.

Here's what I'm looking for:

**Functionality:**

*   The clip should attach to the underside of a table, using a "C" clamp design. One side of the "C" should press against the table's bottom, and the other side of the "C" should have a space for cable to pass through.
*   The cable should sit within a semi-circular groove on the 'hanging' side of the "C" clamp.

**Key Parameters:**

*   **Table Thickness:**  This needs to be adjustable to accommodate different table thicknesses. I'd say a reasonable range would be from 10mm to 100mm.
*   **Clip Length:** This controls how far the clip extends from the edge of the table. A good range would be 20mm to 50mm.
*   **Clip Thickness:** The overall thickness of the clip material itself should be adjustable, probably between 3mm to 6mm.
*   **Clip Width:** The width of the clip, along the long dimension of the table - should be adjustable, say between 10mm and 30mm.
*   **Cable Diameter:** The maximum diameter of the cable the clip should accommodate. I'd like to specify this, from 3mm to 20mm.
*   **Fastener Diameter:** I'd like the option to add a hole for a small screw to make the clip more secure, this should be defined as a diameter value
*   **Fastener Distance:** Related to fastener, it should allow the user to define a distance of the fastener from the edge of the clip where it is attached to the table.

**Desired Features:**

*   **Parametric Design:** All of the above parameters must be easily adjustable within the OpenSCAD file.
*   **Clean Look:**  The design should be relatively clean and simple. No crazy curves or complex geometries needed.
*   **Easy to Print:**  The design should be suitable for 3D printing without requiring supports.
*   **Optional Screw Hole:**  I want the option to easily add a screw hole to improve the connection to the table. The hole should be centered on the part of the clip touching the table.

I'm not really using any libraries at the moment, so there is no need for a library in this revision, but I'd be open to using one in the future if it helps simplify the code.

I've included the OpenSCAD code I started with. Can you generate an improved version that is parametric as described above?

[Assistant]
Clip_cable.scad:
```

//CUSTOMIZER VARIABLES
/* [Basic] */
//Table thickness
Table_Thickness=28;//[10:100]
//Length
Length=30;//[20:50]
//Clip thickness
Clip_Thickness=3;//[3:6]
//Clip width
Clip_Width=15;//[10:30]
//Max cable diameter
Cable_Diameter=10;//[3:20]
//CUSTOMIZER VARIABLES END

$fs=0.2;
cube ([Clip_Thickness,Length,Clip_Width]);
translate ([Table_Thickness+Clip_Thickness+1,0,0]) cube ([Clip_Thickness,Length,Clip_Width]);
cube ([Table_Thickness+Clip_Thickness*3+Cable_Diameter,Clip_Thickness,Clip_Width]);
translate ([Clip_Thickness-0.3,Length-1,0]) cylinder(h=Clip_Width,r=1);
translate ([Table_Thickness+Clip_Thickness+1.3,Length-1,0]) cylinder(h=Clip_Width,r=1);
translate ([Table_Thickness+Clip_Thickness*3+Cable_Diameter,Length-Clip_Thickness/2,0]) cylinder(h=Clip_Width,r=Clip_Thickness/2);
translate ([Table_Thickness+Clip_Thickness*3+Cable_Diameter,Length/2,0]) difference () {
	cylinder(h=Clip_Width,r=Length/2);
	translate ([0,0,-0.5])cylinder(h=Clip_Width+1,r=Length/2-Clip_Thickness);
	translate ([-Length/2,-Length/2,-0.5]) cube([Length/2,Length,Clip_Width+1]);
}
```


[User]
Okay, I'd like to design a small, 3D-printable circular loom for making those rubber band bracelets, like the Rainbow Loom. I've been playing around with some settings in my own version but it feels a little clunky.

I'd like the design to be parametric, meaning I can easily adjust different aspects of the loom through variables. Here are the key features I want to be adjustable:

*   **Overall Size:**  I need to be able to set the outer diameter of the main ring.
*   **Inner Hole Size:**  There should be a hole in the middle that can be adjusted in size.
*   **Number of Pins:**  I need to be able to specify how many pins are arranged around the circle.
*   **Pin Notches:** I'd like to be able to add notches to each pin to help hold the rubber bands and adjust how many notches there are. Also, adjust the depth and height of each notch.
*   **Ring Height:**  The thickness of the main ring itself should be adjustable.
*   **Pin Height:**  The height of each pin sticking up from the ring should be adjustable.
*   **Pin Radius:** The radius of the pins themselves should be adjustable.
*    **Pin Wall Thickness:** I need the ability to adjust how thick the walls of the pins are.

I'd like the pins to be evenly spaced around the central hole. The notches should also be evenly spaced along the length of each pin.

I'd also like to be able to include a build plate for reference, like in my version. I use a Replicator 2, but it'd be good to have options for other printers or manual dimensions, where I can specify the x and y dimensions of the build plate.

I’m trying to keep my current design as simple as possible so I don't want the code to use any additional libraries beyond what is already included in standard OpenSCAD.

Could you generate an OpenSCAD file that includes these features, and makes the necessary variables available at the top of the file for easy customization?

[Assistant]
loom.scad:
```
include <utils/build_plate.scad>

//CUSTOMIZER VARIABLES

// Outer size
size = 15; //[5:60]

// Inner hole size
inner_size = 9; //[3:55]

// Number of pins
pins = 8; //  [3,4,5,6,7,8,9,10]

// notches on pins
notches = 1; // [0,1,2,3,4]

notch_depth = 1.1;

notch_height = 9;

// Ring thickness
ring_height = 4; // [2:6]

// Pin height
pin_height = 18; // [5:30]

pin_radius = 4;

// pin wall size in mm
pin_wall_thickness = 1;

//  This section is creates the build plates for scale
//  for display only, doesn't contribute to final object
build_plate_selector = 0; //[0:Replicator 2,1: Replicator,2:Thingomatic,3:Manual]

//  when Build Plate Selector is set to "manual" this controls the build plate x dimension
build_plate_manual_x = 100; //[100:400]

//  when Build Plate Selector is set to "manual" this controls the build plate y dimension
build_plate_manual_y = 100; //[100:400]

//CUSTOMIZER VARIABLES END

//  This is just a Build Plate for scale
build_plate(build_plate_selector,build_plate_manual_x,build_plate_manual_y);

module pin(rot) {
  rotate([0,0,rot]) {
    translate([inner_size + pin_radius, 0, (pin_height / 2)]) {
      difference() {
        scale([1,0.8,1]) cylinder(r=pin_radius, h=pin_height, center=true, $fs=1);

        // drill out the pin
        scale([1,0.8,1]) cylinder(r=pin_radius - pin_wall_thickness, h=pin_height * 1.1, center=true, $fs=1);

        // notches
        for (p=[notches/2 * -1 + 1:notches/2]) {
          translate([0, 0, p * ring_height]) {
            translate([1.5,0,0]) cube([notch_depth, 360/pins, notch_height], center=true);
          }
        }
      }
    }
  }
}

translate([0, 0, ring_height/2]) difference() {
  cylinder(r=size, h=ring_height, center=true);

  // cut out center hole
  cylinder(r=inner_size, h=ring_height + 2, center=true);
}

difference() {
  for (i=[1:pins]) {
    pin(i * (360 / pins));
  }

  // outer ring to shear off the pins
  translate([0,0,(ring_height + pin_height) / 2.2]) {
    difference() {
      cylinder(r=size*2, h=ring_height + pin_height, center=true);
      cylinder(r=size, h=ring_height + pin_height, center=true);
    }
  }
}

```


[User]
Okay, I'm looking for a parametric OpenSCAD design for a sword. I've already got a basic design in mind, and I'd like the AI to refine it and make it more robust using parameters. I'll give the core dimensions and parts in the request and would like the final file to use named parameters wherever possible to make it easily customizable.

Here's the basic structure I'm aiming for: The sword consists of a blade, a hilt, a handle, and some decorative elements.

1.  **Blade:** The blade should be a polyhedron, essentially a long, pointed shape. I'd like control over the blade's overall length (`blade_length`), the height of its sides (`blade_side_height`), and the height of the center ridge (`blade_center_height`). The blade should narrow towards the tip.

2.  **Handle:** The handle should be a simple rectangular prism. Its width (`handle_width`) and height (`handle_height`) should be configurable. I also want to define the length of the handle - it should be 40 units long, but I would prefer that to also be defined as a variable (`handle_length`).

3.  **Hilt:** The hilt is another rectangular prism, placed perpendicular to the handle. It needs a configurable width (`hilt_width`) and length (`hilt_length`).  It's centered on the end of the handle, intersecting the blade.

4.  **Decorations:** There are three decorative cube elements. One is located below the handle on the underside of the sword, and two flank the hilt.
    *   The bottom decoration needs a width and height (`large_decoration_width`, `large_decoration_height`) and is rotated 45 degrees.
    *   The hilt decorations also need width and height parameters (`small_decoration_width`, `small_decoration_height`) and are also rotated 45 degrees. These should be placed symmetrically on either side of the hilt where it meets the blade.

All of these parts should be connected to each other with the handle as the base.

I'd like the OpenSCAD file to include comments explaining each section of code and the purpose of each parameter. In particular, I'd like to see the code use a module or function for generating the blade to make it more easily adjusted. I don't need any specific modules or libraries, so I'm not asking for anything specific there. I want the design to be clean and easy to adjust for different sizes and proportions. Finally, make sure the code is formatted well to make it easily readable, especially with all the comments and parameter declarations I'm requesting.

Could you generate the OpenSCAD file based on these specifications?

[Assistant]
sword.scad:
```
large_decoration_height = 8; //[0:30]
small_decoration_height = 7; //[0:30]
large_decoration_width = 24; //[10:40]
small_decoration_width = 15; //[7:35]
handle_width = 15; //[5:25]
hilt_width = 10; //[5:25]
hilt_length = 70; //[30:130]
handle_height = 5; //[0:30]
blade_length = 120; //[20:250]
blade_side_height = 2; //[0:30]
blade_center_height = 6; //[0:30]

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

//bottom
	rotate([0,0,45])
	translate([-large_decoration_width/2,-large_decoration_width/2,0])
	cube(size=[large_decoration_width,large_decoration_width,large_decoration_height]);

//handle
translate([0,-handle_width/2,0])
cube(size = [40,handle_width,handle_height]);

//hilt
translate([40 - hilt_width/2,-hilt_length/2,0])
cube(size = [hilt_width,hilt_length,handle_height]);

//where the two parts of the handle intersect
translate([40,0,0])
	rotate([0,0,45])
	translate([-large_decoration_width/2,-large_decoration_width/2,0])
	cube(size=[large_decoration_width,large_decoration_width,large_decoration_height]);

//right of hilt
translate([40,-hilt_length/2,0])
	rotate([0,0,45])
	translate([-small_decoration_width/2,-small_decoration_width/2,0])
	cube(size=[small_decoration_width,small_decoration_width,small_decoration_height]);

//left of hilt
translate([40,hilt_length/2,0])
	rotate([0,0,45])
	translate([-small_decoration_width/2,-small_decoration_width/2,0])
	cube(size=[small_decoration_width,small_decoration_width,small_decoration_height]);

//blade
translate([40,0,0])
polyhedron(
	points=[
			//bottom
			[0,-7.5,0], //0
			[blade_length-7.5,-7.5,0], //1
			[blade_length-7.5,7.5,0], //2
			[0,7.5,0], //3
			[blade_length,0,0], //4
			//middle
			[0,-7.5,blade_side_height], //5
			[blade_length-7.5,-7.5,blade_side_height], //6
			[blade_length-7.5,7.5,blade_side_height], //7
			[0,7.5,blade_side_height], //8
			[blade_length,0,blade_side_height], //9
			//top
			[0,0,blade_center_height], //10
			[blade_length-7.5,0,blade_center_height] //11
			],
	triangles=[
			//~-~bottom~-~
			[0,1,2],
			[0,2,3],
			//bottom point
			[1,4,2],
			//~-~walls~-~
			//right
			[0,5,1],
			[5,6,1],
			//right point
			[1,6,4],
			[4,6,9],
			//left
			[8,3,2],
			[7,8,2],
			//left point
			[7,2,4],
			[7,4,9],
			//back
			[0,3,5],
			[5,3,8],
			//~-~top~-~
			//right
			[10,6,5],
			[11,6,10],
			//right point
			[11,9,6],
			//left
			[10,8,7],
			[7,11,10],
			//left point
			[11,7,9],
			//back
			[10,5,8]
			]

);

```