[User]
I'm looking to design a parametric model of the E3D Chimera dual hotend, similar to what's already out there, but I'd like it to be fully parametric and easily adjustable for different configurations. I'm going to be 3D printing this, so it needs to be printable without support if possible. I'd also like to be able to swap between v6 and volcano heater blocks.

Here's what I'm thinking:

*   **Core Chimera Block:** The main block should be parametric in terms of width, height, and depth, as well as the spacing between the two hotend mounting holes. I'd like to be able to adjust the chamfer on the edges, too. The fan mounting should be a separate, attached piece, also fully parametric.
*   **Heater Blocks:** I need to be able to select between standard E3D v6 heater blocks and volcano blocks, including the relevant cutouts and screw holes in the main chimera block. The heater blocks themselves should be detailed, but don't necessarily need to be separate files or editable beyond choosing to include a standard or volcano type. Make sure that all heater block and nozzle mounting holes are accurately positioned.
*   **Filament Paths:** The filament entry points need to be accurately positioned based on the selected heater block (v6 or volcano).  I'd like the option to adjust the diameter of the filament path opening if needed. It would also be great if the cooling slots are parametric too, allowing for adjustment of the slot spacing and depth.
*   **Mounting:** Mounting holes should be parametric, with options for both back and top mounting locations. It should be possible to adjust the diameter and placement of the mounting holes.

I want the design to be reasonably detailed, but not so detailed that it takes forever to render. I'd like to have a resolution parameter that I can adjust to trade off detail for render speed. Can you generate the necessary OpenSCAD files for this, and are there any external libraries that you plan to use? I'm generally familiar with OpenSCAD, so feel free to use more advanced techniques if needed.

[Assistant]
e3d_v6_chimera.scad:
```
/*
Name: E3D Chimera Dual v6 HotEnd in OpenSCAD
Author: Professional 3D - Jons Collasius from Germany/Hamburg
URL Professional 3D: http://professional3d.de

License: CC BY-NC-SA 4.0
License URL: https://creativecommons.org/licenses/by-nc-sa/4.0/

Creator of "E3D-v6 All Metal HotEnd": E3D Online - JR
URL E3D v6: http://wiki.e3d-online.com/wiki/E3D-v6_Documentation

Creator of "E3D Chimera": E3D-Online
URL E3D Chimera: http://e3d-online.com/Multi-Extrusion/Chimera
*/

// ######################################################################################################################
/* [Global] */

// resolution of round object. each line segment is fnr mm long. fnr = 1 crude and good for development (its faster), aim for fnr = 0.4 or smaller for a production render. smaller means more details (and a lot more time to render).
resolution = 0.25;
// detail level
detaillevel = 1; // [0:coarse render only outlines,1:fine render with all details]
//
withfan = 1; // [0:render without fan frame,1:render with fan frame]
// ######################################################################################################################
print_part();

// ######################################################################################################################
module print_part() {
	e3d();
}

// ######################################################################################################################
module e3d() {
	chimera_and_cyclops_body();
	for(i=[[9,0,0],[-9,0,0]]) translate(i) fncylinder(d=6.8,h=14);
	translate([9,0,-2]) rotate([180,0,0]) v6_heater(rotate=0);
	translate([-9,0,-2]) rotate([180,0,0]) v6_heater(rotate=180);
}

// ######################################################################################################################
module chimera_and_cyclops_body() {
	if (withfan==1) translate([-15,-12-10,0]) difference() {
		// fan
		chamfercube([30,9.5,30]);
		// fan holes
		if(detaillevel==1) {
			translate([15,0,15]) rotate([-90,0,0]) fncylinder(d=28,h=9.5,enlarge=1);
			translate([15,0,15]) for(i=[0:3]) rotate([0,i*90,0]) translate([12,0,12]) rotate([-90,0,0]) fncylinder(d=3.2,h=9.5,enlarge=1);
		}
	}
	translate([-15,-12,0]) difference() {
		union() {
			// main block
			chamfercube([30,18,30]);
		}
		if(detaillevel==1) {
			// filament
			for(i=[6,24]) translate([i,12,0]) {
				fncylinder(d=4.2,h=30,enlarge=1);
				translate([0,0,-1]) fncylinder(d=7,h=15);
				translate([0,0,13.995]) fncylinder(d=7,d2=4.2,h=1.005);
				translate([0,0,23.5]) fncylinder(d=8,h=7.5);
				translate([0,0,22.5]) fncylinder(d2=8,d=4.2,h=1.005);
			}
			// cooling slots
			slotspace=1.75;
			for(i=[0:6]) translate([-1,-1,1.75+i*(1.75+(16/7))]) chamfercube([32,7,(16/7)]);
			// back mount
			for(i=[[10.5,10,20],[19.5,10,20],[15,10,10]]) translate(i) rotate([-90,0,0]) fncylinder(d=3,h=9);
			// top mount
			for(i=[[6.5,3,22],[23.5,3,22],[15,15,22]]) translate(i) fncylinder(d=3,h=9);
			// back mount
			for(i=[[6,-1,3],[24,-1,3],[6,-1,11],[24,-1,11]]) translate(i) rotate([-90,0,0]) fncylinder(d=3,h=20);
			// fan mount
			for(i=[[3,-1,27],[27,-1,3]]) translate(i) rotate([-90,0,0]) fncylinder(d=2.8,h=7);
		}
	}
}

// ######################################################################################################################
module v6_heater(rotate=0) {
	rotate([0,0,rotate]) difference() {
		union() {
			translate([0,0,-3.1]) fncylinder(r=2,h=4.1);
			translate([-8,-4.5,0]) chamfercube([16,20,11.5],side=[0.4,0.4,0.4,0.4],top=[0.4,0.4,0.4,0.4],bottom=[0.4,0.4,0.4,0.4]);
			translate([0,0,10.5]) fncylinder(r=2.5,h=3);
			translate([0,0,12.5]) fncylinder(r=4.03,h=3,fn=6);
			translate([0,0,14.5]) fncylinder(r=3,r2=0.5,h=3);
		}
		if(detaillevel==1) {
			// heated block
			translate([-9,8,7.5]) rotate([0,90,0]) fncylinder(r=3.05, h=18);
			translate([-9,8,6.5]) cube([18,8.5,2]);
			translate([0,13,-1]) fncylinder(r=1.4, h=13.5);
			translate([4.45,-1,6.7]) rotate([0,90,0]) fncylinder(r=1.4, h=4.45);
			translate([3.45,-2.5,9.5]) rotate([0,90,0]) fncylinder(r=1.15, h=5.45);
		}
	}
}

// ######################################################################################################################
module volcano_heater(rotate=0) {
// 48.1
	rotate([0,0,rotate])	difference() {
		union() {
			translate([0,0,-3.1]) fncylinder(r=2,h=4.1);
			translate([-4.5,-4.5,1.5]) chamfercube([11.5,20,18.5],side=[0.4,0.4,0.4,0.4],top=[0.4,0.4,0.4,0.4],bottom=[0.4,0.4,0.4,0.4]);
			translate([-4.5,-4.5,0]) chamfercube([11.5,12,5],side=[0.4,0.4,0.4,0.4],top=[0.4,0.4,0.4,0.4],bottom=[0.4,0.4,0.4,0.4]);
			translate([0,0,19]) fncylinder(r=2.5,h=3);
			translate([0,0,21]) fncylinder(r=4.03,h=3,fn=6);
			translate([0,0,23]) fncylinder(r=3,r2=0.5,h=3);
		}
		if(detaillevel==1) {
			translate([-0.5,7.5,-1]) fncylinder(r=3.05, h=22);
			translate([-1.5,7.5,-1]) cube([2,8.5,22]);
			translate([-5.5,13,4.5]) rotate([0,90,0]) fncylinder(r=1.4, h=13.5);
			translate([-5.5,13,13.5]) rotate([0,90,0]) fncylinder(r=1.4, h=13.5);
			translate([-5.5,13,4.5]) rotate([0,90,0]) fncylinder(r=1.6, h=5.2);
			translate([-5.5,13,13.5]) rotate([0,90,0]) fncylinder(r=1.6, h=5.2);
			translate([8,4,11]) rotate([0,-90,0]) fncylinder(r=1.4, h=4.45);
			translate([8,4,14]) rotate([0,-90,0]) fncylinder(r=0.9, h=3);
			translate([8,4,14]) rotate([0,-90,0]) fncylinder(r=0.75, h=5.45);
		}
	}
}

// ######################################################################################################################
module chamfercube(xyz=[0,0,0],side=[0,0,0,0],top=[0,0,0,0],bottom=[0,0,0,0],x=false,y=false,z=false) {
	translate([x==true?-xyz[0]/2:0,y==true?-xyz[1]/2:0,z==true?-xyz[2]/2:0]) difference() {
		cube(xyz);
		if(side[0]>=0) translate([0,0,xyz[2]/2]) rotate([0,0,45]) cube([side[0]*2,side[0]*3,xyz[2]+2],center=true);
		if(side[1]>=0) translate([xyz[0],0,xyz[2]/2]) rotate([0,0,-45]) cube([side[1]*2,side[1]*3,xyz[2]+2],center=true);
		if(side[2]>=0) translate([xyz[0],xyz[1],xyz[2]/2]) rotate([0,0,45]) cube([side[2]*2,side[2]*3,xyz[2]+2],center=true);
		if(side[3]>=0) translate([0,xyz[1],xyz[2]/2]) rotate([0,0,-45]) cube([side[3]*2,side[3]*3,xyz[2]+2],center=true);
		if(top[0]>=0) translate([xyz[0]/2,0,xyz[2]]) rotate([-45,0,0]) cube([xyz[0]+2,top[0]*2,top[0]*3,],center=true);
		if(top[2]>=0) translate([xyz[0]/2,xyz[1],xyz[2]]) rotate([45,0,0]) cube([xyz[0]+2,top[2]*2,top[2]*3,],center=true);
		if(top[3]>=0) translate([0,xyz[1]/2,xyz[2]]) rotate([0,45,0]) cube([top[3]*2,xyz[1]+2,top[3]*3,],center=true);
		if(top[1]>=0) translate([xyz[0],xyz[1]/2,xyz[2]]) rotate([0,-45,0]) cube([top[1]*2,xyz[1]+2,top[1]*3,],center=true);
		if(bottom[0]>=0) translate([xyz[0]/2,0,0]) rotate([45,0,0]) cube([xyz[0]+2,bottom[0]*2,bottom[0]*3,],center=true);
		if(bottom[2]>=0) translate([xyz[0]/2,xyz[1],0]) rotate([-45,0,0]) cube([xyz[0]+2,bottom[2]*2,bottom[2]*3,],center=true);
		if(bottom[3]>=0) translate([0,xyz[1]/2,0]) rotate([0,-45,0]) cube([bottom[3]*2,xyz[1]+2,bottom[3]*3,],center=true);
		if(bottom[1]>=0) translate([xyz[0],xyz[1]/2,0]) rotate([0,45,0]) cube([bottom[1]*2,xyz[1]+2,bottom[1]*3,],center=true);
	}
}

// ######################################################################################################################
module fncylinder(r,r2,d,d2,h,fn,center=false,enlarge=0,pi=3.1415926536){
	translate(center==false?[0,0,-enlarge]:[0,0,-h/2-enlarge]) {
		if (fn==undef) {
			if (r2==undef && d2==undef) {
				cylinder(r=r?r:d?d/2:1,h=h+enlarge*2,$fn=floor(2*(r?r:d?d/2:1)*pi/resolution));
			} else {
				cylinder(r=r?r:d?d/2:1,r2=r2?r2:d2?d2/2:1,h=h+enlarge*2,$fn=floor(2*(r?r:d?d/2:1)*pi/resolution));
			}
		} else {
			if (r2==undef && d2==undef) {
				cylinder(r=r?r:d?d/2:1,h=h+enlarge*2,$fn=fn);
			} else {
				cylinder(r=r?r:d?d/2:1,r2=r2?r2:d2?d2/2:1,h=h+enlarge*2,$fn=fn);
			}
		}
	}
}
```


[User]
I'm looking to create a parametric 3D model of a dual-extrusion hotend, specifically based on the E3D Chimera design but with Volcano-style heater blocks. I'd like the model to be configurable in OpenSCAD.

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

*   **Overall Structure:** The design should have the core Chimera block, with two Volcano heater blocks and nozzles attached. I need to be able to control the spacing between the two Volcano blocks and the size of the main Chimera body.

*   **Chimera Block:**  The main block needs to have the characteristic cooling fins/slots, mounting holes (both on the top and back), and attachment points for the hotend heatbreaks. I need to be able to toggle the fan mount on or off. I also want to be able to control the overall dimensions and hole positions for things like the mounting holes and filament paths, as well as the dimensions and spacing of the cooling fins. I want to have the option to render only outlines, or with full details, as in the given code.

*   **Volcano Heater Blocks:** Each Volcano block should be accurately modeled with the basic form, including the heater cartridge and thermistor holes, as well as the nozzle mounting. The size of the heater block should also be parameterizable.

*  **Fan Mount:** The fan mount should be optional and include the mounting holes for the fan. It needs to be toggleable on and off.

