[User]
Hey, I'm looking to design a parametric fan duct for my 3D printer, and I've got some specific ideas in mind. I've seen the "Spaceship Fan Duct" design and the parametric OpenSCAD version by paul0, and I'd like to essentially recreate that, but with the ability to customize many parameters, as well as make the duct and the fan mount separately. I'd like to use dotSCAD, which includes the `rotate_p.scad`, `shape_square.scad`, `bezier_curve.scad`, `bezier_smooth.scad`, and `polysections.scad` files, for this, since they're used in the parametric version I referenced.

I need two main pieces: a fan plate and a fan duct. The fan plate should have mounting holes for a standard 40mm fan (or any fan, if I can make that parameterizd) and also attach to the hot end. The fan duct needs to direct air from the fan towards the print nozzle and be adjustable in its dimensions and the angle of the nozzle output.

Here’s what I'm thinking for the **fan plate**:

*   It should be a flat plate that mounts to a hotend assembly. I want to parameterize the distance between mounting screw holes, the thickness of the plate, and the wall thickness around the edges and holes.
*   There should be cutouts for the mounting screws, obviously. I'm using M3 screws right now, so the hole diameter should be a parameter.
*   I need the ability to specify the center distance of the screws and the thickness of the plate.
*   I want it to have a sort of "cutout" style, to keep it light, but also strong.

For the **fan duct**, I'd like these parameters:

*   **Fan Placement**: The position of the fan nozzle relative to the extruder nozzle tip. I should be able to adjust the x, y, and z coordinates. I'll also need to specify the size of the fan nozzle itself (x, y, and z dimensions) along with the wall thickness for that nozzle.
*   **Fan Nozzle Latch**: The latch that connects to the fan should also be customizable. I need to specify the horizontal and vertical latch sizes, and the position of the horizontal latch from the center of the nozzle side.
*  **Duct Nozzle**: I need full control over the duct nozzle, which includes the angle, length, width, and height. I should also be able to specify an offset of the duct nozzle from the extruder and from the plate, as well as a base height for the duct. I want a parameter to choose to cut the duct nozzle from the bottom, for easier printing.
*   **Duct Shape**: It should smoothly transition from the fan nozzle to the duct nozzle. I need some way to control the expansion/morphing from the fan size to the output size. Maybe a function that controls this transition? The original design uses a `morph_coeff` function to achieve this.
*   **LED Mount**: I'd also like the option to add an LED strip mount to the duct. This mount should have parameters for width, wall thickness, length, inclination angle, and offset from the fan.
*   **Vertical Supports**:  I need the option to include or exclude vertical supports within the fan duct intake.
*   **Intake**:  The design needs to have an intake on the fan side that matches up to the fan and allows for a snug fit. I want to specify the nozzle inner and outer widths and heights, and the wall thicknesses.
*   **Test Part**: It would be great to have a test part that only creates the intake section for testing the fit.

I'd like to be able to print the fan duct either vertically or horizontally and have the option to include vertical supports within the intake when printing horizontally. I saw that you could use `rotate([90,0,0])` to accomplish that in the OpenSCAD.
Also, I'd like to have a demo mode that previews the duct (in a light blue color) with the hotend and build plate, so I can visualize how it fits. Also, it would be very helpful to have an animation feature to see how changing different parameters affects the shape of the duct.

I'm pretty sure that covers it! Let me know if you have any questions, I'm eager to see what you come up with.

