[User]
Hey, I'm looking for help designing a keychain in OpenSCAD, and it's kind of complex. It's based on those old motel keychains, and I want to make it parametric so I can easily change its size and other features.

The basic shape is a rounded rectangle, made from a hull of four ellipses. Two ellipses are oriented horizontally and two vertically. The horizontal ones are placed at the top and bottom, and the vertical ones are on the left and right. I need to control the size and shape of these ellipses with parameters. I also need to be able to control the overall height and width.

On the front of the keychain, I want to add text in a white color, along with a few small circles next to each line of text. The text is stacked vertically; it's meant to say "THEY", "MIGHT BE", "GIANTS", "INSTANT", and "FAN CLUB", one line below the other. The text and circles are extruded slightly and offset in the Z direction to sit on top of the base shape. Each line of text should have a different spacing between letters, so I need control over that too.

Below the text, there's a rectangular groove that should run most of the length of the keychain, also with parametric dimensions. Above and below the text and that rectangle, I need horizontal lines that go all the way across the keychain, spaced evenly, and also fully parametric.

The text, circles, groove, and lines should all be "carved into" the main shape; I'd like to see that as a second color when previewed, but actually this will all be a single piece and needs to work that way when rendered as STL. I'd like a parameter to control the thickness of the text, and another to control the offset of the text from the main body.

I need to use the `hershey.scad` library to render the text. I've got a copy of that, but it is an external file. I think you'll be able to handle it with use <hershey.scad>.
Also, I’d like the circles next to the text lines to have $fn=8, as well as parametric size.
Could you help me build this with OpenSCAD? I'd like the result to be a parametric set of OpenSCAD files, not just a single, hard-coded one.

[Assistant]
hotel.scad:
```
use <hershey.scad>

$fn = 32;
module ellipse(x,y) {
    m = max(x,y);
    scale([x/m, y/m]) circle(m);
}

module main() {
    difference() {
        hull() {
            translate([0,h/2]) ellipse(e1x, e1y);
            translate([0,-h/2]) ellipse(e1x, e1y);
            translate([w/2,0]) ellipse(e2x, e2y);
            translate([-w/2,0]) ellipse(e2x, e2y);
        }
        translate([0,h/2]) circle(4);
    }
}

h = 77;
w = 33;
e1x = 12;
e1y = 8;
e2x = 8;
e2y = 12;
ht=3;
ofs=.7;
module color1() {
    color([.2,.2,.2])
    linear_extrude(height=ht)
    main();
}

module color2() {
    color("white")
    translate([0,0,ofs]) linear_extrude(height=ht)
    {
        translate([0,16,0]) drawHersheyText("THEY", font="rowmans", halign="center", size=4, extraSpacing=3)
        circle(.41, $fn=8);
        translate([0, 8,0]) drawHersheyText("MIGHT BE", font="rowmans", halign="center", size=4, extraSpacing=1)
        circle(.41, $fn=8);
        translate([0,0,0]) drawHersheyText("GIANTS", font="rowmans", halign="center", size=4, extraSpacing=2)
        circle(.41, $fn=8);
        translate([0,-16,0]) drawHersheyText("INSTANT", font="rowmans", halign="center", size=3, extraSpacing=1)
        circle(.41, $fn=8);
        translate([0,-24,0]) drawHersheyText("FAN CLUB", font="rowmans", halign="center", size=3, extraSpacing=.5)
        circle(.41, $fn=8);

        translate([0,-6])
        square([24, 1], center=true);

        intersection() {
            union() {
                for(yy = [42, 39, 36, 33]) {
                    translate([0,yy])
                    square([55, 1], center=true);
                    translate([0,-yy])
                    square([55, 1], center=true);
                }
            }
            offset(r=-.1) main();
            hull() offset(r=-1.5) main();
        }
        difference() {
            hull() offset(r=-1.5) main();
            hull() offset(r=-2.1) main();
        }
    }
}

mode = "preview";
if(mode == "preview") {
    color1();
    color2();
} else if(mode == "color1") {
    color1();
} else if(mode == "color2") {
    difference() { color2(); color1(); }
}

```


[User]
Hi, I'm looking for an OpenSCAD design for a compound planetary gearbox, and I have some pretty specific requirements. I'd like it to be parametric so I can easily adjust the gear ratios and dimensions. Here’s what I’m after:

**Core Functionality:**

*   **Two-Stage Planetary System:** The gearbox should have two planetary gear stages, each with a sun gear, planet gears, and a ring gear. I want to be able to select whether I want two or three layers by adjusting an optional `modules` parameter.
*   **Fused Sun Gears:** The sun gears of both stages should be fused into a single piece. This is crucial for strength and efficient power transfer, as well as easier post-printing processing. The fusion must maintain a 1:1 relationship between the two stages, so the sun gears must rotate in unison.
*   **Variable Gear Ratios:** I need to be able to control the gear ratios by specifying the number of teeth for the planet gears (`planet_t` and `planet_t2`), and ring gears (`ring_t1` and `ring_t2`). The sun gear tooth count should be a multiple of the planet gear count (e.g., `drive_t = planet_t * sgm`).
*   **Flexible Ring Gear Teeth:** The design shouldn’t be strictly constrained to the R=S+2P teeth relationship.  I need to be able to drop teeth and stretch the ring gear to accommodate different combinations of gears. There is a warning that gets displayed if this condition is not met.

**Parametric Design:**

I'd like to be able to adjust these parameters:

*   `modules`: The number of gear layers, set to `2` or `3`. Default to 2.
*   `gear_h`: Height of the planetary layers (first stage).
*   `gear_h2`: Height of the planetary layers (second stage).
*   `cp`: Circular pitch.
*   `planet_t`: Number of teeth in the first stage planet gears.
*   `planet_t2`: Number of teeth in the second stage planet gears.
*   `ring_t1`: Number of teeth in the first stage ring gear.
*   `ring_t2`: Number of teeth in the second stage ring gear.
*   `sgm`: Sun gear multiplier (the number of multiples of planet gears).
*    `shaft_d`: Shaft diameter for the sun and planet gears.
*   `shafts`: Number of support shafts for larger sun gears.
*   `outer_d`: Outer diameter of the ring gears.
*   `outer_t`: Number of teeth/notches on the outside of the ring gear.
*   `outer_w`: Width of the outer teeth/notches.
*   `wall`: Wall thickness.
*   `slot_w`: Slot width for additional features.
*   `slot_l`: Slot length for additional features.
*   `planets`: Number of planet gears in each stage.
*   `nTwist`: Number of teeth to twist across for herringbone gears.
*   `depth_ratio`: Gear depth ratio.
*   `tol`: Gear clearance.
*   `P`: Pressure angle (in degrees).
*   `$fa`, `$fs`: Curve resolution settings, minimum angle and minimum size respectively.
*   `layer_h`: Layer height for horizontal split of the ring gear.
*   `AT`, `ST`, `TT`: Tolerances for geometry connections.

**Specific Design Features:**

*   **Herringbone Gears:** The gears should have a herringbone design for smoother and quieter operation.
*   **Print-in-Place:** The entire gearbox should be designed to be printed in place and fully assembled without requiring any support material (except where absolutely necessary).
*   **Optional Outer Notches:** There should be an option to have notches around the outside of the ring gear (controlled by `outer_t`).
*   **Clearance/Tolerances:** I need the design to include clearances so parts don't fuse together, controlled by the `tol`, `AT`, `ST`, `TT` variables.
*   **Gearcase:** I need the design to use a `gearcase` module for the ring gears.
*   **Drivegear/Planetgear:** I'd also need `drivegear` and `planetgear` modules as well.

**Libraries:**
I'd also like the design to use the functions within the `MCAD/involute_gears.scad` library, where applicable.

I think that covers it. Please let me know if you have any questions or need any clarifications. Thanks!