*   **Parametric Control:** I'd like to control things like:
    *   Overall dimensions of the main Chimera block.
    *   Distance between the two Volcano heater blocks.
    *   Size and spacing of the cooling slots.
    *   Diameter and position of all mounting holes.
    *   Volcano block dimensions
    *   Resolution of curved surfaces.
    *   Toggle for including/excluding the fan mount and fan holes

*   **Libraries:** I'm not looking to include libraries beyond standard OpenSCAD functionality

Can you generate the necessary OpenSCAD file(s) to accomplish this? Please make sure the code is well-commented. I'd like to be able to easily modify and extend the design later.

[Assistant]
e3d_vulcano_chimera.scad:
```
/*
Name: E3D Chimera Dual Volcano HotEnd in OpenSCAD
Author: Professional 3D - Jons Collasius from Germany/Hamburg
URL Professional 3D: http://professional3d.de

License: CC BY-NC-SA 4.0
License URL: https://creativecommons.org/licenses/by-nc-sa/4.0/

Creator of "E3D Volcano": E3D Online - JR
URL E3D Volcano: http://wiki.e3d-online.com/wiki/E3D-v6_%28Volcano%29_Documentation

Creator of "E3D Chimera": E3D-Online
URL E3D Chimera: http://e3d-online.com/Multi-Extrusion/Chimera
*/

// ######################################################################################################################
/* [Global] */

// resolution of round object. each line segment is fnr mm long. fnr = 1 crude and good for development (its faster), aim for fnr = 0.4 or smaller for a production render. smaller means more details (and a lot more time to render).
resolution = 0.25;
// detail level
detaillevel = 1; // [0:coarse render only outlines,1:fine render with all details]
//
withfan = 1; // [0:render without fan frame,1:render with fan frame]
// ######################################################################################################################
print_part();

// ######################################################################################################################
module print_part() {
	e3d();
}

// ######################################################################################################################
module e3d() {
	chimera_and_cyclops_body();
	for(i=[[9,0,0],[-9,0,0]]) translate(i) fncylinder(d=6.8,h=14);
	translate([9,0,-2]) rotate([180,0,0]) volcano_heater(rotate=0);
	translate([-9,0,-2]) rotate([180,0,0]) volcano_heater(rotate=0);
}

// ######################################################################################################################
module chimera_and_cyclops_body() {
	if (withfan==1) translate([-15,-12-10,0]) difference() {
		// fan
		chamfercube([30,9.5,30]);
		// fan holes
		if(detaillevel==1) {
			translate([15,0,15]) rotate([-90,0,0]) fncylinder(d=28,h=9.5,enlarge=1);
			translate([15,0,15]) for(i=[0:3]) rotate([0,i*90,0]) translate([12,0,12]) rotate([-90,0,0]) fncylinder(d=3.2,h=9.5,enlarge=1);
		}
	}
	translate([-15,-12,0]) difference() {
		union() {
			// main block
			chamfercube([30,18,30]);
		}
		if(detaillevel==1) {
			// filament
			for(i=[6,24]) translate([i,12,0]) {
				fncylinder(d=4.2,h=30,enlarge=1);
				translate([0,0,-1]) fncylinder(d=7,h=15);
				translate([0,0,13.995]) fncylinder(d=7,d2=4.2,h=1.005);
				translate([0,0,23.5]) fncylinder(d=8,h=7.5);
				translate([0,0,22.5]) fncylinder(d2=8,d=4.2,h=1.005);
			}
			// cooling slots
			slotspace=1.75;
			for(i=[0:6]) translate([-1,-1,1.75+i*(1.75+(16/7))]) chamfercube([32,7,(16/7)]);
			// back mount
			for(i=[[10.5,10,20],[19.5,10,20],[15,10,10]]) translate(i) rotate([-90,0,0]) fncylinder(d=3,h=9);
			// top mount
			for(i=[[6.5,3,22],[23.5,3,22],[15,15,22]]) translate(i) fncylinder(d=3,h=9);
			// back mount
			for(i=[[6,-1,3],[24,-1,3],[6,-1,11],[24,-1,11]]) translate(i) rotate([-90,0,0]) fncylinder(d=3,h=20);
			// fan mount
			for(i=[[3,-1,27],[27,-1,3]]) translate(i) rotate([-90,0,0]) fncylinder(d=2.8,h=7);
		}
	}
}

// ######################################################################################################################
module volcano_heater(rotate=0) {
// 48.1
	rotate([0,0,rotate])	difference() {
		union() {
			translate([0,0,-3.1]) fncylinder(r=2,h=4.1);
			translate([-4.5,-4.5,1.5]) chamfercube([11.5,20,18.5],side=[0.4,0.4,0.4,0.4],top=[0.4,0.4,0.4,0.4],bottom=[0.4,0.4,0.4,0.4]);
			translate([-4.5,-4.5,0]) chamfercube([11.5,12,5],side=[0.4,0.4,0.4,0.4],top=[0.4,0.4,0.4,0.4],bottom=[0.4,0.4,0.4,0.4]);
			translate([0,0,19]) fncylinder(r=2.5,h=3);
			translate([0,0,21]) fncylinder(r=4.03,h=3,fn=6);
			translate([0,0,23]) fncylinder(r=3,r2=0.5,h=3);
		}
		if(detaillevel==1) {
			translate([-0.5,7.5,-1]) fncylinder(r=3.05, h=22);
			translate([-1.5,7.5,-1]) cube([2,8.5,22]);
			translate([-5.5,13,4.5]) rotate([0,90,0]) fncylinder(r=1.4, h=13.5);
			translate([-5.5,13,13.5]) rotate([0,90,0]) fncylinder(r=1.4, h=13.5);
			translate([-5.5,13,4.5]) rotate([0,90,0]) fncylinder(r=1.6, h=5.2);
			translate([-5.5,13,13.5]) rotate([0,90,0]) fncylinder(r=1.6, h=5.2);
			translate([8,4,11]) rotate([0,-90,0]) fncylinder(r=1.4, h=4.45);
			translate([8,4,14]) rotate([0,-90,0]) fncylinder(r=0.9, h=3);
			translate([8,4,14]) rotate([0,-90,0]) fncylinder(r=0.75, h=5.45);
		}
	}
}

// ######################################################################################################################
module chamfercube(xyz=[0,0,0],side=[0,0,0,0],top=[0,0,0,0],bottom=[0,0,0,0],x=false,y=false,z=false) {
	translate([x==true?-xyz[0]/2:0,y==true?-xyz[1]/2:0,z==true?-xyz[2]/2:0]) difference() {
		cube(xyz);
		if(side[0]>=0) translate([0,0,xyz[2]/2]) rotate([0,0,45]) cube([side[0]*2,side[0]*3,xyz[2]+2],center=true);
		if(side[1]>=0) translate([xyz[0],0,xyz[2]/2]) rotate([0,0,-45]) cube([side[1]*2,side[1]*3,xyz[2]+2],center=true);
		if(side[2]>=0) translate([xyz[0],xyz[1],xyz[2]/2]) rotate([0,0,45]) cube([side[2]*2,side[2]*3,xyz[2]+2],center=true);
		if(side[3]>=0) translate([0,xyz[1],xyz[2]/2]) rotate([0,0,-45]) cube([side[3]*2,side[3]*3,xyz[2]+2],center=true);
		if(top[0]>=0) translate([xyz[0]/2,0,xyz[2]]) rotate([-45,0,0]) cube([xyz[0]+2,top[0]*2,top[0]*3,],center=true);
		if(top[2]>=0) translate([xyz[0]/2,xyz[1],xyz[2]]) rotate([45,0,0]) cube([xyz[0]+2,top[2]*2,top[2]*3,],center=true);
		if(top[3]>=0) translate([0,xyz[1]/2,xyz[2]]) rotate([0,45,0]) cube([top[3]*2,xyz[1]+2,top[3]*3,],center=true);
		if(top[1]>=0) translate([xyz[0],xyz[1]/2,xyz[2]]) rotate([0,-45,0]) cube([top[1]*2,xyz[1]+2,top[1]*3,],center=true);
		if(bottom[0]>=0) translate([xyz[0]/2,0,0]) rotate([45,0,0]) cube([xyz[0]+2,bottom[0]*2,bottom[0]*3,],center=true);
		if(bottom[2]>=0) translate([xyz[0]/2,xyz[1],0]) rotate([-45,0,0]) cube([xyz[0]+2,bottom[2]*2,bottom[2]*3,],center=true);
		if(bottom[3]>=0) translate([0,xyz[1]/2,0]) rotate([0,-45,0]) cube([bottom[3]*2,xyz[1]+2,bottom[3]*3,],center=true);
		if(bottom[1]>=0) translate([xyz[0],xyz[1]/2,0]) rotate([0,45,0]) cube([bottom[1]*2,xyz[1]+2,bottom[1]*3,],center=true);
	}
}

// ######################################################################################################################
module fncylinder(r,r2,d,d2,h,fn,center=false,enlarge=0,pi=3.1415926536){
	translate(center==false?[0,0,-enlarge]:[0,0,-h/2-enlarge]) {
		if (fn==undef) {
			if (r2==undef && d2==undef) {
				cylinder(r=r?r:d?d/2:1,h=h+enlarge*2,$fn=floor(2*(r?r:d?d/2:1)*pi/resolution));
			} else {
				cylinder(r=r?r:d?d/2:1,r2=r2?r2:d2?d2/2:1,h=h+enlarge*2,$fn=floor(2*(r?r:d?d/2:1)*pi/resolution));
			}
		} else {
			if (r2==undef && d2==undef) {
				cylinder(r=r?r:d?d/2:1,h=h+enlarge*2,$fn=fn);
			} else {
				cylinder(r=r?r:d?d/2:1,r2=r2?r2:d2?d2/2:1,h=h+enlarge*2,$fn=fn);
			}
		}
	}
}
```


[User]
I'm looking to design a parametric model of the E3D Cyclops hotend in OpenSCAD. I've seen a few versions online, but I want one that's highly configurable. I'm not worried about performance, but I do want good quality output.

Specifically, I need the following:

*   **Main Body:** A central block with a defined width, height, and depth. It should have chamfered edges and an option to control the chamfer size on the sides, top, and bottom individually, even if the sides and top/bottom are configured the same.
*   **Filament Paths:** Two separate cylindrical paths running through the main block, representing the filament inlets. These should have adjustable diameters, and positions in the X direction from the center of the block. These paths should include a conical transition down to the nozzle, and then another conical transition into the main filament path. All these cones should be independently sized and placed relative to the main cylinder.
*   **Cooling Slots:** Several slots cut into the side of the main block for cooling. The number of slots, their width, depth and the spacing between them should all be parameters. I'm thinking of having the slots at a constant offset from the bottom face, so they go up the side of the block.
*   **Mounting Points:** I need various mounting points on the model. These include:
    *   Back mount points - cylinders for screws that will mount to the printer, located along the back face, and some that come from the back face further to the outside.
    *   Top mount points - cylinders located on the top surface.
    *   Fan mounts - cylinders for mounting the cooling fan at the front, one on either side of the main block at the front.
*   **Heater Blocks:** These will be attached to the filament paths at the bottom, and should be mirrored on the X axis, but be independently sized in terms of height. They will transition from a cylinder that surrounds the end of the filament path to a rectangular block. This transition should have configurable angle and height. They should also have the following detail:
    *   Grooves cut into the sides, top and bottom. The grooves on the top/bottom should be continuous between the left and right block
    *   Mounting points on the sides, for mounting the heater cartridge
    *   A mounting point for a thermistor.

*   **Fan Frame:** The fan frame should be configurable to be included or not. It is a rectangular block with holes for mounting screws and a large circular cutout for the fan.

*   **Resolution:** I want to control the resolution of the round objects, allowing for quick previews with low resolution and high-quality renders with high resolution. This should be done by specifying the distance between each point, rather than an $fn value.

*   **Detail Level:** A parameter to toggle between a coarse render (outlines only) and a fine render (with all details) to make rendering faster.

The whole model should be parametrically driven, so I can easily adjust all dimensions and positions.

I am not planning to use any external libraries.