[Assistant]
fan-plate.scad:
```
thickness = 1.5;
screw_distance_axis = 42;
wall=5;
screw_dia=3.6;

$fn=64;

module plate(distance,wall) {
    side = distance+2*wall;
    difference() {
        square(side,center=true);

        rotate(-45) {
            translate([0,(side/2+wall)*sqrt(2)])
                square(side*sqrt(2),center=true);
            translate([0,-(side/2+wall)*sqrt(2)])
                square(side*sqrt(2),center=true);
        }
    }
}

linear_extrude(height=thickness) {
    difference() {
        plate(screw_distance_axis,wall);

        offset(-wall/2)
            plate(screw_distance_axis-wall*2,wall);

        translate([-screw_distance_axis/2,screw_distance_axis/2])
            circle(d=screw_dia);
        translate([screw_distance_axis/2,-screw_distance_axis/2])
            circle(d=screw_dia);
    }
}

```
fan-duct.scad:
```
include <dotSCAD/rotate_p.scad>;
include <dotSCAD/shape_square.scad>;
include <dotSCAD/bezier_curve.scad>;
include <dotSCAD/bezier_smooth.scad>;
include <dotSCAD/polysections.scad>;

/* [Select part] */

part="demo"; // [demo,animate-nozzle-cut,animate-nozzle,animate-height,animate-position,print-vertical,print-horizontal,test-intake-vertical,test-intake-horizontal]

/* [Common parameters] */

$fn=64; // [8:256]

$g_wall=1.7; // [0.1:0.1:5]
$g_thin_wall=0.8; // [0.1:0.1:5]
// Rounding radius of inner section
$g_rounding_r=0; // [0:0.1:10]
$g_with_vertical_supports=true;
// Extrusion width
$g_print_min_width=0.6; // [0:0.1:3]

// For demo
$g_hotend="e3d-volcano"; // [mk8,e3d-v6,e3d-volcano]

/* [Fan size and placement] */

// Fan nozzle center position against extruder nozzle tip, Spaceship: [2.93,-41.44,18.03], 36mm from nozzle to the bed for MK8+Volcano
$g_fan_pos=[3,-41.5,36]; // [0:0.1:100]
// Real: [19.2,?,?], Spaceship: [20.04,15.12,4.85]
$g_fan_nozzle_size=[19.7,15.6,3]; // [0:0.1:50]
$g_fan_nozzle_wall=1.2; // [0.1:0.1:5]
// Horizontal and vertical fan nozzle latch size, vertical latch size is from the bottom edge of the nozzle. Spaceship: [2.4,11.4]
$g_fan_nozzle_latch_size=[4,12];
// Horizontal latch position from the center of the nozzle side. Spaceship: 0.93
$g_fan_nozzle_latch_pos=0.93; // [0:0.01:5]
// Used to calculate fan_nozzle_split_from_left
$g_fan_radius=27; // [1:50]

/* [Duct nozzles size and placement] */

// Spaceship: 30
$g_duct_nozzle_angle=15; // [0:90]
// Spaceship: 5
$g_duct_nozzle_len=13; // [0:50]
// Spaceship: 15
$g_duct_nozzle_width=22; // [0:50]
// Spaceship: 3
$g_duct_nozzle_height=2.5; // [0.1:0.1:20]
$g_duct_nozzle_height_expansion_coeff=1; // [0.1:0.1:10]
$g_duct_nozzle_cut_from_bottom=true;
// Spaceship: 16.5
$g_duct_nozzle_offset_from_extruder=10; // [0:0.5:100]
$g_duct_nozzle_offset_from_plate=2.5; // [0:0.1:20]
// Spaceship: 6.7
$g_duct_base_height=10; // [0.1:0.1:50]

/* [LED strip mount] */

$g_led_mount=1;
$g_led_width=10;
$g_led_wall=2;
$g_led_length=50;
$g_led_inclination_angle=75;
$g_led_fan_offset=5;

// This function is used to transform tube width and height from duct
// nozzle to the intake. We start tube transformation near the duct
// nozzle to reduce the duct width. This is a specially crafted function.
// https://www.desmos.com/calculator/qbnwtb8lpl
//function morph_coeff(x)=1-1/(1+exp(5-x*20)/3);
// https://www.desmos.com/calculator/zqllwusfbn
//function morph_coeff(x)=1.15*(1-1/(1+exp(2.8-x*13)/2.5));
// https://www.desmos.com/calculator/83oepkjcpg
//function morph_coeff(x)=1.5*(1-1/(1+exp(1.6-x*13)/2.5));
// https://www.desmos.com/calculator/fzfn9su6k0
//function morph_coeff(x)=1.2*(1-1/(1+exp(2.3-x*13)/2));
// https://www.desmos.com/calculator/pw7fhjunjm
function morph_coeff(x)=1.15*(1-1/(1+exp(2.6-x*13)/2));

if (part=="print-vertical") {
    rotate([90,0,0])
        duct();
} else if (part=="print-horizontal") {
    duct(with_vertical_supports=false);
} else if (part=="demo") {
    $fn=8;
    color("lightblue") duct(with_vertical_supports=false);
    hotend();
    color("dimgray",0.2) build_plate();
} else if (part=="animate-nozzle-cut") {
    animate("nozzle-cut");
} else if (part=="animate-nozzle") {
    animate("nozzle");
} else if (part=="animate-height") {
    animate("height");
} else if (part=="animate-position") {
    animate("position");
} else if (part=="test-intake-vertical") {
    rotate([90,0,0])
        intake(test_part=true);
} else if (part=="test-intake-horizontal") {
    intake(with_vertical_supports=false,test_part=true);
}

// Helper functions
function translate_p(p,v) = [p.x+v.x, p.y+v.y, p.z+v.z];
function scale_p(p,v) = [p.x*v.x, p.y*v.y, p.z*v.z];
function mirror_p(p,v) = [v.x?-p.x:p.x, v.y?-p.y:p.y, v.z?-p.z:p.z];
function add_z(v,n=0) = [ for (p=v) [p.x,p.y,n] ];
function section_pts(v) = $g_rounding_r
    ? add_z(shape_square(size=v,corner_r=$g_rounding_r))
    : [ [-v.x/2,-v.y/2,0],[v.x/2,-v.y/2,0],[v.x/2,v.y/2,0],[-v.x/2,v.y/2,0] ];
// https://github.com/openscad/scad-utils/blob/master/lists.scad
function reverse(list) = [for (i = [len(list)-1:-1:0]) list[i]];

module reflect(v) {
    children();
    mirror(v)
        children();
}

module build_plate()
{
    translate([0,0,-1])
        cube([60,60,2],center=true);
}

module hotend(heater_block=$g_hotend)
{
    nozzle_offset=0.5; // From heater block
    color("goldenrod") {
        if (heater_block=="e3d-v6" || heater_block=="e3d-volcano") {
            cylinder(d1=1,d2=5,h=2+0.001);
            translate([0,0,2])
                cylinder(d=7*2/sqrt(3),h=3+0.001,$fn=6);
            translate([0,0,5])
                cylinder(d=5,h=1.5+0.001);
        } else if (heater_block=="mk8") {
            dd1=0.65;
            dd2=7*2/sqrt(3);
            hh=((7-dd1)/sqrt(3));
            intersection() {
                cylinder(d1=dd1,d2=dd2,h=hh+0.001);
                cylinder(d=dd2,h=hh+0.001,$fn=6);
            }
            translate([0,0,hh])
                cylinder(d=dd2,h=8-hh+0.001,$fn=6);
            translate([0,0,8])
                cylinder(d=5,h=1+0.001);
        }
    }
    color("silver") {
        if (heater_block=="e3d-v6") {
            translate([-8,-8,5+nozzle_offset])
                cube([16,23,11.5]);
        } else if (heater_block=="e3d-volcano") {
            translate([-4.5,-4.5,5+nozzle_offset])
                cube([11.5,20,20]);
        } else if (heater_block=="mk8") {
            translate([-10,-6.5,8+nozzle_offset])
                cube([20,20,10]);
        }
    }
}

module led_mount()
{
    x_fan_offset=-$g_fan_pos.x*2/3; // XXX hardcoded

    if ($g_led_mount) {
        translate([$g_fan_pos.x+x_fan_offset,$g_fan_pos.y+$g_fan_nozzle_size.y/2+$g_wall+$g_led_fan_offset,$g_fan_pos.z-$g_duct_base_height-2*$g_wall]) {
            translate([-$g_fan_nozzle_size.x/2,-$g_led_fan_offset-$g_wall,0])
                cube([$g_fan_nozzle_size.x,$g_led_fan_offset+$g_wall,$g_wall]);

            rotate([90-$g_led_inclination_angle,0,0])
                translate([-$g_led_length/2,0,0])
                    cube([$g_led_length,$g_led_width,$g_wall]);
        }
    }
}

module duct(with_vertical_supports=$g_with_vertical_supports)
{
    // Calculate duct width
    start_w=$g_fan_nozzle_size.y;
    end_w=$g_duct_nozzle_width;
    morph_coeff=morph_coeff(0.5);
    ww=start_w+(end_w-start_w)*morph_coeff;
    radius=(abs($g_fan_pos.y)-start_w/2-end_w/2-2*$g_wall)/2;
    start_offset=abs($g_fan_pos.x)/2+$g_fan_nozzle_size.x/2+$g_wall;
    end_offset=$g_duct_nozzle_offset_from_extruder+$g_duct_nozzle_len;
    duct_width=2*radius+4*$g_wall+2*ww+start_offset+end_offset;
    echo(duct_width=duct_width);

    render() difference() {
        duct_sections=duct_sections(
            start_h=$g_duct_base_height,
            start_w=start_w,
            start_offset=$g_fan_nozzle_size.x/2+$g_wall,
            end_h=$g_duct_nozzle_height,
            end_w=end_w
        );

        render()
            polysections(duct_sections, "HOLLOW");

        translate([$g_fan_pos.x,$g_fan_pos.y,$g_fan_pos.z-$g_wall/2-$g_rounding_r/2])
            cube([$g_fan_nozzle_size.x-2*$g_fan_nozzle_wall,$g_fan_nozzle_size.y,$g_wall+$g_rounding_r+0.002],center=true);

        if ($g_duct_nozzle_cut_from_bottom)
            translate([0,0,-($g_duct_nozzle_height+2*$g_thin_wall)/2+$g_duct_nozzle_offset_from_plate])
                cube([2*$g_duct_nozzle_offset_from_extruder+2*$g_duct_nozzle_len+$g_duct_nozzle_width+10,$g_duct_nozzle_width+2*$g_thin_wall+10,$g_duct_nozzle_height+2*$g_thin_wall],center=true);
    }

    render() {
        translate([$g_fan_pos.x,$g_fan_pos.y,$g_fan_pos.z-$g_wall-$g_duct_base_height/2]) {
            difference() {
                translate([0,0,-0.001])
                    cube([$g_fan_nozzle_size.x,$g_fan_nozzle_size.y+0.002,$g_duct_base_height+0.002],center=true);

                // Ensure the flow from radial fan distributes evenly between nozzles
                r0=$g_fan_radius-($g_fan_nozzle_size.x-2*$g_fan_nozzle_wall);
                split_from_left=$g_fan_radius-sqrt(($g_fan_radius*$g_fan_radius+r0*r0)/2)+$g_fan_nozzle_wall; // Spaceship: 6.4
                echo(split_from_left=split_from_left);
                off=$g_print_min_width/2;

                for (pos=["left","right"]) {
                    hh=pos=="right"?$g_fan_nozzle_size.x-split_from_left:split_from_left;

                    split_sections=split_sections(
                        pos=pos,
                        start_h=hh-off,
                        start_w=$g_fan_nozzle_size.y,
                        end_h=$g_duct_base_height,
                        offsets=[-($g_fan_nozzle_size.x/2-split_from_left)+(pos=="right"?off+0.001:-off-0.001),0,$g_duct_base_height/2+0.001]
                    );

                    polysections(split_sections);
                }
            }
        }
    }

    render()
        intake(with_vertical_supports=with_vertical_supports);

    led_mount();
}

module intake(
    with_vertical_supports=$g_with_vertical_supports,
    test_part=false
) {
    translate($g_fan_pos) {
        difference() {
            hh=$g_fan_nozzle_latch_size[1]+2.5*$g_wall;

            rotate([90,0,0])
                translate([0,0,($g_wall-$g_thin_wall)/2])
                    linear_extrude(height=$g_fan_nozzle_size.y+$g_wall+$g_thin_wall,center=true)
                        polygon([
                            [-$g_fan_nozzle_size.x/2-$g_wall,-2*$g_wall],
                            [$g_fan_nozzle_size.x/2+$g_wall,-2*$g_wall],
                            [$g_fan_nozzle_size.x/2+$g_wall,$g_fan_nozzle_size.z],
                            [$g_fan_nozzle_size.x/2,$g_fan_nozzle_size.z],
                            //[0,hh],
                            [-$g_fan_nozzle_size.x/2,hh],
                            [-$g_fan_nozzle_size.x/2-2*$g_wall,hh],
                            [-$g_fan_nozzle_size.x/2-2*$g_wall,hh-$g_wall],
                            [-$g_fan_nozzle_size.x/2-$g_wall,hh-2.5*$g_wall]
                        ]);

            difference() {
                union() {
                    translate([0,0,hh/2-$g_wall/2])
                        cube([$g_fan_nozzle_size.x-2*$g_fan_nozzle_wall,$g_fan_nozzle_size.y,hh+$g_wall+2],center=true);
                    translate([0,0,hh/2+0.5])
                        cube([$g_fan_nozzle_size.x,$g_fan_nozzle_size.y,hh+1],center=true);
                }

                if (with_vertical_supports) {
                    for (ii = [1:3]) {
                        translate([-$g_fan_nozzle_size.x/2+$g_fan_nozzle_size.x*ii/4,0,hh/2+0.5])
                            cube([$g_print_min_width,$g_fan_nozzle_size.y+2,hh+3],center=true);
                    }
                }
            }
            xx = $g_fan_nozzle_size.x+(test_part?-2*$g_fan_nozzle_wall:2*$g_wall+2);
            translate([0,0,-0.5-$g_wall*1.5])
                cube([xx,$g_fan_nozzle_size.y,$g_wall+1],center=true);

            // Latch hole
            translate([-$g_fan_nozzle_size.x/2-$g_wall/2,$g_fan_nozzle_latch_pos,$g_fan_nozzle_latch_size[1]/2])
                cube([$g_wall+2,$g_fan_nozzle_latch_size[0],$g_fan_nozzle_latch_size[1]],center=true);
        }
    }
}

function tube_sections(
        pos,
        height,
        depth, // Between nozzle tip and fan nozzle center
        twist,
        start_w,
        end_w,
        start_h,
        end_h,
        start_offset,
        end_offset,
        start_vwall,
        offsets
    ) =
        let (
            vmirr=[pos=="right"?0:1,0,0],
            // $fn should always be set for number of inner and outer points to match. $fn should be equal in tube_sections() and in nozzle_section().
            $fn=$fn?$fn:16,
            // Better resolution for large object
            nsec=4*$fn,
            radius=(depth-start_w/2-end_w/2-2*$g_wall)/2,
            center_y_offset=-end_w/2-$g_wall-radius
        ) [ for(i = [0:nsec]) // n+1 sections for n segments
            let(
                // Width and height of the current inner segment
                morph_coeff=morph_coeff(i/(nsec-1)),
                ww=start_w+(end_w-start_w)*morph_coeff,
                hh=start_h+(end_h-start_h)*morph_coeff,

                tr2=[start_offset*i/nsec+end_offset*(nsec-i)/nsec,center_y_offset,0],
                rot=[90, 0, 90-i*twist/nsec],
                tr1=[radius+$g_wall+ww/2,i*height/nsec,0],

                round_r=min($g_rounding_r,hh/2)-0.001
            )
                concat(
                    // Outer points
                    [ for(p = section_pts([ww+2*$g_wall,hh+2*$g_wall],round_r+$g_wall/2))
                        translate_p(mirror_p(translate_p(rotate_p(translate_p(p,tr1),rot),tr2),vmirr),offsets) ],
                    // Inner points
                    [ for(p = section_pts([ww,hh],round_r))
                        translate_p(mirror_p(translate_p(rotate_p(translate_p(p,tr1),rot),tr2),vmirr),offsets) ]
                )
        ];

function nozzle_section(
        pos,
        angle,
        end_w,
        end_h,
        offsets=[0,0,0]
    ) =
        let (
            vmirr=[pos=="right"?0:1,0,0],
            rot=[90-angle, 0, 90],
            round_r=min($g_rounding_r,end_h/2)-0.001,
            $fn=$fn?$fn:16 // $fn should always be set for number of inner and outer points to match. $fn should be equal in tube_sections() and in nozzle_section().
        ) [ concat(
            // Outer points
            [ for(p = section_pts([end_w+2*$g_thin_wall,end_h+2*$g_thin_wall],round_r+$g_thin_wall))
                translate_p(mirror_p(rotate_p(p,rot),vmirr),offsets) ],
            // Inner points
            [ for(p = section_pts([end_w,end_h],round_r))
                translate_p(mirror_p(rotate_p(p,rot),vmirr),offsets) ]
        )];

function duct_sections(
        start_h,
        start_w,
        start_offset,
        end_h,
        end_w
    ) =
        let(
            voffset=$g_duct_nozzle_offset_from_plate+($g_duct_nozzle_cut_from_bottom?-end_h/2:end_h/2+$g_thin_wall)*cos($g_duct_nozzle_angle),
            duct_nozzle_z_height=$g_duct_nozzle_len*tan($g_duct_nozzle_angle),
            height=$g_fan_pos.z-start_h/2-voffset,
            nsections = [ for (pos=["left","right"]) nozzle_section(
                pos=pos,
                angle=$g_duct_nozzle_angle,
                end_w=end_w,
                end_h=end_h,
                offsets=[(pos=="right"?1:-1)*$g_duct_nozzle_offset_from_extruder,0,voffset]
            ) ],
            tsections = [ for (pos=["left","right"]) tube_sections(
                pos=pos,
                height=height-duct_nozzle_z_height-$g_wall,
                depth=abs($g_fan_pos.y),
                twist=180, // TODO: parameterize
                start_w=start_w,
                end_w=end_w,
                start_h=start_h,
                end_h=end_h*$g_duct_nozzle_height_expansion_coeff,
                start_offset=start_offset+(pos=="right"?($g_fan_pos.x>0?$g_fan_pos.x:0):($g_fan_pos.x<0?-$g_fan_pos.x:0)),
                end_offset=$g_duct_nozzle_offset_from_extruder+$g_duct_nozzle_len,
                start_vwall=$g_wall+$g_fan_nozzle_wall,
                offsets=[0,0,duct_nozzle_z_height+voffset]
            ) ]
        )
//            concat(tsections[0],reverse(tsections[1]));
            concat(nsections[0],tsections[0],reverse(tsections[1]),reverse(nsections[1]));

function split_sections(
        pos,
        start_h,
        start_w,
        end_h,
        offsets
    ) =
        let (
            vmirr=[pos=="right"?0:1,0,0],
            fn=$fn?$fn:16,
            path=[[0,end_h,0],[start_h,end_h,0],[start_h,0,0]],
            steps=bezier_smooth(path_pts=path,round_d=min(start_h,end_h)),
            nsteps=len(steps)
        ) [ for(i=[0:nsteps-1])
            let(
                step = steps[i],
                angle=atan(step.x/step.y),
                xx=sqrt(step.x*step.x+step.y*step.y),
                tr2=[start_h,0,0],
                rot=[0, -90+angle, 0],
                tr1=[-xx/2,0,0],
                round_r=0
            )
                [ for(p = section_pts([xx,start_w],round_r))
                    translate_p(mirror_p(translate_p(rotate_p(translate_p(p,tr1),rot),tr2),vmirr),offsets) ]
        ];

module animate(what="nozzle")
{
    $fn=8;
    $g_led_mount=0;

    module show() {
        color("lightblue") duct(with_vertical_supports=false);
        hotend();
        //color("dimgray",0.1) build_plate();
    }

    t = (what == "position") ? $t : (($t < 0.5) ? 2*$t : 2*(1 - $t));
    echo($t=$t,t=t);

    if (what == "nozzle-cut") {
        $g_duct_nozzle_angle=15+t*20;
        $g_duct_nozzle_width=15+t*10;
        $g_duct_nozzle_height=2.5+t*1;
        $g_duct_nozzle_offset_from_extruder = 10 + t*10;
        $g_duct_nozzle_len = 13-t*6;
        show();
    } else if (what == "nozzle") {
        $g_duct_nozzle_angle=45-t*15;
        $g_duct_nozzle_width=10+t*15;
        $g_duct_nozzle_height=2.5+t*1;
        $g_duct_nozzle_cut_from_bottom = 0;
        $g_duct_nozzle_offset_from_plate=2;
        $g_duct_nozzle_offset_from_extruder = 10 + t*10;
        $g_duct_nozzle_len = 10-t*6;
        show();
    } else if (what == "height") {
        $g_fan_pos = [3,-41.5,36-t*10];
        $g_duct_base_height = 10-t*3;
        show();
    } else if (what == "position") {
        $g_fan_pos = [3+10*sin(360*t),-41.5+10*cos(360*t),36];
        show();
    }
}

```


[User]
I'd like to create a customizable 2D lighthouse design that I can print. I'm envisioning something like the "Customizable Origami - Lighthouse" on Thingiverse, but I need to be able to adjust quite a few parameters.

Specifically, I need to control:

*   The overall maximum size of the design (the longest side) in millimeters. The shorter side should scale proportionally.
*   The height (thickness) of the model in millimeters.
*   The thickness of the outer outline in millimeters.
*   The thickness of the inner outlines in millimeters.
*   The roundness of the ends of the inner outlines in millimeters.
*   And a boolean flag to flip the model horizontally.

