[User]
I'd like to create a parametric coffin and lid using OpenSCAD. I've got some basic ideas and dimensions, but I need help translating this into a fully functional model.

The design should allow for switching between creating just the coffin base or just the lid. I'm also thinking about three different styles for the overall shape - "parisien", "lyonnais", and "tombeau", so the code needs to handle those as options. The dimensions I'm working with are based on the inside, specifically an internal length `L`, internal width `l`, and internal height `H`. I'll also want to set a thickness `Ep` for the material.

To add some customization, I'd like to include a "pouet" ratio that controls how the sides slope inwards towards the ends for the parisien and lyonnais styles. A basic cross decoration `croix` is needed, that can be either "simple" or "none". I'd also like to be able to include some text but that part is not super important to me.

Here are the key parameters I want to control:
*   `model`: Either "coffin" or "lid"
*   `type`: "parisien", "lyonnais", or "tombeau"
*   `L`: Internal length
*   `l`: Internal width
*   `H`: Internal height
*   `Ep`: Thickness
*   `pouet`: Sloping ratio
*   `croix`: Decoration type, "simple" or "none"
*  `txt`: Text

I'd like the code to be well-structured with modules for different parts, such as the base, the walls, and the lid. I think the basic 2D shapes should be defined first, then extruded to create the 3D components.

Could you provide the OpenSCAD code to do this? Also, I'm not sure which libraries are best for this project, but let me know if you think I should use any. Thanks!

[Assistant]
coffin.scad:
```
//+-----------------------------+
//|  OPENSCAD Cerceuil - coffin |
//|    2017 gaziel@gmail.com    |
//+-----------------------------+

//humain boby standart ( cm:175x55x41 175x60x45 185x55x41 185x60x45 195x55x41 195x60x45)
// barbie, ken  mm : 280*75*45
//classic Gi-joe  mm: 300*75*55
model="lid";//[coffin,lid]
//Coffin or lid type
type="lyonnais";//[parisien,lyonnais,tombeau]
// preview[view:south, tilt:top]
//internal Lenght
L=290;
// internal lenght
l=95;
// internal height
H=45;
//thinkness
Ep=3;
// ratio
pouet=0.22;//[0.10:0.01:0.40]
//decoration
croix ="simple";//[none,simple]
//
//text
//txt="test";

i=l*pouet;
j=L*(1-pouet);

module baseplate(ep){
    if (type=="tombeau"){
        square([L+2*ep,l+2*ep]);
    }
   if (type=="parisien"){
       polygon(points=[[0,i],[0,l-i+2*ep],[j+ep,l+2*ep],[L+2*ep,l-i+2*ep],[L+2*ep,i],[j+ep,0]], paths=[[0,1,2,3,4,5,,6]]);
   }

      if (type=="lyonnais"){
          polygon(points=[[0,i],[0,l-i+2*ep],[L++2*ep,l+2*ep],[L+2*ep,0]], paths=[[0,1,2,3]]);
   }

}
module base(Ep){
    linear_extrude(height = Ep, center = false, convexity = 10)baseplate(Ep);
}
module tourplate(){
    difference(){
        baseplate(Ep);
        translate([Ep,Ep,0])baseplate(0);
    }

}
module tour(H){
    linear_extrude(height = H, center = false, convexity = 10)tourplate();
}
module coffre(){
    base(Ep);
    translate([0,0,Ep])tour(H);
}
module couvercle(){

    if (type=="tombeau"){
        hull(){
            base(2*Ep);
            color("pink")translate([Ep,Ep,7*Ep])base(Ep);
        }
        translate([(L/2)+Ep,(l/2)+2*Ep,7*Ep])croix();
    }
    else{
        difference(){
            base(2*Ep);
            translate([Ep,Ep,Ep])tour(Ep);

        }
        translate([L/2+L/8,l/2+l/16,Ep])croix();
    }

}
module croix(){
    if (croix =="simple"){
            translate([0,0,Ep*1.5])cube([L/4,l/4,Ep],center=true);
            translate([L/10-L/16,0,Ep*1.5])cube([L/16,l/1.5,Ep],center=true);
           }
       }

//coffre();//test
//baseplate(Ep);//test
//baseextru();//test
//tour();//test
if (model=="coffin"){
coffre();
}
else{
couvercle();
}
```


[User]
I'm looking to create a parametric rheostat knob insert. I want to be able to adjust the outer diameter, height, depth of the hole, inner diameter of the hole, the number of splines, and the height of the splines. I'd also like some knurling on the outside.

Specifically, I want the following features:

*   **Outer Cylinder:** A main cylinder body that will form the outer shape of the insert.
*   **Inner Hole:** A cylindrical hole that will go most of the way through the insert.
*   **Splines:** Splines inside the hole that will interface with the rheostat shaft. I'd like to specify the number of splines. The splines should be formed by taking a regular polygon of the specified number of sides, and extruding it, and then cutting that out of the central hole. I also want to be able to adjust how far up into the hole the splines go.
*   **Knurling:** The outer cylinder should have some knurling. I'd like the knurling to be created by a series of small, diamond-shaped cylinders along the circumference. Specifically, for each row of knurls, I want to have two different offset rows.

I want to be able to adjust the following parameters:
*   `outside_diameter` (float, in mm): The diameter of the main cylinder.
*   `height` (float, in mm): The height of the main cylinder.
*   `depth` (float, in mm): The depth of the inner hole.
*  `hole_diameter` (float, in mm): The diameter of the inner hole.
*   `splines` (integer, must be a multiple of 3): The number of splines inside the inner hole.
*   `spline_height` (float, in mm): The height of the splines inside the hole.

Could you generate a parametric OpenSCAD file that will accomplish this? I'd prefer not to rely on any external libraries if possible.

[Assistant]
knob_insert.scad:
```
// This is a Guitar Knob Insert.
//
// Warning -- some sanding and fitting may be required.
//
// This is licensed under the creative commons+attribution license
//
// To fulfil the attribution requirement, please link to:
// http://www.thingiverse.com/thing:2226463

/* [Main] */

// Define number of facets (large numbers provide better smoothing)
$fn=100;

// Define height of knob in mm
height=12.5;

// Define outside diameter of knob in mm (without knurl)
outside_diameter=8.0;

// Define depth of hole in mm
depth=10.0;

// Define inside diameter of hole in mm
hole_diameter=6.5;

// Define number of splines (must be multiple of 3)
splines=24;

// Define height of splines in mm
spline_height=7.0;

module knurl1()
{
	for(i=[0:1:5])
	{
		translate([outside_diameter/2+height/24,0,i*height/6+height/12])
        rotate([0,90,0]) cylinder(h=height/12,r1=height/12,r2=0,center=true,$fn=4);
	}
}

module knurl2()
{
    for(i=[0:1:4])
    {

        translate([outside_diameter/2+height/24,0,i*height/6+height/6])
        rotate([0,90,0]) cylinder(h=height/12,r1=height/12,r2=0,center=true,$fn=4);
    }
}

module splines()
{
	union()
	{
		if(splines==0)
		{
			translate([0,0,depth/2]) rotate([0,0,angle]) cylinder(h=depth+1,r=hole_diameter/2,center=true,$fn=100);
		}
		if(splines!=0)
		{
			for(angle=[0:360/splines:360/3])
			{
				translate([0,0,depth/2]) rotate([0,0,angle]) cylinder(h=depth+1,r=hole_diameter/2,center=true,$fn=3);
			}
		}
		translate([0,0,-0.25]) cylinder(h=depth-spline_height,r=hole_diameter/2,center=false,$fn=100);
	}
}

difference()
{
	union()
	{
		// Draw outer shape
		translate([0,0,0]) cylinder(h=height,r=outside_diameter/2,center=false);

		// Draw small pyramids
		for(angle=[0:30:330])
		{
			rotate([0,0,angle])    knurl1();
            rotate([0,0,angle+15]) knurl2();
		}

	}

	// Drill inside hole
	splines();
}
```


[User]
I'd like to design a customizable pencil holder using OpenSCAD, kind of like the one I already made, but I want to give the design to someone else and have them generate the code.

The basic structure should be a cylindrical cup, but I want it to have a twisted, spoke-like design around the outside. Let's start with these main parameters:

*   **Overall Width:** This will be the diameter of the cup.
*   **Overall Height:** The total height of the pencil holder.
*   **Bottom Thickness:** The thickness of the base.
*   **Top Ring Height:** The height of the solid ring at the top of the cup.
*   **Wall Thickness:** The thickness of the cup's walls and the spokes.
*   **Twist Degrees:** The angle to twist the spokes around the cup's height. I'd like the twist to go both ways, creating a sort of helix, or double helix, pattern.
*   **Spokes Count:**  The number of spokes or vertical supports around the cup.
*   **Spokes Start:** This parameter will dictate how the spokes start at the base, using the following logic:
    *   1: The same place, all spokes should begin at the same spot, as in they would all be aligned with the same radial line coming out from the center of the cylinder.
    *   2: Next to each other, the spoke edges should line up next to each other as if the spokes are rotating along the cylinder, with one spoke starting immediately after another.
    *   3: The same distance, all spokes should be evenly spaced along the cylinder at their base, starting from the midpoint between two spokes.
*  **Spokes Shape:** 1: Circular, 2: Square; will define the shape of the cross section of the spokes.
*   **Bottom Ring:** A boolean to have a solid ring at the bottom, similar to the ring at the top of the cup.
*   **Bottom Ring Height:**  The height of the bottom ring (only used when the bottom ring parameter is set to yes).

I want the spokes to start from the top of the bottom solid part (or from the bottom ring, if selected) and continue to the base of the top ring. If a bottom ring is present, that should be cut out from the outer cylinder shape. Similarly, the top ring should also cut out from the same shape. I think this should be all the parameters I need. It shouldn't require any external libraries.

[Assistant]
pencil_holder_A.scad:
```
// Overall cup width (2 x radius)
width = 80;
// Overall height
height = 100;
bottomThickness = 2;
topRingHeight = 4;
wallThickness = 2;
twistDegrees = 90;
spokesCount = 16;
spokesStart = 2; // [1: The same place, 2: Next to each other, 3: The same distance]
spokesShape = 1; // [1: Circular, 2: Square]
bottomRing = 1; // [1: Yes, 0: No]
// Not needed if no bottom ring
bottomRingHeight = 4;

/* [Hidden] */
$fa = 1;
$fs = 0.5;

module bottom()
{
    cylinder(r = width / 2, h = bottomThickness);
}

module topRing()
{
    translate([0, 0, height - bottomThickness - topRingHeight])
        difference()
        {
            cylinder(r = width / 2, h = topRingHeight);
            translate([0, 0, -1])
                cylinder(r = width / 2 - wallThickness, h = topRingHeight + 2);
        }
}

module spokesSide(twist)
{
    for(i = [1 : spokesCount])
    {
        rotate([0, 0, (i * (360 / spokesCount))])
            spokeSideRotate(twist);
    }
}

module spokeSide(twist)
{
    translate([0, 0, bottomThickness + (bottomRing ? bottomRingHeight : 0)])
        linear_extrude(height = height - bottomThickness - topRingHeight - (bottomRing ? bottomRingHeight : 0), twist = twist)
            translate([0, width / 2 - wallThickness / 2, 0])
                circle(r = wallThickness / 2, $fn = (spokesShape == 2 ? 4 : $fn));
}

module spokeSideRotate(twist)
{
    if(spokesStart == 2 && twist > 0)
        // arc length simplified to wallThickness value
        rotate([0, 0, -(360 * wallThickness) / (2 * PI * (width / 2 - wallThickness / 2))])
            spokeSide(twist);
    else if(spokesStart == 3 && twist > 0)
        rotate([0, 0, -360 / spokesCount / 2])
            spokeSide(twist);
    else
        spokeSide(twist);
}

module spokes()
{
    spokesSide(twistDegrees);
    spokesSide(-twistDegrees);
}

module bottomRing()
{
    translate([0, 0, bottomThickness])
        difference()
        {
            cylinder(r = width / 2, h = bottomRingHeight);
            translate([0, 0, -1])
                cylinder(r = width / 2 - wallThickness, h = bottomRingHeight + 2);
        }
}

bottom();
topRing();
spokes();
if(bottomRing && bottomRingHeight < height - 2 * bottomThickness)
    bottomRing();

```