[Assistant]
e3d_cyclops.scad:
```
/*
Name: E3D Cyclops in OpenSCAD
Author: Professional 3D - Jons Collasius from Germany/Hamburg
URL Professional 3D: http://professional3d.de

License: CC BY-NC-SA 4.0
License URL: https://creativecommons.org/licenses/by-nc-sa/4.0/

Creator of "E3D Cyclops": E3D-Online
URL E3D Cyclops: http://e3d-online.com/Cyclops
*/

// ######################################################################################################################
/* [Global] */

// resolution of round object. each line segment is fnr mm long. fnr = 1 crude and good for development (its faster), aim for fnr = 0.4 or smaller for a production render. smaller means more details (and a lot more time to render).
resolution = 0.5;
// detail level
detaillevel = 1; // [0:coarse render only outlines,1:fine render with all details]
//
withfan = 1; // [0:render without fan frame,1:render with fan frame]
// ######################################################################################################################
print_part();

// ######################################################################################################################
module print_part() {
	e3d();
}

// ######################################################################################################################
module e3d() {
	chimera_and_cyclops_body();
	translate([0,0,-3.1]) rotate([180,0,0]) cyclops_heater(rotate=180);
}

// ######################################################################################################################
module chimera_and_cyclops_body() {
	if (withfan==1) translate([-15,-12-10,0]) difference() {
		// fan
		chamfercube([30,9.5,30]);
		// fan holes
		if(detaillevel==1) {
			translate([15,0,15]) rotate([-90,0,0]) fncylinder(d=28,h=9.5,enlarge=1);
			translate([15,0,15]) for(i=[0:3]) rotate([0,i*90,0]) translate([12,0,12]) rotate([-90,0,0]) fncylinder(d=3.2,h=9.5,enlarge=1);
		}
	}
	translate([-15,-12,0]) difference() {
		union() {
			// main block
			chamfercube([30,18,30]);
		}
		if(detaillevel==1) {
			// filament
			for(i=[6,24]) translate([i,12,0]) {
				fncylinder(d=4.2,h=30,enlarge=1);
				translate([0,0,-1]) fncylinder(d=7,h=15);
				translate([0,0,13.995]) fncylinder(d=7,d2=4.2,h=1.005);
				translate([0,0,23.5]) fncylinder(d=8,h=7.5);
				translate([0,0,22.5]) fncylinder(d2=8,d=4.2,h=1.005);
			}
			// cooling slots
			slotspace=1.75;
			for(i=[0:6]) translate([-1,-1,1.75+i*(1.75+(16/7))]) chamfercube([32,7,(16/7)]);
			// back mount
			for(i=[[10.5,10,20],[19.5,10,20],[15,10,10]]) translate(i) rotate([-90,0,0]) fncylinder(d=3,h=9);
			// top mount
			for(i=[[6.5,3,22],[23.5,3,22],[15,15,22]]) translate(i) fncylinder(d=3,h=9);
			// back mount
			for(i=[[6,-1,3],[24,-1,3],[6,-1,11],[24,-1,11]]) translate(i) rotate([-90,0,0]) fncylinder(d=3,h=20);
			// fan mount
			for(i=[[3,-1,27],[27,-1,3]]) translate(i) rotate([-90,0,0]) fncylinder(d=2.8,h=7);
		}
	}
}

// ######################################################################################################################
module cyclops_heater(rotate=0) {
	rotate([0,0,rotate])	difference() {
		union() {
			for(i=[-9,9]) translate([i,0,0]){
				translate([0,0,-1.5]) fncylinder(d=6,h=1.505);
				translate([0,0,-3.605]) fncylinder(d=2.95,h=2.11);
				translate([0,0,-17.1]) fncylinder(d=6.9,h=13.5);
			}
			translate([-16,-10,0]) chamfercube([32,14,13.5],side=[0.4,0.4,0.4,0.4],top=[0.4,0.4,0.4,0.4],bottom=[0.4,0.4,0.4,0.4]);
			translate([0,0,13.7]) fncylinder(d=6.928,h=2,fn=6);
			translate([0,0,15.695]) fncylinder(r=1.8,r2=0.4,h=1.005);
			translate([0,0,13.495]) fncylinder(r=2.5,h=0.201);
		}
		if(detaillevel==1) {
			for(i=[-9,9]) translate([i,0,0]) for(i1=[-1,1]) {
				translate([i1*3,0,-1.6]) chamfercube([1,7,1.6],x=true,y=true);
			}
			translate([0,0,7.5]) {
				rotate([0,90,0]) fncylinder(d=1.75,h=32,center=true,enlarge=1);
				for(i=[-1,1]) translate([i*16,0,0]) rotate([0,90,0]) {
					fncylinder(d=4,h=0,center=true,enlarge=4);
					fncylinder(d=3,h=0,center=true,enlarge=5.4);
				}
			}
			translate([0,-6,8]) rotate([0,90,0]) fncylinder(d=6.1,h=32,center=true,enlarge=1);
			translate([0,-6,8]) fncylinder(d=3,h=7);
			translate([0,2,5.5]) rotate([-90,0,0]) fncylinder(d=2,h=3);
			translate([0,-0.5,5.5]) rotate([-90,0,0]) fncylinder(d=1.5,h=5.5);
			translate([-2.6,0.5,4.4]) rotate([-90,0,0]) fncylinder(d=3,h=4.5);
		}
	}
}

// ######################################################################################################################
module chamfercube(xyz=[0,0,0],side=[0,0,0,0],top=[0,0,0,0],bottom=[0,0,0,0],x=false,y=false,z=false) {
	translate([x==true?-xyz[0]/2:0,y==true?-xyz[1]/2:0,z==true?-xyz[2]/2:0]) difference() {
		cube(xyz);
		if(side[0]>=0) translate([0,0,xyz[2]/2]) rotate([0,0,45]) cube([side[0]*2,side[0]*3,xyz[2]+2],center=true);
		if(side[1]>=0) translate([xyz[0],0,xyz[2]/2]) rotate([0,0,-45]) cube([side[1]*2,side[1]*3,xyz[2]+2],center=true);
		if(side[2]>=0) translate([xyz[0],xyz[1],xyz[2]/2]) rotate([0,0,45]) cube([side[2]*2,side[2]*3,xyz[2]+2],center=true);
		if(side[3]>=0) translate([0,xyz[1],xyz[2]/2]) rotate([0,0,-45]) cube([side[3]*2,side[3]*3,xyz[2]+2],center=true);
		if(top[0]>=0) translate([xyz[0]/2,0,xyz[2]]) rotate([-45,0,0]) cube([xyz[0]+2,top[0]*2,top[0]*3,],center=true);
		if(top[2]>=0) translate([xyz[0]/2,xyz[1],xyz[2]]) rotate([45,0,0]) cube([xyz[0]+2,top[2]*2,top[2]*3,],center=true);
		if(top[3]>=0) translate([0,xyz[1]/2,xyz[2]]) rotate([0,45,0]) cube([top[3]*2,xyz[1]+2,top[3]*3,],center=true);
		if(top[1]>=0) translate([xyz[0],xyz[1]/2,xyz[2]]) rotate([0,-45,0]) cube([top[1]*2,xyz[1]+2,top[1]*3,],center=true);
		if(bottom[0]>=0) translate([xyz[0]/2,0,0]) rotate([45,0,0]) cube([xyz[0]+2,bottom[0]*2,bottom[0]*3,],center=true);
		if(bottom[2]>=0) translate([xyz[0]/2,xyz[1],0]) rotate([-45,0,0]) cube([xyz[0]+2,bottom[2]*2,bottom[2]*3,],center=true);
		if(bottom[3]>=0) translate([0,xyz[1]/2,0]) rotate([0,-45,0]) cube([bottom[3]*2,xyz[1]+2,bottom[3]*3,],center=true);
		if(bottom[1]>=0) translate([xyz[0],xyz[1]/2,0]) rotate([0,45,0]) cube([bottom[1]*2,xyz[1]+2,bottom[1]*3,],center=true);
	}
}

// ######################################################################################################################
module fncylinder(r,r2,d,d2,h,fn,center=false,enlarge=0,pi=3.1415926536){
	translate(center==false?[0,0,-enlarge]:[0,0,-h/2-enlarge]) {
		if (fn==undef) {
			if (r2==undef && d2==undef) {
				cylinder(r=r?r:d?d/2:1,h=h+enlarge*2,$fn=floor(2*(r?r:d?d/2:1)*pi/resolution));
			} else {
				cylinder(r=r?r:d?d/2:1,r2=r2?r2:d2?d2/2:1,h=h+enlarge*2,$fn=floor(2*(r?r:d?d/2:1)*pi/resolution));
			}
		} else {
			if (r2==undef && d2==undef) {
				cylinder(r=r?r:d?d/2:1,h=h+enlarge*2,$fn=fn);
			} else {
				cylinder(r=r?r:d?d/2:1,r2=r2?r2:d2?d2/2:1,h=h+enlarge*2,$fn=fn);
			}
		}
	}
}
```


[User]
Hey, I'm looking to design a kind of plug/bearing thing for some projects I'm working on, and I could really use some help with OpenSCAD.

Here's the basic idea: it should be a cylindrical shape with a few distinct sections. The bottom will be a short, solid cylinder with a specified diameter and height. Then, there's a longer, hollow cylindrical middle section, with an inner and outer diameter, a height, and a groove cut through the side. Finally, a top part that transitions from the middle section, and can be either a flat or pointy top.

Specifically, I need parameters for:

*   **Base:**
    *   `baseHeight` (the height of the bottom cylinder).
    *   `baseDiameter` (the diameter of the bottom cylinder).
*   **Middle:**
    *   `midInnerDiameter` (the inner diameter of the middle cylinder).
    *   `midOuterDiameter` (the outer diameter of the middle cylinder).
    *   `midHeight` (the height of the middle cylinder).
    *   `cutWidth` (the width of the groove cut through the middle).
    *   `cutHeight` (the height at which the groove cut begins).
    *   `cutFillet` (a boolean, 1 for a fillet in the cut-out, 0 for no fillet).
    *   `solidBase` (a boolean, 1 for a solid base, 0 for a hollow base - in the middle).
    *   `baseFillet` (a boolean, 1 for a fillet where the base connects to the middle section, 0 for no fillet - only available if `solidBase` is 1).
*   **Top:**
    *   `topDiameter` (the outer diameter of the top cylinder).
    *   `angleDownSide` (the angle of the lower sides of the top part, in degrees).
    *   `angleUpside` (the angle of the top sides of the top part, in degrees).
    *   `pointyTop` (a boolean, 1 for a pointy top, 0 for a flat top).
    *  `removeSides` (a boolean, 1 to remove the sides, which makes it easier to put into a hole, 0 for no removal).

I would like to be able to turn various fillets on and off, as well as the hollowness of the base and the pointiness of the top. I will also want to remove the sides of the top for certain situations.

The design also needs to be smooth, so I think a `$fn` of 50 should be a good baseline, but it should be changeable. It would be great if you could write the whole thing as a single parametric OpenSCAD file. I'm not asking you to generate any documentation or anything, but I want to be able to change those parameters.

Thanks a bunch!

[Assistant]
plug.scad:
```
//  Measure for the smoothness
$fn = 50;

baseHeight = 1;
baseDiameter = 5.5;
midInnerDiameter = 2.5;
midOuterDiameter = 4.5;
midHeight = 10.5;

//  The extra height and with of the top
topDiameter = 5.5;
angleDownSide = 45;
angleUpside = 30;

//  The width of the cut through the middle
cutWidth = 1;

//  The height at which the cut begins
cutHeight = 3;

//  Create a fillet in the cut out for strenght, 1 for yes, 0 for no
cutFillet = 1;  //  [1, 0]

//  To make the bottom hollow, 1 for yes, 0 for no
solidBase = 1;    //  [1, 0]

//  To create a fillet between the base and the middle part, 1 for yes, 0 for no. Only available if solidBase = 1
baseFillet = 1;   //  [1, 0]

//  To make the top pointy
pointyTop = 1;      //  [1, 0]

//  To remove the side bits of the top, makes it easier to put it through a hole, 1 for yes, 0 for no
removeSides = 0;    //  [1, 0]

module base(rOuter, rInner, height, solid){
    difference(){
        cylinder(r = baseDiameter / 2, h = height);
        if (solid == 0){
            translate(  [   0,
                            0,
                            -0.1]){
                cylinder(r = rInner, h = height + 0.2);
            }
        }
    }
}

module middle(rInner, rOuter, height, cutHeight, cutWidth, cutFillet, baseFillet, solidBase){
    difference(){
        //  Make the tube shape
        cylinder(r = rOuter, h = height);

        //  Cut out the base with optional fillet
        if(baseFillet == 1 && solidBase == 1){
            translate(  [   0,
                            0,
                            rInner  ]){
                sphere(r = rInner);
                cylinder(r = rInner, h = height);
                            }
        }

        //  No base fillet
        else{
            translate(  [   0,
                            0,
                            -0.1    ]){
                cylinder(r = rInner, h = height + 0.2);
            }
        }

        //  Cut out the groove with optional fillet
        translate(  [   -rOuter,
                        -cutWidth / 2,
                        cutHeight]){
            if(cutFillet == 1){
                translate(  [   -0.1,
                                1/2 * cutWidth,
                                1/2 * cutWidth  ]){
                    rotate( [   0,
                                90,
                                0   ]){
                        cylinder(r = cutWidth / 2, h = height + 0.2);
                    }
                }
            }
            translate(  [   -0.1,
                            0,
                            1/2 * cutWidth * cutFillet ]){
                cube(   [   2 * rOuter + 0.2,
                            cutWidth,
                            height  ]);
            }
        }
    }
}

module top(rInner, rMid, rOuter, cutWidth, angleDown, angleUp, pointy, removeSides){
    delta = 0.000000000000001;

    //  Determine scale factor for morfing top in shape
    scaleFactor = (rMid / rOuter - 1) * removeSides + 1;

    bottomHeight = (rOuter - rMid) / tan(angleDown) - delta;

    //  Calculating topheight and implementing (optional) pointy top
    topRadius = (rInner - rMid) * pointy + rMid;
    topHeight = (rOuter - topRadius) / tan(angleUp) - delta;

    difference(){
        union(){
            hull(){
                cylinder(r = rMid, h = delta);
                translate(  [   0,
                                0,
                                bottomHeight]){
                    scale(  [   scaleFactor,
                                1,
                                1]){
                        cylinder(r = topDiameter / 2, h = delta);
                    }
                    translate(  [   0,
                                    0,
                                    topHeight]){
                        cylinder(r = topRadius, h = delta);
                    }
                }
            }
        }

        translate(  [   -rOuter - 0.1,
                        -1/2 * cutWidth,
                        -0.1    ]){
            cube(   [   2 * rOuter + 0.2,
                        cutWidth,
                        bottomHeight + topHeight + 0.2   ]   );
        }
        translate(  [   0,
                        0,
                        -0.1    ]){
            cylinder(r = rInner, h = bottomHeight + topHeight + 0.2);
        }
    }
}

module plug(){
    union(){
        //  The base
        base(baseDiameter / 2, midInnerDiameter / 2, baseHeight, solidBase);

        //  The middle part
        translate(  [   0,
                        0,
                        baseHeight] ){
            middle(midInnerDiameter / 2, midOuterDiameter / 2, midHeight, cutHeight, cutWidth, cutFillet, baseFillet, solidBase);
        }

        //  The top part
        translate(  [   0,
                        0,
                        baseHeight + midHeight] ){
            top(midInnerDiameter / 2, midOuterDiameter / 2, topDiameter / 2, cutWidth, angleDownSide, angleUpside, pointyTop, removeSides);
        }
    }
}

plug();
```