The design is based on a set of pre-defined coordinates, which I can provide as well. Let me know if you need those, and how you would like them formatted, but they should be points for defining both a main polygon, and inner polygon cutouts.
I also need the code to:
* use $fn = 32, like in the original file.
* I would like to use the `resize` command rather than a simple scaling of coordinates to control dimensions.
* I want an overall `create()` module to make the design and apply all of the offset and polygon commands.

I'm open to using libraries if that helps with the creation of the model, but please do not assume I have any of the library code already. Can you generate an OpenSCAD file (or multiple if it makes sense) for me? I am trying to create something I can 3D print easily, so it should be a single 2D shape that gets extruded, and I want the inner shapes cut out.

[Assistant]
customizable_origami_lighthouse.scad:
```
/*
 * Customizable Origami - Lighthouse - https://www.thingiverse.com/thing:2723778
 * by Dennis Hofmann - https://www.thingiverse.com/mightynozzle/about
 * created 2017-12-21
 * version v1.0
 *
 * Changelog
 * --------------
 * v1.0:
 *      - final design
 * --------------
 *
 * This work is licensed under the Creative Commons - Attribution - NonCommercial - ShareAlike license.
 * https://creativecommons.org/licenses/by-nc-sa/3.0/
 */

 // Parameter Section //
//-------------------//

// preview[view:north, tilt:top]

// The maximum size of the longest side. The shorter side will be automatically resized in same ratio.
max_size_in_millimeter = 120; //[20:300]

// The height of the model.
model_height_in_millimeter = 5; //[0.2:0.2:100]

// Thickness of the outer outline.
outline_size_in_millimeter = 1.4; //[0.5:0.1:20]

// Thickness of the inner outline.
inline_size_in_millimeter = 0.8; //[0.5:0.1:20]

// Roundiness of the ends of the inner outlines.
inline_edge_radius_in_millimeter = 0.5; //[0.0:0.1:5]

// Flip model
flip_model = "no"; //[yes,no]

/*[hidden]*/
max_size = max_size_in_millimeter;
model_height = model_height_in_millimeter;
$fn=32;

// Outer Points
A1 = [449, 155];
A2 = [474, 367];
A3 = [609, 430];
A4 = [590, 430];
A5 = [572, 568];
A6 = [616, 568];
A7 = [616, 659];
A8 = [616, 723];
A9 = [584, 811];
A10 = [559, 811];
A11 = [561, 855];
A12 = [565, 964];
A13 = [577, 1164];
A14 = [582, 1276];
A15 = [595, 1479];
A16 = [600, 1589];
A17 = [601, 1629];
A18 = [975, 1629];
A19 = [1062, 1759];
A20 = [1062, 1907];
A21 = [904, 1907];
A22 = [831, 1907];
A23 = [694, 1907];
A24 = [500, 1907];
A25 = [195, 1907];
A26 = [247, 1818];
A27 = [288, 1818];
A28 = [297, 1681];
A29 = [305, 1567];
A30 = [313, 1357];
A31 = [319, 1243];
A32 = [330, 1037];
A33 = [336, 924];
A34 = [338, 811];
A35 = [315, 811];
A36 = [283, 723];
A37 = [283, 659];
A38 = [283, 568];
A39 = [328, 568];
A40 = [312, 430];
A41 = [290, 430];
A42 = [427, 367];

outline = [A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18, A19, A20, A21, A22, A23, A24, A25, A26, A27, A28, A29, A30, A31, A32, A33, A34, A35, A36, A37, A38, A39, A40, A41, A42];

// Inner Points
B1 = [500, 1759];
B2 = [694, 1759];
B3 = [831, 1786];
B4 = [904, 1786];
B5 = [500, 1818];
B6 = [451, 568];
B7 = [451, 659];
B8 = [368, 659];
B9 = [368, 568];
B10 = [532, 568];
B11 = [532, 659];

// Polygons
C1 = [A1, A2, A42];
C2 = [A2, A3, A4, A40, A41, A42];
C3 = [A4, A5, B10, B6, B9, A39, A40];
C4 = [A38, A37, B8, B9];
C5 = [B9, B6, B7, B8];
C6 = [B6, B10, B11, B7];
C7 = [B10, A5, A6, A7, B11];
C8 = [A7, A8, A36, A37, B8, B7, B11];
C9 = [A36, A35, A34, A10, A9, A8];
C10 = [A10, A34, A33, A11];
C11 = [A11, A33, A32, A12];
C12 = [A32, A31, A13, A12];
C13 = [A13, A31, A30, A14];
C14 = [A14, A15, A29, A30];
C15 = [A15, A16, A28, A29];
C16 = [A16, A17, B1, B5, A27, A28];
C17 = [A26, A25, A24, B5, A27];
C18 = [B1, A17, B2, A23, A24, B5];
C19 = [A17, A18, A19, B2];
C20 = [B2, A19, A20, A21, B4, B3, A22, A23];
C21 = [B3, B4, A21, A22];

cut_polygons = [/*C1,*/ C2, C3, C4, C5, C6, C7, C8, C9, C10, /*C11,*/ C12, /*C13,*/ C14, /*C15,*/ C16, C17, C18, C19, C20, C21];

min_x = A25[0];
min_y = A1[1];
max_x = A19[0];
max_y = A20[1];

x_size = max_x - min_x;
y_size = max_y - min_y;

x_factor = max_size / x_size;
y_factor = max_size / y_size;

inline_size = x_size > y_size ? inline_size_in_millimeter / x_factor / 2: inline_size_in_millimeter / y_factor / 2;
inline_edge_radius = x_size > y_size ? inline_edge_radius_in_millimeter / x_factor: inline_edge_radius_in_millimeter / y_factor;
outline_size = x_size > y_size ? outline_size_in_millimeter / x_factor - inline_size: outline_size_in_millimeter / y_factor - inline_size;

 // Program Section //
//-----------------//

if(x_size > y_size) {
    resize(newsize=[max_size, x_factor * y_size, model_height]){
        if(flip_model == "yes") {
            mirror([0,1,0]) {
                rotate([180,180,0]) {
                    create(outline, cut_polygons);
                }
            }
        } else {
            create(outline, cut_polygons);
        }
    }
} else {
    resize(newsize=[y_factor * x_size, max_size, model_height]){
        if(flip_model == "yes") {
            mirror([0,1,0]) {
                rotate([180,180,0]) {
                    create(outline, cut_polygons);
                }
            }
        } else {
            create(outline, cut_polygons);
        }
    }
}

 // Module Section //
//----------------//

module create() {
    linear_extrude(height=1) {
        difference() {
            offset(r = -0) {
                offset(r = +outline_size) {
                    polygon(points = outline, convexity = 10);
                }
            }

            for(cut_polygon = [0:len(cut_polygons)]) {
                offset(r = +inline_edge_radius) {
                    offset(r = -inline_size - inline_edge_radius) {
                        polygon(points = cut_polygons[cut_polygon], convexity = 10);
                    }
                }
            }
        }
    }
}

```


[User]
I'd like to create a parametric headphone stand in OpenSCAD. It should have a base, a support arm, and a top cradle for the headphones. I'd like to be able to control the overall height of the stand, the length of the support arm, and the angle that the arm makes with the base.

The base should be a rounded rectangle with a cut-out in the middle, and it should be thicker at the bottom than at the top, with the top of the base scaled to be a percentage of the bottom. The bottom of the base should be wider than the top, with the shape changing between the top and bottom. Also, there should be a cut out at the top of the base along the line of the angle of the support arm. The base can also be split into two pieces to make it easier to print.

The support arm will start from the cut-out at the top of the base and will extend upwards at an angle that can be adjusted. It should end in the top cradle, which should be designed to hold the headphones. It would be great if the whole design could be made with rounded edges as an option, although I know that can take a long time to render.

Could you generate an OpenSCAD file for this? I don't need any external libraries.

[Assistant]
headphonestand.scad:
```
////////////////////////////////////////////////////////////////////////////////
// Head Phone Stand
////////////////////////////////////////////////////////////////////////////////
//
// (c) Andreas Mueller
// License: Creative Commans - Attribution
// http://creativecommons.org/licenses/by/4.0/
//
////////////////////////////////////////////////////////////////////////////////

// Height (mm)
height = 205 ; // [150:250]
// Length (mm)
length =  50 ; // [ 40: 80]
// Angle (°)
angle  =  70 ; // [ 60: 90]
// Print in two parts
split = 0 ;    // [0:all, 1:split]

// calculating round edges takes very long time
roundEdge = 0+0 ; // [0:no, 1:yes]

/* [Hidden] */

////////////////////////////////////////////////////////////////////////////////

module headPhoneStand(height=185, lengthTop=50, angle=70, split=0, roundEdge=0)
{
  $fn = 90 ;
  length0 = height / tan(angle) ;
  lengthBottom = (lengthTop+length0) * 1.2 ;

  extrudeScale = (lengthBottom-length0) / lengthBottom ;
  widthBottom = 120 ;

  a = lengthBottom * 0.8 ;
  b = widthBottom / 2 * 0.8 ;
  t = tan(20) ;
  x = (a*b) / sqrt(b*b + a*a * t*t) ;
  y = (b/a) * sqrt(a*a - x*x) ;

  l = x - lengthTop/extrudeScale ;

  ////////////////////////////////////////

  module platform()
  {
    difference()
    {
      linear_extrude(height=height, scale=extrudeScale)
        difference()
      {
        scale([2*lengthBottom, widthBottom]) circle(d=1, $fa=12, $fs=2) ;

        translate([0,  widthBottom+y]) square([lengthBottom*2, widthBottom*2], center=true) ;
        translate([0, -widthBottom-y]) square([lengthBottom*2, widthBottom*2], center=true) ;
        translate([ lengthBottom-l,0]) square([lengthBottom*2, widthBottom*2], center=true) ;
      }

      translate ([0, 0, height/2 - 20]) cube([4*lengthBottom, 4*widthBottom, height], center=true) ;
      translate ([0, 0, 1.5*height   - 10]) cube([4*lengthBottom, 4*widthBottom, height], center=true) ;

      difference()
      {
        lx = (lengthTop-20)/extrudeScale ;
        linear_extrude(height=height, scale=extrudeScale)
        translate([-x+lx/2+10/extrudeScale,0])
        square([lx, widthBottom], center=true) ;

        translate([0,0,height/2-12])
        cube([4*lengthBottom, 4*widthBottom, height], center=true) ;
      }
    }
  }

  ////////////////////////////////////////

  module base()
  {
    module baseShape(length, width)
    {
      difference()
      {
        scale([2*length, width]) circle(d=1, $fa=12, $fs=2) ;
        scale([2*length*0.8, width*0.8]) circle(d=1, $fa=12, $fs=2) ;
        translate([length-l,0]) square([length*2, width*2], center=true) ;
      }
    }

    difference()
    {
      linear_extrude(height=height, scale=extrudeScale)
        baseShape(lengthBottom, widthBottom) ;

      translate([0,0,height*0.75-20])
        cube([5*lengthBottom, 5*lengthBottom, height/2], center=true) ;
      rotate([0,5,0])
        translate([0,0,height*0.25+10])
        cube([5*lengthBottom, 5*lengthBottom, height/2], center=true) ;

      rotate([0,0,80])
        translate([0,-lengthBottom,20])
        cube([5*lengthBottom, 5*lengthBottom,height]) ;
      rotate([0,0,190])
        translate([-lengthBottom,0,20])
        cube([5*lengthBottom, 5*lengthBottom,height]) ;
    }

    linear_extrude(height=height, scale=extrudeScale)
      difference()
    {
      baseShape(lengthBottom, widthBottom) ;
      rotate(  70) translate([0,-2.5*lengthBottom]) square(5*lengthBottom) ;
      rotate(-100) translate([0,-2.5*lengthBottom]) square(5*lengthBottom) ;
    }

    linear_extrude(height=height, scale=extrudeScale)
      difference()
    {
      baseShape(lengthBottom, widthBottom) ;
      rotate(-70) translate([0,-2.5*lengthBottom]) square(5*lengthBottom) ;
      rotate(100) translate([0,-2.5*lengthBottom]) square(5*lengthBottom) ;
    }
  }

  ////////////////////////////////////////

  module roundEdge()
  {
    if (roundEdge > 0)
    {
      difference()
      {
        minkowski()
        {
          sphere(d=4, $fn = 20) ;
          union()
          {
            children() ;
          }
        }

        translate([0,0,-500]) cube([1000,1000,1000], center=true) ;
      }
    }
    else
    {
      children() ;
    }
  }

  ////////////////////////////////////////

  module split()
  {
    splitHeight = (roundEdge>0) ? height - 22 : height - 20 ;
    echo(splitHeight=splitHeight) ;

    if (split > 0)
    {
      difference()
      {
        union() children() ;
        translate([0, 0, 1.5*splitHeight]) cube([4*lengthBottom, 4*widthBottom, splitHeight], center=true) ;
      }

      translate([length/2, 0, -splitHeight])
      difference()
      {
        union() children() ;
        translate([0, 0, 0.5*splitHeight]) cube([4*lengthBottom, 4*widthBottom, splitHeight], center=true) ;
      }

    }
    else
    {
      children() ;
    }
  }

  ////////////////////////////////////////

  split()
  {
    roundEdge()
    {
      platform() ;
      base() ;
    }
  }
}

////////////////////////////////////////////////////////////////////////////////

headPhoneStand(height, length, angle, split, roundEdge) ;

////////////////////////////////////////////////////////////////////////////////
// EOF
////////////////////////////////////////////////////////////////////////////////

```


