[User]
I'd like a parametric OpenSCAD design for a toy train turntable, compatible with Brio-style tracks. I need to be able to customize the size of the turntable, the number of rails coming off of it, and I'd like to be able to generate individual parts separately.

Here are the specifics:

1.  **Turntable Size:** The turntable's diameter should be driven by the number of teeth on the main turntable gear. This gear will have a circular pitch of 333 and a pressure angle of 28. I need to be able to change the number of teeth.
2.  **Rail Connections:** The rails should connect to the turntable at variable angles and have male and female connectors to connect to standard wooden tracks. The number of rails and their starting angle and spacing should be customizable. The design should use the existing rail connector from the provided design, so I've included the relevant track details at the bottom of the file, and the 'connector', 'connector_male', etc., modules.
3.  **Turntable Gear:** The turntable should have a gear underneath that interacts with a control gear.  The control gear has a fixed size, and should use the same gear profile as the main turntable gear.
4.  **Wheels:** The turntable should use wheels to roll on the base plate. The number of wheels should adjust based on the size of the turntable, with the angles being calculated based on the turntable's gear pitch radius. I'd like the wheels and their axles to also be separate modules so I can print them separately.
5. **Base Plate:** The base plate needs to support the turntable and the control gear, with appropriate clearances for the moving parts.
6.  **Individual Parts:** I need to be able to render the entire assembly, and also each part individually (base plate, turntable, control gear, wheels, wheel axles) using a variable.
7. **Libraries:** Please use the `involute_gears.scad` library from MCAD for the gear generation. I've included a bearing design, but feel free to use something simpler or different.

I've included the OpenSCAD code I've been working on - it has the modules I need for the rails, the bearing, the gear calculations and the wheel positions.  This should be used as a starting point, and I don't expect an exact reproduction. Please make sure that all parts can be printed without supports if possible, or are designed such that support removal is easy. I've included all the necessary modules for the rails and the gear generation, so you shouldn't need any additional files.

[Assistant]
turntable.scad:
```
What_to_show=1; // [1:All in one, 2:Floor plate, 3:Turntable gear, 4:Turntable wheels, 5:Control gear]

// Number of teeth of the turntable
Number_of_teeth=64; // [40:200]

Rails_angle_start = 45;
Rails_angle_step = 45;
Rails_angle_end = 270;

use <MCAD/involute_gears.scad>

turntableGearPitchRadius = Number_of_teeth * 333 / 360;
function wheelAngles() = Number_of_teeth < 50?[]:
	Number_of_teeth < 60?[0, 180]:
	Number_of_teeth < 80?[45, 135, 225, 315]:
	Number_of_teeth < 120?[90-asin(35/turntableGearPitchRadius),90+asin(35/turntableGearPitchRadius),270-asin(35/turntableGearPitchRadius),270+asin(35/turntableGearPitchRadius), 0, 180]:
	Number_of_teeth < 160?[90-asin(35/turntableGearPitchRadius),90+asin(35/turntableGearPitchRadius),270-asin(35/turntableGearPitchRadius),270+asin(35/turntableGearPitchRadius), 30, -30, 150, 210]:
	[90-asin(35/turntableGearPitchRadius),90+asin(35/turntableGearPitchRadius),270-asin(35/turntableGearPitchRadius),270+asin(35/turntableGearPitchRadius), 45, 135, 225, 315, 0, 180];

function entryAngle() = Number_of_teeth < 50?50:
	Number_of_teeth < 70?45:
	Number_of_teeth < 90?40:
	Number_of_teeth < 110?36:
	Number_of_teeth < 130?33:
	Number_of_teeth < 150?31:
	29;

floorLayerHeight = 2+0;
pinBaseOffset = 1 + 0;
pinBaseHeigth = floorLayerHeight + pinBaseOffset;

controlGearPitchRadius = 18.7+0;
clearance=0.2 + 0;

module turnTable() {
	bearing();

	difference() {
		// gear
		gear(number_of_teeth=Number_of_teeth, circular_pitch=333, pressure_angle=28, hub_thickness=0, bore_diameter=turntableGearPitchRadius*2 - 24.1, rim_thickness=7, rim_width=10);
		// wheel holes
		for (angle = wheelAngles()) {
			rotate([0, 0, angle]) {
				translate([0, turntableGearPitchRadius-8, 3.5]) {
					cube([10, 4, 7], center=true);
					translate([0, 5.8, 0]) {
						rotate([90, 0, 0]) {
							cylinder(10, r=2);
						}
					}
				}
			}
		}
	}

	// rails on turntable
	intersection() {
		translate([-turntableGearPitchRadius, -20, -2.4]) {
			rotate([90,0,90]) {
				linear_extrude(turntableGearPitchRadius * 2) {
					body();
				}
			}
		}
		difference() {
			cylinder(10, r=turntableGearPitchRadius-2);
			cylinder(12.4, r=11);
		}
	}
}

module controlGear() {
	rotate([0, 0, 360/40]) {
		bearing();

		gear(number_of_teeth=20, circular_pitch=333, pressure_angle=28, hub_thickness=0, bore_diameter=22, rim_thickness=7, rim_width=6);
		translate([13.8, 0, 7]) {
			cylinder(10, r=3);
		}
		translate([13.8, 0, 17]) {
			sphere(5);
		}
	}
}

module wheelAxis() {
	translate([0, 0, 1]) {
		cylinder(2, r=3.2, center=true);
	}
	translate([0, 0, 5.75]) {
		cylinder(11.5, r=1.93, center=true);
	}
}

module wheel() {
	translate([0,0,1.75]) {
		difference() {
			cylinder(3.5, r=4.5, center=true);
			cylinder(3.5, r=2.2, center=true);
		}
	}
}

bottomHeigth = 8;
edgeRounding = 2;

turntableGearMargin = 3;
turntableGearEdgeWidth = 15;

controlGearMargin = 3;
controlGearEdgeWidth = 5;

pinRadius = 3.95;
pinHeigth = 10;
pinBaseRadius = 4.75;

$fn=100;

module pin() {
	translate([0, 0, pinHeigth/2]) {
		cylinder(pinHeigth, r=pinRadius, center=true);
	}
	translate([0, 0, pinBaseHeigth/2]) {
		cylinder(pinBaseHeigth, r=pinBaseRadius, center=true);
	}
}

module rails(length, connectorType) {
	if (connectorType == 0) {
		difference() {
			rotate([90, 0, 90]) {
				translate([-20, 0, 0]) {
					linear_extrude(length) body();
				}
			}
			translate([length, 0, 20]) {
				rotate([90, 0, 180]) {
					connector();
				}
			}
		}
	} else {
		rotate([90, 0, 90]) {
			translate([-20, 0, 0]) {
				linear_extrude(length-17) body();
			}
		}
		translate([length, 0, 0]) connector_male(17);
	}
}

module floorPlate() {
	difference() {
		union() {
			hull() {
				union() {
					cylinder(bottomHeigth - edgeRounding, r=turntableGearPitchRadius + turntableGearMargin + turntableGearEdgeWidth + edgeRounding);
					translate([0, 0, bottomHeigth - edgeRounding]) {
						cylinder(edgeRounding, r1=turntableGearPitchRadius + turntableGearMargin + turntableGearEdgeWidth + edgeRounding, r2=turntableGearPitchRadius + turntableGearMargin + turntableGearEdgeWidth);
					}
				}

				translate([turntableGearPitchRadius + clearance + controlGearPitchRadius, 0, 0]) {
					cylinder(bottomHeigth - edgeRounding, r=controlGearPitchRadius + controlGearMargin + controlGearEdgeWidth + edgeRounding);
					translate([0, 0, bottomHeigth - edgeRounding]) {
						cylinder(edgeRounding, r1=controlGearPitchRadius + controlGearMargin + controlGearEdgeWidth + edgeRounding, r2=controlGearPitchRadius + controlGearMargin + controlGearEdgeWidth);
					}
				}
			}
			rotate([0, 0, entryAngle()]) {
				rails(turntableGearPitchRadius+40, 0);
			}
			for (railAngle = [Rails_angle_start:Rails_angle_step*2:Rails_angle_end]) {
				rotate([0, 0, railAngle + entryAngle()]) {
					rails(turntableGearPitchRadius+40, 1);
				}
			}
			for (railAngle = [Rails_angle_start+Rails_angle_step:Rails_angle_step*2:Rails_angle_end]) {
				rotate([0, 0, railAngle + entryAngle()]) {
					rails(turntableGearPitchRadius+40, 0);
				}
			}
		}
		translate([0, 0, 20+floorLayerHeight]) {
			cylinder(40, r=turntableGearPitchRadius + turntableGearMargin, center=true);
		}
		translate([turntableGearPitchRadius + clearance + controlGearPitchRadius, 0, bottomHeigth/2 + floorLayerHeight]) {
			cylinder(bottomHeigth, r=controlGearPitchRadius + controlGearMargin, center=true);
		}
	}

	pin();
	translate([turntableGearPitchRadius + clearance + controlGearPitchRadius, 0, 0]) {
		pin();
	}
}

/*********************************************************\
* Combinations of the modules, for rendering and printing *
\*********************************************************/
if (What_to_show == 1) {
	allInOne();
} else if (What_to_show == 2) {
	floorPlate();
} else if (What_to_show == 3) {
	turnTable();
} else if (What_to_show == 4) {
	wheelsForPrinting();
} else if (What_to_show == 5) {
	controlGear();
} else if (What_to_show == 6) {
	wheel();
} else if (What_to_show == 7) {
	wheelAxis();
}

module allInOne() {
	floorPlate();
	translate([0,0,pinBaseHeigth]){
		color("green") {
			turnTable();
		}
	}
	translate([turntableGearPitchRadius + clearance + controlGearPitchRadius,0,pinBaseHeigth]) {
		color("blue") {
			controlGear();
		}
	}
	color("orange") {
		for (angle = wheelAngles()) {
			rotate([0, 00, angle]) {
				translate([0, turntableGearPitchRadius - 9.8, 4.5 + floorLayerHeight]) {
					rotate([-90, 0, 0]) {
						wheel();
					}
				}
			}
		}
	}
	color("red") {
		for (angle = wheelAngles()) {
			rotate([0, 0, angle]) {
				translate([0, turntableGearPitchRadius - 14.4, 4.5 + floorLayerHeight]) {
					rotate([-90, 0, 0]) {
						wheelAxis();
					}
				}
			}
		}
	}
}

module wheelsForPrinting() {
	if (len(wheelAngles()) > 0) {
		translate([-len(wheelAngles())*7.5-8, -8, 0])
		for (wheel = [1:len(wheelAngles())]) {
			translate([wheel * 15, 0, 0]) {
				wheel();
			}
			translate([wheel * 15, 15, 0]) {
				wheelAxis();
			}
		}
	}
}

/******************************************************************************************************\
|* This is a trimmed-down and slightly modified version of by https://www.thingiverse.com/thing:43278 *|
\******************************************************************************************************/
WIDTH=40.7;
HEIGHT=12.4;
LENGTH=205;
BEVEL=1;
TRACK_WIDTH=6.2;
TRACK_HEIGHT=3;
TRACK_DIST=20;

BRIDGE_HEIGHT=64;
BRIDGE_R1=214;
BRIDGE_R2=220;

CONN_WIDTH=7.3;
CONN_R=6.5;
CONN_BEVEL=1.7;
CONN_DEPTH=17;

CONN_HEIGHT=11.5;

CONN_MALE_R=6;
CONN_MALE_W=6.5;
CONN_MALE_HOLE_Y=6.8;
CONN_MALE_HOLE_Z=6.4;
CONN_MALE_RIM=1;
CONN_MALE_PROTRUDE=0.75;
CONN_MALE_PROTRUDE_R=1.5;

CONN_FEMALE_R=5.6;
CONN_FEMALE_PROTRUDE_R=1.2;
CONN_FEMALE_BRIDGE_L=6.5;
CONN_FEMALE_BRIDGE_W1=3.5;
CONN_FEMALE_BRIDGE_W2=4.5;
CONN_FEMALE_BRIDGE_RIM=CONN_FEMALE_BRIDGE_W2-CONN_FEMALE_BRIDGE_W1;
CONN_FEMALE_THICK=1.7;

module track_single() {
    square([TRACK_WIDTH,TRACK_HEIGHT]);
}

module track() {
    translate([WIDTH/2-TRACK_WIDTH-TRACK_DIST/2,HEIGHT-TRACK_HEIGHT,0])
        track_single();
    translate([WIDTH/2+TRACK_DIST/2,HEIGHT-TRACK_HEIGHT,0])
        track_single();
}

module body() {
    difference() {
        polygon(points=[[BEVEL,0],[WIDTH-BEVEL,0],[WIDTH,BEVEL],[WIDTH,HEIGHT-BEVEL],[WIDTH-BEVEL,HEIGHT],[BEVEL,HEIGHT],[0,HEIGHT-BEVEL],[0,BEVEL]]);
        translate([0,0,0.01])
            track();
    }
}

module conn_bevel() {
    translate([WIDTH/2-BEVEL,0,0])
    linear_extrude(height=10*HEIGHT)
        polygon(points=[[0,-0.01],[BEVEL+0.01,BEVEL],[BEVEL+0.01,-0.01]]);
}
module connector() {
    rotate([90,90,0])
    {
    hull() {
        translate([-(CONN_WIDTH+2*CONN_BEVEL)/2,-0.01,0])
            cube([CONN_WIDTH+2*CONN_BEVEL, 0.01, 10*HEIGHT]);
        translate([-CONN_WIDTH/2,CONN_BEVEL,0])
            cube([CONN_WIDTH, 0.01, 10*HEIGHT]);
    }
    translate([-CONN_WIDTH/2,0,0])
        cube([CONN_WIDTH, CONN_DEPTH, 10*HEIGHT]);

    difference() {
        translate([0,CONN_DEPTH-CONN_R+1.1,0])
            cylinder(10*HEIGHT,r=CONN_R);
    }

    conn_bevel();
    mirror([1,0,0])
        conn_bevel();

    }
}

module connector_male_protrude() {
    translate([0,CONN_MALE_R-CONN_MALE_PROTRUDE_R+CONN_MALE_PROTRUDE,0])
        cylinder((CONN_HEIGHT-2*CONN_MALE_RIM)/2,r=CONN_MALE_PROTRUDE_R,$fn=20);
}

module connector_male_end(len) {
	intersection() {
		translate([0,50,0])
			cube([100,100,100],center=true);
		union() {
			translate([0,0,CONN_HEIGHT/2-CONN_MALE_RIM])
				hull() {
					cylinder(0.01, r=CONN_MALE_R, $fn=20);
					translate([0,0,CONN_MALE_RIM])
						cylinder(0.01, r=CONN_MALE_R-CONN_MALE_RIM, $fn=20);
				}
			cylinder(CONN_HEIGHT/2-CONN_MALE_RIM, r=CONN_MALE_R, $fn=20);
		}
	}
}

module connector_male_bridge(len) {
    hull() {
        cube([len-CONN_MALE_R,0.01,CONN_HEIGHT/2], center=true);
        translate([0,CONN_MALE_RIM,-CONN_MALE_RIM/2])
            cube([len-CONN_MALE_R,0.01,CONN_HEIGHT/2-CONN_MALE_RIM], center=true);
    }
    translate([0,-(CONN_MALE_W-2*CONN_MALE_RIM)/4,0])
        cube([len-CONN_MALE_R,(CONN_MALE_W-2*CONN_MALE_RIM)/2,CONN_HEIGHT/2], center=true);
}

module connector_male_quart(len) {
    connector_male_end(len);
    translate([(len-CONN_MALE_R)/2,CONN_MALE_W/2-CONN_MALE_RIM,CONN_HEIGHT/4])
        connector_male_bridge(len);
}

module connector_male(len) {
	rotate([0, 0, 180])
    translate([CONN_MALE_R,0,CONN_HEIGHT/2]) {
        connector_male_quart(len);
        mirror([0,0,1])
            connector_male_quart(len);
        mirror([0,1,0]) {
            connector_male_quart(len);
            mirror([0,0,1])
                connector_male_quart(len);
        }
    }
}

/******************************************************************************************************\
|* This bearing was once inspired by https://www.thingiverse.com/thing:2746804                        *|
\******************************************************************************************************/
module bearing() {
	rotate_extrude() {
		difference() {
			translate([4, 0]) square([7, 7]);
			translate([7.625, 0]) extractPolygon();
		}
	}
	for (angle=[0:40:360]) {
		rotate([0, 0, angle]) translate([7.62, 0]) bearingPin();
	}
}

module bearingPin() {
	half_pin();
	translate([0,0,7]) {
		mirror([0,0,1]) {
			half_pin();
		}
	}
}

module half_pin() {
	cylinder(0.25, 2.25, 2.5);
	translate([0,0,0.25]) cylinder(1.15, r=2.5);
	translate([0,0,1.40]) cylinder(1.40, 2.5, 1.5);
	translate([0,0,2.80]) cylinder(0.70, r=1.5);
}

module extractPolygonPart() {
	polygon([[2.925, 0], [2.675, 0.25], [2.675, 1.40], [1.7, 2.80], [1.7, 3.5], [0, 3.5], [0,0]]);
}

module extractPolygon() {
	extractPolygonPart();
	translate([0, 7, 0]) mirror([0, 1, 0]) extractPolygonPart();
	mirror([1, 0, 0]) {
		extractPolygonPart();
		translate([0, 7, 0]) mirror([0, 1, 0]) extractPolygonPart();
	}
}

```


