[User]
I need an OpenSCAD design for a cover that fits over a standard cabinet door hinge pocket, but with a key feature: it needs to accommodate doors that have been cut down, where the edge of the door overlaps the original hinge pocket. This cut-back should be adjustable and not just for one fixed size.

Essentially, I want to create a parametric cover that sits flush over a circular hinge recess. This cover needs a circular plug that fits snugly into the hinge hole. The outer edge of the cover will extend beyond the hinge diameter to look like a normal hinge cover, but I need the leading edge (closest to the door edge) to be cut back as if it were sliced by the edge of the door. The degree of that cutback needs to be configurable. So, the front edge of the cover will have a chord shape, rather than a complete circle.

Here are the dimensions I have for the standard hinge and the design parameters I need to control:

*   **Hinge Plug:**
    *   `hinge_diameter`: Diameter of the hinge cutout in the cabinet. (e.g., 36mm)
    *   `hinge_height`: Depth of the plug that goes into the cutout. (e.g., 8mm)
    *   `hinge_gap`:  Tolerance (gap) between the plug and the hinge hole to ensure a snug fit. (e.g., 0.5mm)
    *   `plug_wall`: Thickness of the plug wall. (e.g., 1.6mm)
    *   `nib_size`: Diameter of small nibs/bumps around the plug (for improved grip), optional. (e.g., 0.8mm)
	*	`nib_scale`: Taper ratio for nibs (bottom to top), for the shape, optional. (e.g., 0.8)
*   **Screw Plugs:**
    *   `screw_diameter`: Diameter of the screw holes in the hinge. (e.g., 8mm)
    *   `screw_Xoff`:  Horizontal (X) offset of screw holes from the hinge center. (e.g., 9.5mm)
    *  `screw_Yoff`: Vertical (Y) offset of screw holes from the hinge center. (e.g., 22.5mm)
    *   `screw_gap`: Tolerance (gap) for screw hole plugs. (e.g., 0.75mm)
*   **Cover:**
    *   `cover_overlap`: The amount the cover extends beyond the hinge/screw features. (e.g., 3.5mm)
    *   `cover_thick`: Thickness of the cover. (e.g., 1.6mm)
    *   `cutoff_length`:  The length of the cutback along the front edge, where 0 means a full circle and negative values cut back more than half way (though we need to be careful with screw positions). For example, 30mm will cut back some of the plug so it's not a complete circle, but -30 will do so more drastically.
*   **Other:**
    *   `nibs_wanted`: Boolean flag (0 or 1) to indicate whether nibs are needed.
	*	`studs_wanted`: Boolean flag for screw hole plugs (1 = yes, 0 = no)
	*	`pips_wanted`: Boolean flag for small location pips at screw holes (1 = yes, 0 = no), not to be confused with the plug nibs
    *   `fn`: Resolution parameter for circles and spheres. (e.g., 30)

I would want a modular design such that the basic plug, cover and studs can be enabled / disabled. The program should generate a single object, not a series of separate objects. Please make sure the cutback is handled correctly and doesn't go beyond the limits of the circular plug geometry.

[Assistant]
cutback_hinge_cover.scad:
```
// Cabinet hinge cover
// features cut-back front edge for reduced width doors
// basic dimensions fit standard door hinge
// By misterC @ thingiverse

// CUSTOMIZER VARIABLES
/* [Customize options] */
// Cut length (parallel to door edge) or zero if none required. Negative value for cuts past halfway (use with caution)
cutoff_length = 30;		// [-60:60]
// Do we want nibs around the plug (can help fixing grip)
nibs_wanted = 1;		// [0:False, 1:True)
// Options for extras - if both are true then pips get covered by studs
// Studs to fill screw holes
studs_wanted = 1;		// [0:False, 1:True]
// Small pips to locate on marker holes
pips_wanted = 0;		// [0:False, 1:True]
// Model resolution
fn = 30;				// [10:LoPoly, 30:Standard, 90:Final render]

// input parameters
/* [Hinge plug] */
// Diameter of hinge cutout
hinge_diameter = 36;	// [20:60]
// Depth of plug into cutout
hinge_height = 8;       // [5:25]
// Fitting tolerance for plug
hinge_gap = 0.5;		// [0:0.25:2]
// Thickness of plug wall
plug_wall = 1.6;		// [0.8:0.2:3]
// Diameter of nibs around plug
nib_size = 0.8;			// [0.5:0.1:2]
// Taper ratio of nibs (bottom to top)
nib_scale = 0.8;		// [0.5:0.1:1]
/* [Screw plugs] */
// Diameter of hinge screw holes
screw_diameter = 8;		// [4:12]
// X offset of screw holes from hinge centre
screw_Xoff = 9.5;       // [0:50]
// Y offset of screw holes from hinge centre (+Y & -Y used)
screw_Yoff = 22.5;      // [0:50]
// Fitting tolerance for plugs into screw holes
screw_gap = 0.75;		// [0:0.25:2]
/* [Cover sizes] */
// Cover horizontal distance beyond geometry
cover_overlap = 3.5;		// [1:10]
// Cover vertical thickness (fillet included)
cover_thick = 1.6;		// [1:0.1:3]

// PROGRAM VARIABLES AFTER THIS POINT
/* [Hidden] */

// Working constants
cut_fudge = 0.5;
cube_extra = 2;
$fn = fn;

// Calculated constants
plug_diameter = true_diameter(hinge_diameter) - 2*hinge_gap;
plug_inner = plug_diameter - 2*plug_wall;
plug_shoulder = 0.75*hinge_height;
plug_taper = 0.25*hinge_height;
screw_stud = hinge_height * 0.3;
stud_diameter = true_diameter(screw_diameter) - 2*screw_gap;

hinge_radius = true_diameter(hinge_diameter)/2;
screw_radius = true_diameter(screw_diameter)/2;

cutoff_Y = (abs(cutoff_length) >= plug_diameter) ? plug_diameter/2 : abs(cutoff_length/2);	// Trap cut length > diameter and +/-
cutoff_X = sqrt(pow(plug_diameter/2,2) - pow(cutoff_Y,2)) * sign(cutoff_length);			// Pythagoras with +/- adjustment
cutoff_A = (cutoff_X==0) ? 90 : (cutoff_length > 0) ? cutang() : 180 - cutang();			// Sort angle for 90 and +/- cutoff

echo (cutoff_Y, cutoff_X, cutoff_A, cutang());

half_width = screw_Yoff + screw_radius + cover_overlap;
plug_profile = [[0,0],[0,plug_shoulder+plug_taper],[plug_wall,plug_shoulder],[plug_wall,0],[0,0]];

// PROGRAM

// make plug
if (cutoff_length)		// We have to condider a cut
{
	intersection()
	{
		plug_profile(cutoff_A);
		// intersect with a cube to remove volume beyond cut line
		translate([-(plug_diameter+cube_extra)/2,-(plug_diameter+cube_extra)/2,-1])
			cube([1+plug_diameter/2+cutoff_X-plug_wall,plug_diameter+cube_extra,plug_shoulder+plug_taper+cube_extra]);
	}
	// seal cutoff with wall (use plug profile for neatness)
	intersection()
	{
		wall_offset(cutoff_X,0) polygon(plug_profile);
		solid_plug();
	}

	// cover area
	part_cover(cutoff_X);
}
else					// Just plug and cover.  Simples
{
	plug_profile();
	full_cover();
}

// add studs if wanted
if(studs_wanted) for (ycount=[-screw_Yoff,screw_Yoff])
{
    translate([-screw_Xoff,ycount,0]) cylinder(h=screw_stud,d=stud_diameter);
    translate([-screw_Xoff,ycount,screw_stud]) scale([1,1,0.5]) sphere(d=stud_diameter);
}
// add pips if wanted (doesn't matter if both, this lot gets hidden by the previous element)
if(pips_wanted) for (ycount=[-screw_Yoff,screw_Yoff]) translate([-screw_Xoff,ycount,0]) cylinder(h=1,d1=1,d2=0);

// END OF PROGRAM

// MODULES
module full_cover()		// uses a minkowski to make a radiussed plate then intersects it to cut off at z=0 for a smooth surface
{
	intersection()
	{
		hull()
		{
			do_minkowski(hinge_radius);
			for (xcount=[screw_radius,hinge_radius-screw_radius], ycount=[-screw_Yoff,screw_Yoff])
				translate([-xcount,ycount,0]) do_minkowski(screw_radius);
		}
		// now keep the volume below z=0
		translate([0,0,-cover_thick]) cube([3*hinge_diameter,3*hinge_diameter,2*cover_thick],center=true);
	}
}

module part_cover(X_offset)
{
	difference()	// cut off at the cutoff distance
	{
		full_cover();
		wall_offset(X_offset,-cover_thick-cut_fudge) square([hinge_diameter-X_offset,cover_thick+2*cut_fudge]);
	}
	intersection()	// with a filleted edge
	{
		full_cover();
		hull()
		{
			for(ycount=[-half_width,half_width]) translate([X_offset-cover_overlap,ycount,-cover_thick/2])
			{
				cylinder(r=cover_overlap,h=cover_thick);
				scale([cover_overlap,cover_overlap,cover_thick]) sphere(r=1);
			}
		}
	}
}

module plug_profile(start_ang=0,)	// spin the plug wall profile then add nibs.  Default angle gives 360 plug
{
	// plug profile with taper top, formed by spinning wall profile from start_ang through 180 to -start_ang
	rotate(start_ang) rotate_extrude(angle=2*(180-start_ang),$fn=2*fn) translate([plug_inner/2,0,0]) polygon(plug_profile);
	// add locating nibs
	if (nibs_wanted) nib([0:60:360]);		// create nibs at this point so they get included in Boolean geometry of plug
}

module solid_plug()		// the volume occupied by the plug (ignoring central hole) used for intersection operations
{
	cylinder(h=plug_shoulder,d=plug_diameter);
	translate([0,0,plug_shoulder]) cylinder(h=plug_taper,d1=plug_diameter,d2=plug_inner);
}

module nib(angle_range)	// tapering cylinders with rounded top to act as a fixing aid
// at the moment this is a "dumb" call, could be improved to cater for start_ang variable
{
	$fn=fn/2;
	for (angle=angle_range) rotate(angle)
	{
		translate([plug_diameter/2,0,0]) cylinder(h=plug_shoulder*nib_scale,r1=nib_size,r2=nib_size*nib_scale);
		translate([plug_diameter/2,0,plug_shoulder*nib_scale]) scale([nib_scale,nib_scale,pow(nib_scale,2)]) sphere(r=nib_size);
	}
}

module wall_offset(X_offset,Z_offset)	// position the flat plug wall and extrude the child element over the full cover width
{
	translate([X_offset-plug_wall,0,Z_offset]) rotate([90,0,0]) linear_extrude(height=2*(half_width+cut_fudge),center=true) children();
}

module do_minkowski(minkowski_distance) // makes a filleted cylinder
{
    minkowski()
    {
        cylinder(r=minkowski_distance-(cover_overlap/2),h=cover_thick/2,center=true);
        scale([cover_overlap,cover_overlap,cover_thick]) sphere(r=1);
    }
}

// FUNCTIONS

function true_diameter(input_size)
    = input_size * 1/cos(180/fn);

function cutang()
	= asin(abs(cutoff_length) / plug_diameter);		// both are twice the required value so scalar cancels

```


[User]
Hey, I'm looking to create a 3D printable ambigram, kind of like the one in that Thingiverse link, but I want it to be fully parametric so I can change the words and other aspects easily.