[User]
Hey there! I'm looking to create a customizable gift tag that I can 3D print, ideally in two colors.

The tag should have a basic shape - a rectangle with a sort of triangular point on one end, like a classic tag shape. I need to be able to define the overall length and height of the tag. I also want to specify the base depth of the tag, and a depth for the text that will be printed on the tag that's a little deeper than the base, giving it some pop. I'll also need to specify the font and text of the tag itself. Finally I'd like to control how far the text is from the edge of the tag, and how thick the border of the tag is. I'd like to make it with a hole at the pointed end for string, of course.

The idea is I'll print the tag's base in one color, and the text, tag border, and the string hole in another color, using Prusa's color print feature, so they need to be separate objects. I need to be able to use different fonts too, so I would like the ability to use fonts in OpenSCAD.

I'd like the design to be parametric, so I can adjust these parameters easily. Could you help me generate an OpenSCAD file for that?

[Assistant]
gift_tag.scad:
```
/* [Customize] */

// the words that will appear on your tag.
tag_text = "to: Elizabeth";
// the font to render
font_name = "Nunito"; // [Roboto,Bungee,Noto Sans,Nunito,Oswald]
// the length of the tag in mm (x axis)
tag_length = 84;
// the height of the tag in mm (y axis)
tag_height = 16;
// the depth of the tag base in mm (z axis)
tag_depth = 1;
// the depth of the text in mm (must be > tag_depth, is 2x by default)
text_depth = tag_depth*2;
// how much space between the text and the edge
text_border=3;
// how wide to make the tag border
tag_border=2;

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

// Model - Start

bold_font_name = str(font_name,":style=Bold");

//Arial Rounded MT Bold is a great 3d printer font. Sadly not available on thingiverse
//bold_font_name = "Arial Rounded MT Bold";

tag_points = [
    [tag_length,-1*(tag_height/2)],
    [-1*(tag_height/2), -1*(tag_height/2)],
    [-1*(tag_height),0],
    [-1*(tag_height/2),tag_height/2],
    [tag_length, tag_height/2]];

difference() {
    union() {
        linear_extrude(height=tag_depth) {
            polygon(points=tag_points);
        }
        translate([(-1*(tag_height/2))+(tag_height/5/2),0,0]) {
            cylinder(r=(tag_border*2),h=text_depth);
        }
    }
    translate([(-1*(tag_height/2))+(tag_height/5/2),0,0]) {
        cylinder(r=tag_border,h=text_depth*2);
    }
}

translate([text_border,0,0]) {
    linear_extrude(height = text_depth) {
        text(tag_text,font=bold_font_name, size=tag_height-text_border*2, valign="center");
        }
}

linear_extrude(height = text_depth) {
    polygon(points=[
    [tag_points[0][0], tag_points[0][1]],
    [tag_points[0][0], tag_points[0][1]-tag_border],
    [tag_points[1][0], tag_points[1][1]-tag_border],
    [tag_points[1][0], tag_points[1][1]],
    ]);

    polygon(points=[
    [tag_points[1][0], tag_points[1][1]],
    [tag_points[1][0], tag_points[1][1]-tag_border],
    [tag_points[2][0]-tag_border, tag_points[2][1]],
    [tag_points[2][0], tag_points[2][1]],
    ]);

    polygon(points=[
    [tag_points[2][0], tag_points[2][1]],
    [tag_points[2][0]-tag_border, tag_points[2][1]],
    [tag_points[3][0], tag_points[3][1]+tag_border],
    [tag_points[3][0], tag_points[3][1]],
    ]);

    polygon(points=[
    [tag_points[3][0], tag_points[3][1]+tag_border],
    [tag_points[3][0], tag_points[3][1]],
    [tag_points[4][0], tag_points[4][1]],
    [tag_points[4][0], tag_points[4][1]+tag_border],
    ]);

    polygon(points=[
    [tag_points[4][0], tag_points[4][1]+tag_border],
    [tag_points[4][0]+tag_border, tag_points[4][1]+tag_border],
    [tag_points[0][0]+tag_border, tag_points[0][1]-tag_border],
    [tag_points[0][0], tag_points[0][1]-tag_border],
    ]);
}
```


[User]
Hey, I'm looking to create a customizable, rounded text box with a lid, and I'd like to be able to adjust a bunch of parameters. It's similar to the "RoundedTextBox_VC.scad" file I found, but I need a fresh version. I'm envisioning a base container, a lid, or both, with the option to switch between the three. I'd like to specify the text, font, font size, text extrusion height, bubble radius (for the rounded effect), wall thickness for the lid, and a little wiggle room so the lid fits nicely onto the base. I'd also like to add a small amount of thickness to the letters on top of the cover for better definition.

Specifically, could you generate OpenSCAD code that includes:

*   **Type Selection:** A parameter to choose whether to generate just the base container ("bottom_container"), just the lid ("top_lid"), or both ("both").
*   **Text Input:** A string parameter to specify the text to be rendered on the box and lid.
*   **Font Selection:** A dropdown menu to select the font from a list of fonts similar to the ones listed in the example, with a visual separation between bold and thin styles.
*   **Text Size:** A numeric parameter to control the font size in millimeters.
*   **Text Height:** A numeric parameter to control the text extrusion height (depth) in millimeters.
*   **Bubble Radius:** A numeric parameter to control the radius of the rounded corners/edges (the "bubble").
*   **Wall Thickness:** A numeric parameter to control the wall thickness of the lid.
*   **Lid Wiggle:** A numeric parameter to add a bit of tolerance for a snug lid fit.
*    **Letter Thickness Adder**: A parameter to control a little bit of added height to the letters on top of the lid.
*   **Clean Code:** Code that is easy to understand and modify.

I'd like all of this generated with parametric OpenSCAD code, so I can make changes easily in the customizer. I don't need any additional libraries for this, just pure OpenSCAD. Thanks!