[User]
I want to design a customizable hollow egg-shaped carrier, like a container that can be split into two halves. The two halves should mate together securely using a combination of alignment pins and a snap-fit mechanism. I'd like to control a few key dimensions, such as the overall length of the egg, the wall thickness, and the size of the coupler that will fit into a tube, like a rocket body.

Specifically, I want the design to be parametric and generated by an OpenSCAD file or files. Let's call the two halves "Side-A" and "Side-B". Side-A and Side-B will be identical except for the snap feature.

Here are the details:

*   **Overall Shape:** The main body should be an egg shape. I'll need a way to define this profile, probably with a mathematical function, and it should be customizable with a length parameter.
*   **Shell Thickness:** The wall thickness of the egg shell needs to be adjustable.
*   **Coupler:** Each side should have a cylindrical coupler extending outwards that can fit into a tube. I need to control the length and diameter of this coupler's shoulder and fitting sections separately.
*   **Alignment Pins/Holes:** Each half should have alignment features - Side-A will have cylindrical pins and Side-B will have holes to receive them. I'd like to control the diameter of the pins/holes, as well as the depth of the holes. The number of pins and locations should be configurable.
*   **Snap Feature:** One side should have a snap-fit mechanism to hold the two halves together. Side-A will have the protruding boss, and Side-B will have the receiving cut-out and an additional slot to receive a separate snap piece. The width, height, and thickness of the snapping features must all be customizable. There will be a separate snap piece which can be press-fit or glued into the slot on Side-B. This piece will have a barb-like shape to hold the two halves together firmly.
*   **Part Selection:** It should be possible to select a specific part ("A-Side", "B-Side", or "Snap") to generate via a variable.
*   **OpenSCAD libraries:** I'm not using any OpenSCAD libraries, so the entire design needs to be done in base OpenSCAD.
*   **Units:** Assume dimensions are in millimeters.
*   **Customization:** I need to be able to control all of the parameters through variables at the beginning of the file, including the number of alignment pins, their locations along the egg axis, and the dimensions of the snap feature.

I'm not sure how to achieve the proper tolerances for mating of parts - can you provide some advice? Maybe it's just a matter of using a small offset?

[Assistant]
Customizable_hollow_egg_carrier.scad:
```
// Copyright 2017 Arthur Davis (thingiverse.com/artdavis)
// This file is licensed under a Creative Commons Attribution 4.0
// International License.
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.

// Optimize view for Makerbot Customizer:
// preview[view:south east, tilt:bottom]

// Choose geometry:
part = "A-Side"; // [A-Side, B-Side, Snap]
// Length of the Egg Casing Shell
case_length = 80; // [60:2:100]
// Coupler Shoulder Length
coupler_shoulder_len = 6.0; // [1.0:1.0:25.0]
// Coupler Shoulder Diameter
coupler_shoulder_diam = 22; // [10.0:0.2:50.0]
// Fitting Shoulder Length
coupler_fitting_len = 12.0; // [5.0:1.0:25.0]
// Fitting Shoulder Diameter
coupler_fitting_diam = 17.9; // [10.0:0.2:50.0]
// Wall thickness
wall_th = 2.0; // [1.0:0.2:4.0]
// Alignment boss diameters
boss_diam = 5; // [2.0:0.2:10.0]
// Alignment pin hole dimaters
pin_diam = 2.2; // [1.0:0.2:6.0]
// Depth of alignment pin holes
pin_depth= 4.0; // [1.0:0.2:10.0]
// Width of the snapping feature boss
snap_boss_wd = 10.0; // [2.0:1.0:20.0]
// Height of the snapping feature boss
snap_boss_ht = 3.0; // [1.0:1.0:10.0]
// Thickness of the snapping feature
snap_th = 2.0; // [1.0:1.0:6.0]
// Width of the snapping feature
snap_wd = 8.0; // [2.0:1.0:18.0]

/* [Hidden] */
// Special variables for facets/arcs
$fn = 48;

// Incremental offset to make good overlap for CSG operations
delta = 0.1;

// Amount to undersize features so they'll fit into cutouts
fit_tol = 0.2;

// Coupler extension to overlap with egg shell
coupler_extra = 50.0;

// Number of steps to sample the half profile of the shell
steps = 100;

// X-coordinates for the studs
stud_xpts = [0.2 * case_length, 0.8 * case_length];

// Egg profile computing function
function egg(x, l=case_length)= 0.9*l*pow(1-x/l, 2/3)*sqrt(1-pow(1-x/l, 2/3));

// Create egg profile
module egg_profile(length=case_length, offset=0, steps=steps) {
    ss = length / (steps-1); // step size
    v1 = [for (x=[0:ss:length]) [egg(x, length), x + offset]];
    // Make absolute sure the last point brings the profile
    // back to the axis
    v2 = concat(v1, [[0, length + offset]]);
    // Close the loop
    v3 = concat(v2, [[0, offset]]);
        polygon(points = v3);
}

// Create a solid egg part
module solid_egg(length=case_length, offset=0, steps=steps) {
    rotate_extrude(convexity = 10) {
        egg_profile(length=length, offset=offset, steps=steps);
    }
}

// Create exterior shell trimming volume
module egg_trim(length=case_length, offset=0, steps=steps){
    difference() {
        translate(v = [-delta, -length*1.05, -delta]) {
            cube(size=2.1*length);
        }
        rotate(a = [0, 90.0000000000, 0]) {
            solid_egg(length=length, offset=offset, steps=steps);
        }
    }
}

module main_body() {
    rotate(a = [0, 90.0000000000, 0])
    {
        difference() {
            difference() {
                union() {
                    solid_egg(length=case_length, offset=0, steps=steps);
                    difference() {
                        union() {
                            translate(v = [0, 0, -coupler_shoulder_len]) {
                                cylinder(d = coupler_shoulder_diam,
                                         h = coupler_shoulder_len + coupler_extra);
                            }
                            translate(v = [0, 0,
                                    -(coupler_shoulder_len+coupler_fitting_len)]) {
                                cylinder(d = coupler_fitting_diam,
                                         h = coupler_fitting_len + delta);
                            }
                        }
                        translate(v = [0, 0,
                        -(coupler_shoulder_len + coupler_fitting_len + delta/2.)]) {
                            cylinder(d = coupler_fitting_diam - 2 * wall_th,
                                     h = coupler_shoulder_len + coupler_extra + coupler_fitting_len + delta);
                        }
                    }
                }
                solid_egg(case_length - 2*wall_th, wall_th);
            }
            translate(v = [0, -100.0000000000, -100.0000000000]) {
                cube(size = 200);
            }
        }
    }
}

module stud(loc_diam, cyl_diam, ht, x) {
    translate(v = [x + loc_diam/2, egg(x, case_length - loc_diam), 0]) {
        cylinder(h=ht, d=cyl_diam);
    }
    translate(v = [x + loc_diam/2, -egg(x, case_length - loc_diam), 0]) {
        cylinder(h=ht, d=cyl_diam);
    }
}

// Create boss features for mating the shell haves
module egg_boss() {
    difference() {
      union() {
          for(x = stud_xpts)stud(boss_diam, boss_diam, case_length, x);
            }
        egg_trim();
    }
}

// Create boss feature for snap geometry (A-Side)
module snap_boss_a(){
    difference() {
        translate(v = [case_length - snap_boss_ht - wall_th, -snap_boss_wd/2, 0]) {
            cube(size = [snap_boss_ht, snap_boss_wd, wall_th]);
        }
        egg_trim();
    }
}

// Create boss feature for snap geometry (B-Side)
module snap_boss_b(){
    difference() {
        difference() {
            translate(v = [case_length - 2*snap_boss_ht - wall_th - fit_tol, -snap_boss_wd/2,0]) {
                cube(size = [2*snap_boss_ht + fit_tol, snap_boss_wd, case_length]);
            }
            translate(v=[case_length - 2*snap_th - snap_boss_ht - fit_tol, -snap_wd/2, 0]) {
            cube(size = [snap_th, snap_wd, case_length]);
            }
        }
        egg_trim();
    }
}

module make_nosecone() {
    difference() {
        union() {
            main_body();
            if (part == "A-Side") {
                snap_boss_a();
            } else if (part == "B-Side") {
                snap_boss_b();
            }
            egg_boss(diam=boss_diam);
        }
        for(x = stud_xpts)stud(boss_diam, pin_diam, pin_depth, x);
    }
}

module make_snap() {
    slen = 3 * wall_th; // Snap length
    sht = 2*wall_th; // Snap height
    sth = wall_th - fit_tol; // Snap thickness
    swd = snap_wd - fit_tol; // Snap width
    union() {
        cube(size = [sth, slen, swd]);
        difference() {
            translate(v=[0, slen, 0]){
                cube(size = [sht, sth, swd]);
            }
            translate(v=[sht, slen, -delta/2]){
                rotate(a=[0, 0, 45])
                cube(size = [2*sth, 2*sth, swd + delta]);
            }
        }
    }
}

// Allow MakerBot Customizer to generate STL based on part selection
module print_part() {
    if (part == "Snap") {
        make_snap();
    } else {
        make_nosecone();
    }
}

//part = "A-Side";
//part = "B-Side";
//part = "Snap";
print_part();
```


[User]
I'd like to have a customizable OpenSCAD model for a bed leveling test. It should print a grid of circles, and I need to be able to specify how many circles in the x and y directions, the diameter of the circles, their height, and the spacing between them.

Specifically, I'd like to control these parameters:

*   `num_circles_x`: The number of circles in a row.
*   `num_circles_y`: The number of circles in a column.
*   `circle_diameter`: The diameter of each circle.
*   `circle_height`: The height of the circles (this will control the thickness of the test).
*   `x_spacing`: The distance between the center of circles horizontally.
*   `y_spacing`: The distance between the center of circles vertically.

The model should output a single object consisting of all circles. I'd like to avoid using any external libraries for this simple model. The default resolution should be fine, as I only plan to print these.

[Assistant]
circle-test.scad:
```
// 9-Area Bed Level Calibration Test
// V1.0 - 2017/04/06
//
// timfou - Mitch Fournier
// http://www.thingiverse.com/thing:2230659

// How many circles in a row? (Default: 3)
num_circles_x = 3;
// How many circles in a column? (Default: 3)
num_circles_y = 3;
// Diameter of the test circles (Default: 40mm)
circle_diameter = 40;
// Height of the circles (Default: 0.3mm, good for 0.2mm layer test)
circle_height = 0.3;
// X-spacing between circle centers (Default: 95mm)
x_spacing = 95;
// Y-spacing between circle centers (Default: 75mm)
y_spacing = 75;

$fn=128*1;

// = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
//	Draw ***ALL THE CIRCLES***
// = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
linear_extrude(circle_height) drawCircles();

module drawCircles() {
	for (i=[0:num_circles_y-1]) {
		for (j=[0:num_circles_x-1]) {
			translate([j*x_spacing,i*y_spacing,0]) circle(circle_diameter/2);
		}
	}
}
```


[User]
I'm looking for an OpenSCAD design for a parametric, printable battery holder, specifically for cylindrical cells. I've been using a modified version of the "flexbattery" design, and I want something more flexible and user-friendly from the ground up. My current version is optimized for 18650s, but I'd like to be able to support a wider range of battery sizes, with the possibility of easily extending to other sizes in the future, along with features like stackability.

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