Specifically, I need an OpenSCAD design that can take two words as input, and those words should ideally have the same number of characters. It should extrude each letter of both words, and then intersect these extrusions in a way that you get the first word when looking at it from one angle, and the second word when viewed from a different angle.

I'd also like to have some control over the font size, spacing between letters, and the font used. And I'd want the option to add a base to the design, either as a cylinder or a cube, so it stands up nicely.

I'm thinking something like this:

*   **Inputs:**
    *   `text_1`: The first word (string).
    *   `text_2`: The second word (string).
    *   `font_size`: Size of the letters (number).
    *   `font_spacing`: Space between the letters (number).
    *   `font`: The font name, like "Arial" or "Source Code Pro" (string).
    *   `build_base`: A boolean that determines whether to add a base (yes/no, probably represented as a 1 or a 0).
    *   `base_type`: If a base is built, should it be a circle or a square (string)?

*   **Output:** A 3D ambigram model that is formed by the intersection of the extruded letters.
*   **Optional Base:** If `build_base` is active, a base should be added under the letters using a hull.

Could you generate the OpenSCAD file(s) for me? I'm not using any special libraries yet, but if you think there's a good one to use to improve the design, let me know and I can download that.

[Assistant]
ambigram.scad:
```
text_1 = "HELLO";

text_2 = "WORLD";

font_size = 20;

//size of the space between letters
font_spacing = 8;

font = "Source Code Pro:style=Bold";

build_base = "yes"; //[yes,no]

base_type = "circle"; //[circle,square]

union() {
    length = max(len(text_1), len(text_2));
    base_offset = build_base == "yes" ? font_size / 5 : 0;

    // generate letters
    translate([0, 0, base_offset]) intersection() {

        // generate letter extrusions for first text
        translate([0, (font_spacing + font_size) * length, 0]) rotate([90, 0, 0]) {
            for (i = [0 : len(text_1) - 1]) {
                linear_extrude(height = (font_spacing + font_size) * length) // extrude the letters
                    translate([(font_size + font_spacing) * (i + 0.5), 0, 0]) // shift half the total allocated space
                    text(text_1[i], size = font_size, font = font, halign = "center");
            }
        }

        // generate letter extrusions for second text
        rotate([90, 0, 90]) {
            for (i = [0 : len(text_2) - 1]) {
                linear_extrude(height = (font_spacing + font_size) * length) // extrude the letters
                    translate([(font_size + font_spacing) * (i + 0.5), 0, 0]) // shift half the total allocated space
                    text(text_2[i], size = font_size, font = font, halign = "center");
            }
        }

        // generate cubes around desired letters
        for (i = [0 : length - 1]) {
            translate([(font_size + font_spacing) * i, (font_size + font_spacing) * i, 0])
                cube(font_size + font_spacing);
        }

    }

    //generate base
    if (build_base == "yes") {
        hull() {
            translate([(font_size + font_spacing) * (0.5), (font_size + font_spacing) * (0.5), font_size / 5 * (0.5)])
                if (base_type == "circle") {
                    cylinder(h = font_size / 5, r = (font_size + font_spacing) / 2, center = true);
                } else {
                    cube([font_size + font_spacing, font_size + font_spacing, font_size / 5], center = true);
                }
            translate([(font_size + font_spacing) * (length - 0.5), (font_size + font_spacing) * (length - 0.5), font_size / 5 * (0.5)])
                if (base_type == "circle") {
                    cylinder(h = font_size / 5, r = (font_size + font_spacing) / 2, center = true);
                } else {
                    cube([font_size + font_spacing, font_size + font_spacing, font_size / 5], center = true);
                }
        }
    }
}
```


[User]
Hi, I'm looking to create a parametric OpenSCAD design for a comfort-fit ring shank, similar to the one described in the provided code but from scratch. I need it to be highly customizable with a flat top option and would like to ensure the design is clean and uses good practices in OpenSCAD. I'm very much a beginner so any extra explanations would be helpful!

Here are the specific parameters I need:

*   **Ring Size:** I need this to be based on the North American ring size system, allowing for sizes from 0 to 20 in quarter-size increments. The internal diameter (id) calculation should follow the formula: `id = 11.63 + (Size * 0.8128)`. I'm unsure how to best define it but I need a variable that allows me to define the ring size as a number such as '9' rather than calculating the diameter directly.
*   **Band Width:** This is the width of the ring band, measured in millimeters (mm). This should have a minimum of 1mm and allow up to at least 15mm, ideally adjustable in 0.5mm increments
*   **Band Thickness:** The thickness of the band, also in millimeters (mm). This should be adjustable from 1mm to 5mm in 0.25mm increments.
*   **Top Width:** This optional parameter controls the width of the flat top part, in millimeters (mm). If set to 0, the flat top should not be included in the model. It should be adjustable from 0 to at least 40mm, and ideally in 0.5mm increments. I would like the top width to adjust in response to the ring's overall diameter.
*   **Top Height:**  The height or thickness of the flat top, also in millimeters (mm). This should be adjustable from 0 to at least 5mm with at least 0.1mm increments.

The design should consider the following:

*   **Comfort Fit:** The inner surface of the ring should be slightly curved.
*   **Flat Top Option:** If `Top_width` is greater than 0, a flat rectangular top should be added. The design should account for the potential of the top height being less than the band thickness, and cut out the appropriate portion of the ring to maintain the flat top.
*   **Clear Separation:** I'd like to keep the main ring structure and the flat top functionality separate using `if` conditions, like in the provided code so I can enable and disable the top independently.

I would like this design to be parametric, so that changing the variables updates the entire design. It might make sense to create two files, one for the main ring and one to add the flat top, but I'm fine with a single file if that makes more sense. I'd prefer that any potentially confusing sections be commented.

I think I'd prefer if you do not use any libraries like BOSL or MCAD as I'm trying to get a handle on using the language itself.

Thanks in advance for your help!

[Assistant]
ring_shank.scad:
```
//  Comfort-fit ring shank customizer - North American version
//  by jamcultur - jamcultur@gmail.com

// North American ring size
Size = 9; // [0:0.25:20]
// in millimeters
Band_width = 6; // [1:0.5:15]
// in millimeters
Band_thickness = 2; // [1:0.25:5]
// in millimeters
Top_width = 10; // [0:0.5:40]
// in millimeters
Top_height = 2; // [0:0.1:5]

id = 11.63+(Size*0.8128);
od = id+(Band_thickness*2);

difference() {
    rotate_extrude(convexity=8, $fn=256)
        translate([(od+id)/4, 0, 0])
            scale([(od-id)/(Band_width*2), 1, 1])
                circle(d=Band_width+0.25);
    translate([0, 0, Band_width/2])
        cylinder(d=od+2, h=2);
    translate([0, 0, -(Band_width/2)-2])
        cylinder(d=od+2, h=2);

    if (Top_width && Top_height<Band_thickness)
        translate([(id/2)+Top_height, -(id/2), -(Band_width/2)-1])
            cube([Band_thickness+1, id, Band_width+2]);
}

if (Top_width) {
    rect_width = min(max(Top_width, 1)-Band_thickness, od-Band_thickness);
    difference() {
        union() {
            translate([0, -rect_width/2, -Band_width/2])
                cube([(id/2)+Top_height, rect_width, Band_width]);
            rotate([0, 90, 0]) linear_extrude(height=Top_height+(id/2), $fn=128) {
                translate([0, rect_width/2, -Band_width/2])
                    scale([1, (od-id)/(Band_width*2), 1])
                        circle(d=Band_width+0.25);
                translate([0, -rect_width/2, -Band_width/2])
                    scale([1, (od-id)/(Band_width*2), 1])
                        circle(d=Band_width+0.25);
            }
        }

        translate([0, 0, -(Band_width/2)-1])
            cylinder(d=(id+od)/2, h=Band_width+2);
        translate([0, (rect_width/2)-(Band_thickness/2), Band_width/2])
            cube([(id/2)+Top_height+1, Band_thickness, 2]);
        translate([0, -((rect_width/2)+(Band_thickness/2)), Band_width/2])
            cube([(id/2)+Top_height+1, Band_thickness, 2]);
        translate([0, (rect_width/2)-(Band_thickness/2), -(Band_width/2)-2])
            cube([(id/2)+Top_height+1, Band_thickness, 2]);
        translate([0, -((rect_width/2)+(Band_thickness/2)), -(Band_width/2)-2])
            cube([(id/2)+Top_height+1, Band_thickness, 2]);
    }
}
```


[User]
I'm looking to create a parametric OpenSCAD design for comfort-fit rings, specifically for lost-wax casting. I need the design to be flexible enough to handle a variety of ring sizes, band widths, thicknesses, and top features.

Here's a breakdown of what I'd like:

**Ring Shank:**

*   **Comfort Fit:** The ring shank should have a rounded profile on the inside, creating a "comfort fit".
*   **Parametric Size:** I need to specify the inner circumference in millimeters, following the ISO metric standard.
*   **Band Dimensions:** I need parameters for band width (in mm) and band thickness (in mm).
*   **Basic Shape:** The base of the ring should be a simple revolved shape to achieve the rounded comfort fit profile.
*   **Optional Flat Top:** I'd like the option to add a flat top surface to the ring shank, suitable for attaching other components or carving. The flat top should be parameterized for width and height (both in mm), with height being relative to the base band thickness.

**OpenSCAD Features:**

*   **Parametric Design:** Everything should be controlled by parameters for ease of customization.
*   **Units:** Millimeters (mm) should be the standard unit of measurement.
*  **No external library dependencies** - I want all code to be standalone without using any additional OpenSCAD libraries.

**Specific Parameters:**

*   `ISO_ring_size` (mm): Inner circumference of the ring (e.g., 60mm).
*   `Band_width` (mm): Width of the ring band.
*   `Band_thickness` (mm): Thickness of the ring band.
*   `Top_width` (mm): Width of the optional flat top. Should be 0 to remove the flat top.
*  `Top_height` (mm): Height of the flat top.

**Output:**

*   I just need the main .scad file.

I think that covers everything. Let me know if you need anything else.

[Assistant]
ring_shank_ISO.scad:
```
//  Comfort-fit ring shank customizer - ISO metric version
//  by jamcultur - jamcultur@gmail.com

// inner circumference in mm
ISO_ring_size = 60; // [35:1:80]
// in mm
Band_width = 6; // [1:0.5:15]
// in mm
Band_thickness = 2; // [1:0.25:5]
// in mm
Top_width = 10; // [0:0.5:40]
// in mm
Top_height = 2; // [0:0.1:5]

id = ISO_ring_size/3.14159;
od = id+(Band_thickness*2);

difference() {
    rotate_extrude(convexity=8, $fn=256)
        translate([(od+id)/4, 0, 0])
            scale([(od-id)/(Band_width*2), 1, 1])
                circle(d=Band_width+0.25);
    translate([0, 0, Band_width/2])
        cylinder(d=od+2, h=2);
    translate([0, 0, -(Band_width/2)-2])
        cylinder(d=od+2, h=2);

    if (Top_width && Top_height<Band_thickness)
        translate([(id/2)+Top_height, -(id/2), -(Band_width/2)-1])
            cube([Band_thickness+1, id, Band_width+2]);
}

if (Top_width) {
    rect_width = min(max(Top_width, 1)-Band_thickness, od-Band_thickness);
    difference() {
        union() {
            translate([0, -rect_width/2, -Band_width/2])
                cube([(id/2)+Top_height, rect_width, Band_width]);
            rotate([0, 90, 0]) linear_extrude(height=Top_height+(id/2), $fn=128) {
                translate([0, rect_width/2, -Band_width/2])
                    scale([1, (od-id)/(Band_width*2), 1])
                        circle(d=Band_width+0.25);
                translate([0, -rect_width/2, -Band_width/2])
                    scale([1, (od-id)/(Band_width*2), 1])
                        circle(d=Band_width+0.25);
            }
        }

        translate([0, 0, -(Band_width/2)-1])
            cylinder(d=(id+od)/2, h=Band_width+2);
        translate([0, (rect_width/2)-(Band_thickness/2), Band_width/2])
            cube([(id/2)+Top_height+1, Band_thickness, 2]);
        translate([0, -((rect_width/2)+(Band_thickness/2)), Band_width/2])
            cube([(id/2)+Top_height+1, Band_thickness, 2]);
        translate([0, (rect_width/2)-(Band_thickness/2), -(Band_width/2)-2])
            cube([(id/2)+Top_height+1, Band_thickness, 2]);
        translate([0, -((rect_width/2)+(Band_thickness/2)), -(Band_width/2)-2])
            cube([(id/2)+Top_height+1, Band_thickness, 2]);
    }
}
```