[Assistant]
RoundedTextBox_VC.scad:
```
type="both"; //[bottom_container,top_lid,both]

//Set the text to render
textstring="Oh!";

//Font name. In the list is first a selection of bold fonts. After the dashed line you get a list of thinner fonts, which are not really recommended.
fontname="Arial"; //[Arial,BungeeHairline,Holtwood One SC,Alegreya Sans SC Black,Alfa Slab One,Asset,Black Ops One,Bowlby One,Bowlby One SC,Chango,Cinzel Decorative Black,Coustard,Elsie Black,Elsie Swash Caps Black,Erica One,Exo2 Black,Fascinate,Lobster,PassionOne,Plaster,Poller One,Rammetto One,Ruslan Display,Sarpanch Black,Sigmar One,Sonsie One,Titan One,Ultra,Hanalei,---------,ABeeZee,Abel,Abril Fatface,Aclonica,Acme,Actor,Adamina,Advent Pro,Aguafina Script,Akronim,Aladin,Aldrich,Alef,Alex Brush,Alice,Alike,Alike Angular,Allan,Allerta,Allerta Stencil,Allura,Almendra,Almendra Display,Almendra SC,Amarante,Amaranth,Amatic SC,Amethysta,Amiri,Anaheim,Andada,Andika,Angkor,Annie Use Your Telescope,Anonymous Pro,Antic,Antic Didone,Antic Slab,Anton,Arapey,Arbutus,Arbutus Slab,Architects Daughter,Archivo Black,Archivo Narrow,Arimo,Arizonia,Armata,Artifika,Arvo,Asap,Asset,Astloch,Asul,Atomic Age,Aubrey,Audiowide,Autour One,Average,Average Sans,Averia Gruesa Libre,Averia Libre,Averia Sans Libre,Averia Serif Libre,Bad Script,Balthazar,Bangers,Basic,Battambang,Baumans,Bayon,Belgrano,Belleza,BenchNine,Bentham,Berkshire Swash,Bevan,Bigelow Rules,Bigshot One,Bilbo,Bilbo Swash Caps,Bitter,Black Ops One,Bokor,Bonbon,Boogaloo,Bowlby One,Bowlby One SC,Brawler,Bree Serif,Bubblegum Sans,Bubbler One,Buda,Buenard,Butcherman,Butterfly Kids,Cabin,Cabin Condensed,Cabin Sketch,Caesar Dressing,Cagliostro,Calligraffitti,Cambay,Cambo,Candal,Cantarell,Cantata One,Cantora One,Capriola,Cardo,Carme,Carrois Gothic,Carrois Gothic SC,Carter One,Caudex,Cedarville Cursive,Ceviche One,Changa One,Chango,Chau Philomene One,Chela One,Chelsea Market,Chenla,Cherry Cream Soda,Cherry Swash,Chewy,Chicle,Chivo,Cinzel,Cinzel Decorative,Clicker Script,Coda,Coda Caption,Codystar,Combo,Comfortaa,Coming Soon,Concert One,Condiment,Content,Contrail One,Convergence,Cookie,Copse,Corben,Courgette,Cousine,Coustard,Covered By Your Grace,Crafty Girls,Creepster,Crete Round,Crimson Text,Croissant One,Crushed,Cuprum,Cutive,Cutive Mono,Damion,Dancing Script,Dangrek,Dawning of a New Day,Days One,Dekko,Delius,Delius Swash Caps,Delius Unicase,Della Respira,Denk One,Devonshire,Dhurjati,Didact Gothic,Diplomata,Diplomata SC,Domine,Donegal One,Doppio One,Dorsa,Dosis,Dr Sugiyama,Droid Sans,Droid Sans Mono,Droid Serif,Duru Sans,Dynalight,Eagle Lake,Eater,EB Garamond,Economica,Ek Mukta,Electrolize,Elsie,Elsie Swash Caps,Emblema One,Emilys Candy,Engagement,Englebert,Enriqueta,Erica One,Esteban,Euphoria Script,Ewert,Exo,Exo 2,Expletus Sans,Fanwood Text,Fascinate,Fascinate Inline,Faster One,Fasthand,Fauna One,Federant,Federo,Felipa,Fenix,Finger Paint,Fira Mono,Fira Sans,Fjalla One,Fjord One,Flamenco,Flavors,Fondamento,Fontdiner Swanky,Forum,Francois One,Freckle Face,Fredericka the Great,Fredoka One,Freehand,Fresca,Frijole,Fruktur,Fugaz One,Gabriela,Gafata,Galdeano,Galindo,Gentium Basic,Gentium Book Basic,Geo,Geostar,Geostar Fill,Germania One,GFS Didot,GFS Neohellenic,Gidugu,Gilda Display,Give You Glory,Glass Antiqua,Glegoo,Gloria Hallelujah,Goblin One,Gochi Hand,Gorditas,Goudy Bookletter 1911,Graduate,Grand Hotel,Gravitas One,Great Vibes,Griffy,Gruppo,Gudea,Gurajada,Habibi,Halant,Hammersmith One,Hanalei,Hanalei Fill,Handlee,Hanuman,Happy Monkey,Headland One,Henny Penny,Herr Von Muellerhoff,Hind,Homemade Apple,Homenaje,Iceberg,Iceland,IM Fell Double Pica,IM Fell Double Pica SC,IM Fell DW Pica,IM Fell DW Pica SC,IM Fell English,IM Fell English SC,IM Fell French Canon,IM Fell French Canon SC,IM Fell Great Primer,IM Fell Great Primer SC,Imprima,Inconsolata,Inder,Indie Flower,Inika,Irish Grover,Istok Web,Italiana,Italianno,Jacques Francois,Jacques Francois Shadow,Jim Nightshade,Jockey One,Jolly Lodger,Josefin Sans,Josefin Slab,Joti One,Judson,Julee,Julius Sans One,Junge,Jura,Just Another Hand,Just Me Again Down Here,Kalam,Kameron,Kantumruy,Karla,Karma,Kaushan Script,Kavoon,Kdam Thmor,Keania One,Kelly Slab,Kenia,Khand,Khmer,Khula,Kite One,Knewave,Kotta One,Koulen,Kranky,Kreon,Kristi,Krona One,La Belle Aurore,Laila,Lakki Reddy,Lancelot,Lateef,Lato,League Script,Leckerli One,Ledger,Lekton,Lemon,Liberation Sans,Libre Baskerville,Life Savers,Lilita One,Lily Script One,Limelight,Linden Hill,Lobster,Lobster Two,Londrina Outline,Londrina Shadow,Londrina Sketch,Londrina Solid,Lora,Love Ya Like A Sister,Loved by the King,Lovers Quarrel,Luckiest Guy,Lusitana,Lustria,Macondo,Macondo Swash Caps,Magra,Maiden Orange,Mako,Mallanna,Mandali,Marcellus,Marcellus SC,Marck Script,Margarine,Marko One,Marmelad,Martel Sans,Marvel,Mate,Mate SC,Maven Pro,McLaren,Meddon,MedievalSharp,Medula One,Megrim,Meie Script,Merienda,Merienda One,Merriweather,Merriweather Sans,Metal,Metal Mania,Metamorphous,Metrophobic,Michroma,Milonga,Miltonian,Miltonian Tattoo,Miniver,Miss Fajardose,Modak,Modern Antiqua,Molengo,Molle,Monda,Monofett,Monoton,Monsieur La Doulaise,Montaga,Montez,Montserrat,Montserrat Alternates,Montserrat Subrayada,Moul,Moulpali,Mountains of Christmas,Mouse Memoirs,Mr Bedfort,Mr Dafoe,Mr De Haviland,Mrs Saint Delafield,Mrs Sheppards,Muli,Mystery Quest,Neucha,Neuton,New Rocker,News Cycle,Niconne,Nixie One,Nobile,Nokora,Norican,Nosifer,Nothing You Could Do,Noticia Text,Noto Sans,Noto Serif,Nova Cut,Nova Flat,Nova Mono,Nova Oval,Nova Round,Nova Script,Nova Slim,Nova Square,NTR,Numans,Nunito,Odor Mean Chey,Offside,Old Standard TT,Oldenburg,Oleo Script,Oleo Script Swash Caps,Open Sans,Open Sans Condensed,Oranienbaum,Orbitron,Oregano,Orienta,Original Surfer,Oswald,Over the Rainbow,Overlock,Overlock SC,Ovo,Oxygen,Oxygen Mono,Pacifico,Paprika,Parisienne,Passero One,Passion One,Pathway Gothic One,Patrick Hand,Patrick Hand SC,Patua One,Paytone One,Peddana,Peralta,Permanent Marker,Petit Formal Script,Petrona,Philosopher,Piedra,Pinyon Script,Pirata One,Plaster,Play,Playball,Playfair Display,Playfair Display SC,Podkova,Poiret One,Poller One,Poly,Pompiere,Pontano Sans,Port Lligat Sans,Port Lligat Slab,Prata,Preahvihear,Press Start 2P,Princess Sofia,Prociono,Prosto One,PT Mono,PT Sans,PT Sans Caption,PT Sans Narrow,PT Serif,PT Serif Caption,Puritan,Purple Purse,Quando,Quantico,Quattrocento,Quattrocento Sans,Questrial,Quicksand,Quintessential,Qwigley,Racing Sans One,Radley,Rajdhani,Raleway,Raleway Dots,Ramabhadra,Ramaraja,Rambla,Rammetto One,Ranchers,Rancho,Ranga,Rationale,Ravi Prakash,Redressed,Reenie Beanie,Revalia,Ribeye,Ribeye Marrow,Righteous,Risque,Roboto,Roboto Condensed,Roboto Slab,Rochester,Rock Salt,Rokkitt,Romanesco,Ropa Sans,Rosario,Rosarivo,Rouge Script,Rozha One,Rubik Mono One,Rubik One,Ruda,Rufina,Ruge Boogie,Ruluko,Rum Raisin,Ruslan Display,Russo One,Ruthie,Rye,Sacramento,Sail,Salsa,Sanchez,Sancreek,Sansita One,Sarina,Sarpanch,Satisfy,Scada,Scheherazade,Schoolbell,Seaweed Script,Sevillana,Seymour One,Shadows Into Light,Shadows Into Light Two,Shanti,Share,Share Tech,Share Tech Mono,Shojumaru,Short Stack,Siemreap,Sigmar One,Signika,Signika Negative,Simonetta,Sintony,Sirin Stencil,Six Caps,Skranji,Slabo 13px,Slabo 27px,Slackey,Smokum,Smythe,Sniglet,Snippet,Snowburst One,Sofadi One,Sofia,Sonsie One,Sorts Mill Goudy,Source Code Pro,Source Sans Pro,Source Serif Pro,Special Elite,Spicy Rice,Spinnaker,Spirax,Squada One,Sree Krushnadevaraya,Stalemate,Stalinist One,Stardos Stencil,Stint Ultra Condensed,Stint Ultra Expanded,Stoke,Strait,Sue Ellen Francisco,Sunshiney,Supermercado One,Suranna,Suravaram,Suwannaphum,Swanky and Moo Moo,Syncopate,Tangerine,Taprom,Tauri,Teko,Telex,Tenali Ramakrishna,Tenor Sans,Text Me One,The Girl Next Door,Tienne,Timmana,Tinos,Titan One,Titillium Web,Trade Winds,Trocchi,Trochut,Trykker,Tulpen One,Ubuntu,Ubuntu Condensed,Ubuntu Mono,Ultra,Uncial Antiqua,Underdog,Unica One,UnifrakturCook,UnifrakturMaguntia,Unkempt,Unlock,Unna,Vampiro One,Varela,Varela Round,Vast Shadow,Vesper Libre,Vibur,Vidaloka,Viga,Voces,Volkhov,Vollkorn,Voltaire,VT323,Waiting for the Sunrise,Wallpoet,Walter Turncoat,Warnes,Wellfleet,Wendy One,Wire One,Yanone Kaffeesatz,Yellowtail,Yeseva One,Yesteryear,Zeyada]

//Set font size in mm
textsize=30;

//Text height (extrusion) in mm
textheight=10;

//bubble radius
bubble=7;

//rim thickness of the cover lid
wall=1;

//lid wiggle so it fits
wiggle=.45;

//thickness of the letter on top of the cover
letteradder=1;

/* [Hidden] */
//-------------------------------------------------------------------------------

/*
Rounded Text Box
Version C, December 2017
Written by MC Geisler (mcgenki at gmail dot com)

If you need to store Stuff in words, this is the bubbly way to go.
Have fun!

License: Attribution 4.0 International (CC BY 4.0)

You are free to:
    Share - copy and redistribute the material in any medium or format
    Adapt - remix, transform, and build upon the material
    for any purpose, even commercially.
*/

//$fn = 14;
//$fn = 6; //**********************************************************

dummy_cutoutlen=len(textstring)*textsize*1.5;

module writetext(textstr, sizeit)
{
    text(textstr,size=sizeit*.9,font=fontname,halign="center",valign="baseline");
}

module halfball(rounding)
{
    difference()
    {
        //sphere(r=rounding);
        sphere(r=rounding, $fa=90/4);//, $fs=.1);
        translate([-rounding,-rounding,-2*rounding])
            cube(2*rounding);
    }
}

module BubbleText(textstr, textsize, rounding)
{
    translate([0,0,rounding])
        minkowski()
        {
            linear_extrude(height=textheight,convexity = 32)
                writetext(textstr, textsize);
            halfball(rounding);
        }
}

module HollowBubbleText(textstr, textsize, bubble, wall)
{
    difference()
    {
        BubbleText(textstring,textsize,bubble);
        translate([0,0,wall])
            BubbleText(textstring,textsize,bubble-wall);
    }
}

module CylinderText(textstr, textsize, textheight, rounding)
{
    linear_extrude(height=textheight,convexity = 32)
        minkowski()
        {
            writetext(textstr, textsize);
            circle(r=rounding);
        }
}
module CylinderTextNoHoles(textstr, textsize, textheight, rounding)
{
    delta=4;
    linear_extrude(height=textheight,convexity = 32)
    offset(delta=-delta)
    offset(delta=delta)
        minkowski()
        {
            writetext(textstr, textsize);
            circle(r=rounding);
        }
}
module HollowCylinderText(textstr, textsize, bubble, thickness)
{
    difference()
    {
        CylinderText(textstring,textsize,textheight,bubble);
        translate([0,0,-1])
            CylinderTextNoHoles(textstring,textsize,textheight+2,bubble-thickness);
    }
}

module BubbleTextBottom(textstr, textsize, bubble)
{
    difference()
    {
        scale([1,1,-1])
            translate([0,0,-(textheight+2*bubble)])
                HollowBubbleText(textstr, textsize, bubble,wall);
        translate([-dummy_cutoutlen/2,-dummy_cutoutlen/2,textheight+bubble-.1])
            cube([dummy_cutoutlen,2*dummy_cutoutlen,bubble*3]);
    }
}

module BubbleTextTopFlipped(textstr, textsize, bubble)
{
    lidIn=wall+wiggle;
    lidWidth=wall;
    liplength=2*wall;

    rotate([0,180,0])
        translate([0,0,-(textheight+bubble)-bubble-letteradder])
        {
            //Writing on top
            translate([0,0,(textheight+bubble)+bubble-wall])
                linear_extrude(height=letteradder+wall,convexity = 32)
                     offset(delta=textsize/30)
                        writetext(textstr, textsize);

            //rounded top cover
            difference()
            {
                HollowBubbleText(textstr, textsize, bubble, wall);
                translate([-dummy_cutoutlen/2,-dummy_cutoutlen/2,0])
                    cube([dummy_cutoutlen,2*dummy_cutoutlen,textheight+bubble]);
            }

            //cover lip to fit onto the storage box
            intersection()
            {
                translate([0,0,bubble+textheight])
                {
                    HollowCylinderText(textstr, textsize, bubble, lidWidth+lidIn) ;

                    translate([0,0,-liplength])
                        HollowCylinderText(textstr, textsize, bubble-lidIn, lidWidth) ;
                }

                //intersect with generic shape
                BubbleText(textstr, textsize, bubble) ;
            }
        }
}

module BubbleTextTop(textstr, textsize, bubble)
{
    lidIn=wall+wiggle;
    lidWidth=1.5*wall;
    liplength=2*wall;

    //rotate([0,180,0])
        translate([0,0,-(textheight+bubble)+liplength])
        {
            //Writing on top
            translate([0,0,(textheight+bubble)+bubble])
                linear_extrude(height=letteradder,convexity = 32)
                    writetext(textstr, textsize);

            //rounded top cover
            difference()
            {
                HollowBubbleText(textstr, textsize, bubble, wall);
                translate([-dummy_cutoutlen/2,-dummy_cutoutlen/2,0])
                    cube([dummy_cutoutlen,2*dummy_cutoutlen,textheight+bubble]);
            }

            //cover lip to fit onto the storage box
            intersection()
            {
                translate([0,0,bubble+textheight])
                {
                    HollowCylinderText(textstr, textsize, bubble, lidWidth+lidIn) ;
                    translate([0,0,-liplength])
                        HollowCylinderText(textstr, textsize, bubble-lidIn, lidWidth) ;
                }

                //intersect with generic shape
                BubbleText(textstr, textsize, bubble) ;
            }
        }
}

//[bottom_container,top_lid,both]

if (type=="bottom_container" || type=="both")
    BubbleTextBottom(textstring, textsize, bubble);

if (type=="top_lid" || type=="both")
    translate([0, ( type=="both" ? textsize*1.5+2*bubble+5 : 0 ) ,0])
        BubbleTextTopFlipped(textstring, textsize, bubble);

```


[User] I'd like to create a customizable candle holder, similar to the example I've seen, but with some changes.  I really like the star shape, but I want to be able to control the number of points on it, as well as the inner and outer diameters and heights, similar to the provided code. I'd like the base to be circular, and I want a lip to contain wax spillage.  I don't need the rounded edges for the star, so you can omit that. I'd also like to specify the candle diameter and a little bit of depth for the candle to sit in, as well as the height of the lip. It needs to have a flat bottom. Please generate the OpenSCAD files for this, and try to comment it nicely for me.