[User]
Okay, I'm looking to design a parametric coffee mug in OpenSCAD, and I'd like your help with the code. I've been messing around with some basic shapes, but I'd like a more robust and configurable design.

Here's what I'm envisioning:

1.  **Main Body:** The mug should be generally cylindrical, but with rounded bottom edges. I'd like to control the overall height, the main radius (width) of the cup, the wall thickness, and the radius of the bottom rounding.

2.  **Rounded Rim:** The top rim should have a nice rounded edge, kind of like what you'd see on a typical ceramic mug. The amount of rounding on the rim should be controlled by the wall thickness.

3.  **Handle:** The handle should be a torus-like shape, attached to the side of the mug. I need to control the minor radius of the handle (its thickness), and I'd like to scale it a little in the Z direction to make it a bit more oval-shaped, like a typical handle. I also want to control the X-Z ratio of the handle's minor radius, similar to how it was changed in the provided example. I'd like to be able to position the handle along the height of the cup, with its center point along the center of the cup's height. The handle should be cut out of the main body, not just an added piece.

4.  **Parametric Design:** I'd like all the key dimensions – cup height, cup radius, wall thickness, bottom rounding radius, handle thickness, handle z-scale, and handle x-z scale – to be parameters, so I can easily adjust them. The $fn setting should also be a parameter, allowing for both smooth and faceted versions, for example, by setting it to 6 to get a hexagonal cup.

5. **Handle positioning:** The handle's X position should be tangent to the cup, as if it were simply grafted onto the cup body. This means the handle's base circle's center is on the mug's outside radius, not along the 0,0 point.

I think the approach from the example code using `difference()` to carve out the mug body from two cylinders and the torus handle from another primitive is a good idea.

I don't want to use any external libraries for this (like BOSL or MCAD). I want to keep it all basic OpenSCAD primitives.

Could you generate the OpenSCAD code for this parametric mug?

Thank you!

[Assistant]
CoffeeMug2.scad:
```
// "Fragments" or fineness. Higher = smoother
$fn = 60;
// Rounding of the bottom, radius in mm.
cornd=10;  //
// Height of the cup in mm
ovrht = 115;
// Major radius of the cup in mm.
cupwd = 41;
// Width of the wall  in mm.
cupwal = 4;
// Thickness of handle in mm.
handlr = 5.25;
cornerd = min(cornd,cupwd/2); // Bad things happen if you try to round the bottom too much!
cupht = ovrht - cornerd - cupwal*.5; // cup height adjusted for other features
/* The next functions make a primitive coffee cup from two cylinders and a torus.  */
module cupprim(h1,r1,rc) {
 cylinder(h1,r1,r1); rotate_extrude (convexity=10) translate ([r1-rc,0,-rc/2]) circle (r=rc); translate ([0,0,-rc]) cylinder(rc,r1-rc,r1-rc);
}
// This makes the top rim rounded.
translate ([0,0,cupht]) rotate_extrude (convexity=10) translate([cupwd-cupwal/2,0,0]) circle (r=cupwal/2);
/* scale([1,1,.5]) sphere(r1);
}*/
/* Next, we use difference() function to subtract a smaller primitive from a bigger one to make a shell.*/
difference () {cupprim(cupht,cupwd,cornerd); translate ([0,0,cupwal]) cupprim(cupht+.1,cupwd-cupwal,cornerd);
    }
// Let's make the handle a torus
difference () {
     rotate (a=90, v=[1,0,0]) {
    translate
        ([cupwd,.5*cupht,0]) scale([.75,1,1.75]) rotate_extrude(convexity=12)    translate([.4*cupht,0,0]) circle(r=handlr) ;
}       translate ([0,0,cupwal]) cupprim(cupht,cupwd-cupwal,cornerd);
}
```


[User]
I need a parametric OpenSCAD design for a double T-bracket. Basically, I want two T-brackets joined by a connecting section, allowing me to mount two parallel extrusions closer than the standard 3x extrusion width spacing.

Here are the key parameters I need to control:

*   **`spacing`**: This is the distance between the center points of the two T-brackets. I need to be able to adjust this to go from having the Ts almost touching (flush, spacing = 0) to arbitrarily far apart.
*   **`ext_size`**: This will define the size of the extrusions. For reference, I'm targeting 15mm extrusions like Misumi or OpenBeam. So the T-brackets themselves will be scaled relative to this `ext_size`.
*   **`thickness`**: The thickness of the bracket material.
*   **`m3_hole`**: The diameter for the mounting holes, using M3 bolts.
*   **`corner_radius`**:  I want rounded corners on all the rectangular parts, so I need a radius parameter.

The design should consist of two standard T shapes, connected by a rectangular piece.

Each T will have the standard three arms. Each arm has mounting holes at its center.  Specifically, each T will have 2 rows of holes for mounting to the extrusion in the two directions, these are aligned along the center of the thickness. The T's arms should extend the width of the extrusion. The connecting piece should have its own mounting hole in the center, but *only* when the `spacing` is less than 37. I'd like a through hole to make sure the screws are always long enough. It should also have the same thickness as the rest of the bracket. The overall form of the design should match the attached code, although you should generate entirely new code and use your own abstractions as you see fit.

I want to be able to easily adjust all of these parameters. I'm also keen to have all the dimensions be derived from the `ext_size` rather than hardcoded. I think all this can be done in a single `.scad` file. Could you generate the design and send the code? I'm not looking for any libraries, unless it might simplify the design.

[Assistant]
double_T.scad:
```
//spacing between T centers
spacing = 30;
//15mm for misumi and Openbeam
ext_size = 15;
//thickness of piece
thickness = 2;

m3_hole = 3.5;
corner_radius = 4;

difference() {
  union() {
    difference() {
      union() {
        T();
        translate([spacing,0,0]) T();
        translate([corner_radius,ext_size*2])
        cube([ext_size*3+spacing-corner_radius*2,ext_size,thickness]);
      }
      T_holes();
      translate([spacing,0,0]) T_holes();
    }
    translate([spacing/2+ext_size*1.5,ext_size*2.5,thickness/2])
    if(spacing<37) {
      cylinder(d=ext_size-m3_hole,h=thickness,center=true);
    }
  }
  translate([spacing/2+ext_size*1.5,ext_size*2.5,thickness/2])
  cylinder(d=m3_hole,h=3*thickness,center=true,$fn=30);
}

module T_holes(){
  for (ii = [ext_size/2:ext_size:3*ext_size]) {
    translate([ii,2.5*ext_size ,0 ])
    cylinder(d=m3_hole,h=thickness*3,center=true,$fn=30);
  }
  for (ii = [ext_size/2:ext_size:3*ext_size]) {
    translate([1.5*ext_size,ii ,0 ])
    cylinder(d=m3_hole,h=thickness*3,center=true,$fn=30);
  }
}
module T() {
  difference() {
    union() {
      translate([0,2*ext_size] )
      v_rounded_cube([3*ext_size,ext_size,thickness],corner_radius);
      translate([(ext_size - corner_radius),corner_radius,0])
      v_rounded_cube([ext_size+corner_radius*2,ext_size*3-corner_radius,thickness],corner_radius);
      translate([(ext_size ),0,0])
      v_rounded_cube([ext_size,ext_size*3,thickness],corner_radius);
    }

    translate([-corner_radius,-corner_radius ])
    v_rounded_cube([ext_size+corner_radius,ext_size*2+corner_radius,thickness],corner_radius);
    translate([2*ext_size,-corner_radius ])
    v_rounded_cube([ext_size+corner_radius,ext_size*2+corner_radius,thickness],corner_radius);
  }
}

module v_rounded_cube(xyz,r,$fn=30) {
  z = xyz[2];
  y = xyz[1];
  x = xyz[0];
  translate([r,r])
  hull() {
    cylinder(h=z,r=r);
    translate([0,y-2*r])
    cylinder(h=z,r=r);
    translate([x-2*r,0])
    cylinder(h=z,r=r);
    translate([x-2*r,y-2*r])
    cylinder(h=z,r=r);
  }
}
```


[User]
I'd like to design a parametric box with a hinged lid, and I'd like the design to be customizable through OpenSCAD's customizer. I've got a pretty clear idea of what I want, and it's based on a design I've seen before, but I want it to be completely from scratch - not just tweaks to an existing file.

Here's what I need:

**Overall Box Dimensions:**

*   **`length`**: Total length of the box from left to right.
*   **`width`**: Total width of the box from front to back.
*   **`topHeight`**: Height of the lid.
*   **`botHeight`**: Height of the bottom part of the box.
*   **`wall`**: Thickness of the left, right, and front walls.
*   **`floor`**: Thickness of the floor and roof of the box.
*   **`backwall`**: Thickness of the back wall, specifically where the hinge will be.

**Magnet Cutouts:**

*   **`maLength`**: Length of the magnet cutout.
*   **`maWidth`**: Width (depth) of the magnet cutout.
*   **`maHeight`**: Height of the magnet cutout.
*   **`maSpacer`**: The thickness of material surrounding the magnet cutout.

**Hinge Parameters:**

*   **`hiHeight`**: Height of the hinge pin relative to the bottom of the box.
*   **`hiLength`**: Length of the hinge.
*   **`hiOffs`**: Position of the hinge along the length of the box.
*   **`hiDia`**: Diameter of the hinge pin.
*   **`hiHingSpac`**: Additional space for the hinge to move freely.

**Chamfered Edges:**

*   **`CHAMFEREDGES`**: A boolean to enable/disable chamfered edges.
*   **`CHAMFERLEN`**: Length of the chamfered edges.

**Other:**

*   I need a variable called `part` that lets the user choose if they want to see the `"bottom"`, `"top"`, or `"both"` parts of the box. It needs to work properly in the Customizer.

I'd like the design to have a recessed grip cut out in the middle of the front face of both the bottom and lid. I do not need any specific libraries, but I do need it to use `CYLPREC` to control the polygon count for cylinders and spheres. The design should generate two separate parts: the bottom box and the lid, with the hinge integrated into the top and bottom parts of the box. When "both" is selected for the `part` variable, it should show the box closed and the lid rotated at an angle, not simply placed in alignment.

Can you generate the necessary OpenSCAD file(s) for this?