[User]
Hi! I'm looking to create a parametric spool holder adapter for my Ender 3. I want to be able to use it to make the spool spin smoothly on the stock holder. I've seen a few designs online, but I'd like to make my own, and I'm hoping you can help generate the OpenSCAD files.

Here are the key elements:

1.  **Bearings:** The design needs to incorporate two standard 608 bearings.

2.  **Threaded Rod:** It should use a 5/16" threaded rod for the central axle, about 14cm long. I will need to use two matching nuts to secure it.

3.  **Spacers:** There will be several spacers needed, specifically:
    *   Two small spacers that fit over a small tube (dimensions provided below).
    *   One larger spacer that fits over the big tube on the stock holder (dimensions provided below).
    *   An adapter to transition between the small spacer and the threaded rod
    *   A washer to go on the adapter
    *   A washer to go on the end of the rod.

4.  **Stock Compatibility:** The parts will have to interface with the stock Ender 3 spool holder.

5.  **Parametric Design:** It's critical that the design is parametric, so I can easily adjust the dimensions if needed, because Creality seems to make slight changes to their parts from time to time. I'd like to be able to easily adjust diameters, lengths, and overall spacing.

Here are the specific dimensions I'm working with:

*   **Big Tube (stock spool holder):**
    *   Outer radius: 13.0 mm
    *   Inner radius: 11.2 mm
*   **Small Tube (used in adapter):**
    *   Inner radius: 4.3 mm
    *   Outer radius: 5.8 mm
*   **Threaded Rod Diameter:** 5/16" (roughly 7.9375 mm), so I guess make the hole radius 4mm and assume it has a tight fit.
*   **Bearing Dimensions:** Standard 608, with a 22 mm outer diameter, 8 mm inner diameter, and 7mm thickness. Assume the bearings will sit on a flat surface or up against a cylindrical surface.
*   **Spacer Lengths**
    *   The longer small tube spacer length should be around 60mm
    *   The shorter small tube spacer length should be about 5mm
    *   The big tube spacer length should be about 85mm
    *   The adapter spacer lengths should be 28, 5, and 5mm, respectively.
    *   The adapter washer thickness should be 2mm.
    *   The end washer should have a 5mm total thickness with a 1mm recessed section.

I want the final output to be a few separate .scad files, if that is the best way to organize things, which will then work together to produce the final printed pieces.

I expect that this will involve using basic primitives (cylinders, cubes, differences), along with things like translate and rotate. I'm not requesting any fancy libraries at this time. I'm going to do the boolean math and rotations, so you don't need to worry about that, just generate the basic modules for all the pieces.

Let me know if you have any questions.

[Assistant]
spool_mod.scad:
```

/* [Diameters] */
big_tube_outer_radius = 13.0; // 13.2 was a bit tight
big_tube_inner_radius = 11.2;

small_tube_inner_radius = 4.3;
small_tube_outer_radius = 5.8; // ??

/* [misc] */
print_layout=1;
hide_existing=1;
spacing = ($t < .25) ? 0 : ($t < .75) ? 60 * ($t-.25) : 30;//30;

//test_pieces();

rotate([0,90,0])
{

if (hide_existing==0) {
translate([0,0,25.5])
bearing();

translate([0,0,94.2])
bearing();

// rod
translate([0,0,-22])
cylinder($fn=30, 140,4,4);

translate([0,0,-20])
nut();
translate([0,0,108])
nut();

}

//spacers
if (print_layout==1) {
translate([0,20,50])
rotate([0,-90,0])
spacer(small_tube_outer_radius, small_tube_inner_radius, 60);
}
else {
translate([0,spacing,0])
translate([0,0,33.8])
spacer(small_tube_outer_radius, small_tube_inner_radius, 60);
}

if (print_layout==1) {
translate([0,30,70])
rotate([0,-90,0])
spacer(small_tube_outer_radius, small_tube_inner_radius, 5);
}
else {
translate([0,spacing*1,0])
translate([0,0,102.5])
spacer(small_tube_outer_radius, small_tube_inner_radius, 5);
}

if (print_layout==1) {
translate([0,-20,50])
rotate([0,-90,0])
spacer(big_tube_outer_radius, big_tube_inner_radius, 85);
}
else {
translate([0,spacing*-1,0])
translate([0,0,25])
spacer(big_tube_outer_radius, big_tube_inner_radius, 85);
}

if (print_layout==1) {
translate([-6,20,20])
rotate([0,-90,0])
    adapter();
}
else {
translate([0,spacing,0])
adapter();
}

if (print_layout==1) {
translate([-7,45,45])
rotate([0,-90,0])
    adapter_washer();
}
else {
translate([0,spacing,-1 - spacing/4])
adapter_washer();
}

if (print_layout==1) {
translate([-13,-20,15])
rotate([0,-90,0])
end_washer();
}
else {
translate([0,spacing, - spacing / 2])
end_washer();
}

//cylinder($fn=30, 24.2,5,5);
//cylinder($fn=30, 23.5,10,10);

if (hide_existing==0)
stock_tube();

}

module adapter()
{
union() {
translate([0,0,-3.0])
spacer(small_tube_outer_radius, small_tube_inner_radius, 28);

translate([0,0,-6])
spacer(18, small_tube_inner_radius, 5);

*translate([0,0,-7])
spacer(14.75, small_tube_inner_radius, 5);

}
}

module adapter_washer()
{
    // washer is 2mm thickness
    translate([0,0,-7])
    spacer(14.5, small_tube_inner_radius, 2);

}

module end_washer()
{
    color("yellow",.3)
    render()
    difference()
    {

    translate([0,0,-13])
    spacer(18, small_tube_inner_radius, 5);

    // 1 mm depth
    translate([0,0,-9])
    spacer(15, small_tube_inner_radius, 1);

    }

}

module test_pieces()
{

translate([0,22,0])
spacer(4.8, 4, 5);

translate([0,35,0])
spacer(4.6, 4, 5);

*translate([-0,-0,0])
spacer(13.2, 11.2, 10);

}

module bearing()
{
    color("silver")
    render()
    difference() {
        cylinder($fn=30, 8., 11, 11);
        cylinder($fn=30, 8., 3.5, 3.5);
    }

    color("black")
    render()
    translate([0,0,-.005])
    difference() {
        cylinder($fn=30, 8.01, 9.5, 9.5);
        cylinder($fn=30, 8.01, 5.5, 5.5);
    }

}

module nut()
{
    color("blue")
    spacer(6,2.5,7);
    //import //("/home/dan/3d_print/models/nuts_bolts/long_nut_1_5.stl");

}

module spacer(od, id, length)
{
    color("yellow",.3)
    render()
    difference() {
        cylinder($fn=30, length, od, od);
        cylinder($fn=30, length, id, id);
    }
}

module stock_tube()
{
    color("white",.2)
    render()
    intersection() {
    difference() {
        cylinder($fn=30, 110., 15, 15);
        translate([0,0,24])
        cylinder($fn=30, 86., 13.25, 13.25);

        cylinder($fn=30, 24., 10, 10);

    }
    *color("yellow",.3)
    translate([-20,0,-5])
    cube([40,40,120]);
    }
}
```


[User]
Okay, I'm looking to get a parametric Bahtinov mask designed for telescope focusing. I have an existing .scad file that works, but I’d like something cleaner and easier to adjust. I want it to be fully customizable for different telescopes, meaning I want to be able to specify the telescope's aperture, focal length, and the cap’s geometry so that it can fit snugly.

Here’s what I’m thinking in terms of parameters:

**Telescope Geometry**
*   `focalLength`: (mm) The focal length of the telescope or camera.
*   `aperture`: (mm) The inner diameter of the hole where the cap sits on the telescope.

**Cap Geometry**
*   `capDepth`: (mm) How deep the cap sits inside the telescope's hole.
*   `capEdge`: (mm) How far the cap extends beyond the telescope's aperture.
*   `capThickness`: (mm) The thickness of the cap material.
*   `capWall`: (mm) The thickness of the wall that fits inside the telescope hole.