[Assistant]
CandleStands.scad:
```
// ****************************************************************************
// Customizable Candle Stands
// Author: Peter Holzwarth
// ****************************************************************************
// https://en.wikibooks.org/wiki/OpenSCAD_User_Manual/The_OpenSCAD_Language

/* ********************************************* */
// Tea light, 5:
/* ********************************************* */

/* [Candle] */
// Candle diameter
dCandle= 39.5;
// Thickness of bottom below candle
hCandle= 2;
// Height of ring around candle
hCandleStand= 5;

/* [Star] */
// Outer diameter of star
dOuter= 80;
// Outer height
hOuter= 2;
// Inner diameter of star
dInner= 39.5;
// Inner height
hInner= 5;
// Number of segments
n= 5;
// Rounding radius
rr= 2;
// Smoothness
$fn=100;

StarStand(dCandle/2, hCandle, hCandleStand, dOuter/2, hOuter, dInner/2, hInner, n, rr);

module StarStand(rCandle, hCandle, hCandleStand, rOuter, hOuter, rInner, hInner, n, rr) {
    difference() {
        union() {
            Star(rOuter, hOuter, rInner, hInner, n, rr);
            cylinder(r= rCandle+2, h= hCandleStand);
        }
        // space for candle
        translate([0,0,hCandle]) cylinder(r= rCandle, h= hCandleStand);
        // flat bottom
        translate([0,0,-rr-1]) cylinder(r=rOuter+rr+0.01,h= rr+1);
    }
}

// a star without space for the candle
module Star(rOuter, hOuter, rInner, hInner, n, rr) {
    for (a= [0:360/n:360]) {
        rotate([0,0,a])
            triangle(rOuter, hOuter, rInner, hInner, n, rr);
    }
}

module triangle(rOuter, hOuter, rInner, hInner, n, rr) {
    alpha= 360/n/2;
    b= cos(alpha) *rInner;
    a= sin(alpha) *rInner;
    tPoints= [
        [b, -a, 0],
        [b, -a, hInner],
        [b, a, 0],
        [b, a, hInner],
        [rOuter, 0, 0],
        [rOuter, 0, hOuter],
    ];
    tFaces= [
        [0, 2, 4], // bottom
        [0, 1, 3, 2], // left
        [0, 1, 5, 4], // lower
        [2, 3, 5, 4], // upper
        [1, 3, 5] // top
    ];
    minkowski() {
        hull() {
            polyhedron(tPoints, tFaces);
            intersection() {
                cylinder(r= rInner, h= hInner);
                translate([0, -a, 0]) cube([rOuter, 2*a, rInner]);
            }
        }
        sphere(r= rr);
    }
}

```


[User]
I'd like to create a customizable name tag using OpenSCAD. I want it to be a rectangular shape with a hole for attaching it to things. The main body should have adjustable length, width, and thickness parameters. I would also like the ability to choose a different font and specify the text for the name, and be able to change its size. The text should be extruded from the main body, and the hole should be a simple cylinder. I need to be able to change the hole's diameter, and it should be located a certain distance from the left and top of the rectangle. I want to control the font, font size, and text via parameters as well.

Can you generate the OpenSCAD code for me?

[Assistant]
Name_tag.scad:
```
xSize = 90; // length

myFont = "Liberation Sans"; // [Liberation Mono, Liberation Sans,]
myText = "3D Dream Box";
holeDia = 4; // [2:9]
difference() {
  difference() {
    cube([xSize, 20, 5], center=false);

    translate([10, 10, 0]){
      cylinder(r1=holeDia, r2=holeDia, h=20, center=false);
    }
  }

  translate([20, 7.5, 3]){
    // size is multiplied by 0.75 because openScad font sizes are in points, not pixels
    linear_extrude( height=5, twist=0, center=false){
      text(myText, font = "Liberation Serif", size = 10*0.75);
    }

  }
}
```


[User]
Hey, I'm looking to get an OpenSCAD design for customizable wall switch plates. I've been tinkering with the code I found online, but I'd really like something more flexible and robust. I want to be able to specify the number of switches (up to, say, 6 for now) and the type of each switch (Decora, Toggle, or Blank), along with optional labels for each. I'd also like to have some control over the overall size of the plate, like height and depth, and the thickness of the plastic.

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

**Switch Configurations:**

*   **Number of Gangs:** Allow 1 to 6 switches (gangs) on a single plate.
*   **Switch Types:** Each switch position can be one of three types:
    *   Decora (standard rectangular style)
    *   Toggle (traditional toggle switch)
    *   Blank (no switch, just a solid section on the plate)
*   **Switch Labels:** Optional text labels above each switch. Let's keep this simple, just a single line of text, center aligned above the switch. The font should be configurable, maybe just a selection of standard sans-serif fonts, like "Liberation Sans" and "Arial", for simplicity and ease of access.
*   The spacing between each gang should always be 46.0375mm, I've seen that's the standard.

**Plate Customization:**

*   **Plate Height:** A parameter to set the overall height of the plate. I'd like the width to auto-adjust based on the plate height and the number of gangs. A 2-gang plate width should equal the plate height, and other sizes should scale proportionally. So if height is 127mm, a 2-gang plate will be 127mm wide too.
*   **Plate Depth:** A parameter for the depth of the plate (how much it sticks out from the wall).
*   **Plastic Thickness:**  A parameter for how thick the material is for the plate itself.
*   **Label Emboss/Inset:** A parameter that lets you choose whether the labels are raised (embossed) or recessed (inset) into the plate by 1mm.

**Advanced Features**

*   **Screw Hole Radius:** A parameter for the radius of the screw holes.  The screws aren't meant to be countersunk so it can default to a value that works for non-countersunk screws, but allow the option to specify the countersunk screw head radius and depth.
*   **Hole Expansion:** A parameter to increase the size of the screw holes and switch cutouts to account for printing inaccuracies. I would like this to be a single parameter that adds to both screw holes and switch holes, and the screw hole expansion needs to be considered when figuring out how deep to print countersunk screw heads.

I think that covers it. This shouldn't need any special libraries, just standard OpenSCAD. I'm really looking forward to seeing what you come up with!

[Assistant]
Wall_Switch_Plate.scad:
```
/* [Switches] */

// Type of the first switch in the gang.
switch1_type=1; // [1:Decora,2:Toggle,3:Blank]
// Optional label over the first switch.  Leave blank for no label.
switch1_label="LIGHT";
// Type of the second switch in the gang.  "None" results in this and all further switch types/labels being ignored
switch2_type=0; // [0:None,1:Decora,2:Toggle,3:Blank]
// Optional label over the switch.  Leave blank for no label.
switch2_label="";
// Type of the second switch in the gang.  "None" results in this and all further switch types/labels being ignored
switch3_type=0; // [0:None,1:Decora,2:Toggle,3:Blank]
// Optional label over the switch.  Leave blank for no label.
switch3_label="";
// Type of the second switch in the gang.  "None" results in this and all further switch types/labels being ignored
switch4_type=0; // [0:None,1:Decora,2:Toggle,3:Blank]
// Optional label over the switch.  Leave blank for no label.
switch4_label="";

/* [ Plate Details ] */

// The height, in mm, of the plate. The width is determined from the height on the basis of a 2-gang plate width matching the height.  Standard US plates are 114.3mm high.  Non-standard (oversized) plates come in different heights, and may include values such as 127, 139.7, etc. 127mm is a nice slightly oversized plate
plate_height = 127;

// The depth of the plate is the distance between the wall and the outmost edge of the plate.  Standard US plates are 3.96875mm deep.  Oversized plates usually are a bit deeper.  The deeper plates allow for switches that don't mount quite perfectly flush with the wall or gang boxes that stick out slightly, but might require slightly longer mounting screws.
plate_depth = 6.4;

// How thick should the plastic be printed for the wall plate.  This has nothing to do with printer layer height (or any other slicer settings.)  A smaller value will result in a more hollow (but flimsy) wall plate.  In that case, supports will likely be needed when printing (unless you flip the plate face down when printing.)  A value equal to or greater than the plate_depth will result in a solid chunk of plastic (and somewhat negates the point of having a greater than standard plate_depth due to no hollow space.)
plastic_thickness = 2; // [1.5:.2:4]

// If set to emboss, any labels will be raised from the plate by 1mm.  If set to inset, the labels will be inset in the plate by 1mm.  The embossing usually extrudes nicer lettering, but requires that the plate be printed with the face up (and will require supports.)  If the labels are inset, the object can be flipped so the face prints against the print bed. (or, you can not use labels at all, in which case this setting has no effect.)
emboss_or_inset_labels=1; // [0:inset,1:emboss]

/* [Advanced] */

// the radius (not diameter) of the screw holes.  Should probably be left as 1.7.
screw_hole_radius = 1.7;

// For standard screws that are NOT meant to be countersunk (but the head rests outside the plate), set screw_head_radius to 0.  Otherwise, screw_head_radius should be the radius (not diameter) of the widest part of the screw head, and screw_head_depth is the depth of the screw head before the threads.  (distance between the top of the head and first thread.)  The defualt values of 3.25 (radius) and 2.3 (depth) work well with standard oval head screws.
screw_head_radius = 3.25;
screw_head_depth = 2.3; // this is ignored if screw_head_radius is 0

// Most FDM printers aren't really precise when printing empty space within a solid area (such as switch holes, screw holes, etc.)  Often times, the  empty spaces end up being very slightly smaller than the design.  Set hole_expansion to a positive number to the holes to be designed that much bigger than normal.  This often requires a bit of testing.  Start with 1 and print just the first couple of layers.  Measure the resulting screw holes.  If the screw holes are too big, reduce the hole_expansion.  If they are too small, raise it.
hole_expansion = 0.5;

/* [hidden] */

// vectors for switch types are ordered as:  width, height, screw hole gap (0 for a single hole with no gap, -1 for no holes), height(from center) for text labels
switch_decora = [ 33.3375, 66.675, 96.8375, 37 ];
switch_toggle = [ 10.31875, 23.8125, 60.325, 39 ];
switch_blank = [ 0, 0, 83.34375, 0 ];

gang_cnt = switch2_type == 0 ? 1 : switch3_type == 0 ? 2 : switch4_type == 0 ? 3 : 4;

gang_types = [ [], switch_decora, switch_toggle, switch_blank];

gangs = (0 == switch2_type) ? [[gang_types[switch1_type], switch1_label]] :
    (0 == switch3_type) ? [[gang_types[switch1_type], switch1_label], [gang_types[switch2_type], switch2_label] ] :
        (0 == switch4_type) ? [[gang_types[switch1_type], switch1_label], [gang_types[switch2_type], switch2_label], [gang_types[switch3_type], switch3_label] ] :
            [[gang_types[switch1_type], switch1_label], [gang_types[switch2_type], switch2_label], [gang_types[switch3_type], switch3_label], [gang_types[switch4_type], switch4_label] ];

// ------
$fn = 75;
gang_gap = 0 + 46.0375; // constant
plate_width = plate_height + ((len(gangs) - 2) * gang_gap);

// ---

module draw_screw_hole()
{
    base_r = screw_hole_radius + (hole_expansion * .5);
   // just draw a hole, centered
    cylinder(r = base_r, h =plate_depth*2, center = true, $fn=6);

    if (0 == screw_head_radius)
    {
        translate([0,0,plate_depth])
            cylinder(r = base_r, h=(plastic_thickness - 1)*2, center = true);
    }
    else
    {
        cs_r = screw_head_radius + (hole_expansion * .5);
        hull()
        {
            //screw_counter_radius
            // screw_counter_depth
            translate([0,0,plate_depth+0.0001])
                cylinder(r=cs_r, h=0.1, center=true);

            translate([0,0,plate_depth-screw_head_depth/2])
                cylinder(r=base_r, h=(screw_head_depth), center=true);
        }

    }
}

// need something to handle cases where the plastic thickness is too thin
// to handle the full "depth" of a countersunk screw hole
//
// So, this module will draw a "shell" around a screw hole
module draw_screw_hole_with_shells()
{
    if (screw_hole_radius)
    {
        r = (screw_head_radius) +  (hole_expansion * .5) ;
        r2 = (screw_hole_radius) +  (hole_expansion * .5);
        difference()
        {
            // hard-coded 1.5mm thickness for the screw hole shell
            resize([r*2+1.5, r*2+1.5, 0])
            {
                draw_screw_hole();
                cylinder(r = r2, h = plate_depth *2, center = true);

            }

            //draw_screw_hole();
            translate([0,0, -screw_head_depth-1])
                cube([r*2, r*2,plate_depth*2], center=true);

        }
    }
}

module draw_switch ( v )
{
   // draw things centered!

   // main hole
   if (v[0] && v[1])
   {
      cube([v[0] + hole_expansion, v[1] + hole_expansion, plate_depth*2.1], center = true);
   }
   if (-1 != v[2])
   {
      if (0 != v[2])
      {
         translate([0, v[2]/2, 0]) draw_screw_hole();
         translate([0, -(v[2]/2), 0]) draw_screw_hole();

      }
      else
      {
         draw_screw_hole();
      }
   }
}

module draw_screw_hole_shells()
{
	translate([  -(len(gangs)-1)*gang_gap/2, 0, 0])
	{
		for (i = [0 : len(gangs)-1])
		{
			translate([i*gang_gap, 0, 0])
            {
                if (-1 != gangs[i][0][2])
                {
                    if (0 != gangs[i][0][2])
                    {
                        translate([0, gangs[i][0][2]/2, -.1])
                            draw_screw_hole_with_shells();
                        translate([0, -(gangs[i][0][2]/2), -.1])
                            draw_screw_hole_with_shells();
                    }
                    else
                    {
                        draw_screw_hole_with_shells();
                    }
                }
            }
		}
	}
}

module draw_switch_labels(emboss=true)
{
	translate([  -(len(gangs)-1)*gang_gap/2, 0, plate_depth - .001])
	{
		for (i = [0 : len(gangs)-1])
		{
            if (gangs[i][1])
            {
                switch_type = gangs[i][0];

                translate([i*gang_gap, switch_type[3], emboss ? 0 : -1])
                    linear_extrude(height = 1.001)
                    {
                        text(gangs[i][1],
                             font = "Liberation Sans:style=Regular",
                            //font  = "Liberation Serif:style=Regular",
                            // font="Arial:style=Normal",
                            //font="Liberation Mono:style=Regular",
                            size=6, spacing=1.1,
                            halign="center",
                            valign="baseline");
                    }
            }
		}
	}
}

module draw_all_switches()
{
// draws all the switches, left to right.  The left edge will be at X axis 0, while the Y axis is centered

	translate([  -(len(gangs)-1)*gang_gap/2, 0, 0])
	{
		for (i = [0 : len(gangs)-1])
		{
            //switch_type = switch_decora;

			translate([i*gang_gap, 0, 0])
                draw_switch(gangs[i][0]);
		}
	}
}

module outer_plate(recurse=true)
{
    difference()
    {
        hull()
        {
            a = .75; // 1
            b = a*2;

            translate([-plate_width/2 + plate_depth, 0,0])
                rotate(a=270, v=[1,0,0])
                    cylinder(r=plate_depth,
                        h=(plate_height - plate_depth*b),
                        center=true);

            translate([plate_width/2 - plate_depth, 0,0])
                rotate(a=270, v=[1,0,0])
                    cylinder(r=plate_depth,
                        h=(plate_height - plate_depth*b),
                        center=true);

            translate([0, plate_height/2 - plate_depth,0])
                rotate(a=90, v=[0,1,0])
                    cylinder(r=plate_depth,
                        h=(plate_width - plate_depth*b),
                        center=true);

            translate([0, -plate_height/2 + plate_depth, 0])
                rotate(a=90, v=[0,1,0])
                    cylinder(r=plate_depth,
                        h=(plate_width - plate_depth*b),
                        center=true);

            cube([plate_width, plate_height, 1], center=true);
        }
        // draw a cube that differences off the back of the plate
        translate([0,0, -plate_depth*.5])
            cube([plate_width+1, plate_height+1,
                  plate_depth+0.0001],
                 center=true);
        if (recurse)
            translate([0,0,-plastic_thickness])
                resize([plate_width-plastic_thickness*2,
                        plate_height-plastic_thickness*2, 0])
                    outer_plate(false);

    }
}

difference()
{
	// draw the main plate (centered vertically, but not centered horiz)

	//cube([plate_width, plate_height, 1], center=true);
    union()
    {
        outer_plate();
        draw_screw_hole_shells();

        if (emboss_or_inset_labels) draw_switch_labels();
    }
    if (!emboss_or_inset_labels) draw_switch_labels(false);
	//draw (remove, actually) the switches
    draw_all_switches();
}

```