[Assistant]
box_customizer.scad:
```
//
// PARAMETRIC PENCIL BOX, V1.1
// FMMT666(ASkr) 04/2013
//

// - changes V1.1:
//  - added variable hinge length:
//    "hiHeight" now specifies the height of the hinge pin, relative to the bottom.

// HINTS:
// - Always start with hiHeight set to 0.
//   If this parameter is larger than "botHeight", things might look strange ;)

/* [Main Box] */

// Which part would you like to see?
part = "both"; // [bottom:Bottom,top:Top,both:Both]

// ===============================================================================
// choose parts to print

//PRINTBOT =       1;                // 0/1 turn bottom part off/on
//PRINTTOP =       1;                // 0/1 turn top part (lid) off/on
//PRINTPOS =       0;                // 0/1 move lid in printing position
//SHOWOFFPOS =     1;                // 0/1 nice looking off/on; ONLY IF PRINTPOS=0

// ===============================================================================
// box parameters

//Total Length of box, left-right
length =       90.0;              // length of the box
//Total Width of box, front-back
width =         60.0;              // width of the box
//Height of lid
topHeight =     10.0;              // height of the lid
//Height of bottom
botHeight =     20.0;              // height of bottom box part
//Thickness of left/right/front walls
wall =           2.0;
//Thickness of floor and roof
floor =          3.0;              // thickness of the floor and "roof"
//Thickness of back wall hinge
backwall =       6.0;               //thickness of the back wall only

// ===============================================================================
// magnet parameters

/* [Magnets] */

//Magnet length
maLength =       5.5;              // length of the magnet cutout (x axis)
//Magnet width
maWidth =        5.5;              // depth of the magnet cutout (y axis)
//Magnet height
maHeight =       5.5;              // height of the magnet cuout (z axis)
//Magnet spacer
maSpacer =       1.0;              // thickness of material around magnet

// ===============================================================================
// hinge parameters (usually no change required)

/* [Hinge] */

//Hinge z-height (0.0 = lowest possible)
hiHeight =       0.0;              // z pos of hinge (0.0 = lowest possible)

hiLength =      length/12;         // length of the hinge
hiOffs =        length/4;          // position of the hinge

//Hinge diameter
hiDia =          3.0;              // diameter of the hinge pin cutout

hiDiaDepth =    hiOffs+hiLength;   // drill depth of the hinge pin
hiHingSpac =    hiLength/20;       // additional space to make it move freely

// ===============================================================================
// additional parameters

/* [Chamfer] */

//Chamfer edges
CHAMFEREDGES =   1; //[1:Yes,0:No]
//Chamfer length
CHAMFERLEN =     3.0;

// ===============================================================================
// ===============================================================================
// ===============================================================================
// NO CHANGES BELOW HERE
CYLPREC = 100/1;

print_part();

module print_part() {
	if (part == "bottom") {
		BoxBottom();
	} else if (part == "top") {
        translate( [0, width, botHeight + topHeight ] )
        rotate( [180, 0, 0] )
		BoxTop();
    } else if (part == "both") {
        BoxBottom();
        translate( [ 0, width+floor-backwall, +floor+wall/2 + hiHeight ] )
        rotate( [-45,0,0] )
        translate( [ 0, -width-floor+backwall, -floor-wall/2-hiHeight ] )
        BoxTop();
	} else {
		BoxBottom();
	}
}

// ===============================================================================
// === BOX BOTTOM

//if( PRINTBOT )
//  BoxBottom();

// ===============================================================================
// === BOX TOP
//if( PRINTTOP )
//{
//  if( PRINTPOS )
//  {
//    translate( [0, width, botHeight + topHeight ] )
//    rotate( [180, 0, 0] )
//    BoxTop();
//  }
//  else
//    if( SHOWOFFPOS )
//    {
//      translate( [ 0, width+floor-backwall, +floor+wall/2 + hiHeight ] )
//        rotate( [-45,0,0] )
 //         translate( [ 0, -width-floor+backwall, -floor-wall/2-hiHeight ] )
 //           BoxTop();
//    }
//	else
//      BoxTop();
//}

// ===============================================================================
// ===============================================================================
// ===============================================================================

// ===============================================================================
// === IDIOT BOX (if none of the box parts was selected)
//if( !PRINTTOP && !PRINTBOT )
//  cube([10,10,10]);

// ===============================================================================
// === BOX BOTTOM
module BoxBottom()
{
  difference()
  {
    // === THE BOX
    cube( [ length, width, botHeight ] );
    translate( [ wall, wall, floor ] )
      cube( [ length - 2*wall, width - wall - backwall, botHeight - floor + 1 ] );

    // === LEFT HINGE CUTOUT
    translate( [ hiOffs - hiLength/2, width - 1.5*backwall, floor + hiHeight ] )
      cube( [ hiLength, 2*backwall, botHeight - floor/2 ] );

    // === RIGHT HINGE CUTOUT
    translate( [ length - hiOffs - hiLength/2, width - 1.5*backwall, floor+hiHeight ] )
      cube( [ hiLength, 2*backwall, botHeight - floor/2 ] );

    // === LEFT HINGE PIN CUTOUT
    translate( [ -1, width - backwall/2, floor+backwall/2+hiHeight ] )
    rotate( [ 0, 90 ,0 ] )
      cylinder( r=hiDia/2, h=hiDiaDepth+1, $fn=CYLPREC );

    // === RIGHT HINGE PIN CUTOUT
    translate( [ length - hiDiaDepth + 1, width - backwall/2, floor+backwall/2+hiHeight ] )
    rotate( [ 0, 90 ,0 ] )
      cylinder( r=hiDia/2, h=hiDiaDepth+1, $fn=CYLPREC );

    // === RECESSED GRIP CUTOUT
    RecessedGrip();

    // === LEFT MAGNET CUTOUT
    translate([hiOffs-maLength/2, wall - maWidth, botHeight - maHeight - maSpacer])
      cube( [ maLength, maWidth+1, maHeight ] );

    // === RIGHT MAGNET CUTOUT
    translate([length-hiOffs-maLength/2,wall-maWidth, botHeight-maHeight-maSpacer])
      cube( [ maLength, maWidth+1, maHeight ] );

    // === CHAMFERED EDGES
    if( CHAMFEREDGES )
      ChamferedEdges();

  } // END difference
}

// ===============================================================================
// === BOX TOP
module BoxTop()
{
  union()
  {
    difference()
    {
      // === THE BOX
      translate( [0, 0, botHeight ] )
      cube( [ length, width, topHeight ] );
      translate( [ wall, wall, botHeight -1 ] )
        cube( [ length - 2*wall, width - wall - backwall, topHeight - floor +1 ] );

      // === RECESSED GRIP CUTOUT
      RecessedGrip();

      // === LEFT MAGNET CUTOUT
      translate([hiOffs-maLength/2, wall - maWidth, botHeight+maSpacer])
        cube( [ maLength, maWidth+1, maHeight ] );

      // === RIGHT MAGNET CUTOUT
      translate([length-hiOffs-maLength/2,wall-maWidth,botHeight+maSpacer])
        cube( [ maLength, maWidth+1, maHeight ] );

      // === CHAMFERED EDGES
      translate([0,0,botHeight+topHeight])
        mirror([0,0,1])
          ChamferedEdges();
    }

    // === LEFT HINGE
    LeftHinge();

    // === RIGHT HINGE
    translate( [ length - 2*hiOffs, 0, 0 ] )
      LeftHinge();
  } // END union
}

// ===============================================================================
// === HINGE
module LeftHinge()
{
  difference()
  {
    union()
    {
      translate([hiOffs-hiLength/2+hiHingSpac,width-backwall,floor+0.5*backwall+hiHeight])
        cube([hiLength-2*hiHingSpac, backwall, botHeight-floor-0.5*backwall-hiHeight ] );
      translate([hiOffs-hiLength/2+hiHingSpac,width-backwall/2,floor+0.5*backwall+hiHeight])
        rotate( [0,90,0] )
          cylinder( r = backwall/2, h = hiLength - 2*hiHingSpac, $fn=CYLPREC );
    }

    // === LEFT HINGE PIN CUTOUT
    translate( [ -1, width - backwall/2, floor+backwall/2+hiHeight ] )
    rotate( [ 0, 90 ,0 ] )
      cylinder( r=hiDia/2, h=hiDiaDepth+1, $fn=CYLPREC );

  } // END difference
} // END LeftHinge

// ===============================================================================
// === RECESSED GRIP CUTOUT
module RecessedGrip()
{
  // === RECESSED GRIP
  translate( [ length/2, -wall/3, botHeight ] )
    scale( [ 2*topHeight, wall , topHeight/1.5] )
      sphere( r = 1, $fn=CYLPREC );

}

// ===============================================================================
// === CHAMFERED EDGES
module ChamferedEdges()
{
  // === FRONT CUT
  translate([0,0,CHAMFERLEN])
  rotate([-45,0,0])
    translate([-1,-length/2,-2*CHAMFERLEN])
      cube([length+2,length,2*CHAMFERLEN]);

  // === REAR CUT
  translate([0,width,CHAMFERLEN])
  rotate([45,0,0])
    translate([-1,-length/2,-2*CHAMFERLEN])
      cube([length+2,length,2*CHAMFERLEN]);

  // === LEFT CUT
  translate( [ 0, 0, CHAMFERLEN ] )
    rotate( [0,45,0] )
    translate( [ -width / 2, -1, -2 * CHAMFERLEN ] )
      cube([width,2+width,2*CHAMFERLEN]);

  // ===RIGHT CUT
  translate( [ length, 0, CHAMFERLEN ] )
  rotate( [0,-45,0] )
  translate( [ -width / 2, -1, -2 * CHAMFERLEN ] )
    cube([width,2+width,2*CHAMFERLEN]);

}

```


[User]
Hi, I need help designing a tool for removing machine tapers, specifically drill chuck tapers. I've included a description of how it's used and a SCAD file I made a few years ago. I'm looking for a more robust, parametric design.

The basic idea is a wedge that is inserted into the gap between the drill chuck and the machine spindle. The wedge is then tapped to separate the taper joint. The design in the file works, but I want to be able to easily adjust it for different taper sizes and machines. Here's what I'm thinking, based on the provided code and my experience using it:

**Core Wedge Design:**
*   **Wedge Length:** The overall length of the wedge. This should be easily adjustable.
*   **Shaft Length:** The length of the straight "shaft" portion of the wedge before the taper starts.
*   **Wedge Width (Taper Width):** This is the width of the wedge itself, which should be related to the taper size (MT1, MT2, etc.). I'd like to be able to enter a taper size, and have the wedge width adjust accordingly, or manually specify the width if I need to.
*   **Taper Length:** The length of the tapered section of the wedge.
*   **Taper Angle:** The angle of the taper. I'd like to calculate the necessary geometry instead of using a percentage based on length, if possible. The provided example uses `slopepercent`, but I would prefer a more direct angle parameter.
*   **Hole:** I need a hole through the wedge for a pin, probably about 5mm in diameter, to act as an alignment guide or for some other purposes. This should be able to be toggled on/off with a boolean parameter.
*   **Rounding:** Option to enable or disable rounded edges on the wedge. The original wedge is not rounded, but I think that would be beneficial.

**Anti-Warping Features**
*   **Ears:** Small cylindrical features that are added to the sides of the wedge. They help prevent warping when printing with ABS and also give it a little more surface area, making it easier to grab. I want to be able to control their diameter, height, and placement. I would prefer to be able to place these ears along the side edges of the wedge, with the user controlling the location along the wedge length and number of sets of ears. I want each set of ears to have two ears on each side, as in the original.

**Parametric Control:**
*   I'd like to have all of these values configurable via user-defined parameters.
*   I'd like to be able to specify standard taper sizes (MT1, MT2, MT3, MT4, MT5) and have the program automatically set the taper width accordingly (using a lookup table or similar approach). I've included the MT taper sizes below:

    *   MT1: 5.2 mm
    *   MT2: 6.3 mm
    *   MT3: 7.9 mm
    *   MT4: 11.9 mm
    *   MT5: 15.9 mm

*   I'd like to be able to select from preset taper types with varying degrees.

**Output Requirements:**
*   I need a single OpenSCAD (.scad) file that includes all the parameters and modules to generate the wedge.
*   It would be great if the scad file had comments explaining the parameters and sections of code.
*   I'd like to use the BOSL2 library if possible.

Thanks for your help! Let me know if you need any more information.

[Assistant]
wedge2.scad:
```
////////////////////////////////////////////////
///////wedge for removing MT tapers//////
/*author:Rudiger Vanden Driessche
ruudoleo@skynet.be
date:10/09/2015
ABS   print with 100% innfill

about tapers:
http://www.beautifuliron.com/mttaper.htm
Had to replace the head of my drilling machine, but the taper was lodged after 20 years nonuse.
*/
/*//parameters//////*/
/* [Wedge]*/
Wedgelenght=150;
Wedgeshaft=30;
Wedgewidth=6.3;//[5.2:MT1,6.3:MT2,7.9:MT3,11.9:MT4,15.9:MT5]
Rounding=true;
Hole=5;
taperw=10;
lenghtpercent=50;
slopepercent=4;
/* [Antiwarpears]*/
eardia=15;
earh=1;
/* [Hidden]*/
safety=0.1;

space=taperw-Wedgewidth;
slope=Wedgelenght-Wedgeshaft;
a1=space-(lenghtpercent/100*slope*slopepercent/100);
a2=space+(1-lenghtpercent/100)*slope*slopepercent/100;
angle=slopepercent/100*45;
echo(a1,a2);

difference(){
hull(){

    //shaft
    translate([0,Wedgewidth/2,Wedgewidth/2]){
rotate(-90,[0,1,0]){
cylinder(d=Wedgewidth,h=Wedgeshaft,$fn=100);
}//end rotate
}//end translate

//straight end
translate([slope,Wedgewidth/2+a2,Wedgewidth/2]){
rotate(-90,[0,1,0]){
cylinder(d=Wedgewidth,h=Wedgeshaft+slope,$fn=100);
 }//end rotate
}//end translate
//sloped end
rotate(angle,[0,0,1]){
translate([0,Wedgewidth/2,Wedgewidth/2]){
    rotate(90,[0,1,0]){
      cylinder(d=Wedgewidth,h=slope,,$fn=100);
    }//end rotate
    }//end translate
}//end rotate

}//end hull
//bore
translate([-Wedgeshaft/2,Wedgewidth/2+a2/2,-safety/2])
    cylinder(d=Hole,h=Wedgewidth+safety,$fn=100);
}//end difference
//ears
translate([0.5*Wedgelenght-Wedgeshaft,a2,0.5*earh]) {
  antiwarpears(eardia,earh,Wedgelenght-eardia,0.5*eardia);

}//end translate
module antiwarpears(dia,h,xd,yd){
	for(x=[-1,1], y=[-1,1])
       {
		translate([xd/2*x,yd/2*y,0])
            cylinder(d=dia,h=1,center=true,$fn=50);
       }//end for
   }//end module

```