[Assistant]
Compound10.scad:
```
// OpenSCAD Compound Planetary System
// (c) 2019, tmackay
//
// Licensed under a Creative Commons Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license, http://creativecommons.org/licenses/by-sa/4.0.
//include <MCAD/involute_gears.scad>

// Modules, planetary layers
modules = 2; //[2:1:3]
// Height of planetary layers (drive stage)
gear_h = 7.5;
// Height of planetary layers (output stage)
gear_h2 = 7.5;
// Circular pitch: Length of the arc from one tooth to the next
cp = 245;
// Number of teeth in inner planet gears
planet_t = 13; //[10:1:20]
planet_t2 = 15; //[10:1:20]
// Number of teeth in ring gears
ring_t1 = 38; //[30:1:90]
ring_t2 = 45; //[30:1:90]
// Sun gear multiplier
sgm = 1; //[1:1:5]
// Shaft diameter
shaft_d = 10;
// secondary shafts (for larger sun gears)
shafts = 6;
// Outer diameter
outer_d = 60;
// Outer teeth
outer_t = 0;
// Width of outer teeth
outer_w=3;
// Wall thickness
wall = 0;
// Slot width
slot_w = 0;
// Slot length
slot_l = 0;
// Number of planet gears in inner circle
planets = 3; //[3:1:21]
// number of teeth to twist across
nTwist=1;
// Gear depth ratio
depth_ratio=1;
// Gear clearance
tol=0.2;
// pressure angle
P=45; //[30:60]
// Curve resolution settings, minimum angle
$fa = 5;
// Curve resolution settings, minimum size
$fs = 1;
// Layer height (for ring horizontal split)
layer_h = 0.2;

// For fused sun gears, we require them to be a multiple of the planet teeth
drive_t = planet_t*sgm;
drive_t2 = planet_t2*sgm;

if ((drive_t+ring_t1)%planets)
{
    echo(str("Warning: For even spacing, planets must divide ", drive_t+ring_t1));
}
if ((drive_t2+ring_t2)%planets)
{
    echo(str("Warning: For even spacing (2), planets must divide ", drive_t2+ring_t2));
}

if (drive_t + 2*planet_t != ring_t1) {
    echo(str("Teeth fewer than ideal (ring1): ", drive_t+2*planet_t-ring_t1));
}
if (drive_t2 + 2*planet_t2 != ring_t2) {
    echo(str("Teeth fewer than ideal (ring2): ", drive_t2+2*planet_t2-ring_t2));
}

// Planetary gear ratio for fixed ring: 1:1+R/S
echo(str("Gear ratio of first planetary stage: 1:", 1+ring_t1/drive_t)); // eg. 1:3.1818...

// (Planet/Ring interaction: Nr*wr-Np*wp=(Nr-Np)*wc)
// one revolution of carrier (wc=1) turns planets on their axis
// wp = (Np-Nr)/Np = eg. (10-31)/10=-2.1 turns
// Secondary Planet/Ring interaction
// wr = ((Nr-Np)+Np*wp)/Nr = eg. ((34-11)-11*2.1)/34 = 1/340
// or Nr2/((Nr2-Np2)+Np2*(Np1-Nr1)/Np1)
echo(str("Gear ratio of planet/ring stage: 1:", abs(ring_t2/((ring_t2-planet_t2)+planet_t2*(planet_t-ring_t1)/planet_t)))); // eg. 3.8181..

// Final gear ratio is product of above, eg. 1:1298.18..
echo(str("Input/Output gear ratio: 1:",abs((1+ring_t1/drive_t)*ring_t2/((ring_t2-planet_t2)+planet_t2*(planet_t-ring_t1)/planet_t))));

// what ring should be for teeth to mesh without additional scaling
ring_t1_n = drive_t+2*planet_t;
ring_t2_n = drive_t2+2*planet_t2;

// Coincident planet offsets
cp2=(drive_t+planet_t)*cp/(drive_t2+planet_t2);

// Tolerances for geometry connections.
AT=0.02;
ST=AT*2;
TT=AT/2;

helix_angle=atan(PI*nTwist*cp/90/gear_h);
helix_angle2=atan(PI*nTwist*cp2/90/gear_h);

// center gears
rotate([0,0,180/drive_t*(1-planet_t%2)])
    drivegear(t1=drive_t,bore=shaft_d,rot=180/drive_t*(1-planet_t%2));
translate([0,0,gear_h-TT])intersection(){
    rotate([0,0,180/drive_t2*(1-planet_t2%2)])
        drivegear(t1=drive_t2,bore=shaft_d,cp=cp2,helix_angle=helix_angle2,gear_h=gear_h2,rot=180/drive_t2*(1-planet_t2%2));
    rotate([0,0,180/drive_t*(1-planet_t%2)])
        linear_extrude(height=gear_h2,scale=1+gear_h2/(drive_t*cp/360)*sqrt(3),slices=1)
            gear2D(drive_t,cp*PI/180,P,depth_ratio,tol);
}
if(modules==3)translate([0,0,gear_h+gear_h2-AT])intersection(){
    rotate([0,0,180/drive_t*(1-planet_t%2)])
        drivegear(t1=drive_t,bore=shaft_d,rot=180/drive_t*(1-planet_t%2));
    rotate([0,0,180/drive_t2*(1-planet_t2%2)])
        linear_extrude(height=gear_h,scale=1+gear_h/(drive_t2*cp2/360)*sqrt(3),slices=1)
            gear2D(drive_t2,cp2*PI/180,P,depth_ratio,tol);
}

// planets
planets(t1=planet_t, t2=drive_t,offset=(drive_t+planet_t)*cp/360,n=planets,t=ring_t1+drive_t)
    planetgear(t1 = planet_t, bore=shaft_d);

translate([0,0,gear_h-TT])
    planets(t1=planet_t2, t2=drive_t2,offset=(drive_t2+planet_t2)*cp2/360,n=planets,t=ring_t2+drive_t2)
        intersection(){
            planetgear(t1 = planet_t2, bore=shaft_d,cp=cp2,helix_angle=helix_angle2,gear_h=gear_h2);
            linear_extrude(height=gear_h2,scale=1+gear_h2/(planet_t*cp/360)*sqrt(3),slices=1)
                    gear2D(planet_t,cp*PI/180,P,depth_ratio,tol);
        }
if(modules==3)translate([0,0,gear_h+gear_h2-AT])
    planets(t1=planet_t, t2=drive_t,offset=(drive_t+planet_t)*cp/360,n=planets,t=ring_t1+drive_t)
        intersection(){
            planetgear(t1 = planet_t, bore=shaft_d);
            linear_extrude(height=gear_h,scale=1+gear_h/(planet_t2*cp2/360)*sqrt(3),slices=1)
                    gear2D(planet_t2,cp2*PI/180,P,depth_ratio,tol);
        }

// rings
s1=ring_t1_n/ring_t1;
s2=ring_t2_n/ring_t2;
ha1=atan(PI*nTwist*s1*cp/90/gear_h); // not sure about this, seems close enough.
ha2=atan(PI*nTwist*s2*cp2/90/gear_h);
gearcase(t1=ring_t1,bore=outer_d/2,cp=s1*cp,helix_angle=ha1);
translate([0,0,gear_h-TT])
    difference(){
        gearcase(t1=ring_t2,bore=outer_d/2,cp=s2*cp2,helix_angle=ha2,gear_h=gear_h2);
        linear_extrude(height=(ring_t1*s1*cp/360)/sqrt(3),scale=0,slices=1)
            hull()gear2D(ring_t1,s1*cp*PI/180,P,depth_ratio,-tol);
        translate([-outer_d,-outer_d,-TT])cube([2*outer_d,2*outer_d,layer_h+AT]);
    }
if(modules==3)translate([0,0,gear_h+gear_h2-AT])
    difference(){
        gearcase(t1=ring_t1,bore=outer_d/2,cp=s1*cp,helix_angle=ha1);
        linear_extrude(height=(ring_t2*s2*cp2/360)/sqrt(3),scale=0,slices=1)
            hull()gear2D(ring_t2,s2*cp2*PI/180,P,depth_ratio,-tol);
        translate([-outer_d,-outer_d,-TT])cube([2*outer_d,2*outer_d,layer_h+AT]);
    }

// Drive gear with slot
module drivegear(t1=13,reverse=false,bore=2*cos(P)*13*cp/360-wall,rot=0)
{
    planetgear(t1,!reverse,bore,cp=cp,helix_angle=helix_angle,gear_h=gear_h,rot=rot);
}

// reversible herringbone gear with bore hole
module planetgear(t1=13,reverse=false,bore=0,rot=0)
{
    difference()
    {
        translate([0,0,gear_h/2])
        if (reverse) {
            mirror([0,1,0])
                herringbone(t1,PI*cp/180,P,depth_ratio,tol,helix_angle,gear_h);
        } else {
            herringbone(t1,PI*cp/180,P,depth_ratio,tol,helix_angle,gear_h);
        }

        translate([0,0,-TT]){
            rotate([0,0,-rot])
                cylinder(d=bore, h=2*gear_h+AT);
            // Extra speed holes, for strength
            if(bore>0 && bore/4+(t1-2*tan(P))*cp/720>bore)
                for(i = [0:360/shafts:360-360/shafts])rotate([0,0,i-rot])
                    translate([bore/4+(t1-2*tan(P))*cp/720,0,-AT])
                        cylinder(d=bore,h=2*gear_h+AT);
        }
    }
}

// Space out planet gears approximately equally
module planets()
{
    for(i = [0:n-1])
    rotate([0,0,round(i*t/n)*360/t])
        translate([offset,0,0]) rotate([0,0,round(i*t/n)*360/t*t2/t1])
            children();
}

module gearcase(t1=13,teethtwist=1,bore=18*cp/360)
{
    difference() {
        cylinder(r=bore,h=gear_h);
        translate([0,0,-TT])planetgear(t1=t1,gear_h=gear_h+AT,tol=-tol,helix_angle=helix_angle,cp=cp,depth_ratio=depth_ratio,P=P);
	}
            // outer notches
        if(outer_t>0)for(i = [0:360/outer_t:360-360/outer_t])rotate([0,0,i])
            translate([outer_d/2,0,-AT])rotate([0,0,45])
                cylinder(d=outer_w,h=gear_h+AT,$fn=4);

}

// Herringbone gear code, taken from:
// Planetary gear bearing (customizable)
// https://www.thingiverse.com/thing:138222
// Captive Planetary Gear Set: parametric. by terrym is licensed under the Creative Commons - Attribution - Share Alike license.
module herringbone(
	number_of_teeth=15,
	circular_pitch=10,
	pressure_angle=28,
	depth_ratio=1,
	clearance=0,
	helix_angle=0,
	gear_thickness=5){
union(){
    translate([0,0,-TT])
	gear(number_of_teeth,
		circular_pitch,
		pressure_angle,
		depth_ratio,
		clearance,
		helix_angle,
		gear_thickness/2+TT);
	mirror([0,0,1]) translate([0,0,-TT])
		gear(number_of_teeth,
			circular_pitch,
			pressure_angle,
			depth_ratio,
			clearance,
			helix_angle,
			gear_thickness/2+TT);
}}

module gear (
	number_of_teeth=15,
	circular_pitch=10,
	pressure_angle=28,
	depth_ratio=1,
	clearance=0,
	helix_angle=0,
	gear_thickness=5,
	flat=false){
pitch_radius = number_of_teeth*circular_pitch/(2*PI);
twist=tan(helix_angle)*gear_thickness/pitch_radius*180/PI;

flat_extrude(h=gear_thickness,twist=twist,flat=flat)
	gear2D (
		number_of_teeth,
		circular_pitch,
		pressure_angle,
		depth_ratio,
		clearance);
}

module flat_extrude(h,twist,flat){
	if(flat==false)
		linear_extrude(height=h,twist=twist,slices=6)children(0);
	else
		children(0);
}

module gear2D (
	number_of_teeth,
	circular_pitch,
	pressure_angle,
	depth_ratio,
	clearance){
pitch_radius = number_of_teeth*circular_pitch/(2*PI);
base_radius = pitch_radius*cos(pressure_angle);
depth=circular_pitch/(2*tan(pressure_angle));
outer_radius = clearance<0 ? pitch_radius+depth/2-clearance : pitch_radius+depth/2;
root_radius1 = pitch_radius-depth/2-clearance/2;
root_radius = (clearance<0 && root_radius1<base_radius) ? base_radius : root_radius1;
backlash_angle = clearance/(pitch_radius*cos(pressure_angle)) * 180 / PI;
half_thick_angle = 90/number_of_teeth - backlash_angle/2;
pitch_point = involute (base_radius, involute_intersect_angle (base_radius, pitch_radius));
pitch_angle = atan2 (pitch_point[1], pitch_point[0]);
min_radius = max (base_radius,root_radius);

intersection(){
	rotate(90/number_of_teeth)
		circle($fn=number_of_teeth*3,r=pitch_radius+depth_ratio*circular_pitch/2-clearance/2);
	union(){
		rotate(90/number_of_teeth)
			circle($fn=number_of_teeth*2,r=max(root_radius,pitch_radius-depth_ratio*circular_pitch/2-clearance/2));
		for (i = [1:number_of_teeth])rotate(i*360/number_of_teeth){
			halftooth (
				pitch_angle,
				base_radius,
				min_radius,
				outer_radius,
				half_thick_angle);
			mirror([0,1])halftooth (
				pitch_angle,
				base_radius,
				min_radius,
				outer_radius,
				half_thick_angle);
		}
	}
}}

module halftooth (
	pitch_angle,
	base_radius,
	min_radius,
	outer_radius,
	half_thick_angle){
index=[0,1,2,3,4,5];
start_angle = max(involute_intersect_angle (base_radius, min_radius)-5,0);
stop_angle = involute_intersect_angle (base_radius, outer_radius);
angle=index*(stop_angle-start_angle)/index[len(index)-1];
p=[[0,0], // The more of these the smoother the involute shape of the teeth.
	involute(base_radius,angle[0]+start_angle),
	involute(base_radius,angle[1]+start_angle),
	involute(base_radius,angle[2]+start_angle),
	involute(base_radius,angle[3]+start_angle),
	involute(base_radius,angle[4]+start_angle),
	involute(base_radius,angle[5]+start_angle)];

difference(){
	rotate(-pitch_angle-half_thick_angle)polygon(points=p);
	square(2*outer_radius);
}}

// Mathematical Functions
//===============

// Finds the angle of the involute about the base radius at the given distance (radius) from it's center.
//source: http://www.mathhelpforum.com/math-help/geometry/136011-circle-involute-solving-y-any-given-x.html

function involute_intersect_angle (base_radius, radius) = sqrt (pow (radius/base_radius, 2) - 1) * 180 / PI;

// Calculate the involute position for a given base radius and involute angle.

function involute (base_radius, involute_angle) =
[
	base_radius*(cos (involute_angle) + involute_angle*PI/180*sin (involute_angle)),
	base_radius*(sin (involute_angle) - involute_angle*PI/180*cos (involute_angle))
];
```


[User]
Hi, I'm looking to create some parametric OpenSCAD files for a project I'm working on. It involves creating recesses for magnets in various 3D printed parts. I need a system where I can easily adjust the magnet dimensions and the surrounding padding to control the fit.

Here's what I'm envisioning:

I'll be using 11 different 3D printed parts. Each part will need a magnet recess. The parts, based on the existing STL files, are: `OpenTab1`, `OpenTabBR`, `Front_Spacer2`, `Front_Spacer`, `Front_Spacer_TL`, `Front_Spacer_TR`, `Hinge1`, `HingeBR`, `HingeTL`, `HingeTR`, and `DoorStop`.