[User]
I'd like to create a customizable 2D pineapple design in OpenSCAD, similar to the one described in the Thingiverse link. I need to be able to control the overall size, the height, and the thickness of both the outer and inner outlines. I also want an option to flip the model.

Here are the specifics:

*   **Overall Size:** I should be able to specify a maximum size for the longest side, and the shorter side should automatically resize proportionally.
*   **Height:** The height of the extruded shape should be adjustable.
*   **Outline Thickness:** I need to be able to set the thickness of the outer outline.
*   **Inner Outline Thickness:** I need to set the thickness of the inner outlines (cutouts).
*   **Inner Outline Edge Radius:** I need to control the roundness of the ends of the inner outlines.
*  **Flip Model:** I need the ability to flip the model along the y-axis.

The design itself is based on a set of predefined points for the outer shape and inner cutouts. I'll include those in case they are useful, though you may want to use a different technique:

```
// Outer Points
A1 = [665, 694];
A2 = [768, 803];
A3 = [871, 637];
A4 = [849, 833];
A5 = [899, 798];
A6 = [858, 906];
A7 = [972, 853];
A8 = [879, 988];
A9 = [936, 959];
A10 = [922, 1030];
A11 = [975, 1009];
A12 = [854, 1144];
A13 = [893, 1153];
A14 = [968, 1306];
A15 = [974, 1464];
A16 = [888, 1663];
A17 = [678, 1677];
A18 = [614, 1559];
A19 = [564, 1394];
A20 = [618, 1217];
A21 = [680, 1145];
A22 = [698, 1139];
A23 = [586, 974];
A24 = [686, 1029];
A25 = [630, 943];
A26 = [693, 942];
A27 = [648, 838];
A28 = [736, 893];

outline = [A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18, A19, A20, A21, A22, A23, A24, A25, A26, A27, A28];

// Inner Points
B1 = [818, 859];
B2 = [803, 943];
B3 = [756, 1071];
B4 = [798, 1100];
B5 = [803, 1519];
B6 = [728, 1389];
B7 = [736, 1264];
B8 = [857, 1283];
B9 = [799, 1199];
B10 = [762, 908];
B11 = [761, 1129];

// Polygons
C1 = [A2, A3, A4, B1];
C2 = [A5, A6, B2, B10, B1, A4];
C3 = [B1, A2, A1, A28, B10];
C4 = [A27, A28, B10, B2, A26];
C5 = [B2, A6, A7, A8, B3];
C6 = [A9, A10, B4, B3, A8];
C7 = [A11, A12, B11, B4, A10];
C8 = [B4, B3, A24, A23, A22, B11];
C9 = [A21, B9, A13, A12, B11];
C10 = [A13, B8, B7, B9];
C11 = [B9, A21, B7];
C12 = [A21, A20, B7];
C13 = [A20, A19, B7];
C14 = [B7, A19, B6];
C15 = [B6, B7, B8];
C16 = [A13, A14, B8];
C17 = [A14, A15, B8];
C18 = [A15, B5, B8];
C19 = [B8, B5, B6];
C20 = [B6, A18, B5];
C21 = [B5, A17, A18];
C22 = [B6, A19, A18];
C23 = [A17, B5, A16];
C24 = [A16, A15, B5];
C25 = [A24, A25, A26, B2, B3];

cut_polygons = [C1, C2, C3, C4, C5, C6, C7, C8, C9, C10, C11, C12, C13, C14, C15, C16, C17, C18, C19, C20, C21, C22, C23, C24, C25];
```

I'd like the final result to be a 3D model created by extruding a 2D shape. I'd prefer to keep the design as a single `.scad` file. I don't need any external libraries for this.

[Assistant]
customizable_origami_pineapple.scad:
```
/*
 * Customizable Origami - Pineapple - https://www.thingiverse.com/thing:2728893
 * by Dennis Hofmann - https://www.thingiverse.com/mightynozzle/about
 * created 2017-12-24
 * version v1.0
 *
 * Changelog
 * --------------
 * v1.0:
 *      - final design
 * --------------
 *
 * This work is licensed under the Creative Commons - Attribution - NonCommercial - ShareAlike license.
 * https://creativecommons.org/licenses/by-nc-sa/3.0/
 */

 // Parameter Section //
//-------------------//

// preview[view:north, tilt:top]

// The maximum size of the longest side. The shorter side will be automatically resized in same ratio.
max_size_in_millimeter = 120; //[20:300]

// The height of the model.
model_height_in_millimeter = 5; //[0.2:0.2:100]

// Thickness of the outer outline.
outline_size_in_millimeter = 1.4; //[0.5:0.1:20]

// Thickness of the inner outline.
inline_size_in_millimeter = 0.7; //[0.5:0.1:20]

// Roundiness of the ends of the inner outlines.
inline_edge_radius_in_millimeter = 0.3; //[0.0:0.1:5]

// Flip model
flip_model = "no"; //[yes,no]

/*[hidden]*/
max_size = max_size_in_millimeter;
model_height = model_height_in_millimeter;
$fn=32;

// Outer Points
A1 = [665, 694];
A2 = [768, 803];
A3 = [871, 637];
A4 = [849, 833];
A5 = [899, 798];
A6 = [858, 906];
A7 = [972, 853];
A8 = [879, 988];
A9 = [936, 959];
A10 = [922, 1030];
A11 = [975, 1009];
A12 = [854, 1144];
A13 = [893, 1153];
A14 = [968, 1306];
A15 = [974, 1464];
A16 = [888, 1663];
A17 = [678, 1677];
A18 = [614, 1559];
A19 = [564, 1394];
A20 = [618, 1217];
A21 = [680, 1145];
A22 = [698, 1139];
A23 = [586, 974];
A24 = [686, 1029];
A25 = [630, 943];
A26 = [693, 942];
A27 = [648, 838];
A28 = [736, 893];

outline = [A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18, A19, A20, A21, A22, A23, A24, A25, A26, A27, A28];

// Inner Points
B1 = [818, 859];
B2 = [803, 943];
B3 = [756, 1071];
B4 = [798, 1100];
B5 = [803, 1519];
B6 = [728, 1389];
B7 = [736, 1264];
B8 = [857, 1283];
B9 = [799, 1199];
B10 = [762, 908];
B11 = [761, 1129];

// Polygons
C1 = [A2, A3, A4, B1];
C2 = [A5, A6, B2, B10, B1, A4];
C3 = [B1, A2, A1, A28, B10];
C4 = [A27, A28, B10, B2, A26];
C5 = [B2, A6, A7, A8, B3];
C6 = [A9, A10, B4, B3, A8];
C7 = [A11, A12, B11, B4, A10];
C8 = [B4, B3, A24, A23, A22, B11];
C9 = [A21, B9, A13, A12, B11];
C10 = [A13, B8, B7, B9];
C11 = [B9, A21, B7];
C12 = [A21, A20, B7];
C13 = [A20, A19, B7];
C14 = [B7, A19, B6];
C15 = [B6, B7, B8];
C16 = [A13, A14, B8];
C17 = [A14, A15, B8];
C18 = [A15, B5, B8];
C19 = [B8, B5, B6];
C20 = [B6, A18, B5];
C21 = [B5, A17, A18];
C22 = [B6, A19, A18];
C23 = [A17, B5, A16];
C24 = [A16, A15, B5];
C25 = [A24, A25, A26, B2, B3];

cut_polygons = [C1, C2, C3, C4, C5, C6, C7, C8, C9, C10, C11, C12, C13, C14, C15, C16, C17, C18, C19, C20, C21, C22, C23, C24, C25];

min_x = A19[0];
min_y = A3[1];
max_x = A11[0];
max_y = A17[1];

x_size = max_x - min_x;
y_size = max_y - min_y;

x_factor = max_size / x_size;
y_factor = max_size / y_size;

inline_size = x_size > y_size ? inline_size_in_millimeter / x_factor / 2: inline_size_in_millimeter / y_factor / 2;
inline_edge_radius = x_size > y_size ? inline_edge_radius_in_millimeter / x_factor: inline_edge_radius_in_millimeter / y_factor;
outline_size = x_size > y_size ? outline_size_in_millimeter / x_factor - inline_size: outline_size_in_millimeter / y_factor - inline_size;

 // Program Section //
//-----------------//

if(x_size > y_size) {
    resize(newsize=[max_size, x_factor * y_size, model_height]){
        if(flip_model == "yes") {
            mirror([0,1,0]) {
                rotate([180,180,0]) {
                    create(outline, cut_polygons);
                }
            }
        } else {
            create(outline, cut_polygons);
        }
    }
} else {
    resize(newsize=[y_factor * x_size, max_size, model_height]){
        if(flip_model == "yes") {
            mirror([0,1,0]) {
                rotate([180,180,0]) {
                    create(outline, cut_polygons);
                }
            }
        } else {
            create(outline, cut_polygons);
        }
    }
}

 // Module Section //
//----------------//

module create() {
    linear_extrude(height=1) {
        difference() {
            offset(r = -0) {
                offset(r = +outline_size) {
                    polygon(points = outline, convexity = 10);
                }
            }

            for(cut_polygon = [0:len(cut_polygons)]) {
                offset(r = +inline_edge_radius) {
                    offset(r = -inline_size - inline_edge_radius) {
                        polygon(points = cut_polygons[cut_polygon], convexity = 10);
                    }
                }
            }
        }
    }
}

```