**Mask Geometry**
*   `bFactor`: A Bahtinov factor. I think 150-200 should be a good range, but I'd like to adjust it.
*   `minimumSlat`: (mm) The minimum size of the mask slats.
*   `slatAngle`: (deg) The angle between slats in different regions of the mask (I'd like this to be adjustable, say, in the 0-90 degree range).
*   `shadowSize`: (mm) The size of the center shadow disc, if there is one.

The design needs to produce a cap that has a circular base with a lip to fit into the telescope aperture. The mask part sits on top of this base. The mask itself needs to have three sets of slats: one vertical, and then two others angled from vertical, all arranged around a central region (possibly with a shadow disk in the middle).

I'd ideally like the design to compute the slat spacing automatically based on the `focalLength` and `bFactor`, ensuring that slats are no smaller than `minimumSlat`.

For libraries, I do not need external ones beyond what is included in a default installation, but if you can make it work using BOSL, that would be a great addition for potential future complexity. Specifically, it would be nice if the cap construction could make use of BOSL's `cylinder_ext()` and related functions.

Could you generate the necessary .scad file(s) for this?

[Assistant]
bahtinov.scad:
```
// bahtinov mask
// https://en.wikipedia.org/wiki/Bahtinov_mask

/*[ Telescope Geometry ]*/

// (mm) focal length of telescope or camera
focalLength = 900;

// (mm) inner diameter of the hole the cap sits inside
aperture = 150;

/*[ Cap Geometry ]*/

// (mm) how deep the cap sits inside the hole
capDepth = 15;

// (mm) how far beyond the aperture the cap extends
capEdge = 8;

// (mm) how thick the cap is
capThickness = 3;

// (mm) how thick the wall is that sits inside the hole
capWall = 4;

/*[ Mask Geometry ]*/

// Bahtinov factor
bFactor = 150; // [150:200]

// (mm) slats will not be smaller than this
minimumSlat = 2;

// (deg) angle between slats in different regions
slatAngle = 30; // [0:90]

// (mm) size of the center shadow structural disc
shadowSize = 0;

//
// END OF CONFIGURATION
//

// calculate the minimum slat stride
function slatStride(i) = (i * focalLength / bFactor > 2 * minimumSlat) ? (i * focalLength / bFactor) : slatStride(i + 2);

module slats(angle, d, offs) {
    stride = slatStride(1);
    endi = ceil(d / stride / 2);
    rotate([0, 0, angle]) intersection() {
        union() for (i = [-endi : endi]) translate([0, i * stride + offs]) {
            square([d, stride / 2], true);
        }
        circle(d=d);
    }
}

module mainSlats(d) {
    dividerSize = slatStride(1) / 2;
    intersection() {
        slats(0, d, 0);
        translate([-(d + dividerSize) / 2, -d / 2]) square([d / 2, d]);
    }
}

module upperSlats(d) {
    dividerSize = slatStride(1) / 2;
    intersection() {
        slats(slatAngle, d, dividerSize * cos(2 * slatAngle) / 2);
        translate([dividerSize / 2, dividerSize / 2]) square(d / 2, d / 2);
    }
}

module allSlats(d) {
    difference() {
        union() {
            mainSlats(d);
            upperSlats(d);
            mirror([0, 1]) upperSlats(d);
        }
        circle(d=shadowSize);
    }
}

module baseCap() {
    // the bottom layer
    cylinder(h=capThickness, d=aperture + 2 * capEdge);

    // the inside wall
    translate([0, 0, capThickness]) {
        // outer cylider - inner cylinder
        difference() {
            // outer cylinder has a chamfer
            union() {
                cylinder(h=capDepth - capWall / 2, d=aperture);
                translate([0, 0, capDepth - capWall / 2]) {
                    cylinder(h=capWall / 2, d1=aperture, d2=aperture - capWall);
                }
            }
            // inner cylinder
            cylinder(h=2 * capDepth, d=aperture - 2 * capWall);
        }
    }
}

module capWithSlats() {
    difference() {
        baseCap();
        translate([0, 0, -capThickness / 2]) linear_extrude(2 * capThickness) {
            allSlats(aperture - 2 * capWall);
        }
    }
}

$fn=128;
capWithSlats();

```


[User]
I'm looking to create a parametric OpenSCAD model of stairs, similar to the one I have, but I need something more flexible and easier to customize. I'd like the design to be based on standard stair calculations, and to be able to handle different scale models.

Here's what I'm envisioning:

*   **Parametric Design:** The whole thing needs to be customizable through parameters. This includes:
    *   **Scale:** I should be able to specify a scale for model trains (like N, HO, O, G) which will impact the sizing of the stairs.
    *   **Stair Dimensions:** I'd want to be able to input the run (horizontal step), total rise (total vertical height), tread thickness, and individual rise (vertical height of each step), exactly as I would for a real staircase.
    *   **Calculated Values:** The script should use these inputs, and perhaps other calculations, to determine things like the total run, number of steps, stringer length and angle etc. It's okay if some of these values are just derived from the base inputs, but they should be easily accessible for my calculations.
    *  **Optional Dimensions:** Tread width, stringer thickness, tread overhang, baluster width and height, and balustrade width should all be parameters.
    * **Print Options:** The output needs to have different modes - one where the stairs are displayed in a 3D model, and another where the parts are laid flat for easy 3D printing on a standard printer.

*   **Stair Structure:**
    *   **Stringers:** There should be two stringers, on the left and right, that support the stairs. The stringers need to be properly shaped based on rise and run values.
    *   **Treads:** There should be individual treads for each step. I'd like to be able to set the width of each tread and support them with small brackets.
    *  **Railing:** I'd like to add optional balusters (vertical posts) and a balustrade (the rail). They should also be parametric in terms of height and width. The balusters should align with the front of each step.

*   **Build Plate:**
    * The ability to include a build plate outline would be incredibly helpful.  This would be similar to a build plate library for customizer from Thingiverse - just a simple visual guide that is not rendered in the final model, but rather just for the layout.

*   **Libraries:** I'm not particular about specific libraries as long as the design is flexible and easy to use. I'd assume you could make good use of OpenSCAD's built-in functions though, so no need to reinvent the wheel there.

I've previously used a script that incorporates some of this, and it was okay, but I really want to streamline the design process and make it a lot easier for others to use. It would be great if the different outputs could be easily toggled - and of course if the units are correctly scaled based on the model scale selected. I am not asking for any specific library to be used here as I am not familiar with the OpenSCAD libraries, and I am leaving it to you to make the best selection to accomplish this task.

Can you help me generate the SCAD code for this? I want all code (except libraries) to be created from scratch.

[Assistant]
Stairs.scad:
```
//
//  Customizable Stairs
//  Mark DiVecchio
//  Nov 2019  V1.0
//  Original development using OpenSCAD 2017.01.20
//
// This SCAD script is licensed under a
// Creative Commons Attribution-NonCommercial 3.0 Unported License.
//
//
/*
Stair values from this web page:

https://www.calculator.net/stair-calculator.html

Use the "Comprehensive Version" of the Stair Calculator.

This program is capable of building every stair possible. I believe that if you
always make the Total Rise equal to an integral multiple of the Rise, the program
will be able to build the stair.

Enter your values into the equations on that web page. Select the "Use One Run" tab.
Set "Fixed Rise", "Has tread", "No headroom restriction" and "Standard stringer mount"
Also enter values here for Run, Total Rise, Rise and Tread thickness. Enter
a Thread Thickness of 1 inch. Then press "Calculate".

Enter the Results from that web page into this script's customizer. You may have to reenter
the Rise if the calculator could not work with your suggested Rise.
The Stairs OpenSCAD program does not need every Result value.

More information about stairs equations:

https://www.jlconline.com/training-the-trades/stair-stringers-calculation-and-layout_o

Uses Build Plate from the Thingiverse library.

3D printers may have a hard time with HO and N part thickness.
G scale stairs may not fit on a typical build plate and each part of the stairs may have to
be printed individually.

I've added the stairs to Thingiverse here:
https://www.thingiverse.com/thing:3971212

My web page: http://www.silogic.com/trains/layout.html
*/
// http://www.silogic.com/trains/layout.html
//
$fn=32 * 1;
//
// CUSTOMIZING
//

/* [Model Railroad Scale] */
// Model Railroad Scale (3D printers may have a hard time with HO and N scale lumber)
Scale = 48; //[160:N, 87:HO, 60:S, 48:O, 22.5:G]

/* [Inputs to Calculator] */
// Run in Inches (Horizontal measurement of each individual step)
Run = 10.0; //[9.0:0.25:11.0]
// Total Rise in feet (from finished floor to finished floor)
Total_Rise = 12; //[1.0:0.1:50.0]
// Tread Thickness in inches
Tread_Thickness = 1.0; //[1.0:0.25:2.0]

/* [Results from Calculator] */
// Rise in inches (Vertical measurement of each individual step)
Rise = 8.0; //[7.0:0.25:8.0]
// Total Run in feet
Total_Run = 14.166;   //[1.0:0.1:50.0]
// Number of Steps (total horizontal distance)
Number_of_Steps = 17;   //[1:1:50]
// Stringer Length in feet
Stringer_Length = 18.097;   //[1.0:0.25:50.0]
// Stringer Height in feet
Stringer_Height = 11.025;   //[1.0:0.25:50.0]
// Angle in Degrees
Angle = 38.66;   //[1.0:0.5:89.0]
// First Step Height in inches
First_Step_Height = 8.0;   //[7.0:0.25:11.0]

/* [Optional Dimensions] */
// Tread Width in inches
Tread_Width = 36;   // [12.0:0.25:48.0]
// Thickness of Stringers in inches (Most open stringers are cut from 2x12 stock)
Stringer_Thickness = 1.5;  // [1.0:0.25:3.0]
// Tread Overhang in inches
Tread_Overhang = 0.5;   // [0.25:0.25:2.0]
// Baluster (posts) Width in inches (will be square)
Baluster_Width = 2.0;    //[2.0:0.25:4.0]
// Baluster (posts) Height in inches
Baluster_Height = 36; //[24.0:0.25:60.0]
// Balustrade (railing) Width in inches (will be square)
Balustrade_Width = 2.0;    //[2.0:0.25:4.0]

/* [Print] */
// Display or Create Printable parts layout for STL
CreateSTL = "Display";   //[Display,Print]
//
/* [Build Plate] */
// defaults to Prusa i3 Mk2 build plate size
// Show a Build Plate in Customizer. It will not be rendered. Set size below.
show_build_plate="yes"; //[yes,no]
//when show_build_plate is set to "yes" this controls the build plate x dimension (in mm)
build_plate_x = 250; //[100:25:400]
//when show_build_plate is set to "yes" this controls the build plate y dimension (in mm)
build_plate_y = 210; //[100:25:400]

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

/* [Hidden] */
inch=25.4;
SFin = inch/Scale;
SFft = 12 * inch/Scale;
show_stringer = true;
show_tread = true;
show_railing = true;

if (show_build_plate=="yes") {
    build_plate(build_plate_x, build_plate_y);
}

translate([Total_Run * SFft/-2, Total_Rise * SFft/-2, 0])
    print_part();

  /////////////
 // Modules //
/////////////

module print_part() {
    //
    // ASSEMBLE STAIRWAY
    //

    // Generate an outline of the stairway area
    if (CreateSTL == "Display") {
        color("red", 0.5)   // This outline will not be rendered
            translate([0, 0,-Stringer_Thickness * SFin])
            %cube([Total_Run * SFft, Total_Rise * SFft, Stringer_Thickness * SFin]);
    }
    // Left side stringer
    if (show_stringer == true) if (CreateSTL == "Display") {
        // Displayable stringer
        Stringer();
    } else {
        // Printable Stringer
        translate([0, -0.5 * Rise * SFin, 0])
            Stringer();
    }
    // Right side stringer
    if (show_stringer == true) if (CreateSTL == "Display") {
        // Displayable stringer
        translate([0, 0, (Tread_Width - (Stringer_Thickness)) * SFin])
            Stringer();
    } else {
        // Printable stringer
        translate([0, -3 * Rise * SFin, 0])
            Stringer();
    }
    // Treads
    if (show_tread == true) if (CreateSTL == "Display") {
        // Displayable treads
        for (i = [1 : Number_of_Steps ]) {
            translate([(i-1) * Run * SFin, i * Rise * SFin, 0])
            Tread();
        }
    } else {
        // Printable treads
        for (i = [1 : Number_of_Steps ]) {
            rotate([-90, 0, 0])
            translate([(i-1) * (Run * 1.25) * SFin, 0, -8 * Rise * SFin])
            Tread();
        }
    }
    // Baluster
    if (show_railing) for (i = [1 : Number_of_Steps ]) {
        translate([(i-1) * Run * SFin + ((Baluster_Width / 2) * SFin),i * Rise * SFin,0])
        Baluster();
    }
    // Balustrade
    if (show_railing) Balustrade();
}

//
module Stringer () {
    // first step
    color("black", 1.0)
        translate ([0, 0, 0])
        cube([Run * SFin, (First_Step_Height) * SFin, Stringer_Thickness * SFin]);
    // Other Steps
    for (i = [1 : Number_of_Steps - 1 ]) {
        color("black", 1.0)
            translate ([i * Run * SFin, (((i-1)  * Rise)) * SFin, 0])
            linear_extrude(height = Stringer_Thickness * SFin)
            polygon([[0,0],
                [0, (First_Step_Height + Rise) * SFin],
                [Run * SFin, (First_Step_Height + Rise) * SFin],
                [Run * SFin, tan(Angle) * Run * SFin]
                ]);
        }
    //
    }
module Tread() {
    color("green", 1.0)
        translate([ -Tread_Overhang * SFin, -Tread_Thickness * SFin, 0])
        cube([ (Run + Tread_Overhang) * SFin, Tread_Thickness * SFin, (Tread_Width) * SFin]);
    // support brackets
    color("white", 1.0)
        translate([(Run/2 - (6/2)) * SFin, -4 * SFin, (Stringer_Thickness) * SFin])
        cube([6 * SFin, 4 * SFin, 2 * SFin]);
    color("white", 1.0)
        translate([(Run/2 - (6/2)) * SFin, -4 * SFin, (Tread_Width - (Stringer_Thickness * 2) - 0.5) * SFin])
        cube([6 * SFin, 4 * SFin, 2 * SFin]);

}

// The Balusters - the vertical posts holding the Balustrade
module Baluster() {
    color("blue", 1.0)
        translate([0,0,0])
        cube([Baluster_Width * SFin, Baluster_Height * SFin, Baluster_Width * SFin]);
}

// The Balustrade - what we might call the railing
module Balustrade() {
    color("blue", 1.0)
        translate([0, (Baluster_Height + Rise - tan(Angle) * 2 * Baluster_Width) * SFin, 0])
        rotate(Angle)
        cube([Stringer_Length * SFft, Balustrade_Width * SFin, Balustrade_Width * SFin]);
}

module build_plate(manX,manY){
    /*
    Build Plate Library for Customizer by MakerBot
    Published on January 23, 2013
    www.thingiverse.com/thing:44094
    */

    CenterX = 0;
    CenterY = 0;
    // This build plate will not be rendered - for layout on the buld plate only
	translate([CenterX,CenterY,-.52])
		%cube([manX,manY,1],center = true);

	translate([CenterX,CenterY,-.5]){
		for(i = [-(floor(manX/20)):floor(manX/20)]){
			translate([i*10,0,0])
				%cube([.5,manY,1.01],center = true);
		}
		for(i = [-(floor(manY/20)):floor(manY/20)]){
			translate([0,i*10,0])
				%cube([manX,.5,1.01],center = true);
		}
    }
}
```


[User]
I need a custom tie design for a 3D print, and I'd like to be able to adjust its dimensions using parameters. I've got some basic ideas, but I'd really appreciate it if you could generate the OpenSCAD code for it.

The tie needs to have a main body with a rectangular base, and a central reinforcing spine running along its length. The tie will be used to wrap around an object, so its overall length will need to be significantly larger than the diameter of the object it's meant to tie.

Here are the key parameters I'd like to control:

*   `Height`: This controls the overall thickness of the tie (in mm).
*   `Core`: This is the width of the central reinforcing spine, and it will also heavily affect the overall width of the tie.
*   `MaxDiameter`: The maximum diameter of the object that the tie is meant to wrap around (in mm).
*   `View`: A parameter that lets me choose to see either just the tie itself or to see both the tie and some dimensional text labels.

The tie should have a "handle" section at one end, consisting of a rectangular extension with a cutout. The spine should extend along the entire length of the tie, and it should end in a small cylinder at the tip. I'd like to have triangular "fins" that reinforce the tie and are distributed along its length, and I also want the code to include text labels showing the overall dimensions of the tie when `View` is set to "all".

The overall width of the tie (excluding the triangular fins) should be three times the `Core` parameter. The cutout in the "handle" should have a width of `Core` * 1.4 and a height of twice the `Height` plus 1. The fins should be triangular and equally spaced, with the base of each triangle covering the full width of the tie. The spacing between them should be based on the width of the tie and the overall length of the tie. Also, a small cylinder with a diameter the same as the width of the core should be placed at the tip of the spine, which should be aligned with the base of the tie. The length of the tie should be approximately the circumference of the object with a diameter of `MaxDiameter`, plus some extra to allow for easy fastening.

I want the text labels to show the width and total length of the tie in millimeters.

Could you generate the OpenSCAD code for this, please? I'm looking forward to seeing what you come up with.

[Assistant]
TPU_CT.scad:
```
// of the tie (mm).
Height = 1.6; // [1:0.2:5]
//. Width of the central part of the tie, this will affect its strength significantly. Total width will be 3 times this value (mm).
Core = 3; // [2:1:15]
// of the object the tie will contain. This will affect the length of the tie (mm).
MaxDiameter = 30; // [10:10:200]
//
View = "all"; // [all:All,tie:Tie only]
/* [Hidden] */
agarre_inicial = 20;
espesor = Height;
ancho_central = Core;
diametro = MaxDiameter+espesor;
largo = diametro*3.1415927;
ancho = ancho_central*3;
alt_triangulos = ancho/2;
triangulos = ceil((largo-15+alt_triangulos)/alt_triangulos);
ancho_ojal = ancho_central*1.4;
largo_ojal = (espesor*2)+1;
inicio_t = agarre_inicial+largo_ojal+15;
ver();
module ver() {
    if (View == "all") {
        echo("quiero ver todo");
        tie();
        dimensiones();
    }
    else { tie(); }
}
module tie() {
    difference() {
    cube([ancho,inicio_t,espesor]);
    translate([((ancho-ancho_ojal)/2),agarre_inicial,0])
    cube([ancho_ojal,largo_ojal,espesor]);
    }
    for (a = [inicio_t:alt_triangulos:((triangulos-1)*alt_triangulos)+inicio_t]) {
        translate([0,a,0]) {
            linear_extrude(height=espesor) polygon(points=[[0,0],[(ancho/2),alt_triangulos],[ancho,0]]);
        }
    }

    translate([((ancho-ancho_central)/2),inicio_t,0])
    cube([ancho_central,(triangulos*alt_triangulos)+20,espesor]);
    translate([(ancho/2),(triangulos*alt_triangulos)+inicio_t+20,0])
    cylinder(espesor,ancho_central/2,ancho_central/2,$fn = 12);
}
module dimensiones() {
    largo_total = inicio_t+(triangulos*alt_triangulos)+20+(ancho_central/2);
    translate([ancho+20,(largo_total/2)-30,2])
    rotate([0,0,90]) text(text=str(largo_total,"mm"));
    translate([-10,-20,2])
    text(text=str(ancho,"mm"));
}

```


[User]
Hey there, I'm looking to create a custom top punch for reloading bullets, specifically for use with a Lyman lubri-sizer. I need a way to protect the delicate tips of spire-point bullets during the sizing process, so I'm thinking a recessed punch that matches the bullet's nose profile would be ideal.

I've seen some designs that use a secant ogive shape, and that seems to work well. Here are some of the parameters I think are necessary to customize the punch:

*   **Bullet Diameter:** This will be the diameter of the main punch body.
*   **Punch Length:** The overall length of the punch.
*   **Ogive Radius:** The radius of the circle used to form the ogive portion of the bullet's nose.
*   **Secant Length:** The length along the bullet axis that the secant portion extends.
*   **Nose Depth Percentage:** How deep to recess the punch nose, expressed as a percentage of the distance from the full ogive to the bullet's diameter.

I'd like to be able to adjust all of these parameters. Also, I will want to be able to specify a low and high resolution for preview and print. I have an example of an existing SCAD file, but I'd like to be able to do this parametric from the start.

I'm not sure if this is enough information, but I'd also like the punch to have a small cylindrical step at the very top for the lubri-sizer's ram to engage. I think the example I included also has another slightly wider cylindrical section, but I'm not sure how important that is. Can you provide an OpenSCAD file that will allow me to customize all of these parameters? I'm familiar with OpenSCAD. Thanks!

[Assistant]
Bullet_Nose_Secant.scad:
```
// High Resolution ($fn=[36:360])
H_Res = false;
$fn=H_Res?360:36;

// Bullet Diameter
diameter = 0.301;
// Length of Punch
length = 0.330;
// Tangent Ogive Radius
ogive = 2.92;
// Secant Length
secant_length = .490;
// Depth of Nose %
depth = 50; // [0:75]

module secant(Sd,Sl,Or,d){
    inch = 25.4;
    bullet_radius = Sd/2 * inch;
    ogive_radius = Or * Sd * inch;
    secant_length = Sl * inch;
    alpha = acos((ogive_radius - bullet_radius)/ogive_radius);
    depth = ogive_radius * sin(alpha) * (100-d)/100;

    translate([0,0,-depth]){
        rotate_extrude(angle = 360) {
            intersection() {
                translate ([bullet_radius-ogive_radius,0,0]) {
                    circle(ogive_radius);
                }
                square ([bullet_radius, ogive_radius]);
            }
        }
        cylinder(secant_length + 0.025 *inch , 0.030 * inch, 0.030 * inch);
    }
}

module top_punch(diam,len) {
    in = 25.4 + 0;
    union() {
        cylinder((len + 0.005) * in,(diam/2 -0.005) * in, (diam/2 -0.005) * in);
        translate([0,0,len* in]) {
            cylinder(0.175 * in,(0.475 * in)/2,(0.475 * in)/2);
        }
        translate([0,0,(len + 0.170) * in]) {
            cylinder(0.437 * in,(0.260 * in)/2,(0.260 * in)/2);
        }
    }
}
difference (){
    top_punch(diameter, length);
    secant(diameter,secant_length,ogive,depth);
}

```


[User]
Hey, I'm looking to get a parametric phone/tablet mount designed, something that I can 3D print. I want it to be pretty customizable for different phone sizes, and I'd like it to be able to attach to standard camera mounts.

Here are the specifics:

*   **Basic Shape:** The core of the mount should be a sort of open-ended clamp, where the phone is held between two curved arms. I'd like to be able to define the width and thickness of the phone, and the mount should adjust to those dimensions. Think of it as a C-shape but with the ends being circular to hug the phone.
*   **Size Adjustment:** I need to be able to adjust the overall height of the mount.
*   **Side Cutouts:** Some phones have buttons on the side, so I'd like parameters to define cutouts on the left and right sides of the mount. For each side, there should be a height, vertical position, and width parameter for the cutout. If no cutouts are needed, these parameters can be set to zero.
*   **Wall Thickness:** I want to be able to set how thick the walls of the mount are going to be.
*   **Grip Adjustment:** It would be great if there was a way to adjust the grip of the mount. Maybe a percentage based parameter that can slightly change the curvature of the arms. A negative value would tighten the grip, and a positive value would loosen it. I would like to be able to adjust how much of the circle is visible or used to clamp the phone.
*  **Mounting:** The base of the mount should include a 3/8 inch threaded boss. This is so that I can attach it to a standard camera tripod mount using an adapter. So I need the boss and the screw thread itself.
* **Units** Please use millimeters.

I think that's it. I'm hoping this can be done using OpenSCAD, and I don't need any fancy libraries. I'm aiming for good print quality, so could you set `$fn=60` in the code by default? This should make it nice and smooth. I appreciate your help with this!

[Assistant]
Universal_phone_clip_openscad_10.scad:
```
// measurements in mm

// Export quality
$fn=60; //[20:Low,40:Medium,60:High]

//Width of your phone/tablet, in mm. Try your exact width first, if it's too loose in the mount, make the mount width 1 or 2mm smaller, depending on how much grip you want. The mount structure should flex to accomodate, especially in ABS. Width and height are references to the phone in it's portrait orientation. Keep in mind, the phone grips are designed for rounded edges. If your phone has sharper edges, you may have to go slightly wider.
phoneWidth=75;

phoneThickness=8;

mountHeight=70;

//A cutaway for buttons on the right side, if you don't have any, set it to 0
rightCutawayHeight=50;

//Location of the right side cutaway. 0 is the middle, positive number goes down, negative goes up.
rightCutawayLocation=35;

//A cutaway for buttons on the left side, if you don't have any, set it to 0
leftCutawayHeight=0;

//Location of the left side cutaway. 0 is the middle, positive number goes down, negative goes up.
leftCutawayLocation=0;

//How thick will you be printing this. Default value is a good balance. Thicker = stronger grip, but harder to mount/unmount.
wallThickness=1.8;

//This is expressed as a percentage, from -100 to 100. Negative values will make the opening smaller, positive will make it bigger. A bigger opening will make clipping the phone into the mount easier, but it eats away at the mounting surface, making device less secure. Positive 100% is basically unusable, as there is no concave left, and negative 100% makes the grip a perfect half-circle which is usable only if you slide the phone in from the side, but offers a lot of grip.
moreOrLessOpening=20;

module generateEndCircle2d(yOffset) {
   difference() {
       offset(r = wallThickness) {
           translate([0,yOffset]) circle(phoneThickness/2);
       }
       offset(r = 0) {
           translate([0,yOffset]) circle(phoneThickness/2);
       }
   }
}

module generateEndCircle2dInside(yOffset) {
    translate([0,yOffset]) circle(phoneThickness/2);
}

module generateFrameCircle2d(yOffset,zOffset,circleHeight) {
    difference() {
       offset(r = wallThickness) {
           translate([zOffset,yOffset]) scale([0.4,1,1]) circle(circleHeight);
       }
       offset(r = 0) {
           translate([zOffset,yOffset]) scale([0.4,1,1]) circle(circleHeight);
       }
    }
}

module generateFrameCircle2dInside(yOffset,zOffset,circleHeight) {
    translate([zOffset,yOffset]) scale([0.4,1,1]) circle(circleHeight);
}

module generateFull3dShape() {
    linear_extrude(mountHeight, twist = 0, slices = 0, center=true) {
        generateEndCircle2d(phoneThickness/2);
        generateEndCircle2d(phoneWidth-phoneThickness/2);
        generateFrameCircle2d(phoneWidth/2,-3,phoneWidth/2-(phoneThickness/2)*0.75); //compensate for different sizes
    }
}

module generateInside3dShape() {
    translate([0,0,-10]) linear_extrude(mountHeight+40, twist = 0, slices = 0, center=true) {
        generateEndCircle2dInside(phoneThickness/2);
        generateEndCircle2dInside(phoneWidth-phoneThickness/2);
        generateFrameCircle2dInside(phoneWidth/2,-3,phoneWidth/2-(phoneThickness/2)*0.75);
    }
}

module booleMainShape() {
    difference() {
        generateFull3dShape();
        generateInside3dShape();
    }
}

module generateFrontCutoutCube(openingCompensation){
    openingTrim=(phoneThickness/2)*(openingCompensation/100);
    translate([0,phoneThickness/4-openingTrim/2,-mountHeight])
    cube([80,phoneWidth-phoneThickness/2+openingTrim,mountHeight*2],center=false); //big cube
}

module generateTopCutoutCube(x,y,z){
    translate([x,phoneWidth-phoneThickness/2,z-rightCutawayHeight/2])
    cube([phoneThickness*8,80,rightCutawayHeight],center=false); //cutaway cube
}

module generateBottomCutoutCube(x,y,z){
    rotate([180,0,0]) translate([x,-phoneThickness/2,z-leftCutawayHeight/2])
    cube([phoneThickness*8,80,leftCutawayHeight],center=false); //cutaway cube
}

module generateScrewBoole() {
    translate([-(phoneWidth/2-(phoneThickness/2)*0.75)*0.4-12,phoneWidth/2,0])
    rotate([90,0,90])
    cylinder(20,5,5);
}

union() {
    difference() {
        booleMainShape();
        generateFrontCutoutCube(moreOrLessOpening);
        generateScrewBoole();
        generateTopCutoutCube(-phoneThickness/2-wallThickness,0,rightCutawayLocation);
        generateBottomCutoutCube(-phoneThickness/2-wallThickness,0,leftCutawayLocation);
        }
    generateThreadInCube();
}

/*
 * Below script snippet for thread generation is made by aubenc @ Thingiverse
 * Taken and from polyScrewThread_r1.scad
 *
 * http://www.thingiverse.com/thing:8796
 *
 * CC Public Domain

od - Thread major diameter
st - Thread pitch (gap)
lf0 - Thread angle
lt - Thread length
rs - Thread rotational symmetry
cs - Chamfer style (1, 2, or 3)
df - Head diameter
hg - Head thickness
ntl - Shank thickness
ntd - Shank diameter

https://www.engineeringtoolbox.com/unified-screw-threads-unc-unf-d_1809.html
*/

module generateThreadInCube() {
    translate([-(phoneWidth/2-(phoneThickness/2)*0.75)*0.4-12,phoneWidth/2,0]) rotate([90,0,90]) {
        difference() {
            translate([-10,-10,1]) cube([20,20,8]);
            scale([1.08,1.08,1]) screw_thread(9.525,1.5875,30,10,3,3);
        }
        if (mountHeight>50) {
            translate([-10,-10,1]) rotate([-270,0,0]) prism(20, 8, 20);
            translate([10,10,1]) rotate([270,180,0]) prism(20, 8, 20);
        } else {
            translate([-10,-10,1]) rotate([-270,0,0]) prism(20, 8, (mountHeight-20)/2);
            translate([10,10,1]) rotate([270,180,0]) prism(20, 8, (mountHeight-20)/2);
        }
    }
}

module screw_thread(od,st,lf0,lt,rs,cs)
{
    or=od/2;
    ir=or-st/2*cos(lf0)/sin(lf0);
    pf=2*PI*or;
    sn=floor(pf/rs);
    lfxy=360/sn;
    ttn=round(lt/st+1);
    zt=st/sn;

    intersection()
    {
        if (cs >= -1)
        {
           thread_shape(cs,lt,or,ir,sn,st);
        }

        full_thread(ttn,st,sn,zt,lfxy,or,ir);
    }
}

module thread_shape(cs,lt,or,ir,sn,st)
{
    if ( cs == 0 )
    {
        cylinder(h=lt, r=or, $fn=sn, center=false);
    }
    else
    {
        union()
        {
            translate([0,0,st/2])
              cylinder(h=lt-st+0.005, r=or, $fn=sn, center=false);

            if ( cs == -1 || cs == 2 )
            {
                cylinder(h=st/2, r1=ir, r2=or, $fn=sn, center=false);
            }
            else
            {
                cylinder(h=st/2, r=or, $fn=sn, center=false);
            }

            translate([0,0,lt-st/2])
            if ( cs == 1 || cs == 2 )
            {
                  cylinder(h=st/2, r1=or, r2=ir, $fn=sn, center=false);
            }
            else
            {
                cylinder(h=st/2, r=or, $fn=sn, center=false);
            }
        }
    }
}

module full_thread(ttn,st,sn,zt,lfxy,or,ir)
{
  if(ir >= 0.2)
  {
    for(i=[0:ttn-1])
    {
        for(j=[0:sn-1])
			let( pt = [	[0,                  0,                  i*st-st            ],
                        [ir*cos(j*lfxy),     ir*sin(j*lfxy),     i*st+j*zt-st       ],
                        [ir*cos((j+1)*lfxy), ir*sin((j+1)*lfxy), i*st+(j+1)*zt-st   ],
								[0,0,i*st],
                        [or*cos(j*lfxy),     or*sin(j*lfxy),     i*st+j*zt-st/2     ],
                        [or*cos((j+1)*lfxy), or*sin((j+1)*lfxy), i*st+(j+1)*zt-st/2 ],
                        [ir*cos(j*lfxy),     ir*sin(j*lfxy),     i*st+j*zt          ],
                        [ir*cos((j+1)*lfxy), ir*sin((j+1)*lfxy), i*st+(j+1)*zt      ],
                        [0,                  0,                  i*st+st            ]	])
        {
            polyhedron(points=pt,
              		  faces=[	[1,0,3],[1,3,6],[6,3,8],[1,6,4],
											[0,1,2],[1,4,2],[2,4,5],[5,4,6],[5,6,7],[7,6,8],
											[7,8,3],[0,2,3],[3,2,7],[7,2,5]	]);
        }
    }
  }
  else
  {
    echo("Step Degrees too agresive, the thread will not be made!!");
    echo("Try to increase de value for the degrees and/or...");
    echo(" decrease the pitch value and/or...");
    echo(" increase the outer diameter value.");
  }
}

module prism(l, w, h){
   polyhedron(
           points=[[0,0,0], [l,0,0], [l,w,0], [0,w,0], [0,w,h], [l,w,h]],
           faces=[[0,1,2,3],[5,4,3,2],[0,4,5,1],[0,3,4],[5,2,1]]
           );

   // preview unfolded (do not include in your function
   }

```


[User]
Hi there, I'm looking to design a parametric laptop stand in OpenSCAD, and I have a few specific requirements. I'd like it to be adjustable to accommodate various laptop sizes and desired angles. The core idea is to have a stand that holds the laptop nearly vertically, similar to a tablet stand, to minimize desk space when using an external monitor and keyboard.

Here's what I'm thinking:

**General Structure:**

*   The stand should consist of two supporting legs (front and back), and a connecting bar to keep them aligned.
*   The front legs should have a lip that catches the front edge of the laptop. This lip needs to be adjustable based on the thickness of the laptop.
*   The back legs should provide support and be angled to achieve the desired tilt.

**Key Parameters (these should be user-adjustable):**

*   `frontLength`: The total length of the stand from front to back.  (e.g. 100-400mm)
*   `height`: The overall height of the stand. (e.g. 60-200mm)
*   `lAngle`: The desired angle of the laptop from vertical (a negative value means it's leaning back). (e.g. -22:Shallow, -13:Medium, -10:Steep)
*   `lDepth`: The depth of the laptop (which is roughly its screen height). (e.g. 10-300mm)
*   `lHeight`: The height of the laptop (thickness of the keyboard). (e.g. 8-30mm)
*    `lipDepth`: The depth of the lip that holds the laptop in place. (e.g. 10-30mm)
*   `wall`: The thickness of the stand's material. (e.g. 5-15mm)

**Specific Design Features:**

*   The supporting legs should have an angled section to achieve the desired `lAngle`.
*   The laptop lip should have a slight cutout to prevent interference with the laptop body.
*   Calculations needed:
    * The length of each support leg (`lSupportLen`) is a fraction of the total frontLength, which should scale to keep the same proportions as the frontLength is adjusted. I'm imagining a calculation like  `frontLength/pow(1.61803398875,3);` to get that proportion.
     * The depth of the back leg (`backDepth`) should be derived from `lDepth` and `lAngle` to ensure support is close to the hinge point of the laptop, I'm imagining a calculation like `lDepth*tan(lAngle)*1.25;`.
*   Use rounded edges on all components for a nicer finish using `rCube` function.

I think that's about everything. Could you provide me with the necessary OpenSCAD code? I anticipate that I'll be using the Customizer feature to adjust all of the parameters. No libraries should be needed for this simple project I believe. Thanks in advance!

[Assistant]
laptopStand2.scad:
```

///length of stand
frontLength = 190; //[100:400]

//height of stand
height = 100; //[60:200]

// Desired keyboard angle from vertical
lAngle = -13; // [-22:Shallow, -13:Medium, -10:Steep]

// laptop depth (aka screen height, used to estimate center of gravity)
lDepth = 250; // [10:1:30]

//laptop height (aka thickness of keyboard)
lHeight = 14; //[8:1:30]

//depth for laptop lip
lipDepth = 15; //[10:1:30]

//basic wall thickness
wall = 10; //[5:1:15]

/* [Hidden] */
//CALCULATED FIELDS

//length of each support
lSupportLen = frontLength/pow(1.61803398875,3);
//back depth, ensures supports reach to hinge depth + 25%
backDepth = lDepth*tan(lAngle)*1.25;
echo(backDepth=backDepth);

//legs
frontLeg(); backLeg();
translate([0,frontLength-lSupportLen,0]){
	frontLeg(false);
	backLeg(false);
}

//connecting bar
translate([-wall/4,0,0])
	rCube([wall,frontLength-1,wall]);

module backLeg(left=true){
	translate([0,left?lSupportLen-wall:0,0]){
		//base case solid bar
		translate([backDepth,0,0])
			rCube([abs(backDepth)+1,wall,wall]);
		//angled support

		hull(){
			rotate([0,lAngle,0])translate([0,0,0])
				rCube([1,wall,max(wall*2,height/2)]);
			translate([backDepth/pow(1.61803398875,2),0,0])
				rCube([1,wall,wall]);
		}

	}
}

module rCube( xyz, r=2){
	cVec = xyz - [r,r,r];
	translate([r,r,r])
	hull(){
		for(x = [0,1])for(y = [0,1])for(z = [0,1])
		translate([cVec.x*x,cVec.y*y,cVec.z*z]) sphere(r=r, $fn=$preview?8:16);
	}
}

module frontLeg(left=true){
	difference(){
	union(){
		rCube([lHeight+wall*2,lSupportLen,lipDepth+wall]);
		rotate([0,lAngle,0]) hull(){
			rCube([lHeight,lSupportLen,lipDepth+wall]);
			translate([0,left?lSupportLen-wall:0,height-2])
				rCube([lHeight,wall,1]);
		}
	}

	//main slab representing laptop
	translate([wall,-2,wall])
		rotate([0,lAngle,0])
			rCube([lHeight,lSupportLen+4,lipDepth+height]);

	//reduce lip overhang
	translate([wall,-2,wall])
		rotate([0,lAngle/2,0])
			rCube([lHeight,lSupportLen+4,lipDepth+height]);
	}
}
```


[User]
Hey there! I'm looking to design a corner mounting plate for a Valve Index lighthouse (base station) using OpenSCAD. I'd like it to be parametric, so I can easily adjust things later.

Here's what I need:

**Overall Shape:** The main body of the plate should be a rounded rectangle. I'm envisioning a flat plate, about 45mm thick, with rounded corners rather than sharp edges. The main dimensions for the plate should be adjustable, lets call these `plate_length`, and `plate_width` and be able to adjust the roundness via `corner_radius`.

**Mounting Holes:** The plate needs to have mounting holes that align with the standard Valve Index lighthouse mounting plate. There should be two mounting holes, one on each side of the plate. These holes are angled at 45 degrees relative to the sides of the plate and be located near the top edge of the plate. They should have countersunk screw holes, but the amount of bevel should be adjustable. So, I'd need variables for the mounting hole radius (`inner_r`) and the outer radius of the counter sink (`outer_r`), along with the countersink height `bevel_h` as variables.

**Additional Mounting Holes:** I also need two additional through-holes with a slightly larger countersunk hole on the surface of the plate. These will help screw the plate to the wall.  They should be on the top edge of the plate at distance from the top of the plate with a distance between them defined with a variable as well. These holes should also be adjustable in size. Specifically, variables for the radius of the through hole (`hole_r`), the diameter of the counter sink (`countersink_d`) and the depth of the countersink `countersink_h`.

**Tolerance:** It should have a tolerance variable to adjust the size of the screw holes to achieve proper fit when 3D printed. This is a global variable I'll need to use for all of the through holes.

**Base:** I'd like it to have a way of cutting off parts of the bottom so it makes better contact when its mounted into a corner. The bottom of the part should have a series of planes that remove material from the bottom so when its mounted in a corner it will make full contact on all of the edges of the device.

I'm okay with assuming that the base station mounting holes will be oriented toward the inside of the corner.

I'm not using any specific libraries in the SCAD code I wrote before; it uses only base OpenSCAD primitives.

Could you generate the OpenSCAD code for this, with all the parameters I mentioned and well-commented? Thanks!

[Assistant]
Lighthouse_Corner_Plate.scad:
```
// Tolerance factor for hole punches; added to screw hole radius. Default: 0.2
param_hole_tolerance = 0.2;

module block_params() { /* Customizer ignores params after first module def */ }

$fn=180;

// Set true to generate a fit tester
TEST_PLATE=false;   // true | false

// Rounded rectangle block.
// Source: https://www.thingiverse.com/thing:9347
module roundedRect(size, radius)
{
    x = size[0];
    y = size[1];
    z = size[2];

    linear_extrude(height=z)
    hull()
    {
        // place 4 circles in the corners, with the given radius
        translate([(-x/2)+(radius/2), (-y/2)+(radius/2), 0])
        circle(r=radius);

        translate([(x/2)-(radius/2), (-y/2)+(radius/2), 0])
        circle(r=radius);

        translate([(-x/2)+(radius/2), (y/2)-(radius/2), 0])
        circle(r=radius);

        translate([(x/2)-(radius/2), (y/2)-(radius/2), 0])
        circle(r=radius);
    }
}

// cutting cubes to shave the base off
module cut_planes()
{
    // Left Angle
    color("Orange")
    rotate([45,0,0])
    translate([0,0,-50])
    cube([200,200,100],center=true);

    // Right Angle
    color("Tomato")
    rotate([-45,0,0])
    translate([0,0,-50])
    cube([200,200,100],center=true);

    // Bottom
    color("Beige")
    rotate([0,0,0])
    translate([0,0,-27])
    cube([200,200,100],center=true);

    // Hollow out (1)
    color("Yellow")
    translate([33,0,13])
    cube([50,40,50], center=true);

    // Hollow out (2)
    color("DarkRed")
    translate([-33,0,13])
    cube([50,40,50], center=true);

    // Hollow out (3)
    color("Green")
    translate([0,0,10+12])
    cube([100,40,20], center=true);
}

// Mounting hole punch
module mount_hole_punch(inner_r, outer_r, bevel_h)
{
    union() {
        color("Purple")
        cylinder(r=inner_r, h=100, center=true);
        color("Navy")
        translate([0,0,25])
        cylinder(r=outer_r, h=50, center=true);
        translate([0,0,-bevel_h/2+0.001])
        cylinder(h=bevel_h, r1=inner_r, r2=outer_r, center=true);
    }
}

// Left side mounting hole punch
module mount_hole_punch_L(tol=0.0)
{
    centerline_offset_y = +17;
    translate([0, centerline_offset_y, 40])
    rotate([45,0,0])
    translate([0,0,-5])
    mount_hole_punch(2.8+tol,5.8,0);
}

// Right side mounting hole punch
module mount_hole_punch_R(tol=0.0)
{
    centerline_offset_y = -17;
    translate([0, centerline_offset_y, 40])
    rotate([-45,0,0])
    translate([0,0,-5])
    mount_hole_punch(2.8+tol,5.8,0);
}

// Corner Plate
module corner_plate()
{
    difference()
    {
        corner_radius=5;
        plate_length=92;
        plate_width=70;
        mount_hole_dist_from_top=13.5;
        plate_mount_holes_dist=70;  // Distance between mounting holes

        union()
        {
            color("Gray")
            roundedRect([plate_length-corner_radius,
                         plate_width-corner_radius, 45], corner_radius);
        }

    }
}

// Assemble the corner plate
module corner_mounting_plate_assembly(tol=0.0)
{
    mount_hole_dist_from_top=13.5;
    plate_mount_holes_dist=70;  // Distance between mounting holes

    translate([0,0,45])
    rotate([180,0,0])
    difference() {
        union() {
            difference() {
                corner_plate();
                cut_planes();
                color("Brown")  mount_hole_punch_L(tol=param_hole_tolerance);
                color("Purple") mount_hole_punch_R(tol=param_hole_tolerance);
            }
            translate([46-mount_hole_dist_from_top,0, 35])
            cylinder(d1=15, d2=17, h=6, center=true);
            translate([46-mount_hole_dist_from_top-plate_mount_holes_dist, 0, 35])
            cylinder(d1=15, d2=17, h=6, center=true, $fn=180);
        }

        color("Red")
        translate([46-mount_hole_dist_from_top, 0, 41.5])
        mount_hole_punch(1.5+param_hole_tolerance, 5.0, 3);

        color("Green")
        translate([46-mount_hole_dist_from_top-plate_mount_holes_dist, 0, 41.5])
        mount_hole_punch(1.5+param_hole_tolerance, 5.0, 3);
    }
}

//
// BEGIN HERE
//

difference()
{
    corner_mounting_plate_assembly(tol=param_hole_tolerance);
    if(TEST_PLATE==true)
    {
        translate([0,0,15+0.5])
        cube([120,90,30], center=true);
    }
    else
    {
        translate([0,0,-.01])
        roundedRect([92-5-7,70-5-7,3], 5);
        //cube([58,60,2], center=true);
    }
}

```


[User]
Hey, I'm looking to get a parametric design for a chapstick holder that can attach to a keychain. I've been playing around in OpenSCAD a bit, but I'm not great at it, so I need some help.

The main idea is a tube-like holder with a press-fit clamp to hold a standard chapstick tube. It needs a hole for a keyring, and I'd like the option to add a small zip tie for extra security.

Here are the dimensions I'm thinking of:

*   **`tube_d`**: Diameter of the chapstick tube (around 15.5 mm).
*   **`tube_l`**: Length of the main body of the chapstick (excluding lid/wheel, about 41 mm).
*   **`thickness`**: Thickness of the clamp part, this should end up as half this final amount (around 3 mm).
*   **`keyring_hole_d`**: Diameter of the keyring hole (maybe 5 mm).
*   **`clamp_opening_height`**: Height of the opening in the clamp (something like 2.5 mm).
*   **`zip_tie_enabled`**: A boolean flag to enable or disable the zip tie hole.
*   **`zip_tie_hole_w`**: Width of the zip tie hole (around 4 mm).
*   **`zip_tie_hole_h`**: Height of the zip tie hole (around 3 mm).

The design should use a `hull()` to create the main body with the keyring hole integrated into it.  I was thinking a `difference()` would work well, for cutting out the tube, keyring hole, clamp opening, and the optional zip tie hole. I want the keyring hole to come out the side and not the top. Also, I'd like the clamp to open up on one side to allow for the chapstick to be pushed in.

The keyring hole should be close to the end of the chapstick holder (not in the middle). I was thinking the clamp would be created by subtracting a rectangular space from the full cylinder that extends into the cylinder. And, it'd be good if the whole thing was properly oriented when I render it.

I think those are all the details. Hopefully, that is clear enough! Let me know if you need more information. Oh, and I don't really have a preference about libraries, but I suppose if there's anything standard for handling some of these operations, you could use them. Thanks!

[Assistant]
chapstick_holder.scad:
```
// no $fn or $fs needed here

/*
 * this is a press-fit chapstick holder for a keychain.
 * optionally supports a small zip tie to really clamp the
 * chapstick down if things get rough, you never know...
 */

// chapstick diameter
tube_d = 15.5;

// length of chapstick main body, excluding lid and turn wheel
tube_l = 41;

// how thick the chapstick clamp is, will end up half this
thickness = 3;

// where the keyring goes
keyring_hole_d = 5;

// clamp opening distance
clamp_opening_height = 2.5;

// optional zip tie hole
zip_tie_enabled = false;

zip_tie_hole_w = 4;
zip_tie_hole_h = 3;

module clamp() {
difference() {
    hull() {
        rotate(90, [0,1,0])
            cylinder(d=tube_d + thickness, h=tube_l);
        translate([tube_l - keyring_hole_d/2, tube_d/2 + thickness + keyring_hole_d/2, 0])
            cylinder(d=keyring_hole_d, h=thickness);
    }

    // tube cutout
    translate([-tube_l/2, 0, 0])
        rotate(90, [0,1,0])
            cylinder(d=tube_d, h=tube_l * 2);

    // key ring hole
    translate([(tube_l - keyring_hole_d/2) - thickness/2, tube_d/2 + keyring_hole_d/2, -tube_l/2])
        cylinder(d=keyring_hole_d, h=tube_l*2);

    // clamp opening
    translate([0, -tube_d+thickness, -clamp_opening_height/2])
        cube([tube_l, thickness*2, clamp_opening_height]);

    if (zip_tie_enabled) {
        // zip tie hole
        translate([tube_l/2, tube_d/2, -tube_l/2])
            cube([zip_tie_hole_w, zip_tie_hole_h, tube_l]);
    }
}
}

// clamp();

module present() {
translate([0, 0, tube_l])
    rotate(90, [0, 1, 0])
        clamp();
}

present();
```


[User]
I'd like to create a parametric dollhouse using OpenSCAD. I've seen some existing designs, but I need something more customizable.

Here's what I'm looking for:

**Overall Structure:**

*   A basic box-shaped room with customizable length, height, and depth.
*   The wall thickness should also be adjustable.
*   I need to be able to choose from different roof styles: none, a slanted roof to the left, a slanted roof to the right, and a double sloped "rooftop" style.
*   I also need options for roof windows, including none, a round window (Type 1), and a rectangular window (Type 2).

**Decor:**

*   I'd like to have options for adding windows, either none, one round window, or one rectangular window. The position of these windows should be pre-defined relative to the center of the front facing wall.
*   I'll want to be able to specify "wallnail" as a parameter, but I'll leave the functionality empty for now - I just want the variable to be available.

**Passages:**

*   I need to be able to configure the presence and type of doors on the left and right sides. The door options should be none, a simple rectangular door opening (Type 1), and a door opening with a cylindrical shape attached to it (Type 2).
*   Also, I'll need options for a roof hatch and a basement hatch. These can just be "none," "Type 1," and "Type 2" similar to the doors, I don't need to see the geometry of the hatch itself, just the hole or doorframe.

**Details:**

*   I'd like to be able to define the `$fn` for more precise curves.
*   I'd like the door and window placements to be a function of the overall room dimensions so I don't need to manually move them.

**Output:**

*   I'm looking for a set of OpenSCAD files that will allow me to achieve this. It would be great if they were well-organized and easy to understand, with variables that are straightforward to adjust.

Could you generate the necessary OpenSCAD code for me?

[Assistant]
doors_holes.scad:
```
if (leftdoor==0){
}
if (leftdoor==1){
if (roof==0){
if (side=="l"){
frame_x=115;
frame_y=5;
frame_z=50;
translate([-0.5,4,5])
color("brown")
cube([frame_y+wall,frame_x,frame_z]);

}
}
if (roof==1){
}
if (roof==2){
if (side=="l"){
frame_x=115;
frame_y=5;
frame_z=50;
translate([-0.5,4,5])
color("brown")
cube([frame_y+wall,frame_x,frame_z]);

}
}
if (roof==3){
}
}
if (leftdoor==2){
if (roof==0){
if (side=="l"){
frame_x=115;
frame_y=5;
frame_z=50;
translate([-0.5,4,5])
color("brown")
cube([frame_y+wall,frame_x,frame_z]);

translate([-0.5,frame_x+4,frame_z/2+5])
rotate([0,90,0])
translate([0,4,0])
color("brown")
cylinder(d=50,h=frame_y+wall-3);

}
}
if (roof==1){
}
if (roof==2){
if (side=="l"){
frame_x=115;
frame_y=5;
frame_z=50;
translate([-0.5,4,5])
color("brown")
cube([frame_y+wall,frame_x,frame_z]);

translate([-0.5,frame_x+4,frame_z/2+5])
rotate([0,90,0])
translate([0,4,0])
color("brown")
cylinder(d=50,h=frame_y+wall-3);

}
}
if (roof==3){
}
}

if (rightdoor==0){
}
if (rightdoor==1){
if (roof==0){
if (side=="r"){
frame_x=115;
frame_y=5;
frame_z=50;
translate([-0.5,4,5])
color("brown")
cube([frame_y+wall,frame_x,frame_z]);
}
}
if (roof==1){
if (side=="r"){
frame_x=115;
frame_y=5;
frame_z=50;
translate([-0.5,4,5])
color("brown")
cube([frame_y+wall,frame_x,frame_z]);
}
}
if (roof==2){
}
if (roof==3){
}
}
if (rightdoor==2){
if (roof==0){
if (side=="r"){
frame_x=115;
frame_y=5;
frame_z=50;
translate([-0.5,4,5])
color("brown")
cube([frame_y+wall,frame_x,frame_z]);

translate([-0.5,frame_x+4,frame_z/2+5])
rotate([0,90,0])
translate([0,4,0])
color("brown")
cylinder(d=50,h=frame_y+wall-3);

}
}
if (roof==1){
if (side=="r"){
frame_x=115;
frame_y=5;
frame_z=50;
translate([-0.5,4,5])
color("brown")
cube([frame_y+wall,frame_x,frame_z]);

translate([-0.5,frame_x+4,frame_z/2+5])
rotate([0,90,0])
translate([0,4,0])
color("brown")
cylinder(d=50,h=frame_y+wall-3);

}
}
if (roof==2){
}
if (roof==3){
}
}

```
basetest.scad:
```

/* [Room] */
// Room length
room_x=180;

// Room hight
room_y=180;

// Room deep
room_z=100;

// Wall thickness
wall=8;

// Roof sloping
roof=0; //[0:"none",1:"left",2:"right",3:"roottop"]
roof_window=0; //[0:"none",1:"Typ 1",2:"Typ 2"]

/* [Decor] */
// Windows
window=0; //[0:"none",1:"1 Window round",2:"1 angular Window"]

// Wallnail
wallnail="none";

/* [Passages] */
// Left Door
leftdoor=0;//[0:"none",1:"Typ 1",2:"Typ 2"]

// Right Door
rightdoor=0;//[0:"none",1:"Typ 1",2:"Typ 2"]

// Roof hatch
roofdoor=0;//[0:"none",1:"Typ 1",2:"Typ 2"]

// Basement hatch
basedoor=0;//[0:"none",1:"Typ 1",2:"Typ 2"]

/* [Hidden] */
$fn=75;

module wall_back(){
cube([room_x,room_y,wall]);
if (roof==0){
}
if (roof==1){

}
if (roof==2){

}
if (roof==3){
}
}
module wall_back_open(){
if (roof==0){
}
if (roof==1){
roof_x=sqrt(pow(room_x,2)+pow(room_y,2));
    roof_y=roof_x/2;
    rotate([0,0,45])
    cube([roof_x,roof_y,room_z+0.2]);

}
if (roof==2){
roof_x=sqrt(pow(room_x,2)+pow(room_y,2));
    roof_y=roof_x/2;
translate([0,room_y,0])
    rotate([0,0,-45])
    cube([roof_x,roof_y,room_z+0.2]);

}
if (roof==3){
roof_x=sqrt(pow(room_x,2)+pow(room_y,2));
    roof_y=roof_x/2;
    rotate([0,0,45])
    cube([roof_x,roof_y,room_z+0.2]);

roof_x2=sqrt(pow(room_x,2)+pow(room_y,2));
    roof_y2=roof_x2/2;
translate([0,room_y,0])
    rotate([0,0,-45])
    cube([roof_x2,roof_y2,room_z+0.2]);
}

}

module windows(){
include <windows.scad>;
}
module windows_holes(){
include <windows_holes.scad>;
}
module doors(side){

include <doors.scad>;
}
module doors_holes(side){
include <doors_holes.scad>;
}
module fenster(){
translate([((room_x/2)/2+wall)-wall,((room_y/2)/2+wall)+wall,room_z/2])
rotate([0,90,-45])
    windows();

translate([((room_x/2)/2+wall)-wall+45,((room_y/2)/2+wall)+wall+45,room_z/2])
rotate([0,90,-45])
    windows();
translate([((room_x/2)/2+wall)-wall+90,((room_y/2)/2+wall)+wall+90,room_z/2])
rotate([0,90,-45])
    windows();
}
module fenster_open(){
    translate([((room_x/2)/2+wall)-wall-1,((room_y/2)/2+wall)+wall,room_z/2])
rotate([0,90,-45])
windows_holes();
    translate([((room_x/2)/2+wall)-wall-1+45,((room_y/2)/2+wall)+wall+45,room_z/2])
rotate([0,90,-45])
windows_holes();
translate([((room_x/2)/2+wall)-wall-1+90,((room_y/2)/2+wall)+wall+90,room_z/2])
rotate([0,90,-45])
windows_holes();
}

module walls(){
if (roof==0){
//left
cube([wall/2,room_y,room_z]);
//right
translate([room_x-(wall/2),0,0])
cube([wall/2,room_y,room_z]);
//top
translate([0,room_y-(wall/2),0])
cube([room_x,wall/2,room_z]);
dlz=(room_z-60)/2;
translate([0,0,dlz])
doors("l");

drz=(room_z-60)/2;
translate([room_x-5,0,drz])
doors("r");

//bottom
cube([room_x,wall/2,room_z]);
}
if (roof==1){
//left italic
    roof_x=sqrt(pow(room_x,2)+pow(room_y,2));
    roof_y=wall;
    rotate([0,0,45])
    cube([roof_x,roof_y,room_z]);
//right
translate([room_x-(wall/2),0,0])
cube([wall/2,room_y,room_z]);
//bottom
cube([room_x,wall/2,room_z]);
drz=(room_z-60)/2;
translate([room_x-5,0,drz])
doors("r");

if (roof_window==0){
}
if (roof_window==1){
fenster();

}
if (roof_window==2){
frame_x=120;
frame_y=5;
frame_z=50;
translate([((room_x)/2-frame_x/2+wall
    +17.5),((room_y/2)/2+25),room_z/2/2])
rotate([0,0,-45])
    windows();

}

}
if (roof==2){
//left
cube([wall/2,room_y,room_z]);
//bottom
cube([room_x,wall/2,room_z]);

//right italic
roof_x=sqrt(pow(room_x,2)+pow(room_y,2));
    roof_y=wall;
translate([0,room_y,0])
    rotate([0,0,-45])
    cube([roof_x,roof_y,room_z]);
dlz=(room_z-60)/2;
translate([0,0,dlz])
doors("l");

if (roof_window==0){
}
if (roof_window==1){

rotate([0,0,-90])
translate([-195,-15,0])
fenster();
}
if (roof_window==2){
frame_x=120;
frame_y=5;
frame_z=50;
translate([62,-10,0])
translate([((room_x)/2-frame_x/2+wall
    +17.5),((room_y/2)/2+25),room_z/2/2])
rotate([0,0,45])
    windows();

}

}
if (roof==3){
//top
    roof_x3=sqrt(pow(wall,2)+pow(wall,2))/2;
    roof_y3=wall;
translate([room_x/2-roof_x3,room_y/2+roof_x3,0])
    rotate([0,0,-45])
    cube([wall,wall,room_z+10]);
//bottom
cube([room_x,wall/2,room_z]);
//left italic half
roof_x=sqrt(pow(room_x,2)+pow(room_y,2))/2;
    roof_y=wall;
translate([0,0,0])
    rotate([0,0,45])
    cube([roof_x,roof_y,room_z]);

//right italic half
roof_x2=sqrt(pow(room_x,2)+pow(room_y,2))/2;
    roof_y2=wall;
translate([room_x/2,room_y/2,0])
    rotate([0,0,-45])
    cube([roof_x2,roof_y2,room_z]);

if (roof_window==0){
}
if (roof_window==1){

//left window round
translate([((room_x/2)/2+wall)-wall,((room_y/2)/2+wall)+wall,room_z/2])
rotate([0,90,-45])
    windows();

//right window round
    translate([((room_x/2)/2+room_x/2)+wall-25+7.5,(room_y/6)+22.5,room_z/2])
rotate([0,90,45])
color("brown")
windows();

}
if (roof_window==2){
//left window quader
frame_x=60;
frame_y=5;
frame_z=50;
translate([((room_x/2)/2-frame_x/2+wall
    +1),((room_y/2)/2+frame_y/2-wall),room_z/2/2])
rotate([0,0,-45])
    windows();
//right window quader
frame_x2=60;
frame_y2=5;
frame_z2=50;
translate([((room_x/2)/2+(room_x/2)+wall+5),(room_y/6),room_z/2/2])
rotate([0,0,45])
color("brown")
windows();
}

}
}
module walls_open(){
if (roof==0){
dlz2=(room_z-60)/2;
translate([-2,0,dlz2])
doors_holes("l");
drz2=(room_z-60)/2;
translate([room_x-7,0,drz2])
doors_holes("r");
}
if (roof==1){
drz2=(room_z-60)/2;
translate([room_x-7,0,drz2])
doors_holes("r");

if (roof_window==0){
}
if (roof_window==1){
fenster_open();
}
if (roof_window==2){
frame_x=110;
frame_y=5;
frame_z=40;
translate([((room_x)/2-frame_x/2+wall
    +12.5),((room_y/2)/2+25),room_z/2/2])
rotate([0,0,-45])
windows_holes();

}
}
if (roof==2){
dlz2=(room_z-60)/2;
translate([-2,0,dlz2])
doors_holes("l");
if (roof_window==0){
}
if (roof_window==1){
rotate([0,0,-90])
translate([-195,-15,0])
fenster_open();
}
if (roof_window==2){
frame_x=110;
frame_y=5;
frame_z=40;
translate([62,-10,0])
translate([((room_x)/2-frame_x/2+wall
    +12.5),((room_y/2)/2+25),room_z/2/2])
rotate([0,0,45])
windows_holes();
}
}
if (roof==3){
if (roof_window==0){
}
if (roof_window==1){
//left window round
translate([((room_x/2)/2+wall)-wall-1,((room_y/2)/2+wall)+wall,room_z/2])
rotate([0,90,-45])
windows_holes();
//right window round
    translate([((room_x/2)/2+room_x/2)+wall-25+7,(room_y/6)+22.5,room_z/2])
rotate([0,90,45])
color("brown")
windows_holes();
}
if (roof_window==2){
frame_x=50;
frame_y=5;
frame_z=40;
translate([((room_x/2)/2-frame_x/2+wall
    -5),((room_y/2)/2+frame_y/2-wall)+1.5,room_z/2/2])
rotate([0,0,-45])
windows_holes();
//right window quader
frame_x2=60;
frame_y2=5;
frame_z2=50;
translate([((room_x/2)/2+(room_x/2)+wall+5),(room_y/6),room_z/2/2])
rotate([0,0,45])
color("brown")
windows_holes();

}
}

}

module all_pcs(){
 //   difference(){
 //   windows();
 //   windows_holes();
 //   }
difference(){
    wall_back();
translate([0,0,-0.1])
wall_back_open();
}
walls();
}

module all_cuts(){
walls_open();
}
difference(){
all_pcs();
translate([0,0,-0.1])
all_cuts();
}

```
doors.scad:
```
if (leftdoor==0){
}
if (leftdoor==1){
if (roof==0){
if (side=="l"){
frame_x=120;
frame_y=0;
frame_z=60;
translate([0,4,0])
color("brown")
cube([frame_y+wall-3,frame_x,frame_z]);

}
}
if (roof==1){
}
if (roof==2){
if (side=="l"){
frame_x=120;
frame_y=0;
frame_z=60;
translate([0,4,0])
color("brown")
cube([frame_y+wall-3,frame_x,frame_z]);

}
}
if (roof==3){
}
}
if (leftdoor==2){
if (roof==0){
if (side=="l"){
frame_x=120;
frame_y=0;
frame_z=60;
translate([0,4,0])
color("brown")
cube([frame_y+wall-3,frame_x,frame_z]);

translate([0,frame_x,frame_z/2])
rotate([0,90,0])
translate([0,4,0])
color("brown")
cylinder(d=60,h=frame_y+wall-3);

}
}
if (roof==1){
}
if (roof==2){
if (side=="l"){
frame_x=120;
frame_y=0;
frame_z=60;
translate([0,4,0])
color("brown")
cube([frame_y+wall-3,frame_x,frame_z]);

translate([0,frame_x,frame_z/2])
rotate([0,90,0])
translate([0,4,0])
color("brown")
cylinder(d=60,h=frame_y+wall-3);

}
}
if (roof==3){
}
}

if (rightdoor==0){
}
if (rightdoor==1){
if (roof==0){
if (side=="r"){
frame_x=120;
frame_y=0;
frame_z=60;
translate([0,4,0])
color("brown")
cube([frame_y+wall-3,frame_x,frame_z]);
}
}
if (roof==1){
if (side=="r"){
frame_x=120;
frame_y=0;
frame_z=60;
translate([0,4,0])
color("brown")
cube([frame_y+wall-3,frame_x,frame_z]);
}
}
if (roof==2){
}
if (roof==3){
}
}
if (rightdoor==2){
if (roof==0){
if (side=="r"){
frame_x=120;
frame_y=0;
frame_z=60;
translate([0,4,0])
color("brown")
cube([frame_y+wall-3,frame_x,frame_z]);
translate([0,frame_x,frame_z/2])
rotate([0,90,0])
translate([0,4,0])
color("brown")
cylinder(d=60,h=frame_y+wall-3);

}
}
if (roof==1){
if (side=="r"){
frame_x=120;
frame_y=0;
frame_z=60;
translate([0,4,0])
color("brown")
cube([frame_y+wall-3,frame_x,frame_z]);
translate([0,frame_x,frame_z/2])
rotate([0,90,0])
translate([0,4,0])
color("brown")
cylinder(d=60,h=frame_y+wall-3);

}
}
if (roof==2){
}
if (roof==3){
}
}

```
windows.scad:
```
if (roof_window==0){
}
if (roof_window==1){
if (roof==1){
translate([0,0,0])
color("brown")
cylinder(d=50,h=5+wall);
translate([0,0,0])
color("brown")
cylinder(d=50,h=5+wall);
translate([0,0,0])
color("brown")
cylinder(d=50,h=5+wall);
}
if (roof==2){
translate([0,0,0])
color("brown")
cylinder(d=50,h=5+wall);
translate([0,0,0])
color("brown")
cylinder(d=50,h=5+wall);
translate([0,0,0])
color("brown")
cylinder(d=50,h=5+wall);
}

if (roof==3){
translate([0,0,0])
color("brown")
cylinder(d=50,h=5+wall);

}
}
if (roof_window==2){
if (roof==1){
frame_x=120;
frame_y=5;
frame_z=50;
translate([0,0,0])
color("brown")
cube([frame_y+wall,frame_x,frame_z]);

}
if (roof==2){
frame_x=120;
frame_y=5;
frame_z=50;
translate([0,0,0])
color("brown")
cube([frame_y+wall,frame_x,frame_z]);

}

if (roof==3){
frame_x=60;
frame_y=5;
frame_z=50;
translate([0,0,0])
color("brown")
cube([frame_y+wall,frame_x,frame_z]);

}
}

```
windows_holes.scad:
```
if (roof_window==0){
}
if (roof_window==1){
if (roof==1){
translate([0,0,-0.1])
color("brown")
cylinder(d=40,h=5+wall+20);
translate([0,0,-0.1])
color("brown")
cylinder(d=40,h=5+wall+20);
translate([0,0,-0.1])
color("brown")
cylinder(d=40,h=5+wall+20);
}
if (roof==2){
translate([0,0,-0.1])
color("brown")
cylinder(d=40,h=5+wall+20);
translate([0,0,-0.1])
color("brown")
cylinder(d=40,h=5+wall+20);
translate([0,0,-0.1])
color("brown")
cylinder(d=40,h=5+wall+20);
}

if (roof==3){
translate([0,0,0])
color("brown")
cylinder(d=40,h=5+wall+20);

}
}
if (roof_window==2){
if (roof==1){
frame_x=110;
frame_y=5;
frame_z=40;
translate([-5,5,5])
color("brown")
cube([frame_y+wall+40,frame_x,frame_z]);

}
if (roof==2){
frame_x=110;
frame_y=5;
frame_z=40;
translate([-5,5,5])
color("brown")
cube([frame_y+wall+40,frame_x,frame_z]);

}

if (roof==3){
frame_x=50;
frame_y=5;
frame_z=40;
translate([-5,5,5])
color("brown")
cube([frame_y+wall+20,frame_x,frame_z]);

}
}

```


[User]
I'd like to create a parametric dog tag using OpenSCAD, and I'm hoping you can help me design the code. I want it to be in the shape of a classic dog bone, with a space for the dog's name and a notch for attaching a keyring.

Here are the specifics:

**Dog Bone Shape:**

*   The bone should be made from a central rectangle with two circles on each end, forming a rounded bone shape.
*   I need to be able to control the width and height of the center rectangle as well as the radius of the end circles.
*   The circles should overlap with the rectangle. The amount of this overlap should be a parameter that I can set.
*   I would like to control the overall depth (thickness) of the bone.
*   I want a slight inset/recess on the top of the bone, essentially creating a border for the name, and I need to control the depth of that as well as the width of the border.

**Text:**

*   I need to be able to include the dog's name on the bone, using text.
*   I should be able to set the font, size, and other text parameters that OpenSCAD supports.
*   The text should be centered on the bone's face.
*    I would like the text to be recessed from the top surface of the dog bone. This recess should match the depth of the border.

**Zipper Pull Notch:**

*   I want to include a small notch at the top of the tag for attaching it to a keyring or split ring. The idea is to use a 'negative' of a zipper pull shape, so that a keyring can be inserted and not easily slide off the tag.
*   I want to be able to adjust the position of this notch on the dog tag. I might also want to rotate it slightly.
*   Could you please include a separate file, say, "zipper_notch.scad", which will create the notch shape? I'll import that into the main dog tag design file. This file could use a simple `linear_extrude` to make the zipper shape.

**Parameters**
* I'd like all dimensions to be parametric - I don't want to have to hunt through the code for dimensions I want to change. I would like a number of parameters that I can define at the top of the file to make it easy to adjust the size and shape of the tag.
    *   `bone_width`: The width of the center rectangle of the bone.
    *   `bone_height`: The height of the center rectangle of the bone.
    *   `bone_overlap`: The amount the circles overlap the center rectangle.
    *   `bone_radius`: Calculated radius of the end circles. `(bone_height/2) + bone_overlap`
    *   `depth`: The overall depth of the tag.
    *   `edge`: The thickness of the inset border. Also the depth of the inset.
    *   `name`: The dog's name as a string.
    *  `font`: The font used for the dog's name
    *  `fontsize`: The font size for the dog's name
    *  `zipper_adjust`: Amount to adjust the zipper horizontally

*   Also, please use `$fn` for smooth curves.

I don't want to use any external libraries, just the built in OpenSCAD modules.

[Assistant]
dog_bone_tag.scad:
```
$fn=80;
name="Your dog's name here";
depth=5.5; //at least 6 mm needed
bone_width=60; //Width of the center rectangle
bone_height=25;
bone_overlap=3; //How much the two circles overlap
bone_radius=(bone_height/2)+bone_overlap;
corner1=bone_width/2;
corner2=bone_height/2;
edge=.5; //Determines the text depth as well as the bone outline edge
zipper_adjust=-2; //May need to play with this setting to get the zipper in the right place

module bone(){
    difference(){
        union()
        {
         translate([-corner1,-corner2,0]) cube([bone_width,bone_height,depth]);
         translate([-corner1,corner2,0]) cylinder(depth,bone_radius,bone_radius);
         translate([corner1,corner2,0]) cylinder(depth,bone_radius,bone_radius);
         translate([-corner1,-corner2,0]) cylinder(depth,bone_radius,bone_radius);
         translate([corner1,-corner2,0]) cylinder(depth,bone_radius,bone_radius);
        }
        union()
        {
         translate([-corner1+edge,-corner2+edge,depth-edge]) cube([bone_width-2*edge,bone_height-2*edge,edge+2]);
         translate([-corner1,corner2,depth-edge]) cylinder(h=2+edge,r=bone_radius-edge);
         translate([corner1,corner2,depth-edge]) cylinder(h=2+edge,r=bone_radius-edge);
         translate([-corner1,-corner2,depth-edge]) cylinder(h=2+edge,r=bone_radius-edge);
         translate([corner1,-corner2,depth-edge]) cylinder(h=2+edge,r=bone_radius-edge);
        }
    }
}
difference(){
    union(){
        bone();
        #linear_extrude(height = depth) {
               text( text=name, font="Ubuntu:bold", size = 6 , halign = "center", valign="center", spacing=.9);
        }
    }
#rotate([0,0,-90]) translate([zipper_adjust,0,1]) import("/Users/michael/Documents/3D image/ZipperPull_Notch.stl",  convexity=3);
}

```


[User]
I'm looking for an OpenSCAD design for a customizable pen case with a snap-fit lid. I'd like it to have three compartments inside and a space for a label on the bottom.

Here are the key parameters I need to control:

*   **Overall dimensions:**
    *   `length`: The total length of the case (in mm).
    *   `width`: The total width of the case (in mm).
*   **Compartment widths:**
    *   `section1`: Width of the first compartment (in mm).
    *   `section3`: Width of the third compartment (in mm). The middle compartment's width should be calculated based on the overall width and the other two compartment widths.
*   **Wall thickness:**
    *   `thickness`: Thickness of the case walls (in mm).
*   **Labeling:**
    *   `name`: Text for the label on the bottom of the case.
    *   `fontsize`: Size of the label text (in mm).
*   **Part selection:**
    *   `b_lowerpart`: Boolean to generate the lower part of the case (default `true`).
    *   `b_upperpart`: Boolean to generate the upper/lid part of the case (default `true`).
*   **Angular accuracy:**
    *   `$fn`: Resolution for curved surfaces (in degrees, defaults to 360).

The case should consist of two parts: a lower part with the compartments and a lid that snaps onto it using an overhang. The overhang will be on the lid, not on the base. The bottom text should be mirrored with center alignment for both halign and valign. I'd like to be able to specify whether I want to generate just the bottom, just the top, or both. Please use the "Cooper Black" font.

Could you generate the OpenSCAD files for this? I would like the design to be generated from scratch, without relying on the existing file.

[Assistant]
Brillenetuiv3.1.scad:
```
// version 2: keine Schnapper, dafuer Ueberhang am Boden
// version 3: extremerer Ueberhang, englische Variablen
/* [dimensions in mm] */
//outside length
length=145;// 30 Test, 145 kleine Stifte, 175 mm fuer lange Stifte
//outside width
width=66;

//first section width - middle section will be calculated
section1=11;// fuer Kreide

// third section width - middle section will be calculated
section3=12;// fuer Kuli

//wall thickness
thickness=1.2;

/*[labeling]*/
// label text on the bottom
name="Noname";

// fontsize in mm
fontsize =17;

/*[parts]*/
//lower part?
b_lowerpart=true;

// upper part?
b_upperpart=true;

/*[angular accuracy]*/
// angular accuracy in degree
$fn=360;

/*
// Schnittt
difference(){
  color("red")  unterteil(name);
  cube([length/2,width,width]);
}
//
*/

if(b_lowerpart)color("red")  unterteil(name);
//color("blue")  oberteil();
if(b_upperpart) color("blue")  translate([0,-(width+thickness),0])oberteil();

module oberteil(){

  difference(){

    translate([0,width/2,width/7])
    rotate([0,90,0])scale([0.75,1,1])
    rotate_extrude(angle=360)
    translate([width/2,0,0])
      rotate([0,0,90])
        polygon([[0,0],[length,0],
              [length,2*thickness],
              [length-thickness/2,2*thickness],
              [length-thickness,thickness],
              [thickness,thickness],
              [thickness/2,2*thickness],
              [0,2*thickness]]);
    // unten abschneiden
    saubererschnitt=1;// fuer sauberen Schnitt
    translate([-saubererschnitt,0,-width/2])cube([length+2*saubererschnitt,width,width/2]);

  }

}

module unterteil(txt){

  difference(){

    translate([thickness,width/2,width/7])
    rotate([0,90,0])scale([0.75,1,1])cylinder(h=   length-2*thickness, d=width-2*thickness);

    // untere Haelfte weg
    translate([0,0,-width/2])cube([length,width, width/2]);

    hmax=0.8*width/2+width/7;
    // 1.Faech weg
    translate([2*thickness,3*thickness,thickness])cube([length-4*thickness,section1,hmax]);
    // Tiefere Kante aussen
    translate([2*thickness,-thickness,thickness+width/8])cube([length-4*thickness,section1,hmax]);
    // 2. Fach weg
    translate([2*thickness,4*thickness+section1,thickness])cube([length-4*thickness,width-8*thickness-section1-section3,hmax]);
    // 3. Fach weg
    translate([2*thickness,width-3*thickness-section3,thickness])cube([length-4*thickness,section3,hmax]);
    // Tiefere Kante aussen
    translate([2*thickness,width-section3,thickness+width/8])cube([length-4*thickness,section3,hmax]);

    //text am Boden
    translate([length/2,width/2,0])linear_extrude(height = 2*thickness/3)   mirror([1,0,0])text(txt, size = fontsize, /*font = "Script MT Bold",*/font ="Cooper Black", halign = "center", valign = "center", $fn = 32);

  }

}

```