[User]
Okay, I need an OpenSCAD design for a motor mount, and I'd like it to be parametric so I can easily adjust it for different motor sizes later. I've got some basic dimensions and requirements here:

The mount should essentially be a hollow cylinder with some mounting holes and an optional opening on top. Specifically, the key parameters are:

*   `motorRadius`: The radius of the motor itself.
*   `motorLength`: The length of the motor.
*   `wallThickness`: The thickness of the mount walls.
*   `cutOutRadius`: The radius of a hole through the center of the mount.
*   `screwMounts`: The number of mounting screw holes.
*   `screwAx`: The distance from the center of the motor to the center of the screw holes
*   `screwRadius`: The radius of the mounting screw holes.
*   `topOpen`: A flag (0 or 1) to indicate if the top of the mount should be open or closed.

I need the final design to use those parameters, and also include a small tolerance, which I had set as "tolerance = 0.1". I need a variable for that as well, so "tolerance" would be a good name.

Basically, I need a cylinder that the motor fits into with the specified wall thickness, and then mounting holes placed around it. There will be a hollow cylinder through the center, and the optional opening on top.

I'm imagining something like the mount from the following code, but I'd like a fresh, well-structured version from scratch using best practices. I'd like to use the BOSL2 library, which is the only library I need for this design, and I'm not providing the code, because I want you to generate a new design using best practices. Also, make sure that the final mount is centered at the origin.
```
//  Measure for smoothness
$fn = 100;

//  Tolerance on the radius
tolerance = 0.1;

motorRadius = 24 / 2;
motorLength = 31;
wallThickness = 1;
cutOutRadius = 6 / 2;
//  Amount of holes for screws
screwMounts = 2;
//  Distance from holes to ax
screwAx = 17.2 / 2;
screwRadius = 2 / 2;

//  Mount opened on the top, 0 for no, 1 for yes
topOpen = 0;    //  [1, 0]

module motorMount(){
    difference(){
        translate(  [   -(motorRadius + wallThickness + tolerance),
                        0,
                        -(motorRadius + wallThickness + tolerance)]){
            cube(   [   2 * (motorRadius + wallThickness + tolerance),
                        motorLength + wallThickness,
                        2 * (motorRadius + wallThickness + tolerance)],
                    center = false);
        }
        if(topOpen == 1){
            translate(  [   -(motorRadius + tolerance),
                            -0.1,
                            0]){
                cube(   [   2 * (motorRadius + tolerance),
                            motorLength + 0.1,
                            2 * (motorRadius + wallThickness + tolerance)],
                        center = false);
            }
        }
        rotate([-90,0,0]){
            translate([0,0,-0.1]){
                cylinder(r = motorRadius + tolerance, h = motorLength + 0.1);
                cylinder(r = cutOutRadius + tolerance, h = motorLength + wallThickness + 0.2);
            }
            for(i = [1:screwMounts]){
                rotate([0,0,360 / screwMounts * i + 90]){
                    translate([0,screwAx,0]){
                        cylinder(r = screwRadius + tolerance, h = motorLength + wallThickness + 0.2);
                    }
                }
            }
        }
    }
}

motorMount();
```

[Assistant]
motorMount.scad:
```
//  Measure for smoothness
$fn = 100;

//  Tolerance on the radius
tolerance = 0.1;

motorRadius = 24 / 2;
motorLength = 31;
wallThickness = 1;
cutOutRadius = 6 / 2;
//  Amount of holes for screws
screwMounts = 2;
//  Distance from holes to ax
screwAx = 17.2 / 2;
screwRadius = 2 / 2;

//  Mount opened on the top, 0 for no, 1 for yes
topOpen = 0;    //  [1, 0]

module motorMount(){
    difference(){
        translate(  [   -(motorRadius + wallThickness + tolerance),
                        0,
                        -(motorRadius + wallThickness + tolerance)]){
            cube(   [   2 * (motorRadius + wallThickness + tolerance),
                        motorLength + wallThickness,
                        2 * (motorRadius + wallThickness + tolerance)],
                    center = false);
        }
        if(topOpen == 1){
            translate(  [   -(motorRadius + tolerance),
                            -0.1,
                            0]){
                cube(   [   2 * (motorRadius + tolerance),
                            motorLength + 0.1,
                            2 * (motorRadius + wallThickness + tolerance)],
                        center = false);
            }
        }
        rotate([-90,0,0]){
            translate([0,0,-0.1]){
                cylinder(r = motorRadius + tolerance, h = motorLength + 0.1);
                cylinder(r = cutOutRadius + tolerance, h = motorLength + wallThickness + 0.2);
            }
            for(i = [1:screwMounts]){
                rotate([0,0,360 / screwMounts * i + 90]){
                    translate([0,screwAx,0]){
                        cylinder(r = screwRadius + tolerance, h = motorLength + wallThickness + 0.2);
                    }
                }
            }
        }
    }
}

motorMount();
```


[User]
I'd like to design a customizable clothespin-like character, starting with a female base. The design should be parametric, allowing for adjustments to various body parts and overall proportions. I'm envisioning something that can be easily modified for different styles later on.

Here’s the general concept:

**Core Structure:** The figure is built around a head, torso, and hip section. The legs are essentially extruded from the hip.

**Head:** This should be a sphere sitting on a cylindrical neck. I'd like to control the radius of both the head and neck.

**Torso:** This should be a sphere centered above the hip, with adjustable radius and height. I'd also like to control its X position relative to the hip.

**Hip:** A sphere at the base of the torso, with adjustable radius. I'd like control over its X position and Z position (vertical) as well.

**Waist:** The waist should be defined using a metaball technique, creating a smooth connection between the torso and hips. The "tightness" of the waist can be adjusted using a tangent parameter. I realize this will be calculated based on a series of variables.

**Legs:** Simple, extruded rectangles from the bottom of the hip. I need to control the overall length of the legs and how far up the leg is the extruded rectangle as a percentage, and also the extruded rectangle's scale. The leg should also include a support cylinder through the middle.

**Parameters:** Here are the specific parameters I want to be able to control:

*   `resolution`: Overall mesh resolution.
*   `head_radius`: Radius of the head sphere.
*   `neck_size`: Radius of the neck cylinder.
*   `torso_radius`: Radius of the torso sphere.
*   `torso_x`: Horizontal position of the torso relative to the origin.
*   `torso_height`: Vertical position of the torso relative to the origin
*   `hip_radius`: Radius of the hip sphere.
*  `hip_x`: Horizontal position of the hip relative to the origin
*  `hip_z`: Vertical position of the hip relative to the origin
*   `waist_tangent`: Controls the waist curvature/tightness.
*   `leg_length`: Overall length of the legs from the bottom of the hip.

**Libraries:** I don't need any libraries used for this.

I'm looking for a single OpenSCAD file that implements all of this. Could you help me with that?

[Assistant]
clothespin_female.scad:
```
/////////////////////////////
// SETTINGS

// preview[view:north, tilt:side]
resolution = 40 *1;
head_radius = 9.0; //[7.0:0.1:11.0]
neck_size = 3.0; //[2:0.1:5]
torso_radius = 13; // [10:0.1:25]
torso_x = 0 * 1;
torso_height = 35; // [0:5:50]
hip_radius = 18; // [10:0.1:25]
hip_x = 0 * 1;
hip_z = 0 *1;
//Decrease if waist disappears
waist_tangent = 5.0; // [1.0:0.1:10.0]
leg_length = 80; // [45:5:100]

/////////////////////////////
// MATH

inner_leg = leg_length * .9;
meta_radius = (hip_radius + torso_radius)/waist_tangent;
force1 = hip_radius + meta_radius;
force2 = torso_radius + meta_radius;
force_distance = sqrt(((hip_x - torso_x)*(hip_x - torso_x)) + ((hip_z - torso_height)*(hip_z - torso_height)));
donutz = (( force1 * force1 ) - ( force2 * force2 ) + ( force_distance * force_distance ))/( 2 * force_distance );
donutx = sqrt(( force1 * force1 ) - ( donutz * donutz ));
side1 = sqrt((donutz * donutz) + (donutx * donutx));
taperBottomz = (hip_radius/side1) * donutz;
taperBottomx = (hip_radius/side1) * donutx;
side2 = abs(torso_height - donutz);
taperTopz = torso_height-((torso_radius/force2) * side2);
taperTopx = (torso_radius/force2) * donutx;
taperExtrude = abs(taperBottomz - taperTopz);
taperAmount = taperTopx/taperBottomx;

/////////////////////////////
// RENDER

translate([0,0,torso_height+torso_radius+hip_radius-head_radius])
  cylinder(r=neck_size, h=head_radius*2, $fn=resolution);

translate([0,0,torso_height+torso_radius+hip_radius+((head_radius/2)*2)])
  sphere(r=head_radius);

translate([0,0,hip_radius])
  metaBalls();

module metaBalls(){

  if (force_distance > force1 + force2){
    echo (str("Circles are too far apart. No Metaball Allowed"));
  }

  else if(force_distance < abs(force1-force2)){
    echo (str("Circle contained inside. No Metaball Allowed"));
  }

  else if(force_distance==0 && force1==force2){
    echo (str("These are the same circle. No Metaball Allowed"));
  }
  else{
    difference(){
      tangent();
      donut();
    }
  };

  difference(){
    hull(){
      translate([0,0, -leg_length])
        cylinder(r=5);

      translate([hip_x,0,hip_z])
        sphere(r=hip_radius, $fn=resolution);
    }

    union()
      translate([0,0, -leg_length])
        linear_extrude(height=inner_leg, scale=1.5)
          square(size=[2,100], center=true);
       translate([0,0, inner_leg - leg_length])
        rotate([90, 0,0])
          cylinder(r=1.5, h=100, center=true, $fn=resolution);
  }

  translate([torso_x,0,torso_height])
    sphere(r=torso_radius, $fn=resolution);
}

/////////////////////////////
// MODULES

module donut(){
  translate([0,0,donutz])
    rotate_extrude(convexity = 10, $fn=resolution)
      translate([donutx, 0 ,0])
        circle(r=meta_radius, $fn=resolution, center=true);
}

module tangent(){
  translate([ 0,0,taperBottomz ])
    linear_extrude(height=taperExtrude, scale=taperAmount)
      circle(r=taperBottomx, $fn=resolution, center=true);
}

```


[User]
Hey, I'd like to design a customizable comb using OpenSCAD. I have some specific dimensions in mind and want it to be fully parametric.

Here's what I'm looking for:

**Overall Structure:** The comb should have a main back section with teeth extending from one side.

**Customizable Parameters:**
*   `$fn`: A variable to control the detail/smoothness of curves. I'd like to be able to set this to different values like 20, 50, 100.
*   `backWide`:  The width of the main back section of the comb, this should be in mm and I'd like to be able to adjust it from 2 to 20.
*  `endWide`: the width of the small end tabs at either side of the comb. This should be scaled off of toothDia, and should be adjustable between 0.25 and 10, with 0.25 increments
*   `toothDia`: The diameter of each tooth in mm, adjustable from 0.5 to 10 in 0.1 increments.
*   `toothGap`: The gap between each tooth in mm, also adjustable from 0.5 to 10 in 0.1 increments.
*   `toothLen`: The length of each tooth in mm, adjustable from 5 to 30.
*   `numTeeth`: The number of teeth on the comb, which I need to adjust between 5 and 100.

**Specifics:**

*   The teeth should be cylindrical, with a rounded tip using a cone-like shape.
*   The back section should be a rectangular shape with rounded ends using cylinders and spheres.
*   The end pieces on the comb (where the teeth end and the back begins) should also be rounded like the back. They should be thick, like a continuation of the back.
*   I'd like the design to be centered on the origin.

I don't need any complex libraries for this, just basic OpenSCAD functions.