**Core Functionality:**

*   **Parametric Design:** The design should be fully parametric, allowing me to specify the number of batteries, cell diameter, cell length, extrusion width, material thickness etc., and overall dimensions. The goal is to easily support various cylindrical cell sizes such as 18650, 21700, AA, AAA, C, and D, or even specific variants of each, like protected 18650s vs unprotected ones.
*   **Flexible Spring Contacts:** I want integrated, printed flexible springs for the negative terminal contact. These should be designed for reliable contact while being printable from a variety of material, and easy to modify with additional parameters.
*   **Simplified Wiring:** Instead of internal wire channels, I prefer an external wiring approach, with simple, easy-to-access terminals for both positive and negative contacts, allowing for simple soldering or twist/crimp connections.
*   **Single-Layer and Stackable:** I want each cell to rest on a flat base for easy single-layer printing. I'd also love for each module to be designed for easy stacking and clipping, allowing for creation of larger battery packs if desired.
*   **Minimalist Design:** Focus on quick printing, reduced material usage, and ease of assembly, so avoid unnecessary frills.

**Specific Design Elements:**

*   **Battery Cavity:** The cavity for each battery needs to be sized correctly with a small tolerance for easy insertion and removal. The bottom of the cavity should be flat, and a small lip at the top can be used to help secure the battery.
*   **Spring Design:** The printed spring should have a simple, effective design that maximizes flex and reduces width, while still being strong enough to keep batteries firmly in place.
*   **Terminal Design:** Simple posts/bumps for the positive and negative terminals that allow wire to be easily wrapped and connected, with enough spacing to prevent shorts.
*   **Stacking:** If stacking is implemented, the mating surfaces should lock cells together without relying on screws.
*   **Dimensions:** A starting point would be using a 0.45mm extrusion width and 0.35mm layer height but I would like all relevant dimensions to be parameterized in the top level.
*   **Mounting:** A few small mounting holes for screws for securing the holder to a surface.

**Output:**

*   I would like all code to be well-commented and use a modular design approach, separating different functions in separate modules (where this makes sense). I would also prefer to only use the core OpenSCAD language, and avoid unnecessary external libraries.
*   I'd like you to provide both a core module that handles the battery holder generation and a selection of preset modules for all the battery types mentioned above.
*   Also, include a short module to preview a single cell and a multi-cell holder for all of the listed battery types to make testing and visual confirmation easy.

I think that's all for now. Let me know if you have any questions, and thanks for your help!

[Assistant]
flexbattery-18650-fiveangle.scad:
```
//////////////////////////////////////////////////////////////////////////////////////
///
///  FLEXBATTER: Flexing battery holder with built-in spring
///
///  This file generates battery holders for arbitrary cylindrical sizes.
///  The number of batteries and their size is fully parametrized.
///
///  The usual metallic spring at the minus pole is replaced by a
///  flexible printed spring, which is pressing the contacts firmly to
///  the battery.
///
///  The contacts for the plus and minus pole can easily be made by
///  a few windings of the uninsulated ends of the connecting wires.
///  Each battery compartment contains are several holes to the outside
///  as well ad to the neighboring compartments, through which connecting
///  wires can be passed for easy configuring of parallel, serial or
///  balanced-serial battery packs.
///
///  The preconfigured battery sizes are:
///  AA, AAA, C, D, 18650(Li-Ion), 18650P(protected Li-Ion), CR123A(16340)
///
///  Given that the printed plastic spring needs to be flexible, ABS is the material
///  of choice here.
///
//////////////////////////////////////////////////////////////////////////////////////
///
///  2014-09-09 Heinz Spiess, Switzerland
/*
2017apr06 - Dave Johnson - fiveangle@gmail.com
-Optimized for print speed and reduced material usage:
  -Removed all wire channels which allowed making the base 3 full layers (@0.350mm) thinner (as such, all wiring must be routed externally)
  -Removed the double slots for battery terminals, allowing the wire to simply fold over the top
  -Extended cylindrical bump designed to protrude wire for battery terminal to front-back to allow one to wrap the wire around the top and twist around itself more easily
  -Reduced overally height to exactly mid-level (giving up ability to stack - mine can be used only single-layer)
  -Redesigned spring to remove double-width unsprung area (reducing width of each slot by 4 ew)
  -Removed side and bottom grooves
  -Reduced walls between adjacent batteries to 2 shells (@0.45ew)
  -Removed text and battery markings
  -Reduced wall height using a modified version of enif's "grip" feature
  -Probably plenty of other things and small bugfixes I don't remember
  -This file is hacked together to get only the 18650 battery to work so is not longer generic (but feel free to fix if you want :)
*/
///  released under Creative Commons - Attribution - Share Alike licence (CC BY-SA)
//////////////////////////////////////////////////////////////////////////////////////
$fn = 72;

// build a cube with chamfered edges
module chamfered_cube(size, d = 1) {
    hull() {
        translate([d, d, 0]) cube(size - 2 * [d, d, 0]);
        translate([0, d, d]) cube(size - 2 * [0, d, d]);
        translate([d, 0, d]) cube(size - 2 * [d, 0, d]);
    }
}

// draw an arc width height h between radius r1..r2 and angles a1..a2
module arc(r1, r2, h, a1 = 0, a2 = 0) {
    if (a2 - a1 <= 180) {
        difference() {
            cylinder(r = r2, h = h);
            translate([0, 0, -1]) cylinder(r = r1, h = h + 2);
            rotate(a2) translate([-r1 - r2, 0, -1]) cube([2 * (r1 + r2), 2 * (r1 + r2), h + 2]);
            rotate(a1 + 180) translate([-r1 - r2, 0, -1]) cube([2 * (r1 + r2), 2 * (r1 + r2), h + 2]);
        }
    } else {
        difference() {
            cylinder(r = r2, h = h);
            translate([0, 0, -1]) cylinder(r = r1, h = h + 2);
            intersection() {
                rotate(a2) translate([-r1 - r2, 0, -1]) cube([2 * (r1 + r2), 2 * (r1 + r2), h + 2]);
                rotate(a1 + 180) translate([-r1 - r2, 0, -1]) cube([2 * (r1 + r2), 2 * (r1 + r2), h + 2]);
            }
        }
    }
}

/////////////////////////////////////////////////////////////////////////////////
// sline - generate a "snake line" of width w and height h
// with a arbitrary sequence of segments defined by a radius and a turning angle
//
//   angle[i] > 0  left turn / counter-clockwise
//   angle[i] < 0  left turn / clockwise
//   angle[i] = 0  straight segment with length radius[i]
//
/////////////////////////////////////////////////////////////////////////////////
// Heinz Spiess, 2014-09-06 (CC BY-SA)
/////////////////////////////////////////////////////////////////////////////////
module sline(angle, radius, i, w, h) {
    scale([angle[i] >= 0 ? 1 : -1, 1, 1])
    assign(r = abs(radius[i])) assign(a = angle[i])
    translate([a ? r : 0, 0, 0]) {
        translate([-w / 2, -r - 0.01, 0]) cube([w, 0.02, h]); // tiny overlap!
        if (a) arc(r - w / 2, r + w / 2, 0, a, h = h);
        else if (r > 0) translate([-w / 2, -r, 0]) cube([w, r, h]);
        if (i + 1 < len(angle))
            rotate(angle[i])
        translate([a ? -r : 0, a ? 0 : -r, 0])
        sline(angle, radius, i + 1, w, h);
    }
}

//////////////////////////////////////////////////////////////////////////////////
//
//  FLEXBATTER:  Flexing battery holder with integrated plastic spring
//
//////////////////////////////////////////////////////////////////////////////////
module flexbatter(n = 1, l = 65, d = 18, hf = 0.75, r = 4, shd = 3, eps = 0.28, el = 0, xchan = [1 / 4, 3 / 4], $fn = 24) {
    ew = 0.45; // extrusion width
    eh = 0.35; // extrusion height
    w = 2 * ew; // case wall thickness
    ws = 2 * ew; // spring wall thickness
    ch = ws - ws; // edge chamfering
    deepen = 1; //deepening for side grip of batteries
    el = 0; // extra length in spring
    eps = 0.28 - 0.28;
    //shd = 3; // screw hole diameter
    //hf=0.75;
    //xchan=[1/4,3/4]; // relative position of traversal wire channels

    r = d / 5 + 2 * ws; // linear spring length (depends on sline() call!)

    for (i = [0: n - 1]) translate([0, i * (d + w + ws - w), 0]) { // generate n battery cases
        difference() {
            union() {
                difference() {
                    // main body
                    // translate([0, -w - d / 2, 0]) chamfered_cube([l + w, d + 2 * w + (i < n - 1 ? ws : 0), hf * d + w + ch], ch);
                    translate([0, -w - d / 2, 0]) chamfered_cube([l + w, d + 2 * w + (i < n - 1 ? 0 : 0), hf * d + w + ch], ch);
                    // main cavity
                    translate([-2, -d / 2, w]) cube([2 + l, d, d + 1]);
                    // cavity for locating plastic spring
                    translate([-1, -d / 2, -1]) cube([1, d, d + w + 2]);
                    // small cylindrical carving of walls and bottom
                    if (eps > 0) translate([-1, 0, d / 2 + w]) rotate([0, 90, 0]) cylinder(r = d / 2 + eps, h = l + 1);
                }
                difference() {
                    // plastic spring for minus pole
                    for (sy = [-1, 1]) scale([1, sy, 1]) assign(D = d + 2 * w - 2 * ws - 0.7) {
                        translate([ch, d / 2 + w - ws / 2, 0]) rotate(-90)
                        //sline([90,0,120,90,120,90,0],[d/8+2,d/6,d/8-1,d/8,-d/8,d/8,d/2],0,ws,hf*d+w);
                        sline([0, 180, 0, 180, 0, -180, 0, 90, 0], [r + ch + el, D / 4, el, D / 12, el / 2, D / 12, 1 + el / 2, D / 5, D / 3], 0, ws, hf * d + w);
                    }

                }
            }

            // lower and upper holes for contacts
            for (z = [-2 * ws, 2 * ws])
                translate([-2 * ws, -w, w - ws / 2 + d / 2 + z]) cube([l + 2 * w + 2, 2 * w, 2 * ws]);

            // longitudinal bottom wire channel
            //translate([-2*ws,0,0])rotate([0,90,0])cylinder(r=w/2,h=l+w+2+r,$fn=5);

            // traversal bottom wire channels
            //for(x=l*xchan)translate([x,-d/2-w-1,eh]) rotate([-90,0,0])cylinder(r=w/2,h=d+2*w+ws+2,$fn=6);

            // grip deepening
            if (deepen > 0)
                translate([w + l / 2 - 0.5, -d / 2 - w - 0.01, w + d + l + (3.3)]) {
                    rotate([-90, 0, 0]) {
                        cylinder(r = l + deepen * d, h = d + 2 * w + 2 * ws + 2, $fn = 72);
                        if (i == 0) cylinder(r1 = l + deepen * d + ch, r2 = l + deepen * d, h = ch + 0.02, $fn = 72);
                        if (i == n - 1) translate([0, 0, d + 2 * w - ch]) cylinder(r2 = l + deepen * d + ch, r1 = l + deepen * d, h = ch + 0.02, $fn = 72);
                    }
                }
                                        // cap angle from deepen operation
                    translate([-(w + l / 2 - 0.5), -d / 2 - w - 0.01, d - (7.6)]) {
                        cube([100, d + 2 * w + 2 * ws + 2, 100]);
                    }

        }
        // conical screw holes in corners
        /*
              for(x=[7+shd,l-2*shd])for(y=[-d/2+shd,d/2-shd])
            translate([x,y,-1]){
               cylinder(r=shd/2,h=w+2);
               translate([0,0,w-shd/2+1])cylinder(r1=shd/2,r2=shd,h=shd/2+0.01);
            }
              */

        // holes for wires passing inside
        /*
               for(sy=[-1,1])scale([1,sy,1]){
	    translate([l-1,-d/2,w])cube([w+2,2,2]);
            for(x=[3,l-7])translate([x,-d/2-w-ws-1,w])cube([3,w+ws+3,2]);
            translate([3,-d/2+w/2-0.75,-1])cube([3,1.5,w+2]);
            translate([-0.5,-d/2+w/2,0])rotate([0,90,0])cylinder(r=w/2,h=6.5,$fn=5);
         }
               */

        // engrave battery symbol
        /*
         translate([w+l/2,d/4+1,w])cube([l/5,d/4.5,4*eh],true);
	 translate([w+l/2+l/10,d/4+1,w])cube([d/7,d/10,4*eh],true);
	 // engrave plus symbol
	 assign(sy=(l>12*shd)?1:-1){ // for short batteries +- on the side
	    translate([w+l/2+l/(sy>0?5:10),sy*(d/4+1),w]){
	       cube([1,d/4,4*eh],true);
	       cube([d/4,1,4*eh],true);
            }
	 // engrave minus symbol
	    translate([w+l/2-l/(sy>0?5:10),sy*(d/4+1),w])
	       cube([1,d/4,4*eh],true);
         }
         */

        //correction for middle separators
        /*
                 if(i<n-1) translate([-d,d/2+w,-1])cube([d,ws/2+0.1,d+2]);
        	 else translate([1,d/2+w,-0.01])cylinder(r1=ch,r2=0,h=ch);
                 if(i>0) translate([-d,-d/2-w-0.1,-1])cube([d,ws/2+0.1,d+2]);
        	 else translate([1,-d/2-w,-0.01])cylinder(r1=ch,r2=0,h=ch);
        */

        // horizontal contact bulges (+ and - pole)
        for (x = [-0.8, l+0.5])
            hull() for (y = [-3 + el, 3 - el])
                translate([x, y, w + d / 2]) sphere(r = ws);

        // vertical contact bulge (+ pole only)
        //if(0)hull()for(z=[-3+el,3-el])for(x=[0,w-ws])
        //      translate([l+x,0,w+d/2+z])sphere(r=ws);

    }

}

module flexbatter18650(n = 1) {
    flexbatter(n = n, l = 65.5, d = 18.4, hf = 0.75, shd = 3, eps = 0.28);
}

module flexbatter18650P(n = 1) {
    flexbatter(n = n, l = 67.5, d = 18.4, hf = 0.75, shd = 3, eps = 0.28);
}

module flexbatterCR123A(n = 1) {
    flexbatter(n = n, l = 35.1, d = 16.7, hf = 0.75, shd = 3, xchan = [0.5], eps = 0.28);
}

module flexbatterD(n = 1) {
    flexbatter(n = n, l = 61.5, d = 34.0, hf = 0.75, shd = 3, eps = 0.28);
}

module flexbatterC(n = 1) {
    flexbatter(n = n, l = 51.6, d = 26.4, hf = 0.75, shd = 3, eps = 0.28);
}

module flexbatterAA(n = 1) {
    flexbatter(n = n, l = 51.6, d = 14.4, hf = 0.80, shd = 2.5, el = 0.5, eps = 0.28);
}

module flexbatterAAA(n = 1) {
    flexbatter(n = n, l = 46.1, d = 10.45, hf = 0.84, shd = 2, el = 1, xchan = [0.5], eps = 0);
}

module flexbatter18650x1() { // AUTO_MAKE_STL
    flexbatter18650(n = 1);
}

module flexbatter18650Px1() { // AUTO_MAKE_STL
    flexbatter18650P(n = 1);
}

module flexbatterCR123Ax1() { // AUTO_MAKE_STL
    flexbatterCR123A(n = 1);
}

module flexbatterAAx1() { // AUTO_MAKE_STL
    flexbatterAA(n = 1);
}

module flexbatterAAAx1() { // AUTO_MAKE_STL
    flexbatterAAA(n = 1);
}

module flexbatterCx1() { // AUTO_MAKE_STL
    flexbatterC(n = 1);
}

module flexbatter18650x2() { // AUTO_MAKE_STL
    flexbatter18650(n = 2);
}

module flexbatterAAx2() { // AUTO_MAKE_STL
    flexbatterAA(n = 2);
}

module flexbatterAAAx2() { // AUTO_MAKE_STL
    flexbatterAAA(n = 2);
}

module flexbatterCx2() { // AUTO_MAKE_STL
    flexbatterC(n = 2);
}

module flexbatter18650x3() { // AUTO_MAKE_STL
    flexbatter18650(n = 3);
}

module flexbatterAAx3() { // AUTO_MAKE_STL
    flexbatterAA(n = 3);
}

module flexbatterAAAx3() { // AUTO_MAKE_STL
    flexbatterAAA(n = 3);
}

module flexbatter18650x4() { // AUTO_MAKE_STL
    flexbatter18650(n = 4);
}

module flexbatterAAx4() { // AUTO_MAKE_STL
    flexbatterAA(n = 4);
}

module flexbatterAAAx4() { // AUTO_MAKE_STL
    flexbatterAAA(n = 4);
}

// uncomment as needed:

//flexbatterCR123A(n=2);
//rotate([0,0,0])translate([0,0,-9])flexbatter18650(n=1);
//translate([0,40,0])rotate([90,0,0])translate([0,0,-9])flexbatter18650(n=1);
//translate([0,80,0])rotate([180,0,0])translate([0,0,-9])flexbatter18650(n=1);
//translate([0,120,0])rotate([-90,0,0])translate([0,0,-9])flexbatter18650(n=1);
//translate([0,33,0])flexbatter18650(n=2);
//translate([0,90,0])flexbatter18650(n=3);
//translate([-90,33,0])flexbatter18650(n=4);
//translate([0,28,0])flexbatterAA(n=1);
//translate([0,50,0])flexbatterAAA(n=1);
//flexbatterC(n=1);
//flexbatterD(n=1);
//translate([0,40,0])flexbatter18650(n=8);
flexbatter18650(n = 1);
```


