[User]
I'd like to design a parametric birdhouse in OpenSCAD, and I need some help getting started.

The basic shape of the birdhouse should be a cylinder with a semi-circular roof. I'd like to make it so the main dimensions can be adjusted easily. Specifically, I need to control the `house_length`, which should be the width of the flat front of the house, and this also determines the radius of the semicircle roof. The depth of the house should be double the radius of the semicircle. I also need to control `wall_thickness` so I can adjust the printing parameters and overall size of the house.

There should be a circular entrance hole, and I need to be able to adjust the `door_radius` and `door_above_floor` (the distance from the bottom of the house to the bottom of the door). Around the door, I want a small ring to prevent birds from being injured on the edge, and I need to be able to control this `door_ring_radius`.

Finally, I want a way to hang the birdhouse using two rings and the `hang_ring_radius` needs to be adjustable as well. The roof should be a separate piece that fits snugly over the top of the main birdhouse body, and I want to make sure I can adjust the `wall_thickness` to control how tight this fit will be.

I think a useful feature would be the ability to add small air holes, controlled by a boolean variable.

So, to summarize, I need to be able to adjust these parameters:

-   `house_length`
-   `wall_thickness`
-   `door_radius`
-   `door_above_floor`
-   `door_ring_radius`
-   `hang_ring_radius`
-   `air_holes` (boolean)

Could you generate an OpenSCAD file (or files if that is easier) to achieve this? I don't need to use any special libraries, it can all be done with built-in functions.

[Assistant]
bird_house.scad:
```
house_length = 150;
wall_thickness = 1.5;
door_radius = 27.5;
door_above_floor = 30;
door_ring_radius = 4;
hang_ring_radius = 5;
air_holes = "YES"; // [YES, NO]

// Given a `radius` and `angle`, draw an arc from zero degree to `angle` degree. The `angle` ranges from 0 to 90.
// Parameters:
//     radius - the arc radius
//     angle - the arc angle
//     width - the arc width
module a_quarter_arc(radius, angle, width = 1) {
    outer = radius + width;
    intersection() {
        difference() {
            offset(r = width) circle(radius, $fn=48);
            circle(radius, $fn=48);
        }
        polygon([[0, 0], [outer, 0], [outer, outer * sin(angle)], [outer * cos(angle), outer * sin(angle)]]);
    }
}

// Given a `radius` and `angles`, draw an arc from `angles[0]` degree to `angles[1]` degree.
// Parameters:
//     radius - the arc radius
//     angles - the arc angles
//     width - the arc width
module arc(radius, angles, width = 1) {
    angle_from = angles[0];
    angle_to = angles[1];
    angle_difference = angle_to - angle_from;
    outer = radius + width;
    rotate(angle_from)
        if(angle_difference <= 90) {
            a_quarter_arc(radius, angle_difference, width);
        } else if(angle_difference > 90 && angle_difference <= 180) {
            arc(radius, [0, 90], width);
            rotate(90) a_quarter_arc(radius, angle_difference - 90, width);
        } else if(angle_difference > 180 && angle_difference <= 270) {
            arc(radius, [0, 180], width);
            rotate(180) a_quarter_arc(radius, angle_difference - 180, width);
        } else if(angle_difference > 270 && angle_difference <= 360) {
            arc(radius, [0, 270], width);
            rotate(270) a_quarter_arc(radius, angle_difference - 270, width);
       }
}

// Given a `radius` and `angle`, draw a sector from zero degree to `angle` degree. The `angle` ranges from 0 to 90.
// Parameters:
//     radius - the sector radius
//     angle - the sector angle
module a_quarter_sector(radius, angle) {
    intersection() {
        circle(radius, $fn=96);

        polygon([[0, 0], [radius, 0], [radius, radius * sin(angle)], [radius * cos(angle), radius * sin(angle)]]);
    }
}

// Given a `radius` and `angle`, draw a sector from `angles[0]` degree to `angles[1]` degree.
// Parameters:
//     radius - the sector radius
//     angles - the sector angles
module sector(radius, angles) {
    angle_from = angles[0];
    angle_to = angles[1];
    angle_difference = angle_to - angle_from;

    rotate(angle_from)
        if(angle_difference <= 90) {
            a_quarter_sector(radius, angle_difference);
        } else if(angle_difference > 90 && angle_difference <= 180) {
            sector(radius, [0, 90]);
            rotate(90) a_quarter_sector(radius, angle_difference - 90);
        } else if(angle_difference > 180 && angle_difference <= 270) {
            sector(radius, [0, 180]);
            rotate(180) a_quarter_sector(radius, angle_difference - 180);
        } else if(angle_difference > 270 && angle_difference <= 360) {
            sector(radius, [0, 270]);
            rotate(270) a_quarter_sector(radius, angle_difference - 270);
       }
}

// 2D module, composed of a semi-circle and a square. The square's length is equal to the circle radius.
//
// Parameters:
//     house_radius - the semi-circle radius of the house
module bird_house_2d_contour(house_radius) {
    sector(house_radius, [0, 180], 1);
    translate([0, -house_radius / 2, 0])
	    square([house_radius * 2, house_radius], center = true);
}

// The brid house with no top. The door radius is 1/2 `house_radius`.
// The house depth is double `house_radius`.
// Choose a suitable `door_ring_radius` for your bird's claw size.
//
// Parameters:
//     house_radius - the semi-circle radius of the house
//     door_ring_radius - the ring radius on the door
//     wall_thickness - the wall thicnkess.
module bird_house_body(house_radius, door_radius, door_above_floor, door_ring_radius, wall_thickness) {
    house_depth = house_radius * 2;

	difference() {
	    // create the room
		linear_extrude(house_depth)
			bird_house_2d_contour(house_radius);

		translate([0, 0, wall_thickness])
			linear_extrude(house_depth - wall_thickness * 2)
				bird_house_2d_contour(house_radius - wall_thickness);

		// remove the top
        translate([0, -house_radius + wall_thickness, 0]) rotate([90, 0, 0])
		    linear_extrude(wall_thickness * 2)
		        translate([-house_radius, 0, 0])
				    square(house_radius * 2);

		// create a door
		translate([0, door_radius - door_above_floor, wall_thickness])
		    linear_extrude(house_depth)
			    circle(door_radius);
	}

	// create the door ring
	translate([0, door_radius - door_above_floor, house_radius * 2])
		rotate_extrude(convexity = 10)
			translate([door_radius + door_ring_radius, 0, 0])
				circle(door_ring_radius, $fn = 24);
}

// The top cover of the bird house.
//
// Parameters:
//     length - the length of the cover side
//     wall_thickness - the wall thicnkess.
module bird_house_cover(length, wall_thickness) {
    spacing = 0.6;
	five_wall_thickness = wall_thickness * 5;
	scale = 0.95;

	// the outer cover
	difference() {
		linear_extrude(five_wall_thickness)
			square(length, center = true);

		linear_extrude(five_wall_thickness, scale = scale)
			square(length - wall_thickness * 2, center = true);
	}

	// the inner cover
	linear_extrude(five_wall_thickness, scale = scale)
		square(length - (wall_thickness + spacing) * 2, center = true);
}

// The hang ring of the bird house.
//
// Parameters:
//     ring_radius - the radius of the hang ring
//     house_radius - the semi-circle radius of the house
//     wall_thickness - the wall thicnkess.
module hang_ring(ring_radius, house_radius, wall_thickness) {
    offset = (house_radius - 0.525 * wall_thickness) / 0.475 / 2;

    translate([offset, -house_radius - wall_thickness * 2, offset])
	    rotate([0, 90, -90])
	        linear_extrude(wall_thickness * 2)
		        arc(ring_radius, [0, 180], wall_thickness * 2);
}

// A bird house.
// The door radius is 1/2 `house_radius`.
// The house depth is double `house_radius`.
// Choose a suitable `door_ring_radius` for your bird's claw size.
//
// Parameters:
//     ring_radius - the radius of the hang ring
//     house_radius - the semi-circle radius of the house
//     door_ring_radius - the ring radius on the door.
//     wall_thickness - the wall thicnkess.
module bird_house(house_length, door_radius, door_above_floor, hang_ring_radius, door_ring_radius, wall_thickness) {
    house_radius = house_length / 2;

    bird_house_body(house_radius, door_radius, door_above_floor, door_ring_radius, wall_thickness);

    length = (house_radius - 0.525 * wall_thickness) / 0.475;

    translate([0, -house_radius - wall_thickness * 4, house_radius])
        rotate([-90, 0, 0])
            bird_house_cover(length, wall_thickness);

    hang_ring(hang_ring_radius, house_radius, wall_thickness);
    mirror([1, 0, 0])
	    hang_ring(hang_ring_radius, house_radius, wall_thickness);
}

difference() {
	rotate([90, 0, 0])
		bird_house(house_length, door_radius, door_above_floor, hang_ring_radius, door_ring_radius, wall_thickness);

	if(air_holes == "YES") {
		// air holes
		union() {
			translate([0, 0, -house_length / 3]) sphere(door_radius * 0.25);
			translate([house_length / 3, 0, -house_length / 3]) sphere(door_radius * 0.25);
			translate([-house_length / 3, 0, -house_length / 3]) sphere(door_radius * 0.25);

			translate([0, -house_length, -house_length / 2.5]) sphere(door_radius * 0.25);
			translate([house_length / 3, -house_length, -house_length / 3]) sphere(door_radius * 0.25);
			translate([-house_length / 3, -house_length, -house_length / 3]) sphere(door_radius * 0.25);
		}
	}
}

```


[User]
Okay, I'm looking to design a simple latch lock in OpenSCAD, and I'd like it to be parametric so I can easily adjust the dimensions for different projects. I have a rough idea of the design, which I'll describe below. It should be pretty easy to 3D print with no supports needed.

The lock is composed of three main parts: a base, a top piece, and a hook.

The **base** is a rectangular block with rounded corners (using minkowski sum) and has four mounting holes for screws. It should also have a cylindrical pillar in the center of the base. There should be a shorter, smaller-diameter cylinder placed concentrically below the main pillar.

The **top piece** is a flat cylinder, which fits over the central pillar on the base. It should have a hole for one of the mounting screws. This will attach to one of the two bases you'll need to print.

The **hook** is a bit more complex. It should have a central cylindrical portion that can move vertically within the pillars on the base. Extending from this central portion, it should have a tab that runs into the gap between the two bases. At the end of the hook, there should be a small, angled tab which will engage into the receiving base.

Here are the parameters I'd like to be able to adjust:

**Base Settings:**
*   `BaseHeight`: The height of the rectangular base.
*   `BaseLength`: The length of the rectangular base.
*   `BaseWidth`: The width of the rectangular base.
*   `MountingHoles`: The diameter of the mounting holes.

**Pillar Settings:**
*   `CylHeight`: The height of the main cylindrical pillar.
*    `Spacing`: The amount of space between the cylindrical pillar of the base and the mating surface of the top piece and hook.

**Hook Settings:**
*   `HookLength`: The length of the hook arm.
*   `TabLength`: The length of the tab at the end of the hook.

**Hidden/Constant Settings:**
*   `TabWidth`: The width of the hook tab (this one is not meant to be customizable by the end user).

I'd like to be able to select between generating only the base, the top, the hook, or all parts together to see them assembled. I'm assuming each part will be centered at the origin. So, please provide a single .scad file with all three modules, that takes these parameters and produces the described latch lock.