[Assistant]
CombCust.scad:
```
// Cusomizeable Simple Comb
// TrevM 17/09/2015

/* [Global] */

// What quality?
$fn = 50;	// [20,30,40,50,60,70,80,90,100]

// Width (mm) of back?
backWide = 5;	// [2:20]

// Width (teeth) of ends?
endWide = 0.75;	// [0.25:0.25:10.00]

// Tooth (mm) Diameter?
toothDia = 1.5;	// [0.5:0.1:10.0]

// Gap (mm) between teeth?
toothGap = 1.5;	// [0.5:0.1:10.0]

// Tooth (mm) length?
toothLen = 20;	// [5:30]

// Number of teeth?
numTeeth = 39;	// [5:100]

/* [Hidden] */
backLen = (numTeeth-1)*(toothDia+toothGap);
endLen = endWide*toothDia;

comb();

//translate([-((numTeeth*(toothGap+toothDia))+toothGap)/2,backWide+toothDia+2,0])
//	rotate([0,90,0])	cylinder(r=1,h=115);

module comb()
{
	translate([-((numTeeth*(toothGap+toothDia))+toothGap)/2,0,toothDia/2])
	{
		// do teeth
		for(x=[1:numTeeth])
			translate([(x-1)*(toothGap+toothDia),toothDia/2,0])
				tooth();
		// left thick tooth
		translate([-(endWide*toothDia),toothDia/2,0])
		{
			tooth();
			translate([0,-toothLen+toothDia,0])
			{
				rotate([0,90,0])
					cylinder(d=toothDia,h=endWide*toothDia);
				translate([0,0,-toothDia/2])
					cube([endWide*toothDia,toothLen-toothDia,toothDia]);
			}
		}
		// right thick tooth
		translate([backLen,toothDia/2,0])
		{
			translate([endLen,0,0])	tooth();
			translate([0,-toothLen+toothDia,0])
			{
				rotate([0,90,0])
					cylinder(d=toothDia,h=endWide*toothDia);
				translate([0,0,-toothDia/2])
					cube([endLen,toothLen-toothDia,toothDia]);
			}
		}
		// do back
		translate([-endLen,0,0])
		{
			// left end
			rotate([-90,0,0])	cylinder(d=toothDia,h=backWide);
			translate([0,backWide,0])
			{
				// left back corner
				sphere(d=toothDia);
				// back edge
				rotate([0,90,0])	cylinder(d=	toothDia,h=backLen+(endLen*2));
			}
			// front edge
			rotate([0,90,0])	cylinder(d=	toothDia,h=backLen+(endLen*2));
			translate([backLen+(endLen*2),0,0])
			{
				// right back corner
				translate([0,backWide,0])	sphere(d=toothDia);
				// right end
				rotate([-90,0,0])	cylinder(d=	toothDia,h=backWide);
			}
			// back fill
			translate([0,0,-toothDia/2])
				cube([backLen+(endLen*2),backWide,toothDia]);
		}
	}
}

module tooth()
{
	rotate([90,0,0])
	{
		cylinder(d=toothDia,h=toothLen-toothDia);
		translate([0,0,toothLen-toothDia])
			cylinder(d1=toothDia,d2=0.5,h=toothDia/2);
	}
}

```


[User]
I'd like to design a customizable ear plug using OpenSCAD, and I'd like it to have a few different decoration options. I have some existing code that I'm trying to replicate and improve with more flexibility.

The basic plug should be a rounded cylinder shape, and I need to be able to control the overall diameter and height, as well as a "groove" at the base that makes the edge less sharp. I'd also like a way to control the curvature of the rounded edges with a smoothing parameter. It's important that all of these base features are adjustable via parameters.

I would like to have several options for the decoration on the plug face:
1. A simple solid plug (no decoration).
2. A hollowed plug with an inner cylinder removed.
3. A star shape.
4. A heart shape.
5. A negative sign (horizontal bar).
6. A positive sign (cross).
7.  The Open Source Hardware logo (a gear with a central cross).

The decorations should be centered on the plug face. For the decorated versions, I'd also like to control the size of the decoration with a "cursor" percentage, as well as a "margin" parameter to adjust the spacing between the decoration and the plug. For example, a cursor of 50% would make the decoration half the size of the ear plug's diameter, and a margin of 0.2 would add a 0.2mm gap around the decoration where it meets the plug. The decoration should be embedded into the plug, not just placed on the surface. Also, I want to be able to control the resolution of the shapes using `$fn`.

I'd also like to have a way to select whether I'm generating the ear plug itself, or just the decoration, so I can create the decorations separately.

Could you generate a parametric OpenSCAD file or set of files that handles all of this? I'd prefer that the code be reasonably well-organized. It would be helpful if comments explained the different parts of the code. Also, I'd prefer that all the variables are at the beginning of the code. I don't need any external libraries for this.

[Assistant]
Customizable_Ear_Plug.scad:
```
/* ----------------------------------------------------------------------------
	Customizer Variables
---------------------------------------------------------------------------- */
type     = 6; // [0:Solid,1:Hollowed,2:Star,3:Heart,4:Negative Sign,5:Positive Sign,6:OSHW Sign]
// for display only, doesn't contribute to final object
part     = 0; // [0:Plug,1:Decoration]
// or ear hole in mm
diameter = 10;
// or height in mm
weight   = 11;
// (baby) in mm
groove   = 1;
// smoothing (0.5 to 2 is good values)
edges    = 1;
// or the size of the inner piece in percent : %
cursor   = 100; // [10:100]
// or the gap between the inner and outer piece
margin   = 0.1;
// resolution
$fn = 50;

/* ----------------------------------------------------------------------------
	Curve Module By Skarab, 2013
	Original script By Don B, 2011
	Released into the Public Domain
	http://www.thingiverse.com/thing:8931
---------------------------------------------------------------------------- */
module Curve(p1, p2, cursor, steps = 5, filled = true)
{
	stepsize1 = (cursor - p1) / steps;
	stepsize2 = (p2 - cursor) / steps;

	for (i = [0:steps - 1])
	{
		assign(point1 = p1 + stepsize1 * i)
		assign(point2 = cursor + stepsize2 * i)
		assign(point3 = p1 + stepsize1 * (i + 1))
		assign(point4 = cursor + stepsize2 * (i + 1))
		{
			assign(bpoint1 = point1 + (point2 - point1) * (i / steps))
			assign(bpoint2 = point3 + (point4 - point3) * ((i + 1) / steps))
				polygon(points = [bpoint1, bpoint2, filled ? p1 : cursor]);
		}
	}
}

/* ----------------------------------------------------------------------------
	Filled Plug Module
---------------------------------------------------------------------------- */
module plug(w = weight, d = diameter, g = groove, e = edges)
{
	// External Radius
	r = (d / 2) + g;

	// Curves Points
	p1 = [-e, 0];
	p2 = [0, e];
	p3 = [0, w - e];
	p4 = [-e, w];

	// Curves Cursors
	c1 = [0, 0];
	c2 = [-g * 2, w / 2];
	c3 = [0, w];

	// Plug Creation
	rotate_extrude($fn = 180)
		translate([r, 0, 0])
			union()
			{
				Curve(p1, p2, c1, 10, true);
				Curve(p2, p3, c2, 40, false);
				Curve(p3, p4, c3, 10, true);
				polygon(points=[p1, p2, c2, p3, p4, [-r, w], [-r, 0]]);
			}
}

/* ----------------------------------------------------------------------------
	Return X percent From Y
---------------------------------------------------------------------------- */
function percent(x, y) = ((y) / 100) * x;

/* ----------------------------------------------------------------------------
	Hollowed Plug Module
---------------------------------------------------------------------------- */
module hollowed_plug()
{
	d = percent(cursor, diameter - 3);

	difference()
	{
		plug();

		if (d > 2)
		{
			translate([0, 0, -edges])
				plug(weight + (2 * edges), d);
		}
	}
}

/* ----------------------------------------------------------------------------
	Parametric star
	(c)  2010 Juan Gonzalez-Gomez (Obijuan) juan@iearobotics.com
	GPL license

	http://www.thingiverse.com/thing:5052

	The 2*N points of an N-ponted star are calculated as follows:
	There are two circunferences:  the inner and outer.  Outer points are located
	at angles: 0, 360/N, 360*2/N and on the outer circunference
	The inner points have the same angular distance but they are 360/(2*N) rotated
	respect to the outers. They are located on the inner circunference

	INPUT PARAMETERS:
	N: Number of points
	h: Height
	ri: Inner radius
	ro: outer radius
---------------------------------------------------------------------------- */
module parametric_star(N = 5, h = 3, ri = 15, re = 30)
{
	// Calculate and draw a 2D tip of the star
	// n: Number of the tip (from 0 to N-1)
	module tipstar(n)
	{
		i1 = [ri*cos(-360*n/N+360/(N*2)), ri*sin(-360*n/N+360/(N*2))];
		e1 = [re*cos(-360*n/N), re*sin(-360*n/N)];
		i2 = [ri*cos(-360*(n+1)/N+360/(N*2)), ri*sin(-360*(n+1)/N+360/(N*2))];

		polygon([ i1, e1, i2]);
	}

	// Draw the 2D star and extrude
	// The star is the union of N 2D tips.
	// A inner cylinder is also needed for filling
	// A flat (2D) star is built. The it is extruded
	linear_extrude(height = h)
		union()
		{
			for (i=[0:N-1])
				tipstar(i);
			rotate([0,0,360/(2*N)])
				circle(r=ri+ri*0.01,$fn=N);
		}
}

/* ----------------------------------------------------------------------------
	Star Plug Module
---------------------------------------------------------------------------- */
module star_plug()
{
	d      = percent(cursor, (diameter / 2) - 1.5);
	half_d = d / 2;

	if (part == 0)
	{
		difference()
		{
			plug();
			translate([0, 0, -0.01])
				parametric_star(5, weight + 0.02, half_d, d);
		}
	}
	else parametric_star(5, weight, half_d - margin, d - margin);
}

/* ----------------------------------------------------------------------------
	Heart Module By Skarab, 2013
---------------------------------------------------------------------------- */
module heart(s = 10, h = 10)
{
	// Sizes
	hs= s / 2;
	qs= s / 4;

	// Circles
	// Curves Points
	p1 = [-hs, 0];
	p2 = [0, -3 * qs];
	p3 = [hs, 0];
	p4 = [(qs * cos(30)) - qs, qs * sin(30)];
	p5 = [(qs * cos(150)) + qs, qs * sin(150)];

	// Curves Cursors
	c1 = [-hs, -qs];
	c2 = [hs, -qs];
	c3 = [0, qs * sin(150) / 2];

	translate([0, qs, 0])
		linear_extrude(height = h)
			union()
			{
				translate([-qs, 0, 0])
					circle(qs, $fn = 50);
				translate([qs, 0, 0])
					circle(qs, $fn = 50);
				Curve(p1, p2, c1, 20, true);
				Curve(p2, p3, c2, 20, true);
				Curve(p4, p5, c3, 20, false);
				polygon(points = [p1, p2, p3]);
				polygon(points = [p4, c3, [0, 0]]);
				polygon(points = [p5, c3, [0, 0]]);
			}
}

/* ----------------------------------------------------------------------------
	Heart Plug Module
---------------------------------------------------------------------------- */
module heart_plug()
{
	d      = percent(cursor, diameter / 1.414);
	half_d = d / 2;
	y      = ((half_d * 1.414) - half_d) / 3;

	if (part == 0)
	{
		difference()
		{
			plug();
			translate([0, -y, -0.01])
				heart(d, weight + 0.02);
		}
	}
	else heart(d - margin, weight);
}

/* ----------------------------------------------------------------------------
	Negative Sign Module
---------------------------------------------------------------------------- */
/*
module negative_sign(d, w)
{
	h = d / 4;
	r = h / 2;
	x = (d / 2) - r;

	hull()
	{
		translate([-x, 0, 0])
			cylinder(h = w, r = r);
		translate([x, 0, 0])
			cylinder(h = w, r = r);
	}
}
*/

module negative_sign(d, w)
{
	h = d / 4;

	translate([-d/2, -h/2, 0])
		cube([d, h, w]);
}

/* ----------------------------------------------------------------------------
	Negative Sign Plug Module
---------------------------------------------------------------------------- */
module negative_sign_plug()
{
	d = percent(cursor, diameter - 3);

	if (part == 0)
	{
		difference()
		{
			plug();
			translate([0, 0, -0.01])
				negative_sign(d, weight + 0.02);
		}
	}
	else negative_sign(d - margin, weight);
}

/* ----------------------------------------------------------------------------
	Positive Sign Module
---------------------------------------------------------------------------- */
module positive_sign(d, w)
{
	negative_sign(d, w);
	rotate([0, 0, 90])
		negative_sign(d, w);
}

/* ----------------------------------------------------------------------------
	Positive Sign Plug Module
---------------------------------------------------------------------------- */
module positive_sign_plug()
{
	d = percent(cursor, diameter - 3);

	if (part == 0)
	{
		difference()
		{
			plug();
			translate([0, 0, -0.01])
				positive_sign(d, weight + 0.02);
		}
	}
	else positive_sign(d - margin, weight);
}

/* ----------------------------------------------------------------------------
	OSHW Sign Module
---------------------------------------------------------------------------- */
module oshw_sign(d, w)
{
    s = d / 180;

    module gear_tooth() {
        polygon(
            points=[[0, 25.0], [90.0, 12.0], [90.0, -12.0], [0, -25.0]],
            paths=[[0, 1, 2, 3]]
        );
    }

    linear_extrude(height=w) scale(s, s) rotate(-45-90) {
        difference() {
            union() {
                circle(r=70.0);
                for(i=[1:7]) assign(angle=360*i/8+45) rotate(angle)
                    gear_tooth();
            }
            circle(r=25.0);
            intersection() {
                rotate(-20) square(size=[100, 100]);
                rotate(20)  square(size=[100, 100]);
            }
        }
    }
}

/* ----------------------------------------------------------------------------
	Positive Sign Plug Module
---------------------------------------------------------------------------- */
module oshw_sign_plug()
{
    d = percent(cursor, diameter - 1.5);

    if (part == 0)
	{
		difference()
		{
			plug();
			translate([0, 0, -0.01])
                oshw_sign(d, weight + 0.02);
		}
	}
	else oshw_sign(d - margin, weight);
}

/* ----------------------------------------------------------------------------
	Plug Creation
---------------------------------------------------------------------------- */
if (type == 1)      hollowed_plug();
else if (type == 2) star_plug();
else if (type == 3) heart_plug();
else if (type == 4) negative_sign_plug();
else if (type == 5) positive_sign_plug();
else if (type == 6) oshw_sign_plug();
else                plug();

```