[User]
I'm looking to create a custom divided box with a sliding lid, and I'd like it to be parametric so I can easily adjust the dimensions and features. I've seen some similar designs, but I need more control over the compartment sizes and fit.

Here's what I'm hoping to achieve:

**Compartments:**

*   I need to be able to specify the internal dimensions of each compartment separately in both the X and Y directions. So, I'd provide lists of compartment lengths and widths, and the code should calculate the overall internal box dimensions.
*   The compartment heights will all be the same, so I'll just define one value for that.
*   I'll need to be able to set the wall thickness for the box, as well as the thickness of the dividers.
*   I'd like to add an option to have the dividers slope down slightly at the edges - maybe a min and max height, and the dividers are tallest in the middle. It would be great if I could specify the percentage of the divider length at the max height, so I could tune this to the geometry that works best.
* I want to define a radius for the rounded corners of the box.

**Lid:**

*   The lid should be a sliding fit. I need parameters to adjust the fit tolerance in the X, Y, and Z directions separately, for both the hole in the box and the lid itself. This is super important, since my printer requires different offsets for proper fits.
*   I would like a small fingernail slot to make opening easier. I'd like to adjust its depth with a parameter as well.
*   It would be awesome if I could optionally add a catch to help secure the lid in place.
    *   This catch would consist of a bump on the box and a corresponding hole in the lid.
    *   I'd like to adjust the size of the bump and hole, as well as their position on the box. It would be useful if these positions were controlled by a percentage of the box width.
    * I want to define the cylinder diameter of the catch bump, and the diameter of the hole for the catch.
    * I would like to position the catch hole based on a percentage of the box wall thickness (0 is outer edge, 1 is inner edge).

**Overall:**

*   I need a way to specify which part to render, i.e. just the box, just the lid, or both.
*   I'd prefer to use the `MCAD` library for the rounded box function, if possible.

Could you generate the necessary OpenSCAD files for this? I'm thinking of the code in the `Box_Customizer.scad` file I've given you, but I'd like you to generate it from scratch. Please also include code for the `boxes.scad` file that you're referencing from the MCAD library.

