[User]
I'm looking to design a GPU extension for a Lian Li A4H2O case, since my graphics card is a bit too long. I want it to be parametric so I can adjust the length and other dimensions. I've seen some designs use a click-on mechanism, and I'd like to incorporate that too.

Here's a breakdown of what I need:

*   **Basic Shape:** It should be a rectangular box, essentially extending the front of the case.
*   **Length:** This needs to be adjustable via a parameter (in cm, probably). I want to be able to make it as small as about 2 cm (roughly 0.8 inches) or larger.
*   **Width and Height:** The width should match the case (140 mm) and the height should be about the case's height, which is 244 mm. These should be parameters but might not need to be varied as often as the length.
*   **Click-On Mechanism:** I want to use a specific type of click-socket and pin. I'll be using the one from this thingiverse link: https://www.thingiverse.com/thing:5787989. The socket has a particular height of 5.8mm that should be a parameter.
*   **GPU Clearance:** I need to make sure there's enough internal space for the GPU. The internal space needed is the case width minus a 5.1mm offset on either side.
*   **Side Details:** I'd like to include a style that mimics the case sides. I can describe what that should look like; basically, it has trapezoidal cutouts, and the depth of these cutouts are important. The side panels are mirrored.
*   **Splitting:** For smaller printers, it needs to be split into two parts, top and bottom. This should be a boolean parameter.
*   **Remove Options:** Include remove options on the left side and top side with rounded corners; these are not critical and could be skipped for now, though.
*   **Detailed Rendering:** I would like a high level of detail for the curved parts, using $fn = 50 or so.
*   **Libraries**: I'd like to avoid needing third-party libraries if possible.

Could you generate the necessary OpenSCAD files for this? I'm not sure how many files it'll take; just whatever is best.

[Assistant]
lian-li-a4h2o_gpu_extension.scad:
```
// length of the extension in cm; at least 2 cm (~0.8 inches)
length = 2;
// change if click-mechanism does not fit or is too loose
socket_height = 5.8;
// distance from the outside, to fit GPU width in mm
side_spacer = 5.1;
// split model in 2 parts for smaller printers
split_model = true;
// detail
$fn = 50;
// don't change, 140 is default value
width = 140;
// don't change, 244 is default value
height = 244;

whole_model(length, split_model);

module whole_model(length, split_model) {
    true_length = length * 10;
    if(split_model) {
        // top part
        translate([20, -50, 0]) {
            difference() {
                gpu_extension(true_length);
                cube([width,height/2,true_length + 10]);
            }
        }
        // bottom part
        difference() {
            gpu_extension(true_length);
            translate([0, height / 2, 0]) {
                cube([width,height/2,true_length + 10]);
            }

        }
    } else {
        gpu_extension(true_length);
    }
}

module gpu_extension(length) {
    length = max(length, 20);
    difference() {
        union(){
            cube([width, height, length]);
            // stub top
            translate([ width/2,
                        height-16,
                        length]) {
                stub_stem();
            }
            // stub bottom
            translate([ width/2,
                        16,
                        length]) {
                stub_stem();
            }
        }
        stems(
            side_distance = 22,
            top_distance = 16,
            width = width,
            length = height,
            z_diff = length);
        translate([side_spacer, 22, 0]) {
            gpu_space(length);
        }
        sockets(
            side_distance = 22,
            top_distance = 16,
            width = width,
            length = height,
            z_diff = 0);
        remove_options(width, height, length);
        #mirroring_side_panels_style(length);
    }
}

module stems(
        side_distance,
        top_distance,
        width,
        length,
        z_diff) {
    // top
    translate([ side_distance,
                length-top_distance,
                z_diff]) {
        rotate([180,0,0]){
            click_socket();
        }
    }
    translate([ width-side_distance,
                length-top_distance,
                z_diff]) {

        rotate([180,0,0]){
            click_socket();
        }
    }
    // middle
    translate([ 91,
                146,
                z_diff]) {

        rotate([180,0,90]){
            click_socket();
        }
    }
    // bottom
    translate([ side_distance,
                top_distance,
                z_diff]) {

        rotate([180,0,0]){
            click_socket();
        }
    }
    translate([ width-side_distance,
                top_distance,
                z_diff]) {

        rotate([180,0,0]){
            click_socket();
        }
    }
}

module gpu_space(height) {
    roundedcube(size = [86 - side_spacer,155,height], radius = 5);
}

module sockets(
        side_distance,
        top_distance,
        width,
        length,
        z_diff) {
    // top
    translate([ side_distance,
                top_distance,
                z_diff]) {
        click_socket();
    }
    translate([ width/2,
                top_distance,
                z_diff]) {
        stub_socket();
    }
    translate([ width-side_distance,
                top_distance,
                z_diff]) {
        click_socket();
    }

    // middle
    translate([ 91,
                146,
                z_diff]) {
        rotate([0,0,90]) {
            click_socket();
        }
    }

    // bottom
    translate([ side_distance,
                length-top_distance,
                z_diff]) {
        click_socket();
    }
    translate([ width/2,
                length-top_distance,
                z_diff]) {
        stub_socket();
    }
    translate([ width-side_distance,
                length-top_distance,
                z_diff]) {
        click_socket();
    }
}

module remove_options(width, length, height) {
    top_side = true;
    left_side = true;
    union() {
        if(top_side) {
            translate([side_spacer,length - 63,0]) {
                roundedcube(size = [width - side_spacer * 2,44.5 - side_spacer,height], radius = 5);
            }
        }
        if(left_side) {
            translate([96 ,22,0]) {
                roundedcube(size = [44- side_spacer,155,height], radius = 5);
            }
        }
    }
}

module mirroring_side_panels_style(height) {
    total_length = 244;
    total_width = 140;
    side_panel_height = 16;
    carving_length = 183.5;
    thickness = 1.8;
    translate([0,(total_length - carving_length) / 2,height - side_panel_height]){
        side_panel(carving_length, side_panel_height, thickness);
    }
    translate([total_width - thickness,(total_length - carving_length) / 2,height-side_panel_height]){
        side_panel(carving_length, side_panel_height, thickness + 0.2);
    }
}

module side_panel(carving_length, depth, thickness){
    triangle_length = depth;
    translate([0,triangle_length,0]) {
        cube_length = carving_length - triangle_length * 2;
        rotate([90,-90,90]) {
            rectangular_triangle(triangle_length, thickness);
        }
        cube([thickness,cube_length,depth]);
        translate([0,cube_length + triangle_length,triangle_length]) {
            rotate([90,180,90]) {
                rectangular_triangle(triangle_length, thickness);
            }
        }
    }
}

module rectangular_triangle(length, thickness) {
    difference() {
        cube([length, length, thickness]);
        rotate([0,0,45]) {
            cube([length*2, length, thickness]);
        }
    }
}

module click_socket() {
    depth = 15;
    holding_plate = 14.9;
    holder_thickness = 0.8;
    inner_chamber = 12.3;
    inlay = 1;
    hook_depth = 1.4;
    rotate([90,0,0]){
        translate([-holding_plate / 2, 0, -socket_height/2]){
            translate([holding_plate/2 - inner_chamber/2,holder_thickness + inlay,0]) {
                cube([inner_chamber,depth,socket_height]);
            }
            inside_width = inner_chamber - hook_depth * 2;
            translate([(holding_plate - inside_width) / 2,0,0]) {
                cube([inside_width, inlay + holder_thickness,socket_height]);
            }
            cube([holding_plate,inlay,socket_height]);
        }
    }
}

module stub_stem() {
    diameter = 5;
    radius = diameter / 2;
    totalHeight = 5.1;
    cylinder(d=diameter, h=totalHeight - radius);
    translate([0,0,totalHeight - radius]) {
        sphere(radius);
    }
}

module stub_socket() {
    cylinder(d=6, h=10);
}

module roundedcube(size = [1,1,1], radius = 5) {
    radius = min(size[0]/2-0.01, size[1]/2-0.01, radius);
    minkowski() {
        diameter = radius * 2;
        cube([
            size[0] - diameter,
            size[1] - diameter,
            size[2]/2]);
        translate([radius,radius]) {
            cylinder(r=radius,h=size[2]/2);
        }
    }
}
```


[User]
Okay, so I'm looking to create a customizable, reusable cable tie design for flexible filaments like TPU, and I want it to have a bunch of adjustable features. I've seen a really great one by 3DP_freiberg, but the customizer isn't working, and I want to have something tailored exactly to my needs anyway.

Here's what I'm envisioning:

**Core Design:**

*   The main body of the cable tie should be a strip with a series of bumps (teeth) along one side and a slot at the end for the tie to lock into.
*   The design needs to be fully parametric, with adjustable dimensions for every part.
*   I'd like the option to have a "double slot", basically a second slot a short distance away from the main slot so you can use it as an anchor point on a cable.
*   I also want to be able to add a mounting hole somewhere on the tie for screwing it down to something if needed, or just for extra grip.

**Specific Parameters/Features I Need to Control:**

*   **Bump Count:**  I should be able to specify how many bumps there are along the tie.
*   **Bump Shape:**  I'd like an option to select the bump shape.  One style should be the standard kind, sloped to make it easy to pull the tie tighter but hard to open. The other style will allow the tie to be opened in either direction.
*  **Make Double Tie:** I need a toggle to mirror the cable tie and connect two of them together.
*   **Double Slot:**  A toggle to enable or disable the second slot. Also, I need to set the spacing between the two slots.
*   **Mounting Hole:** A toggle to turn the mounting hole on or off.  And I need parameters for the mounting hole's inner diameter, outer diameter, and offset (distance from the slot) as well as the thickness of the mounting hole.
*   **Base Thickness:** The thickness of the main body of the tie, it should be adjustable.
*   **End Thickness:** The thickness at the end of the tie where the slot is, should also be adjustable.
*   **Base Width:**  The width of the main strip of the tie.
*   **End Radius:** The radius of the round end of the tie.
*   **Slot Height:** The height of the slot cut out.
*   **Slot Distance:** The distance from the last bump to the slot.
*   **Bump Pitch:** The spacing between the bumps.
*   **Bump Height:** The height of each bump.
*   **Tip Length:** The length of the angled lead-in tip on the tie.
*   **Tip Width:** The width of the angled lead-in tip on the tie.

**Advanced/Hidden Parameters**
* Epsilon value to adjust for minor differences between parts,
* quality of arcs and circles,
* Length of slot cut
* length of base tie
* Mounting hole offset calculation
* Max end thickness calculation
* Max mounting hole thickness calculation

**Other Requirements:**

*   I'd like to make use of the `linear_extrude()` and `circle()` primitives, like the original design does.
*   Use appropriate `$fn` values for circles/arcs based on a quality setting to control smoothness.
*   Please make sure the design is easy to modify.

Could you generate a set of OpenSCAD files that achieves this? I'd really appreciate it!