[Assistant]
LatchLock.scad:
```
// Which one would you like to see?
part = "all"; // [first:Base Only,second:Top Only,third:Hook only,all:All]

/* [Base Settings] */
BaseHeight=5;
BaseLength=45;
BaseWidth=35;
//This one applies also to the hole to set the top on to the base.
MountingHoles=4;
/* [Pillar Settings] */
CylHeight=15;
Spacing=.3;
/* [Hook Settings] */
HookLength=30;
TabLength=15;
/* [Hidden] */
TabWidth=5;
print_part();

module print_part(){
    if(part=="first"){
        Base(BaseHeight,BaseLength,BaseWidth,MountingHoles,CylHeight);
    }
    else if(part=="second"){
        translate([0,0,BaseHeight/2+Spacing+CylHeight-CylHeight/5]) Top(BaseHeight,MountingHoles);
    }
    else if(part=="third"){
        translate([0,0,CylHeight/5]) Hook(HookLength,BaseHeight,BaseWidth,TabLength,CylHeight,Spacing);
    }
    else if(part=="all"){
        Base(BaseHeight,BaseLength,BaseWidth,MountingHoles,CylHeight);
translate([0,0,BaseHeight/2+Spacing+CylHeight-CylHeight/5]) Top(BaseHeight,MountingHoles);
translate([0,0,CylHeight/5]) Hook(HookLength,BaseHeight,BaseWidth,TabLength,CylHeight,Spacing);
    }
}

module Base(BaseHeight,BaseLength,BaseWidth,MountingHole,CylHeight){
    union(){difference(){
        minkowski(){
            cube([BaseLength-10,BaseWidth-10,BaseHeight-1],center=true);
            cylinder(r=5,h=1);
        }
        translate([BaseLength/3,BaseWidth/3,-BaseHeight/2+0.5]) cylinder(h=BaseHeight,r=MountingHoles/2);
        translate([BaseLength/3,-BaseWidth/3,-BaseHeight/2+0.5]) cylinder(h=BaseHeight,r=MountingHoles/2);
        translate([-BaseLength/3,-BaseWidth/3,-BaseHeight/2+0.5]) cylinder(h=BaseHeight,r=MountingHoles/2);
        translate([-BaseLength/3,BaseWidth/3,-BaseHeight/2+0.5]) cylinder(h=BaseHeight,r=MountingHoles/2);
    }
    difference(){
        union(){
            if(BaseLength<BaseWidth){
                translate([0,0,BaseHeight/2]) cylinder(r=BaseLength/3,h=(CylHeight/5));
                translate([0,0,BaseHeight/2+CylHeight/5]) cylinder(r=BaseLength/4-0.2,h=(CylHeight+Spacing)-((CylHeight/5)*2));
            }
            else{
                translate([0,0,BaseHeight/2]) cylinder(r=BaseWidth/3,h=(CylHeight/5));
                translate([0,0,BaseHeight/2+CylHeight/5]) cylinder(r=BaseWidth/4-0.2,h=(CylHeight+Spacing)-((CylHeight/5)*2));
            }

        }
            translate([0,0,(BaseHeight/2)+CylHeight-(CylHeight/1.5)+Spacing]) cylinder(r=MountingHoles/2,h=CylHeight/1.5);
        }
    }
}

module Top(BaseHeight,MountingHoles){
    if(BaseLength<BaseWidth){
                difference(){
                cylinder(r=BaseLength/3,h=CylHeight/5);
        cylinder(r=MountingHoles/2,h=CylHeight/5);
            }
        }
            else{
                difference(){
                cylinder(r=BaseWidth/3,h=CylHeight/5);
        cylinder(r=MountingHoles/2,h=CylHeight/5);
            }
    }
}

module Hook(HookLength,BaseHeight,BaseWidth,TabLength,CylHeight,Spacing){
            if(BaseLength<BaseWidth){
                difference(){
                translate([0,0,BaseHeight/2+Spacing/2]) cylinder(r=BaseLength/3,h=(CylHeight)-(2*(CylHeight/5)));
                 translate([0,0,BaseHeight/2+Spacing/2]) cylinder(r=BaseLength/4,h=(CylHeight-(2*(CylHeight/5))));
                }
            }
            else{
                difference(){
                translate([0,0,BaseHeight/2+Spacing/2]) cylinder(r=BaseWidth/3,h=(CylHeight-(2*(CylHeight/5))));
                    translate([0,0,BaseHeight/2+Spacing/2]) cylinder(r=BaseWidth/4,h=(CylHeight-(2*(CylHeight/5))));}
            }
        if(BaseLength<BaseWidth){
                translate([BaseLength/3-BaseLength/24,-TabWidth/2,BaseHeight/2+Spacing/2]) cube([HookLength,TabWidth,CylHeight-(2*(CylHeight/5))]);
            }
            else{
                translate([BaseWidth/3-BaseWidth/24,-TabWidth/2,BaseHeight/2+Spacing/2]) cube([HookLength,TabWidth,CylHeight-(2*(CylHeight/5))]);
            }
            if(BaseLength<BaseWidth){
                union(){
                translate([HookLength-BaseLength/12+BaseLength/1.5,1.5,BaseHeight/2+Spacing/2]){difference(){
                cylinder(r=BaseLength/3,h=(CylHeight)-(2*(CylHeight/5)));
                cylinder(r=BaseLength/4,h=(CylHeight-(2*(CylHeight/5))));
                translate([-BaseLength/3,-BaseLength/3-4,0]) cube([BaseLength/1.5,BaseLength/3,CylHeight-(2*(CylHeight/5))]);
                }
                translate([BaseLength/3-BaseLength/24,-4,0]) cube([TabLength,TabWidth,(CylHeight-(2*(CylHeight/5)))]);
            }
            }
            }
            else{
                union(){
                translate([HookLength-BaseWidth/12+BaseWidth/1.5,1.5,BaseHeight/2+Spacing/2]){difference(){
                cylinder(r=BaseWidth/3,h=(CylHeight)-(2*(CylHeight/5)));
                cylinder(r=BaseWidth/4,h=(CylHeight-(2*(CylHeight/5))));
                translate([-BaseWidth/3,-BaseWidth/3-4,0]) cube([BaseWidth/1.5,BaseWidth/3,CylHeight-(2*(CylHeight/5))]);
                }
                translate([BaseWidth/3-BaseWidth/24,-4,0]) cube([TabLength,TabWidth,(CylHeight-(2*(CylHeight/5)))]);
            }
            }
            }
}

/*Base(BaseHeight,BaseLength,BaseWidth,MountingHoles,CylHeight);
translate([0,0,BaseHeight/2+Spacing+CylHeight-CylHeight/5]) Top(BaseHeight,MountingHoles);
translate([0,0,CylHeight/5]) Hook(HookLength,BaseHeight,BaseWidth,TabLength,CylHeight,Spacing);
*/

```


[User]
I'd like to create a customizable battery box in OpenSCAD. I need a box with a specified width, length, and battery hole depth. The battery holes themselves need to be able to accept different sizes; I'm thinking in terms of diameter. I'd like to be able to control the minimum wall and bottom thickness as well. I'd like to be able to pack as many battery holes into the box as will reasonably fit, based on the chosen hole diameter and wall thickness. So, in particular, I’ll need the code to automatically calculate the number of holes in each dimension, and then the spacing between each hole and the edge of the box based on those numbers.

The basic idea is this: I want to specify the outer dimensions of the box, the diameter of the holes, the depth of the holes, and the minimum wall/bottom thickness. Then, the script should figure out how many batteries of that diameter will fit in the box, then calculate the precise positioning of those holes to center them and ensure there's a consistent gap between holes.

Can you create that for me, please? I don't have any particular preference on external libraries, other than that I would prefer one which is fairly common.

[Assistant]
BatteryBox.scad:
```
// variable description
// Width of the Box
box_width=87;

// Length of the Box
box_length=102;

// Depth of the battery hole
hole_depth=15;

// Diameter of the hole: AAA=10.5 AA=14.5
hole_diameter=11;

// Minimum wall and bottom thickness
wall_size=5; // [2:1:5]

/* [Hidden] */
$fn=50;
bottom=wall_size-2;

difference () {
hull () {
    union () {
        translate ([wall_size,wall_size,0]) cylinder(hole_depth-bottom,wall_size,wall_size);
        translate([wall_size,wall_size,hole_depth-bottom]) sphere(wall_size);
    }
    union () {
        translate ([box_width-wall_size,wall_size,0]) cylinder(hole_depth-bottom,wall_size,wall_size);
        translate([box_width-wall_size,wall_size,hole_depth-bottom]) sphere(wall_size);
    }
    union () {
        translate ([wall_size,box_length-wall_size,0]) cylinder(hole_depth-bottom,wall_size,wall_size);
        translate([wall_size,box_length-wall_size,hole_depth-bottom]) sphere(wall_size);
    }
    union () {
        translate ([box_width-wall_size,box_length-wall_size,0]) cylinder(hole_depth-bottom,wall_size,wall_size);
        translate([box_width-wall_size,box_length-wall_size,hole_depth-bottom]) sphere(wall_size);
    }
}

anzb=round(((box_width-2*wall_size)/(hole_diameter+0.2))-0.5);
anzl=round(((box_length-2*wall_size)/(hole_diameter+0.2))-0.5);
vx=((box_width-2*wall_size)-anzb*hole_diameter)/(anzb+1);
vy=((box_length-2*wall_size)-anzl*hole_diameter)/(anzl+1);

for(y=[0:anzl-1]) {
    for(x=[0:anzb-1]) {
        #translate([vx+wall_size+hole_diameter/2+x*(hole_diameter+vx),vy+wall_size+hole_diameter/2+y*(hole_diameter+vy),wall_size-bottom]) cylinder(hole_depth,hole_diameter/2,hole_diameter/2);
    }
}
}
```


[User]
Okay, I'd like to design a parametric tablet stand. I have some specific ideas in mind and a few different component types, and I need a way to generate these in OpenSCAD.

The main structure will be built using "tubes" which are essentially cylinders with some thickness. I need several types: a straight tube, and a "bent" tube. The straight tube should be able to be placed in different orientations relative to the X,Y, and Z axes. The stand should be created by combining several of these tubes.

I'd like to be able to specify the length of each tube with variables. So, for example, I might have variables like `front_length`, `back_length`, `top_length`, `left_length`, and `right_length`. Each of these will determine the length of a straight tube. There should also be a way to set the diameter of the tube, like `tube_diameter`.

For the straight tubes, I need to be able to define a "thickness," which should be the distance between the outer diameter and the inner diameter of the tube. Let's call this variable `tube_thickness`. The tube inner diameter should always be a consistent ratio with the outer diameter, using something like 90% and 75% for the inner and inner-inner diameters of the tubes.

Then I also need a bent tube. It should be bent along one axis, and I'd like to be able to set the angle of the bend as a variable, something like `bend_angle`. It should also be able to have a diameter specified. Let's call that `bend_diameter`. Like with the straight tubes, I need to be able to set the thickness of the bent tube.

I want to use the straight and bent tubes to create several different stand configurations.
I want the following stand type options:
*   **"5tube"**: This is the most complex configuration and includes front, back, left, right, and top tubes, all connected in a sort of rectangular frame.
*   **"4tube"**: This will have front, back, left, and top tubes, omitting the right tube.
*   **"3tubel"**: This will have front, back, and left tubes, all lying on their side.
*   **"3tubes"**: This will have front, back, and top tubes, all standing up, like a simple "U" shape.
*   **"tube"**: Just a single straight tube.
*   **"bend"**: Just a single bent tube.

I was thinking of using a single module called `xtube` which uses different `type` parameters (1-4) to generate the 4 stand versions that require several tubes. I would like the ability to use `difference()` to create the hollow tubes. I would like the base of all the tube configurations to use the `cube()` module to act as a support for the tube shapes. The base should be able to have its dimensions be based off of the different `length` parameters.

Could you generate OpenSCAD code that can produce these components and allow me to generate the different stand configurations with all of these parameters? I don't need any external libraries.