[User]
I'd like to design a coffee mug in OpenSCAD, but it should have two handles instead of one. I'm envisioning something similar in overall shape to a standard coffee mug, cylindrical with a rounded bottom and a rounded top lip.

Here's what I have in mind for the key parameters:

*   **`$fn`**: This controls the fineness/smoothness of curves. I'd like to set it to 60 as a good starting point, but I'd like to have it as an adjustable parameter.
*   **`cornd`**: The radius for rounding the bottom edge of the cup, let's start with 10 mm. I want this to be adjustable and to be constrained such that it's never more than half the cup's radius.
*   **`ovrht`**: The overall height of the cup. Let's make this 115mm for now.
*   **`cupwd`**: The major radius of the cup (the radius of the main cylindrical body). Starting at 41 mm would be good.
*   **`cupwal`**: The wall thickness of the cup, let's set that at 4 mm.
*   **`handlr`**: The thickness (radius of the cross-section) of the handle, using 5.25 mm for now.

The cup's body itself should be formed by taking the difference between two rounded-bottomed cylinders, with a rounded top lip. For the handles, I would like to use torus shapes that are then rotated 90 degrees around the x axis, positioned on opposite sides of the cup, scaled a bit in the x and z directions, and also offset outwards a bit from the side of the cup. The toruses should also be offset vertically to the halfway point of the cup. Finally, the smaller, inner cylinder should subtract from the handles as well. I'd like to have the scale and offset parameters of the torus as modifiable parameters.

Could you please generate an OpenSCAD file or files to accomplish this? I'm not using any particular libraries at the moment, so I don't think you'll need to worry about those. Thanks!

[Assistant]
Cup2Handl.scad:
```
// "Fragments" or fineness. Higher = smoother
$fn = 60;
// Rounding of the bottom, radius in mm.
cornd=10;  //
// Height of the cup in mm
ovrht = 115;
// Major radius of the cup in mm.
cupwd = 41;
// Width of the wall  in mm.
cupwal = 4;
// Thickness of handle in mm.
handlr = 5.25;
cornerd = min(cornd,cupwd/2); // Bad things happen if you try to round the bottom too much!
cupht = ovrht - cornerd - cupwal*.5; // cup height adjusted for other features
/* The next functions make a primitive coffee cup from two cylinders and a torus.  */
module cupprim(h1,r1,rc) {
 cylinder(h1,r1,r1); rotate_extrude (convexity=10) translate ([r1-rc,0,-rc/2]) circle (r=rc); translate ([0,0,-rc]) cylinder(rc,r1-rc,r1-rc);
}
// This makes the top rim rounded.
translate ([0,0,cupht]) rotate_extrude (convexity=10) translate([cupwd-cupwal/2,0,0]) circle (r=cupwal/2);
/* Next, we use difference() function to subtract a smaller primitive from a bigger one to make a shell.*/
difference () {cupprim(cupht,cupwd,cornerd); translate ([0,0,cupwal]) cupprim(cupht+.1,cupwd-cupwal,cornerd);
    }
// Let's make the handle a torus
difference () {
     rotate (a=90, v=[1,0,0]) {
    translate
        ([cupwd,.5*cupht,0]) scale([.75,1,1.75]) rotate_extrude(convexity=12)    translate([.4*cupht,0,0]) circle(r=handlr) ;
         translate([-cupwd,.5*cupht,0]) scale([.75,1,1.75]) rotate_extrude(convexity=12)    translate([.4*cupht,0,0]) circle(r=handlr);
}       translate ([0,0,cupwal]) cupprim(cupht,cupwd-cupwal,cornerd);
}
```


[User]
Hey, I'm looking to generate some customizable horns for a cosplay project, and I need some help with an OpenSCAD script. I really like the design of that parametric horn with a buckle you showed, but it doesn't *quite* meet my needs. I would love something similar, but with some tweaks.

Specifically, I need the horn to have a base that can be a different shape than a circle; specifically, I want the base to be a polygon with a configurable number of sides, like a triangle, square, pentagon, and so on, which also needs to be able to be twisted and rotated. The cross-section should transition from this polygon at the base to a circle at the tip and should do so smoothly and parametrically.

The wall thickness, like the design you showed, needs to stay constant, and the length of the horn, as well as the base's size, need to be configurable. I need to have similar twist and offset controls, too, so I can get the horns to curve and point just right. I also want the option for the tip to be a polygon instead of a circle.

Also, the attachment tab is a nice feature from the example, but I need some additional options for it, such as its width, length, height, a parameter to position it on the horn, and a parameter that controls the direction the tab points. I'd like the tab to also have configurable holes for screws or pegs that could be circular, or polygon shaped.

I'd also like to be able to specify separate rotations for the base, the horn itself, and the tab as well as its position along the circumference of the base, and the number of edges of the base polygon and tip polygon separately. Finally, I want to be able to configure the resolution used to generate the horn, similar to how the original design is controlling the resolution in vertical direction but do this also horizontally to control the resolution of the transition between the base polygon and the circle or tip polygon.

Can you help me with this? I'm not sure which libraries would be best, but I'm open to suggestions. Let me know what you think!

[Assistant]
paramHornWithBuckleV3.scad:
```
//	   Customizable Horn with TAB and constant wall thickness
//		    Steven Veltema
//		    September 18, 2015
//
//      With inspiration from:
//	    Customizable Horn - Steve Medwin
//      http://www.thingiverse.com/thing:347425
//
//      And Adafruit LED Fire Horns
//      http://www.thingiverse.com/thing:344412

//higher = smoother, larger files
HORN_FACE_NUMBER = 8; //[6:1:100]

HORN_LENGTH=100.0;// [10:5:300]
//base inner radius
HORN_INNER_RADIUS=25.0;// [10:1:100]
//constant across horn height
HORN_WALL_THICKNESS=4.0;//	[1:1:50]

HORN_TWIST_X_AXIS=0;// [-720:5:720]
HORN_TWIST_Y_AXIS=0; // [-720:5:720]
HORN_TWIST_Z_AXIS=90;// [-720:5:720]

HORN_TIP_OFFSET_X=-30.0;// [-100:5:100]
HORN_TIP_OFFSET_Y=-30.0;// [-100:5:100]
HORN_ROTATE = 0.0;// [0:5:360]

//lower = more detailed, larger files
HORN_VERT_RESOLUTION = 4.0;//[2:1:10]

BASE_HEIGHT = 10.0; // [2:1:100]

INCLUDE_TAB = "true"; // [true,false]
TAB_HEIGHT = 5; // [2:1:10]
TAB_ROTATE = 0.0;// [0:5:360]

$fn = HORN_FACE_NUMBER;

module ring(inner_rad, height){
    linear_extrude(height = height, center = false){
        difference() {
            circle(r = inner_rad+HORN_WALL_THICKNESS);
            circle(r = inner_rad);
        }
    }
}

module base() {
    translate([0,0,-BASE_HEIGHT+0.01])  rotate([0,0,HORN_ROTATE]) ring(HORN_INNER_RADIUS,BASE_HEIGHT);
}

module TAB() {
    shortSide = HORN_INNER_RADIUS+HORN_WALL_THICKNESS;
    longSide = shortSide*2.5;
    height          = TAB_HEIGHT;
    TABHoleDepth = TAB_HEIGHT;

    difference() {
       translate([-longSide/2,-shortSide/2,-BASE_HEIGHT]){
            minkowski() {
                cube(size=[longSide,shortSide,height]);
                cylinder(r=shortSide/4);
            }
         }

         translate([longSide-longSide/2-TABHoleDepth,-shortSide/2,-height-BASE_HEIGHT]) cube(size=[TABHoleDepth,shortSide,height*4]);
         translate([-longSide/2,-shortSide/2,-height-BASE_HEIGHT]) cube(size=[TABHoleDepth,shortSide,height*4]);

        rotate([0,180,0]) translate(0,0,-height) cylinder(h=height*3,r=HORN_INNER_RADIUS);
    }
}

module horn()
{
    fn=floor(HORN_LENGTH/HORN_VERT_RESOLUTION);

    twistX = HORN_TWIST_X_AXIS/fn;
    twistY = HORN_TWIST_Y_AXIS/fn;
    twistZ = HORN_TWIST_Z_AXIS/fn;

    offsetX = HORN_TIP_OFFSET_X/fn;
    offsetY = HORN_TIP_OFFSET_Y/fn;
    offsetZ = HORN_LENGTH/fn;

    rotate([0,0,HORN_ROTATE]) {
       difference() {
           //outershell
            for (i=[0:fn-1]) {
                hull() {
                    rotate([twistX*i,twistY*i,twistZ*i])
                        translate([offsetX*i,offsetY*i,offsetZ*i])
                            linear_extrude(height = 0.1, center = true, convexity = 10, twist = 0)
                                circle(HORN_INNER_RADIUS+HORN_WALL_THICKNESS-(i*(HORN_INNER_RADIUS)/fn));

                    rotate([twistX*(i+1),twistY*(i+1),twistZ*(i+1)])
                        translate([offsetX*(i+1),offsetY*(i+1),offsetZ*(i+1)])
                            linear_extrude(height = 0.1, center = true, convexity = 10, twist = 0)
                                circle(HORN_INNER_RADIUS+HORN_WALL_THICKNESS-((i+1)*(HORN_INNER_RADIUS)/fn));
                 }
            }
           //innershell
             for (i=[0:fn-1]) {
                hull() {
                    lowerOffsetZ = offsetZ*i;
                    if (i==0) {lowerOffsetZ = lowerOffsetZ - 0.1;} //make sure base hole is properly removed
                    rotate([twistX*i,twistY*i,twistZ*i])
                        translate([offsetX*i,offsetY*i,lowerOffsetZ])
                            linear_extrude(height = 0.1, center = true, convexity = 10, twist = 0)
                                circle(HORN_INNER_RADIUS-(i*(HORN_INNER_RADIUS)/fn));

                    rotate([twistX*(i+1),twistY*(i+1),twistZ*(i+1)])
                        translate([offsetX*(i+1),offsetY*(i+1),offsetZ*(i+1)])
                            linear_extrude(height = 0.1, center = true, convexity = 10, twist = 0)
                                circle(HORN_INNER_RADIUS-((i+1)*(HORN_INNER_RADIUS)/fn));

                }
            }
        } //diff
    } //rotate
}

union() {
    horn();
    base();
    if (INCLUDE_TAB != "false") {
        rotate([0,0,TAB_ROTATE]) TAB();
    }
}

```


[User]
I'm looking to design a parametric spool holder for 3D printer filament, similar to the design I have now, but I'd like it to be more easily customizable and use some standard libraries if possible. My current design is pretty basic and uses some hardcoded values.

Specifically, I need a holder that will mount to the side of my printer frame, or a similar flat surface. The core of the design should consist of:

1.  A vertical mounting bracket or flange. This will attach to the printer frame. It should be parameterized for height and thickness.
2. A horizontal rod or spindle for the filament spool to sit on. This should have a diameter and length that I can easily adjust. I need to be able to modify the length to accommodate different width spools. This rod should extend perpendicularly from the mounting bracket.
3. Ideally, there should be a small lip or flange at the end of the spindle to prevent the spool from sliding off.
4. I'd like to have parameters for all the major dimensions:
    *   Mounting bracket height
    *   Mounting bracket thickness
    *   Spindle diameter
    *   Spindle length
    *   Lip/flange thickness

My current spools have a 30mm center hole and are about 85mm wide, but I'd like a flexible design so I can accommodate other sizes in the future. I'd like to be able to specify the hole diameter as well, so that the rod diameter will be properly sized. I was hoping to use libraries to help avoid making errors. I'm hoping you can use `BOSL2` for this, it seems like the kind of thing it's good for.

[Assistant]
z18_spool_holder.scad:
```
// diameter of the rod
d=28;
// length of the rod
l=90;
// height of the rod
height=120; // [35:350]

difference() {
	union() {
		cube([35,6,d]);
		cube([4,13,d]);
		translate([0,10,0]) {
			cube([height,3,d]);
		}
		difference() {
			union() {
				translate([height,12,d/2]) {
					rotate([-90,0,0]) {
						cylinder(r=d/2, h=l+1+2, $fn=100);
					}
				}
				translate([height-3,12+1+l,d/2]) {
					rotate([-90,0,0]) {
						cylinder(r=d/2, h=2, $fn=100);
					}
				}
			}
			translate([height,10+l/4,d/2]) {
				rotate([-90,0,0]) {
					cylinder(r=d/2-9, h=l+1+2+10, $fn=100);
				}
			}
		}
	}
	translate([height,0,-1]) {
		cube([d/2+1,l+12+1+2+1,d+2]);
	}
}

```