For each of these, I need to:

1.  Import the corresponding STL file (e.g., `OpenTab1.stl`, `OpenTabBR.stl`, etc.)
2.  Create a rectangular recess for a magnet. This recess should have adjustable parameters:
    *   `magnet_length`
    *   `magnet_width`
    *   `magnet_depth`
3.  Create a 'padding' around the magnet recess to control the fit. This will be added to the magnet dimensions:
    *   `border_length`
    *   `border_width`
    *   `border_depth`
4. Calculate a `sub_length`, `sub_width` and `sub_depth` to use for the recess which combines magnet size and padding. (`sub_length = magnet_length + 2*border_length`, etc.)
5.  Position this magnet recess at a specific location and orientation in each part. The locations and orientations are described in the existing "magnets.scad" file I have (I can share if needed), and they differ for each part.
6. Perform a `difference()` operation to subtract the recess from the imported STL, creating the magnet hole.

It would be great if the final result was a collection of `.scad` files, one per part name, or a single file with modules for each part.

For example, for the `OpenTab1` module, you'd:

* Import `OpenTab1.stl`,
* Rotate it `[0, 90, 0]`
* Translate it using `[-11.15, 7.5, -10]`
* Translate the magnet recess to `[sub_depth/2, 0, 0]` within the part
* Create the magnet recess using `cube([sub_depth, sub_width, sub_length], center=true)`
* Use a difference to remove the magnet recess from the imported STL

I am using STLs already prepared with no magnet inserts.

I am assuming I will need to add some documentation to the top of each SCAD file for the configurable parameters.

The specific translations and rotations for each part are below, extracted from my existing file:

* `OpenTab1`: rotate `[0, 90, 0]`, translate `[-11.15, 7.5, -10]`, magnet translation `[sub_depth/2, 0, 0]`
* `OpenTabBR`: rotate `[0, -90, 0]`, translate `[11.15, 7.5, 50]`, magnet translation `[-sub_depth/2, 0, 0]`
* `Front_Spacer2`: rotate `[90, 0, 0]`, translate `[19.16, -27, -33]`, magnet translation `[sub_depth/2, 0, sub_width/2]`
* `Front_Spacer`: rotate `[90, 0, 0]`, translate `[19.16, -27, -33]`, magnet translation `[-sub_depth/2, 0, sub_width/2]`
* `Front_Spacer_TL`: rotate `[-90, 0, 0]`, translate `[19.16, 27, 14]`, magnet translation `[-sub_depth/2, 0, -sub_width/2]`
* `Front_Spacer_TR`: rotate `[-90, 0, 0]`, translate `[29.16, 27, 14]`, magnet translation `[sub_depth/2, 0, -sub_width/2]`
* `Hinge1`: rotate `[-90, 0, 0]`, translate `[9.5, 22, 33]`, magnet translation `[sub_depth/2, 0, -sub_width/2]`
* `HingeBR`: rotate `[-90, 0, 0]`, translate `[39.51, 22, 33]`, magnet translation `[-sub_depth/2, 0, -sub_width/2]`
* `HingeTL`: rotate `[-90, 0, 0]`, translate `[9.5, 22, 13]`, magnet translation `[sub_depth/2, 0, -sub_width/2]`
* `HingeTR`: rotate `[-90, 0, 0]`, translate `[39.5, 22, 13]`, magnet translation `[-sub_depth/2, 0, -sub_width/2]`
* `DoorStop`: rotate `[90, 0, 0]`, translate `[20, 0, 7.5]`, magnet translation `[0, sub_depth/2, 0]` (Note this one requires a second identical magnet on the opposite side, same parameters)

I don't think any external libraries are needed.

Could you help me with this?

[Assistant]
magnets.scad:
```
/* [Magnet] */

part = "OpenTab1"; // [OpenTab1, OpenTabBR, Front_Spacer2, Front_Spacer, Front_Spacer_TL, Front_Spacer_TR, Hinge1, HingeBR, HingeTL, HingeTR, DoorStop]

magnet_length=15; // [1:30]
magnet_width=6.5; // [1:10]
magnet_depth=3;   // [1:5]

/* [Padding] */
border_length=0.15;
border_width=0.15;
border_depth=0.15;

/* [Hidden] */
sub_length=magnet_length + (2*border_length);
sub_width=magnet_width + (2*border_width);
sub_depth=magnet_depth + border_depth;

if (part == "OpenTab1") {
  OpenTab1();
} else if (part == "OpenTabBR") {
  OpenTabBR();
} else if (part == "Front_Spacer2") {
  Front_Spacer2();
} else if (part == "Front_Spacer") {
  Front_Spacer();
} else if (part == "Front_Spacer_TL") {
  Front_Spacer_TL();
} else if (part == "Front_Spacer_TR") {
  Front_Spacer_TR();
} else if (part == "Hinge1") {
  Hinge1();
} else if (part == "HingeBR") {
  HingeBR();
} else if (part == "HingeTL") {
  HingeTL();
} else if (part == "HingeTR") {
  HingeTR();
} else if (part == "DoorStop") {
  DoorStop();
}

module OpenTab1() {
  difference() {
    rotate([0, 90, 0])
      import("OpenTab1.stl");
    translate([-11.15, 7.5, -10]) {
      translate([sub_depth/2, 0, 0]) {
        color("lime") cube([sub_depth, sub_width, sub_length], center=true);
      }
    }
  }
}

module OpenTabBR() {
  difference() {
    rotate([0, -90, 0])
      import("OpenTabBR.stl");
    translate([11.15, 7.5, 50]) {
      translate([-sub_depth/2, 0, 0]) {
        color("lime") cube([sub_depth, sub_width, sub_length], center=true);
      }
    }
  }
}

module Front_Spacer2() {
  difference() {
    rotate([90, 0, 0])
      import("Front_Spacer2.stl");
    translate([19.16, -27, -33]) {
      translate([sub_depth/2, 0, sub_width/2]) {
        color("lime") cube([sub_depth, sub_length, sub_width], center=true);
      }
    }
  }
}

module Front_Spacer() {
  difference() {
    rotate([90, 0, 0])
      import("Front_Spacer.stl");
    translate([19.16, -27, -33]) {
      translate([-sub_depth/2, 0, sub_width/2]) {
        color("lime") cube([sub_depth, sub_length, sub_width], center=true);
      }
    }
  }
}

module Front_Spacer_TL() {
  difference() {
    rotate([-90, 0, 0])
      import("Front_Spacer_TL.stl");
    translate([19.16, 27, 14]) {
      translate([-sub_depth/2, 0, -sub_width/2]) {
        color("lime") cube([sub_depth, sub_length, sub_width], center=true);
      }
    }
  }
}

module Front_Spacer_TR() {
  difference() {
    rotate([-90, 0, 0])
      import("Front_Spacer_TR.stl");
    translate([29.16, 27, 14]) {
      translate([sub_depth/2, 0, -sub_width/2]) {
        color("lime") cube([sub_depth, sub_length, sub_width], center=true);
      }
    }
  }
}

module Hinge1() {
  difference() {
    rotate([-90, 0, 0])
      import("Hinge1.stl");
    translate([9.5, 22, 33]) {
      translate([sub_depth/2, 0, -sub_width/2]) {
        color("lime") cube([sub_depth, sub_length, sub_width], center=true);
      }
    }
  }
}

module HingeBR() {
  difference() {
    rotate([-90, 0, 0])
      import("HingeBR.stl");
    translate([39.51, 22, 33]) {
      translate([-sub_depth/2, 0, -sub_width/2]) {
        color("lime") cube([sub_depth, sub_length, sub_width], center=true);
      }
    }
  }
}

module HingeTL() {
  difference() {
    rotate([-90, 0, 0])
      import("HingeTL.stl");
    translate([9.5, 22, 13]) {
      translate([sub_depth/2, 0, -sub_width/2]) {
        color("lime") cube([sub_depth, sub_length, sub_width], center=true);
      }
    }
  }
}

module HingeTR() {
  difference() {
    rotate([-90, 0, 0])
      import("HingeTR.stl");
    translate([39.5, 22, 13]) {
      translate([-sub_depth/2, 0, -sub_width/2]) {
        color("lime") cube([sub_depth, sub_length, sub_width], center=true);
      }
    }
  }
}

module DoorStop() {
  difference() {
    rotate([90, 0, 0])
      import("DoorStop.stl");
    translate([20, 0, 7.5]) {
      translate([0, sub_depth/2, 0]) {
        color("lime") cube([sub_length, sub_depth, sub_width], center=true);
      }
    }
    translate([-20, 0, 7.5]) {
      translate([0, sub_depth/2, 0]) {
        color("lime") cube([sub_length, sub_depth, sub_width], center=true);
      }
    }
  }
}

```


[User]
I'm looking to create a customizable shelving rack, and I've got some specific ideas in mind. I need it to be fully parametric, so I can easily adjust the dimensions to fit different needs.

Here's what I'm thinking:

*   **Basic Structure:** The rack should be made up of a grid of individual box-like compartments, arranged in rows and columns. Think of it like a set of pigeon holes.
*   **Box Dimensions:**
    *   I need to be able to set the width, height, and depth of each individual box compartment.
*   **Grid Dimensions:**
    *   I need to be able to specify the number of rows and columns.
*   **Wall Thickness:**
    *   I'd like to be able to control the wall thickness by setting a multiplier to the nozzle diameter. This makes sense for 3D printing.
    * I need a parameter for the nozzle diameter and wall multiplier.
*   **Corner Radius:**
    *   A parameter to control how rounded the corners are for the outer shell and for the internal boxes. I'd prefer the internal boxes' corner radius to be half of the main corner radius.
*   **Rendering Quality:**
    *   I would like to control the `$fn` parameter.
*   **Rounded Boxes:** You should use the provided `roundedBox()` function which takes in three parameters, the size vector, the corner radius, and a boolean which determines if we only want the sides or the full cube.
*   **No Libraries:** Please don't rely on any external libraries except the `roundedBox()` function provided in the code sample.

I'm essentially recreating the design in the provided code, but I'd like a clean implementation from scratch based on these requirements. Let me know if you have any questions!