[User]
Hey, I'm looking to create a customizable lattice cube in OpenSCAD, and I'd like it to be parametric. I've been playing around with a few ideas, but I'm not sure how to get it all working nicely, particularly when it comes to user-defined parameters.

Essentially, the design is a cube formed by intersecting cylindrical rods or "poles". I'd like to be able to control the following:

1.  **`cubeSize`**: The overall size of the cube (e.g. the length of one side). This should control the extent of the structure, and the grid itself will need to scale with this, not just the position of the outermost poles.
2.  **`poleThickness`**: The thickness of the cylindrical rods. This will directly impact the overall aesthetic and the structural integrity of the cube.
3.  **`gridSpacing`**: The spacing between the rods. I'd like to control how dense the grid is within the overall cube.
4.  **`numGrids`**: The number of grid layers, so I could have a cube with just two sets of intersecting poles or more. I think that will be needed for the `gridSpacing` to work well.

The rods themselves should all intersect perpendicularly. I'd like the cube to be centered at the origin.

I'm looking for a parametric OpenSCAD design, so I can easily change these values and quickly regenerate the model. I'd like for you to generate all of the required files, so I do not need to provide any. I don't need any external libraries this time - just pure OpenSCAD please. Can you help me with that?

[Assistant]
LatticeCubeCustomizer.scad:
```
//!OpenSCAD

module Grid(gridThickness) {
  union(){
    rotate([90, 0, 0]){
      {
        $fn=20;    //set sides to 20
        cylinder(r1=gridThickness, r2=gridThickness, h=98, center=true);
      }
    }
    union(){
      translate([25, 0, 0]){
        rotate([90, 0, 0]){
          {
            $fn=20;    //set sides to 20
            cylinder(r1=gridThickness, r2=gridThickness, h=98, center=true);
          }
        }
      }
      union(){
        translate([-25, 0, 0]){
          rotate([90, 0, 0]){
            {
              $fn=20;    //set sides to 20
              cylinder(r1=gridThickness, r2=gridThickness, h=98, center=true);
            }
          }
        }
        union(){
          translate([48.5, 0, 0]){
            rotate([90, 0, 0]){
              {
                $fn=20;    //set sides to 20
                cylinder(r1=gridThickness, r2=gridThickness, h=100, center=true);
              }
            }
          }
          translate([-48.5, 0, 0]){
            rotate([90, 0, 0]){
              {
                $fn=20;    //set sides to 20
                cylinder(r1=gridThickness, r2=gridThickness, h=100, center=true);
              }
            }
          }
        }
      }
    }
  }
}

translate([0, 0, (gridThickness
    )]){
  union(){
    translate([0, 50, 50]){
      rotate([90, 0, 0]){
        union(){
          rotate([0, 0, 90]){
            union(){
              translate([-25, 0, 50]){
                rotate([0, 90, 0]){
                  Grid(null);
                }
              }
              union(){
                translate([-48.6, 0, 50]){
                  rotate([0, 90, 0]){
                    Grid(null);
                  }
                }
                union(){
                  translate([25, 0, 50]){
                    rotate([0, 90, 0]){
                      Grid(null);
                    }
                  }
                  union(){
                    translate([48.5, 0, 50]){
                      rotate([0, 90, 0]){
                        Grid(null);
                      }
                    }
                    translate([0, 0, 50]){
                      rotate([0, 90, 0]){
                        Grid(null);
                      }
                    }
                  }
                }
              }
            }
          }
          union(){
            translate([-25, 0, 50]){
              rotate([0, 90, 0]){
                Grid(null);
              }
            }
            union(){
              translate([-48.6, 0, 50]){
                rotate([0, 90, 0]){
                  Grid(null);
                }
              }
              union(){
                translate([25, 0, 50]){
                  rotate([0, 90, 0]){
                    Grid(null);
                  }
                }
                union(){
                  translate([48.5, 0, 50]){
                    rotate([0, 90, 0]){
                      Grid(null);
                    }
                  }
                  translate([0, 0, 50]){
                    rotate([0, 90, 0]){
                      Grid(null);
                    }
                  }
                }
              }
            }
          }
        }
      }
    }
    union(){
      rotate([0, 0, 90]){
        union(){
          translate([-25, 0, 50]){
            rotate([0, 90, 0]){
              Grid(null);
            }
          }
          union(){
            translate([-48.6, 0, 50]){
              rotate([0, 90, 0]){
                Grid(null);
              }
            }
            union(){
              translate([25, 0, 50]){
                rotate([0, 90, 0]){
                  Grid(null);
                }
              }
              union(){
                translate([48.5, 0, 50]){
                  rotate([0, 90, 0]){
                    Grid(null);
                  }
                }
                translate([0, 0, 50]){
                  rotate([0, 90, 0]){
                    Grid(null);
                  }
                }
              }
            }
          }
        }
      }
      union(){
        translate([-25, 0, 50]){
          rotate([0, 90, 0]){
            Grid(null);
          }
        }
        union(){
          translate([-48.6, 0, 50]){
            rotate([0, 90, 0]){
              Grid(null);
            }
          }
          union(){
            translate([25, 0, 50]){
              rotate([0, 90, 0]){
                Grid(null);
              }
            }
            union(){
              translate([48.5, 0, 50]){
                rotate([0, 90, 0]){
                  Grid(null);
                }
              }
              translate([0, 0, 50]){
                rotate([0, 90, 0]){
                  Grid(null);
                }
              }
            }
          }
        }
      }
    }
  }
}
// This is the thickness of the poles on the model:
gridThickness = 5;
```


[User]
I'd like to create a parametric snowflake generator in OpenSCAD, and I have some specific ideas for how I want it to work.

The basic snowflake will consist of a central hub with primary branches radiating out.  These branches will have secondary branches, and those secondary branches can have tertiary branches. All branches should have a rectangular cross-section, effectively forming a series of thin cuboids.

I need to be able to control the following:

*   **Overall Thickness**: This will define the height (z-dimension) of the entire snowflake.
*   **Primary Branches Amount**: How many primary branches extend from the center in a circular pattern. This needs to be an integer value.
*   **Primary Branches Length**: The length of the primary branches extending from the center.
*   **Primary Branches Thickness**:  The width of the primary branches.
*   **Secondary Branches Distance**:  The spacing between secondary branches along a primary branch.
*   **Secondary Branches Angle**: The angle of the secondary branches relative to perpendicular to the primary branch (i.e. 0° means perpendicular).
*   **Secondary Branches Thickness**: The width of the secondary branches.
*   **Secondary Branches Length Scale**: A factor to scale the length of the secondary branches. The default length should be derived from their distance from the origin along the primary branch. The length is then multiplied by this scale.
*   **Tertiary Branches Distance**: The spacing between the tertiary branches along a secondary branch.
*   **Tertiary Branches Angle**: The angle of the tertiary branches relative to perpendicular to the secondary branch. 0° means perpendicular.
*   **Tertiary Branches Thickness**: The width of the tertiary branches.
*   **Tertiary Branches Length Scale**: A factor to scale the length of the tertiary branches. The default length should be derived from their distance from their secondary branch along the secondary branch. The length is then multiplied by this scale.

I want to use for loops to generate the branches. If either secondary or tertiary scaling is set to 0, then that branch level shouldn't be generated. Each secondary branch should have 2 mirrored branches and each tertiary branch should have mirrored branches as well.

The code should be well commented and easy to understand. I’m not using any external libraries here, just vanilla OpenSCAD. Can you provide the complete .scad file?

[Assistant]
Customizeable_Fractal_Snowflakes.scad:
```
//!OpenSCAD

// The height in z-direction of the snowflake
Overall_Thickness = 3;
// The amount of primary branches in a circle around the center
Primary_Branches_Amount = 7;
// The length of the primary branches
Primary_Branches_Length = 50;
// The width of the primary branches
Primary_Branches_Thickness = 3;
// The distance between two secondary branches
Secondary_Branches_Distance = 15;
// The angle between the secondary branches perpendicular to the primary branches
Secondary_Branches_Angle = 40;
// The width of the secondary branches
Secondary_Branches_Thickness = 3;
// The default length of the secondary branches is their distance from the origin. This scale factor is applied on that.
Secondary_Branches_Length_Scale = 0.8;
// The distance between two tertiary branches
Tertiary_Branches_Distance = 15;
// The angle between the tertiary branch perpendicular to their secondary branch
Tertiary_Branches_Angle = 20;
// The width of the tertiary branches
Tertiary_Branches_Thickness = 3;
// The default length of the tertiary branches is their distance from their secondary branch. This scale factor is applied on that.
Tertiary_Branches_Length_Scale = 0.5;
translate([0, 0, (Overall_Thickness / 2)]){
  for (i = [0 : abs(360 / Primary_Branches_Amount) : 360]) {
    rotate([0, 0, i]){
      translate([(Primary_Branches_Length / 2), 0, 0]){
        cube([Primary_Branches_Length, Primary_Branches_Thickness, Overall_Thickness], center=true);
      }
      if (Secondary_Branches_Length_Scale > 0) {
        for (j = [Primary_Branches_Length / 10 : abs(Secondary_Branches_Distance) : Primary_Branches_Length]) {
          Secondary_Branch_Length = j * Secondary_Branches_Length_Scale;
          translate([0, 0, 0]){
            translate([(j + (Secondary_Branch_Length * sin(Secondary_Branches_Angle)) / 2), ((Secondary_Branch_Length / 2) * cos(Secondary_Branches_Angle)), 0]){
              rotate([0, 0, (-1 * Secondary_Branches_Angle)]){
                cube([Secondary_Branches_Thickness, Secondary_Branch_Length, Overall_Thickness], center=true);
                if (Tertiary_Branches_Length_Scale > 0) {
                  for (k = [Secondary_Branch_Length / 2 : abs(Tertiary_Branches_Distance) : Secondary_Branch_Length]) {
                    Tertiary_Branch_Length = k * Tertiary_Branches_Length_Scale;
                    translate([0, 0, 0]){
                      translate([((Tertiary_Branch_Length / 2) * cos(Tertiary_Branches_Angle)), ((k + (Tertiary_Branch_Length * sin(Tertiary_Branches_Angle)) / 2) - Secondary_Branch_Length / 2), 0]){
                        rotate([0, 0, Tertiary_Branches_Angle]){
                          cube([Tertiary_Branch_Length, Tertiary_Branches_Thickness, Overall_Thickness], center=true);
                        }
                      }
                      mirror([1,0,0]){
                        translate([((Tertiary_Branch_Length / 2) * cos(Tertiary_Branches_Angle)), ((k + (Tertiary_Branch_Length * sin(Tertiary_Branches_Angle)) / 2) - Secondary_Branch_Length / 2), 0]){
                          rotate([0, 0, Tertiary_Branches_Angle]){
                            cube([Tertiary_Branch_Length, Tertiary_Branches_Thickness, Overall_Thickness], center=true);
                          }
                        }
                      }
                    }
                  }

                }

              }
            }
            mirror([0,1,0]){
              translate([(j + (Secondary_Branch_Length * sin(Secondary_Branches_Angle)) / 2), ((Secondary_Branch_Length / 2) * cos(Secondary_Branches_Angle)), 0]){
                rotate([0, 0, (-1 * Secondary_Branches_Angle)]){
                  cube([Secondary_Branches_Thickness, Secondary_Branch_Length, Overall_Thickness], center=true);
                  if (Tertiary_Branches_Length_Scale > 0) {
                    for (k = [Secondary_Branch_Length / 2 : abs(Tertiary_Branches_Distance) : Secondary_Branch_Length]) {
                      Tertiary_Branch_Length = k * Tertiary_Branches_Length_Scale;
                      translate([0, 0, 0]){
                        translate([((Tertiary_Branch_Length / 2) * cos(Tertiary_Branches_Angle)), ((k + (Tertiary_Branch_Length * sin(Tertiary_Branches_Angle)) / 2) - Secondary_Branch_Length / 2), 0]){
                          rotate([0, 0, Tertiary_Branches_Angle]){
                            cube([Tertiary_Branch_Length, Tertiary_Branches_Thickness, Overall_Thickness], center=true);
                          }
                        }
                        mirror([1,0,0]){
                          translate([((Tertiary_Branch_Length / 2) * cos(Tertiary_Branches_Angle)), ((k + (Tertiary_Branch_Length * sin(Tertiary_Branches_Angle)) / 2) - Secondary_Branch_Length / 2), 0]){
                            rotate([0, 0, Tertiary_Branches_Angle]){
                              cube([Tertiary_Branch_Length, Tertiary_Branches_Thickness, Overall_Thickness], center=true);
                            }
                          }
                        }
                      }
                    }

                  }

                }
              }
            }
          }
        }

      }

    }
  }

}
```