[Assistant]
cable_tie.scad:
```
//TPU Cable Tie
//By Ben Caron 12/30/2022

/*[ Basic ]*/

bump_count = 20;
bump_shape = 2; //[1:one-way, 2:both-ways]
make_double_tie = 0; //[0:false, 1:true]

/*[ Double Slot ]*/

make_double_slot = 1; //[0:false, 1:true]
//spacing between each slot
double_slot_spacing = 6;

/*[ Mounting Hole ]*/

make_mounting_hole = 1; //[0:false, 1:true]
mounting_hole_ID = 3.5;
mounting_hole_OD = 9;
//distance from slot to hole center
mounting_hole_offset = 12;
mounting_hole_thick = 2; //[0.2:0.2:4]

/*[ Advanced ]*/
base_thick = 1; //[0.2:0.2:4]
end_thick = 1; //[0.2:0.2:4]
base_wide = 5;
end_radius = 7;
slot_height = 1.3;
//distance from last bump to slot
slot_distance = 19;

bump_pitch = 4.8;
bump_height = 1.5;

tip_long = 10;
tip_wide = 2;

/* [Hidden] */
epsilon = 0.01;
quality = 10;  //curve quality
quality_small = quality*4;
quality_large = quality*4*2;

slot_long = base_wide+1;
base_long = slot_distance + bump_count*bump_pitch + bump_height;
mounting_hole_offset2 = mounting_hole_offset + double_slot_spacing*make_double_slot;
_end_thick = max(end_thick, base_thick);
_mounting_hole_thick = max(mounting_hole_thick, end_thick);

//Main build
double_tie()
{
    union()
    {
        if(make_mounting_hole)
            build_BaseWithHole();
        else
            build_Base();
        place_bumps();
    }
}

module build_BaseWithHole()
{

    difference()
    {

        union()
        {
            build_Base();

            //mounting hole outside
            linear_extrude(_mounting_hole_thick)
            translate([-mounting_hole_offset2,0])
            circle(mounting_hole_OD/2, $fn=quality_large);

            //connect mounting hole to base
            linear_extrude(min(_end_thick, _mounting_hole_thick))
            translate([-mounting_hole_offset2, -(mounting_hole_OD<=end_radius*2?mounting_hole_OD:end_radius*2)/2])
            square([mounting_hole_offset-slot_height/2-epsilon, mounting_hole_OD<=end_radius*2?mounting_hole_OD:end_radius*2]);
        }

        //mounting hole cut
        translate([-mounting_hole_offset2, 0, -_mounting_hole_thick/2])
        linear_extrude(_mounting_hole_thick*2)
        circle(mounting_hole_ID/2, $fn=quality_small);
    }
}

module build_Base()
{
    union()
    {
        linear_extrude(base_thick)
        union()
        {
            //base
            translate([slot_height/2,-base_wide/2])
            square([base_long-slot_height/2,base_wide]);

            //Tip
            translate([base_long,0])
            polygon([[tip_long,-tip_wide/2],[tip_long,tip_wide/2],[-0,base_wide/2],[-0,-base_wide/2]]);

        }

        linear_extrude(_end_thick)
        difference()
        {
            union()
            {
                //end
                circle(end_radius, $fn=quality_large);

                if(make_double_slot)
                {
                    translate([-double_slot_spacing,0])
                    circle(end_radius, $fn=quality_large);

                    translate([-double_slot_spacing/2,0])
                    square([double_slot_spacing,end_radius*2],center=true);
                }
            }

            //slot
            square([slot_height,slot_long], center=true);
            if(make_double_slot)
            {
                translate([-double_slot_spacing,0])
                square([slot_height,slot_long], center=true);
            }
        }
    }
}

module build_Bump_shape()
{
    if(bump_shape == 2)
        build_Bump();
    else
    {
        translate([-bump_height, 0])
        scale([2,1,1])
        difference()
        {
            build_Bump();

            linear_extrude(bump_height+base_thick+epsilon)
            translate([-bump_height, -base_wide/2])
            square([bump_height+epsilon, base_wide+epsilon]);
        }
    }
}

module build_Bump()
{
    rotate([0,-90,0])
    intersection()
    {
        translate([base_thick, -base_wide/2])
        rotate([-90,-90,0])
        linear_extrude(base_wide)
        difference()
        {
            circle(bump_height, $fn=quality_small);

            translate([-bump_height,-bump_height*2-epsilon])
            square([bump_height*2, bump_height*2]);
        }

        cut_ofs = 1;
        cut_rad = sqrt(pow(base_wide/2,2)+pow(cut_ofs,2));
        translate([base_thick-cut_ofs, 0, -bump_height])
        linear_extrude(bump_height*2)
        circle(cut_rad, $fn=quality_small);
    }
}

module place_bumps()
{
    translate([slot_distance,0,0])
    for ( i = [0:1:bump_count-1])
    {
        translate([i*bump_pitch,0,0])
        build_Bump_shape();
    }
}

module double_tie()
{
    union()
    {
        //original
        translate([mounting_hole_offset2,0])
        children();

        if(make_double_tie)
        {
            //mirrored copy
            mirror([1,0,0])
            translate([mounting_hole_offset2,0])
            children();

            if(!make_mounting_hole)
            {
                //connect the two copies
                linear_extrude(base_thick)
                square([mounting_hole_offset*2-slot_height,(base_wide+end_radius*2)/2], center=true);
            }
        }
    }
}

module copy_mirror(vec)
{
    children();
    mirror(vec)
    children();
}

```


[User] Hey, I have this STL file, `ShapeJS.stl`, and I'd like to create a parametric OpenSCAD model that recreates its shape, but with some adjustable parameters. I'm hoping I can adjust the overall size of the model, specifically with a "scale" factor. I'd also like to be able to adjust the amount of detail, maybe with something like a "resolution" parameter. So higher resolution means a more faithful reproduction of the STL, and lower resolution means it'll have fewer facets. I'm guessing this would involve reading the STL file, so whatever libraries can handle that are fine, but otherwise I don't have any specific library preferences. Could you help me out?

[Assistant]
Sintitulo.scad:
```
import("C:/Users/zahir/Documents/ShapeJS.stl");

```


[User]
I'm looking to design a sun shield for my car radio screen. I have a small gap right above the screen where I can mount it, kind of like a plug-in. I want to make this adjustable, so I can change the size in OpenSCAD.

Here's what I'm envisioning:

The sun shield will be primarily a rectangular box with an extension at the back that will plug into the gap above the screen. I want the main rectangular part to have:

*   `width_top`: the width of the box
*   `depth_top`: the depth of the box
*   `thickness_top`: the thickness of the box

The extension piece will have:

*   `depth_mount`: the depth of the mounting extension
*   `thickenss_mount`: the thickness of the mounting extension

On either side of the main rectangular box I'd like to add side pieces. These sides will have a rectangular cross-section and be tall enough to block the sun from the sides. They will have:

*   `height_side`: The height of the side pieces
*   `depth_side`: The depth of the side pieces (should be the same as `depth_top`)
*   `thickness_side`: The thickness of the side pieces

I want the top corners where the sides connect to the top box to be rounded or filleted, so that they're not sharp.

I would like to use the `BOSL` library for the fillet function and basic shapes like `cube`. I'd also like to be able to control the resolution using `$fn` and a `resolution` parameter.

Could you generate an OpenSCAD file for this with all the parameters I listed?

[Assistant]
sun-protector_car-radio.scad:
```
// sun protector for car radio

// Imports
include <BOSL/constants.scad>
use <BOSL/shapes.scad>
use <BOSL/masks.scad>

/*[ Properties of the sun protector ]*/

resolution = 50;

width_top = 187;
depth_top = 60;
thickness_top = 5;

depth_mount = 8;
thickenss_mount = 3;

height_side = 115;
depth_side = depth_top;
thickness_side = 4;

$fn = resolution;

union() {
    cube([width_top, depth_top, thickness_top]);
    translate([0, -depth_mount , 0]) cube([width_top, depth_mount, thickenss_mount]);
    sideObject();
    translate([width_top - thickness_side, 0 , 0]) sideObject();
}

module sideObject() {
    difference() {
        cube([thickness_side, depth_side, height_side]);
        translate([0, depth_side, height_side]) #fillet_mask(l=thickness_side, r=depth_side, orient=ORIENT_X, center = false);
    }
}

```


[User]
Hey, I'm looking to get a custom pickup ring design made for my Gretsch Junior Jet bass. I've got some measurements and a few specific features in mind, and I'd like a parametric OpenSCAD file so I can adjust it later.

Essentially, I need a pickup ring that can accommodate a standard humbucker, but I also want the ability to easily change the pickup hole dimensions and the screw hole spacing since I might use different pickups. I'd also like to adjust the height offset, specifically at the top, so it sits better against the fretboard if needed. The ring also needs screw holes for mounting to the bass body and for mounting the pickup itself. It's a pretty standard shape; a rounded rectangle with a pickup-sized cutout in the middle.

Here are the dimensions I'm thinking of for the default, but again, these need to be adjustable via parameters:

*   **Pickup Hole:**
    *   Width: 72mm
    *   Height: 40mm
*   **Pickup Screw Distance:** 79mm
*   **Total Ring Size:**
    *   Width: 101.5mm
    *   Height: 44.5mm
*   **Top Edge Offset (shave off):** I'd like a parameter to adjust this, with a default of 0 (no shaving off).
*   **Body Screw Distance:**
	* X Distance: 92 mm
	* Y Distance: 35 mm
*   **Thickness:** The ring should be 2mm thick.  I'd also like to be able to adjust the inner thickness separately - how thick the wall/floor will be. I'm looking for a default of 1mm for the wall and floor thickness.

*   **Wall Width:** 1mm.

I also want rounded corners on the outer rectangle of the pickup ring and the inner cutout. Let's use 4mm for the outer radius and 2mm for the inner radius as the default.

I'd like a parameter that lets me generate just the 2D outline for CNC cutting (like exporting a DXF). It should be able to generate the outline as a projection and also include the screw hole cutouts.

I'd like the files to be parametric. I'm not working with pre-existing libraries (unless it's something that's generally included) so please don't rely on any external libraries like BOSL, or MCAD. I'd need it designed from the ground up.

The pickup and body screws should be represented as cylinders with a head and shaft diameter. Assume both have a head diameter of 6.5 mm and a shaft diameter of 3.25 mm. Also, the screws will be countersunk slightly (1mm) so I'd like to take that into account for the cutouts.

Finally, include a parameter that lets me make the body of the pickup ring hollow.

[Assistant]
pickup_ring_g2220.scad:
```
//Pickup hole width (in mm)
inner_width = 72;
//Pickup hole height (in mm)
inner_height = 40;
//Distance between pickup screws (in mm)
pickup_screw_dist = 79;
//2D projection for CNC, export into DXF etc.
2d = false;

/* [Hidden] */

//Total pickup ring width in millimeters.
total_width = 101.5;
//Total pickup ring height in millimeters.
total_height = 44.5;
//Millimeters to shave off the top edge; useful for neck pickups close to the fretboard.
_top_offset = 0;

// Strandberg pickup rings are 20mm wider than PRS

$fn = 100;

width_offset = total_width - 90;
height_offset = total_height - 46;

top_offset = -_top_offset;

outer_width = 90 + width_offset;
outer_height = 46 + height_offset;

body_screw_head = 6.5;
body_screw_shaft = 3.25;
pickup_screw_head = 6.5;
pickup_screw_shaft = 3.25;
countersink = 1;

body_screw_xdist = 92;//82 + width_offset;
body_screw_ydist = 35;//37;

thickness = 2;
inner_thickness = 1;
wall_width = 1;

outer_radius = 4;
inner_radius = 2;

hollow = false;

module rounded_rectangle(size, radius) {
	hull() {
		translate([-(size[0] / 2 - radius), -(size[1] / 2 - radius)])
			circle(radius);
		translate([ (size[0] / 2 - radius), -(size[1] / 2 - radius)])
			circle(radius);
		translate([ (size[0] / 2 - radius),  (size[1] / 2 - radius)])
			circle(radius);
		translate([-(size[0] / 2 - radius),  (size[1] / 2 - radius)])
			circle(radius);
	}
}

module base() {
	difference() {
		linear_extrude(thickness) {
			difference() {
				translate([0, top_offset / 2])
					rounded_rectangle([outer_width, outer_height + top_offset], outer_radius);
				rounded_rectangle([inner_width, inner_height], inner_radius);
			}
		}
		if(hollow)
			translate([0, 0, -(thickness - inner_thickness)])
				linear_extrude((thickness - inner_thickness) * 2)
					rounded_rectangle([outer_width - wall_width, outer_height - wall_width], outer_radius);
	}
}

module screw(head, shaft, x, y) {
	translate([x, y, thickness/2])
		cylinder(thickness*2, shaft / 2, shaft / 2, true);
//	translate([x, y, thickness])
//		cylinder(countersink*2, head / 2, head / 2, true);
}

module screws() {
	screw(body_screw_head, body_screw_shaft, -(body_screw_xdist / 2), -(body_screw_ydist / 2));
	screw(body_screw_head, body_screw_shaft,  (body_screw_xdist / 2), -(body_screw_ydist / 2));
	screw(body_screw_head, body_screw_shaft,  (body_screw_xdist / 2),  (body_screw_ydist / 2));
	screw(body_screw_head, body_screw_shaft, -(body_screw_xdist / 2),  (body_screw_ydist / 2));
	screw(pickup_screw_head, pickup_screw_shaft, -(pickup_screw_dist / 2),  0);
	screw(pickup_screw_head, pickup_screw_shaft,  (pickup_screw_dist / 2),  0);
}
if (2d) {
	difference() {
        projection (cut = true) base();
        projection (cut = true) screws();
    }
} else {
    difference() {
        base();
        screws();
    }
}
```


[User]
I'm looking to create a custom radius gauge that uses a digital caliper. I've seen a design that works on this principle, but I need to make it parametric for my specific caliper, and I'd like a new design that feels a bit cleaner and easier to print. I want the design to essentially hold the caliper securely with the depth gauge exposed to measure inside corners. The measured depth gauge distance will then be used to calculate the radius. The design should be relatively compact, and the arms should allow for a decent radius range.

Here's what I need to be configurable as parameters:

**Caliper Dimensions:**

*   `CaliperWidth`: The widest part of the caliper body near the depth gauge.
*   `CaliperThickness`: The thickness of the caliper body near the depth gauge. Make sure to account for any screws.
*   `CaliperHoleMargin`: A little extra clearance for the caliper to easily slide in and out.
*   `DepthGaugeWidth`: The total width of the caliper's depth gauge.
*  `DepthGaugeTipWidth`: The width of the tip of the caliper's depth gauge.
*   `DepthGaugeThickness`: The thickness of the caliper's depth gauge.
*   `DepthGaugeHoleMargin`: Extra clearance for the depth gauge to move freely.
*  `DepthGaugeBottomMargin`: The distance of the bottom of the depth gauge from the bottom of the caliper body (that is, how far the depth gauge sticks out when retracted).

**Gauge Body Dimensions:**

*   `SleeveWallThickness`: The thickness of the walls surrounding the caliper.
*   `SleeveDepth`: How much of the caliper should be enclosed by the gauge body for stability and alignment.
*   `InternalSleeveCornerRailsSize`: Optional, if the caliper has a bulge around the depth gauge.  This should be zero if this is not necessary.
*   `ArmLength`: The length of the gauge arms, which determines the maximum measurable radius.
*   `ArmThickness`: The thickness of the gauge arms.
*   `CornerNotch`: A small cut out in the corner, helpful for a cleaner print and helps measuring very small radii. Should be 0 to disable.
*   `Inscription`: Text to label the gauge, something like "R=d*2.414".
*  `InscriptionFontSize`: Font size for the text.
*  `InscriptionDepth`: How much to extrude the text. Make this negative for an engraved effect.
*  `Resolution`:  Number of segments when doing curves.
* `SleeveHoleWidth`: Calculate this based on `CaliperWidth` and `CaliperHoleMargin`.
* `sleeveHoleHeight`: Calculate this based on `CaliperThickness` and `CaliperHoleMargin`
* `SleeveWidth`: Calculate this based on `SleeveHoleWidth` and `SleeveWallThickness`
* `SleeveHeight`: Calculate this based on `sleeveHoleHeight` and `SleeveWallThickness`
* `DepthGaugeHoleHeight`: Calculate this based on `DepthGaugeThickness` and `DepthGaugeHoleMargin`.
* `DepthGaugeHoleWidth`: Calculate this based on `DepthGaugeWidth` and `DepthGaugeHoleMargin`.
* `DepthGaugeOffset`: Calculate the horizontal offset for the depth gauge based on the difference between `DepthGaugeWidth` and `DepthGaugeTipWidth`.

I'd like the design to use a single main module, within which most of the action takes place - including calculating `SleeveHoleWidth`, `sleeveHoleHeight`, `SleeveWidth`, `SleeveHeight`, `DepthGaugeHoleHeight`, `DepthGaugeHoleWidth`, and `DepthGaugeOffset`. There should also be `Arms`, `SideRails`, and `Inscription` modules. It should use the `linear_extrude` and `text` functions, and a `difference` function should be used to cut away the necessary sections. It looks like the original code used `$fn` for resolution. I don't have a preference on which library you use, if any, so just use whatever makes the most sense.

[Assistant]
Caliper_Radius_Gauge.scad:
```
/*
 * Caliper Radius Gauge
 * Created by Douglas Krahmer 2023-01-27
/*

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

/* [Caliper Measurements] */

// Widest part of the caliper near the point where the depth guage emerges.
CaliperWidth = 16;

// Thickest part of the caliper near the point where the depth guage emerges. Be sure to account for any screws that may stick out.
CaliperThickness = 5.5;

// This will be doubled and added to the width and height to allow the caliper room to easily slide in/out.
CaliperHoleMargin = 0.2;

/* [Caliper depth gauge] */

// Total width of caliper depth gauge.
DepthGaugeWidth = 3.5;

// Width of the caliper depth gauge tip.
DepthGaugeTipWidth = 2;

// Caliper depth gauge thickness.
DepthGaugeThickness = 1.2;

// This will be doubled and added to the width and height to allow the depth gauge room to easily slide in/out.
DepthGaugeHoleMargin = 0.3;

// How far is the depth guage from the bottom of he caliper.
DepthGaugeBottomMargin = 1;

/* [Guage body] */

// How thick to make the walls of the guage.
SleeveWallThickness = 2;

// How much of the caliper should be covered to ensure it is aligned.
SleeveDepth = 35;

// For calipers that have a screwed-on depth guage retention "bulge" near the tip. 0 to disable.
InternalSleeveCornerRailsSize = 0.8;

// Guage arm length - determines the largest radius that can be measured
ArmLength = 50;

//
ArmThickness = 6;

// Corner notch to keep the corner tidy. This is also impacts the smallest diameter that can be measured. 0 to disable.
CornerNotch = 0.25;

// Radius calculation text
Inscription = "R=d×2.414";

//
InscriptionFontSize = 0.45;

// Enter a negative number to create a raised inscription
InscriptionDepth = 0.5;

// Higher is better
Resolution = 100;

SleeveHoleWidth = CaliperWidth + 2 * CaliperHoleMargin;
sleeveHoleHeight = CaliperThickness + 2 * CaliperHoleMargin;
SleeveWidth = SleeveHoleWidth + 2 * SleeveWallThickness;
SleeveHeight = sleeveHoleHeight + 2 * SleeveWallThickness;

DepthGaugeHoleHeight = DepthGaugeThickness + 2 * DepthGaugeHoleMargin;
DepthGaugeHoleWidth = DepthGaugeWidth + 2 * DepthGaugeHoleMargin;
DepthGaugeOffset = -(DepthGaugeWidth - DepthGaugeTipWidth) / 2;

main();

module main()
{
	$fn = 100;

	difference(){
		difference() {
			union() {
				Arms();
				// main body
				translate([DepthGaugeOffset, 0, 0]) {
					translate([-SleeveWidth / 2, -SleeveDepth, 0]) {
						cube([SleeveWidth, 1.2 * SleeveDepth + SleeveWallThickness, SleeveHeight]);
					}
				}
			}

			// main hole
			translate([DepthGaugeOffset, 0, 0]) {
				// main sleeve hole
				translate([-SleeveHoleWidth / 2, -SleeveDepth, SleeveWallThickness]) {
					cube([SleeveHoleWidth, SleeveDepth, sleeveHoleHeight]);
				}

				// depth guage hole
				translate([-DepthGaugeHoleWidth / 2, 0, SleeveWallThickness + CaliperHoleMargin + DepthGaugeBottomMargin - DepthGaugeHoleMargin])
					cube([DepthGaugeHoleWidth, SleeveDepth + SleeveWallThickness, DepthGaugeHoleHeight]);

				if (InscriptionDepth > 0)
					Inscription();
			}
		}

		// remove extra material at arms base
		rotate(45)
			cube([SleeveHoleWidth, SleeveHoleWidth, SleeveHeight]);

		// corner notch
		translate([-CornerNotch / 2, -CornerNotch / 2, 0])
			cube([CornerNotch, CornerNotch, SleeveHeight]);
	}

	if (InscriptionDepth < 0)
		Inscription();

	SideRails();
}

// Arms
module Arms() {
	// Left
	rotate(-45)
		cube([ArmThickness, ArmLength, SleeveHeight]);

	// Right
	rotate(45)
		translate([-ArmThickness, 0, 0])
			cube([ArmThickness, ArmLength, SleeveHeight]);
}

module SideRails() {
	internalSleeveCornerRailsSize = InternalSleeveCornerRailsSize + CaliperHoleMargin / 2;
	translate([DepthGaugeOffset, 0, 0]) {
		translate([-SleeveHoleWidth / 2, -SleeveDepth, SleeveWallThickness + sleeveHoleHeight - internalSleeveCornerRailsSize])
			cube([internalSleeveCornerRailsSize, SleeveDepth, internalSleeveCornerRailsSize]);
		translate([-SleeveHoleWidth / 2, -SleeveDepth, SleeveWallThickness])
			cube([internalSleeveCornerRailsSize, SleeveDepth, internalSleeveCornerRailsSize]);
		translate([SleeveHoleWidth / 2 - internalSleeveCornerRailsSize, -SleeveDepth, SleeveWallThickness + sleeveHoleHeight - internalSleeveCornerRailsSize])
			cube([internalSleeveCornerRailsSize, SleeveDepth, internalSleeveCornerRailsSize]);
		translate([SleeveHoleWidth / 2 - internalSleeveCornerRailsSize, -SleeveDepth, SleeveWallThickness])
			cube([internalSleeveCornerRailsSize, SleeveDepth, internalSleeveCornerRailsSize]);
	}
}

module Inscription() {
	translate([InscriptionFontSize * 4.6, SleeveWallThickness - SleeveDepth, SleeveHeight - (InscriptionDepth > 0 ? InscriptionDepth : 0)])
		rotate([0, 0, 90])
			scale([InscriptionFontSize, InscriptionFontSize, abs(InscriptionDepth)])
				linear_extrude(1)
					text(Inscription);
}

```


[User]
I need an OpenSCAD design for metric nuts, specifically a parametric design that covers a wide range of sizes. I'd like to be able to specify the "M" size (e.g., M4, M10, M30) and have the nut automatically adjust its dimensions accordingly.

The design should closely follow standard metric nut specifications. The key parameters I need to be adjustable are:

*   **D:** This is the "M" size designation (e.g., 30 for M30, 10 for M10)
*  **fn:** This controls the number of polygons used to generate the nut profile, influencing the visual smoothness of the part (24 for coarse to 120 for very fine).

I've included some data below to help with the calculation:
*   M4    .7     7x3.2   2.8
*   M4.5   .75
*   M5    .8     8x4     3.5
*   M6    1      10x5    4
*   M7    1              4.8
*   M8    1.25   13x6.5  5.3
*   M9    1.25
*  M10    1.5    17x8    6.4
*  M12    1.75   19x10   7.5
*  M14    2      22x11   8.8
*  M16    2      24x13   10
*  M18    2.5    27x15   11.5
*  M20	2,5     30x16   12.5
*  M22	2,5     32x18   14
*  M24	3       36x19   15
*  M27	3       41x22   17
*  M30	3,5     46x24   18.5
*  M33	3,5     50x26   21
*  M36	4       55x29   22.5
*  M39	4       60x31   25
*  M42	4,5     65x34   26
*  M45	4,5     70x36   28
*  M48	5       75x38   30
*  M52	5       80x42   33
*  M56	5,5     85x45   35
*  M60   5,5     90x48   38
*  M64   6       95x51   40
*  M68   6       100x54  42
*  M72   6       105x58  45
*  M76   6       110x61  48
*  M80   6       115x64  50
*  M90   6       130x72  56
*  M100  6       145x80  62

The nut should have a standard hexagonal shape, and I need the internal thread to be modeled. The external collapsing part of the design should also be included. I'm planning on 3D printing these, so keep that in mind.

Please use standard OpenSCAD libraries, and specify which one you are using if required.