[Assistant]
Customisable_Box_Rack_v1.0.scad:
```
// A fully parameterised basic shelving rack
//   Author: Nick Wells
// Revision: 1.0 23/03/2019 Initial release
// http://customizer.makerbot.com/docs

// Set the box dimensions here. all units in mm
/* [box Dimensions] */
  // box Width
boxW    = 20; //[10:1:200]
  // box Height
boxH    = 20;  //[10:1:200]
  // box Depth
boxD    = 20;  //[5:1:200]
  // Number of rows
rows    = 5;   //[1:1:20]
  // Number of columns
columns = 5;   //[1:1:20]

// Nozzle diameter
nozzleD = 0.3; //[0.3:0.05:1]
// Wall thickness mulitplier (x nozzle thickness
wallM   = 3;   //[1:1:20]
// Corner Radius
cornerR = 0; //[0:0.5:10]
// Curve rendering quality
$fn     = 25;

//include <MCAD\boxes.scad>

// I had to include the library code for this to work in Thingiverse customiser
// ---Snip library---

// Library: boxes.scad
// Version: 1.0
// Author: Marius Kintel
// Copyright: 2010
// License: 2-clause BSD License (http://opensource.org/licenses/BSD-2-Clause)

// roundedBox([width, height, depth], float radius, bool sidesonly);

// EXAMPLE USAGE:
// roundedBox([20, 30, 40], 5, true);

// size is a vector [w, h, d]
module roundedBox(size, radius, sidesonly)
{
  rot = [ [0,0,0], [90,0,90], [90,90,0] ];
  if (sidesonly) {
    cube(size - [2*radius,0,0], true);
    cube(size - [0,2*radius,0], true);
    for (x = [radius-size[0]/2, -radius+size[0]/2],
           y = [radius-size[1]/2, -radius+size[1]/2]) {
      translate([x,y,0]) cylinder(r=radius, h=size[2], center=true);
    }
  }
  else {
    cube([size[0], size[1]-radius*2, size[2]-radius*2], center=true);
    cube([size[0]-radius*2, size[1], size[2]-radius*2], center=true);
    cube([size[0]-radius*2, size[1]-radius*2, size[2]], center=true);

    for (axis = [0:2]) {
      for (x = [radius-size[axis]/2, -radius+size[axis]/2],
             y = [radius-size[(axis+1)%3]/2, -radius+size[(axis+1)%3]/2]) {
        rotate(rot[axis])
          translate([x,y,0])
          cylinder(h=size[(axis+2)%3]-2*radius, r=radius, center=true);
      }
    }
    for (x = [radius-size[0]/2, -radius+size[0]/2],
           y = [radius-size[1]/2, -radius+size[1]/2],
           z = [radius-size[2]/2, -radius+size[2]/2]) {
      translate([x,y,z]) sphere(radius);
    }
  }
}

// ---Snip library---

// Standard flash cards
/*
  boxW = 128;
  boxH = 20;   // 100 cards
  boxD = 40;
  rows = 6;
  columns = 1;
*/

rack();
module rack()
{
  difference()
  {
    outershell();
    compartments();
  }
}
module outershell()
{
  // outer box
  wallT = nozzleD*wallM;
  rackH = (boxH+wallT)*rows+wallT;
  rackW = (boxW+wallT)*columns+wallT;

  roundedBox([rackW, rackH, boxD], cornerR, false);
}
module compartments()
{
  // hollowed out boxes
  wallT = nozzleD*wallM;
  Ystart = -((boxH+wallT)/2)*(rows-1);
  Xstart = -((boxW+wallT)/2)*(columns-1);
  internalR = cornerR/2;

  for (y =[0:rows-1])
  {
    for (x =[0:columns-1])
    {
      translate([Xstart+((boxW+wallT)*x),Ystart+((boxH+wallT)*y),wallT])roundedBox([boxW, boxH,boxD], internalR, false);
    }
  }
}

```