[Assistant]
Tabletstand.scad:
```
// variable description
// Which part?
part = "5tube"; // [5tube:5 Tube,4tube:4 Tube,3tubel:3 Tube lying,3tubes:3 Tube standing,tube:Single pipe,bend:Bend pipe]

// Length of front tube
lf=15; // [10:50]

// Length of back tube
lb=15; // [10:50]

// Length of top tube
lt=15; // [10:50]

// Length of left tube
ll=15; // [10:50]

// Length of right tube
lr=15; // [10:50]

// Diameter of tube
r1=10; // [5:50]

// Thickness of endtube
sf=3; // [1:10]

// Angle of bent tube
w=30;

// Diameter of bent tube
d=40;

/* [Hidden] */
r2=r1*0.9;
r3=r1*0.75;
$fn=50;
f=10;

if(part=="4tube") xtube(1);
else if(part=="3tubel") xtube(2);
else if(part=="3tubes") xtube(3);
else if(part=="5tube") xtube(4);
else if(part=="tube") tube(ts);
else if(part=="bend") bend();

/*xtube(2);
translate([s,0,0]) tube(30);
translate([-s,0,0]) tube(30);
translate([s+30,0,0]) xtube(1);
translate([-s-30,0,0]) xtube(1);
rotate ([0,0,90]) translate([53,0,0]) tube(70);
rotate ([0,0,90]) translate([106,0,0]) xtube(3);
rotate ([0,90,0]) translate([-s+10,106,0]) tube(5);
rotate ([90,0,90]) translate([106-40,s-5,0]) bend();
*/

module xtube(type) {
difference() {
    drawtube(type,false);
    drawtube(type,true);
    }
}

module drawtube(type,del) {
    // front tube
    s_tube(lf,0,0, lf,0,90,0,del);

    // back tube
    s_tube(lb,0,0,-lb,0,90,0,del);

    // left tube
    if(type==1 || type==2 || type==4) {
        s_tube(ll,0,0,-ll,90,0,0,del);
        if(!del) rotate([0,0,90]) translate([ll/2+sf/2,0,-r1+sf/2]) cube([ll+sf,5,sf],true); }

    // right tube
    if(type==4) {
        s_tube(lr,0,0,lr,90,0,0,del);
        if(!del) rotate([0,0,90]) translate([-lr/2-sf/2,0,-r1+sf/2]) cube([lr+sf,5,sf],true); }

    // top tube
    if(type==1 || type==3 || type==4) s_tube(lt,0,0,lt,0,0,90,del);

    // bottom
    if(!del) translate([(lf-lb)/2,0,-r1+sf/2]) cube([lf+lb+2*sf,5,sf],true);
}

module s_tube(l,x,y,z,wx,wy,wz,del) {
    xf=x!=0?(x>0?sf:-sf):0;
    yf=y!=0?(y>0?sf:-sf):0;
    zf=z!=0?(z>0?sf:-sf):0;
    echo(x,y,z,xf,yf,zf);
    if(!del) union() {
        rotate([wx,wy,wz]) translate([x/2,y/2,z/2]) cylinder(l,r2,r2,true);
        rotate([wx,wy,wz]) translate([x+xf/2,y+yf/2,z+zf/2]) cylinder(sf,r1,r1,true);
    }
    if(del) rotate([wx,wy,wz]) translate([x/2+xf/2,y/2+yf/2,z/2+zf/2]) cylinder(l+sf,r3,r3,true);
}

module bend() {
    rotate ([90,0,0]) translate([-d,0,0])
    difference() {
    union() {
        rotate_extrude(angle=w,convexity=10) translate([d, 0, 0]) circle(r=r2);
        rotate([90,0,0]) translate([d,0,sf/2]) cylinder(sf,r1,r1,true);
        rotate([90,0,w]) translate([d,0,-sf/2]) cylinder(sf,r1,r1,true);
    }
        rotate_extrude(angle=w,convexity=10)
        translate([d, 0, 0])
        circle(r=r3);

        rotate([90,0,0]) translate([d,0,sf/2]) cylinder(sf+0.1,r3,r3,true);
        rotate([90,0,w]) translate([d,0,-sf/2]) cylinder(sf+0.1,r3,r3,true);
}
}

```


[User]
Hey, I'm working on a 3D scanner project and need a parametric laser mount. I've got a basic design I've been using, but it's not very flexible. I'm looking to improve on this design with the goal of greater customizability through parameters.

Here's the breakdown of the existing design I want to improve:

It's a mount designed to attach a cylindrical laser module to a flat plate. The main body of the mount is basically a box with a cylindrical cutout for the laser. It also has a cutout to allow it to fit around the plate itself. The current version uses a few hardcoded values for the size of the laser, plate thickness, mount length, and wall thickness. I want these to be parameters in the new design. I'd like the ability to customize:

*   `nozzleRadius`: This is a small value and it's just used to generate a small offset for the laser.
*   `plateThickness`: The thickness of the plate the mount will attach to.
*   `mountLength`: How far the mount extends beyond the plate.
*   `wallThickness`: The thickness of the mount walls, a consistent thickness for all walls.
*   `laserRadius`: The radius of the laser module being mounted.
*   I'd also like to control the mount's overall `height`, `width`, and `length` through other parameters rather than relying on them being dependent variables.
*  I would also like to define an offset or `play` between the laser cutout and the radius of the laser module.

The design should have the mount body, a cutout for the laser, and a cutout for the plate. The laser cutout should be a cylinder, and the plate cutout should be a box shape.

I think that's about it. Could you generate an OpenSCAD file or files for this? I'm not sure if there's a particular library that might be helpful. I'm fine using whatever's appropriate. I want to be able to adjust all the dimensions as well as the `play` parameter.

[Assistant]
laser_mount.scad:
```
$fn = 100;

nozzleRadius = 0.35 / 2;
play = nozzleRadius;

plateThickness = 18.3;
mountLength = 15;
wallThickness = 3;
laserRadius = 12.09 / 2;

height = 2 * wallThickness + 2 * laserRadius;
width = 2 * wallThickness + plateThickness;
length = wallThickness + mountLength;

laserMount();

module laserMount()
{
    rotate([90, 0, 0])  //  Rotate the design to the most favourable orientation for FDM
    {
        difference()
        {
            union()
            {
                cube([width, length, height]);  //  Start with the base for the mount
                translate([-laserRadius, 0, wallThickness + laserRadius])
                {
                    rotate([-90, 0, 0])
                    {
                        cylinder(r = laserRadius + wallThickness, h = length);  //  Base for the laser mount
                    }
                }
            }
            translate([wallThickness, wallThickness, -0.1])
            {
                cube([plateThickness, mountLength + 0.1, height + 0.2]); // Cut out the shape of the plate the design is attached to
            }
            translate([-laserRadius, 0, wallThickness + laserRadius])
            {
                rotate([-90, 0, 0])
                {
                    translate([0, 0, -0.1])
                    {
                        cylinder(r = laserRadius + play, h = length + 0.2);   //  Cut out the shape of the laser with a little play to provide a nice fit
                    }
                }
            }
        }
    }
}
```


[User]
Hey, I'm looking to get a battery holder design made in OpenSCAD. I've got some 18650 Li-ion batteries that I use for projects and want a good, configurable way to hold them together.

Basically, I need a grid-style holder that can be adjusted for different numbers of batteries. Each battery should have its own cylindrical slot, and the holder needs to have a base and some small supports around the top of each battery to keep them from moving around too much.

Here are the parameters I need to be able to configure:

*   **`holesize`**: The diameter of the battery hole. I'm thinking 19mm is good for 18650s, but I need to be able to adjust this for other battery sizes if needed.
*   **`alt`**: The height of the base of the holder, let's say 4mm as a starting value.
*   **`supalt`**: The height of the support structure at the top of each battery, maybe 1mm to start.
*   **`varx`**: The number of batteries in the X direction.
*   **`vary`**: The number of batteries in the Y direction.
*   **`filler`**: A way to add some optional "filler" material between the batteries. I was thinking maybe some small cylinders or a star shape, but this is something I might want to set to "none" too. I'd like three options here, `0` for none, `1` for cylinders, `2` for stars.
*   **`$fn`**: I'd like to control the resolution of the circles and cylinders using `$fn`. I usually set this to `100` for high quality, and maybe `20` for something quick to render and test out.

So, I'd like a parametric OpenSCAD design that lets me specify all of these parameters.  For the "star" shaped filler, I envision something like a small cube with small cylinders cut out from each face.

I'm not sure what other modules might be useful, but please use the standard OpenSCAD library and anything else you might need. Let me know if you have questions.

[Assistant]
batterypackholder.scad:
```
//
// Parametric Battery Pack Holder
// ------------------------------
//
// Created by Joao Alves (jpralves@gmail.com)
// ------------------------------------------
//
// Parameters:

// Hole Diameter (19 for 18650 Li-ion Battery)
holesize = 19; // [5:0.1:25]
// Support Height
alt = 4; // [2:6]
// End Support Height
supalt = 1; // [1:2]

// Number of X Batteries
varx = 2; // [1:9]
// Number of Y Batteries
vary = 3; // [1:9]

// Filler Type between Batteries
filler=2; // [0:None, 1:Circle, 2:Star]
// Level of Detail
$fn=100; // [20:Low Res, 50:Normal Res, 100:Hi Res]

bateria(varx,vary);

module bateria(x,y) {

  unitspace= holesize+holesize/10;

  rotate([0,180,0])
  for (i = [0 : 1 : x-1]) {
    for (j = [0 : 1 : y-1]) {
        translate([i*unitspace,j*unitspace,0]) {

        difference() {
          union() {
              difference() {
                cube([unitspace,unitspace,alt]);
                translate([(unitspace)/2,(unitspace)/2,-0.1])
                  cylinder(h=alt+1,d=holesize);
              }
              difference() {
                union() {
                  translate([0,0,alt])
                    cube([holesize/2,holesize/2,supalt]);
                  translate([unitspace-holesize/2,0,alt])
                    cube([holesize/2,holesize/2,supalt]);
                  translate([0,unitspace-holesize/2,alt])
                    cube([holesize/2,holesize/2,supalt]);
                  translate([unitspace-holesize/2,unitspace-holesize/2,alt])
                    cube([holesize/2,holesize/2,supalt]);
                }
                union() {
                  translate([(unitspace)/2,(unitspace)/2,-0.1])
                    cylinder(h=alt+supalt+2,d=holesize-holesize/5);
                }
              }
          }

          if (filler==1) {
              union() {
                translate([0,0,-0.1])
                  cylinder(h=alt+supalt+2,d=holesize/3);
                translate([unitspace,0,-0.1])
                  cylinder(h=alt+supalt+2,d=holesize/3);
                translate([0,unitspace,-0.1])
                  cylinder(h=alt+supalt+2,d=holesize/3);
                translate([unitspace,unitspace,-0.1])
                  cylinder(h=alt+supalt+2,d=holesize/3);
              }
          } else if (filler==2){
              union() {
                translate([-(holesize/3)/2,-(holesize/3)/2,-0.1])
                  peca(holesize/3,alt+supalt+2);
                translate([-(holesize/3)/2,unitspace-holesize/3/2,-0.1])
                  peca(holesize/3,alt+supalt+2);
                translate([unitspace-holesize/3/2,-(holesize/3)/2,-0.1])
                  peca(holesize/3,alt+supalt+2);
                translate([unitspace-holesize/3/2,unitspace-holesize/3/2,-0.1])
                  peca(holesize/3,alt+supalt+2);

              }
          }
        }
      }
    }
  }
}

module peca(dimensao,alt) {

    difference() {
      cube([dimensao,dimensao,alt]);
      translate([0,0,-0.1]) cylinder(h=alt,d=dimensao/1.2);
      translate([dimensao,0,-0.1]) cylinder(h=alt,d=dimensao/1.2);
      translate([0,dimensao,-0.1]) cylinder(h=alt,d=dimensao/1.2);
      translate([dimensao,dimensao,-0.1]) cylinder(h=alt,d=dimensao/1.2);
    }
}

```


[User]
Hi there, I'm looking to create a customizable multi-sided funnel using OpenSCAD. I've seen some examples that use `$fn` to control the number of sides, and I like that approach. I'd like to be able to specify the width across the corners of the funnel and the number of sides I want, and have the other dimensions of the funnel adjust accordingly. I've included a detailed description in a previous message.

Here's what I have in mind:

*   **Parametric Control:** I want to be able to easily change the number of sides of the funnel (3 for triangular, 4 for square, 5 for pentagonal, and so on). I also need to set the overall width of the funnel – which should be the distance between opposite corners, not the distance between flats. The design should use the `$fn` variable for this purpose.
*   **Funnel Shape:** The funnel should consist of a cylinder base with one or more conical sections that taper toward a smaller outlet. The total height should be determined by the width, it doesn't have to be exact.
*   **Proportions:** I would like the diameter at the base of the funnel to be specified directly by the user. The diameter of the next stage down should be about 1/3 of the base, and the final outlet should be around 1/9 of the base. The lengths of the cylinder, the first conical section, and the last conical section should be scaled with the same base width value, perhaps by fractions of 1/7, 1/3 and 1/2 respectively.  I'd like the proportions to be adjustable.
*   **Hollow Object:** I need to ensure that the output is a hollow funnel, so I will make sure to configure my slicer settings to have no top or bottom layers and no infill when I'm done. I'd like the OpenSCAD file to be able to produce a solid, manifold object.
*   **No Libraries:** I don't think I need any libraries for something like this, but I'll let you know if that changes.

Could you generate the OpenSCAD code for this?

Thanks!