[Assistant]
nut.scad:
```

//Size Mxx
D=30; //[6,8,10,12,14,16,18,20,22,24,27,30,33,36,39,42,45,48,52,56,60,64,68,72,76,80,90,100]
//Polygons (24 coarse .. 120 very fine)
fn=30; //[24:24:120]
//Profile="for_3D_Print"; //["True_Metric","for_3D_Print"]
/* [Hidden] */
Model="nut"; //["bolt","nut","bolt & nut"]

// D, P, S x M , K
// M4    .7     7x3.2   2.8
//M4.5   .75
// M5    .8     8x4     3.5
// M6    1      10x5    4
// M7    1              4.8
// M8    1.25   13x6.5  5.3
// M9    1.25
//M10    1.5    17x8    6.4
//M12    1.75   19x10   7.5
//M14    2      22x11   8.8
//M16    2      24x13   10
//M18    2.5    27x15   11.5
//M20	2,5     30x16   12.5
//M22	2,5     32x18   14
//M24	3       36x19   15
//M27	3       41x22   17
//M30	3,5     46x24   18.5
//M33	3,5     50x26   21
//M36	4       55x29   22.5
//M39	4       60x31   25
//M42	4,5     65x34   26
//M45	4,5     70x36   28
//M48	5       75x38   30
//M52	5       80x42   33
//M56	5,5     85x45   35
//M60   5,5     90x48   38
//M64   6       95x51   40
//M68   6       100x54  42
//M72   6       105x58  45
//M76   6       110x61  48
//M80   6       115x64  50
//M90   6       130x72  56
//M100  6       145x80  62
$fn=fn;
Pitch=0;

P=(D==5)?.8:(D==6)?1:(D==8)?1.25:(D==10)?1.5:(D==12)?1.75:
  (D==14 || D==16)?2: (D>=18 && D<=22)?2.5: (D==24 || D==27)?3:
  (D>=30 && D<=33)?3.5:(D>=36 && D<=39)?4.0:(D>=42 && D<=45)?4.5:
  (Pitch==0 && D>=48 && D<=52)?5:
  (Pitch==0 && D>=56 && D<=60)?5.5:
  (Pitch==0 && D>=64)?6:Pitch;
s=(D==5)?8: (D==6)?10: (D==8)?13: (D==10)?17: (D==12)?19:
  (D==14)?22: (D==16)?24: (D==18)?27: (D==20)?30: (D==22)?32:
  (D==24)?36: (D==27)?41: (D==30)?46: (D==33)?50: (D==36)?55:
  (D==39)?60: (D==42)?65: (D==45)?70: (D==48)?75: (D==52)?80:
  (D==56)?85: (D==60)?90: (D==64)?95: (D==68)?100:
  (D==72)?105:(D==76)?110:(D==80)?115:(D==90)?130:
  (D>=100)?145:0;
m=(D==5)?4: (D==6)?5: (D==6.5)?13: (D==10)?8: (D==12)?10:
  (D==14)?11: (D==16)?13: (D==18)?15: (D==20)?16: (D==22)?18:
  (D==24)?19: (D==27)?22: (D==30)?24: (D==33)?26: (D==36)?29:
  (D==39)?31: (D==42)?34: (D==45)?36:
 (D>=48)?round(D*.8):0;

//if (D==5) { P=.8;  s=8;  m=4;};
//if (D==6) { P=1;   s=10; m=5;};
//if (D==8) { P=1.25;s=13; m=6.5;};
//if (D==10) {P=1.5; s=17; m=8;};
//if (D==12) {P=1.75;s=19; m=10;};
//if (D==14) {P=2;   s=22; m=11;};
//if (D==16) {P=2;   s=24; m=13;};
//if (D==18) {P=2.5; s=27; m=15;};
//if (D==20) {P=2.5; s=30; m=16;};
//if (D==22) {P=2.5; s=32; m=18;};
//if (D==24) {P=3;   s=36; m=19;};
//if (D==27) {P=3;   s=41; m=22;};
//if (D==30) {P=3.5; s=46; m=24;};

//nut

R=D/2;
dZ=-P*.2;
//translate([0,0,-m])
difference(){
cylinder(h=m,d=D*1.77,$fn=6);  //matice
  //external collapse below
for(i=[1:2:$fn])rotate([0,0,(i-1)*360/$fn])
translate([D*.725,0,0])rotate([0,-30])translate([0,-D/2,-D])cube(D);
  //external collapse at the top
for(i=[1:2:$fn])rotate([0,0,(i-1)*360/$fn])
translate([D*.725,0,m])rotate([0,-60])translate([0,-D/2,-D])cube(D);
  //cylindrical hole
translate([0,0,-1])cylinder(D,d=D*.88);
  //internal collapse below
translate([0,0,-P*.05])cylinder(d1=D*1.05,d2=0,h=R/2,$fn=$fn/2);
  //internal collapse at top
translate([0,0,m])mirror([0,0,1])translate([0,0,-P*.05])cylinder(d1=D*1.05,d2=0,h=D*.55,$fn=$fn/2);
  //center view (section)
//rotate([0,0,270])translate([0,0,-1])cube(D);
  //thread
for(i=[-$fn/2:$fn/2+ceil(m/P)*$fn])translate([0,0,i*P/$fn])rotate([0,0,(i-.5)*360/$fn])
hull()for(j=[-1:2:1])rotate([0,0,j*180/$fn])translate([0,0,j*.5*P/$fn])
mirror([0,max(j,0),0])rotate([90])translate([R/2,0,0])linear_extrude(.05,scale=.01,center=false)
polygon( points=[[0,-P/2],[R*.35,-P/2],[R*.35,-P/2+dZ],[R/2,-R*.01],[R/2,R*.01],[R*.35+dZ,P/2],[R*.35,P/2],[0,P/2]]);
//#
//translate([0,0,m*.925])cylinder(h=m*.2,d=D*2);
//#
//for(j=[1:2:11])rotate([0,0,j*30])translate([(j==7)?R*.5:0,0,0])
//hull()for(i=[0,1])
//translate([i*s*.48,0,1.8])
//cylinder(h=m,d=.2,$fn=6);
}

//}

```


[User]
I'd like a customizable OpenSCAD design for a heart, suitable for 3D printing. It should have space for two names to be embossed on the front and a hole in the back for a small magnet. I'd like to be able to adjust several parameters.

Specifically:

*   **Heart Size:** I need to control the overall size of the heart.
*   **Heart Thickness:** I need to control the thickness of the heart.
*   **Names:** The design should have two text fields for customizable names (e.g., Name1 and Name2), and a plus sign between the names, all embossed on the front.
*   **Text Properties:**
    *   I want to be able to specify the font, font size, font style (like regular, bold, italic, etc.) and spacing between letters for the text.
    *   I need to control the vertical position of each name, relative to the heart's center.
    *   I need to be able to adjust the height of the text extrusion.
*   **Magnet:**
    *   I need a circular hole for a magnet on the back of the heart.
    *   I need to specify the diameter and thickness of the magnet.
    *   I need a tolerance parameter to allow for variations in magnet sizes and printer precision.
*   **General:**
    *   The design should be parametric and easily customizable via the OpenSCAD customizer.
    *   I want to make sure that the magnet hole doesn't go all the way through the heart if the magnet thickness is greater than or equal to the heart thickness; please add an assertion to the code that prevents that condition from rendering and gives an error message.

I don't need any specific libraries beyond what's included in standard OpenSCAD, but if you have a suggestion for how using a particular library could improve the overall code quality, please let me know; I'm always eager to learn!

Could you please provide the necessary `.scad` file(s)?

[Assistant]
heart.scad:
```
/* [Heart] */

// Overall size of the heart
Heart_Size = 20;
// Thickness of the heart
Heart_Thickness = 4;

/* [Text] */

Name1 = "Name 1";
Name2 = "Name 2";

Line_Height = 2.0; // [1:0.1:10]
Font_Size = 4; // [1:0.1:10]

// You can choose any font installed on your system. Make sure you type the font name correctly. You can see what fonts are available from Help -> Font List.
Font = "Arial";

// Font style. Not all fonts support all styles.
Font_Style = "Regular"; // ["Regular", "SemiBold", "Bold", "Italic", "Bold Italic", "Black"]

Font_Spacing = 1.0; // [0.1:0.1:3]

// How much the text pops out from the heart
Text_Height = 0.4; // [0.1:0.1:10]

// Depending on the names, you can set a different offset so the text lines fit the heart shape better.
Offset = -0.05; // [-1.0:0.01:1.0]

/* [Magnet] */

Magnet_Diameter = 6;
Magnet_Thickness = 3;

// Depending on your printer, you might want to add some tolerance to the magnet hole.
Magnet_Tolerance = 0.2; // [0:0.01:2]

module __Customizer_Limit__ () {}

$fn=100;

if (Heart_Thickness <= Magnet_Thickness) {
    assert(false, "ERROR: Magnet hole goes through the whole object");
}

union() {
    difference(){
        translate([0,Heart_Size / 2 + Heart_Size / 2 * Offset,0]) {
            rotate([0, 0, -135]) {

                cube([Heart_Size, Heart_Size, Heart_Thickness]);
                translate([Heart_Size/2,0,0]) {

                    cylinder(h=Heart_Thickness,d=Heart_Size);
                    translate([-Heart_Size/2,Heart_Size/2,0]) {
                        cylinder(h=Heart_Thickness,d=Heart_Size);
                    }
                }
            }
        }

        translate([0,Heart_Size / 2 * Offset,0]) {
            cylinder(h=Magnet_Thickness,d=Magnet_Diameter + Magnet_Tolerance);
        }
    }

    translate([0, 0, Heart_Thickness]) {
        translate([0, Line_Height * 1 * Line_Height, 0]) {
            linear_extrude(height = Text_Height) {
                text(Name1, Font_Size, font=str(Font, ":style=", Font_Style), halign="center", valign="center", spacing=Font_Spacing);
            }
        }
        translate([0, Line_Height * -0.25 * Line_Height, 0]) {
            linear_extrude(height = Text_Height) {
                text("+", Font_Size, font=str(Font, ":style=", Font_Style), halign="center", valign="center");
            }
        }
        translate([0, Line_Height * -1 * Line_Height, 0]) {
            linear_extrude(height = Text_Height) {
                text(Name2, Font_Size, font=str(Font, ":style=", Font_Style), halign="center", valign="center", spacing=Font_Spacing);
            }
        }
    }
}

echo("===================================");
echo("Press F5 to preview changes.");
echo("Press F6 to render model.");
echo("Press F7 to save model as STL.");
echo("===================================");
```


[User]
I want to create a heart-shaped key fob with two names on it, and I need a parametric OpenSCAD file to do it.  It should have options for how the names appear - either as a hidden lithophane, engraved on the surface, or cut all the way through. It'd be great if the user could specify the font, font size, rotation, and position of each name independently. Also, I'd like to include an optional joining symbol between the names, either a plus sign or an ampersand, that can also be configured for cut type, font, size, position, and rotation. Finally, there should be an option to include or exclude an attachment ring for the key fob. I saw another design that used a minkowski sum with a sphere for rounded edges, and that looked really nice.

Here are the parameters I'm thinking of, but please let me know if there's anything else you think would be useful:

*   **Heart Parameters:**
    *   `heart_width`: The width of the heart at its widest point.
    *   `heart_thickness`: The thickness of the heart.
    *   `add_ring`: Boolean (0 or 1) to include or exclude the attachment ring.

*   **Name 1 Parameters:**
    *   `name1_cut_type`:  Integer (1 for hidden lithophane, 2 for engraved, 3 for cut through).
    *   `name1`: String for the first name.
    *   `name1_font_size`: Font size for the first name.
    *   `name1_font_name`: Integer to select from a list of font names or "other" where the specific font is specified in `name1_other_font`.
    *   `name1_other_font`:  String to specify a font if `name1_font_name` is "other".
    *   `name1_angle`: Rotation of the first name in degrees.
    *   `name1_move_right`: Horizontal adjustment of the first name.
    *   `name1_move_up`: Vertical adjustment of the first name.

*   **Name 2 Parameters:**
    *   `name2_cut_type`: Integer (0 for same as name 1, 1 for hidden lithophane, 2 for engraved, 3 for cut through).
    *   `name2`: String for the second name.
    *   `name2_font_size`: Font size for the second name.
    *   `name2_font_name`: Integer to select from a list of font names or "other" where the specific font is specified in `name2_other_font`.
    *    `name2_other_font`: String to specify a font if `name2_font_name` is "other".
    *   `name2_angle`: Rotation of the second name in degrees.
    *   `name2_move_right`: Horizontal adjustment of the second name.
    *   `name2_move_up`: Vertical adjustment of the second name.

*  **Join Symbol Parameters:**
    *   `join_symbol_cut_type`: Integer (0 for same as name 1, 1 for hidden lithophane, 2 for engraved, 3 for cut through).
     *   `join_symbol`: Integer (0 for none, 1 for plus, 2 for ampersand).
    *  `join_symbol_font_size`: Font size for the joining symbol.
     *   `join_symbol_font_name`: Integer to select from a list of font names or "other" where the specific font is specified in `join_symbol_other_font`.
     *   `join_symbol_other_font`:  String to specify a font if `join_symbol_font_name` is "other".
    *  `join_symbol_angle`: Rotation of the join symbol in degrees.
    *  `join_symbol_move_right`: Horizontal adjustment of the joining symbol.
    *   `join_symbol_move_up`: Vertical adjustment of the joining symbol.

I don't expect you to use any external libraries for this. I think it could all be done with basic OpenSCAD modules.