[Assistant]
Box_Customizer.scad:
```

/*
  Add a ready made library for making rounded boxes
  Learn more about the MCAD libraries here: http://reprap.org/wiki/MCAD
*/
include <MCAD/boxes.scad>

/*
  OpenSCAD Parametric Divided Box V.2 by Ryan Burnsides
  - Based heavily on OpenSCAD Parametric Box Lesson and Box With Sliding Top by Aaron Ciuffo - http://www.thingiverse.com/thing:1201466 - OpenSCAD Parametric Box Lesson
    - http://www.thingiverse.com/thing:201304 - Box With Sliding Top

  April 2017

  Released under the Creative Commons Share Alike License
  http://creativecommons.org/licenses/by-sa/3.0/

  Thanks to:
  Aaron Ciuffo for his excellent lesson

  This version adds the following functionality
  - Custom compartment sizes, specify different size for each compartment
  - Automatic calculation of box dimensions from compartment requirements
  - Optional catch
  - More options for fit tuning

  Roadmap:
  - Can I think of an elegant way to allow variable numbers of sub-compartments instead of forcing a grid?
  - Is there a better shape for the sliding mechanism that is easier to tune for fit?
  - Add support for extruded custom text on lid
 */

// Which part would you like to see?
part = "both"; // [first:Box Only,second:Lid Only,both:Box and Lid]

/* [Compartment Sizes] */
// use the following syntax to add 1 or more internal x compartment lengths (mm)
x_compartment_sizes = [67];
// use the following syntax to add 1 or more internal y compartment widths (mm)
y_compartment_sizes = [92, 20];
// internal compartment height in (mm)
compartment_height=10;
// wall thickness (mm)
wall_thickness = 3;
// corner radius (mm)
corner_rad = 2;

/* [Dividers] */
// divider thickness (mm)
divider_thickness = 2;
// divider can be made to slope lower at edges
divider_min_height = 8.5;
divider_max_height = 9.8;
// percentage of divider at max height, max height will be in the middle of the divider
divider_percent_at_max_height = .6;

/* [Catch] */
// print a catch to help hold the lid in place
print_catch = "yes"; // [yes, no]
// diameter of catch cylinder (mm)
catch_diameter = 1;
// width of hole for catch (mm)
catch_hole_diameter = 2;
// length of catch bump as a percentage of box width
catch_bump_ratio = .65;
// length of catch hole as a percentage of box width
catch_hole_ratio = .75;
// position of catch bump on box wall as a percentage of wall thickness (0 is outer edge, 1 is inner edge)
catch_wall_ratio = .75;

/* [Fit Tuning] */
// Change hole x by this amount, if negative, need digit before decimal point (mm)
hole_buffer_x = .1;
// Change hole y by this amount, if negative, need digit before decimal point (mm)
hole_buffer_y = .1;
// Change hole z by this amount, if negative, need digit before decimal point (mm)
hole_buffer_z = .1;
// Change lid x by this amount, if negative, need digit before decimal point (mm)
lid_buffer_x = -0.25;
// Change lid y by this amount, if negative, need digit before decimal point (mm)
lid_buffer_y = -0.15;
// Change lid z by this amount, if negative, need digit before decimal point (mm)
lid_buffer_z = -0.25;
// Adjust depth of fingernail hole, make this bigger to make the hole deeper (mm)
slot_adjust = 1;

/* [Hidden] */
fudge = .01;
wall_sub = wall_thickness*2;

function SumList(list, start, end) = (start == end) ? 0 : list[start] + SumList(list, start+1, end);
function ComputeInnerBoxDimension(compartment_list_x, compartment_list_y) = [SumList(compartment_list_x, 0, len(compartment_list_x)) + (len(compartment_list_x) - 1)*divider_thickness, SumList(compartment_list_y, 0, len(compartment_list_y)) + (len(compartment_list_y) - 1)*divider_thickness, compartment_height];
function ComputeOuterBoxDimension(innerBox) = [innerBox[0] + wall_thickness*2, innerBox[1] + wall_thickness*2, innerBox[2] + wall_thickness*2];
function lid_cut_height() = wall_thickness + hole_buffer_z;
function lid_solid_height() = wall_thickness + lid_buffer_z;

module Lid(innerBox, outerBox, cutting)
{
    /*
    Lid profile

       boxX - 2* wall thickness + 2*(wall thickness/tan(trap angle))
    p0 ---------------- p1
       \) trap angle  /
        \            /
    P3   ------------   p2
         boxX - 2* wall thickness

  */

  // define how snug the fit should be on the lid
  // when this sub is used to "cut" enlarge the dimensions to make the opening larger
  buffer_z = cutting == true ? hole_buffer_z + fudge : lid_buffer_z;
  buffer_x = cutting == true ? hole_buffer_x : lid_buffer_x;
  buffer_y = cutting == true ? hole_buffer_y : lid_buffer_y;

  // define the lid width (X)
  lidX = outerBox[0] - wall_sub + buffer_x;

  // define the length of the lid (Y)
  lidY = outerBox[1] - wall_thickness + buffer_y;

  // define the thickness of the lid
  lidZ = wall_thickness + buffer_z;

  // define slot dimensions
  slotX = lidX*.9;
  slotY = 5;

  // define the angle in the trapezoid; this needs to be less than 45 for most printers
  trapAngle = 70;
  lidAdd = wall_thickness/tan(trapAngle);

  // define points for the trapezoidal lid
  p0 = [0, 0];
  p1 = [lidX, 0];
  p2 = [lidX + lidAdd, lidZ];
  p3 = [0 + -lidAdd , lidZ];

    //center the lid
    translate([-lidX/2, -lidZ/2, 0])
        // rotate the lid -90 degrees
        rotate([-90])

                difference()
                {
                    // draw a polygon using the points above and then extrude
                    // linear extrude only works in the Z axis so everything has to be rotated after
                    linear_extrude(height = lidY, center = true)
                        polygon([p0, p1, p2, p3], paths = [[0, 1, 2, 3]]);

                    if (cutting == false)
                    {
                        // add a fingernail slot for making opening the lid easier
                        // the variable names are a bit wonky because the lid is drawn rotated -90 degrees
                        translate([lidX/2, -(lidZ), lidY/2-slotY*2])
                          roundedBox([slotX, lidZ - slot_adjust, slotY], radius = slotY/2, $fn=36);

                        // make a hole for the catch
                        if(print_catch == "yes")
                        {
                           echo("Printing Catch");
                           translate([lidX/2, lidZ/2, -lidY/2 + wall_thickness*catch_wall_ratio])
                            cube([catch_hole_ratio*lidX, wall_thickness*2, catch_hole_diameter], center=true);
                        }
                    }
                }

}

module DrawDivider(baseLength)
{
  /*
    divider profile, we'll extrude this to divider_thickness, then rotate it into place
    if max_height and min_height are the same, we'll leave out points 0 and 1

        p0 -------- p1
          /        \  divider_max_height - divider_min_height
         /          \
    P5   ------------   p2
        |            |
        |            | divider_min_height
        |            |
     p4 -------------- p3

  */

    drawTop = (divider_max_height > divider_min_height) ? true : false;

    topLength = baseLength*divider_percent_at_max_height;

    p0 = [-topLength/2, divider_max_height];
    p1 = [topLength/2, divider_max_height];

    p2 = [baseLength/2, divider_min_height];
    p3 = [baseLength/2, 0];
    p4 = [-baseLength/2, 0];
    p5 = [-baseLength/2, divider_min_height];

    points = drawTop ? [p0, p1, p2, p3, p4, p5] : [p2, p3, p4, p5];
    paths = drawTop ? [0, 1, 2, 3, 4, 5] : [0, 1, 2, 3];

    rotate([90])
        linear_extrude(height = divider_thickness, center = true)
            polygon(points, paths = [paths]);
}

module MakeXDividers(innerBox, outerBox, x_compartment_sizes)
{
    vectorSize = len(x_compartment_sizes);
    echo("x_compartment_sizes=", x_compartment_sizes);
    // make the list of divider positions
    for(n=[1:vectorSize])
    {
        if(n != vectorSize)
        {
            // need sum size of compartments up to this one
            sum = SumList(x_compartment_sizes, 0, n);
            dividerPos = -innerBox[0]/2 + sum + divider_thickness*(n-1) + divider_thickness/2;
            echo("x dividerPos=", dividerPos);
            translate([dividerPos, 0, -divider_max_height/2 - fudge])
                rotate([0, 0, 90])
                    DrawDivider(innerBox[1]);
        }
    }
}

module MakeYDividers(innerBox, outerBox, y_compartment_sizes)
{
    vectorSize = len(y_compartment_sizes);
    echo("y_compartment_sizes=", y_compartment_sizes);
    // make the list of divider positions
    for(n=[1:vectorSize])
    {
        if(n != vectorSize)
        {
            // need sum size of compartments up to this one
            sum = SumList(y_compartment_sizes, 0, n);
            dividerPos = -innerBox[1]/2 + sum + divider_thickness*(n-1) + divider_thickness/2;
            echo("y dividerPos=", dividerPos);
                translate([0, dividerPos, -divider_max_height/2 - fudge])
                    DrawDivider(innerBox[0]);
        }
    }
}

module BasicBox(innerBox, outerBox)
{
    // Set the curve refinement
    $fn = 36;

    // Create the box then subtract the inner volume and make a cut for the sliding lid
    difference()
    {
        // call the MCAD rounded box command imported from MCAD/boxes.scad
        // size = dimensions; radius = corner curve radius; sidesonly = round only some sides

        // First draw the outer box
        roundedBox(size = outerBox, radius = corner_rad, sidesonly = 1);
        // Then cut out the inner box
        roundedBox(size = innerBox, radius = corner_rad, sidesonly = 1);
        // Then cut out the lid
        translate([0, 0, (outerBox[2]/2)+fudge])
          Lid(innerBox, outerBox, cutting = true);
    }
}

module MakeCatch(innerBox, outerBox)
{
    // Set the curve refinement
    $fn = 36;

    translate([0, -outerBox[1]/2 + wall_thickness*catch_wall_ratio, innerBox[2]/2])
        union()
        {
            translate([catch_bump_ratio*innerBox[0]/2, 0, 0])
                sphere(catch_diameter/2);
            translate([-catch_bump_ratio*innerBox[0]/2, 0, 0])
                    sphere(catch_diameter/2);
            rotate([0, 90, 0])
                cylinder(catch_bump_ratio*innerBox[0], catch_diameter/2, catch_diameter/2, center=true);
        }
}

module DividedBox(innerBox, outerBox)
{
    innerBox = ComputeInnerBoxDimension(x_compartment_sizes, y_compartment_sizes);
    outerBox = ComputeOuterBoxDimension(innerBox);

    BasicBox(innerBox, outerBox);
    MakeXDividers(innerBox, outerBox, x_compartment_sizes);
    MakeYDividers(innerBox, outerBox, y_compartment_sizes);
    if(print_catch == "yes")
    {
        MakeCatch(innerBox, outerBox);
    }
}

module PrintPart()
{
    echo("x_compartment length=", len(x_compartment_sizes));
    echo("sum x compartments=", SumList(x_compartment_sizes, 0, len(x_compartment_sizes)));

    echo("y_compartment length=", len(y_compartment_sizes));
    echo("sum y compartments=", SumList(y_compartment_sizes, 0, len(y_compartment_sizes)));

    innerBox = ComputeInnerBoxDimension(x_compartment_sizes, y_compartment_sizes);
    outerBox = ComputeOuterBoxDimension(innerBox);

    echo("InnerBox=", innerBox);
    echo("OuterBox=", outerBox);

    if(part == "first")
    {
        translate([0, 0, outerBox[2]/2])
            DividedBox(innerBox, outerBox);
    }
    else if(part == "second")
    {
        translate([0, 0, lid_solid_height()])
            Lid(innerBox, outerBox, cutting=false);
    }
    else
    {
        translate([-outerBox[0]/2 - wall_thickness, 0, outerBox[2]/2])
            DividedBox(innerBox, outerBox);

        translate([outerBox[0]/2 + wall_thickness, 0, lid_solid_height()])
            Lid(innerBox, outerBox, cutting=false);
    }
}

PrintPart();
```


[User]
Hey, I'm trying to design a parametric rocket in OpenSCAD. I've got a basic structure in mind, but I need help making it flexible and easy to customize.

Essentially, the rocket should have a cylindrical body with a hollow core, a nose cone, and fins. The core can be solid, or hollow based on a true/false parameter. I'd like all the dimensions to be adjustable so I can tweak the rocket to different sizes.

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

**Core Body:**

*   A main cylindrical body that is hollow.
*   Parameters:
    *   `body_radius`: The radius of the outer cylinder.
    *   `body_height`: The height of the main body.
    *  `wall_thickness`: How thick the walls of the cylinder are.
  * `solid_core`: boolean to determine if the core is solid or hollow

**Nose Cone:**

*   A spherical top for the rocket.
*   Parameters:
    *   `nose_radius`: The radius of the sphere
    *   `nose_height_offset`: distance from top of body to center of nose sphere.

**Fins:**

*   Four fins equally spaced around the base of the rocket.
*   Parameters:
    *   `fin_base_length`: The length of the fin along the rocket body.
    *   `fin_height`: The height of the fin.
    *   `fin_width`: The thickness of the fin.
     *   `fin_offset`: distance from bottom of body to start of fin base

Ideally, I want to be able to control all of these parameters, so I can adjust the size and proportions of the rocket easily. Also, I'd really like to be able to print it either solid or hollow with a boolean value. Could you help me generate an OpenSCAD file that implements all this? I think you could keep it all in one file.

[Assistant]
Rocket.scad:
```

difference()
{
	for(i=[0:0])
	rotate([0,120*i,0])
	cylinder(r=10,h=70);

	for(i=[0:0])
	rotate([0,120*i,0])
	translate([0,0,-1])
	cylinder(r=8,h=72);
}

translate([0,0,60]) scale([0.8,0.8,1]) cylinder(10, 10, 10);

translate([0,0,70]) scale([1,1,1]) sphere(10);

b = 60;
h = 10;
w = 4;

//the fins
rotate(a=[90,-90,0])
linear_extrude(height = w, center = true, convexity = 10, twist = 0)
translate([0,9,0]) scale([2,0.2,1])polygon(points=[[0,0],[h,0],[0,b]], paths=[[0,1,2]]);

rotate(a=[90,-90,180])
linear_extrude(height = w, center = true, convexity = 10, twist = 0)
translate([0,9,0]) scale([2,0.2,1])polygon(points=[[0,0],[h,0],[0,b]], paths=[[0,1,2]]);

rotate(a=[180,-90,0])
linear_extrude(height = w, center = true, convexity = 10, twist = 0)
translate([0,9,0]) scale([2,0.2,1])polygon(points=[[0,0],[h,0],[0,b]], paths=[[0,1,2]]);

rotate(a=[180,-90,180])
linear_extrude(height = w, center = true, convexity = 10, twist = 0)
translate([0,9,0]) scale([2,0.2,1])polygon(points=[[0,0],[h,0],[0,b]], paths=[[0,1,2]]);

```