[Assistant]
parametric_multi_sided_funnel.scad:
```
// This makes use of the $fn function to limit the number of facets (sides) of cylinders.
// So essentially this is just a cylinder with a couple of cones stacked on top.
// Setting $fn to 3 gives a 3 sided funnel (triangular) funnel.
// Setting $fn to 4 gives a 4 sided (square) funnel.
// etc. The higher the number, the more "round" it becomes.

// REALLY IMPORTANT. THE STL PRODUCES A SOLID OBJECT WHICH WON'T BE MUCH USE AS A FUNNEL.
// TO MAKE THIS WORK, YOU NEED TO SLICE IT WITH NO TOP AND BOTTOM LAYERS, NO INFILL, BUT 3 OR 4 PERIMETERS.
// THAT WILL PRODUCE A G-CODE WHICH WILL MAKE A HOLLOW FUNNEL.

// Number of sides. 3 makes a trangular funnel, 4 makes a square funnel, 5 would be pentagonal, etc
Number_Of_Sides = 4;

$fn=Number_Of_Sides;

// Width across corners . NOTE this is the width across the corners, not across the flats.
// Essentialy, the width is the diameter of a circle within which your funnel will fit.
// So for example, if you want a 4 sided cone that is 100 mm across flats, you will need
// to set the width to approximately 1.4 times greater - i.e. 140mm.

Width_Across_Corners = 70;

dia1=Width_Across_Corners;

// If you want, you can change the proportions by playing around with the following variables.

dia2=dia1/3;
dia3=dia2/3;
h1=dia1/7;
h2=dia1/3;
h3=dia1/2;

// This is the main code section

rotate ([0,0,45])
cylinder (d=dia1, h=h1);
rotate ([0,0,45])
translate ([0,0,(h1-.001)]) // Set the z axis starting point very slightly lower to ensure that it is manifold
cylinder (d1=dia1, d2=dia2, h= h2);
rotate ([0,0,45])
translate ([0,0,(h1+h2-.002)]) // As above comment.
cylinder (d1=dia2, d2=dia3, h= h3);

```


[User]
Okay, I'd like to create a customizable guitar "eyelash" - that's the little piece that goes on the headstock. I've seen some cool designs where the strings seem to pass *through* the eyelash itself. I've got a basic idea in mind, and I'd like it to be easily adjustable using OpenSCAD parameters.

Here are the things I need to be able to control:

*   **Overall Width:** This is the total length of the eyelash.
*   **Height:** The overall height/thickness of the eyelash from the base to the top.
*   **Depth:** The depth of the eyelash, how thick it sticks out from the headstock.
*   **Cord Diameter:** The thickness of the "cords" or cylindrical parts that the strings seem to pass through.
*   **Number of Cords:** How many of these cylindrical "cords" to include.
*   **First Cord Offset:** The distance from the left edge of the eyelash to the center of the first cord.
*   **Cord Step:** The spacing between the center of each cord.
*   **Cord Angle:** The angle of each individual cord, and I'd like to be able to adjust it by specifying a value, per cord.
*   **Text:** The text to engrave into the eyelash.
*   **Text Offset X:** The horizontal distance from the left edge of the eyelash to the start of the text.
*   **Text Offset Z:** The vertical distance from the base of the eyelash to the start of the text.
*   **Font Size:** Size of the text
*   **Text Thickness:** How far the text should extrude.

The basic shape is a rectangular prism with cylindrical protrusions acting as guides for the strings. I would like the cords to be created using hull, connecting two cylinders to create an arch-like opening.

I will want to customize the text and have it engraved/extruded into the main body of the eyelash, using a boolean difference.

I'm not attached to any particular OpenSCAD libraries, but would appreciate it if you could keep the code concise, using standard OpenSCAD functions where possible, or well-regarded helper libraries, if needed.

[Assistant]
Eyelash.scad:
```
// DiGiorgio Studant No18 2004
//  Width: 52
//  FirstCordOffset: 4
//  CordStep: 9
// Giannini Estudos Feito a mão
//  Width: 48
//  FirstCordOffset: 2.5
//  CordStep: 8.6

CordDiameter = 1.4;
FirstCordOffset = 2.5;
CordStep = 8.6;
Width = 48;
Height=10;
Depth=5;
TextOffsetX = 14;
TextOffsetZ = 4;
FontSize = 5;
Text = "Rafael";

rotate(a=[90,0,0]){
    difference(){
        cube([Width,Depth,Height]);
        for(d = [0:5]){
            translate([FirstCordOffset+CordStep*d,7,Height-0.5]){
                desv = (d==3 ? 4.5 : (d==2 ? -4.5 : 0));
                rotate(a=[90,0,desv])
                    hull(){
                        cylinder(d=CordDiameter,h=Depth*2,$fn=50);
                        translate([0,2,0])
                            cylinder(d=CordDiameter,h=Depth*2,$fn=50);
                    }
            }
        }
        translate([TextOffsetX,0.5,TextOffsetZ])
            rotate(a=[90,0,0])
                linear_extrude(2)
                    text(Text,FontSize);
    }
}
```


[User]
Hey, I'm looking to design an enclosure for a RepRapDiscount LCD, specifically for mounting on a Kossel Mini 3D printer, and I've got some specific requirements. I need a parametric design, so I can adjust the dimensions easily.

Essentially, I'm after a box that holds the LCD, its mainboard, and has cutouts for the various components like the LCD screen itself, the speaker, rotary encoder, emergency stop button, and SD card slot. The design should also include a way to mount it to the Kossel's extrusion frame.

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

**General Box Structure:**

*   The main box should have an internal space to fit the LCD and mainboard, with some padding around the components.
*   The walls of the box should have a configurable thickness.
*   The corners of the box should be rounded.
*   The box should have mounting holes designed for M3 screws.
*   I need the overall size of the box to be parametric.

**Component Cutouts:**

*   **LCD Screen:** A rectangular cutout for the LCD screen itself.
*   **Mainboard:** An area to mount the mainboard behind the screen with cutouts for its mounting holes.
*   **Speaker:** A small circular cutout for the piezo speaker.
*   **Rotary Encoder:** A circular cutout for the rotary encoder.
*   **Emergency Stop Button:** A circular cutout for the stop button, which should also have a relief cut for the button's flange.
*   **SD Card Slot:** A cutout for the SD card slot, with space for inserting and removing an SD card.

**Mounting:**

*   The design should include mounting points for screwing the enclosure to the Kossel Mini's frame.
*   The mounting method should use M3 screws for attachment.
*   The mounting points should be located on the side of the enclosure, allowing it to be mounted perpendicular to the frame's extrusion.
*   I need a fixation at the top of the box as well. It should be designed to "hug" the extrusion and be screwed in place via a hole in the middle. This should be adjustable in terms of its width and thickness, and should be a module in the design.

**Parametric Considerations:**

*   I need to be able to easily adjust the following parameters:
    *   The size of the extrusion the mount clamps to
    *   The box's overall dimensions
    *   Wall thickness/borders/padding
    *   Radius of the rounded corners
    *   The thickness and width of the top fixation mount.

Could you please generate the necessary OpenSCAD files for this? I think it would be best to use separate modules for each component, and for the main box. I don’t need any library files. Thanks!

[Assistant]
reprapdiscount_lcd_box.scad:
```
/***************************************************************************
// RepRapDiscount LCD box with mount for Kossel Mini
// Licence: CC BY-SA 3.0, http://creativecommons.org/licenses/by-sa/3.0/
// Author: Dominik Scholz <schlotzz@schlotzz.com> and contributors
// visit: http://www.schlotzz.com

// Updated by DavidTre07 (https://github.com/DavidTre07)
// Added a fixation on top
***************************************************************************/

// - Taille des montants - Size of extrusion
Extrusion_Size=15; //[15:1:25]

/* [Hidden] */
// - Epaisseur de la fixation - Fixation thickness
Fixation_Thickness=3;
// - Largeur de la fixation - Fixation Width
Fixation_Width=15; //Should be =< Extrusion_Size

// avoid openscad artefacts in preview
epsilon = 0.05;

// Increase this if your slicer or printer make holes too tight.
extra_radius = 0.1;

// Major diameter of metric 3mm thread.
m3_major = 2.85;
m3_radius = m3_major / 2 + extra_radius;
m3_wide_radius = m3_major / 2 + extra_radius + 0.2;

//Fixation
module fixation()
{
    difference() {
        hull() {
            cube([Fixation_Width,Extrusion_Size/2,Fixation_Thickness],center=false); //Fixation en bas (angle droit)
            translate([Fixation_Width/2,Extrusion_Size/2,0]) {
                cylinder($fs=0.01,h=Fixation_Thickness,d=Fixation_Width,center=false);
            }
            rotate([19,0,0]) { //Fixation en haut (continuité face avant)
                translate([0,0,0])
                    cube([Fixation_Width,Extrusion_Size/2,Fixation_Thickness],center=false);
                translate([Fixation_Width/2,Extrusion_Size/2,0])
                    cylinder($fs=0.01,h=Fixation_Thickness,d=Fixation_Width,center=false);
            }
        }
        translate([Fixation_Width/2,Extrusion_Size/2,-epsilon]) { //Trou
            cylinder($fs=0.01,h=20,d=3.5,center=false); //Trou normal
            translate([0,0,Fixation_Thickness])
                cylinder($fs=0.01,h=20,d=7,center=false); //Trou pour tete vis
        }
    }
}

// rounded rectangle
module roundedRectangle(size = [1, 1, 1], r = 1, center = false, $fn = 16)
{
	translate(center ? [0, 0, 0] : (size / 2))
	hull()
	{
		for (x = [-size[0] / 2 + r, size[0] / 2 - r])
			for (y = [-size[1] / 2 + r, size[1] / 2 - r])
				translate([x, y, 0])
					cylinder(r = r, h = size[2], center = true);
	}
}

// mainboard
module panel_mainboard()
{
	size = [150, 55, 1.75];
	hole_offsets= [
		[2.5, 2.5, 0],
		[size[0] - 2.5, 2.5, 0],
		[2.5, size[1] - 2.5, 0],
		[size[0] - 2.5, size[1] - 2.5, 0]
	];

	speaker_radius = 11.75 / 2;
	speaker_height = 9.5;
	speaker_offset = [136.25, 44, 0];

	encoder_size = [12.25, 12.25, 4.5];
	encoder_radius = 7 / 2;
	encoder_height = 24.5;
	encoder_offset = [138, 25.25, 0];

	stop_size = [6, 6, 4.25];
	stop_offset = [136.5, 8, 0];

	// board
	color("white")
	difference()
	{
		cube(size);

		for (a = hole_offsets)
			translate(a - [0, 0, epsilon])
				cylinder(r = m3_wide_radius, h = size[2] + 2 * epsilon);
	}

	// piezo speaker
	color("grey")
	translate(speaker_offset + [0, 0, size[2]])
		cylinder(r = speaker_radius, h = speaker_height, $fn = 32);

	// rotary encoder
	color("grey")
	translate(encoder_offset + [0, 0, size[2] + encoder_size[2] / 2])
		cube(encoder_size, center = true);
	color("lightgrey")
	translate(encoder_offset + [0, 0, size[2]])
		cylinder(r = encoder_radius, h = encoder_height, $fn = 32);

	// emergency stop button
	color("grey")
	translate(stop_offset + [0, 0, size[2] + stop_size[2] / 2])
		cube(stop_size, center = true);

	// lcd board
	translate([14, -8, size[2] + 4.25])
	panel_lcdboard();

	// sd card slot
	translate([0, 8.5, -2.75])
	panel_sdcard();
}

// lcd board
module panel_lcdboard()
{
	size = [98, 60, 1.5];

	lcd_size = [97.5, 40, 9.5];
	lcd_offset = [0, 10, 0];

	// board
	color("green")
	cube(size);

	// lcd module
	color("black")
	translate(lcd_offset + [0, 0, size[2]])
		cube(lcd_size);

	color([.1, .2, 1, 0.7])
	translate(lcd_offset + [10, 6, size[2] + epsilon])
		cube(lcd_size - [20, 12, 0]);
}

// sd card slot
module panel_sdcard()
{
	size = [25.75, 26.75, 2.75];

	card_size = [32, 24, 2.25];
	card_offset = [-10.5, 1.375, 0.25];

	// slot
	color("lightgrey")
	cube(size);

	// sd card
	color("blue")
	translate(card_offset)
		cube(card_size);
}

// stop button
module panel_button(r = 4, delta = 4)
{
	cylinder(r = r + 1, h = 1, $fn = 32);
	translate([0, 0, 1])
		cylinder(r = r - 0.35, h = 7.5, $fn = 32);
	translate([0, 0, 8.5])
		cylinder(r1 = r - 0.35, r2 = r - 1, h = .5, $fn = 32);

	for (a = [[-r - delta, 0, 0], [r + delta, 0, 0]])
		translate(a)
			difference()
			{
				cylinder(r = 2.5, h = 1, $fn = 16);
				cylinder(r = 1.5, h = 10, $fn = 16, center = true);
			}

	translate([0, 0, 0.5])
		cube([1.5, 2 * (r + 2), 1], center = true);

	translate([-r - delta, -r / 2 - 2, 0.5])
		cube([1.5, r, 1], center = true);

	translate([r + delta, r / 2 + 2, 0.5])
		cube([1.5, r, 1], center = true);

	translate([-0.75, r + 1.5, 0])
		cube([2 * r + 1.5, 1.5, 1]);

	translate([-0.75 - 2 * r, -r - 3, 0])
		cube([2 * r + 1.5, 1.5, 1]);

}

// lcd box
module panel_lcd_box()
{
	inner_size = [150, 73, 20];
	padding = [1, 3, 0];
	borders = [3, 3, 3]; // was [2, 2, 2]
	border_radius = 3;

	lcd_offset = [13.5, 9.5, 0];
	lcd_size = [98.5, 41, 30];

	speaker_radius = .75;
	speaker_offset = [138, 51.75, 0];
	speaker_delta = [
		[-3, 0, 0],
		[ 0, 0, 0],
		[ 3, 0, 0]
	];

	encoder_radius = 7 / 2 + 1;
	encoder_offset = [138, 33.25, 0];

	stop_radius = 4;
	stop_offset = [138, 16.25, 0];

	mounting_offsets = [
		[2.5, 2.5, 0],
		[147.5, 2.5, 0],
		[2.5, 52.5, 0],
		[147.5, 52.5, 0]
	];

	// display panel
	%translate([0, 8, 7])
		panel_mainboard();

	difference()
	{

        translate(-borders - padding - [0, 0, 25])
        roundedRectangle(inner_size + 2 * padding + 2 * borders + [0, 0, 25], r = border_radius, center = false);
		// inner space
		translate(-padding - [0, 0, 25 + epsilon])
			roundedRectangle(inner_size + 2 * padding + [0, 0, 25], r = border_radius, center = false);

		// lcd hole
		translate(lcd_offset)
			cube(lcd_size);

		// speaker holes
		for (a = speaker_delta)
			translate(speaker_offset + a)
				cylinder(r = speaker_radius, h = 30, $fn = 16);

		// encoder hole
		translate(encoder_offset)
			cylinder(r = encoder_radius, h = 30, $fn = 16);

		// stop hole
		translate(stop_offset + [0, 0, inner_size[2] - 2 * epsilon])
			cylinder(r = stop_radius, h = borders[2] + 4 * epsilon, $fn = 32);
		translate(stop_offset + [0, 0, inner_size[2] + borders[2] - 2 - 2 * epsilon])
			cylinder(r1 = stop_radius, r2 = stop_radius + 1.5, h = 2 + 4 * epsilon, $fn = 32);

		// sd card
		translate([-10, 17.25, 4]) // was 1
			difference()
			{
				cube([30, 25.25, 3.25]);
				for (a = [0, 5, 10, 15, 20, 25])
				translate([0, a - 2.25, 0])
					cube([20, .5, 6]);
			}
	}

	// mounting cylinders
	for (a = mounting_offsets)
		translate(a + [0, 8, 8.75]) // was 6.75
			difference()
			{
				cylinder(r = 3.75, h = 11.25, $fn = 16); // was 13.25
				translate([0, 0, -epsilon])
					cylinder(r = m3_radius, h = 10, $fn = 16);
			}

	// stop button
	translate(stop_offset + [0, 0, 14.5]) // was 12.5
		difference()
		{
			union()
			{
				cylinder(r = stop_radius + 1.5, h = 5.5, $fn = 32); // was 7.5
				translate([-stop_radius - 4.2, 0, 0])
					cylinder(r = 2.5, h = 5.5, $fn = 32);
				translate([stop_radius + 4.2, 0, 0])
					cylinder(r = 2.5, h = 5.5, $fn = 32);
			}
			translate([0, 0, -epsilon])
				cylinder(r = stop_radius, h = 5.5 + 2 * epsilon, $fn = 32);
			translate([-stop_radius - 4, 0, -epsilon])
				cylinder(r = .75, h = 5.5, $fn = 32);
			translate([stop_radius + 4, 0, -epsilon])
				cylinder(r = .75, h = 5.5, $fn = 32);

		}

	%color("red")
	translate(stop_offset + [0, 0, 13.5])
		panel_button();
}

// kossel mounted box
module kossel_lcd_box()
{

	size = [158, 3, 43.75];
	holes = [
		[20, 0, 7.5],
		[20, 0, size[2] - 7.5],
		[size[0] - 20, 0, 7.5],
		[size[0] - 20, 0, size[2] - 7.5],
	];
	radius = 71;

	//Adding the fixation
    translate([0,size[1],43.5-Fixation_Thickness/2])
        fixation();
    translate([size[0]-15,size[1],43.5-Fixation_Thickness/2])
        fixation();
    difference()
	{
		union()
		{
			cube(size);

			translate([4, -60, -1])
				rotate([19, 0, 0])
					panel_lcd_box();
		}

		// cut off top
		translate([-10, -10, 45])
			cube([size[0] + 20, 20, 20]);

		// cut off bottom
		translate([-50, -200, -200 + epsilon])
			cube([300, 300, 200]);

		// cut off back
		translate([-10, 3, 0])
			cube([180, 50, 50]);

		// hole for data cables
		translate([30, -epsilon, 0])
			cube([size[0] - 60, 10, size[2] - 15]);

		// mounting holes
		for (a = holes)
			translate(a)
				rotate([90, 0, 0])
					cylinder(r = m3_wide_radius, h = 10, center = true, $fn = 16);
	}
}

rotate([180-19, 0, 0])
	kossel_lcd_box();
//panel_lcd_box();

//panel_button();

```