[Assistant]
TwoNamesHeartKeyFob-v1.1.scad:
```
/* Heart Shaped Key Fob With Two Name
   by Lyl3

Create a heart shaped key fob with a hidden lithophane name (or any other text).
Can also create the name visibly engraved or cut through the heart.

This code is published at:
https://www.thingiverse.com/thing:5836188
and at:
https://www.printables.com/model/390374

licensed under the Creative Commons - Attribution - Share Alike license (CC BY-SA 3.0)

V0.1 - basic functioning code copied from name heart key fob with one name
V0.2 - improved positioning algorithms
V0.3 - made attachment ring a bit bigger, fine tuned the parameters
V1.0 - ready for publication
V1.1 - added option to make the heart without the attachment ring
*/

/* [Heart Parameters] */

// Enter the width of the heart at the widest part (mm).
heart_width = 42; // [30:1:100]

// Enter the thickness of the heart (mm).
heart_thickness = 3; // [2:0.1:5]

// The attachment ring to make the heart into a key fob is optional.
add_ring = 1; // [ 0:no, 1:yes ]

/* [Name 1 Parameters] */

// Select the cutting type of the first name. If you want a hidden lithophane, first select engraved or cut through to preview and adjust the sizing of the name and then change it to lithophane to render it.
name1_cut_type = 2; // [ 1:hidden lithophane, 2:engraved, 3:cut through]

// Enter the first name to put on the key fob.
name1 = "You";

// Enter the size of the font to be used for the first name.
name1_font_size = 6.5; // [3:0.1:30]

// Choose from a small selection of fonts that should work well in this application (NOTE: Arial is not available on the Thingiverse customizer and none of them are available on the OpenSCAD customizer unless you have them installed on your computer).
name1_font_name = 6; // [ 0:other, 1:Arial Black, 2:Arial Bold Italic, 3:Berkshire Swash, 4:Courgette, 5:Pacifico, 6:Sriracha, 7:Yellowtail, 8:Tangerine, 9:Parisienne, 10:Italianno]

// If "other" is selected above, you can specify any font available from the Google fonts repository if you are running this on the Thingiverse customizer. See https://fonts.google.com/ for available fonts. If you are running OpenSCAD on your own computer you can see the fonts available in the "Help/Font List" menu item. The syntax is like this example: "Nunito Sans:style=Bold Italic" (without the quotes).
name1_other_font = "Nunito Sans";

// Enter the amount to rotate the first name. (degrees)
name1_angle = 0; // [-45:1:45]

// Enter the amount to move the first name to the right. A negative value will move it to the left. Depending on the font and angle, a non-zero value might be needed to place it in the best looking position. (mm)
name1_move_right = 0; // [-20:0.1:20]

// Enter the amount to move the first name up. A negative value will move it down. Depending on the font and angle, a non-zero value might be needed to place it in the best looking position. (mm)
name1_move_up = 0; // [-20:0.1:20]

/* [Name 2 Parameters] */

// Select the cutting type of the second name. If you want a hidden lithophane, first select engraved or cut through to preview and adjust the sizing of the name and then change it to lithophane to render it.
name2_cut_type = 0; // [0:same as name 1, 1:hidden lithophane, 2:engraved, 3:cut through]

// Enter the second name to put on the key fob.
name2 = "Me";

// Enter the size of the font to be used for the second name.
name2_font_size = 6.5; // [3:0.1:30]

// Choose from a small selection of fonts that should work well in this application (NOTE: Arial is not available on the Thingiverse customizer and none of them are available on the OpenSCAD customizer unless you have them installed on your computer).
name2_font_name = 6; // [ 0:other, 1:Arial Black, 2:Arial Bold Italic, 3:Berkshire Swash, 4:Courgette, 5:Pacifico, 6:Sriracha, 7:Yellowtail, 8:Tangerine, 9:Parisienne, 10:Italianno]

// If "other" is selected above, you can specify any font available from the Google fonts repository if you are running this on the Thingiverse customizer. See https://fonts.google.com/ for available fonts. If you are running OpenSCAD on your own computer you can see the fonts available in the "Help/Font List" menu item. The syntax is like this example: "Nunito Sans:style=Bold Italic" (without the quotes).
name2_other_font = "Nunito Sans";

// Enter the amount to rotate the second name. (degrees)
name2_angle = 0; // [-45:1:45]

// Enter the amount to move the second name to the right. A negative value will move it to the left. Depending on the font and angle, a non-zero value might be needed to place it in the best looking position. (mm)
name2_move_right = 0; // [-20:0.1:20]

// Enter the amount to move the second name up. A negative value will move it down. Depending on the font and angle, a non-zero value might be needed to place it in the best looking position. (mm)
name2_move_up = 0; // [-20:0.1:20]

/* [Join Symbol Parameters] */

// Select the cutting type of the joining symbol. If you want a hidden lithophane, first select engraved or cut through to preview and adjust the sizing of the name and then change it to lithophane to render it.
join_symbol_cut_type = 0; // [0:same as name 1, 1:hidden lithophane, 2:engraved, 3:cut through]

// Select the symbol to join the two names
join_symbol = 2; // [ 0:none, 1:plus sign, 2:ampersand]

// Enter the size of the font to be used for the second name.
join_symbol_font_size = 4; // [3:0.1:30]

// Choose from a small selection of fonts that should work well in this application (NOTE: Arial is not available on the Thingiverse customizer and none of them are available on the OpenSCAD customizer unless you have them installed on your computer).
join_symbol_font_name = 6; // [ 0:other, 1:Arial Black, 2:Arial Bold Italic, 3:Berkshire Swash, 4:Courgette, 5:Pacifico, 6:Sriracha, 7:Yellowtail, 8:Tangerine, 9:Parisienne, 10:Italianno]

// If "other" is selected above, you can specify any font available from the Google fonts repository if you are running this on the Thingiverse customizer. See https://fonts.google.com/ for available fonts. If you are running OpenSCAD on your own computer you can see the fonts available in the "Help/Font List" menu item. The syntax is like this example: "Nunito Sans:style=Bold Italic" (without the quotes).
join_symbol_other_font = "Nunito Sans";

// Enter the amount to rotate the second name. An angle of zero keeps the name at the widest part of the cutter. An angle of plus or minus 16 degrees works well for centering the name on the cutter for typical font sizes. (degrees)
join_symbol_angle = 0; // [-45:1:45]

// Enter the amount to move the join symbol to the right. A negative value will move it to the left. Depending on the font and angle, a non-zero value might be needed to place it in the best looking position. (mm)
join_symbol_move_right = 0; // [-20:0.1:20]

// Enter the amount to move the join symbol up. A negative value will move it down. Depending on the font and angle, a non-zero value might be needed to place it in the best looking position. (mm)
join_symbol_move_up = 0; // [-20:0.1:20]

joinSymbolText = (join_symbol == 0) ? " " : (join_symbol == 1) ? "+" : "&";

/* [Hidden] */
fudge = 0.01;
rounding_radius = 0.5;
$fa= $preview ? 3 : 1;
$fs= $preview ? 2 : 0.5;

// Determine the thickness of the first name (mm). For a hidden lithophane it should be 1.2 mm less than the thickness of the heart to leave a reasonable thickness of 0.6 mm above and below the name. To have the name cut all the way through the heart or to be visibly engraved it should be set to the same thickness as the heart.
name1_thickness = (name1_cut_type == 1) ? heart_thickness - 1.2: heart_thickness;

// Determine the distance to offset the first name from the bottom of the heart. It should be zero for a hidden lithophane or to have the name cut all the way through the heart. It should be set to a non-zero value less than the thickness of the heart for the name to be visibly engraved into the heart. (mm)
name1_offset = (name1_cut_type == 2) ? heart_thickness - 0.6: 0;

// Determine the thickness of the second name (mm). For a hidden lithophane it should be 1.2 mm less than the thickness of the heart to leave a reasonable thickness of 0.6 mm above and below the name. To have the name cut all the way through the heart or to be visibly engraved it should be set to the same thickness as the heart.
name2_thickness = (name2_cut_type == 1 || (name2_cut_type == 0 && name1_cut_type == 1)) ? heart_thickness - 1.2: heart_thickness;

// Determine the distance to offset the second name from the bottom of the heart. It should be zero for a hidden lithophane or to have the name cut all the way through the heart. It should be set to a non-zero value less than the thickness of the heart for the name to be visibly engraved into the heart. (mm)
name2_offset = (name2_cut_type == 2 || (name2_cut_type == 0 && name1_cut_type == 2)) ? heart_thickness - 0.6: 0;

// Determine the thickness of the join symbol (mm). For a hidden lithophane it should be 1.2 mm less than the thickness of the heart to leave a reasonable thickness of 0.6 mm above and below the name. To have the name cut all the way through the heart or to be visibly engraved it should be set to the same thickness as the heart.
join_symbol_thickness = (join_symbol_cut_type == 1 || (join_symbol_cut_type == 0 && name1_cut_type == 1)) ? heart_thickness - 1.2: heart_thickness;

// Determine the distance to offset the join from the bottom of the heart. It should be zero for a hidden lithophane or to have the name cut all the way through the heart. It should be set to a non-zero value less than the thickness of the heart for the name to be visibly engraved into the heart. (mm)
join_symbol_offset = (join_symbol_cut_type == 2 || (join_symbol_cut_type == 0 && name1_cut_type == 2)) ? heart_thickness - 0.6: 0;

// This convoluted way of selecting the font from an array was a requirement introduced by a change
// on the Thingiverse customizer that broke the ability to directly select fonts with a style specified.
// This issue was first noticed 2020-02-26 and probably happened within the two months prior to that date.
fontNames = ["other", "Arial Black:style=Regular", "Arial:style=Bold Italic", "Berkshire Swash:style=Regular", "Courgette:style=Regular", "Pacifico:style=Regular", "Sriracha:style=Regular", "Yellowtail:style=Regular", "Tangerine:style=Bold", "Parisienne:style=Regular", "Italianno:style=Regular"];

selectedFont1 = (name1_font_name==0) ? name1_other_font : fontNames[name1_font_name];
selectedFont2 = (name2_font_name==0) ? name2_other_font : fontNames[name2_font_name];
selectedJoinSymbolFont = (join_symbol_font_name==0) ? join_symbol_other_font : fontNames[join_symbol_font_name];

// Separate names by moving name 1 up this amount and name 2 down this amount
names_separation = heart_width / 8;

{
  difference() {
    /* Create the heart */
    color("Crimson") minkowski() {
      translate([0,0,rounding_radius])
        linear_extrude(max(heart_thickness-2*rounding_radius,0.001)) union() {
          flat_heart(heart_width-2*rounding_radius);
          // Create the ring
          if (add_ring == 1) translate([0,heart_width/4,0]) difference() {
            circle(5-rounding_radius,$fn=$preview ? 12 : 30);
            circle(4-rounding_radius,$fn=$preview ? 12 : 30);
          }
        }
      sphere(rounding_radius,$fn=$preview ? 12 : 30);
    }
    /* Cut out the first name */
    translate ([0,0,name1_offset+(heart_thickness-name1_thickness-fudge)/2])
      linear_extrude(name1_thickness+fudge)
         rotate([0,0,name1_angle]) translate ([name1_move_right,names_separation+name1_move_up-abs(name1_angle/10),0])
            text(name1,size=name1_font_size,halign="center",valign="center",font=selectedFont1);
    /* Cut out the second name */
    translate ([0,0,name2_offset+(heart_thickness-name2_thickness-fudge)/2])
      linear_extrude(name2_thickness+fudge)
        rotate([0,0,name2_angle]) translate ([name2_move_right, -names_separation+name2_move_up-abs(name2_angle/10),0])
            text(name2,size=name2_font_size,halign="center",valign="center",font=selectedFont2);
    /* Cut out the join symbol*/
    translate ([0,0,join_symbol_offset+(heart_thickness-join_symbol_thickness-fudge)/2])
      linear_extrude(join_symbol_thickness+fudge)
        rotate([0,0,join_symbol_angle]) translate ([join_symbol_move_right, join_symbol_move_up-abs(join_symbol_angle/10),0])
            text(joinSymbolText,size=join_symbol_font_size,halign="center",valign="center",font=selectedJoinSymbolFont);
  }
}

module flat_heart(s=20) {
  size=s/1.707;
  translate ([0,-size/PI,0]) rotate([0,0,45]) {
    square(size,center=true);

    translate([0, size/2, 0])
    circle(size/2);

    translate([size/2, 0, 0])
    circle(size/2);
  }
}

```


[User]
Hi! I'm looking for some help designing a phone stand for a wireless charger, specifically the IKEA Nordmärke. I've got some specific needs and dimensions in mind, and I'd like it to be parametric so I can adjust it for different phones in the future.

Basically, the stand needs to have a circular base that sits on top of the charger, and this base needs to have a cutout so the charging area is exposed. The stand will also have two side supports that run along the length of the phone and these supports need to have an angled surface to help center the phone. Finally, there should be some kind of adjustable rest at the top, that the top of the phone will lean against. This rest needs to be adjustable in height and have a way to make sure the phone will not just slide off.