[User]
I'd like a highly customizable gear generator, please. I've got some specific ideas for what I want it to be able to do.

First, I need to be able to choose from four different gear types: a regular spur gear, a helix gear, a double helix gear, and a herringbone gear.

The basic dimensions should be customizable: the radius from the center to the base of the teeth, the overall thickness of the gear, and the thickness of the inner portion of the gear (which can be different from the outer thickness). Also, I'll need to define the radial thickness of the rings that make up the inner part of the gear - that is, the difference in radius between the outer and inner rings.

For the center, I'd like an option for no hole, a circular hole, or a hexagonal hole, with the diameter of that center hole being configurable.

I also want to have options for lightening holes to reduce material. There should be options for no lightening holes, circular holes, or "wheelarm style" holes, as I'm calling them. If I use lightening holes, I need to specify how many holes, the distance between each hole, and the distance from the outer edge of the ring to the holes. For the wheelarm style holes I need to configure how rounded the inner corners are.

Next, for the teeth themselves: I need to specify the number of teeth, the height of the teeth, the width of the teeth at their base, and whether the tooth ends are flat or rounded. The width of the end of the teeth needs to be configurable as well, and also I need to be able to choose a "tooth finish" on the teeth ends, which can be none, rounded, or beveled. The tooth finish width should be the same as the tooth end width. The herringbone angle for helical and herringbone gears should be configurable. Finally, for herringbone gears I need a space width between the two sets of teeth.

I think that covers all the needed features. Also, you can use `$fa` and `$fs` for the overall resolution of the model. I think that's it, thanks!

[Assistant]
gear.scad:
```
/******************************************************************************
 *
 *  GLOBALS
 *
 ******************************************************************************/

/* [General] */
gearType = 3; //[1: Regular gear, 2: Helix gear, 3: Double helix gear, 4: Herringbone gear]
// Radius from center to teeth base (!)
wheelRadius = 40;
outerThickness = 20;
innerThickness = 6;
// Inner/outer rings radius difference
outerRingThickness = 4;

/* [Inner Part] */
centerHole = 2; // [0: None, 1: Circular, 2: Hex]
// Not needed if no center hole
centerHoleDiameter = 10;

/* [Lightening Holes] */
lighteningHoles = 1; // [0: None, 1: Circular, 2: Wheelarm style]
// Not needed if no lightening holes
lighteningHolesCount = 6;
// Not needed if no lightening holes
lighteningHolesDistance = 4;
// Not needed if no lightening holes
lighteningHolesOuterDistance = 2;
// Needed only for wheelarm style holes
wheelarmHolerRoundness = 2;

/* [Teeth configuration] */
// Not needed for regular gear
herringboneAngle = 15;
// Needed only for herringbone gear
herringboneSpaceWidth = 2;
teethCount = 44;
toothHeight = 4;
toothBaseWidth = 4;
toothEnd = 2; // [1: Flat, 2: Rounded]
// Also used as the primary dimension for tooth finish!
toothEndWidth = 2;
toothFinish = 2; // [0: None, 1: Rounded, 2: Bevel]

/* [Hidden] */
$fa = 1;
$fs = 0.5;

/******************************************************************************
 *
 *  EXECUTION
 *
 ******************************************************************************/

ringsPart();
teethPart();

/******************************************************************************
 *
 *  DIRECT MODULES
 *
 ******************************************************************************/

module teethPart()
{
    difference()
    {
        _teeth();
        _teethFinish();
    }
}

module ringsPart()
{
    difference()
    {
        _gearRings();
        union()
        {
            _centerHole();
            _lightening();
        }
    }
}

/******************************************************************************
 *
 *  HELPER AND COMPONENT MODULES
 *
 ******************************************************************************/

module _teethFinish()
{
    if(toothFinish > 0)
    {
        translate([0, 0, -0.001])
            rotate_extrude(convexity = 10)
                translate([wheelRadius + toothHeight - toothEndWidth, 0, 0])
                    _teethFinishShape();
        translate([0, 0, outerThickness + 0.001])
            rotate_extrude(convexity = 10)
                translate([wheelRadius + toothHeight - toothEndWidth, 0, 0])
                    mirror([0, 1, 0])
                        _teethFinishShape();

    }
}

module _teethFinishShape()
{
    if(toothFinish == 2)
    {
        difference()
        {
            square(toothEndWidth + 0.001);
            rotate([0, 0, 45])
                square(toothEndWidth * 2);
        }
    }
    else
    {
        difference()
        {
            square(toothEndWidth + 0.001);
            translate([0, toothEndWidth, 0])
                circle(toothEndWidth + 0.001);
        }
    }
}

module _teeth()
{
    if(gearType == 2)
    {
        _helixGear();
    }
    else if(gearType == 3)
    {
        _doubleHelixGear();
    }
    else if(gearType == 4)
    {
        _herringboneGear();
    }
    else
    {
        _regularGear();
    }
}

module _regularGear()
{
    _halfGear();
    translate([0, 0, outerThickness / 2])
        _halfGear();
}

module _helixGear()
{
    _halfGear(herringboneAngle);
    translate([0, 0, outerThickness / 2])
        rotate([0, 0, -herringboneAngle])
            _halfGear(herringboneAngle);
}

module _doubleHelixGear()
{
    _halfGear(-herringboneAngle);
    translate([0, 0, outerThickness / 2])
        rotate([0, 0, herringboneAngle])
            _halfGear(herringboneAngle);
}

module _herringboneGear()
{
    difference()
    {
        _doubleHelixGear();
        _herringboneSpace();
    }
}

module _minkowskiInside(mask = [9999, 9999]) // "Intel Inside"! No...
{
    minkowski()
    {
        difference()
        {
            square(mask, center = true);
            minkowski()
            {
                difference()
                {
                    square(mask, center = true);
                    children(0);
                }
                children(1);
            }
        }
        children(1);
    }
}

module _pie2d(angle, radius)
{
    if(angle > 90)
    {
        for(i = [1: 90: angle - (angle % 90)])
        {
            rotate([0, 0, i])
                _pie2d(90, radius);
        }

        rotate([0, 0, angle - (angle % 90)])
            _pie2d(angle % 90, radius);
    }
    else
    {
        rotate([0, 0, 90])
            intersection()
            {
                circle(radius);
                scale([2, 2, 1])
                    hull()
                    {
                        rotate([90, 0, 0])
                            square([radius, 44]); // no idea, why, but less than 10 kills OpenSCAD :)
                        rotate([90, 0, angle])
                            square([radius, 44]);
                    }
            }
    }
}

module _herringboneSpace()
{
        translate([0, 0, outerThickness / 2 - herringboneSpaceWidth / 2])
            difference()
                {
                    cylinder(r = wheelRadius + toothHeight + 4, h = herringboneSpaceWidth);
                    translate([0, 0, -1])
                        cylinder(r = wheelRadius - outerRingThickness / 2, h = herringboneSpaceWidth + 2);
                }
}

module _halfGear(twist = 0)
{
    linear_extrude(height = outerThickness / 2, twist = twist, convexity = 8)
        for(i = [0: 360 / teethCount: 360])
            rotate([0, 0, i])
                translate([wheelRadius, 0, 0])
                    _tooth();
}

module _tooth()
{
    union()
    {
        if(toothEnd == 1)
        {
            polygon([
                [0, toothBaseWidth / 2], [0, -toothBaseWidth / 2], [toothHeight, -toothEndWidth / 2], [toothHeight, toothEndWidth / 2]
            ]);
        }
        else
        {
            flatPartHeight = toothHeight - toothEndWidth / 2;
            union()
            {
                polygon([
                    [0, toothBaseWidth / 2], [0, -toothBaseWidth / 2], [flatPartHeight, -toothEndWidth / 2], [flatPartHeight, toothEndWidth / 2]
                ]);
                translate([flatPartHeight, 0, 0])
                    circle(toothEndWidth / 2);
            }
        }
        translate([-outerRingThickness/8, 0, 0])
            square([outerRingThickness/4, toothBaseWidth], center = true); // getting rid of freespaces the ugly-way
    }
}

module _lightening()
{
    if(lighteningHoles > 0)
    {
        angle = 360 / (lighteningHolesCount);
        for(i = [1 : lighteningHolesCount])
        {
            rotate([0, 0, angle * i])
            {
                if(lighteningHoles == 1)
                {
                    arm = wheelRadius - outerRingThickness;
                    // OMFG! It's been ages since I used trigonometry!
                    holeRadius = arm * sin(angle / 2) / (1 + sin(angle / 2)) - lighteningHolesDistance / 4 - lighteningHolesOuterDistance / 2;
                    translate([wheelRadius - outerRingThickness - holeRadius - lighteningHolesOuterDistance, 0, 0])
                        cylinder(r = holeRadius, h = innerThickness + outerThickness, $fn = (lighteningHoles == 2 ? 3 : $fn));
                }
                else
                {
                    innerRadius = wheelRadius - outerRingThickness - lighteningHolesOuterDistance;
                    distanceAngle = lighteningHolesDistance * 180 / (PI * innerRadius / 2);
                    linear_extrude(height = 40, convexity = 8)
                        _minkowskiInside()
                        {
                            difference()
                            {
                                difference()
                                {
                                    _pie2d(angle, innerRadius);
                                    circle(centerHoleDiameter / 2 + lighteningHolesDistance);
                                }
                                _pie2d(distanceAngle, innerRadius);
                            }
                            circle(wheelarmHolerRoundness);
                        }
                }
            }
        }
    }
}

module _centerHole()
{
    if(centerHole > 0)
    {
        translate([0, 0, -1])
            cylinder(r = centerHoleDiameter / 2, h = innerThickness + outerThickness, $fn = (centerHole == 2 ? 6 : $fn));
    }
}

module _gearRings()
{
    if(outerThickness > innerThickness)
    {
        difference()
        {
            _outerGear();
            _innerGearNegative();
        }
    }
    else
    {
        _outerGear();
        if(outerThickness < innerThickness)
        {
            _innerGearPositive();
        }
    }
}

module _outerGear()
{
    cylinder(r = wheelRadius, h = outerThickness);
}

module _innerGearNegative()
{
        union()
        {
            translate([0, 0, (outerThickness - innerThickness) / 2 + innerThickness])
                cylinder(r = wheelRadius - outerRingThickness, h = outerThickness);
            translate([0, 0, -(outerThickness - innerThickness) / 2 - innerThickness])
                cylinder(r = wheelRadius - outerRingThickness, h = outerThickness);
        }
}

module _innerGearPositive()
{
    translate([0, 0, (outerThickness - innerThickness) / 2])
        cylinder(r = wheelRadius - outerRingThickness, h = innerThickness);
}
```


[User]
Hey, I'm looking to design a parametric bag clip in OpenSCAD. I've seen a few designs out there, and I'd like one that's customizable. Essentially, I want two arms that interlock to create a secure seal.

Here's what I'm envisioning:

*   **Two Arms:** The clip will consist of two main arms. One arm (let's call it the "lock arm") will have a latching mechanism, and the other arm ("free arm") will have a corresponding feature to engage with the lock arm.
*   **Arm Length:** I need to be able to control the effective internal length of the clip (the length inside the grip when closed). I think `armLength` should be a parameter for this. Let's start at 55 mm.
*   **Arm Thickness:** The thickness of the main part of the arms needs to be adjustable with `armThickness`. I'm thinking 5mm as a starting point.
*   **Height:** The overall height of the clip should be controlled by a `height` parameter (10mm to begin with).
*   **Latch Arm Thickness:** The thickness of the latching part of the lock arm should be adjustable as well, with `latchArmThickness`. Let's start at 2mm but allow adjustments from 1 to 3mm in 0.1mm increments.
*   **Gaps:** There needs to be some tolerance for movement between the arms. I think there should be two gaps: one for the latching mechanism (`latchGap`), and one where the arms rotate (`pivotGap`). Both should start at 0.4mm and allow adjustments from 0.2 to 0.8mm in 0.05mm increments.
*   **Initial Angle:** Before the arms are brought together to seal, I want them to have an initial angle. It should be controlled by a parameter called `initialArmsAngle` which can be adjusted from 15 to 90 degrees in 15 degree increments. Let's start with 30 degrees.
*   **Interlocking:** The lock arm should have a hook-like feature that catches on a corresponding lip on the free arm to provide a secure seal. I think the free arm needs a little space removed for the lip to easily engage.
*   **Movement:** It should be designed to actually move and allow the arms to hinge together.

I was thinking about using a combination of `linear_extrude`, `difference`, `union`, `translate`, `rotate`, `circle`, `square`, and `polygon` for basic shapes and transformations. The shapes themselves are mostly flat so linear extrusion should be sufficient for the 3D aspect of the clip. It is possible there are better ways to implement the shapes I want. I would like that implemented in the main scad file.

I'm not looking to use any external libraries for this. Could you help me with the OpenSCAD code?

[Assistant]
bag_clip.scad:
```
/******************************************************************************
 *
 *  GLOBALS
 *
 ******************************************************************************/

/* [General] */

// Effective (internal) length of the clip
armLength = 55;
// Should not be less than two times latch arm hickness plus movement gap :)
armThickness = 5;
height = 10;
latchArmThickness = 2; // [1:0.1:3]
// Simply just tollerance, must be positive for movement
latchGap = 0.4; // [0.2:0.05:0.8]
pivotGap = 0.4; // [0.2:0.05:0.8]
// Angle (in degrees) for printing area adjustment
initialArmsAngle = 30; // [15:15:90]
/* [Hidden] */
$fa = 1;
$fs = 0.5;

/******************************************************************************
 *
 *  EXECUTION
 *
 ******************************************************************************/

lockArm();
freeArm();

/***************************************************************************
 *
 *  DIRECT MODULES
 *
 ******************************************************************************/

module lockArm()
{
    difference()
    {
        linear_extrude(height = height, convexity = 8)
            _lockArmPlane();
        translate([-armThickness - 1, -1, height / 4 - pivotGap / 2])
            cube([2 * armThickness + 1, armThickness + 1, height / 2 + pivotGap]);

        translate([armThickness + latchGap, armThickness + latchGap / 2, height / 2 - sqrt(2) / 2])
            rotate([45, 0, 0])
                cube([armLength, 1, 1]);
    }
}

module freeArm()
{
    translate([0, armThickness, 0])
        rotate([0, 0, -initialArmsAngle])
            translate([0, -armThickness, 0])
            {
                difference()
                {
                    union()
                    {
                        linear_extrude(height = height, convexity = 8)
                            _freeArmPlane();
                        translate([0, 0, height / 4 + pivotGap / 2])
                            cube([armThickness + pivotGap, armThickness - latchGap, height / 2 - pivotGap]);
                        translate([armThickness + pivotGap, armThickness - latchGap / 2, height / 2 - sqrt(2) / 2])
                            rotate([45, 0, 0])
                                cube([armLength, 1, 1]);
                    }
                    translate([0, 0, -1])
                        linear_extrude(height = height + 2, convexity = 8)
                            polygon([[-1, -1], [armThickness + pivotGap, 0], [0, armThickness / 2]]);

                    translate([0, 0, -1])
                        linear_extrude(height = height + 2, convexity = 8)
                            polygon([
                                [armLength + armThickness + latchGap, armThickness / 2],
                                [armLength + armThickness + latchGap + 1, armThickness / 2],
                                [armLength + armThickness + latchGap, armThickness + sqrt(2)],
                                [armLength + armThickness + latchGap - latchArmThickness, armThickness + sqrt(2)]
                                ], center = true);
                }
            }
}

/******************************************************************************
 *
 *  HELPER AND COMPONENT MODULES
 *
 ******************************************************************************/

module _freeArmPlane()
{
    translate([0, armThickness, 0])
        circle(armThickness / 2 - pivotGap / 2);
    translate([armThickness + pivotGap, 0, 0])
        square([armLength, armThickness - pivotGap / 2]);
}

 module _lockArmPlane()
 {
    union()
    {
        difference()
        {
            union()
            {
                translate([0, armThickness, 0])
                    circle(armThickness);
                translate([0, armThickness + latchGap / 2, 0])
                    square([armLength + armThickness + latchGap, armThickness - latchGap / 2]);
                translate([armLength + armThickness - 2 * latchArmThickness + latchGap, 2 * armThickness - latchArmThickness, 0])
                    square([3 * latchArmThickness + latchGap, latchArmThickness]);
                translate([armLength + armThickness + 2 * latchGap, - latchGap, 0])
                    square([latchArmThickness, 2 * armThickness + latchGap]);
                polygon([
                    [armLength + armThickness + 2 * latchGap + latchArmThickness, -latchGap],
                    [armLength + armThickness + latchGap - latchArmThickness * 0.75, -latchGap],
                    [armLength + armThickness + latchGap - latchArmThickness * 0.75, -latchGap - latchArmThickness / 2],
                    [armLength + armThickness + 2 * latchGap, -latchGap - latchArmThickness * 1.5],
                    [armLength + armThickness + 2 * latchGap + latchArmThickness, -latchGap - latchArmThickness * 1.5]
                    ]);
            }
            translate([0, armThickness, 0])
                circle(armThickness / 2 + pivotGap / 2);
            translate([armLength + armThickness - 2 * latchArmThickness, armThickness * 2 - latchArmThickness - latchGap, 0])
                square([2 * latchArmThickness + latchGap, latchGap]);
            translate([armLength + armThickness + 2 * latchGap + latchArmThickness, armThickness * 2 - latchArmThickness/2, 0])
                rotate([0, 0, 45])
                    square(latchArmThickness);

        }
    }
 }
```


[User]
I need a parametric OpenSCAD design for furniture foot extensions. These extensions should be rectangular, and will slide over the existing furniture feet to level them on uneven floors. The design should allow for adjustments in the extension height, the size of the furniture foot it fits, the wall thickness of the extension, and an optional central hole in the base.

Specifically, I need the following parameters:

*   `extension`: This will define the amount of vertical extension needed. It should be adjustable in millimeters.
*   `fsize_x`: The width of the furniture foot that the extension will fit over. Adjustable in millimeters.
*   `fsize_y`: The length of the furniture foot that the extension will fit over. Adjustable in millimeters.
*   `holedia`: The diameter of an optional central hole. If no hole is needed, it can be set to zero. Adjustable in millimeters.
*  `wall`: The thickness of the outer wall of the extension. Adjustable in millimeters.
*  `minwall`: The minimum total height of the outer wall (or fence), that will also extend around the furniture foot. This can be zero. Adjustable in millimeters.
*  `fence`: The minimum amount that the outer wall should overlap with the furniture foot it sits on. Adjustable in millimeters.
*  `tol`: A tolerance value to create a slight gap between the furniture foot and the extension, for easy sliding on and off. Adjustable in millimeters. This is only a tolerance used for fitting to the existing furniture foot and should be applied only as described in the original code.
* The design should also include a "d" value which is 0.1mm. This d value is used for minor offsets.

I'd like a clean design where the extension sits flush on the floor and has an outer wall that extends upwards around the existing foot, creating a secure fit. The walls should have a consistent thickness, and the tolerances should be applied to the inside of the extension to allow it to fit over the furniture foot. The inner hollow area should always extend to the bottom surface of the model. This should also be the case with any optional center hole. I would prefer the design not to have any unnecessary overlaps. It should be manufacturable using a 3D printer and thus be easily printed.

I am not currently using any libraries for other SCAD designs, so I don't need it to use any specific ones.

[Assistant]
footext.scad:
```
//
//  parametric furniture foot extension
//  for leveling furniture on uneven floors
//  but also uneven furniture on even floors
//

extension = 15.0; // amount of extension needed

fsize_x = 44.5; // size of furniture foot
fsize_y = 44.5; // size of furniture foot
holedia = 30.0; // central hole, if desired, can be zero
wall = 2.0; // outer wall (fence) thickness
minwall = 0.0; // minimum outer wall total height (can be zero)
fence = 10.0; // minimum outer wall overlap of original foot

tol = 0.5; // tolerance

d = 1*0.1;

difference () {
    union () { // add:
        translate([-fsize_x/2, -fsize_y/2, 0]) cube([fsize_x, fsize_y, extension]);
        hull () {
            translate([-fsize_x/2-tol-wall, -fsize_y/2-tol-wall, min(extension-2*wall,extension+fence-minwall)]) cube([fsize_x+2*tol+2*wall, fsize_y+2*tol+2*wall, max(2*wall+fence, minwall)]);
            translate([-fsize_x/2, -fsize_y/2, extension-2*wall-wall]) cube([fsize_x, fsize_y, wall]);
        }
    }
    union () { //sub:
        // hole for furniture foot:
        translate([-fsize_x/2-tol, -fsize_y/2-tol, extension]) cube([fsize_x+2*tol, fsize_y+2*tol, max(minwall,fence)+d]);
        // any excess "below the surface":
        translate([-fsize_x/2-tol-wall-d, -fsize_y/2-tol-wall-d, -(wall+max(minwall,fence)+d)]) cube([fsize_x+2*tol+2*wall+2*d, fsize_y+2*tol+2*wall+2*d, wall+max(minwall,fence)+d]);
        // central hole:
        translate([0, 0, -(wall+max(minwall,fence)+d)]) cylinder(d=holedia, h=d+wall+max(minwall,fence)+extension+max(minwall,fence)+d, $fn=120);
    }
}

```


[User]
I'm looking for an OpenSCAD design for a center finder, something that helps accurately mark the center of a circular or rectangular object. I have some specific parameters in mind, so it needs to be easily customizable.

Here's what I envision:

**Overall Structure:**

*   The center finder will have a main, flat plate-like body.
*   On each end of the main plate, there will be cylindrical "limiters" or guides, to align the center finder on an object. These limiters will protrude upwards from the main plate.
*   There should be a hole in the center of the plate, to be used for marking.

**Parameters:**

*   `length`: The overall length of the center finder.
*   `limiterDiameter`: The diameter of the cylindrical limiters.
*   `limiterHeight`: The height of the cylindrical limiters, measured above the main plate.
*   `holeDiameter`: The diameter of the center marking hole.
*   `plateWidth`: The width of the main plate body.
*   `plateThickness`: The thickness of the main plate.

**Specifics:**

*   The main plate needs to be able to handle both rectangular and circular cross-sections, or even something between these two. There should be a circular section at each end, and a connecting rectangular area in the middle, where the rectangular part’s width is equal to the diameter of the circles.
* The limiters should be centered on the plate.
* The center hole needs to be at the exact center of the plate.
* The main plate should have smooth transitions from the circular sections at its ends to the main rectangular part; it should have smooth arcs between the rectangle and circles at the ends.
*   I'd prefer to specify only the outer dimensions of the limiters, and not their relative placement, if possible.
*   I want a flat plate with the limiters attached to one side.
*   I need to have the hole go all the way through the plate.
*  The center hole should be easy to use for marking purposes, so making it slightly counterbored, or with a chamfer, would be helpful. The counterbore or chamfer should be small.

**Additional Considerations:**

*   The design should be fully parametric, with all the dimensions controlled by variables.
*   I would like to use the default $fa and $fs values unless I specify otherwise.

Could you create an OpenSCAD file or files for this? I am looking for a new project from scratch, please don't assume I have other libraries or files.

[Assistant]
center_finder.scad:
```
/******************************************************************************
 *
 *  GLOBALS
 *
 ******************************************************************************/

/* [General] */

// Overall length
length = 100;
limiterDiameter = 6;
// Measured without plate thickness
limiterHeight = 16;
holeDiameter = 3;
plateWidth = 20;
plateThickness = 3;

/* [Hidden] */
$fa = 1;
$fs = 0.5;

/******************************************************************************
 *
 *  EXECUTION
 *
 ******************************************************************************/

plate();
limiters();

/***************************************************************************
 *
 *  DIRECT MODULES
 *
 ******************************************************************************/

module plate()
{
    difference()
    {
        linear_extrude(height = plateThickness, convexity = 8)
            _platePlane();
        translate([(length - plateWidth) / 2, plateWidth / 2, -0.0002])
            cylinder(plateThickness - 1, holeDiameter / 2 + plateThickness / 2, holeDiameter / 2 );
        translate([(length - plateWidth) / 2, plateWidth / 2, 0])
            cylinder(plateThickness + 1, holeDiameter / 2, holeDiameter / 2);
    }

}

module limiters()
{
    translate([-(plateWidth / 2 - limiterDiameter / 2), plateWidth / 2, plateThickness])
        cylinder(r = limiterDiameter / 2, h = limiterHeight);
    translate([length - plateWidth/2 - limiterDiameter / 2, plateWidth / 2, plateThickness])
        cylinder(r = limiterDiameter / 2, h = limiterHeight);
}

/******************************************************************************
 *
 *  HELPER AND COMPONENT MODULES
 *
 ******************************************************************************/

module _platePlane()
{
    difference()
    {
        union()
        {
            translate([0, plateWidth / 2, 0])
                circle(plateWidth / 2);
            square([length - plateWidth, plateWidth]);
            translate([length - plateWidth, plateWidth / 2, 0])
                circle(plateWidth / 2);
        }
        hull()
        {
            translate([-plateWidth / 2 + limiterDiameter + plateWidth / 3, plateWidth / 2, 0])
                circle(plateWidth / 3);
            translate([length / 2 - plateWidth / 2 - plateWidth / 3 - holeDiameter - plateThickness, plateWidth / 2, 0])
                circle(plateWidth / 3);
        }
        hull()
        {
            translate([length / 2 - plateWidth / 2 + plateWidth / 3 + holeDiameter + plateThickness, plateWidth / 2, 0])
                circle(plateWidth / 3);
            translate([length - limiterDiameter - plateWidth / 3 - plateWidth / 2, plateWidth / 2, 0])
                circle(plateWidth / 3);
        }
    }
}
```


[User]
Hi! I'm looking for some help designing some customizable storage drawers for small parts, like electronic components. I have some specific needs in mind, and I'd like the design to be parametric so I can tweak it for different magazine types.

Essentially, I need a drawer that fits inside a standard small parts magazine, and it should have internal dividers to create a grid of compartments. I'd also like the ability to add layers above the drawer using inlay shelves.

Here are the main parameters I'd like to control:

*   **Drawer Dimensions:**
    *   `width`: The width of the drawer.
    *   `height`: The height of the drawer.
    *   `length`: The depth of the drawer (excluding the grip).
*   **Grip:**
    *   `grip_depth`: How much the grip protrudes from the front.
    *   `grip_height`: The height of the grip's overhang.
    *   `grip_frontheight`: The height of the vertical front part of the grip.
    *   `grip_downshift`: How much the grip is offset down from the top edge.
    *   `griphole_diameter`: The diameter of the holes in the grip.
*   **Compartment Layout:**
    *   `rows`: Number of rows of compartments.
    *   `columns`: Number of columns of compartments.
    *   `layers`: Number of inlay shelves (including the main drawer itself).
    *   `compartment_wall_topdistance`: the distance between the top rim of the drawer and the top rim of an inlay compartment wall.
*   **Wall Thickness and Spacing:**
    *   `wall_thickness`: The thickness of all the walls.
    *   `sfm` (space for moving parts): A small tolerance for fitting things together.
    *   `backholder_width`: width of a holder on the backwall
    *   `backholder_height`: height of a holder on the backwall
*   **Printing:**
    *   `print_distance`: distance between objects for printing
    *   `print_layout`: boolean, arranges objects for printing
    *   `print_drawer`: boolean, print the drawer or not
    *   `print_inlays`: integer, how many inlays to print

I envision the design including a main drawer with a grip on the front and a back holder, and then inlay shelves that fit into the main drawer, creating multiple levels of compartments. The partition walls in the main drawer are fixed. The main drawer itself is hollow, and is a box with wall_thickness.  The inner drawers are boxes, with wall_thickness on all sides. I'd prefer to use fixed partition walls and the shelves should not move or slip when filled.

I'm hoping to get two main SCAD files. One that creates the basic parts, named something like `smallpartsdrawer.scad`. And another SCAD file for printing all the parts, named something like `print_smallpartsdrawer.scad`. I can then edit print_smallpartsdrawer.scad to configure what to print, and then create a single .stl file from it.

I'm not picky about specific libraries, but if you think one might be useful for the design, feel free to include it.

Let me know if you need any other clarification!

[Assistant]
smallpartsdrawer.scad:
```
/* [dimensions] */
// width of drawer
width = 54;
// height of drawer
height = 37;
// depth of drawer without grip
length = 139;
// depth of grip
grip_depth = 12;
// height of the overhanging part of the grip
grip_height = 12;
// height of the vertical front
grip_frontheight = 23;
// distance between upper rim and grip
grip_downshift = 1;
// diameter of the holes in the grip
griphole_diameter = 24;
// thickness of all walls
wall_thickness = 0.8;
// vert. dist. rim of drawer and rim of inlay
compartment_wall_topdistance = 1;
// width of holder on back-wall
backholder_width=44;
// height of holder on back-wall
backholder_height=4;
// space for moving parts
sfm = 0.75;

/* [organization] */
// number of rows (over length)
rows = 2;
// number of columns
columns = 3;
// number of shelves (including the drawer)
layers=3;

/* [printing] */
// distance between objects
print_distance = 5;
// layout for printing
print_layout=1;
// print the drawer
print_drawer=1; // [0:no, 1:yes]
// number of inlay-shelves to print
print_inlays=2;

/* [Hidden] */
debug_flag=false;
tol = 0.1;

/* Raaco 150-0 Drawer:
width = 54;
height = 37;
length = 139;
grip_depth = 12;
grip_height = 12;
grip_frontheight = 23;
grip_downshift = 1;
griphole_diameter = 24;
*/

/* Powerfix Kleinteile-Magazin:
width = 68;
height = 36;
length = 118;
grip_depth = 8;
grip_height = 8;
grip_frontheight = 26;
grip_downshift = 1;
griphole_diameter = 16;
*/

//compartment_wall_height = 17.5;
compartment_wall_height = (height-compartment_wall_topdistance)/layers;
a = atan2(grip_depth,grip_height);
// echo(a);

rotate(0,0,-90)
{
    if (print_drawer)
    {
        Drawer();
    }
    if (print_inlays)
    {
        for (layer=[1:print_inlays])
        {
            translate(
            print_drawer ?
                print_layout
                ?
                    [(width+print_distance)*layer,0,0]
                :
                    [(wall_thickness+sfm),wall_thickness+sfm,(compartment_wall_height+sfm)*layer]
            :
                [0,0,0]
            )
                InnerBox();
        }
    }
}

module GripSidewall(ext,h)
{
    linear_extrude(height=h)
    {
        polygon(
        [
            [0,-ext*wall_thickness],
            [0,grip_depth],
            [grip_height+grip_frontheight,grip_depth],
            [grip_frontheight-ext*wall_thickness*tan(90-a),-ext*wall_thickness]
        ]);
    }
}

module LabelHolder()
{
    difference()
    {
        GripSidewall(2,width);
        translate([-tol,0,-tol])
            cube([grip_frontheight+grip_height,grip_depth+2*wall_thickness+tol,width+2*tol]);
        translate([-tol,-wall_thickness,wall_thickness])
            cube([grip_frontheight-2*wall_thickness+2*tol,grip_depth+2*wall_thickness+tol,width-2*wall_thickness]);
        translate([-tol,-2*wall_thickness-tol,3*wall_thickness])
            cube([grip_frontheight-4*wall_thickness,wall_thickness+2*tol,width-6*wall_thickness]);
    }
}

module Grip()
{
    ngripholes = round((width-2*wall_thickness)/(griphole_diameter+wall_thickness)-0.5);
    griphole_distance=width/ngripholes;
    difference()
    {
        linear_extrude(height=width)
        {
            polygon(
            [
                [0,0],
                [0,wall_thickness/cos(a)],
                [grip_frontheight,wall_thickness/cos(a)],
                [grip_height+grip_frontheight-wall_thickness/sin(a),grip_depth],
                [grip_height+grip_frontheight,grip_depth],
                [grip_frontheight,0]

            ]);
        }
        for (i=[0:ngripholes-1])
        {
            //x = griphole_diameter/2+wall_thickness + i * griphole_distance;
            x = griphole_distance/2 + i * griphole_distance;
            translate([grip_height+grip_frontheight,grip_depth,x])
                rotate([90,0,0])
                    translate([0,0,-tol])
                    cylinder(r=griphole_diameter/2, h=grip_depth+2*wall_thickness+tol, $fn=8);
                // sphere(r=griphole_diameter/2);
        }
    }
    /*
    */
    translate([0,0,0])
        LabelHolder();

    for (x=[0,,width-wall_thickness])
        translate([0,0,x])
            GripSidewall(2,wall_thickness);
    for (i=[0:ngripholes-2])
    {
        x = griphole_distance + i * griphole_distance;
        translate([0,0,x-wall_thickness/2])
            GripSidewall(0,wall_thickness);
    }
}

module Drawer()
{
    Box(width,length,height,wall_thickness);
    translate([(width-backholder_width)/2,length-wall_thickness,height-tol])
        cube([backholder_width,wall_thickness,backholder_height]);
    translate([0,-grip_depth,height-grip_downshift])
        rotate([0,90,0])
            Grip();
}

module InnerBox()
{
    Box(width-2*(sfm+wall_thickness),
        length-2*(sfm+wall_thickness),
        compartment_wall_height-sfm,
        wall_thickness);
}

module Box(width,length,height,wall_thickness)
{
    difference()
    {
        cube([width,length,height]);
        translate([wall_thickness,wall_thickness,wall_thickness])
            cube([width-(2*wall_thickness),length-(2*wall_thickness),height-wall_thickness+tol]);
    }
    compartment_depth = ((length-wall_thickness)/rows);
    compartment_width = ((width-wall_thickness)/columns);
    inner_compartment_depth = compartment_depth - wall_thickness;
    inner_compartment_width = compartment_width - wall_thickness;
    echo(str("inner compartment width: ", inner_compartment_width,
            "; inner compartment length: ", inner_compartment_depth,
            "; inner compartment height: ", compartment_wall_height - wall_thickness
    ));
    if (debug_flag)
    {
        for (i=[0:rows-1])
        {
            for (j=[0:columns-1])
                translate([j*compartment_width+wall_thickness,i*compartment_depth+wall_thickness,compartment_wall_height])
                    #cube([inner_compartment_width,inner_compartment_depth,1]);
        }
    }

    if (rows > 1)
        for (i=[1:rows-1])
        {
            y = i * compartment_depth;
            translate([wall_thickness/2,y,wall_thickness/2])
                cube([width-wall_thickness,wall_thickness,compartment_wall_height-wall_thickness*1.5]);
        }
    if (columns > 1)
        for (i=[1:columns-1])
        {
            x = i * compartment_width;
            translate([x,wall_thickness/2,wall_thickness/2])
                cube([wall_thickness,length-wall_thickness,compartment_wall_height-wall_thickness*1.5]);
        }
}

```