[User]
Hey, I'm looking to design a headphone winder, and I have some specific ideas in mind. I'd like it to have a central spine with fins extending outwards, which the headphone cord can be wrapped around.

For the spine, I'm picturing a rounded shape, kind of like a stretched-out capsule. It should be roughly 50 units tall. I'd like it to be generated using `minkowski` and `hull` operations, making use of two spheres with different scales. One of the spheres should be at the very top of the spine, and another should be more centered. This should give it the rounded capsule look. The spheres should also be used with the `$fn` variable for smoother shapes.

The fins should extend out from the spine. I want a series of them positioned along the spine's height. Ideally, the fins will be generated using a `difference` operation which will subtract scaled cubes from them and leave an angled edge. The scale of these cubes should change along the spine. I'd like it to also include a cylinder at the end of the spine, and not use the angled cube subtraction for that cylinder.

I want to be able to adjust the fin length and spine height, so those should be parameters. I'd also like the scale of the cubes subtracted from the fins to be a variable, so I can adjust the angle of the fins and how big they are. I'd like to be able to adjust the sphere resolution as well, so that's a parameter too. I think that should be everything! I'm not expecting any external libraries here. Can you generate an OpenSCAD file that implements this?

[Assistant]
headphone_winder_v1.scad:
```

// fins
fin_ratio = .8;
module sub_fins(){
    //minkowski(){
    difference(){
		children()         ;

		 for(i=[0:5:spine_height]){
            translate([i, 0,-50]){
					if(i==spine_height) {

								#cylinder(100,5,true);

					}
					else{
						scale([ fin_ratio+i/(1-i) +1.1 ,((spine_height-i)/spine_height) * i+30, 100]){
						cube(1);
					}
				}
            }
        }

    };
    //sphere($fn=sphere_resolution, r=1.5);
//}
}
// spine
spine_height = 50;

// cube
cube_dims = 8;
sphere_resolution = 50;
module draw_spine(){
rotate([0,90,0])
   minkowski(){
       hull(){
           scale([0.15,1,1]){
           translate([0,0,spine_height])
                sphere(cube_dims, $fn=sphere_resolution);
           scale([1,0.5,1])
                sphere(cube_dims, $fn=sphere_resolution);
           }

        }

   }
}

module connect_parts(){
            sub_fins()
                draw_spine();

}

connect_parts();
```


[User] I want to create a logo made of interlocking rectangular sticks. The basic unit is a rectangular prism, and they alternate orientation along the diagonal like a staircase, where each step is a single rectangular stick. The user should be able to specify the width of the short side of the stick, the long side of the stick, the depth of the stick and the number of sticks used in the logo. Can you create an OpenSCAD file to do that?

[Assistant]
logo.scad:
```
//Width of stick
w = 12;
//Height of stick
h = 4;
//Depth of stick
z = 4;
//Num of stick
num_sticks = 6; // Barrabes = 6

logo(w,h,z,num_sticks);

module logo(a=2, b=2,h=2,n=4) {
    for(i = [0:1:n-1]){
        ii = floor(i/2);
        if(i%2 ==0){
            translate([ii*(a-b), ii*(b-a)])
                cube([b,a,h]);
        }else{
            translate([ii*(a-b), ii*(b-a)])
                cube([a,b,h]);
        }
    }
}
```


[User]
I'm looking to create a customizable nail polish organizer, specifically designed to fit a mix of Brazilian brands like Colorama and Risqué. I've noticed most organizers are made for standard shapes and don't accommodate the slightly different sizes.

Here's what I need:

*   **Individual Slots:** The design should create individual slots to hold nail polish bottles.
*   **Two Brands:** I'm using two main brands, Colorama and Risqué, and want to have the flexibility to choose how many of each type of slot I have.
*   **Brand-Specific Shapes:** Colorama bottles are kind of oval-shaped, while Risqué ones are more cylindrical. The design needs to have cutouts that match these shapes for each type of polish, to prevent them from rolling around or tipping over.
*   **Parametric Design:** I need to be able to adjust the number of slots, their arrangement, and overall dimensions of the box. I'd like to control how many rows, and columns, of each polish type are made.
*   **Height:** I would like to set the height of the box.

I don't want to use any specific libraries, this is meant to be simple to read and build.

Could you help me generate the OpenSCAD file(s) for this?

[Assistant]
caixa_esmalte.scad:
```

itens_per_line = 2;
z_size = 15;
colorama_lines = [2];
risque_lines   = [1];
num_x = len(colorama_lines) + len(risque_lines);

for(x = [1 : 1 :num_x])
{
    for( y = [1 : 1 : itens_per_line])
    {
        for ( z = [0 : 1 : len(colorama_lines)])
        {
            if ( colorama_lines[z] == x )
            {
                 colorama((38*x),(38*y));
            }
        }

        for ( z = [0 : 1 : len(risque_lines)])
        {
            if ( risque_lines[z] == x )
            {
                 risque((38*x),(38*y));
            }
        }
    }

}

module colorama(x,y)
{
    translate([x,y,0]){
        difference(){
            translate([0,0,0])
                cube([38,38,z_size],center=true);
            translate([0,0,1])
                oval(21.5,33,z_size,true);
        }
    }
}

module risque(x,y)
{
      translate([x,y,0]){
        difference(){
            translate([0,0,0])
                cube([38,38,z_size],center=true);
            translate([0,0,10])
                cylinder(30,29/2,29/2,true);
        }
    }
}
module oval(w,h, height, center = false) {
    h = h/2;
    w = w/2;
  scale([1, h/w, 1]) cylinder(h=height, r=w, center=center);
 }
```


[User]
Hey, I'm looking to design a wall-mounted holder for my Wii remotes and nunchuks. I've seen a few designs online, but they're usually for 4 remotes, and I only have two. I'd like a parametric design, where I can specify how many remotes I want to store and it adjusts accordingly.

Here are some specific things I'm thinking about:

*   **Number of Bins:** I want a parameter, `n`, to control the number of bins. Each bin should hold one Wii remote and one nunchuk.
*   **Wiimote Holder:** The holder for the Wiimote should be a snug fit, with a cutout for the cable. I'm picturing a kind of box-like shape with a cavity for the controller to rest in. I had some dimensions in mind. The outer box needs to be 48mm wide and 39mm tall. there's also a 'm' variable of 3mm that is used for several dimensions. The wiimote will not go all the way to the back of the box so the overall depth is 54mm, but the cavity that the wiimote will sit in has a depth of just 3mm. I have an outline for the wiimote holder defined by a series of coordinates (outer_points and inner_points).
    *   `outer_points =[[0,a], [0,h+2*m-b], [b,h+2*m], [w+2*m-b,h+2*m], [w+2*m,h+2*m-b], [w+2*m,a], [w+2*m-a,0], [a,0]];`
    *   `inner_points =[[m,a], [m,h+2*m-b], [b,h+m], [w+2*m-b,h+m], [w+m,h+2*m-b], [w+m,a], [w+2*m-a,m], [a,m]];`
    *   `a=6`, `b=9`, `w=48`, `h=39`, `m=3`, `z=54`
*   **Nunchuk Holder:** The nunchuk holder should be a simple cylinder extending out from the side of the Wiimote holder. I'm picturing it as a cylinder that extends 6.5mm out, with a diameter of 25mm for the nunchuck's main body. There should also be a smaller cylinder to form a void space for the nunchuk's cord, it should have a diameter of 11mm and also be 6.5mm tall, as well as a third cylinder that has a diameter of 17mm and a height of 3mm, all these cylinders will be centered on the same point.
*   **Bin Shape:** Each wiimote and nunchuck assembly needs to be contained within a sort of half-pipe shape that's been rotated 90 degrees. I have the outline for this defined by `profile_points` and then I'll use linear_extrude.
  *   `profile_points = [[0,0], [0, 54], [b, 54], [h+2*m, 40], [h+2*m+5, 40], [h+2*m+5, 4+5], [h+2*m-4, 0]];`