[User]
Hi, I'm looking for help designing a parametric spool adapter for refilling filament. I've got some old spools I want to reuse, and I want to design something similar to the spool adapter described [here](https://www.thingiverse.com/thing:35124438).

Essentially, the adapter needs to fit inside the old spool and hold the refill filament. I want to be able to cut the old spool in half, use the adapter as a template to drill holes through the old spool halves, and then use cable ties to hold everything together.

Here's a breakdown of the key features:

*   **Parametric Design:** It needs to be customizable for different spool sizes, so I need to define parameters for the inner and outer diameter as well as the height of the adapter.
*   **Cable Tie Grooves:** It needs to have grooves to sink the cable ties into. These should be along the outside of the adapter. These would need to be a specific depth to accommodate the cable ties.
*   **Cable Tie Knots:** The design also needs areas to accommodate the cable tie knots so they don't stick out beyond the outer diameter.
*   **Drill Holes:** The adapter needs to include holes for drilling through the old spool halves. These should line up to secure the old spool with the adapter. These holes should be a specific diameter (5mm).

Specifically, I want to be able to specify these parameters:

*   `height`: The height of the adapter
*   `outerdiameter`: The outer diameter of the adapter (should fit the inner diameter of the refill filament).
*   `innerdiameter`: The inner diameter of the adapter (should fit the outer diameter of the old spool)

I'd like to have three cable tie slots evenly spaced around the circumference of the adaptor, and the drill holes should be also be spaced such that the cable ties secure the old spool halves together. The drill holes should also be slightly offset from the vertical to assist in the drilling operation.

Can you create an OpenSCAD design that is parametric based on those parameters? Also I need the cable tie grooves/slots, cable tie knot recesses, and the drill holes. I'd prefer to avoid using any external libraries, just standard OpenSCAD functions.

[Assistant]
spooladaptor.v2.scad:
```

// -------------------------------------+---------------------------------------+---------------------------------------+---------------------------------------
// Title:        Parametric refill Spool Adaptor
// Version:      2
// Release Date: 2019-03-23
// Author:       Peter Van voorn ( Alias Mazhive)
// -------------------------------------+---------------------------------------+---------------------------------------+---------------------------------------
//
// Description:
//
// - Parametric Refill spool adaptor , designed to be printed in as less as possible filament and recycle old spool by cutting it in halve and use the holes to drill in the old spool and use those to zip tie ( tie wrap) both half together as one spool again.
// -------
//

// Refill filament used on an old spool.
// dont get me wrong the masterspool from Richrap is oke but my problem is it takes ages to print.
// This takes about 3 hours to print and 5 minutes assembly and it uses far less plastic.
// Use 0.4 or even more ( depending nozzle size) layer height if you can and it will print fine and fast.

// Please telll me how it worked for you !! As i had no problems with it using it.

// requirement:

// old spool, drill bit 5mm and 3 tie wraps ( cable ties)

// The parametric version is available so you can use it on any spool

// The outer diameter is 104.9 that is super tight on a master spool but i had no problem fitting it on the adapter.
// The inner circle of the adapter is 78mm. This is for my specific old spool but you can easily change this in the customizer .. the height of the adaptor is 45mm.

// Assembly :

// Cut the old spool in half , sand the cutted sides afterwards as flat as possible
// measure the distance from rim to end cut if it is more then 22mm you need to cut a piece of. The adaptor is 45mm so if its to long the adapter is too short. ( can be altered in customizer openscad file).
// push the adapter on one half spool and use the wholes as template to drill 5mm wholes through the half spool.
// place the refill with the cable tie knots on top and place the second half on top,
// Use the other side of the spool to drill the second 6 wholes all the way through.
// insert 3 tie cables into each first whole and tie them from the other wholes.

// cut the ends off and last but not least release( cut ) the masterspool tie cables.

// Please if you like the model and planned to make it please post a make
// https://www.thingiverse.com/thing:35124438/make

//Height of the adaptor
height=63;
//Outer diameter (or inner refil spool)
outerdiameter=79.8;
//Inner diameter (or outer old spool)
innerdiameter=63.75;

/* [Hidden] */

//extra length
e=0.02;

difference () {

depthcabletie=1.5; //times 2 for actual depth so 1.5 = actually 3

cylinder(h = height, d = outerdiameter , center = true ,$fn=64 );
cylinder(h = height+e, d = innerdiameter , center = true ,$fn=100 );

// cabletie grove

for (a = [0:2])
    rotate(a * 120)
    translate([outerdiameter/2-depthcabletie,0,0])
    cube([3,8,height+e], center = true);

// cabletie knot

cubedepth = 6.5;
cubedepth1 = cubedepth/2 ;
for (a = [0:2])
    rotate(a * 120)
    translate([outerdiameter/2-cubedepth1,0,height/2-5])
    cube([cubedepth,10,10+e], center = true);

// cable tie duct

location1 = (outerdiameter-innerdiameter)/4;

for (a = [0:2]) rotate(a * 120)
    rotate (12.5)
    translate ([outerdiameter/2-location1,2,0])
    cylinder(h = height+e, d = 5 , center = true ,$fn=64 );

for (a = [0:2])
    rotate(a * 120)
    rotate (-12.5)
    translate ([outerdiameter/2-location1,-2,0])
    cylinder(h = height+e, d = 5 , center = true ,$fn=64 );

// filament wholes

// horizontale top
difrence = outerdiameter-innerdiameter;
difrence2 = difrence/4;

for (a = [0:2])
    rotate(a * 120)
    rotate ([90,0,60])
    translate ([innerdiameter/2+difrence2,height/2,0])
    cylinder(h = 90, d = 4 , center = true ,$fn=64 );

//horizontale bottom
for (a = [0:2])
    rotate(a * 120)
    rotate ([90,0,120])
    translate ([-innerdiameter/2-difrence2,-height/2,0])
    cylinder(h = 180, d = 4 , center = true ,$fn=64 );

//verticals
for (a = [0:2]) rotate(a * 120)
    rotate (60)
    translate ([outerdiameter/2-location1,0,0])
    cylinder(h = height+e, d = 5 , center = true ,$fn=64 );

}

```


[User]
Hey, I'm looking to get a custom toothpaste squeezer design made in OpenSCAD, and I need it to be parametric so I can easily make a bunch of them with different names on them. I've got a rough idea, and a starting point in the form of an existing .scad file that you can use for reference, but I need you to build it from the ground up so that it works better.

Here's what I need:

*   **Basic Shape:** It should be a rectangular prism with rounded corners (using Minkowski sums, I guess), and I want a hole cut through the side for the toothpaste tube to slot in, also made with Minkowski sums, and a bit of a flat area cut out for the tube to sit in, also a cut out.
*   **Text:** I need to be able to put a name on the front, extruded outwards from the surface. Additionally, I'd like to cut some text out on the back. Make this all parametric and be mindful that names can be a variety of lengths, and try to scale text size when names get too long.
*   **Array of Names:** I'd like to have the ability to easily create multiple of these squeezers, each with a different name, by passing an array of names as a parameter. It should be positioned so that when printed and laid out they are side by side, without overlapping.
*   **Dimensions:** I need to be able to control the overall dimensions - the x, y, and z lengths of the main body, the radius of the corners, the depth and width of the toothpaste tube slot, the text size and height, and the radius of any other small round things used to make the design work. These all need to be customizable.

I've attached the .scad file I was using for reference; it's called `ToothpasteTag_thingiverse_v2.scad`, but you should create a fresh set of files. I don't want you to use any external libraries other than the built in one. I don't want you to use the OpenSCAD `text()` module, instead, I need you to convert the text into letter shapes as detailed below.

Text should be created as follows:

*   You'll need to use the `linear_extrude` function.
*   Each text character should be transformed using `projection()` to create a 2D shape of each letter.
*   Characters should be positioned side by side and should be aligned on their baseline using `translate()`.
*   The font for the characters should be "Liberation Sans".

I think that's everything. Can you create this for me in OpenSCAD?

[Assistant]
ToothpasteTag_thingiverse_v2.scad:
```
names = ["Name","LongName",];

backText = "back";
letter_height = 3;
letter_size = 15;
xLength = 40;
yLength = 80;
zLength = 5;
radius = 1;
font = "Liberation Sans";

cornerRadius = 5;
holeRadius = 6.0; // mm
tubeDepth = 1.2;
tubeWidth = 70;

$fn=16;// make this number smaller to speed up generation when playing with measurements

xOffset = xLength + 5;
echo("length names = ",len(names));
for(i = [0:1: len(names)-1])
{
    name = names[i];
    // assume yLength = 12 + 12*number of characters in string
    // rough guesstimate since some letters are wide "WM" and some are narrow "il"
    //yLength = 9 * len(name);
    //yLength = 86;
    echo(" i = ", i,", name = \"",name,"\", yLength = " , yLength, ", len(name) = ", len(name) );

    translate([xOffset*i, 0 ,0])
    difference()
    {
        union()
        {
            minkowski()
            {
                difference()
                {
                    minkowski()
                    {
                        // make a rectangle
                        cube([xLength - 2*cornerRadius- 2 * radius,yLength - 2*cornerRadius- 2 * radius,zLength- 2 * radius-2], center = true);
                        // minkowski it with a big cylinder to round the corners
                        cylinder(r=cornerRadius+radius, h=1);
                    }
                    // cut out key hole
                    translate([xLength/-4,yLength/-2.8, -2]) cylinder(r=cornerRadius+radius, h=zLength+2, center = true);
                    // cut out toothpaste groove
                    translate([xLength/4,0, -2]) cube([tubeDepth + 2*radius,tubeWidth - 2*radius,zLength + 2*radius], center = true);
                }
                // minkowski with small sphere
                sphere(r=1);

            }
            // union in name to be attached
            // I hate ternary operators!
            color("gray")  translate([xLength/-6 ,7,zLength-4.5]) rotate([0,0,90]) linear_extrude(height = letter_height+ radius) {text(name, size = len(name)>5?9:letter_size, font = font, halign = "center", valign = "center", $fn = 16); }
        }
        // difference out back text
        color("gray")  translate([0 ,5,zLength-5.5]) rotate([180,0,-90])linear_extrude(height = letter_height+ radius) {text(backText, size = 10, font = font, halign = "center", valign = "center", $fn = 16); }
    }

}
```


[User]
I'd like to design a marking gauge that works with different types of rulers, like a carpenter's folding rule or a metal ruler. The basic idea is to have a base that the ruler sits in, and a lever that clamps down on the ruler to hold it in place. It should be printable in place, so the lever needs to be designed such that it can move after printing. I'd like to be able to adjust the design using parameters to accommodate different sized rulers and have the option to add an angled fence for angled marking.

Here's a breakdown of the features I'm looking for:

**Core Components:**

*   **Base:** A platform that the ruler sits on. The length should be adjustable to accommodate different ruler lengths, but a minimum length is also needed to allow for the clamping mechanism. It should have walls on either side to guide the ruler.
*   **Lever:** A rotating lever that pivots on an axle. When rotated, it clamps down on the ruler to hold it in place. It needs to have a handle for easy turning.
*   **Lever Housing:** A structure that supports the lever's axle and allows it to rotate. It should integrate with the base.
*   **Ruler Tunnel:** A recess or tunnel in the base that the ruler fits into. The depth of the tunnel should be slightly larger than the ruler's thickness with a small clearance adjustment for printing. This section at the back should have a wall at its end to guide the ruler. For very thin metal rulers, I would like to have a slightly elevated base to bring the ruler up to clamping height.
*   **Fence:** A vertical wall that acts as a reference edge, sliding along the edge of the workpiece for consistent marking, or as a depth stop. I would also like the option of having this fence angled, which would require a different type of cutout on the base.

**Parameters:**

*   `ruler_width`: The width of the ruler. (e.g., 17 for a folding ruler, 13.5 for a small metal ruler, etc).
*   `ruler_thickness`: The thickness of the ruler. (e.g., 3.7 for a folding ruler segment, 0.9 for a small metal ruler, etc).
*   `base_length`: The overall length of the base, but there needs to be a minimum length.
*  `lever_length_over_base`: The length of the lever handle extending past the base of the clamp.
*   `guide_height`: The height of the walls guiding the ruler on the base.
*   `fence_length`: How far the fence protrudes from the base.
*   `fence_height`: The vertical height of the fence
*   `fence_angle`: The angle of the fence, can be 0 for a straight fence.
*   `print_adjust`: A small clearance value to account for 3D printing tolerances for printed-in-place parts (e.g. 0.4mm).
*   `cutout_adjust`: A small adjustment value to account for printing tolerances when printing cutouts (e.g. 0.4mm)
*  `wall_thickness`: The thickness of the base plate and the walls surrounding the ruler.

**Additional Notes:**

*   The lever should clamp down on the ruler, and the design should accommodate rulers of various thicknesses.
*   The design should be suitable for printing without needing inner supports. Only supports to the bed should be required.
*   The design should be fully parametric and use proper mathematical functions.
* The code should use the standard OpenSCAD libraries.

I think that should cover everything. Can you help me design this?

[Assistant]
RulerMarkingGauge.scad:
```
/*
    Folding or metal ruler marking gauge - Mk 3
    (Streichmass mit Meterstab oder Metallmass)

    Author: MrFuzzy_F,
    License: CC BY-NC
*/

$fa=1*1;
$fs=0.25*1;

// width of folding ruler
ruler_width = 17; // .. [17:FoldingRuler, 13.5:SmallMetalRuler, 30.6:MidMetalRuler, 32.6:BroadMetalRuler]

// ruler thickness
ruler_thickness = 3.7; // .. [3.7:FoldingRulerSegment, 6.7:FoldingRulerFull, 0.9:SmallMetalRuler, 1.7:MidMetalRuler, 1.2:BroadMetalRuler]

// length of base
base_length = 15;

// lever length standing out over base
lever_length_over_base = 15;

// guide height
guide_height = 11;

// fence length over base (single side)
fence_length = 10;  // 20

// fence height
fence_height = 11; // 11;

// fence rotation angle (>0)
fence_angle = 0; // [0:45]

// print-in-place distance
print_adjust = 0.4;

// cutout adjustment. If inner cutout or drill holes are printed too small.
cutout_adjust = 0.4;

// thickness of base plate and walls
wall_thickness = 5 + 0.0;

housing_base_height = 15 + 0.0;
housing_width = ruler_width + 2*wall_thickness;
clamp_radius = 10 + 0.0;
clamp_holder_diameter = clamp_radius + 6;
protector_thickness = 2 + 0.0;
housing_inner_width = 6 + 0.0;
clamp_width = housing_inner_width - print_adjust*2;
protector_width = clamp_radius;
protector_depth = protector_thickness+2*print_adjust + 1;
axle_diameter = 6 + 0.0;
ambos_inner_size = clamp_radius - 1;
ambos_outer_size = clamp_radius + 4;
fence_angle_adj = abs(fence_angle);
housing_angled_width = housing_width / cos(fence_angle_adj);
angle_extra_length = housing_angled_width * sin(fence_angle_adj);
clamp_mid_pos = 18 - angle_extra_length / 2 ;

tunnel_elevation = ruler_thickness < 2 ? 2 : 0;
base_min_length = clamp_mid_pos+clamp_holder_diameter/2+wall_thickness;
base_length_adj = base_length < base_min_length ? base_min_length : base_length;
if (base_min_length > base_length)
    echo("WARNING - base length too short - adjusted to: ", base_length_adj);
base_length_total = base_length_adj + angle_extra_length;

main();

// TEST
//base();
//lever();
//lever_housing();
//lever_with_housing();
//ruler_protector();
//front();

module main() {

    difference() {
        base();

        // cut away section due to angled fence
        translate([housing_width, 0, 0])
            rotate([0,0,-fence_angle_adj])
                translate([-housing_width*3, -base_length_total, -guide_height])
                    cube([housing_width*3, base_length_total, guide_height*3]);
    }
    front();
}

module base() {

    ya = ambos_inner_size + 2*print_adjust + cutout_adjust;
    yb = ambos_outer_size + 2*print_adjust + cutout_adjust;

    difference() {
        union() {
            translate([0,0,-wall_thickness])
                cube([housing_width, base_length_total, wall_thickness]);

            // right wall
            cube([wall_thickness, base_length_total, guide_height]);

            // left wall
            translate([ruler_width+wall_thickness,0,0]) {
                difference() {

                    cube([wall_thickness, base_length_total, guide_height]);

                    // cut-out in side wall for lever
                    translate([0, angle_extra_length, 0]) {
                        translate([0, clamp_mid_pos-ya/2, 0])
                            cube([wall_thickness, ya, housing_inner_width]);
                        translate([0, clamp_mid_pos-yb/2, 0])
                            cube([wall_thickness/2, yb, housing_inner_width]);
                    }
                }
            }

            translate([0, angle_extra_length, 0])
                lever_with_housing();
        }

    }

    // ambos
    translate([ruler_width+wall_thickness,angle_extra_length,0]) {
        translate([0,clamp_mid_pos-ambos_inner_size/2,print_adjust])
            cube([wall_thickness+2,ambos_inner_size, housing_inner_width-2*print_adjust]);
        translate([0,clamp_mid_pos-ambos_outer_size/2,print_adjust]) {
            trapezoid(2,ambos_outer_size, ambos_inner_size, housing_inner_width-2*print_adjust);
            translate([wall_thickness+2, 0, 0])
                cube([2,ambos_outer_size, housing_inner_width-2*print_adjust]);
        }
    }

    // ruler tunnel at back end
    translate([wall_thickness, base_length_total-wall_thickness, ruler_thickness+cutout_adjust+tunnel_elevation])
        cube([ruler_width, wall_thickness, guide_height-ruler_thickness-cutout_adjust-tunnel_elevation]);

    // tunnel elevation for flat metallic rulers
    if (tunnel_elevation > 0) {
        difference() {
            translate([wall_thickness, -wall_thickness, 0])
                cube([ruler_width, base_length_total+wall_thickness, tunnel_elevation]);

            cut_size = ambos_outer_size+2*(cutout_adjust+print_adjust);
            translate([ruler_width+wall_thickness-3, clamp_mid_pos-cut_size/2+angle_extra_length, 0]) {
                cube([3, cut_size, tunnel_elevation]);
            }
        }
    }
}

module lever_with_housing() {

    housing_width = 2*wall_thickness+housing_inner_width;

    translate([wall_thickness+ruler_width, clamp_mid_pos-clamp_holder_diameter/2, -wall_thickness])
    rotate([90,0,90]) {
        translate([clamp_holder_diameter/2, housing_inner_width/2+wall_thickness, housing_base_height])
            lever();

        lever_housing();
    }

}

module lever_housing() {

    lever_bearing();
    translate([0, wall_thickness+housing_inner_width, 0])
        lever_bearing();

}

module lever_bearing() {
    difference() {
        union() {
            // round holder around axle
            translate([clamp_holder_diameter/2,wall_thickness,housing_base_height])
                rotate([90,0,0])
                    cylinder(wall_thickness, d=clamp_holder_diameter);

            // base below axle holder
            cube([clamp_holder_diameter, wall_thickness, housing_base_height]);

        }
        // cut-out for axle
        translate([clamp_holder_diameter/2,wall_thickness+1,housing_base_height])
            rotate([90,0,0])
                cylinder(wall_thickness+2, d=axle_diameter+cutout_adjust+print_adjust);
    }
    translate([-wall_thickness, 0, wall_thickness])
        difference() {
            cube([clamp_holder_diameter+wall_thickness*2, wall_thickness, wall_thickness]);
            translate([0, -0.01, wall_thickness])
            rotate([-90, 0, 0]) {
                cylinder(wall_thickness+0.02, r=wall_thickness);
                translate([clamp_holder_diameter+wall_thickness*2, 0, 0])
                    cylinder(wall_thickness+0.02, r=wall_thickness);
            }
        }
}

module lever() {

    r = housing_base_height - wall_thickness - 4 - print_adjust;
    //echo("r:", r);
    factor = (housing_base_height - wall_thickness - 2) / r;
    w_handle = housing_inner_width-print_adjust*2;
    l1 = (ruler_width + 2*wall_thickness)/2+lever_length_over_base-clamp_radius;

    rotate([90,-90,0]) {
        // elliptical clamp
        scale([1,factor,1])
            cylinder(clamp_width, r=r, center=true);

        // axle of clamp
        cylinder(clamp_width + 2*wall_thickness, d=axle_diameter, center=true);

        // lever handle
        translate([l1/2, 0, 0])
            cube([l1, clamp_radius, w_handle], center=true);

        // rounding end of lever
        translate([l1, 0, 0])
            cylinder(w_handle, r=clamp_radius/2, center=true);
    }
}

module front() {

    w = housing_angled_width;
    w_delta = (housing_angled_width - housing_width)/2;
    difference() {
        translate([0, housing_angled_width*sin(fence_angle_adj), 0])
            rotate([0, 0, -fence_angle_adj])
                translate([-fence_length+w_delta, -wall_thickness, -wall_thickness])
                    cube([w+2*fence_length, wall_thickness, fence_height+wall_thickness]);

        translate([wall_thickness-cutout_adjust/2, -base_length/2, tunnel_elevation])
            cube([ruler_width+cutout_adjust, base_length*2, ruler_thickness+cutout_adjust]);
    }
}

module trapezoid(x, y1, y2, z) {
    //echo("y1:", y1);
    //echo("y2:", y2);
    d = (y1-y2)/2;
    linear_extrude(z)
        polygon(points=[[2,0], [2,y1], [0,d+y2], [0,d]], paths=[[0,1,2,3,0]]);

}

```


[User]
I'd like to create a parametric OpenSCAD design for a filament swatch or sample tag. The basic idea is a rectangular tag with a hole for hanging, some text fields, and optional thickness samples in the corner.

Here's what I'm looking for in terms of parameters:

*   **Dimensions:**
    *   `width`: The width of the rectangular tag. Default should be 64, adjustable in steps of 1, with a reasonable range like 24 to 128.
    *   `length`: The length of the rectangular tag. Default should be 24, adjustable in steps of 1, with a reasonable range like 16 to 48.
    *   `thickness`: The thickness of the tag. Default should be 1, adjustable in steps of 0.5, with a range of 1 to 8.

*   **Options:**
    *   `frame`: A boolean to add a raised frame around the border of the tag. Default is `true`.
    *   `samples`: A boolean to add small, stepped thickness samples in one of the corners. Default is `true`.

*   **Text:**
    *   `type`: String for the filament type, e.g., "PLA". Default is "PLA".
    *   `line1_text`: String for an upper text line, e.g., the filament brand. Default is "Brand".
    *   `line2_text`: String for a lower text line, e.g., the filament color. Default is "Color".

*   **Font:**
    *   `font_family`: String for the font family. Default is "Roboto", and the user should have all standard OpenSCAD font options.
    *   `font_weight`: String for the font weight, e.g. "bold", default is "bold".
    *  `line1_size`: Size for the upper text line, default of 7 with a range of 6 to 16 in steps of 1.
     * `line2_size`: Size for the lower text line, default of 6 with a range of 6 to 16 in steps of 1.

The design should include:

1.  A main rectangular body for the tag.
2.  An optional frame. If `frame` is true, it should have a slightly raised border with a thickness slightly greater than the `thickness` parameter.
3.  A hanging hole. This can be a simple circle.
4.  The three text fields as described above.
5.  Optional thickness samples. If `samples` is true, three small cubes with slightly different thicknesses stacked on top of each other in a corner.

Please use the standard OpenSCAD libraries. I don't need external libraries for this design.

I think that covers everything.

[Assistant]
filament_swatch.scad:
```
// Filament Swatch / Sample Tag

/* [Dimensions] */

// Width of the tag
width = 64; //[24:1:128]
// Length of the tag
length = 24; //[16:1:48]
// Thickness of the tag
thickness = 1; //[1:0.5:8]

/* [Options] */

// Add frame around the border of the tag?
frame = true;
// Add thickness samples in the corner?
samples = true;

/* [Text] */

// The filament type
type = "PLA";
// Upper text
line1_text = "Brand";
// Lower text
line2_text = "Color";

/* [Font] */

// Font. Select Help -> Font List for possible values
font_family = "Roboto";
// Font weight
font_weight = "bold";
// Text size for upper text
line1_size = 7; //[6:1:16]
// Text size for lower text
line2_size = 6; //[6:1:16]

sample_width = samples? (length-3)/3 : 0;
font = str(font_family, ":style=", font_weight);

if (frame) {
    union() {
        difference() {
            difference() {
                translate([0, length / 2, 0])
                    cylinder(thickness * 2, length / 2, length / 2, $fn = 75);
                translate([0, length / 2, -0.1])
                    cylinder(thickness * 2 + 0.2, length / 2 - 1, length / 2 - 1, $fn = 75);
            }

            cube([width, length, thickness*2+0.2]);
        }

        difference() {
            cube([width, length, thickness * 2]);
            translate([-0.1,1,0])
                cube([width-1, length-2, thickness * 2+0.2]);
        }
    }
}

difference() {
    union() {
        cube([width, length, thickness]);

        difference() {
            translate([0, length / 2, 0])
                cylinder(thickness, length / 2, length / 2, $fn = 75);
            translate([-length / 4, length / 2, -1])
                cylinder(thickness+2, 3, 3, $fn = 50);
        }

        translate([2, length / 2, thickness])
            rotate([0, 0, 90])
            linear_extrude(1)
            text(
                text=type,
                size=6,
                font=font,
                halign="center",
                valign="center"
            );

        translate([(width-sample_width) / 2 + 2, length-length/4-1, thickness])
            linear_extrude(1)
            text(
                text=line1_text,
                size=line1_size,
                font=font,
                halign="center",
                valign="center"
            );

        translate([(width-sample_width) / 2 + 2, length/4+1, thickness])
            linear_extrude(1)
            text(
                text=line2_text,
                size=line2_size,
                font=font,
                halign="center",
                valign="center"
            );
    }

    if (samples) {
        translate([width-sample_width-1.5,1.5,thickness*0.25])
            cube([sample_width,sample_width,thickness]);
        translate([width-sample_width-1.5,1.5+sample_width,thickness*0.5])
            cube([sample_width,sample_width,thickness]);
        translate([width-sample_width-1.5,1.5+sample_width*2,thickness*0.75])
            cube([sample_width,sample_width,thickness]);
    }
}

```


[User]
Hey, I'm looking to create a customizable decision cube with six different slates that can be attached to it. I've seen some cool ones online, and I want to be able to create my own designs for the slates.

So, each slate should be a 30mm x 30mm x 1mm square. I'd like to have text on each slate – top, center, and bottom text – with options to customize the text content, size, and vertical position. It should also have font customization including font family and font weight. Also the choice to emboss the text or not.

I want all of this to be parametric so I can easily create different slates. It should use OpenSCAD, and it should use the basic openSCAD library but no others.

Can you generate the OpenSCAD files for the slate and also the cube itself? I imagine the cube needs to be a separate file as that is pretty much static. It'll need to have the indents cut out to be able to snugly fit the slates. Assume that all the slates will fit the cube.

[Assistant]
Decision_Cube_Slate.scad:
```
//Decision Cube

//Emboss or raised text. Set to 1 for embossed text.
emboss = 1;//[0:1:1]

//Text here appears on the top
text_top = "TOP";
//Size of the top text
size_top = 3;//[2:1:16]
//Vertical position of top text
top_position = 9;//[0:1:11]

//Text here appears on the center
text_center = "CENTER";
//Size of the center text
size_center = 4;//[2:1:16]

//Text here appears on the bottom
text_bottom = "BOTTOM";
//Size of the bottom text
size_bottom = 4;//[2:1:16]
//Vertical position of bottom text
bottom_position = -7;//[-11:1:0]

//Font. Type in the font name
font_family = "Comic Sans MS";
// Font weight. bold/italic/light
font_weight = "bold";

//Resolution.
resolution = 20;//[10:10:100]

if (emboss==1); else {

translate([0,0,-0.5])
cube([30,30,1],center=true);
linear_extrude(height=1) {
text(
    text_center,
    font = str(font_family, ":style=", font_weight),
    size=size_center,
    halign="center",
    valign="center");
}
translate ([0,top_position,0])
linear_extrude(height=1) {
text(
    text_top,
    font = str(font_family, ":style=", font_weight),
    size=size_top,
    halign="center",
    valign="bottom");
}
translate ([0,bottom_position,0])
linear_extrude(height=1) {
text(
    text_bottom,
    font = str(font_family, ":style=", font_weight),
    size=size_bottom,
    halign="center",
    valign="top");
}
}

difference () {

translate([0,0,-0.7+emboss])
cube([30,30,1],center=true);
linear_extrude(height=1) {
text(
    text_center,
    font = str(font_family, ":style=", font_weight),
    size=size_center,
    halign="center",
    valign="center");
}
translate ([0,top_position,0])
linear_extrude(height=1) {
text(
    text_top,
    font = str(font_family, ":style=", font_weight),
    size=size_top,
    halign="center",
    valign="bottom");
}
translate ([0,bottom_position,0])
linear_extrude(height=1) {
text(
    text_bottom,
    font = str(font_family, ":style=", font_weight),
    size=size_bottom,
    halign="center",
    valign="top");
}
}
$fn=resolution;

```


[User]
Okay, I'm looking to create a parametric mold generator in OpenSCAD. I have a basic idea of how it should work, but I need help creating a robust and flexible solution.

Here's the core concept: I want to be able to import an STL file and generate a two-part mold around it. The mold should consist of two halves, and each half should have registration pins and holes. I've tried using a `difference()` operation with a translated mold volume but this isn't working how I expected and is very error prone.

Here's what I need:

1.  **STL Import:** The system should be able to import an arbitrary STL file.
2.  **Bounding Box:** It should calculate the bounding box of the imported STL.
3.  **Mold Box:** The mold box will be a rectangular prism. The user should be able to define the clearance or offset around the imported STL object. This will determine the dimensions of the mold box. For example, if I set a clearance value to 5, the mold box should be at least 5 units bigger than the STL object in each direction. Let’s assume that the mold box should be slightly larger than that, with additional space for a wall thickness. The total size of the mold will be based on the bounding box of the imported STL file plus the user defined clearance and wall thickness.
4.  **Mold Split:** The mold should be split into two halves along the Z-axis.
5.  **Registration Pins and Holes:** Each half should have registration pins on one face and corresponding holes on the other to ensure alignment. The user should be able to set the diameter, height, and number of pins per mold. Additionally the placement of the pins should be symmetrical on the face of the mold. I was thinking that one side of the mold should have the holes, and the other should have the pins, so the pin side is the first half of the mold.
6.  **Parametric Design:** Everything should be parametric so that it's easy to adjust the size of the mold and the registration pins.
7.  **Output:**  The two mold halves should be generated as separate parts so I can print them.
8.  **Wall Thickness:** I should be able to define the wall thickness for the mold (the extra material beyond the clearance).

I'm hoping you can generate all the necessary .scad files to achieve this. Please try to keep everything organized and clean in the code and feel free to use comments to help me understand how it works. I would also prefer to not use any libraries for this.

[Assistant]
Mold_Fixed.scad:
```

intersection(){
        union(){
difference() {
cube (10,center=true);// the bigger the model you want, the bigger the frame will be. take the highest number and add to it 10 (if Z/x/y=100, make the box 110 or bigger for thicker walls).
$fn=300;

cylinder (h=9, r=01, center=false);//h=the holes langht, make it as the model sise.
import("mold_test.stl", center=true);}        }//import the .stl file you want
        translate([-50,0,0])//cange betwin -50 and 50 to get the scond side of the mold.
                cube([100,200,200], center=true);
}

```


[User]
Hi, I'm looking for an OpenSCAD design for a customizable fan grill. I'd like it to be parametric so I can adjust different aspects of the grill.

Here's what I have in mind:

The grill should consist of concentric rings and radial spokes. I need to control the height, thickness, and spacing of the rings. The spokes should also have adjustable height and thickness. The rings can have multiple cross-sectional profile shapes.

I'd like to be able to set the number of spokes at specific rings (so, like, after the first ring, have x spokes, after the next ring, have more spokes, and so on).

For the overall size of the grill, I'll provide the distance between screw holes for the fan, and I need to be able to set the screw hole radius and the screw hole flange (that sort of outer lip around the hole) size. The grill should have screw holes in each corner to mount to the fan.

Specifically, the parameters I'd like to control are:

*   **Rings:**
    *   `ring_ht`:  Height of the rings.
    *   `ring_th`:  Thickness of the rings.
    *   `ring_sp`:  Spacing between rings.

*   **Radial Spokes:**
    *   `spoke_ht`: Height of the spokes.
    *   `spoke_th`: Thickness of the spokes.
    *   `spoke_genstart`: An array or list that dictates how the spokes are generated after each ring, e.g., `[1, 2, 4, 8, 16]` would mean 4 spokes after the first ring, 8 after the second, 16 after the third, and so on. The number of spokes should double with each successive index in the list

*   **Profile:**
    *   `ring_pf`:  String parameter which selects the cross-sectional profile shape for both rings and spokes. Options are "ellipse", "diamond", and "rectangle".
    *   `half_profile`: Boolean that, if true, truncates the profile to a half-shape (so, like, half an ellipse). This only really affects the spoke profile (as a full profile ring looks fine truncated), and makes it into a triangle if `ring_pf == "diamond"`.

*   **Size:**
    *   `h_sp`: Distance between screw holes (this determines the size of the grill).
    *   `h_rd`: Radius of the screw holes.
    *   `h_fl`: Size of the screw hole flange.

The design should create a solid grill suitable for 3D printing. It should use OpenSCAD and not rely on any external libraries.
Thanks!

[Assistant]
FanGrill.scad:
```
// Customizable fan grill
// v1.0, 26/3/2019
// by inks007
// This work is licensed under a Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License
// (CC BY-NC-SA 4.0)

/* [Rings] */
// Ring height
ring_ht = 3;
// Ring thickness
ring_th = 2;
// Ring spacing
ring_sp = 8.6;

/* [Radial Spokes] */
// Spoke height (spokes impede air-flow more than rings)
spoke_ht = 1;
// Spoke thickness (spokes impede air-flow more than rings)
spoke_th = 2;

// Spoke generations starting ring - [1,2,4,8,16] = 4x2⁰ spokes after 1st ring, 4x2¹ spokes after the 2nd ring, 4x2² spokes after the 4th ring...
spoke_genstart = [1,2,4,8,16];

/* [Profile] */
ring_pf = "ellipse"; // [ellipse, diamond, rectangle]
// ellipse -> half-ellipse, diamond -> triangle
half_profile = false;

/* [Size] */
// https://en.wikipedia.org/wiki/Computer_fan
//40mm fan  -> 32mm  screwhole distance
//50mm fan  -> 40mm  screwhole distance
//60mm fan  -> 50mm  screwhole distance
//70mm fan  -> 60mm  screwhole distance
//80mm fan  -> 72mm  screwhole distance
//92mm fan  -> 83mm  screwhole distance
//120mm fan -> 105mm screwhole distance
//140mm fan -> 125mm screwhole distance
//180mm fan -> 165mm screwhole distance (occasionally 153mm)
//200mm fan -> 170mm screwhole distance
// Distance between screw holes, refer to https://en.wikipedia.org/wiki/Computer_fan
h_sp = 125;
// Screw hole radius
h_rd = 2.5; // hole radius
// Screw hole flange
h_fl = 2.5; // hole flange

// Derived parameters
ring_ri = h_sp/2+h_rd+h_fl-ring_th/2; // largest inner (complete) ring
ring_ro = h_sp/2*sqrt(2)-h_rd-ring_th/2; // largest outer ring
spoke_zo = (ring_ri-ring_th/2)%ring_sp+ring_th/2; // spoke offset (for 0th ring)
r_co = [for (gen=[0:len(spoke_genstart)-1]) (spoke_genstart[gen]-1)*ring_sp+spoke_zo]; // spoke offsets for each generation

module profile(x,ht,th) {
	translate([x,0]) {
		if (half_profile) {
			intersection() {
				translate([0,ht/2]) square([th,ht],center=true);
				subprofile(ht*2,th);
			}
		} else subprofile(ht,th);
	}
}

module subprofile(ht,th) {
	if (ring_pf == "rectangle") square([th,ht],center=true);
	else if (ring_pf == "ellipse") scale([th/ht,1]) circle(ht/2,$fn=36);
	else scale([th/ht,1]) circle(ht/2,$fn=4);
}

module innercircles() {
	for (r = [ring_ri:-ring_sp:ring_th/2]) rotate_extrude($fn=r*2+18)  profile(r,ring_ht,ring_th);
}
module outercircles() {
	for (q = [0:90:359]) {
		for (r = [ring_ri+ring_sp:ring_sp:ring_ro]) {
			start_a = acos(ring_ri/r);
			rotate(start_a+q)	rotate_extrude(angle=90-start_a*2,$fn=r*2+18) profile(r,ring_ht,ring_th);
		}
	}
}
module perimeter() {
	difference() {
		for (a = [0:90:359]) rotate(a) {
			translate([h_sp/2,h_sp/2,0]) linear_extrude(ring_ht,center=(half_profile ? false : true)) difference() {
				circle(h_rd+h_fl,$fn=36);
				circle(h_rd,$fn=36);
			}
			translate([ring_ri,0])	rotate([90,0]) linear_extrude(h_sp,center=true) profile(0,ring_ht,ring_th);
		}
		for (a = [0:90:359]) rotate(a) {
			translate([h_sp/2,h_sp/2,0]) linear_extrude(ring_ht,center=(half_profile ? false : true)) circle(h_rd,$fn=36);
		}
	}
}
module crossbrace() {
	step_a = 360/64;
	steps = 64;
	for (s = [0:1:steps]) {
		gen = 4-(s%2==0?1:0)-(s%4==0?1:0)-(s%8==0?1:0)-(s%16==0?1:0);
		a = s*step_a+45;
		length = ring_ri/cos(abs(45-(s*step_a)%90));
		rotate(a) rotate([90,0,0]) translate([0,0,r_co[gen]]) linear_extrude(length-r_co[gen]-(gen==0?((h_rd+h_fl)*(1+sqrt(2))-ring_th/sqrt(2)):0)) profile(0,spoke_ht,spoke_th);
	}
}
union() {
	innercircles();
	outercircles();
	perimeter();
	if (half_profile) {
		crossbrace();
	} else {
		translate([0,0,(spoke_ht-ring_ht)/2]) crossbrace();
	}
}
```


[User]
Hey, I need a parametric design for a copper pipe plug, kind of like the one I've already made but much more flexible. I need to be able to control the overall length, the diameter of the wide end (the bit that sticks out of the pipe), the starting diameter where the plug begins to go into the pipe, and then also control the diameter at each step along the plug, as well as the length of each step. Think of it like a series of increasingly smaller cylinders stacked on top of each other.

I've attached my current attempt, `22mm_copper_pipe_plug.scad`, which is a static design just for a 22mm pipe, but I need something much more adaptable, preferably using a module.

I'd also really like to be able to control the number of steps in the plug, so that I can make it really long and tapered, or short with just a few steps.

Could you create a parametric OpenSCAD file for this? I'd like to avoid using any external libraries if at all possible.

[Assistant]
22mm_copper_pipe_plug.scad:
```
cylinder($fn = 180, h=5, r1=13, r2=13, center=false);
translate([0,0,4])
        cylinder($fn = 180, h=6, r1=10, r2=10, center=false);
translate([0,0,9])
        cylinder($fn = 180, h=6, r1=9.5, r2=9.5, center=false);
translate([0,0,14])
        cylinder($fn = 180, h=6, r1=9, r2=9, center=false);
translate([0,0,19])
        cylinder($fn = 180, h=6, r1=8.5, r2=8.5, center=false);
```


[User]
I'm looking to create a parametric design for a gasket, something I can easily tweak for different projects. I'd like it to be a flat, circular gasket with a number of mounting holes equally spaced around the circumference. The key is that the edges of the mounting holes should be smoothly radiused where they meet the outer edge of the gasket. I've been messing around with some trigonometry to get the chamfering right but it's a bit of a headache!

Here are the parameters I need to control:

*   **Outer Diameter (R1):** The diameter of the main circle of the gasket.
*   **Stud Surround Diameter (R2):** The diameter of the circular area around each mounting hole which is to be smoothly joined to the outer circle of the gasket.
*   **Chamfer Radius (R3):** The radius of the circular fillet that connects each mounting hole to its surrounding circle.
*   **Distance from Centre to Stud Centre (D1):** The distance from the center of the gasket to the center of each mounting hole. I understand that this will be effectively the radius of a circle on which the mounting holes are centered.
*  **Inner Diameter:** The diameter of the hole in the center of the gasket.
*   **Stud Diameter:** The diameter of the mounting holes.
*   **Number of Studs (n):** The number of mounting holes around the gasket.

Ideally, I'd like the design to use smooth curves, so I'd like you to implement the $fa and $fs variables for controlling tessellation. I would like $fs to be set to the same value as $fa, for ease of use.

Additionally, it would be fantastic if I could specify the angular position of each stud independently, instead of them always being evenly spaced. I imagine that this will require me to provide a list or vector of angles, which the system will then use to position the mounting holes.

I'd like to be able to export this as an SVG for laser cutting. I don't mind if the design uses a lot of primitives, so long as it works, although if using fillets rather than lots of small circles is easy that would also be good.

Also, I think I will need to use the `hull()` module at some point, but I'm not sure how.

I'm pretty new to OpenSCAD, so please keep the code relatively easy to understand. Thanks a bunch!

[Assistant]
gasket.scad:
```
// Smoothness - $fs equals this
$fa=0.4;
$fs=$fa;

// outer diameter of main circle
R1=80;
// diameter of stud surround
R2=14;
// chamfer radius
R3=16;
// distance from centre to stud centre
D1=40;
d=D1*2;
// inner diameter
inner=60;
// stud diameter
stud=6.2;
// number of studs
n=5;

		// cos(C)=a2+b2-c2/2ab
		a=R1+R3;
		b=d;
		c=R2+R3;
		C=acos(((a*a)+(b*b)-(c*c))/(2*a*b));

scale(0.5)
difference(){
union(){
circle(R1);
	for(i=[1:1:n]){
rotate(i*360/n) cham(d,R2,R3);

	}
}
// inner circle
circle(inner);
	for(i=[1:1:n]){
rotate(i*360/n) translate([d,0]) circle(stud);
		rotate((i*360/n)+C) translate([a,0]) circle(R3);
		rotate((i*360/n)-C) translate([a,0]) circle(R3);
	}

}

module cham(d=75,R2=14,R3=16){
	// Generates polygons to fill in the gaps between circles

		A=acos(((c*c)+(b*b)-(a*a))/(2*c*b));
		B=180-(A+C);
		h=sqrt((d*d)+(R2*R2)-(2*d*R2*cos(A)));
		e=sin(B)*R3;
		f=sqrt((h*h)-(e*e));
//	echo(C,A,B,h,e);
difference(){
union(){
color("yellow") translate([d,0]) circle(R2);
color("blue") rotate(C) translate([0,0]) polygon([[0,0],[R1,0],[f,-e]]);
color("blue") mirror([0,1]) rotate(C) translate([0,0]) polygon([[0,0],[R1,0],[f,-e]]);
}
color("green") 	rotate(C) translate([a,0]) circle(R3);
color("green") 	rotate(-C) translate([a,0]) circle(R3);
}

}
```


[User]
Hey, I'm looking to get a customizable dog tag designed in OpenSCAD. I've got some basic ideas, and I'd like to make it parametric so I can easily change things later.

Essentially, it's a round tag with a hole for attaching to a collar. I need to be able to put two lines of text on it, each with independent sizing. I also want to be able to control the diameter of the tag, the diameter of the hole, and the distance of the hole from the edge. Plus, I'd like to adjust the border width of the text and the overall thickness of the tag and the text itself. I'd also love to have a font selection option, and the ability to input language codes for special characters and emojis.

Here are the specific parameters I'm imagining:

*   **Text:**
    *   `line_1_text`: Text string for the first line.
    *   `line_1_size`: Size of the first line of text.
    *   `line_2_text`: Text string for the second line.
    *   `line_2_size`: Size of the second line of text.
    *   `text_language`: ISO language code for text (like "en", "de", "es").
    *   `fontname`: A string to choose the font, hopefully with some pre-sets to select from like "DejaVu Sans:DejaVu Sans Condensed Bold", "Coustard:Coustard bold", "Permanent Marker", "Gloria Hallelujah", "Arial:Arial bold", "Pacifico", "Courgette", "Domine:Domine bold", "Ultra", and "Bevan".

*   **Appearance:**
    *   `total_diameter`: Diameter of the entire tag.
    *   `hole_diameter`: Diameter of the attachment hole.
    *   `hole_distance`: Distance from the edge of the tag to the hole center.
    *   `border_width`: Width of the border around the text.

*   **Print Settings:**
    *   `number_of_text_layers`: Number of layers for the text extrusion.
    *  `number_of_base_layers`: Number of layers for the base plate.
    *   `first_layer_height`: Height of the first layer.
    *   `normal_layer_height`: Height of subsequent layers.

I think the tag should be built by stacking extrusions on top of a baseplate, so the text would be raised. It would be cool to have a small border around the edge of the tag to match the raised text.

Could you create a parametric OpenSCAD design for this?  I think that's everything. Let me know if you need more info. Thanks!

[Assistant]
Customizable_Round_Dog_Tag_2.scad:
```

/* [Text] */
// pet name (Holding the WIN key and tap the period may allow you to add symbols)
line_1_text = "I LUV";
// try 2-6, decimals allowed
line_1_size = 6;
// phone number
line_2_text = "MY DOG";
// try 2-6, decimals allowed
line_2_size = 5;
// ISO language code (en, de, it, fr, es...) may help with non-standard characters
text_language = "en";
fontname="DejaVu Sans:DejaVu Sans Condensed Bold"; // [DejaVu Sans:DejaVu Sans Condensed Bold, Coustard:Coustard bold, Permanent Marker, Gloria Hallelujah, Arial:Arial bold, Pacifico, Courgette, Domine:Domine bold, Ultra, Bevan ]

/* [Appearance] */
// (mm)
total_diameter = 36;
// (mm)
hole_diameter = 5;
// from side to side (mm)
hole_distance = 3;
// (mm)
border_width = 1;

/* [Print Settings] */
number_of_text_layers = 3;
number_of_base_layers = 5;
// (mm)
first_layer_height = 0.15;
// (mm)
normal_layer_height = 0.15;

/* [Hidden] */
total_radius = total_diameter / 2;                                                      // computed overall radius
hole_radius = hole_diameter / 2;                                                        // computed hole radius
text_height = normal_layer_height * number_of_text_layers;                              // text and rim extrusion height
plate_height = (number_of_base_layers - 1) * normal_layer_height + first_layer_height;  // base plate height in mm
$fn = 36;

// default number of fragments

// Border
if(border_width > 0){
    translate([0, 0, plate_height + text_height / 2] ) {
        difference() {
            cylinder(h = text_height, r = total_radius, center = true);
            cylinder(h = text_height + 1, r = total_radius - border_width, center = true);
        }
        translate([0, total_radius - hole_distance - hole_radius, 0]) {
            difference() {
                cylinder(h = text_height, r = hole_radius + border_width, center = true);
                cylinder(h = text_height + 1, r = hole_radius, center = true);
            }
        }
    }
}

// Text
translate([0, 0, plate_height]) {
    // Name (text line 1)
    linear_extrude(height = text_height) text(text = line_1_text, size = line_1_size, font = fontname, halign = "center", valign = "baseline", language = text_language);

    // Phone number (text line 2)
    translate([0, - total_radius / 2, 0]) linear_extrude(height = text_height) text(text = line_2_text, size = line_2_size, font = fontname, halign = "center", valign = "bottom", language = text_language);
}
// Base plate with hole
translate([0, 0, plate_height / 2]) {
    difference() {
        cylinder(h = plate_height, r = total_radius, center = true);
        translate([0, total_radius - hole_distance - hole_radius, 0]) cylinder(h = plate_height + 1, r = hole_radius, center = true);
    }
}
```


[User]
Hi, I'm looking to design a cover for an LCD screen, specifically for a Geeetech A10M or A10 3D printer. I want to block out the light at night, so I need a design that will fit over the front of the screen. I already have an STL of the Geeetech logo I'd like to include, so that needs to be incorporated into the design as well. I'd prefer the design be parametric, so I can easily adjust the dimensions and other aspects of the model.

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

*   **Basic Shape:** The cover should be a simple rectangular plate that fits over the LCD screen. There should be a lip at the back that hooks onto the back of the LCD mounting plate to keep it in place.
*   **Dimensions:** I'd like to define the width, front plate length, and thickness of the cover. I also need to be able to control how far the back hook extends downwards.
*   **Logo:** I want to import the Geeetech logo STL into the cover so that the logo is slightly recessed into the cover. I want to control the size and position of the logo and how deep it sits within the cover. There also needs to be an option to disable the logo altogether. I have the dimensions of the logo already.
*   **Parametric Design:** I need to be able to control all of the above via variables in the file, so I can make adjustments without having to manually modify the geometry. I also want it to be designed so I could change the scale of the logo if needed.

I've measured some of the critical dimensions already. Here they are for reference:

*   **Cover Width:**  97 mm (X-axis)
*   **Cover Front Plate Length:** 59 mm (Y-axis)
*   **Cover Thickness:** 2 mm
*   **Cover Back Hook Length:** 5 mm (length of the hook extending downward from the plate)
*  **Logo Width:** 66.7 mm
* **Logo Length:** 50.4 mm
*   **Logo Distance from Top:** 25.5mm (distance from top of the logo to the back hook)
*   **Logo Drop To Surface:** 6.74364424 mm (distance the imported logo needs to be lowered to touch the bottom of the cover)
*   **Logo Depth in Model:** 1.75mm (depth the logo sits inside the cover)

I’m also thinking the logo would need to be scaled down by a factor of approximately  26/50.4 since the LCD is 26mm tall and we want the logo within that region.

Could you generate the OpenSCAD code that fulfills all of these requirements, including defining all of these variables? I'll need the `import()` function to include the logo from the STL file, so that needs to be supported by the design.

[Assistant]
A10M_LCD_Front_Cover_With_Logo.scad:
```
//A10M_LCD_Front_Cover_With_Logo.scad by MegaSaturnv 2019-06-04
//Please include A10M_Geetech_Logo.stl in the same folder as this scad file. An stl of the logo by Kanawati can be downloaded from here: https://www.thingiverse.com/thing:3163963

/* [Basic] */
//Width of the cover. X-axis
COVER_WIDTH              = 97;

//Length of the cover. Y-axis
COVER_FRONT_PLATE_LENGTH = 59;

//Thickness of the cover
COVER_THICKNESS          = 2;

//Lenth the back hook entends downwards to hook onto the back of the LCD mounting plate
COVER_BACK_HOOK_LENGTH   = 5;

/* [Advanced] */
//Set to false to disable logo
LOGO_ENABLE            = true; // [true, false]

//66.7mm Measured from A10M_Geetech_Logo.stl file
LOGO_WIDTH             = 66.7;

//50.4mm Measured from A10M_Geetech_Logo.stl file
LOGO_LENGTH            = 50.4;

//The distance from the top of the logo to the angled 'back hook'. Aligns with top of LCD.
LOGO_DISTANCE_FROM_TOP = 25.5;

//The distance (minus the cover thickness) required to lower the imported A10M_Geetech_Logo.stl file so it just touches the bottom of the model. Arbitrary.
LOGO_DROP_TO_SURFACE   = 6.74364424;

//The distance to lower the logo down inside the model
LOGO_DEPTH_IN_MODEL    = 1.75;

//Descrease the size of the logo so it is all illuminated by the LCD. LCD = 26mm high
LOGO_SCALE             = 26 / LOGO_LENGTH;

module frontPlate() {
    cube([COVER_WIDTH, COVER_FRONT_PLATE_LENGTH, COVER_THICKNESS]);
}

module backHook() {
    cube([COVER_WIDTH, COVER_BACK_HOOK_LENGTH + COVER_THICKNESS, COVER_THICKNESS]);
}

difference() {
    union() {
        frontPlate();
        translate([0, COVER_FRONT_PLATE_LENGTH + COVER_THICKNESS, 0]) rotate([90, 0, 0]) backHook();
    }

    if (LOGO_ENABLE) {
        translate([
            (COVER_WIDTH + (LOGO_WIDTH * LOGO_SCALE))/2,
            COVER_FRONT_PLATE_LENGTH - (LOGO_LENGTH * LOGO_SCALE) - LOGO_DISTANCE_FROM_TOP,
            LOGO_DROP_TO_SURFACE + COVER_THICKNESS - LOGO_DEPTH_IN_MODEL
        ]) scale([LOGO_SCALE, LOGO_SCALE, 2]) mirror([0, 0, 1]) mirror([1, 0, 0]) import("A10M_Geetech_Logo.stl");
    }
}

```


[User]
I'm looking to get some OpenSCAD files created for a bicycle towel clip, something to hold a towel in place while I'm riding my bike indoors on a trainer. I have an existing file that does the trick, but I want something I can customize more easily, ideally with parameters for the different diameters and clip dimensions.

Basically, the design is a C-shaped clip that clamps onto the bike's handlebar or seatpost. The existing version uses a combination of cylinders and cubes to create the C shape and some smaller cubes for the actual clip portion. I'd like to be able to specify the radius of the handlebar/seatpost, the width of the gap for the towel, and the length and width of the arms of the clip. I need it to be designed so that I can easily scale the size of the clip by specifying the radius of the part it's clipping to.

Also, it would be nice to have some kind of bevel on the inner edges of the clamp to help prevent damage to my handlebars and seatpost. And if it's not too difficult, adding some extra material to the end of the clip arms that creates a small lip would help keep the towel secure. Also, the existing clip uses a rotation of a cube at a 45 degree angle to cut the C, so that the open end of the "C" is wider. It'd be nice to have a configurable angle on that cut (or even a radius instead of a cut).

I don't need it to be super complex. Something that's functional and reasonably easy to print would be perfect.
I'd like the final version to be able to be scaled using a single "radius" parameter as a base, as the original version had. It was fairly easy to figure out the different parameters using that method.

It would be awesome if you could generate the OpenSCAD files for this. I'm familiar with how to install and use OpenSCAD, so no worries about detailed installation steps. I'd also be very interested to see how the parametric design is implemented in the code - that would help me improve my own skills. I'm not using any specific libraries.

[Assistant]
bicycleclip.scad:
```
//Created by Bryan Jackson
//Edit radius to match handle bars and seat.
//Print two for handle bars, one for seat.

radius = 16;
difference(){
    union(){
        cylinder(r=radius+3, h=20);
        translate([-40-radius/2,-4,0])
        cube([40,8,20]);
    }
        cylinder(r=radius, h=20);
        cube([radius+3,radius+3,20]);
        translate([-41-radius,-1.5,0])
        cube([38,3,20]);

        translate([-33-radius,-5.5,0])
        rotate([0,0,45])
            cube([8,8,20]);
}
translate([-26.4-radius,-.8,0])
rotate([0,0,45])
cube([3.3,3.3,20]);

translate([-18-radius,-.8,0])
rotate([0,0,45])
cube([3.3,3.3,20]);

```