Here's a breakdown of the dimensions and parameters I'm thinking of:

*   **`inner_diameter`:** The diameter of the base circle. For the Nordmärke, this should be 85mm but it would be good if this was adjustable.
*   **`length`:** The distance from the base to the center of the phone's charging receptor. I'm using a Nokia XR20, which has this at 105mm, but I'd like to make this a variable.
*  **`width`**: The outer width of the support bars. The Nokia XR20 has this at 80mm.
*   **`height`**: The height of the phone's top support above the base. For the XR20 I think 22mm is good but I want this to be a parameter.
*  **base_thickness**: How thick the base should be.
*   **support_thickness**: How thick the support bars should be.
*   **top_support_width**: Width of the top support.
*   **top_support_depth**: Depth of the top support.
*   **top_support_angle**: The angle of the top support to make it easy to drop the phone into place.
*   **top_support_lip**: How much the lip at the top extends out to stop the phone from sliding off.
* **support_angle**: The angle of the support bars.

I'm thinking this would be a good project for using the `rotate_extrude`, `linear_extrude`, `polygon`, `cube`, `cylinder`, and `difference` modules.

I'd really appreciate it if you could create an OpenSCAD file for this. The final result should be a single OpenSCAD file with the above parameters and the functionality as specified. Thanks!

[Assistant]
charger_support.scad:
```
// mobile phone support for wireless charging station
// ensures correct positioning and supports top heavy phones

// 85mm suitable for IKEA Nordmaerke incl. cork
inner_diameter = 85;
// distance top of phone to center of charging receptor (105mm for Nokia XR20)
length = 105;
// outer width of bars; should roughly match phone width (80mm for Nokia XR20)
width = 80;
// height of phone top support over ground, used to level phone
height = 22;

phone_support();

module phone_support()
{
    $fa = 4;

    difference()
    {
        union()
        {
            cylinder(h = 5, d = inner_diameter + 10);
            rotate([0,0,90-15]) translate([0,0,5]) rotate_extrude(angle=30) {translate([inner_diameter/2,0,0]) polygon([[0, 0], [5, 0], [5, 5], [0, 5]]);};
            translate([0,width/2-5,0]) cube([length, 5, 5]);
            translate([0,width/-2,0]) cube([length, 5, 5]);
        };
        translate([0, 0, -1]) cylinder(h = 7, d = inner_diameter);
        translate([0, 0, 0]) rotate([90,0,180]) linear_extrude(height = inner_diameter) {polygon([[-2, 0], [-2, 5], [0, 7], [2, 5], [2, 0]]);};
        translate([0, 0, 10]) rotate([-90,0,15]) linear_extrude(height = inner_diameter) polygon([[0, 0], [0, 2], [2, 0]]);
        translate([0, 0, 10]) rotate([-90,0,-15]) linear_extrude(height = inner_diameter) polygon([[0, 0], [0, 2], [-2, 0]]);
    };

    translate([length,-width/2,0]) cube([5, width, 5]);

    difference()
    {
        translate([length-10,-width/2,5]) cube([15, 15, height+5]);
        translate([length + 5 + 2.5, -width/2+5, 5]) rotate([0, -90, 0]) linear_extrude(height = 20) {polygon([[0, 0], [height-5, 10], [height-5, 11], [0, 11]]);};
        translate([length,-width/2+5+2.5,5]) rotate([0, -90, 90]) linear_extrude(height = 20, center = true) {polygon([[0, 0], [height-5, 10], [height-5, 11], [0, 11]]);};
        translate([length-12.5, -width/2-7.5, height]) linear_extrude(height = 12.5) {polygon([[0, 0], [25, 25], [0, 25]]);};
    }
    difference()
    {
        translate([length-10,width/2-15,5]) cube([15, 15, height+5]);
        translate([length + 5 + 2.5, width/2-5, 5]) rotate([0, -90, 0]) linear_extrude(height = 20) {polygon([[0, 0], [height-5, -10], [height-5, -11], [0, -11]]);};
        translate([length,width/2-5-2.5,5]) rotate([0, -90, 90]) linear_extrude(height = 20, center = true) {polygon([[0, 0], [height-5, 10],[height-5, 11], [0, 11]]);};
        translate([length-12.5, width/2+7.5, height]) linear_extrude(height = 12.5) {polygon([[0, 0], [25, -25], [0, -25]]);};
    }
};

```


[User]
I'm looking to create a customizable cutting board rack in OpenSCAD, based on some designs I found online.  The basic structure involves a series of horizontal base slats connected by vertical supports. I want to be able to control the number of slots for cutting boards, the length of each horizontal base slat, and the overall thickness of the support structure.

Specifically, I need the design to include:

1.  **Horizontal Base Slats:** These will be the shelves that hold the cutting boards. Each slat will have a consistent width (which I'd like to define), and a length that I can set. There will be a repeating pattern of these horizontal slats, with a defined spacing between them. They'll also need rounded edges to look nice. They should have a consistent profile shape, with flat sections in the middle and rounded sections at the ends. I need to be able to define the curvature radius of the rounded sections.

2.  **Vertical Supports:** These are the triangular-shaped supports at the ends of the rack. The supports will be constructed from an overlapping pair of hollow, rounded triangles with a connecting strut between them. I want to define the thickness of the triangle outlines, and also to be able to round the corners of the triangles. The triangles themselves must not go all the way to the bottom or top of the rack. They need to be clipped at the top and bottom.

3.  **Customization:** The whole thing needs to be parametric. I want to be able to define:
    *   `baseDim`: The width of the base slats.
    *   `baseUnitY`: The length of the base slats
    *   `repeats`: The number of slots (which means the number of horizontal slats and vertical supports)
    *   `triEdgeWidth`: The thickness of the outline of the triangles.
    *  `cRad`: The radius of the curvature at the edges of the base and the corners of the triangles

4. The final part needs to be made up of the supports and slats. A single support should go at the bottom, then a horizontal base. Then another support and another horizontal base, and so on until the number of slots (repeats) is reached. Then another support at the top.

I want to be able to set the dimensions, and have the rack generate automatically based on those.

I'd like you to generate the OpenSCAD code that can do this. It shouldn't rely on any external libraries.

[Assistant]
CuttingBoardRack.scad:
```
// https://www.thingiverse.com/thing:5841386 2/07/2023
// by David Phillip Oster
// remix of Cutting board Rack x3 by Matearoa on Thingiverse: https://www.thingiverse.com/thing:4890276
// x4 https://www.thingiverse.com/thing:4676762

// width of base slat height is twice that.
baseDim=20;

// length of base slat
baseUnitY = 60;

// number of slots.
repeats = 2;

// thickness (in 2D of the big triangeles)
triEdgeWidth=10;

// Profile of base slat at right edge
module rightEdge(cRad=0){
  offset(cRad)polygon([
    [baseDim-cRad,0+cRad],
    [(baseDim/2)-cRad,(baseDim/2)-cRad],
    [0+cRad,(baseDim/2)-cRad],
    [0+cRad,0+cRad],
  ]);
}

// Profile of base slat at left edge
module leftEdge(cRad=0){
  mirror([1, 0])rightEdge(cRad);
}

// Profile of base slat that isn't an edge
module middleRidge(cRad=0){
  offset(cRad)polygon([
    [-baseDim/2+cRad,0+cRad],
    [baseDim/2-cRad,0+cRad],
    [(baseDim/4)-cRad,(baseDim/2)-cRad],
    [(-baseDim/4)+cRad,(baseDim/2)-cRad],
  ]);
}

// Profile of base
// TODO: the spacing should be computed based on the triangle size.
module baseProfile(cRad=0){
  translate([-0.5,0])rightEdge(cRad);
  translate([72,0])middleRidge(cRad);
  translate([127,0])middleRidge(cRad);
  translate([200,0])leftEdge(cRad);
}

// A base - between two uprights.
module baseUnit(){
  translate([0,baseUnitY,0])rotate([90, 0, 0])linear_extrude(baseUnitY){
    baseProfile(2);
  }
}

// A 2D triangle.
// inset - make it smaller. inset = 10, is 10mm smaller
// cRad - radius of curvature of the corners.
module solidTriangle(inset=0, cRad=0){
  dim = 145;
  dimY=129;
  offset(cRad)polygon([
    [0+inset+cRad,0+inset+cRad],
    [dim/2, dimY-inset-2*cRad],
    [dim-inset-2*cRad, 0+inset+cRad],
  ]);
}

// a hollow 2D triangle with rounded corners
module triangleProfile1(cRad=0){
  difference(){
    solidTriangle(0, cRad);
    translate([0, -triEdgeWidth*0.4])solidTriangle(inset=triEdgeWidth, cRad);
  }
}

// 2D representation of our upright:
// 2 full triangles, and 2 diagonal pillars, overlapping
// TODO: the spacing should be computed based on the triangle size.
module triangleProfile(){
  triangleProfile1(2);
  translate([54, 0])triangleProfile1(2);

  intersection(){
    translate([-54, 0])triangleProfile1(2);
    solidTriangle();
  }

  intersection(){
    translate([108, 0])triangleProfile1(2);
    translate([53, 0])solidTriangle();
  }
}

// 3D upright: extruded and rounded over
module triangleUnit(){
  translate([0.3, 3, 0])rotate([90, 0, 0]){
    intersection(){
      // slice the bottom tips of the triangles off.
      // TODO: the spacing should be computed based on the triangle size.
      translate([2, 0, 0])cube([195, 150, 12]);
      minkowski() {
        linear_extrude(3)triangleProfile();
        sphere(d=2);
      }
    }
  }
}

// an upright and a sequence bases and uprights.
module all(){
  translate([0, 0.8, 0])triangleUnit();
  for(i=[1:repeats]){
    translate([0,(i-1)*baseUnitY,0])baseUnit();
    translate([0, (i*baseUnitY)-3, 0])triangleUnit();
  }
}

all();

```
CuttingBoardRack.scad:
```
// https://www.thingiverse.com/thing:5841386 2/07/2023
// by David Phillip Oster
// remix of Cutting board Rack x3 by Matearoa on Thingiverse: https://www.thingiverse.com/thing:4890276
// x4 https://www.thingiverse.com/thing:4676762

// width of base slat height is twice that.
baseDim=20;

// length of base slat
baseUnitY = 60;

// number of slots.
repeats = 2;

// thickness (in 2D of the big triangeles)
triEdgeWidth=10;

// Profile of base slat at right edge
module rightEdge(cRad=0){
  offset(cRad)polygon([
    [baseDim-cRad,0+cRad],
    [(baseDim/2)-cRad,(baseDim/2)-cRad],
    [0+cRad,(baseDim/2)-cRad],
    [0+cRad,0+cRad],
  ]);
}

// Profile of base slat at left edge
module leftEdge(cRad=0){
  mirror([1, 0])rightEdge(cRad);
}

// Profile of base slat that isn't an edge
module middleRidge(cRad=0){
  offset(cRad)polygon([
    [-baseDim/2+cRad,0+cRad],
    [baseDim/2-cRad,0+cRad],
    [(baseDim/4)-cRad,(baseDim/2)-cRad],
    [(-baseDim/4)+cRad,(baseDim/2)-cRad],
  ]);
}

// Profile of base
// TODO: the spacing should be computed based on the triangle size.
module baseProfile(cRad=0){
  translate([-0.5,0])rightEdge(cRad);
  translate([72,0])middleRidge(cRad);
  translate([127,0])middleRidge(cRad);
  translate([200,0])leftEdge(cRad);
}

// A base - between two uprights.
module baseUnit(){
  translate([0,baseUnitY,0])rotate([90, 0, 0])linear_extrude(baseUnitY){
    baseProfile(2);
  }
}

// A 2D triangle.
// inset - make it smaller. inset = 10, is 10mm smaller
// cRad - radius of curvature of the corners.
module solidTriangle(inset=0, cRad=0){
  dim = 145;
  dimY=129;
  offset(cRad)polygon([
    [0+inset+cRad,0+inset+cRad],
    [dim/2, dimY-inset-2*cRad],
    [dim-inset-2*cRad, 0+inset+cRad],
  ]);
}

// a hollow 2D triangle with rounded corners
module triangleProfile1(cRad=0){
  difference(){
    solidTriangle(0, cRad);
    translate([0, -triEdgeWidth*0.4])solidTriangle(inset=triEdgeWidth, cRad);
  }
}

// 2D representation of our upright:
// 2 full triangles, and 2 diagonal pillars, overlapping
// TODO: the spacing should be computed based on the triangle size.
module triangleProfile(){
  triangleProfile1(2);
  translate([54, 0])triangleProfile1(2);

  intersection(){
    translate([-54, 0])triangleProfile1(2);
    solidTriangle();
  }

  intersection(){
    translate([108, 0])triangleProfile1(2);
    translate([53, 0])solidTriangle();
  }
}

// 3D upright: extruded and rounded over
module triangleUnit(){
  translate([0.3, 3, 0])rotate([90, 0, 0]){
    intersection(){
      // slice the bottom tips of the triangles off.
      // TODO: the spacing should be computed based on the triangle size.
      translate([2, 0, 0])cube([195, 150, 12]);
      minkowski() {
        linear_extrude(3)triangleProfile();
        sphere(d=2);
      }
    }
  }
}

// an upright and a sequence bases and uprights.
module all(){
  translate([0, 0.8, 0])triangleUnit();
  for(i=[1:repeats]){
    translate([0,(i-1)*baseUnitY,0])baseUnit();
    translate([0, (i*baseUnitY)-3, 0])triangleUnit();
  }
}

all();

```


[User]
I'd like to design a parametric PCB foot in OpenSCAD. It should consist of a base cylinder, a central shaft that extends up from the base, and a retaining flange at the top of the shaft to hold the PCB. I need to be able to define all the dimensions through variables.

Specifically, I need:

*   **Base Dimensions:**
    *   `base_height`: The height of the base cylinder.
    *   `base_diam`: The diameter of the base cylinder.
*   **Hole and Retainer Dimensions:**
    *   `hole_diameter`: The diameter of the central shaft.
    *   `hole_height`: The height of the central shaft. This corresponds to the PCB thickness (or rather how much the shaft should protrude above the base before the flange begins)
    *   `flange`: The extra radius of the flange compared to the shaft (so, the overall diameter of the flange will be `hole_diameter + 2 * flange`).
    *   `flange_height`: The vertical thickness of the retaining flange.
    *   `split`: The thickness of the split or gap to allow the pcb to slide into place.
*   **Circle divisions:**
    *   `$fn`: Number of slices for circles.

The base cylinder should be a standard cylinder with the `base_height` and `base_diam`. The central shaft is also a cylinder, using `hole_diameter` and extending from the top of the base up by `hole_height`.

The flange should be a short cylinder which sits at the very top of the shaft, but it should not be a full circle. Instead, the flange should have a gap in it to allow a PCB to be inserted. This split is defined by the `split` parameter; the flange should be sliced all the way across using a cube whose width is equal to `split`, is centered on the z-axis, and is longer than the overall radius of the flange. The overall diameter of the flange needs to take `hole_diameter` and add twice `flange`, with a vertical height defined by the `flange_height`.

I don't need any fancy libraries or anything. Everything should be achievable with just basic OpenSCAD primitives. Could you generate this for me?

[Assistant]
pcb_feet.scad:
```
/** Circuit board feet - scruss, 2021-03 */
/* [Base Dimensions] */
// Base height in mm
base_height=5;
// Base diameter in mm
base_diam=12;

/* [Hole and retainer dimensions] */
// Hole Diameter
hole_diameter=2.8;
// PCB board thickness
hole_height=3;
// Extra retainer thickness at board
flange=0.7;
// Retainer height
flange_height=6;
// Retainer split thickness
split=0.6;

/* [Circle divisions] */
// Number of slices for circle
$fn=64;

difference() {
    union() {
        cylinder(d=base_diam,h=base_height);// This is the base
        cylinder(d=hole_diameter,h=base_height + hole_height);  // Shaft up to flange
        translate([0,0,base_height + hole_height])
        intersection() {
            cylinder(d1=hole_diameter+flange,d2=2,h=flange_height);
            cube([hole_diameter,hole_diameter+flange,flange_height*2], center=true);
        }
    }
    translate([0,0,base_height+(hole_height + flange_height)])
    cube([base_diam+2,split,flange_height*2+hole_height*2/3], center=true);
}
```


[User] I'm looking to create some customizable PCB feet using OpenSCAD. I'd like to be able to adjust several parameters, including the height and diameter of the vertical standoff, the screw hole diameter in the standoff, the length and height of the leg extending from the standoff, the diameter of the leg around the screw hole, and the screw hole diameter in the leg. It would be great if the design used a polyhedron for the leg shape itself, as this seems like it would be the most straightforward way to define the overall shape, and have cylinders for the vertical stand-off and the raised cylindrical part of the leg. I would prefer a single .scad file for the entire design, and don't need any library dependencies.  Can you help me generate this?

[Assistant]
pcb_screw_feet.scad:
```
/** PCB Feet **/
/* [Vertical standoff dimensions] */
// Height of vertical standoff
vert_height=14;
// Diameter of vertical standoff
vert_diam=6;
// Diameter of screw hole in vertical standoff
vert_hole=2;

/* [Leg dimensions] */
// Screw hole Diameter
leg_hole=4;
// Diameter around screw hole
leg_diam=9;
// Length of the leg
leg_len=23;
// Height of the leg
leg_height=4;

/* [Circle divisions] */
// Number of slices for circle
slices=64;

$fn=slices;

difference() {
    CubePoints = [
      [  0,  -vert_diam/2,  0 ],  //0
      [ leg_len,  -leg_diam/2,  0 ],  //1
      [ leg_len,  leg_diam/2,  0 ],  //2
      [  0,  vert_diam/2,  0 ],  //3
      [  0,  -vert_diam/2,  leg_height ],  //4
      [ leg_len,  -leg_diam/2,  leg_height ],  //5
      [ leg_len,  leg_diam/2,  leg_height ],  //6
      [  0,  vert_diam/2,  leg_height  ]]; //7

    CubeFaces = [
      [0,1,2,3],  // bottom
      [4,5,1,0],  // front
      [7,6,5,4],  // top
      [5,6,2,1],  // right
      [6,7,3,2],  // back
      [7,4,0,3]]; // left

    union() {
        // Vertical standoff
        cylinder(d=vert_diam, h=vert_height);
        // Leg
        polyhedron(CubePoints, CubeFaces);
        translate([leg_len,0,0])
        cylinder(d=leg_diam, h=leg_height);
    }
    // Minus: screw-hole for stand-off
        translate([0,0,-1])
    cylinder(d=vert_hole, h=vert_height+2);
        translate([leg_len,0,-1])
        cylinder(d=leg_hole, h=leg_height+2);
}
```


[User]
Hey, I need an OpenSCAD design for a parametric fan grill. I've got some ideas about how I want it to work, and I think I've got all the variables I'll need, but I'm pretty new to this, so I'd like you to generate the SCAD file(s) for me, if that's alright?

Basically, I want to design a square fan grill, with a circular opening in the middle for the fan itself. I need to control the size of the square sides, the overall thickness, and the diameter of that central fan opening. I also want to be able to specify the number of blades that make up the grill, their width, and the angle they're at. It'd be great if I could also choose between a few different grill patterns like "grid", "radial", "globe", and "lines". I also want the ability to inset the grill on one side to make sure the fan doesn't scrape, so an inset variable would be ideal.

Oh, and I'd also like to have four screw holes, one at each corner. These need their own diameter and spacing variables as well.

I don't think I need any external libraries for this.

So, to recap, here's what I want to be able to control:

*   **Overall Size:** The length of the sides of the square fan grill.
*   **Thickness:** The total thickness of the grill.
*   **Fan Diameter:** The diameter of the central circular opening.
*   **Grill Blades:** The number of blades in the grill (0 for no grill).
*  **Grill Pattern**: The pattern of the grill, options being "grid", "radial", "globe", "lines".
*   **Grill Width:** The width of the grill blades.
*   **Grill Inset:** The amount the grill is inset on one side.
*   **Grill Angle:** The angle of the grill blades.
*   **Screw Hole Spacing:** The distance between the screw holes.
*  **Screw Hole Diameter:** The diameter of the screw holes.

Could you generate the OpenSCAD file(s) for me with these parameters?

[Assistant]
fan-grill.scad:
```
/*[body]*/
//size of the sides of teh fan
size=120.0;
//thickness of fan grill
height=10.0;
//diameter of fan opening
fanDiameter=100.0;
/*[grill]*/
//number of blades in grill (0 for no grill)
grillBlades=4;//[0:1:16]
//pattern of grill
grillPattern="lines"; //["grid", "radial", "globe", "lines"]
//width of grill blades
grillWidth=4.0; //[0.1:0.1:10]
//amount grill is inset on one side (reduce probability of fan scraping)
grillInset=1.0; //[::]
//angle of grillblades (dependent on pattern, not always used)
grillAngle=0; //[-90:5:90]
/*[screws]*/
//distance between screw holes (keep under size).
screwWidth=100.0;
//diameter of the fan screws
screwDiameter=5.0;

fangrill(s=size,h=height,fd=fanDiameter,p=grillPattern,g=grillBlades,gw=grillWidth,gi=grillInset,ga=grillAngle,sw=screwWidth,sd=screwDiameter);

module fangrill(s=120, h=10, fd=100, p="lines", g=4, gw=4, gi=0, ga=0, sw=110, sd = 5) {
    //s = size of sides of fan
    //h = height
    //fd = diameter of fan.
    //p = pattern of grill blades from ["grid", "radial", "globe", "lines"]
    //g = amount of grill blades
    //gw = width of grill blades
    //ga = angle of grill blades
    //sw = diameter between fan screws.
    //sd = screw diameter.

    difference() {
        union() {
            cube([s, s, h], center = true);
        }
        //screw holes
        translate([sw/2, sw/2, 0]) {
            cylinder(r=sd/2, h=h*2, center=true);
        }
        translate([-sw/2, sw/2, 0]) {
            cylinder(r=sd/2, h=h*2, center=true);
        }
        translate([sw/2, -sw/2, 0]) {
            cylinder(r=sd/2, h=h*2, center=true);
        }
        translate([-sw/2, -sw/2, 0]) {
            cylinder(r=sd/2, h=h*2, center=true);
        }

        //generate grill part
        difference() {
            cylinder(r=fd/2, h=h*2, center=true);

            if (p == "globe") {
                rotate([0, 0, ga]) {
                    for (i=[0:g]) {
                        translate([0, fd/2, 0]) {
                            rotate([0, 0, i*360/g]) {
                                cube([fd*2, gw, h*2], center = true);
                            }
                        }
                        //other corner
                        translate([0, -fd/2, 0]) {
                            rotate([0, 0, i*360/g]) {
                                cube([fd*2, gw, h*2], center = true);
                            }
                        }
                        //other corner
                        translate([fd/2, 0, 0]) {
                            rotate([0, 0, i*360/g]) {
                                cube([fd*2, gw, h*2], center = true);
                            }
                        }
                        //other corner
                        translate([-fd/2, 0, 0]) {
                            rotate([0, 0, i*360/g]) {
                                cube([fd*2, gw, h*2], center = true);
                            }
                        }
                    }
                }
            }

            if (p == "radial") {
                for (i=[0:g]) {
                    rotate([ga, 0, i*360/g]) {
                        translate([fd/4, 0 , 0]) {
                            cube([fd/2 * 1.1, gw, h*2], center = true);
                        }
                    }
                }

            }

            if (p == "grid") {
                for (i=[0:g+1]) {
                    rotate([0, 0, ga]) {
                        translate([0, i*fd/(g+1) - fd/2, 0]) {
                            cube([fd, gw, h*2], center = true);
                        }
                    }
                    rotate([0, 0, ga+90]) {
                        translate([0, i*fd/(g+1) - fd/2, 0]) {
                            cube([fd, gw, h*2], center = true);
                        }
                    }
                }
            }

            if (p == "lines") {
                for (i=[0:g+1]) {
                    rotate([0, 0, 0]) {
                        translate([0, i*fd/(g+1) - fd/2, 0]) {
                            rotate([ga, 0, 0]) {
                                cube([fd, gw, fd], center = true);
                            }
                        }
                    }
                }
            }

        }
        //remove the inset on grill from one side
        translate([0, 0, h*1.5-gi]) {
            cylinder(r=fd/2, h=h*2, center=true);
        }
    }

}

```


[User]
I'd like to create a parametric OpenSCAD model for metric bolts, similar to the one I saw on Thingiverse. I need it to handle a range of bolt sizes from M4 to M100, and it should let me choose between a standard hex head, a hex socket cap, and a flat socket cap.

The key parameters I need to control are:

*   **Bolt Type:**  Hex head, hex socket cap, or flat socket cap.
*   **Bolt Size (M):** The standard metric size (e.g., M4, M10, M20).
*   **Bolt Length:**  The total length of the bolt.
*   **Thread Length:** The length of the threaded portion of the bolt, which should always be less than or equal to the overall length.
*   **Thread Pitch:** The pitch of the threads, with an option for automatic based on the bolt size.
*   **Polygon Count:**  The number of polygons to use for circles and cylinders (this affects smoothness), and a variable to display it more coarsely for better performance when previewing.
*   **Visualization Mode:**  An option to toggle a more coarse representation for visualization (e.g., previewing the part).

The model should be fully parametric, with automatic default lengths and thread pitches based on standard metric dimensions if I don't specify them explicitly. I want it to use the standard metric dimensions for bolt head sizes (across the flats for hex heads and the diameter for socket heads) and head height. It should include a shank portion, which is unthreaded, just before the bolt head.

Can you generate an OpenSCAD file (or multiple files if needed) to accomplish this?

[Assistant]
Bolt.scad:
```
//Type 0=none, 1=Hex, 2=Hex_Socket, 3=Flat_Socket
Type=1; //[0,1,2,3]
//Size
M=10; //[5,6,8,10,12,14,16,18,20,22,24,27,30,33,36,39,42,45,48,52,56,60,64,68,72,76,80,90,100]
//Length bolt  (0 - auto)
Length=0; //[0:5:240]
//Screw length (Length-Grip)
b=100; //[0:5:230]
//Thred Pitch  (0 - auto)
Pitch=0; //[0,1,1.25,1.5,1.75,2,2.5,3,3.5,4,4.5,5,5.5,6]

//Polygons (24 coarse .. 120 very fine)
fn=24; //[24:24:120]
vm=false; //[true, false]
/* [Hidden] */
//************//
Profile="for 3D Print"; //["True Metric","for 3D Print"]

// M,    P,     SxM,    K
//=========================
// M4    .7     7x3.2   2.8
//M4.5   .75
// M5    .8     8x4     3.5
// M6    1      10x5    4
// M7    1              4.8
// M8    1.25   13x6.5  5.3
// M9    1.25
//M10    1.5    17x8    6.4
//M12    1.75   19x10   7.5
//M14    2      22x11   8.8
//M16    2      24x13   10
//M18    2.5    27x15   11.5
//M20	2,5     30x16   12.5
//M22	2,5     32x18   14
//M24	3       36x19   15
//M27	3       41x22   17
//M30	3,5     46x24   18.5
//M33	3,5     50x26   21
//M36	4       55x29   22.5
//M39	4       60x31   25
//M42	4,5     65x34   26
//M45	4,5     70x36   28
//M48	5       75x38   30
//M52	5       80x42   33
//M56	5,5     85x45   35
//M60   5,5     90x48   38
//M64   6       95x51   40
//M68   6       100x54  42
//M72   6       105x58  45
//M76   6       110x61  48
//M80   6       115x64  50
//M90   6       130x72  56
//M100  6       145x80  62
$fn=fn;
D=M;
L=(Length==0 && D<10)?8:
  (Length==0 && D>=10  && D<=12)?10:
  (Length==0 && D>=14  && D<=18)?20:
  (Length==0 && D>=20 && D<=30)?40:
  (Length==0 && D>=33 && D<=42)?60:
  (Length==0 && D>=45 && D<=60)?80:
  (Length==0 && D>=64 && D<=76)?100:
  (Length==0 && D>=68 && D<=76)?120:
  (Length==0 && D>=80 && D<=90)?140:
  (Length==0 && D>90)?150:Length;
B=min(b,L);
G=min(max(L-b,M/20,.6),L/2);
P=(Pitch==0 && D==5)?.8:
  (Pitch==0 && D==6)?1:
  (Pitch==0 && D>=8  && D<=10)?1.5:
  (Pitch==0 && D==12)?1.75:
  (Pitch==0 && D>=14 && D<=16)?2:
  (Pitch==0 && D>=18 && D<=22)?2.5:
  (Pitch==0 && D>=24 && D<=27)?3:
  (Pitch==0 && D>=30 && D<=33)?3.5:
  (Pitch==0 && D>=36 && D<=39)?4:
  (Pitch==0 && D>=42 && D<=45)?4.5:
  (Pitch==0 && D>=48 && D<=52)?5:
  (Pitch==0 && D>=56 && D<=60)?5.5:
  (Pitch==0 && D>=64)?6:Pitch;
s=(D==5)?8:   (D==6)?10:  (D==8)?13:  (D==10)?17:
  (D==12)?19: (D==14)?22: (D==16)?24: (D==18)?27:
  (D==20)?30: (D==22)?32: (D==24)?36: (D==27)?41:
  (D==30)?46: (D==33)?50: (D==36)?55: (D==39)?60:
  (D==42)?65: (D==45)?70: (D==48)?75: (D==52)?80:
  (D==56)?85: (D==60)?90: (D==64)?95: (D==68)?100:
  (D==72)?105:(D==76)?110:(D==80)?115:(D==90)?130:
  (D>=100)?145:0;
 sk=(D==5)?4:(D==6)?5:(D==8)?6:(D==10)?8: (D==12)?10: (D==14)?12:
 (D>=16 && D<=18)?14: (D>=20 && D<=22)?17:
 (D>=24 && D<=27)?19: (D==30)?22:
 (D==33)?24: (D<=36 && D<=39)?27:
 (D>=42)?round(D*.78):0;
 Dk=(D==5)?8.5:(D==6)?10:(D==8)?13:(D==10)?16: (D==12)?17:
 (D>=14 && D<=24)?D*1.5:
 (D==27)?40: (D==30)?45: (D==33)?50:
 (D==36)?54: (D==39)?58: (D>=42)?D*1.5:0;
T=Type;
k=(T!=2 && D==5)?3.5:  (T!=2 && D==6)?4:   (T!=2 && D==8)?5.3: (T!=2 && D==10)?6.4:
  (T!=2 && D==12)?7.5: (T!=2 && D==14)?8.8:(T!=2 && D==16)?10: (T!=2 && D==18)?11.5:
  (T!=2 && D==20)?12.5:(T!=2 && D==22)?14: (T!=2 && D==24)?15: (T!=2 && D==27)?17:
  (T!=2 && D==30)?18.5:(T!=2 && D==33)?21: (T!=2 && D==36)?22.5:(T!=2 && D==39)?25:
  (T!=2 && D==42)?26:  (T!=2 && D==45)?28: (T!=2 && D==48)?30:  (T!=2 && D==52)?33:
  (T!=2 && D==56)?35:  (T!=2 && D==60)?38: (T!=2 && D==64)?40:  (T!=2 && D==68)?42:
  (T!=2 && D==72)?45:  (T!=2 && D==76)?48: (T!=2 && D==80)?50:  (T!=2 && D==90)?56:
  (T!=2 && D==100)?62:D;

R=D/2;
a=1;
Mr1=R;
Mr3=R-P*.866;
dZ=(vm==false)?-P*.2:0;
dp=P*.1;
dP=P*.8;

// bolt
difference(){
union(){
translate([0,0,k+L-B])Thread();
translate([0,0,k])Shank();
if (T==1) HCap();
if (T==2) SCap();
if (T==3) FCap();
}
#
if(vm)for(j=[1:2:12])rotate([0,0,j*30])translate([(j==13)?R*.5:0,0,0])
hull()for(i=[0,1])
translate([.8+i*s*.5,0,1.8])
cylinder(h=k+L,d=.15,$fn=6);
}

//cylinder(h=P*.3333, d1=Md3, d2=Md1,$fn=$fn);
//translate([0,0,P*.3333])cylinder(h=P*.6667, d1=Md1, d2=Md3);
module Thread(){
ppp=[
  [Mr3,0,0],
  [Mr1,0,P/2+dZ],
  [Mr3,0,P],
  [.01*round(100.091*Mr3*cos(366/fn)),.01*round(100.07*Mr3*sin(360/$fn)),P/fn],
  [.01*round(100.091*Mr1*cos(366/fn)),.01*round(100.07*Mr1*sin(360/$fn)),P/2+dZ+P/fn],
  [.01*round(100.091*Mr3*cos(366/fn)),.01*round(100.07*Mr3*sin(360/$fn)),P+P/fn]
  ];
intersection(){
 union(){
  translate([0,0,-P/2])cylinder(B+P,r=Mr3+dp);
  for(i=[-fn:fn*(ceil(B/P)+1)])translate([0,0,i*P/$fn])rotate([0,0,i*360/$fn])
  polyhedron(ppp,[
   [2,1,0],
   [2,0,3],[2,3,5],
   [1,2,5],[1,5,4],
   [0,1,4],[0,4,3],
   [3,4,5]
   ]);
 }
 union(){
   cylinder(P/2+dZ,r1=Mr3,r2=R*.98);
   translate([0,0,P/2+dZ])cylinder(B-P,d=D*.98);
   translate([0,0,B-P/2+dZ])cylinder(P-dZ,r1=R*.98,r2=Mr3);
 }
}
}

module Shank(){
cylinder(.6,d1=D,d2=D-1.2,$fn=fn*2);
cylinder(L-B-Mr1+Mr3,r=R-.6);
translate([0,0,L-B-Mr1+Mr3])cylinder(Mr1-Mr3,r1=R-.6,r2=Mr3);
}

module FCap(){
// Flat_Cap
 difference(){
 intersection(){
  cylinder(h=k,d1=D+2*k,d2=D,$fn=fn*2);
  cylinder(h=k,d1=D+2*k-P/2,d2=1.5*D+3*k-P,$fn=fn*2);
 }
 translate([0,0,-.1]){
 intersection(){
 cylinder(h=.1+k,d=(sk+.2)*1.154667,$fn=6);
 cylinder(h=.1+k,d=(sk+.2)*1.154667-.2);
 cylinder(h=.1+k*.9,d1=.4+k*3.6,d2=0);
 }
 cylinder(h=.1+k,d1=(sk+.2)*1.154667,d2=0,$fn=fn*2);
  }}
}
module SCap(){
//if (Type=="Socket_Cap") {
 difference(){
 intersection(){
  cylinder(h=k,d=Dk,$fn=fn*2);
  cylinder(h=k,d1=Dk-P/2,d2=1.5*Dk-P,$fn=fn*2);
 }
 translate([0,0,-.1]){
 intersection(){
 cylinder(h=.1+k,d=(sk+.2)*1.154667,$fn=6);
 cylinder(h=.1+k,d=(sk+.2)*1.154667-.2);
 cylinder(h=.1+k*.9,d1=.4+k*3.6,d2=0);
 }
 cylinder(h=.1+k,d1=(sk+.2)*1.154667,d2=0,$fn=fn*2);
  }}
}
//} else {
module HCap(){
//if (Type=="Hex_Cap") {
union(){
 intersection(){
  cylinder(h=k-P/2,d=s*1.154667,$fn=6);  //head
  cylinder(h=k,d1=s,d2=2*s);
 }
 translate([0,0,k-P/2])cylinder(h=P/2,d=s);
}}

//cylinder(h=L-G,d=D-P*.08888);  //cylinder for screw
//if(Profile=="for 3D Print")  //screw profile
//{polygon( points=[[D,P],[R,P],[R,P+dZ],[R-P*.7,P/2],[R,+dZ],[R,+dZ],[D,+dZ]]);}
//else {polygon( points=[[D,P],[R,P],[R-P*.7,P/2],[R,0.0],[D,0]]);}

```


[User]
I'd like a parametric OpenSCAD design for a Nintendo Switch game case holder. It should be a simple box with slots for the game cases.

Specifically:

*   I need to be able to specify the number of game slots.
*   The design should have walls, a base, and slots for the game cases to sit in.
*   I need to be able to control the wall thickness.
*   There should be a base that the game cases sit on.
*   I need to be able to specify the height of the holder.
*   I need to be able to specify the width of the holder, which should be consistent across all slots.
*   The game slots should be consistently spaced within the holder.
*   I need to be able to control the height of the base.

Could you generate the OpenSCAD code for me? I'd prefer it to be as simple as possible, using only built-in OpenSCAD modules and functions if possible. I don't need any fancy libraries for this.

[Assistant]
switch.scad:
```
nozzle = 0.4;
walls = 2;
games = 10;

wallw = nozzle * walls;
base = 1;
game = 12.4;
height = 65;
width=171;

difference() {
    cube([width + 2*wallw, wallw + (game + wallw)*games, height]);

for (i = [0:(games-1)]) {
    translate([wallw, wallw + (game+wallw)*i, base]) cube([width, game, height]);
}
}

```