*   **Wall Mounting:** I'd like two small holes for screws for wall mounting; they should be positioned at the top of the bin, one on each end and should be circular holes for screws with diameter of 5mm and extending to the depth of 2*m. I have the Z of my box at 54mm, i'd like the holes at the Z of 35mm.
*   **Hole:** the box should have a front-facing rectangle to allow the controllers to be placed in and removed. This should be centered on the box, with 7mm width, 11.5mm of height, and full depth.
*   **No Text:** Please do not include the text at the bottom.
*   **Libraries:** I'm not using any external libraries in my design, so no need to worry about them.

Could you create an OpenSCAD file based on this description? I think that should cover everything. Thanks!

[Assistant]
wiimote_holder.scad:
```
// number of bins
n = 2;

/* [Hidden] */

a = 6;
b = 9;
w = 48;
h = 39;
m = 3;
z = 54;

outer_points =[[0,a], [0,h+2*m-b], [b,h+2*m], [w+2*m-b,h+2*m], [w+2*m,h+2*m-b], [w+2*m,a], [w+2*m-a,0], [a,0]];
inner_points =[[m,a], [m,h+2*m-b], [b,h+m], [w+2*m-b,h+m], [w+m,h+2*m-b], [w+m,a], [w+2*m-a,m], [a,m]];
hole_points = [[-10,0], [-14,4], [-14,19], [-11,22], [-11,26], [-8, 29], [8,29], [11,26], [11,22], [14,19], [14,4], [10,0]];
profile_points = [[0,0], [0, 54], [b, 54], [h+2*m, 40], [h+2*m+5, 40], [h+2*m+5, 4+5], [h+2*m-4, 0]];

 module wiimote()
 {

       difference()
        {
            // main
            linear_extrude(height = z)
               polygon(outer_points);
            // cavity
            translate([0, 0, m])
                linear_extrude(heigth = m)
                    polygon(inner_points);
            // cable hole
            translate([m+(w/2),6.5+1,0])
               linear_extrude(heigth =m)
                 polygon(hole_points);
        }

 }

module nunchuk_positive()
{
    // nunchuck holder
    translate([ m+(w/2), m, 39.5])
      rotate([90,360/16, 0])
        cylinder(h=6.5, d=25, $fn=8);
}

module nunchuk_negative()
{
    // nunchuck holder
    translate([ m+(w/2), 1+m, 39.5])
      rotate([90,360/16, 0])
        {
            cylinder(h=6.5+1, d=11+1, $fn=8);
            cylinder(h=m+1, d=17+1, $fn=8);
        }

}

module bin()
{
  difference()
  {
      intersection()
      {
         translate ([w+2*m, h + 2*m, 0])
           rotate([90, 0, -90])
             linear_extrude(heigth = w + 2*m)
               polygon(profile_points);
          union()
            {
                wiimote();
                nunchuk_positive();
            }
      }

  // front entrance
  translate([m+(w/2)-(7/2), -5, 0])
    cube([7, 6.5+5+1, z]);
  nunchuk_negative();
  }
}

difference()
{
  for (i = [1:n])
    translate([(i-1)*(w+m), 0, 0]) bin();
  // hanging holes
  translate([m+(w/2), h+2*m, 35]) rotate([90, 0, 0]) cylinder(h=2*m, d=5);
  translate([m+(w/2)+(n-1)*(w+m), h+2*m, 35]) rotate([90, 0, 0]) cylinder(h=2*m, d=5);
  # translate([7, 2, 5]) rotate([90, 0, 0])   linear_extrude(height = 2) text("Wii", font = "Arial Rounded MT Bold:style=Regular", size =7);
  }
```


[User]
Okay, I need help creating a parametric hexagonal trash can design in OpenSCAD. I've got a basic concept, but it needs to be much more flexible and easier to customize.

Here's what I'm thinking:

*   **Core Shape:** The trash can should be based on a hexagonal prism.
*   **Layered Structure:** It should have the option to be built with multiple layers, where each layer is essentially a slightly rotated hexagonal prism, creating a kind of "stepped" or "twisted" look as you go up the can.
*   **Parametric Controls:** I need parameters for:
    *   `$border`: The wall thickness of the trash can. This should be able to be adjusted based on nozzle size, ideally as a multiple of nozzle diameter (e.g., 1.2mm if nozzle is 0.4mm and border is set to 3).
    *   `$knick_height`: The height of each individual layer.
    *   `$knick_count`: The total number of layers, this will impact the overall height and also the twist angle per layer. If set to 1, it should just be a normal hexagonal prism.
    *   `$bottom_height`: The height of a solid bottom section at the base of the trash can, so the layers don't sit directly on the print bed
    *   `$outer_radius`: The outer radius of the main hexagon.
*   **Twist Angle:** The rotation between each layer should be calculated automatically based on the number of layers to distribute the total twist (probably 90 degrees, so if 4 layers then a 22.5 degree rotation per layer).
*  **Tolerance:** there should be a tolerance between the inner and outer walls, so that the inner space has room inside the outer walls.
*   **Bottom:** The bottom of the trash can should be solid - no open spaces or holes.

I'd like the OpenSCAD code to use the hull() functionality to join the hexagonal prisms, making it easy to change.

Could you generate the OpenSCAD code for this? I'd like a single .scad file, but I'm happy to receive additional files if necessary to keep the design clean. I don't expect you to provide any library files, just the main model file(s).

[Assistant]
hexbox.scad:
```
$border=1.2;
$knick_height = 50;
$knick_count = 4;
$bottom_height = 1;

difference(){
    union(){

        cylinder(r=80, h=1, $fn=6, center=true);

        for ( layer = [1:$knick_count]) {
            hull(){
                translate([0,0, $bottom_height + (layer-1)*$knick_height ])
                rotate([0, 0, 90/$knick_count * (layer-1) ])
                cylinder(r=80, h=2, $fn=6, center=true);

                translate([0, 0, $bottom_height + (layer)*$knick_height ])
                rotate([0,0,90/$knick_count * layer ])
                cylinder(r=80, h=2, $fn=6, center=true);
            }
        }
    }// union

    union(){
        for ( layer = [1:$knick_count]) {
            hull(){
                translate([0,0, $bottom_height + (layer-1)*$knick_height ])
                rotate([0, 0, 90/$knick_count * (layer-1) ])
                cylinder(r=80-$border, h=2, $fn=6, center=true);

                translate([0, 0, $bottom_height + 0.1 + (layer)*$knick_height ])
                rotate([0,0,90/$knick_count * layer ])
                cylinder(r=80-$border, h=2, $fn=6, center=true);
            }
        }
    } // union
} // difference

```


[User]
I need a parametric box generator, something I can customize for different electronics projects. I've seen a few online, but I'd like something that covers a range of features.

First off, I need to be able to specify the box's dimensions: length, width, and height, as well as wall thickness. I'd also like to have rounded corners with adjustable fillet radius and smoothness.

For options, it'd be great to have the option to include PCB feet inside, four of them, with configurable position, length, width, height, diameter and hole diameter. I'd also like to have optional ventilation holes, along with their width, and I'd also like to have the option for a customizable text on the front, with adjustable font, font size, and of course the text itself. I need also the option to toggle the visibility of different shell components like the Top and Bottom shell, Front and Back panel, and the Text itself, which is really handy for exporting.

I also need to specify a gap tolerance for panels and rails.

Finally, I'd like to have the ability to define colors for the shells and panels separately, even though it's just for visual purposes in the preview.

So, to summarize, I need a parametric box with the following configurable parameters:

*   **Box Dimensions:** Length, Width, Height, Wall Thickness
*   **Corner Fillet:** Fillet Radius, Fillet Smoothness
*   **Options:**
    *   PCB Feet (On/Off, Position X/Y, Length, Width, Height, Foot Diameter, Hole Diameter)
    *   Ventilation Holes (On/Off, Width)
    *   Text (On/Off, Text String, Font, Font Size)
    *   Shell Components (Top Shell, Bottom Shell, Front Panel, Back Panel, Text) toggles
*   **Tolerance:** Gap between panels/rails
*   **Colors:** Shell Color, Panel Color

I'm looking for an OpenSCAD design that allows me to adjust all of these parameters. Also, I need to be able to export the different parts of the box as separate STLs, so it'd be great if the different parts can be enabled/disabled for export. I don't need any libraries right now, although I'm open to them for the more complex features.