[User]
Hi, I'm looking for some help creating a customizable vibration damper design in OpenSCAD. I'd like to have two options: one with a circular base and one with a square base. I have some ideas about how they should work and what parameters should be adjustable.

For the circular one, imagine a stack of rings, each separated by vertical walls. The important parameters are:

*   `diameter`: The overall diameter of the spring.
*   `nlayers`: The number of ring layers.
*   `heightlayer`: The height of each individual layer between rings.
*   `nvertwall`: The number of vertical walls per layer.
*   `thickwall`: The thickness of the vertical walls.
*   `thickring`: The thickness of the rings.
*   `widthring`: The width of the rings.

Essentially, each ring is a cylinder with a smaller cylinder cut out from the center. Then, between each ring, there are vertical walls connecting the rings. The vertical walls should be evenly spaced around the circumference of the rings and should also be centered along the height of each section. I'd like the vertical walls to alternate the angle they attach with respect to each layer; specifically, offset by half the angular spacing, or (360/nvertwall)/2 radians.

For the square one, it's similar, but with a square base instead of a circle. The key parameters are:

*   `width`: The width of the square spring.
*   `nlayers`: The number of layers.
*   `heightlayer`: The height of each layer.
*   `nvertwall`: The number of vertical walls per layer (needs to be an even number).
*   `thickwall`: The thickness of the vertical walls.
*   `thickring`: The thickness of the rings.
*   `widthring`: The width of the square ring.

The square rings should have an inner square cut out, and the vertical walls should again alternate the angle they attach with respect to each layer. This is similar to the circular offset, but should be an offset of (360/(nvertwall\*2)) \* 2 for each layer. Additionally, I'd like a final operation to cut the external walls of the spring (so that only the interior walls and layers remain). This could be accomplished by using a difference operation from a box with a slightly larger width than the base, and also a square cylinder that cuts through the middle of the spring.

Both of these designs should be able to be adjusted through a customizer, and they don't require any special libraries. Could you generate the necessary OpenSCAD files for me?

[Assistant]
spring_vibrationabsorber1.scad:
```
//Parameters
//Diameter spring
diameter=46;
//Number of layers
nlayers=13;
//Height of one layer
heightlayer = 2.2;
//Number vertical walls for each layer
nvertwall=12;
//Thickness vertical walls
thickwall = 0.8;
//Thickness rings
thickring =0.4;
//Width of the ring
widthring = 3.2;

//modules

module ring(hr)
{ translate([0,0,hr])
    difference()
    { cylinder(r=diameter/2,h=thickring);
      translate([0,0,-1])
      cylinder(r=diameter/2-widthring,h=thickring+2);
    }
}

module vertwalls(rmin, hr)
{ translate([0,0,hr+(heightlayer/2+thickring/2)])
  { for(i=[1:nvertwall])
    { rotate([0,0,(360/nvertwall*i)-rmin])
      translate([0,diameter/2-widthring/2,0])
      cube(size=[thickwall,widthring, heightlayer],center=true);
    }
  }
}

//main
$fn=100;
union()
  {
  for(l=[0:nlayers])
    ring(l*heightlayer);
  for(l=[0:nlayers-1])
    vertwalls((round(l/2)-(l/2)) * (360/nvertwall), l*heightlayer);
  }
```
squarespring_vibrationabsorber1.scad:
```
//-------------
//Parameters
//Width square spring
width=30;
//Number of layers
nlayers=10;
//Height of one layer
heightlayer = 3;
//Number vertical walls for each layer, must be even
nvertwall=8;  //must be even
//Thickness vertical walls
thickwall = 0.8;
//Thickness rings
thickring =0.4;
//Width of the square ring
widthring = 4;

//modules

module borderring(ww, hh, rr)
{
  difference()
  {
    cube([ww,ww,hh], center = true);
    cube([ww-2*rr,ww-2*rr,hh*2], center = true);
  }
}

module vertwalls(rmin, hr)
{ translate([0,0,hr+(heightlayer/2+thickring/2)])
  { for(i=[1:nvertwall])
    { rotate([0,0,(360/nvertwall*i)-rmin])
      cube([thickwall,width*1.5, heightlayer],center=true);
    }
  }
}

//main
difference()
{
    union()
    {
      for(l=[0:nlayers])                //the square rings
        translate([0,0,l*heightlayer + thickring/2])
          borderring(width, thickring, widthring);
      for(l=[0:nlayers-1])              //uncut walls ("star")
        vertwalls((round(l/2)-(l/2)) * (360/(nvertwall*2) * 2), l*heightlayer);
    }

  borderring(width*2,nlayers*heightlayer*3,width/2); //outer cutting ring
  cube([width-2*widthring,width-2*widthring,nlayers*heightlayer*3], center=true);     //inner cuttingring
}

```


[User]
Hey, I'm looking to create a customizable box design using OpenSCAD, and I've found this really awesome project called "Ultimate Box Maker" (https://github.com/jbebel/Ultimate-Box-Maker) that seems like a great starting point. I want something that’s really flexible and can accommodate different PCB sizes and components.

Here's what I'm hoping the design will be able to do:

**Core Features:**

*   **Parametric Box:**  The box dimensions should be fully parametric, so I can control length, width, and height using variables. Ideally, these should be calculatable from the PCB size and margins around the PCB, but I also want the option to set the box dimensions manually.
*   **Wall & Panel Thickness:** I need to be able to control the wall and panel thickness independently.
*  **Font Thickness:**  Control for font thickness on text extrusions.
*  **Filet & Rounding:**  I'd like a parameter to set the corner filet radius, and a toggle to switch between rounded and non-rounded (square/beveled) corners.
*   **Printer Margins:** A margin to account for printer tolerances on interior cutouts and also between mating parts.
*  **PCB Feet:** Options for integrated PCB feet in the bottom shell, including specifying their height, diameter, hole diameter (for screws) and positions, and also fillet for feet. Should support a "screwless" peg design for the feet instead of holes/screws.
*   **Decorations:** Toggle to enable or disable decorative vents/holes on the side walls of the box. These should be scalable and go all the way through the box walls. The spacing, width, and an offset for these should all be configurable.
*  **Panel Gaps:** Separate parameters for panel gaps on the horizontal and vertical edges to ensure a good fit.
*   **Fixation Tabs:** Configurable fixation tabs for the box, that can use either screw holes or snap-fit designs. These tabs should be able to be placed on the top or bottom of the box with a parameter for each tab (front left, front right, back left, and back right). The screw hole and outer shell hole diameters should be independently adjustable.

**PCB Specifics:**

*   **PCB Dimensions:**  I need parameters for the PCB length, width, and thickness.
*  **Margins:** Parameters for the margins between the PCB and the front, back, left, right, and top of the box.
*  **Foot Positions:** Parameters to control the X and Y positions of up to four PCB feet on the inside of the box.
*   **Panel Helpers:** Helper variables to position panel elements relative to the PCB.

**Panel Customization:**

*   **Front & Back Panels:**  I need separate modules for front and back panels that can be exported independently.
*   **Holes & Text:** The ability to add custom holes (both cylinder and square types with configurable size and filet) and text (linear and circular). The text should have parameters for font, size, content, horizontal alignment (left, center, right), and vertical alignment (top, center, bottom, baseline).
*   **Panel Visibility:**  Variables that show the visible edges of the panel.

**Output Options:**

*   **Exportable Parts:** The ability to export the top shell, bottom shell, front panel, and back panel individually.

**Other Features:**

*   **Colors:** I want variables for shell, panel, and text color.
*   **Screwless Design (Experimental):** An option for screwless fixation tabs and PCB supports, but it's okay if this is considered experimental.
*   **Resolution:** Resolution parameter based on round parameter for faster previewing

Essentially, I want to be able to make a box, customize its size based on a PCB, add mounting feet for the PCB, create holes and text on the front and back panels, and have options for screw or snap-fit designs. The included code is a pretty comprehensive description, so hopefully it makes it easy to implement. I'm okay if the generated code uses a lot of custom modules, I'm mostly concerned that the design is as complete as possible given this description.

Thanks!

[Assistant]
Ultimate_Box.scad:
```
/* Box design originally by:
////////////////////////////////////////////////////////////////////
              -    FB Aka Heartman/Hearty 2016     -
              -   http://heartygfx.blogspot.com    -
              -       OpenScad Parametric Box      -
              -         CC BY-NC 3.0 License       -
////////////////////////////////////////////////////////////////////

Improved by jbebel:
http://github.com/jbebel/Ultimate-Box-Maker

To create a box, start by modifying the numerical parameters in the sections
below. This can be accomplished using a release of OpenSCAD newer than 2015.03.
As of the time of writing, this means that a development snapshot is required.
The Thingiverse Customizer may also potentially work, but at the time of
writing, it was inoperable.

The simplest choice is to hand-edit the .scad file. Feature toggles are
annotated with a comment. The other numerical parameters are measurements in
mm. Everything is parametrized, so if you double all the non-feature parameters
you will double the box size in every dimension. Certain parameters are derived
from other parameters. If you wish to override them, you may, but sensible
defaults have been chosen. Notably the design in this revision is particularly
PCB-centric, in that you should start with your PCB size and adjust the margins
around it to determine the box size. If you care more about the box size, you
can set the Length, Width, and Height explicitly, but read the comments around
them.

Once your box is sized appropriately, you can use the Panel modules to design
the holes and text for the front and back panels. Helper variables are provided
to assist you in positioning these holes relative to the PCB, if your holes are
for PCB-mounted components.

When you are ready to print, adjust the values in the "STL element to export"
section, and export each part one at a time.

Experimental options are provided for a screwless design, but these are
untested. In particular, the box fixation tabs may need thicknesses adjusted
in order to have the appropriate flexibility.
*/

// preview[view:north east, tilt:top diagonal]
//----------------------- Box parameters ---------------------------

/* [Box options] */
// - Wall thickness
Thick = 2;
// - Panel thickness
PanelThick = 2;
// - Font Thickness
FontThick = 0.5;
// - Filet Radius
Filet = 2;
// - 0 for beveled, 1 for rounded
Round = 1; // [0:No, 1:Yes]
// - Printer margin around interior cutouts
CutoutMargin = 0.3;
// - Margin between mating parts
PartMargin = 0.1;
// - PCB feet? (x4)
PCBFeet = 1; // [0:No, 1:Yes]
// - Decorations?
Decorations = 1; // [0:No, 1:Yes]
// - Decorations to ventilation holes
Vent = 1; // [0:No, 1:Yes]
// - Decoration-Holes width (in mm)
Vent_width = 1.5;
// - Tolerance (Panel/rails gap on one edge)
PanelThickGap = CutoutMargin + PartMargin;
PanelVerticalGap = PartMargin;
PanelHorizontalGap = CutoutMargin + PartMargin;

/* [Box Fixation Tabs] */
// - Side screw hole (or snap) diameter
ScrewHole = 2.2606;
// - Screw thread major diameter for outer shell
BoxHole = 2.8448;
// Thickness of fixation tabs
TabThick = 2;
// Back left tab
BLTab = 1; // [0:Bottom, 1:Top]
// Back right tab
BRTab = 1; // [0:Bottom, 1:Top]
// Front left tab
FLTab = 1; // [0:Bottom, 1:Top]
// Front right tab
FRTab = 1; // [0:Bottom, 1:Top]
// EXPERIMENTAL: Snap tabs
SnapTabs = 0; // [0:Screws, 1:Snaps]

/* [PCB options] */
// - PCB Length
PCBLength = 80;
// - PCB Width
PCBWidth = 144;
// - PCB Thickness
PCBThick = 1.6;
// You likely need to maintain |TabThick| margin on the left and right for tabs
// and whatnot.
// - Margin between front panel and PCB
FrontEdgeMargin = 70;
// - Margin between back panel and PCB
BackEdgeMargin = 0;
// - Margin between left wall and PCB
LeftEdgeMargin = 11;
// - Margin between right wall and PCB
RightEdgeMargin = 11;
// - Margin between top of PCB and box top.
TopMargin = 84;

/* [PCB_Feet] */
// - Foot height above box interior
FootHeight = 8;
// - Foot diameter
FootDia = 8;
// - Hole diameter, or peg for screwless design
FootHole = 2.2606; // tap size for #4 coarse-thread
// - EXPERIMENTAL Screwless design
Screwless = 0; // [0:Screws, 1:Screwless]
FootFilet = FootHeight/4;

// Foot centers are specified as distance from PCB back-left corner.
// X is along the "length" axis, and Y is along the "width" axis.
// - Foot 1 distance from back PCB edge
Foot1X = 5;
// - Foot 1 distance from left PCB edge
Foot1Y = 5;
// - Foot 2 distance from back PCB edge
Foot2X = 5;
// - Foot 2 distance from right PCB edge
Foot2YFromEdge = 5;
Foot2Y = PCBWidth - Foot2YFromEdge;
// - Foot 3 distance from front PCB edge
Foot3XFromEdge = 5;
Foot3X = PCBLength - Foot3XFromEdge;
// - Foot 3 distance from left PCB edge
Foot3Y = 5;
// - Foot 4 distance from front PCB edge
Foot4XFromEdge = 5;
Foot4X = PCBLength - Foot4XFromEdge;
// - Foot 4 distance from right PCB edge
Foot4YFromEdge = 5;
Foot4Y = PCBWidth - Foot4YFromEdge;

/* [STL element to export] */
// - Top shell
TShell = 0; // [0:No, 1:Yes]
// - Bottom shell
BShell = 1; // [0:No, 1:Yes]
// - Front panel
FPanL = 1; // [0:No, 1:Yes]
// - Back panel
BPanL = 1; // [0:No, 1:Yes]
// - Panel holes and text
PanelFeatures = 0; // [0:No, 1:Yes]

/* [Hidden] */
// - Shell color
Couleur1 = "Orange";
// - Panel color
Couleur2 = "OrangeRed";
// - Text color
TextColor = "White";
// - making decorations thicker if it is a vent to make sure they go through
// shell
// Add a small number to Thick in case Filet is 0.
Dec_Thick = Vent ? Thick*1.001 + Filet : Thick/2;
// Separate vents with a square pillar by default.
Dec_Spacing = Thick + Vent_width;
// X offset to center of first vent
Dec_Offset = Thick*2 + PanelThick + PanelThickGap*2 + Dec_Spacing - Vent_width/2;

// Resolution based on Round parameter. Set this first number to something
// smaller to speed up processing. It should always be a multiple of 4.
Resolution = Round ? 100: 4;

/* Calculate box dimensions from PCB. If you want a more box-centric design
   where the outer diameter of the box matters more than the margins around
   the PCB you can set these manually. The PCB will still be placedaccording
   to the left and back margins, and if you want to use the screwless box
   design, you will need to set the TopMargin to
   (Height - Thick*2 - FootHeight - PCBThick)
*/
Length = PCBLength + FrontEdgeMargin + BackEdgeMargin + ((Thick + PanelThick + PanelThickGap*2)*2);
Width = PCBWidth + LeftEdgeMargin + RightEdgeMargin + Thick*2;
Height = FootHeight + PCBThick + TopMargin + Thick*2;
echo("Box: ", Length=Length, Width=Width, Height=Height);
// X position inset of mounting holes and tabs
MountInset = Thick*3 + PanelThick + PanelThickGap*2 + ScrewHole*4;

// Calculate panel dimensions from box dimensions.
PanelWidth = Width - Thick*2 - PanelHorizontalGap*2;
PanelHeight = Height - Thick*2 - PanelVerticalGap*2;

/*  Panel Manager

    Use the below 4 modules to produce holes and text on the front and back
    panels. The holes modules should contain instances of SquareHole or
    CylinderHole defined later in this file. The text modules should contain
    instances of LText or CText defined later in this file. It is
    recommended to use variables that you define for your needs to create
    the size and positions of these objects.
*/

// Calculate board-relative positions with respect to the panel, for
// convenience in placing panel elements.
TopOfBoardWRTPanel = FootHeight + PCBThick - PanelVerticalGap;
LeftEdgeOfBoardWRTFPanel = LeftEdgeMargin - PanelHorizontalGap;
LeftEdgeOfBoardWRTBPanel = RightEdgeMargin - PanelHorizontalGap;
// Visible panel edges
PanelBottomEdge = Thick - PanelVerticalGap;
PanelTopEdge = PanelHeight - Thick + PanelVerticalGap;
PanelLeftEdge = Thick - PanelHorizontalGap;
PanelRightEdge = PanelWidth - Thick + PanelHorizontalGap;

// Holes for front panel
module FPanelHoles() {
    // SquareHole(On/Off, Xpos,Ypos,Length,Width,Filet)
    SquareHole(1, 20, 20, 15, 10, 1);
    SquareHole(1, 40, 20, 15, 10, 1);
    SquareHole(1, 60, 20, 15, 10, 1);
    // CylinderHole(On/Off, Xpos, Ypos, Diameter)
    CylinderHole(1, 27, 40, 8);
    CylinderHole(1, 47, 40, 8);
    CylinderHole(1, 67, 40, 8);
    SquareHole(1, 20, 50, 80, 30, 3);
    CylinderHole(1, 93, 30, 10);
    SquareHole(1, 120, 20, 30, 60, 3);
}

// Text for front panel
module FPanelText() {
    // LText(On/Off, Xpos, Ypos, "Font", Size, "Text", "HAlign", "VAlign")
    LText(1, 20, 83, "Arial Black", 4, "Digital Screen", HAlign="left");
    LText(1, 120, 83, "Arial Black", 4, "Level", HAlign="left");
    LText(1, 20, 11, "Arial Black", 6, "  1     2      3", HAlign="left");
    // CText(On/Off, Xpos, Ypos, "Font", Size, Diameter, Arc(Deg), Starting Angle(Deg),"Text")
    CText(1, 93, 29, "Arial Black", 4, 10, 180, 0,
          ["1", "." , "3", "." , "5", "." , "7", "." , "9", "." , "11"]);
}

// Holes for back panel
module BPanelHoles() {
    CylinderHole(1,
                 LeftEdgeOfBoardWRTBPanel + 16.4,
                 TopOfBoardWRTPanel + 7,
                 5 + PartMargin*2);
    SquareHole(1,
               LeftEdgeOfBoardWRTBPanel + 37.3,
               TopOfBoardWRTPanel,
               39.2,
               12.55,
               1);
}

// Text for back panel
module BPanelText() {
    LText(1,
          LeftEdgeOfBoardWRTBPanel + 16.4,
          TopOfBoardWRTPanel + 7 + 5,
          "Arial Black",
          4, "PWR"
    );
    LText(1,
          LeftEdgeOfBoardWRTBPanel + 37.3 + 39.2/2,
          TopOfBoardWRTPanel + 12.55 + 2,
          "Arial Black",
          4,
          "DATA"
    );
}

// ------- You probably don't need to modify anything below this line. --------

/* Generic rounded box

    Produces a box of the specified dimensions. Corners are rounded
    according to Filet and Resolution parameters.

    Arguments:
    xshrink: the amount to reduce the length on one end compared to the full
        length
    yzshrink: the amount to reduce the width or height on one edge compared
        to the full box
*/
module RoundBox(xshrink=0, yzshrink=0) {
    Filet = (Filet > Thick*2) ? Filet - yzshrink : Filet;
    translate([xshrink, yzshrink, yzshrink]) {
        rotate([90, 0, 90]) {
            linear_extrude(height=Length - xshrink*2) {
                translate([Filet, Filet, 0]) {
                    offset(r=Filet, $fn=Resolution) {
                        square([Width - 2*yzshrink - 2*Filet, Height - 2*yzshrink - 2*Filet]);
                    }
                }
            }
        }
    }
}

/*  MainBox: Main box module

    This module produces the simple main box half. No feet, tabs, vents or
    fixation is applied here.
*/
module MainBox() {
    difference() {
        union() {
            // Makes a hollow box with walls of Thick thickness.
            difference() {
                RoundBox();
                RoundBox(xshrink=Thick, yzshrink=Thick);
            }
            // Makes interior backing for panel as a wall
            difference() {
                RoundBox(xshrink=(Thick + PanelThick + PanelThickGap*2), yzshrink=Thick/2);
                RoundBox(xshrink=(Thick*2 + PanelThick + PanelThickGap*2));
            }
        }
        // Remove the top half
        translate([-Thick, -Thick, Height/2]) {
            cube([Length + Thick*2, Width + Thick*2, Height]);
        }
        // Remove the center for panel visibility.
        RoundBox(xshrink=-Thick, yzshrink=Thick*2);
    }
}

/*  decoration: a single box decoration
*/
module decoration() {
    translate([-Vent_width/2, -Thick, -Thick]) {
        cube([Vent_width, Dec_Thick + Thick, Height/4 + Thick]);
    }
}

/* LeftDecorations: left decorations module

    Produces the decorations/vents for just the left side of the box.
    These can be rotated and translated for the right side.
*/
module LeftDecorations() {
    for (i=[0 : Dec_Spacing : Length/4]) {
        translate([Dec_Offset + i, 0, 0]) {
            decoration();
        }
        translate([Length - Dec_Offset - i, 0, 0]) {
            decoration();
        }
    }
}

/*  Decorations: decorations module

    This module produces the box vents or decorations.
*/
module Decorations() {
    LeftDecorations();
    // Mirror for the right side decorations
    translate([0, Width, 0]) {
        mirror([0, 1, 0]) {
            LeftDecorations();
        }
    }
}

/*  Coque: Shell module

    This module takes no arguments, but produces a box shell. This is half
    the box, including slots for end panels, rounded corners according to
    Filet and Resolution, and vents/decorations according to parameters.
*/
module Coque() {
    color(Couleur1) {
        difference() {
            MainBox();
            if (Decorations) {
                Decorations();
            }
        }
    }
}

/*  tab: tab module

    Produces a single box fixation tab with screw hole or snap button
*/
module tab() {
    translate([0, Thick, Height/2]) {
        rotate([90, 0, 180]) {
            difference() {
                linear_extrude(TabThick) {
                    difference() {
                        circle(r=4*ScrewHole, $fn=6);
                        if (!SnapTabs) {
                            translate([0, ScrewHole*2, 0]) {
                                circle(d=ScrewHole, $fn=100);
                            }
                        }
                    }
                }
                translate([-4*ScrewHole, -ScrewHole, TabThick]) {
                    rotate([90+45, 0, 0]) {
                        cube([8*ScrewHole, 3*ScrewHole, 5*ScrewHole]);
                    }
                }
                translate([-4*ScrewHole, 0, -PartMargin]) {
                    cube([8*ScrewHole,4*ScrewHole,PartMargin*2]);
                }
            }
            if (SnapTabs) {
                translate([0, ScrewHole*2, PartMargin]) {
                    difference() {
                        sphere(d=(ScrewHole - PartMargin*2), $fn=100);
                        translate([0, 0, ScrewHole*.5 + TabThick/2]) {
                            cube(ScrewHole, center=true);
                        }
                    }
                }
            }
        }
    }
}

/*  Tabs: tabs module

    This module produces the wall fixation box tabs.
    Tabs are produced according to the parameters for XXTab indicating top
    or bottom.

    Arguments:
        top: 0 for bottom shell tabs. 1 for top shell tabs. defaults to bottom.
*/
module Tabs(top=0) {
    color(Couleur1) {
        if (BLTab == top) {
            translate([MountInset, 0, 0]) {
                tab();
            }
        }
        if (FLTab == top) {
            translate([Length - MountInset, 0, 0]) {
                tab();
            }
        }
        if (BRTab == top) {
            translate([MountInset, Width, 0]) {
                rotate([0, 0, 180]) {
                    tab();
                }
            }
        }
        if (FRTab == top) {
            translate([Length - MountInset, Width, 0]) {
                rotate([0, 0, 180]) {
                    tab();
                }
            }
        }
    }
}

/*  hole: hole module

    Produces a box hole for fixation. This is either a cylinder for a screw
    or a semispherical indention for snap tabs.
*/
module hole() {
    if (SnapTabs) {
        translate([0, -Thick, Height/2 - 2*ScrewHole]) {
            sphere(d=ScrewHole, $fn=100);
        }
    }
    else {
        translate([0, Thick, Height/2 - 2*ScrewHole]) {
            rotate([90, 0, 0]) {
                cylinder(Thick*3, d=BoxHole, $fn=100);
            }
        }
    }
}

/*  Holes: holes module

    This module produces the holes necessary in the box fixation tabs and in
    the wall of the box for the corresponding tabs to affix to. Holes are
    produced according to the parameters for XXTab indicating top or bottom.

    Arguments:
        top: 0 for bottom shell holes. 1 for top shell holes. defaults to
            bottom.
*/
module Holes(top=0) {
    color(Couleur1) {
        if (BRTab != top) {
            translate([MountInset, Width, 0]) {
                hole();
            }
        }
        if (FRTab != top) {
            translate([Length - MountInset, Width, 0]) {
                hole();
            }
        }
        if (BLTab != top) {
            translate([MountInset, 0, 0]) {
                rotate([0, 0, 180]) {
                    hole();
                }
            }
        }
        if (FLTab != top) {
            translate([Length - MountInset, 0, 0]) {
                rotate([0, 0, 180]) {
                    hole();
                }
            }
        }
    }
}

/*  PCB: PCB module

    Produces the model of the PCB using parameters for its size and thickness.
    The text PCB is placed on top of the board. This is called by the Feet()
    module with the % modifier which makes this module translucent and only
    viewed in preview mode.
*/
module PCB() {
    translate([0, 0, FootHeight]) {
        cube([PCBLength, PCBWidth, PCBThick]);
        translate([PCBLength/2, PCBWidth/2, PCBThick]) {
            color("Olive") {
                linear_extrude(height=FontThick) {
                    text("PCB", font="Arial black", halign="center", valign="center");
                }
            }
        }
    }
}

/*  foot module

    Produces a single foot for PCB mounting.
*/
module foot(top=0) {
    color(Couleur1) {
        rotate_extrude($fn=100) {
            difference() {
                union() {
                    if (Screwless && top) { // Foot with TopMargin height
                        square([FootDia/2 + FootFilet, TopMargin]);
                    }
                    else if (Screwless && !top) { // Foot for PCB peg
                        square([FootDia/2 + FootFilet, FootHeight + PCBThick*2]);
                    }
                    else if (!Screwless && !top) { // Foot with screw hole
                        translate([FootHole/2 + CutoutMargin, 0, 0]) {
                            square([(FootDia - FootHole)/2 - CutoutMargin + FootFilet, FootHeight]);
                        }
                    }
                }
                translate([FootDia/2 + FootFilet, FootFilet, 0]) {
                    offset(r=FootFilet, $fn=Resolution) {
                        square(Height);
                    }
                }
                if (Screwless && !top) { // Remove around peg
                    translate([FootHole/2 - PartMargin, FootHeight]) {
                        polygon([[0, 0],
                                 [FootDia/2, 0],
                                 [FootDia/2, PCBThick*3],
                                 [-FootHole/3, PCBThick*3],
                                 [0, PCBThick]
                                ]
                        );
                    }
                }
                if (Screwless && top) { // Remove hole for peg
                    translate([-FootHole/2, TopMargin - PCBThick, 0]) {
                        polygon([[0, 0],
                                 [(FootHole*5/6 + CutoutMargin), 0],
                                 [(FootHole + CutoutMargin), PCBThick],
                                 [(FootHole + CutoutMargin), PCBThick*2],
                                 [0, PCBThick*2],
                                ]
                        );
                    }
                }

            }
        }
    }
}

/*  Feet module

    Combines four feet to form mounting platform for PCB.
    A model of the PCB is included with the background modifier. It is
    translucent but visible in the preview, but not in the final render.

    No arguments are used, but parameters provide the PCB and foot dimensions.
*/
module Feet(top=0) {
    translate([BackEdgeMargin + Thick + PanelThick + PanelThickGap*2, LeftEdgeMargin + Thick, Thick]) {
        if (!top) {
            %PCB();
        }

        if (Screwless || !top ) {
            translate([Foot1X, Foot1Y]) {
                foot(top=top);
            }
            translate([Foot2X, Foot2Y]) {
                foot(top=top);
                }
            translate([Foot3X, Foot3Y]) {
                foot(top=top);
                }
            translate([Foot4X, Foot4Y]) {
                foot(top=top);
            }
        }
    }
}

/*  TopShell: top shell module

    Produces the top shell, including requested fixation tabs and holes
    Model is rotated and translated to the appropriate position.
*/
module TopShell() {
    translate([0, 0, Height + 0.2]) {
        mirror([0, 0, 1]) {
            difference() {
                union() {
                    Coque();
                    Tabs(top=1);
                    if (Screwless && PCBFeet) {
                       Feet(top=1);
                    }
                }
                Holes(top=1);
            }
        }
    }
}

/*  BottomShell: bottom shell module

    Produces the bottom shell, including requested fixation tabs, holes,
    and PCB feet.
*/
module BottomShell() {
    difference() {
        union() {
            Coque();
            Tabs();
            if (PCBFeet) {
               Feet(top=0);
            }
        }
        Holes();
    }
}

/*  Panel module

    Produces a single panel with potentially rounded corners. Takes no
    arguments but uses the global parameters.
*/
module Panel() {
    Filet = (Filet > Thick*2) ? Filet - Thick - PanelVerticalGap : Filet - PanelVerticalGap;
    echo("Panel:", Thick=PanelThick, PanelWidth=PanelWidth, PanelHeight=PanelHeight, Filet=Filet);
    translate([Filet, Filet, 0]) {
        offset(r=Filet, $fn=Resolution) {
            square([PanelWidth - Filet*2, PanelHeight - Filet*2]);
        }
    }
}

/*  Cylinder Hole module

    Produces a cylinder for use as a holein a panel

    Arguments:
    OnOff: Rendered only if 1
    Cx: X position of hole center
    Cy: Y position of hole center
    Cdia: diameter of hole
*/
module CylinderHole(OnOff, Cx, Cy, Cdia) {
    if (OnOff) {
        echo("CylinderHole:", Cx=Cx, Cy=Cy, Cdia=Cdia + CutoutMargin*2);
        translate([Cx, Cy, 0]) {
            circle(d=Cdia + CutoutMargin*2, $fn=100);
        }
    }
}

/*  Square Hole module

    Produces a rectangular prism with potentially rounded corner for use as
    a hole in a panel

    Arguments:
    OnOff: Rendered only if 1
    Sx: X position of bottom left corner
    Sy: Y position of bottom left corner
    Sl: width of rectangle
    Sw: height of rectangle
    Filet: radius of rounded corner
*/
module SquareHole(OnOff, Sx, Sy, Sl, Sw, Filet) {
    if (OnOff) {
        Offset = Filet + CutoutMargin;
        echo("SquareHole:", Sx=Sx - CutoutMargin, Sy=Sy - CutoutMargin,
             Sl=Sl + CutoutMargin*2, Sw=Sw + CutoutMargin*2, Filet=Offset);
        translate([Sx + Filet, Sy + Filet, 0]) {
            offset(r=Offset, $fn=Resolution) {
                square([Sl - Filet*2, Sw - Filet*2]);
            }
        }
    }
}

/*  LText module

    Produces linear text for use on a panel

    Arguments:
    OnOff: Rendered only if 1
    Tx: X position of bottom left corner of text
    Ty: Y position of bottom left corner of text
    Font: Font to use for text
    Size: Approximate Height of text in mm.
    Content: The text
    HAlign: Text horizontal alignment. Defaults to "center". "left" and
        "right" available.
    VAlign: Text vertical alignment. Defaults to "baseline". "top",
        "center", and "bottom" available.
*/
module LText(OnOff,Tx,Ty,Font,Size,Content, HAlign="center", VAlign="baseline") {
    if (OnOff) {
        echo("LText:", Tx=Tx, Ty=Ty, Font=Font, Size=Size, Content=Content, HAlign=HAlign, VAlign=VAlign);
        translate([Tx, Ty, PanelThick]) {
            linear_extrude(height=FontThick) {
                text(Content, size=Size, font=Font, halign=HAlign, valign=VAlign);
            }
        }
    }
}

/*  CText module

    Produces circular text for a panel

    OnOff:Rendered only if 1
    Tx: X position of text
    Ty: Y position of text
    Font: Font to use for text
    Size: Approximate height of text in mm
    TxtRadius: Radius of text
    Angl: Arc angle
    Turn: Starting angle
    Content: The text
*/
module CText(OnOff, Tx, Ty, Font, Size, TxtRadius, Angl, Turn, Content) {
    if (OnOff) {
        echo("CText:", Tx=Tx, Ty=Ty, Font=Font, Size=Size,
             TxtRadius=TxtRadius, Turn=Turn, Content=Content);
        Angle = -Angl / (len(Content) - 1);
        translate([Tx, Ty, PanelThick]) {
            for (i= [0 : len(Content) - 1] ) {
                rotate([0, 0, i*Angle + 90 + Turn]) {
                    translate([0, TxtRadius, 0]) {
                        linear_extrude(height=FontThick) {
                            text(Content[i], size=Size, font=Font, halign="center");
                        }
                    }
                }
            }
        }
    }
}

/*  FPanL module

    Produces the front panel. No arguments are used, but this module imports
    FPanelHoles() and FPanelText() which must be edited to produce holes and
    text for your box.
*/
module FPanL() {
    translate([Length - (Thick + PanelThickGap + PanelThick),
               Thick + PanelHorizontalGap,
               Thick + PanelVerticalGap]) {
        rotate([90, 0, 90]) {
            color(Couleur2) {
                linear_extrude(height=PanelThick) {
                    difference() {
                        Panel();
                        if (PanelFeatures) {
                            FPanelHoles();
                        }
                    }
                }
            }
            color(TextColor) {
                if (PanelFeatures) {
                    FPanelText();
                }
            }
        }
    }
}

/*  BPanL module

    Produces the back panel. No arguments are used, but this module imports
    BPanelHoles() and BPanelText() which must be edited to produce holes and
    text for your box.
*/
module BPanL() {
    translate([Thick + PanelThickGap + PanelThick,
               Thick + PanelHorizontalGap + PanelWidth,
               Thick + PanelVerticalGap]) {
        rotate([90, 0, 270]) {
            color(Couleur2) {
                linear_extrude(height=PanelThick) {
                    difference() {
                        Panel();
                        if (PanelFeatures) {
                            BPanelHoles();
                        }
                    }
                }
            }
            color(TextColor) {
                if (PanelFeatures) {
                    BPanelText();
                }
            }
        }
    }
}

// Top shell
if (TShell) {
    TopShell();
}

// Bottom shell
if (BShell) {
    BottomShell();
}

// Front panel
if (FPanL) {
    FPanL();
}

// Back panel
if (BPanL) {
    BPanL();
}

```


[User]
I'd like to create a customizable vase with a spiral design, similar to the one I found online. I'd like to control various aspects of it, specifically:

1.  **Overall Dimensions:** I need to set the base width along the X and Y axes and the overall height of the vase. I'll also need to control the base thickness separately.

2.  **Wall Thickness:** There should be a way to adjust the wall thickness at the base of the vase.

3.  **Flare Control:** The vase sides should be able to flare inward or outward, and I'd like a parameter to control the amount of flare. A value of 1 would indicate straight sides.

4.  **Spiral Twisting:** The vase is composed of clockwise and counterclockwise spirals, and I need separate controls for the amount of twist for each direction. A value of zero for twist would create a column instead of a spiral. Also, a negative twist should reverse the direction.

5.  **Spiral Face Shape:**  I'd also like separate controls for the shape of each spiral's face (flat, cornered, or rounded).

6.  **Resolution:** A resolution setting to control the smoothness of the curves in the vase would be helpful. Lower resolution for quick renders and higher resolution for smooth shapes.

Ideally, I would like the design to be parametric, so I can adjust these parameters easily. It uses OpenSCAD, and I do not want to use any libraries like MCAD, BOSL, BOSL2, dotSCAD, NopSCADlib, or BOLTS, but I am happy to use functions that are built-in to OpenSCAD. Could you generate a .scad file for this?

[Assistant]
spiral_vase.scad:
```
// Spiral Vase/Bowl Customizer v1.1
// Copyright (C) 2019 James C. Turner (nyponen@gmail.com)
// This program is free and has no warranty. It is licensed
// under the terms of the GNU General Public License:
// https://www.gnu.org/licenses/gpl-3.0.txt

// Width of the base on the X axis in millimeters
X_width  = 70;
// Width of the base on the Y axis in millimeters
Y_width  = 60;
// Height of the vase/bowl in millimeters
Z_height = 100;
// Thickness of the base in millimeters
Base_thickness = 3;
// Wall thickness at the base in millimeters
Wall_Thickness = 2.5;                         // [2:0.1:10]
// 1 = straight sides, <1 = flare in, >1 = flare out
Flare_factor = 0.7;                         // [0.2:0.1:4]
// How much to twist the clockwise spirals (0 = no twist)
Clockwise_degree_of_twist = 4;              // [-16:1:16]
Clockwise_spiral_face_shape = 8;            // [4:flat, 8:corner, 64:rounded]
// How much to twist the counterclockwise spirals (0 = no twist)
Counterclockwise_degree_of_twist = 8;       // [-16:1:16]
Counterclockwise_spiral_face_shape = 8;     // [4:flat, 8:corner, 64:rounded]
Resolution = 3;                             // [2:low, 3:medium, 4:high]

scale([(X_width -10)/40, (Y_width -10)/40, 1]) {
    spiral(Clockwise_spiral_face_shape, Clockwise_degree_of_twist);
    rotate([0, 0, 45]) spiral(Counterclockwise_spiral_face_shape, -Counterclockwise_degree_of_twist);
}

module spiral(fn, degree_of_twist) {
    base_extrude = min(Base_thickness,Z_height);
    linear_extrude(height = base_extrude, scale = (((Flare_factor-1) * (base_extrude/Z_height))+1), twist = 45*(((degree_of_twist*base_extrude)/Z_height)), slices = base_extrude*Resolution) {
         offset(r=10, $fn=fn) square(20, center = true);
    }

    if (Base_thickness < Z_height) {
        linear_extrude(height = Z_height, scale = Flare_factor, twist = 45*degree_of_twist, slices = Z_height*Resolution) {
            difference() {
                offset(r=10, $fn=fn) {
                    square(20, center = true);
                }
                offset(r=10, $fn=fn) {
                    square(20-((max(Wall_Thickness, 1))*2.5), center = true);
                }
            }
         }
     }
 }
```


[User]
Hey, I'm looking to design a customizable drawer system in OpenSCAD, something like the Akro-Mils storage drawers, but fully parametric so I can adjust the dimensions. I really like the way that the [DrawerV1.2.scad](https://github.com/BrianAlano/openscad-drawers/blob/main/DrawerV1.2.scad) file works. It’s pretty close to what I want, but I’d like to see it redesigned using best practices and perhaps even some libraries.

Here's the breakdown of what I need:

*   **Basic Drawer:** The core component is a rectangular drawer with rounded corners. I need to be able to set the external width, length, and height, plus the corner radius and wall thickness. The drawer should have slots for dividers.
*   **Dividers:** I want to be able to add dividers to the drawer. The number of dividers and their positions should be adjustable, likely through a list of distances from the front of the drawer. The dividers themselves should have adjustable width and a small height leeway. I want the divider slots to have a lead-in for easy assembly.
*   **Handle:** The drawer needs a handle that fits into a slot on the front of the drawer. The handle should have parameters for its width, length, height, and the size of the fingers that attach it to the drawer. I’d like the handle to be able to easily slide into place (or even snap into place).
*   **Parametric Design:** Everything should be fully parametric so that I can easily adjust all dimensions, thicknesses, and positions.
*   **All-in-One Render:** It would be great to have an option to render the drawer, handle, and dividers all together, so I can see the full assembly.
*   **Customization:** It is crucial to be able to render the drawer, handle, and divider individually for easier debugging.

I don’t mind if it requires multiple files or even using libraries to make things cleaner and more maintainable. The existing SCAD file doesn't use any libraries but if you have a preference for something to make this better I'm all for it, but keep in mind I may need to install it.

Could you help me generate the OpenSCAD files for this system?

[Assistant]
DrawerV1.2.scad:
```
/* Customizable components drawer
licensed under the Creative Commons - Attribution - Non-Commercial - Share Alike license
http://creativecommons.org/licenses/by-nc-sa/3.0/

Version 1.2
=====================
* Removed claim that I made dividers optional. They were already optional.

Version 1.1
=====================
remixed by Green Ellipsis LLC - Brian Alano, 2018-06-01
* Added lead-in to slots for easier assembly
* Made parameters Customizer-friendly
* Created preset for Akro-mils 10144 (and 10164) storage units
* Added all-in-one render
TODO: add option to make drawers nestable, like Akro-mils 10144 drawers.
TODO: add handle like Akro-mils 10144 drawers

V1.0 - 201/03/04
----------------
DonJuanito - Juan Manuel FERNANDEZ CASTRO <https://www.thingiverse.com/thing:2200526>
licensed under the Creative Commons - Attribution - Non-Commercial - Share Alike license.
http://creativecommons.org/licenses/by-nc-sa/3.0/

Inspired by timfou's model:
http://www.thingiverse.com/thing:2200136
*/
// preview[view:south east, tilt:top diagonal]

/* [Components] */
//Component to render
COMPONENT="all"; //[all,drawer,handle,divider]
//Show ghosted handle in drawer rendering
SHOW_HANDLE=true;
//Show ghosted dividers in drawer rendering
SHOW_DIVIDERS = true;
// Debug (Drawer YZ plane cutout)
SHOW_CUTAWAY = false;

/* [Drawer] */
// Drawer external width (X)
BEW = 54.4;
// Drawer external length (Y) (without handle)
BEL = 122.4;
// Drawer external height (Z)
BEH = 36.8;
// Drawer external corner radius
BER = 5.1;
// Drawer wall width (both horizontal and vertical walls)
BWW = 1.4;

/* [Divider] */
// Dividers wall width
DWW = 2.1;
// Dividers width leeway (X) (half on each side)
DXLee = 0.4;
// Dividers height leeway (Z). Reduces height of divider.
DZLee = 0.2;

/* [Slots] */
// Distance from front of drawer to center of each divider. Add or remove values for more or less dividers.
DPos = [41.0, 62.0, 83.0];
// Slots leeway (Y direction)
SLee = 0.2;
// Slots holders wall width
SWW = 2.01;
// Slots walls width (X)
SWX = 1.8;
// Slots bottom cutout depth (Z)
SBC = 0.6;

/* [Handle] */
// Handle width (X)
HW = 28.1;
// Handle length (Y)
HL = 10.1;
// Handle horizontal wall width (Z)
HHWW = 2.2;
// Handle vertical wall width (Y)
HVWW = 1.1;
// Holder internal space (Y)
HHYS = 0.8;
// Holder internal space (Z)
HHZS = 15.1;
// Holder internal fingers width (Y)
HIW = 0.8;
// Holder internal fingers length on each side (X)
HIL = 2.1;
// Holder internal fingers/slots leeway (X, Y)
HILee = 0.2;
// Holder borders width (X, Z)
HBW = 1.8;

/* [Rendering] */
// larger is more detailed but slower
$fn = 36;

/* [Hidden] */
DEBUG_D = SHOW_CUTAWAY;
rr=max(BER-BWW, 0);

RENDER_ALL = COMPONENT=="all" ? true : false;
RENDER_DRAWER = COMPONENT=="drawer" ? true : false;
RENDER_HANDLE = COMPONENT=="handle" ? true : false;
RENDER_DIVIDER = COMPONENT=="divider" ? true : false;

// -- Drawer modules ---
module BB(W=BEW, R=BER) {
    hull() {
        translate([R, 0, 0])
            sphere(r=R);
        translate([W-R, 0, 0])
            sphere(r=R);
    }
}

module BoxVolume(BV=[BEW,BEL,BEH], BR=BER) {
    difference() {
        hull() {
            translate([0, BR, BR])
                BB(W=BV[0], R=BR); // Front lower
            translate([0, BV[1]-BR, BR])
                BB(W=BV[0], R=BR); // Back lower
            translate([0, BR, BV[2]])
                BB(W=BV[0], R=BR); // Front upper
            translate([0, BV[1]-BR, BV[2]])
                BB(W=BV[0], R=BR); // Back upper
        }
        translate([BV[0]/2, BV[1]/2, BV[2]+BR])
            cube([BV[0]+0.2, BV[1]+0.2, BR*2], center=true);
    }
}

module Drawer(SH=SHOW_HANDLE, SD=SHOW_DIVIDERS) {
    difference() {
        // External volume
        BoxVolume();
        // Internal volume cutout
        translate([BWW, BWW, BWW+0.1])
            BoxVolume(BV=[BEW-2*BWW, BEL-2*BWW, BEH-BWW+0.2], BR=rr);
        // Handle slots cutouts
        for (i=[-1:2:1])
            translate([BEW/2+i*(HW-BWW+0.2*2)/2, BWW/2, BEH-(HHZS+HHWW-0.2)/2]) {
                cube([HVWW+HILee, BWW+0.2, HHZS+HHWW+0.2], center=true);
                translate([0,0,(HHZS+HHWW+0.2)/2]) rotate([0,45,0])
                    cube([HVWW*2+HILee, BWW+0.2, HVWW*2+HILee], center=true);
            }
        // Divider slots bottom cutout
        for (i=[0:1:len(DPos)-1])
			if (DPos[i] > 0) {
				translate([BEW/2, DPos[i], BWW-SBC+SLee])
				Divider(WW=DWW+SLee);
			}
    }
    PlaceDividers(ShowDiv=SD);

    // Place handle
    if (SH)
        translate([BEW/2, 0, BEH])
            %Handle();
}

// -- Divider/Slots modules ---

module RC(R=rr, W=DWW) {
    translate([-R, 0, 0])
    difference() {
        translate([R, 0, -R])
            cube([R*2, W+0.2, R*2], center=true);
        rotate([90, 0, 0])
            cylinder(r=R, h=W+0.4, center=true);
    }
}

module Divider(WW=DWW) {
    W=BEW-2*BWW-DXLee;
    H=BEH-BWW-DZLee;

    translate([0, 0, H/2])
    difference() {
        cube([W, WW, H], center=true);
        translate([W/2, 0, -H/2+rr])
            RC(W=WW);
        translate([-W/2, 0, -H/2+rr])
        rotate([0, 0, 180])
            RC(W=WW);
    }
}

module DivSlot() {
    SHeight=BEH-DZLee;
	for (j=[0:1:1])
    for (i=[-1:2:1])
    rotate([0, 0, j*180])
    translate([BEW/2-BWW, 0, 0000*BWW])
    translate([-SWX/2, i*(SWW+DWW+SLee)/2, SHeight/2])
    difference() {
        cube([SWX, SWW, SHeight], center=true);
        translate([0, 0, 0.2])
        difference() {
            translate([0, 0, -SHeight/2])
                cube([BER*2, SWW+0.2, BER*2], center=true);
            translate([-BER+SWX/2+BWW, (SWW+0.2)/2, BER-SHeight/2])
            rotate([90, 0, 0])
                cylinder(r=BER, h=SWW+0.4);

        }
    }
}

module PlaceDividers(ShowDiv=true) {
    for (i=[0:1:len(DPos)-1])
		if (DPos[i] > 0) {
			translate([BEW/2, DPos[i], 0]) {
				if (ShowDiv)
					translate([0, 0, BWW])
						%Divider();
				DivSlot();
			}
		}
}

// --- Handle/Label holder ---

module Handle() {
    hty = HIW+BWW+HHYS+HVWW;

    translate([0, 0, -(HHZS+HHWW/2)]) {
        // Handle
        translate([0, -HL/2, 0])
            cube([HW, HL, HHWW], center=true);
        // Holder vertical parts (slots)
        for (i=[-1:2:1]) {
            translate([i*(HVWW-HW)/2, HIW+BWW-hty/2, HHZS/2])
                cube([HVWW, hty, HHZS+HHWW], center=true);
            translate([i*(HVWW-HW)/2, HIW/2+BWW+HILee, HHZS/2])
                cube([HIL*2+HVWW, HIW, HHZS+HHWW], center=true);
        }
        // Holder vertical borders
        difference() {
            translate([0, -HHYS-HVWW/2, (HHZS+HHWW)/2])
                cube([HW, HVWW, HHZS], center=true);
            translate([0, -HHYS-HVWW/2, (HHZS+HHWW+HBW+0.2)/2])
                cube([HW-2*HBW, HVWW+0.2, HHZS-HBW+0.2], center=true);
        }

    }

}

// --- Render ---
//%translate([-BEW/2, -BEL/2, 0])
//Drawer();

//Divider();
//RC();
//PlaceDividers();
//DivSlot();
//Handle();

if (RENDER_ALL) {
	translate([BEW+5 + HW/2+HIL, HL, HHZS+HHWW])
		Handle();
	for(i=[0:len(DPos)-1]) {
		if (DPos[i] > 0 ) {
			translate([BEW*1.5+5, HL+HVWW+HHYS+HIW+5 + i*(BEH-DZLee+5), DWW/2])
				rotate([-90, 0, 0])
				Divider();
		}
	}
}
if (RENDER_DRAWER || RENDER_ALL) {
    difference() {
        Drawer();
        if (DEBUG_D)
            translate([BEW, BEL/2, BEH/2])
                cube([BEW, BEL+0.2, BEH+0.2], center=true);
    }
} else {
    if (RENDER_HANDLE) {
        translate([0, 0, HHZS+HHWW])
            Handle();
    } else {
        if (RENDER_DIVIDER) {
            translate([0, 0, DWW/2])
            rotate([-90, 0, 0])
            Divider();
        }
    }
}
```


[User]
Okay, I'm looking to get a parametric design in OpenSCAD for a wire spool holder. I'm using it for those small 30AWG wrapping wire spools, the kind that come on little plastic reels, and I need to hold several at once. It should be customizable for various spool sizes, and also for how many spools I want in each row and column.

Specifically, here’s what I'm envisioning.  The design should have a base, like a box, but with holes where the spools go. There should be walls on the sides and in between each spool in a row. The main purpose of these walls is to prevent multiple spools from unwinding at once. I want to be able to mount it on a wall, too, so I'll need screw holes for that.  Ideally the mounting screws should have a countersunk head, or at least a bigger head so it doesn't sink into the print, so the screw holes should have two sizes. One for the screw shaft and one for the head.

Also, I want to ensure a small gap behind the spools to minimize friction. The design should have the ability to round the top of the vertical stand at the edges of each column. Finally, I'd like the spool axis to be a separate piece that slides in, this will enable me to have the axis printed with higher precision with a different filament or print profile.

Here are the parameters I need to control:
*   `spool_radius`: The radius of the wire spools.
*   `spool_width`: The width of the wire spools.
*   `spool_internal_radius`: The radius of the hole in the center of the spools.
*   `nb_cols`: The number of columns (how many spools per row).
*   `nb_rows`: The number of rows of spools.
*   `ground_width`: The thickness of the base that rests on a table or wall.
*   `side_width`: The width of the outer walls.
*   `wall_width`: The width of the walls between the spools in a row.
*    `ground_distance`: The distance between the back of the holder and the back of the spool to avoid friction.
*   `screw_thread`: The radius of the screw thread hole.
*   `screw_head`: The radius of the countersunk screw head hole.

I think that's it. I'm not looking for any specific libraries at the moment.

[Assistant]
MyWrappingWireHolder.scad:
```
$fn=40;

// Spools external radius
spool_radius=35;
// Spool width
spool_width=35;
// Spool internal radius (hole)
spool_internal_radius=12.5;
//  How many spools per row
nb_cols=4;
// How many rows of spools
nb_rows=2;
// Floor width (table or wall side)
ground_width=5;
// External side width (needs to be more than 2mm)
side_width=5;
// Intermediate wall width (fillers used to avoir unrolling several spool at a time)
wall_width=3;
// Distance between back and spools to avoid friction
ground_distance = 1;
// Screw thread radius (if wall mounted)
screw_thread = 3;
// Screw head radius (if wall mounted)
screw_head = 4;

box_x=2*side_width+nb_cols*spool_width+(nb_cols-1)*wall_width;
box_y=nb_rows*2*spool_radius+(nb_rows-1)*wall_width;
box_z=ground_width+2*spool_radius+ground_distance;

intersection() {
        difference (){
            // Box
            cube([box_x,box_y,box_z,]);
            //  Hollow top half of the box
            translate ([side_width,-5,ground_width+spool_radius+ground_distance])
                cube([box_x-2*side_width,box_y+10,box_z]);
            // Wall mount screw holes
            translate([spool_width/2,spool_radius/2,ground_width/2])            cylinder(ground_width,screw_head,screw_head);
            translate([spool_width/2,box_y-spool_radius/2,ground_width/2])            cylinder(ground_width,screw_head,screw_head);
            translate([box_x-spool_width/2,spool_radius/2,ground_width/2])            cylinder(ground_width,screw_head,screw_head);
            translate([box_x-spool_width/2,box_y-spool_radius/2,ground_width/2])            cylinder(ground_width,screw_head,screw_head);
            translate([spool_width/2,spool_radius/2,0])            cylinder(ground_width,screw_thread,screw_thread);
            translate([spool_width/2,box_y-spool_radius/2,0])            cylinder(ground_width,screw_thread,screw_thread);
            translate([box_x-spool_width/2,spool_radius/2,0])            cylinder(ground_width,screw_thread,screw_thread);
            translate([box_x-spool_width/2,box_y-spool_radius/2,0])            cylinder(ground_width,screw_thread,screw_thread);
            // Hollow spool columns
            for(col = [1:1:nb_cols])
                translate([side_width+(col-1)*spool_width+(col-1)*wall_width,-5,ground_width])
                    cube([spool_width,box_y+10,box_z]);
            //  Hollow Spool axis locations
            for(row = [1 :1 : nb_rows]) {
                translate([side_width/2,spool_radius+(row-1)*2*spool_radius+(row-1)*wall_width,ground_width+spool_radius+ground_distance])
                    rotate([0,90,0])
                        cylinder (box_x-side_width,spool_internal_radius,spool_internal_radius);
                translate([side_width/2,spool_radius+(row-1)*2*spool_radius+(row-1)*wall_width,ground_width+spool_radius+ground_distance])
                    rotate([0,90,0])
                        linear_extrude(box_x-side_width)
                            polygon([
                            [-2*spool_radius,-2*spool_internal_radius],[0,-0.9*spool_internal_radius],
                            [0,0.9*spool_internal_radius],[-2*spool_radius,2*spool_internal_radius]
                        ]);
            }
    };
    // Top  rounding shape
    union() {
        // Base box
        cube([box_x,box_y,box_z-spool_radius,]);
        // Base vertical stand on both ends
        cube([box_x,spool_radius,box_z]);
        translate ([0,box_y-spool_radius,0]) cube([box_x,spool_radius,box_z]);
        // Spool rows
        for(row = [1:1 : nb_rows])
            translate([-10,spool_radius+(row-1)*2*spool_radius+(row-1)*wall_width,ground_width+spool_radius+ground_distance])
                rotate([0,90,0])
                    cylinder (box_x+20,spool_radius,spool_radius);
    }
};

// Spool axis
for(row = [1 :1 : nb_rows]) {
    //translate([side_width/2,0,spool_radius*2]) rotate([0,90,0])
    translate([-10-spool_internal_radius,spool_radius+(row-1)*2*spool_radius+(row-1)*wall_width,0])
                cylinder (box_x-side_width,spool_internal_radius,spool_internal_radius);
};

```


[User]
I'm looking to create a customizable box, sort of like a modular organizer. I've seen a design for a "Pencil Box" that's close to what I want, but I need something that I can tweak a lot more easily. Here's what I'm thinking:

**Core Box Parameters:**

*   **Width, Length, Height:** I want to be able to set the overall dimensions of the box.
*   **Thickness:** The thickness of the box walls should be adjustable.
*   **Connectors:** The box should be able to have connectors on all four sides (front, back, left, right). I want to be able to choose whether a side has *no* connector, a *tab* connector, or a *slot* connector.
*   **Connector Size:** I'll need to control the radius of the tab/slot connectors and the gap size for the connectors.

**Additional Features**

*   **Brim:** I need an optional brim around the bottom edges of the box. I should be able to control the brim's width and height.
*   **Rounded Corners:** I like the look of rounded corners on the box edges, but if a corner has a connector, it should remain square. I'd like to control the radius of these rounded corners as well.

**OpenSCAD Specifics**

I want this to be entirely parametric, so I can change any of the above settings and the design will update automatically.  I also want smooth curves, so I'd like to set `$fn` to 100. I don't have any libraries that I need to use, just the basic OpenSCAD stuff. I'd like the code to be pretty readable, too, if possible.

Ideally, I want just one .scad file for the whole thing, but if it needs more than one file, that's okay. I'd like it to be easy to copy/paste the code into OpenSCAD and just change the parameters in the file to generate boxes with the different configurations.

Could you help me generate this code?

[Assistant]
OrganizerBox.scad:
```
/* [Box] */

box_width = 50;

box_lenght = 50;

box_height = 25;

box_right_connector = "tab"; // [none, tab, slot]

box_left_connector = "none"; // [none, tab, slot]

box_front_connector = "none"; // [none, tab, slot]

box_back_connector = "slot"; // [none, tab, slot]

add_brim = "yes"; // [yes, no]

brim_width = 6;

/* [Extra Configuration] */

box_thickness = 2;

box_connector_radius = 9;

box_connector_gap = 0.2;

brim_height = 0.2;

// Smoothness
$fn=100;

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

render(convexity = 2) {
   pencil_box();
}

// Ugly code ahead //

// Create a rectangle and round the unused corners.
module rounded_rectangle(width, lenght, height) {
    corner_diameter = width <= lenght ? width/3 : lenght/3;
    corner_x = ((width/2)-(corner_diameter/2));
    corner_y = ((lenght/2)-(corner_diameter/2));
    corner2_x = (width/2)-corner_diameter;
    corner2_y = (lenght/2)-corner_diameter;
    union() {
        difference() {
            cube([width, lenght, height], center=true);
            // corner 1
            if (box_left_connector == "none" && box_front_connector == "none") translate([-corner_x,-corner_y,0]) cube([corner_diameter,corner_diameter,height], center=true);
            // corner 2
            if (box_left_connector == "none" && box_back_connector == "none") translate([-corner_x,corner_y,0]) cube([corner_diameter,corner_diameter,height], center=true);
            // corner 3
            if (box_right_connector == "none" && box_front_connector == "none") translate([corner_x,-corner_y,0]) cube([corner_diameter,corner_diameter,height], center=true);
            //corner 4
            if (box_right_connector == "none" && box_back_connector == "none") translate([corner_x,corner_y,0]) cube([corner_diameter,corner_diameter,height], center=true);
        }
        // corner 1
        if (box_left_connector == "none" && box_front_connector == "none") translate([-(corner2_x),-(corner2_y),0]) cylinder(height,corner_diameter,corner_diameter, center=true);
        // corner 2
        if (box_left_connector == "none" && box_back_connector == "none") translate([-(corner2_x),(corner2_y),0]) cylinder(height,corner_diameter,corner_diameter, center=true);
        // corner 3
        if (box_right_connector == "none" && box_front_connector == "none") translate([(corner2_x),-(corner2_y),0]) cylinder(height,corner_diameter,corner_diameter, center=true);
        // corner 4
        if (box_right_connector == "none" && box_back_connector == "none") translate([(corner2_x),(corner2_y),0]) cylinder(height,corner_diameter,corner_diameter, center=true);
    }
}

// Create the box, removing the area for the slots.
module box(width, lenght, height, thickness) {
    slot_x = (width/2)-box_connector_radius+(thickness*2);
    slot_y = (lenght/2)-box_connector_radius+(thickness*2);
    union() {
        difference() {
            difference() {
                rounded_rectangle(width, lenght, height);
                translate([0,0,thickness/2]) rounded_rectangle(width-(thickness*2), lenght-(thickness*2), height-thickness);
            }
            if (box_right_connector == "slot") translate([slot_x,0,0]) cylinder(height, box_connector_radius,box_connector_radius, center=true);
            if (box_front_connector == "slot") translate([0,-slot_y,0]) cylinder(height, box_connector_radius,box_connector_radius, center=true);
            if (box_left_connector == "slot") translate([-slot_x,0,0]) cylinder(height, box_connector_radius,box_connector_radius, center=true);
            if (box_back_connector == "slot") translate([0,slot_y,0]) cylinder(height, box_connector_radius,box_connector_radius, center=true);
        }
        // Add brim to the box
        if (add_brim == "yes") {
            if (box_left_connector != "none" || box_front_connector != "none")
                translate([-(width/2),-(lenght/2),-((height/2)-(brim_height/2))]) cylinder(brim_height,brim_width,brim_width, center=true);
            if (box_left_connector != "none" || box_back_connector != "none")
                translate([-(width/2),(lenght/2),-((height/2)-(brim_height/2))]) cylinder(brim_height,brim_width,brim_width, center=true);
            if (box_right_connector != "none" || box_front_connector != "none")
                translate([(width/2),-(lenght/2),-((height/2)-(brim_height/2))]) cylinder(brim_height,brim_width,brim_width, center=true);
            if (box_right_connector != "none" || box_back_connector != "none")
                translate([(width/2),(lenght/2),-((height/2)-(brim_height/2))]) cylinder(brim_height,brim_width,brim_width, center=true);
        }
    }
}

// Add tabs and slots to the box.
module pencil_box() {
    slot_x = (box_width/2)-box_connector_radius+(box_thickness*2);
    slot_y = (box_lenght/2)-box_connector_radius+(box_thickness*2);
    tab_x = (box_width/2)+box_connector_radius-(box_thickness*2)+box_connector_gap;
    tab_y = (box_lenght/2)+box_connector_radius-(box_thickness*2)+box_connector_gap;

    union() {
        box(box_width, box_lenght, box_height, box_thickness);
        if (box_right_connector != "none") {
            if (box_right_connector == "slot") {
                union() {
                    difference() {
                        translate([slot_x,0,0]) cylinder(box_height, box_connector_radius,box_connector_radius, center=true);
                        translate([slot_x,0,0]) cylinder(box_height, box_connector_radius-box_thickness,box_connector_radius-box_thickness, center=true);
                        translate([box_width/2+box_connector_radius,0,0]) cube([box_connector_radius*2,box_connector_radius*2,box_height], center=true);
                    }
                    // Add brim
                    if (add_brim == "yes") translate([(box_width/2),0,-((box_height/2)-(brim_height/2))]) cylinder(brim_height,box_connector_radius,box_connector_radius, center=true);
                }
            } else {
                difference() {
                    translate([tab_x,0,0]) cylinder(box_height, box_connector_radius-box_thickness-box_connector_gap,box_connector_radius-box_thickness-box_connector_gap, center=true);
                    translate([tab_x,0,0]) cylinder(box_height, box_connector_radius-(box_thickness*2)-box_connector_gap,box_connector_radius-(box_thickness*2)-box_connector_gap, center=true);
                }
            }
        }
        if (box_front_connector != "none") {
            if (box_front_connector == "slot") {
                union() {
                    difference() {
                        translate([0,-slot_y,0]) cylinder(box_height, box_connector_radius,box_connector_radius, center=true);
                        translate([0,-slot_y,0]) cylinder(box_height, box_connector_radius-box_thickness,box_connector_radius-box_thickness, center=true);
                        translate([0,-(box_lenght/2+box_connector_radius),0]) cube([box_connector_radius*2,box_connector_radius*2,box_height], center=true);
                    }
                    // Add brim
                    if (add_brim == "yes") translate([0,-(box_lenght/2),-((box_height/2)-(brim_height/2))]) cylinder(brim_height,box_connector_radius,box_connector_radius, center=true);
                }
            } else {
                difference() {
                    translate([0,-tab_y,0]) cylinder(box_height, box_connector_radius-box_thickness-box_connector_gap,box_connector_radius-box_thickness-.2, center=true);
                    translate([0,-tab_y,0]) cylinder(box_height, box_connector_radius-(box_thickness*2)-box_connector_gap,box_connector_radius-(box_thickness*2)-box_connector_gap, center=true);
                }
            }
        }
        if (box_left_connector != "none") {
            if (box_left_connector == "slot") {
                union() {
                    difference() {
                        translate([-slot_x,0,0]) cylinder(box_height, box_connector_radius,box_connector_radius, center=true);
                        translate([-slot_x,0,0]) cylinder(box_height, box_connector_radius-box_thickness,box_connector_radius-box_thickness, center=true);
                        translate([-(box_width/2+box_connector_radius),0,0]) cube([box_connector_radius*2,box_connector_radius*2,box_height], center=true);
                    }
                    // Add brim
                    if (add_brim == "yes") translate([-(box_width/2),0,-((box_height/2)-(brim_height/2))]) cylinder(brim_height,box_connector_radius,box_connector_radius, center=true);
                }
            } else {
                difference() {
                    translate([-tab_x,0,0]) cylinder(box_height, box_connector_radius-box_thickness-box_connector_gap,box_connector_radius-box_thickness-box_connector_gap, center=true);
                    translate([-tab_x,0,0]) cylinder(box_height, box_connector_radius-(box_thickness*2)-box_connector_gap,box_connector_radius-(box_thickness*2)-box_connector_gap, center=true);
                }
            }
        }
        if (box_back_connector != "none") {
            if (box_back_connector == "slot") {
                union() {
                    difference() {
                        translate([0,slot_y,0]) cylinder(box_height, box_connector_radius,box_connector_radius, center=true);
                        translate([0,slot_y,0]) cylinder(box_height, box_connector_radius-box_thickness,box_connector_radius-box_thickness, center=true);
                        translate([0,box_lenght/2+box_connector_radius,0]) cube([box_connector_radius*2,box_connector_radius*2,box_height], center=true);
                    }
                    // Add brim
                    if (add_brim == "yes") translate([0,(box_lenght/2),-((box_height/2)-(brim_height/2))]) cylinder(brim_height,box_connector_radius,box_connector_radius, center=true);
                }
            } else {
                difference() {
                    translate([0,tab_y,0]) cylinder(box_height, box_connector_radius-box_thickness-box_connector_gap,box_connector_radius-box_thickness-box_connector_gap, center=true);
                    translate([0,tab_y,0]) cylinder(box_height, box_connector_radius-(box_thickness*2)-box_connector_gap,box_connector_radius-(box_thickness*2)-box_connector_gap, center=true);
                }
            }
        }
    }
}

```