[Assistant]
U_Box_V103.scad:
```

/*//////////////////////////////////////////////////////////////////
              -    FB Aka Heartman/Hearty 2016     -
              -   http://heartygfx.blogspot.com    -
              -       OpenScad Parametric Box      -
              -         CC BY-NC 3.0 License       -
////////////////////////////////////////////////////////////////////
12/02/2016 - Fixed minor bug
28/02/2016 - Added holes ventilation option
09/03/2016 - Added PCB feet support, fixed the shell artefact on export mode.

*/////////////////////////// - Info - //////////////////////////////

// All coordinates are starting as integrated circuit pins.
// From the top view :

//   CoordD           <---       CoordC
//                                 ^
//                                 ^
//                                 ^
//   CoordA           --->       CoordB

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

////////// - Paramètres de la boite - Box parameters - /////////////

/* [Box dimensions] */
// - Longueur - Length
  Length        = 80;
// - Largeur - Width
  Width         = 60;
// - Hauteur - Height
  Height        = 30;
// - Epaisseur - Wall thickness
  Thick         = 2;//[2:5]

/* [Box options] */
// Pieds PCB - PCB feet (x4)
  PCBFeet       = 0;// [0:No, 1:Yes]
// - Decorations to ventilation holes
  Vent          = 0;// [0:No, 1:Yes]
// - Decoration-Holes width (in mm)
  Vent_width    = 1.5;
// - Text you want
  txt           = "HeartyGFX";
// - Font size
  TxtSize       = 4;
// - Font
  Police        ="Arial Black";
// - Diamètre Coin arrondi - Filet diameter
  Filet         = 2;//[0.1:12]
// - lissage de l'arrondi - Filet smoothness
  Resolution    = 50;//[1:100]
// - Tolérance - Tolerance (Panel/rails gap)
  m             = 0.9;

/* [PCB_Feet--TheBoard_Will_NotBeExported) ] */
//All dimensions are from the center foot axis
// - Coin bas gauche - Low left corner X position
PCBPosX         = 7;
// - Coin bas gauche - Low left corner Y position
PCBPosY         = 6;
// - Longueur PCB - PCB Length
PCBLength       = 70;
// - Largeur PCB - PCB Width
PCBWidth        = 50;
// - Heuteur pied - Feet height
FootHeight      = 10;
// - Diamètre pied - Foot diameter
FootDia         = 8;
// - Diamètre trou - Hole diameter
FootHole        = 3;

/* [STL element to export] */
//Coque haut - Top shell
  TShell        = 1;// [0:No, 1:Yes]
//Coque bas- Bottom shell
  BShell        = 1;// [0:No, 1:Yes]
//Panneau arrière - Back panel
  BPanel        = 1;// [0:No, 1:Yes]
//Panneau avant - Front panel
  FPanel        = 1;// [0:No, 1:Yes]
//Texte façade - Front text
  Text          = 1;// [0:No, 1:Yes]

/* [Hidden] */
// - Couleur coque - Shell color
Couleur1        = "Orange";
// - Couleur panneaux - Panels color
Couleur2        = "OrangeRed";
// Thick X 2 - making decorations thicker if it is a vent to make sure they go through shell
Dec_Thick       = Vent ? Thick*2 : Thick;
// - Depth decoration
Dec_size        = Vent ? Thick*2 : 0.8;

//////////////////// Oversize PCB limitation -Actually disabled - ////////////////////
//PCBL= PCBLength+PCBPosX>Length-(Thick*2+7) ? Length-(Thick*3+20+PCBPosX) : PCBLength;
//PCBW= PCBWidth+PCBPosY>Width-(Thick*2+10) ? Width-(Thick*2+12+PCBPosY) : PCBWidth;
PCBL=PCBLength;
PCBW=PCBWidth;
//echo (" PCBWidth = ",PCBW);

/////////// - Boitier générique bord arrondis - Generic Fileted box - //////////

module RoundBox($a=Length, $b=Width, $c=Height){// Cube bords arrondis
                    $fn=Resolution;
                    translate([0,Filet,Filet]){
                    minkowski (){
                        cube ([$a-(Length/2),$b-(2*Filet),$c-(2*Filet)], center = false);
                        rotate([0,90,0]){
                        cylinder(r=Filet,h=Length/2, center = false);
                            }
                        }
                    }
                }// End of RoundBox Module

////////////////////////////////// - Module Coque/Shell - //////////////////////////////////

module Coque(){//Coque - Shell
    Thick = Thick*2;
    difference(){
        difference(){//sides decoration
            union(){
                     difference() {//soustraction de la forme centrale - Substraction Fileted box

                        difference(){//soustraction cube median - Median cube slicer
                            union() {//union
                            difference(){//Coque
                                RoundBox();
                                translate([Thick/2,Thick/2,Thick/2]){
                                        RoundBox($a=Length-Thick, $b=Width-Thick, $c=Height-Thick);
                                        }
                                        }//Fin diff Coque
                                difference(){//largeur Rails
                                     translate([Thick+m,Thick/2,Thick/2]){// Rails
                                          RoundBox($a=Length-((2*Thick)+(2*m)), $b=Width-Thick, $c=Height-(Thick*2));
                                                          }//fin Rails
                                     translate([((Thick+m/2)*1.55),Thick/2,Thick/2+0.1]){ // +0.1 added to avoid the artefact
                                          RoundBox($a=Length-((Thick*3)+2*m), $b=Width-Thick, $c=Height-Thick);
                                                    }
                                                }//Fin largeur Rails
                                    }//Fin union
                               translate([-Thick,-Thick,Height/2]){// Cube à soustraire
                                    cube ([Length+100, Width+100, Height], center=false);
                                            }
                                      }//fin soustraction cube median - End Median cube slicer
                               translate([-Thick/2,Thick,Thick]){// Forme de soustraction centrale
                                    RoundBox($a=Length+Thick, $b=Width-Thick*2, $c=Height-Thick);
                                    }
                                }

                difference(){// Fixation box legs
                    union(){
                        translate([3*Thick +5,Thick,Height/2]){
                            rotate([90,0,0]){
                                    $fn=6;
                                    cylinder(d=16,Thick/2);
                                    }
                            }

                       translate([Length-((3*Thick)+5),Thick,Height/2]){
                            rotate([90,0,0]){
                                    $fn=6;
                                    cylinder(d=16,Thick/2);
                                    }
                            }

                        }
                            translate([4,Thick+Filet,Height/2-57]){
                             rotate([45,0,0]){
                                   cube([Length,40,40]);
                                  }
                           }
                           translate([0,-(Thick*1.46),Height/2]){
                                cube([Length,Thick*2,10]);
                           }
                    } //Fin fixation box legs
            }

        union(){// outbox sides decorations
            //if(Thick==1){Thick=2;
            for(i=[0:Thick:Length/4]){

                // Ventilation holes part code submitted by Ettie - Thanks ;)
                    translate([10+i,-Dec_Thick+Dec_size,1]){
                    cube([Vent_width,Dec_Thick,Height/4]);
                    }
                    translate([(Length-10) - i,-Dec_Thick+Dec_size,1]){
                    cube([Vent_width,Dec_Thick,Height/4]);
                    }
                    translate([(Length-10) - i,Width-Dec_size,1]){
                    cube([Vent_width,Dec_Thick,Height/4]);
                    }
                    translate([10+i,Width-Dec_size,1]){
                    cube([Vent_width,Dec_Thick,Height/4]);
                    }

                    }// fin de for
               // }
                }//fin union decoration
            }//fin difference decoration

            union(){ //sides holes
                $fn=50;
                translate([3*Thick+5,20,Height/2+4]){
                    rotate([90,0,0]){
                    cylinder(d=2,20);
                    }
                }
                translate([Length-((3*Thick)+5),20,Height/2+4]){
                    rotate([90,0,0]){
                    cylinder(d=2,20);
                    }
                }
                translate([3*Thick+5,Width+5,Height/2-4]){
                    rotate([90,0,0]){
                    cylinder(d=2,20);
                    }
                }
                translate([Length-((3*Thick)+5),Width+5,Height/2-4]){
                    rotate([90,0,0]){
                    cylinder(d=2,20);
                    }
                }
            }//fin de sides holes

        }//fin de difference holes
}// fin coque

////////////////////////////// - Experiment - ///////////////////////////////////////////

///////////////////////////////// - Module Front/Back Panels - //////////////////////////

module Panels(){//Panels
    color(Couleur2){
        translate([Thick+m,m/2,m/2]){
             difference(){
                  translate([0,Thick,Thick]){
                     RoundBox(Length,Width-((Thick*2)+m),Height-((Thick*2)+m));}
                  translate([Thick,-5,0]){
                     cube([Length,Width+10,Height]);}
                     }
                }
         }
}

/////////////////////// - Foot with base filet - /////////////////////////////
module foot(FootDia,FootHole,FootHeight){
    Filet=2;
    color("Orange")
    translate([0,0,Filet-1.5])
    difference(){

    difference(){
            //translate ([0,0,-Thick]){
                cylinder(d=FootDia+Filet,FootHeight-Thick, $fn=100);
                        //}
                    rotate_extrude($fn=100){
                            translate([(FootDia+Filet*2)/2,Filet,0]){
                                    minkowski(){
                                            square(10);
                                            circle(Filet, $fn=100);
                                        }
                                 }
                           }
                   }
            cylinder(d=FootHole,FootHeight+1, $fn=100);
               }
}// Fin module foot

module Feet(){
//////////////////// - PCB only visible in the preview mode - /////////////////////
    translate([3*Thick+2,Thick+5,FootHeight+(Thick/2)-0.5]){

    %square ([PCBL+10,PCBW+10]);
       translate([PCBL/2,PCBW/2,0.5]){
        color("Olive")
        %text("PCB", halign="center", valign="center", font="Arial black");
       }
    } // Fin PCB

////////////////////////////// - 4 Feet - //////////////////////////////////////////
    translate([3*Thick+7,Thick+10,Thick/2]){
        foot(FootDia,FootHole,FootHeight);
    }
    translate([(3*Thick)+PCBL+7,Thick+10,Thick/2]){
        foot(FootDia,FootHole,FootHeight);
        }
    translate([(3*Thick)+PCBL+7,(Thick)+PCBW+10,Thick/2]){
        foot(FootDia,FootHole,FootHeight);
        }
    translate([3*Thick+7,(Thick)+PCBW+10,Thick/2]){
        foot(FootDia,FootHole,FootHeight);
    }

} // Fin du module Feet

///////////////////////////////////// - Main - ///////////////////////////////////////

if(BPanel==1)
//Back Panel
translate ([-m/2,0,0]){
Panels();
}

if(FPanel==1)
//Front Panel
rotate([0,0,180]){
    translate([-Length-m/2,-Width,0]){
     Panels();
       }
   }

if(Text==1)
// Front text
color(Couleur1){
     translate([Length-(Thick),Thick*4,(Height-(Thick*4+(TxtSize/2)))]){// x,y,z
          rotate([90,0,90]){
              linear_extrude(height = 0.25){
              text(txt, font = Police, size = TxtSize,  valign ="center", halign ="left");
                        }
                 }
         }
}

if(BShell==1)
// Coque bas - Bottom shell
color(Couleur1){
Coque();
}

if(TShell==1)
// Coque haut - Top Shell
color( Couleur1,1){
    translate([0,Width,Height+0.2]){
        rotate([0,180,180]){
                Coque();
                }
        }
}

if (PCBFeet==1)
// Feet
translate([PCBPosX,PCBPosY,0]){
Feet();
 }
```


[User]
I'd like to create a customizable box, specifically designed to fit into various commercially available sortiment cases (like Sortimo and Alutec). I'd like to be able to adjust the overall size, number of internal compartments, wall thicknesses, and whether to include mounting holes for feet.

Here are the specific features I need:

*   **Box Type:** I need a parameter to select from a few preset box types. These should correspond to the internal dimensions of common sortiment boxes from manufacturers like Sortimo (Small, Medium, Large), Allit (Euro Plus Small, Euro Plus Large), and Alutec. I also need an option for a completely custom size where I can define the width, depth, and height directly.
*   **Number of Units:**  I'd like to specify how many base units are present along the x and y axes. This would allow me to create a box that uses a 3x1 or 2x2 grid of the base size for the chosen box type.
*   **Internal Separators:**  I need parameters to control how many separators to include along the x and y axes, creating internal compartments.
*   **Feet Mounting Holes:** I'd like a boolean option to include mounting holes for feet at each corner of the box's base.
*   **Wall Thickness:** I'd like to control the main wall thickness and the inner separator wall thickness separately.
*   **Custom Dimensions:** If I select the "Custom" box type, I need to define custom width, depth, and height for the base unit.
*   **Corner Radius:** The corners of the box should be rounded with a set radius.
*   **Foot Height:** There should be a variable for the foot height, and the height of the overall box should take that into account.
*   **Hole Dimensions:** If feet holes are added, I would need to specify a standard hole distance from the edges of the box, along with the diameter of these holes.
*   **File Structure:** If possible, I would appreciate the parameters to be defined in a single file, such as `params.scad`, then a `main.scad` that calls the other files. I would then prefer the generation of different box objects to be handled in separate modules. For instance, one module should generate the external walls, another for the internal dividers/compartments, and another module to cut out the foot holes.

I need all of this done in OpenSCAD with parametric design in mind. I'd like to use the standard `hull` and `difference` commands to create the rounded corners and the hollowed out space in the main body.

[Assistant]
SimplBox4.scad:
```
// created by skytale
// http://www.thingiverse.com/skytale/designs

// Options!
/* [SimplBox Insert] */
//Box measures
type = 6; // [0:Custom,1:Sortimo Small,2:Sortimo Medium,3:Sortimo Large, 4:Allit Euro Plus Small, 5:Allit Euro Plus Large, 6:Alutec]
// How many units in x-direction?
xCount = 3; // [1:6]
// How many units in y-direction?
yCount = 1; // [1:6]
// How many separators in x-direction?
xSeparators = 2;
// How many separators in y-direction?
ySeparators = 0;
// Feet holes?
feetHoles = true; // [true:yes, false:no]

/* [Misc Parameters] */
// Wall Thickness.
wallThickness = 1.2;
innerWallThickness = 0.8;

customWidth = 50;
customDepth = 50;
customHeight = 20;
feetHeight = 2.4;

/* [Hidden] */
cornerRadius = 5;
holeDistance = 6.5;
holeDiameter = 4;
fn = 40;

// DIMENSIONS

// Custom
if (type == 0) doBox(customWidth * xCount, customDepth * yCount, customHeight - feetHeight, holeDistance);

// Sortimo S
if (type == 1) doBox(52 * xCount, 52 * yCount, 31 - feetHeight, holeDistance);

// Sortimo M
if (type == 2) doBox(52 * xCount, 52 * yCount, 44 - feetHeight, holdeDistance);

// Sortimo L
if (type == 3) doBox(52 * xCount, 52 * yCount, 63 - feetHeight, holeDistance);

// Allit S
if (type == 4) doBox(54 * xCount, 54 * yCount, 45 - feetHeight, holeDistance);

// Allit L
if (type == 5) doBox(54 * xCount, 54 * yCount, 63 - feetHeight, holeDistance);

// Alutec (feet distance = 38.5)
if (type == 6) doBox(48 * xCount + (xCount - 1), 48 * yCount + (yCount - 1), 50.3 - feetHeight, (48-33.5-5)/2);  // 1mm*(xyCount -1):-> 1mm space compensation for multilength boxes

module doBox(width, depth, height, holeDistance) {
	difference() {
		box(width, depth, height);
		if (feetHoles) holes(width, depth, holeDistance);
	}
	makeSeparators(width, depth, height);
}

module box(width, depth, height) {
	cWidth = width - 2 * cornerRadius;
	cDepth = depth - 2* cornerRadius;
	difference() {
		hull() {
			translate([-cWidth / 2, -cDepth / 2, 0]) cylinder(height, cornerRadius, cornerRadius, $fn = fn);
			translate([+cWidth / 2, -cDepth / 2, 0]) cylinder(height, cornerRadius, cornerRadius, $fn = fn);
			translate([+cWidth / 2, +cDepth / 2, 0]) cylinder(height, cornerRadius, cornerRadius, $fn = fn);
			translate([-cWidth / 2, +cDepth / 2, 0]) cylinder(height, cornerRadius, cornerRadius, $fn = fn);
		}
		hull() {
			translate([-cWidth / 2, -cDepth / 2, wallThickness]) cylinder(height, cornerRadius - wallThickness, cornerRadius - wallThickness, $fn = fn);
			translate([+cWidth / 2, -cDepth / 2, wallThickness]) cylinder(height, cornerRadius - wallThickness, cornerRadius - wallThickness, $fn = fn);
			translate([+cWidth / 2, +cDepth / 2, wallThickness]) cylinder(height, cornerRadius - wallThickness, cornerRadius - wallThickness, $fn = fn);
			translate([-cWidth / 2, +cDepth / 2 , wallThickness]) cylinder(height, cornerRadius - wallThickness, cornerRadius - wallThickness, $fn = fn);
		}
	}
}

module holes(width, depth, holeDistance) {
	translate([-width / 2 + holeDistance, -depth / 2 + holeDistance, -1]) cylinder(wallThickness + 2, holeDiameter / 2, holeDiameter / 2, $fn = fn);
	translate([+width / 2 - holeDistance, -depth / 2 + holeDistance, -1]) cylinder(wallThickness + 2, holeDiameter / 2, holeDiameter / 2, $fn = fn);
	translate([+width / 2 - holeDistance, +depth / 2 - holeDistance, -1]) cylinder(wallThickness + 2, holeDiameter / 2, holeDiameter / 2, $fn = fn);
	translate([-width / 2 + holeDistance, +depth / 2 - holeDistance, -1]) cylinder(wallThickness + 2, holeDiameter / 2, holeDiameter / 2, $fn = fn);
}

// separators

module makeSeparators(width, depth, height){
 if(xSeparators >= 1){
  for (i = [1 : xSeparators]){
	xSeparator(width, depth, height, ((width - wallThickness) / (xSeparators + 1)) * i);
	//xSeparator(0);
	//xSeparator(width - wallThickness);
  }
 }
 if(ySeparators >= 1){
  for (i = [1 : ySeparators]){
  	ySeparator(width, depth, height, ((depth - wallThickness) / (ySeparators + 1)) * i);
	//ySeparator(0);
	//ySeparator(depth - wallThickness);
  }
 }
}

module xSeparator(width, depth, height, pos){
	translate([(-width + wallThickness) / 2 + pos, 0 ,height / 2]) cube(size = [innerWallThickness, depth - wallThickness, height], center = true);
}

module ySeparator(width, depth, height, pos){
	translate([0, (-depth + wallThickness) / 2 + pos ,height / 2]) cube(size = [width - wallThickness, innerWallThickness, height], center = true);
}

```


[User]
I'm looking to design a parametric fan shroud for an E3D hotend, and I'd like it to be fairly customizable. I have a few specific needs and preferences in mind, and I'd love for you to generate the necessary OpenSCAD files for this project.

First off, the core of the shroud needs to wrap around the hotend. It should support different hotend diameters, with a default of 22.4mm for an E3D v6, but also allow for a 25mm diameter to fit an E3D v5. The height of this main shroud body should also be adjustable, with a default of 30mm.

Secondly, I'd like to include an option for a fan mount. If enabled, this fan mount should have an adjustable height above the bottom of the shroud, and should have a support structure generated alongside it. I'm thinking a height of 2mm by default, and I'd like to use magnetic couplers in my fan design. I also need 30mm fan mounting holes.

The design also needs to include an optional BLTouch mount, also with an adjustable height relative to the base of the shroud. I'd like the default height to be 23.7mm.

Finally, the shroud needs to have optional mounting holes for attaching the shroud assembly to the printer.

So, to recap, the parameters I'd like are:

*   `extruderDiameter`: Diameter of the hotend. Default: 22.4 (E3D v6), with an option to set to 25 (E3D v5).
*   `extruderHeight`: Height of the main shroud body. Default: 30.
*   `fan`: Boolean to enable/disable fan mount. Default: true.
*   `fanHeight`: Height of the fan mount from the bottom of the shroud. Default: 2.
*   `support`: Boolean to enable/disable fan mount support. Default: true.
*   `blTouch`: Boolean to enable/disable blTouch mount. Default: true.
*   `blTouchHeight`: Height of the blTouch mount from the bottom of the shroud. Default: 23.7.
*  `mountingHoles`: Boolean to enable/disable mounting holes for the shroud. Default: true
*   `overlap`: Overlap between the fan vents and the main shroud body. Default: 9.5.
*   `ventDistance`: Distance between fan vents. Default: 18.
*   `cornerRadius`: Radius of rounded corners for the shroud. Default: 2.
*  `fanSize`: Size of the fan. Default: 30.

For the design of the fan mount I'd like it to use magnets. Here's some details:
* `magnetDia` - Diameter of the magnets. Default: 6.6
* `magnetDepth` - Depth of the magnet hole. Default: 3
* `magnetDistance` - Distance between the centers of the two magnets. Default: 7.75
* `hookWidth` - Width of the fan mounting hook. Default: 8.5
* `hookHeight` - Height of the fan mounting hook. Default: 13
* `hookDepth` - Depth of the fan mounting hook. Default: 4
* `hookRillDia` - Diameter of the screw hole in the fan mounting hook. Default: 3.2
* `supportWidth` - Width of the support underneath the fan mounting hook. Default: 1

For the BLTouch mount, these are the dimensions I'd like:

* `LatchWidth` - Width of the BLTouch latch. Default: 26
* `LatchDepth` - Depth of the BLTouch latch. Default: 11.53
* `btHoleDia` - Diameter of the BLTouch mounting holes. Default: 3
* `btHoleDist` - Distance between BLTouch mounting holes. Default: 18
* `btHoleDepth` - Depth of the BLTouch mounting holes. Default: 4
* `btBodySpace` - Space for the BLTouch body. Default: 13.5
* `spacer` - Spacer for the BLTouch mount. Default: 0.5

I'd like to leverage the `hull()` module for the main body of the shroud to create smooth curves. I would also like to include comments that indicate the purpose of each code section.

I think that should cover everything! Let me know if you have any questions.

[Assistant]
FanShroud.scad:
```
// Fanshroud by skytale

/* [e3d fan shroud] */
// Select your extruder:
extruderDiameter = 22.4; // [22.4:e3d v6, 25:e3d v5]
// Height of the shroud:
extruderHeight = 30; // [30:40]
// Do you want a fan mount?
fan = true; // [true:yes,false:no]
// Height of the fan mount from bottom. Use values inbetween 0-3.
fanHeight = 2;
//Create support structure for fan mount?
support = true;
// Do you want a blTouch mount?
blTouch = true; // [true:yes,false:no]
// Height of the blTouch mount from bottom. Use values inbetween 18-28.
blTouchHeight = 23.7;
// Do you want mounting holes?
mountingHoles = true; // [true:yes,false:no]

/* [Misc Parameters] */
overlap = 9.5;
ventDistance = 18;
cornerRadius = 2;
fanSize = 30;

/* [Hidden] */
fn = 40;

module shroud() {
	hull() {
		translate([-overlap + cornerRadius, -fanSize / 2 + cornerRadius, cornerRadius]) sphere(cornerRadius, $fn = fn);
		translate([0, -fanSize / 2 + cornerRadius, cornerRadius]) rotate([0,90,0]) cylinder(ventDistance,cornerRadius,cornerRadius,$fn = fn);
		translate([0, +fanSize / 2 - cornerRadius, cornerRadius]) rotate([0,90,0]) cylinder(ventDistance,cornerRadius,cornerRadius,$fn = fn);
		translate([-overlap + cornerRadius, +fanSize / 2 - cornerRadius, cornerRadius]) sphere(cornerRadius, $fn = fn);

		translate([-overlap + cornerRadius, -fanSize / 2 + cornerRadius, extruderHeight - cornerRadius]) sphere(cornerRadius, $fn = fn);
		translate([0, -fanSize / 2 + cornerRadius, extruderHeight - cornerRadius]) rotate([0,90,0]) cylinder(ventDistance,cornerRadius,cornerRadius,$fn = fn);
		translate([0, +fanSize / 2 - cornerRadius, extruderHeight - cornerRadius]) rotate([0,90,0]) cylinder(ventDistance,cornerRadius,cornerRadius,$fn = fn);
		translate([-overlap + cornerRadius, +fanSize / 2 - cornerRadius, extruderHeight - cornerRadius]) sphere(cornerRadius, $fn = fn);
	}
}

module extruder() {
	cylinder(extruderHeight, extruderDiameter/2, extruderDiameter/2, $fn = fn);
}

module airFlow() {
	translate([0,0,fanSize/2]) rotate([0,90,0]) cylinder(ventDistance+1, fanSize/2 - 2, fanSize/2 - 2, center=false, $fn = fn);
}

module fanHoles() {
dia = 3.2;
depth = 10;
holeDist = 12;
translate([ventDistance-depth, -holeDist, fanSize/2-holeDist]) rotate([0,90,0]) cylinder(depth+1,dia/2,dia/2,$fn = fn);
translate([ventDistance-depth, -holeDist, fanSize/2+holeDist]) rotate([0,90,0]) cylinder(depth+1,dia/2,dia/2,$fn = fn);
translate([ventDistance-depth, +holeDist, fanSize/2+holeDist]) rotate([0,90,0]) cylinder(depth+1,dia/2,dia/2,$fn = fn);
translate([ventDistance-depth, +holeDist, fanSize/2-holeDist]) rotate([0,90,0]) cylinder(depth+1,dia/2,dia/2,$fn = fn);
}

module mountingHoles() {
	dia = 3;
	depth = 3;
	holeDist = 14.5;
	holeOffset = 7;
	translate([holeDist,holeOffset, extruderHeight-depth]) cylinder(depth+1,dia/2,dia/2,$fn = fn);
	translate([holeDist,-holeOffset, extruderHeight-depth]) cylinder(depth+1,dia/2,dia/2,$fn = fn);
}

module fanHook() {
	magnetDia = 6.6;
	magnetDepth = 3;
	magnetDistance = 7.75;
	hookWidth = 8.5;
	hookHeight = 13;
	hookDepth = 4;
	hookRillDia = 3.2;
	supportWidth = 1;

	rotate([90,0,180])
	translate([0,hookWidth/2,0])
	difference(){
		union() {
			cylinder(hookDepth,hookWidth/2,hookWidth/2,$fn = fn);
			translate([-hookWidth/2, 0, 0]) cube([hookWidth, hookHeight, hookDepth], center = false);
		}
		translate([0,0,hookDepth-magnetDepth])cylinder(magnetDepth+1,magnetDia/2,magnetDia/2,$fn = fn);
		translate([0,magnetDistance,hookDepth-magnetDepth]) cylinder(magnetDepth+1,magnetDia/2,magnetDia/2,$fn = fn);
		translate([-hookWidth/2-1, hookHeight, hookDepth/2]) rotate([0,90,0]) cylinder(hookWidth+2,hookRillDia/2,hookRillDia/2,$fn = fn);
		translate([-hookWidth/2-1,hookHeight-0.6,hookDepth/2]) cube([hookWidth+2, 1, hookDepth/2+1], center = false);
	}
	if (support) translate([-supportWidth/2,0,-fanHeight]) cube([supportWidth, hookDepth,fanHeight+0.5], center = false);
}

module blTouch() {
	LatchWidth = 26;
	LatchDepth = 11.53;
	btHoleDia = 3;
	btHoleDist = 18;
	btHoleDepth = 4;
	btBodySpace = 13.5; // 13 + 0.5
	spacer = 0.5;

	translate([-LatchWidth/2,-fanSize/2,0])
	rotate([90,0,90])
	difference() {
		linear_extrude(height = LatchWidth, center = false, convexity = 10, twist = 0)
			polygon(points=[[0,blTouchHeight/2],[-LatchDepth,blTouchHeight],[0,blTouchHeight]], paths=[[0,1,2]]);
		translate([-LatchDepth,0,LatchWidth/2-btBodySpace/2]) cube([LatchDepth, blTouchHeight, btBodySpace], center = false);
		translate([-LatchDepth/2,blTouchHeight-btHoleDepth,LatchWidth/2-btHoleDist/2]) rotate([-90,0,0]) cylinder(blTouchHeight+1,btHoleDia/2,btHoleDia/2,$fn = fn);
		translate([-LatchDepth/2,blTouchHeight-btHoleDepth,LatchWidth/2+btHoleDist/2]) rotate([-90,0,0]) cylinder(blTouchHeight+1,btHoleDia/2,btHoleDia/2,$fn = fn);
	}
}

difference() {
	union() {
		shroud();
		if (fan) translate([0,fanSize/2,fanHeight]) fanHook();
	}
	extruder();
	airFlow();
	fanHoles();
	if (mountingHoles) mountingHoles();
}
if (blTouch) translate([ventDistance-13,0,0]) blTouch();

```