[User]
I'm looking for an OpenSCAD design for a customizable label tag for IKEA Trofast bins. I'd like it to be parametric so I can easily adjust the dimensions and text.

Here's what I have in mind:

*   **Overall Shape:** The tag should be a rectangular prism with a small hinge mechanism at the top. The hinge should have two rectangular sections: one that's a bit thicker and goes under the top of the bin, and a smaller bit that extends downwards and is a little shorter. The goal is for it to hook onto the side of the Trofast container.
*   **Dimensions:**
    *   I need to be able to set the overall `length` of the tag.
    *   I need to set the overall `width` of the tag.
    *   The `thickness` of the main tag body should be adjustable.
    *   The vertical `hinge_space` between the lower rectangular hinge section and main body of the tag should be adjustable.
    *   The `hinge_height` (the length of the smaller, downward-pointing rectangle of the hinge) should be adjustable.
*   **Text:**
    *   I need to be able to specify the `subject` text that is written on the label.
    *   I'd like control over the `font_size` of the text.
    *   It would be good to be able to select the `font_family` (ideally using any font available from Google Fonts). The text should be centered on the tag.
*   **Construction:** The text should be cut out of the main body of the tag.

Could you generate an OpenSCAD file (or files, if that makes more sense) for this? Please make sure to include good comments and use parametric design, so everything can be configured easily. I would like to see the code make good use of modules and avoid repeated code.

[Assistant]
trofast-tag.scad:
```
/**
 * A labelling system for IKEA Trofast containers. Customizable text.
 *
 * Author: Joseph Paul <joseph@sehrgute.software>
 * License: Public Domain
 */

/* [Tag Dimensions] */

// Material thickness of the entire tag
thickness = 2; // [1:10]
// Lenght of the tag (keep <130mm for the short side and <230mm for the long side of your Trofast)
length = 100; // [10:230]
// Width of the entire Tag
width = 20; // [10:230]

/* [Caption] */

// The text written on the tag
subject = "ERFINDERGARDEN";
// Font size for the text
font_size = 8; // [2:128]
// Font Family (all google fonts are supported, see https:\/\/fonts.google.com)
font_family = "Open Sans";

hinge_space = 10;
hinge_height = 10;

module tag()
{
	union() {
		cube([length, thickness, width]);
		translate([0, 0, width - thickness])
		cube([length, hinge_space + 2*thickness, thickness]);
		translate([0, hinge_space + thickness, width - thickness - hinge_height])
		cube([length, thickness, hinge_height]);
	}
}

module caption()
{
	text(subject, font=font_family, size=font_size, valign="center", halign="center");
}

difference() {
	tag();
	translate([length/2, thickness+1, width/2])
	rotate([90, 0, 0])
	linear_extrude(thickness+2)
	caption();
}

```


[User]
I'd like to be able to generate rolling pin guides that help me roll dough to a consistent thickness. I'm not very good at rolling evenly, and my cookies come out all different thicknesses.

I've got a rolling pin, and I'd like to create some sort of ring or guide that slides onto the ends, so the dough is rolled to the correct thickness. Here are the parameters I would need for this:

*   **`diameter`**: The diameter of the rolling pin itself (in millimeters). I need to be able to adjust this parameter, since I might use different rolling pins. It's probably between 30 and 70 mm, maybe in 0.5 mm increments.
*   **`width`**: This is the thickness I want the dough to be (in millimeters). This could range from 1 to 10mm, maybe in 1mm increments.
*   **`height`**: The height of the guide (in millimeters). This is how tall the cylinders will be and should be adjustable between 2 and 10 mm, maybe in 1 mm increments.
*   **`number`**: The number of guides to generate, options should be One, Two or Four. So it would generate that many guides, either at the specified locations or all the same location.
*   **`facet`**: A boolean to indicate whether there should be an angled "facet" on the outside of the guide to help it slide over the dough. It's either on or off, so 0 or 1.
*   **`second_facet`**: Another boolean, only relevant if `facet` is on, if on, there should be a second facet or angled bit.
*  **`thickness`**: The thickness of the facet (in millimeters), should be between 1 and 5 mm, in 0.5mm increments, but should never be larger than half of the `height`.

I think that's everything! Could you make an OpenSCAD file that uses these parameters to create the guides? I'm not sure if the best way to do the positioning would be to use `translate()` calls, but maybe you'll have a better solution. I'm also not sure about the best way to do the angled facets, but a cylinder with a different radius on each end might work.

Oh, also, I don't need the `$fn` variable to be set in the code. My computer handles the rendering fine.

[Assistant]
rolling_pin_enhancer.scad:
```
/* Copyright © 2016. Alexander Golikov.
 *
 * This file is free software: you can redistribute it and/or modify it under the terms of the Creative Commons Attribution-NonCommercial-ShareAlike International Public License, either version 4.0 of the License, or (at your option) any later version.
 *
 * This file is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the Creative Commons Attribution-NonCommercial-ShareAlike International Public License for more details.
 *
 * You should have received a copy of the Creative Commons Attribution-NonCommercial-ShareAlike International Public License along with this file.
 *
 * If not, see https://creativecommons.org/licenses/by-nc-sa/4.0/legalcode.
 */

// Diameter of rolling pin.
diameter = 40.5; 		// [30:0.5:70]
// Thickness of the rolled dough.
width = 7; 				// [1:1:10]
// Height of the extender.
height = 5; 			// [2:1:10]
// Number of the extenders
number = 2; 			// [1:One, 2:Two, 4:Four]
// Sharp facet. NOTE! Depends on opportunities of Your printer
facet = 1; 			// [1:On, 0:Off]
// Dual sharp facet, if "Sarp facet" is on.
second_facet = 0; 	// [1:On, 0:Off]
// Thickness of "Sarp facet". NOTE! May be NOT MORE then Height/2!
thickness = 1; 			// [1:0.5:5]

/* [Hidden] */

//$fn=64;
d=diameter;
w=width;
h=height;
th=thickness;

r1=(d/2+w);
r2=(d/2+(w-1));

if (th > (h/2)) {
	th = round(h/2);
}

if(number==4) {
	guide(d,d);
	guide(d,-d);
	guide(-d,d);
	guide(-d,-d);
} else if(number==2) {
	guide(0,d);
	guide(0,-d);
} else {
	guide(0,0);
}

module guide(x,y) {
	translate([x,y,0]){
		difference(){
			union(){
				color("green")
					if(facet==1){
						if(second_facet==1){
							union(){
								cylinder(h=th,r1=r2,r2=r1,center=false);
								translate([0,0,th]){
									cylinder(h=th,r1=r1,r2=r2,center=false);
								}
							}
						} else {
							cylinder(h=2*th,r1=r1,r2=r2,center=false);
						}
					} else {
						cylinder(h=h,r=r1,center=false);
					}
				color("red")
					cylinder(h=h,d=(d+(2*th)),center=false);
			}
			color("yellow")
				translate([0,0,-(th/2)])
					cylinder(h=h+th,d=d,center=false);
			color("blue")
				translate([((d/2)-th),-(th/2),-(th/2)])
					linear_extrude(h=(h+th), slices=(5*h), twist=(3*h))
						square([(w+(2*th)),(th)],false);
		}
	}
}

```


[User]
Hi, I'm looking to design a rotary transmission based on the SRI abacus concept, you know, like in that Popular Mechanics article I linked, using OpenSCAD. I've made a start (and will attach what I have) but I think I need a more parametric approach for the different parts. Basically, it's got inner and outer races with wavy profiles and rollers that fit between the races.

Specifically, I'd like to be able to control these aspects:

*   **Inner Race:**
    *   Inner diameter
    *   Race thickness
    *   Number of inner cycles (the waves)
    *   The amplitude of the wave
*   **Outer Race:**
    *   Outer diameter
    *   Race thickness
    *   Number of outer cycles (the waves)
    *    The amplitude of the wave
*   **Rollers:**
    *   Number of rollers
    *   Roller diameter
    *   Roller taper (if any)
    * The spacing and placement between the rollers
*   **General:**
    *  Overall thickness of the unit

I'd like the waves to be generated using `sin()` functions, as in my code, and the rollers to be a kind of truncated cone shape, though maybe we can work on the details of that once the basic parts are done.

I'd prefer all of this to be generated in a few separate .scad files: one for the rollers, one for the inner race, and another for the outer race. These should be able to be included into a master file for assembly. I'm not sure if it's going to work well with my current values so these parameters should be able to be tweaked easily for experimentation.

I'm not planning to use any external libraries beyond the standard OpenSCAD functionality.

Could you generate the code for me based on these parameters?

[Assistant]
AbacusDriveshow.scad:
```
part=0;//[0,1,2,3]
$fn=50;
//inner race
inrace= 30;
//outer race
outrace= 40;
//inner cycles
icyc=6;
//outer cycles
ocyc=8;
//no rollers
rollers=7;
//roller size
roller=10;
//roller taper
cone=0.1;

step=360/($fn*3);
if (part==1||part==0){
 color("Red")for (i=[0:90/rollers*2:90])
{rotate([0,0,i+90])
 translate([outrace+10+roller*1.5,0,00]){
  rotate_extrude(angle = 360, convexity = 2) hull(){
offset(0.5,$fn=3)offset(-0.5)hull(){
square([roller,0.01]);
translate([roller*cone,-10,0])square([0.01,20] );
}
translate([0,-9,0])square([0.01,16] );
}}
}}

if (part==2||part==0){
 color("LightGreen")difference(){
orace(outrace,20);

for(i=[0:step:360])
{
hull(){
rotate([0,0,(i)])translate([outrace,0,0])
scale([1.1+ (sin((i) *ocyc))  ,1,1.1+ (sin((i) *ocyc))  ])scale([1,1,0.5])rotate([0,45,0])
cube([10,0.1,10],center=true);

rotate([0,0,(i+step)])translate([outrace,0,0])
scale([1.1+ (sin((i+step) *ocyc))  ,1,1.1+ (sin((i+step) *ocyc))  ])scale([1,1,0.5])rotate([0,45,0])
cube([10,0.1,10],center=true);
 }
}
 for (i=[0:360/ocyc:360]){
rotate([0,0,i+(360/ocyc)*0.75])translate([outrace +5,0,0])cylinder(21,2,2,center=true);}

}}

if (part==3||part==0){
 color("LightBlue") difference(){
 irace(inrace,20);
for(i=[0:step:360])
{
hull(){

rotate([0,0,(i)])translate([inrace,0,0])
scale([1+ (sin((i)*icyc)) ,1,1.1+ (sin((i) *icyc))  ])scale([1.5,1,0.5])rotate([0,45,0])
cube([10,0.1,10],center=true);

rotate([0,0,(i+step)])translate([inrace,0,0])
scale([1+ (sin((i+step)*icyc)) ,1,1.1+ (sin((i+step) *icyc))  ])scale([1.5,1,0.5])rotate([0,45,0])
cube([10,0.1,10],center=true);

}
}
 for (i=[0:360/icyc:360]){
rotate([0,0,i+(360/icyc)*0.75])translate([inrace -5,0,0])cylinder(21,2,2,center=true);}
}}

module orace (ri,ro)
{

 rotate_extrude(angle = 360, convexity = 2)
 offset(0.5,$fn=5)offset(-0.5 )translate([ri , -ro*0.5 ])square([ro*0.5 ,ro*0.50] );
}
module irace (ri,ro)
{

 rotate_extrude(angle = 360, convexity = 2)
 offset(0.5,$fn=5)offset(-0.5 )translate([ri -ro*0.5, -ro*0.5 ])square([ro*0.5 ,ro*0.5] );
}
```


[User]
I'd like to create a customizable, lattice-like structure based on rotating cubes, similar to the design I saw on Makers Muse, but with some enhancements. I need an OpenSCAD file or files that allows me to control several parameters.

First, the basic cube size should be adjustable. Let's call this parameter `cube_side` or `cs`.

Second, I need to control the number of lattice dividers within each cube. This would be a whole number, `dividers`, or `dn`.  This should affect the spacing of the lattice bars.

Third, the width of the lattice bars needs to be settable, let's use `bar_width` or `ws`. I would want it to be something that can be set to either a round or square cross-section using a string variable called `bar_type` or `bt` which can be either "round" or "square".

Fourth, I want an optional base for the structure. This should be defined by a parameter `base_height` or `dh`. If this is 0, there shouldn't be any base. I would like to control the size of the base through a relative value to the distance between lattice points which i'm calling `base_scale` or `ds`.

Finally, I need to control how many rotated cube layers are stacked, let’s call this parameter `cube_multiplier` or `dbl`. This will cause the entire structure to be repeated at different rotation angles around the vertical axis.

I’m not looking to use any external libraries for this, since the core functionality appears simple enough. The main concept is to generate the individual bar pieces as either spheres or cubes and use `hull()` to make bars, then rotate all the bars around a given center point for different `dbl` layers. A base should be generated if a base height is requested, by adding a cylinder that matches the general shape of the structure and has a given height and radius.

Hopefully that gives you what you need to generate the SCAD file, let me know if you have any questions!

[Assistant]
cube2.scad:
```
//Cube side; 62 will make it 100 high
cs=62;//[10:250]
//Number of dividers
dn=1;//[0,1,2,3,4,5]
//Bar width
ws=4;//[1:0.2:10]
//Bar type
bt="round";//[round,sqare]
//Base height (0 for none)
dh=0.6;//[0:0.1:5]
//Make it double or more
dbl=2;//[1:single,2:double,3:tripple,4:quadruple,5:5,6:6,7:7,8:8,9:9,10:10,11:11,12:12]
/* [Hidden] */
ds=1.25;
$fn=16;
dl=cs/(dn+1);
a2=35.264;
module node(){
    if (bt=="round"){
        sphere(ws/2);
    } else {
        cube(ws,true);
    }
}

difference(){
for(ndbl=[1:dbl])translate([0,0,-cs/(dn+1)*sin(a2)+dh])rotate([45,-a2,120/dbl*ndbl])rotate([0,0,0])for(n1=[0:dn+1]){
    for(n2=[0:dn+1]){
        hull(){
            translate([n1*dl,n2*dl,0])node();
            translate([n1*dl,n2*dl,cs])node();
        }
        hull(){
            translate([n1*dl,0,n2*dl])node();
            translate([n1*dl,cs,n2*dl])node();
        }
        hull(){
            translate([0,n1*dl,n2*dl])node();
            translate([cs,n1*dl,n2*dl])node();
        }
    }
}
translate([-cs,-cs,-2*cs+dh])cube(2*cs);
}
cylinder(h=dh,r=cs/(dn+1)*cos(a2)*ds);

```


[User]
I'd like to design a parametric coin cell holder for 3D printing, and I'm hoping you can help generate the OpenSCAD code. It should be customizable for different battery types and number of cells, similar to a design I saw online.

Here are the key features I'm looking for:

*   **Parametric Battery Types:** It needs to easily handle CR2032, CR2025, and AG13 batteries as presets, but also allow for a custom battery type where I can specify the radius and width.
*   **Number of Cells:** I need to be able to set the number of cells the holder will accommodate.
*   **Loose Fit:** The holders should be slightly oversized so the coin cells are easy to remove and insert. I don’t need a very tight fit.
*   **Dividers:** Each battery should have a divider between them to keep them separate. These dividers should have a configurable width.
*   **Text Label:** It would be useful to have a text label on the side to indicate the type of batteries the holder is designed for.
*   **Base:** The holder should have a simple rectangular base.
*   **OpenSCAD Libraries:** I don't need any external libraries for this.

Could you provide the OpenSCAD code for this design? Let me know if you need any other clarifications.

[Assistant]
storage.scad:
```
// License: Creative Commons, Attribution
// Parametrized coin cell holder

// Author: dereulenspiegel

// Battery count
nr = 10; //[5:50]

// Battery type
battery = "CR2023"; //[CR2025, CR2023, AG13, custom]

// Radius of the battery
custom_radius = 10; // [2:50]

// Width of the battery
custom_width = 3.4; //[1:10]

// Text
custom_text = "cells";

// Width of the divider and walls
width_divider = 0.8;

$fn=128;

module holder(radius, width, text) {
  length = nr*(width_divider+width) + width_divider;

  difference(){
    cube([2*radius + 2*width_divider, length, radius+width_divider]);
    for(i = [0:nr]){
      translate([width_divider+radius, (i*(width_divider + width) + width_divider + width), radius+width_divider]){
        rotate([90,0,0]){
          cylinder(h=width, r=radius);
        }
      }
    }
    rotate([90,0,0]){
      translate([radius+width_divider,radius/2,-0.3]){
        linear_extrude(1.2){
          text(text,size=3, halign="center", valign="center");
        }
      }
    }
  }
}

if (battery == "CR2023") {
  holder(10, 3.4, "CR2023");
}
if (battery == "AG13") {
  holder(6, 5.7, "AG13");
}
if (battery == "CR2025") {
  holder(10, 2.8, "CR2025");
}
if (battery == "custom") {
  holder(custom_radius, custom_width, custom_text);
}

```


[User]
Hey, I'm looking to generate some 3D printable poop models, but I want them to be highly customizable. I've seen some designs that use a spiral shape, and I'd like to be able to control things like the number of turns, how detailed the shape is, and how wide the spiral gets.

Ideally, I'd like to be able to specify:

*   **Number of turns:** How many times the spiral twists around.
*   **Detail level:** The number of polygons used to define each element of the spiral, kind of like the `$fn` parameter in OpenSCAD.
*   **Turn resolution:** How many "points" are used to make up each turn of the spiral. A higher resolution should make the spiral look smoother and rounder.
*   **Spiral width:** How far the spiral moves out from the center.
*   **Spiral direction:** Clockwise or counter-clockwise.
*   **Overall Height:** The height of the "poop"

It should create a model using these parameters. I don't need to do any fancy Boolean operations, a single object will work. I was thinking something along the lines of building a helix, and then using spheres or something to create the round shape, but I am open to other suggestions if there is a better way. I’d also like to have the base be flat so it can sit nicely on a surface. I don't need it to be a specific size or anything like that, just make sure all the parts scale together properly.

I know OpenSCAD can be slow for complex shapes so if there are ways to optimize this, I’d be grateful. I’m not familiar with using any OpenSCAD libraries, so a basic implementation would be great.

[Assistant]
poop.scad:
```
// Bosta paramétrica
// Customized poop
// By Patola
// 31 oct 2016

// How many turns the poop will have
turns=5; // [1:50]

// Definition (number of polygons) for each element
definition=30; // [10:100]

// Resolution of each turn (number of plots by turn, the bigger the rounder)
resolution=64; // [3:100]

// Distance of the turns from the center. The bigger the wider.
distance=80; // [-30:200]

// Counterclockwise (default) or clockwise.
clockwise=1; // [-1:clockwise,1:counterclockwise]

/* [Hidden] */
radius=30*5/turns; // greater turns, smaller sphere
rate=10*5/turns*clockwise; // every turn decreases by this much;
zlift=160;
angle=turns*360*clockwise;
interval=360/resolution*clockwise;

difference() {
  for (i=[interval:interval:angle]) {
    echo (zlift*(i/angle));
    hull() {
      rotate([0,0,i-interval]) translate([distance-rate*(i/360),0,zlift*((i-interval)/angle)]) sphere(r=radius*sqrt(sqrt((angle-i+interval)/angle)),$fn=definition);
      rotate([0,0,i]) translate([distance-rate*(i/360),0,zlift*(i/angle)]) sphere(r=radius*sqrt(sqrt(((angle-i)/angle))),$fn=definition);
    }
  }
  translate([-2*distance,-2*distance,-distance]) cube([4*distance,4*distance,distance]);
}
```


[User]
I need a design for a wall mount for wire mesh panels, something that attaches to the wall with standard #10 mini-stapler needles, like those used in "Kabebijin" products. I'm thinking of a design where the wire panel sits a bit off the wall, maybe around 6mm, but that should be adjustable. I'd also like to be able to customize the wire diameter of the panel to hold it securely, since they vary a bit.

Here's a breakdown of what I need:

**Overall Design:**

*   The mount should have a flat base that sits against the wall.
*   It needs to have two "staple points" to hold the mini-stapler needles, so it's attached securely.
*   The mount should have a curved "cradle" area that will hold the wire mesh panel.
*   The "cradle" needs to have a customizable diameter based on the wire thickness.
*   The wire panel should be offset from the wall a configurable amount.

**Customization Parameters:**

*   **wire\_diameter:** The diameter of the wire in the mesh panel, ranging from 2.0mm to 5.0mm.
*   **clearance:** A clearance value, from 0.1mm to 0.4mm, to account for 3D printer accuracy - this will change the size of the cradle so the wire fits correctly.
*  **panel\_offset:** The distance that the wire mesh panel is offset from the wall - let's have that be adjustable from 3mm to 10mm.
*   **testprint:** A boolean flag where, if it's enabled, only the center portion of the mount is created ( the wire panel cradle ). This is for test printing and verifying the fit before making the whole thing.
*   **quantity:** The number of mounts to generate, ranging from 1 to 6.
*   The design should include rounded edges and chamfers for aesthetics and ease of use. I don't want sharp edges on any of it.

**Specifics:**

*   I need the design to be parametric, so I can easily modify these values in OpenSCAD.
*   The design should be easily printable, so no crazy overhangs. PLA is likely the best material, so that's what it should be designed for.
*   I am looking to use #10 mini stapler needles.
*   I would prefer it if the OpenSCAD code was easy to read and well commented, if possible.
* I don't need the code to use any custom libraries, just what is included by default.

That should be enough, I think. Please let me know if you need any more information.

[Assistant]
mesh_panel_wall_mount.scad:
```
// preview[view:east, tilt:top diagonal]

/*[Parameters]*/

wire_diameter = 3.8;	//[2.0:2.0mm,2.1:2.1mm,2.2:2.2mm,2.3:2.3mm,2.4:2.4mm,2.5:2.5mm,2.6:2.6mm,2.7:2.7mm,2.8:2.8mm,2.9:2.9mm,3.0:3.0mm,3.1:3.1mm,3.2:3.2mm,3.3:3.3mm,3.4:3.4mm,3.5:3.5mm,3.6:3.6mm,3.7:3.7mm,3.8:3.8mm,3.9:3.9mm,4.0:4.0mm,4.1:4.1mm,4.2:4.2mm,4.3:4.3mm,4.4:4.4mm,4.5:4.5mm,4.6:4.6mm,4.7:4.7mm,4.8:4.8mm,4.9:4.9mm,5.0:5.0mm]
clearance = 0.1;	//[0.1:0.1mm,0.2:0.2mm,0.3:0.3mm,0.4:0.4mm]
panel_offset = 6;	//[3:3mm,4:4mm,5:5mm,6:6mm,7:7mm,8:8mm,9:9mm,10:10mm]
testprint = 0;	//[0:None,1:For Test Print]
quantity = 1;	//[1:1,2:2,3:3,4:4,5:5,6:6]

/*[Hidden]*/

module mesh_panel_wall_mount(wire_diameter,clearance,panel_offset,testprint,quantity)
{
	module rounded_cube(x,y,z,r,top_chamfer,bottom_chamfer) {
		difference(){
			cube([x,y,z]);
			if ( r > 0 ) {
				for ( tr=[[[-adj,-adj,-adj],[r,r,-adj]],[[x-r,-adj,-adj],[x-r,r,-adj]],[[-adj,y-r,-adj],[r,y-r,-adj]],[[x-r,y-r,-adj],[x-r,y-r,-adj]]] ) {
					difference(){
						translate(tr[0]) cube([r+adj,r+adj,z+adj*2]);
						translate(tr[1]) cylinder(r=r,h=z+adj*2,$fn=fn);
					}
				}
			}

			if ( top_chamfer > 0 ) {
				for ( tr=[[[0,r,0],[0,0,0],y],[[r,y,0],[0,0,-90],x],[[x,y-r,0],[0,0,-180],y],[[x-r,0,0],[0,0,-270],x]] ) {
					translate(tr[0]) {
						rotate(tr[1]) {
							translate([0,-adj,z]) {
								rotate([-90,0,0]) {
									linear_extrude(height=tr[2]-r*2+adj*2,center=false,convex=10) {
										polygon(points=[[-adj,-adj],[top_chamfer+adj,-adj],[-adj,top_chamfer+adj]]);
									}
								}
							}
							translate([r,tr[2]-r*2,z]) {
								intersection() {
									rotate_extrude($fn=fn) {
										translate([-r,0,0]) {
											polygon(points=[[-adj,adj],[top_chamfer+adj,adj],[-adj,-top_chamfer-adj]]);
										}
									};
									translate([-r-adj,0,-top_chamfer-adj]) {
										cube([r+adj,r+adj,top_chamfer+adj*2]);
									}
								}
							}
						}
					}
				}
			}

			if ( bottom_chamfer > 0 ) {
				for ( tr=[[[0,r,0],[0,0,0],y],[[r,y,0],[0,0,-90],x],[[x,y-r,0],[0,0,-180],y],[[x-r,0,0],[0,0,-270],x]] ) {
					translate(tr[0]) {
						rotate(tr[1]) {
							translate([0,-adj,0]) {
								rotate([-90,0,0]) {
									linear_extrude(height=tr[2]-r*2+adj*2,center=false,convex=10) {
										polygon(points=[[-adj,adj],[bottom_chamfer+adj,adj],[-adj,-bottom_chamfer-adj]]);
									}
								}
							}
							translate([r,tr[2]-r*2,0]) {
								intersection() {
									rotate_extrude($fn=fn) {
										translate([-r,0,0]) {
											polygon(points=[[-adj,-adj],[bottom_chamfer+adj,-adj],[-adj,bottom_chamfer+adj]]);
										}
									};
									translate([-r-adj,0,-adj]) {
										cube([r+adj,r+adj,bottom_chamfer+adj*2]);
									}
								}
							}
						}
					}
				}
			}

		}
	}

	fn=36;
	width=24;
	depth=80;
	height=2.0;
	staple_thickness=0.4;
	staple_width=11;
	bezel_width=3.2;
	outer_round=4.2;
	adj=0.1;

	offset=panel_offset-height;
	dia1=wire_diameter+clearance*2;	//3.8,0.1 -> 4.0  3.8,0.2 -> 4.2
	dia2=wire_diameter-0.4+clearance*2;	//3.8,0.1 -> 3.6  3.8,0.2 -> 3.8

	l1=1.0;
	l2=6.0+wire_diameter;
	slot_chamfer=0.5;

	mount_height=offset+dia1+l1;
	mount_width=mount_height*2+l2/2;

	for ( q = [0:quantity-1] ) {
		translate([q*(width+1.0),0,0]) {
			intersection() {
				union() {
					difference(){
						rounded_cube(width,depth,height,outer_round);

						translate([
							bezel_width-(height-staple_thickness)
							,bezel_width-(height-staple_thickness)
							,staple_thickness]
						)
							rounded_cube(
								width-bezel_width*2+(height-staple_thickness)*2
								,staple_width+(height-staple_thickness)*2
								,height-staple_thickness+adj
								,outer_round-bezel_width+(height-staple_thickness)
								,0
								,(height-staple_thickness)
							);

						translate([
							bezel_width-(height-staple_thickness)
							,depth-bezel_width-staple_width-(height-staple_thickness)
							,staple_thickness
						])
							rounded_cube(
								width-bezel_width*2+(height-staple_thickness)*2
								,staple_width+(height-staple_thickness)*2
								,height-staple_thickness+adj
								,outer_round-bezel_width+(height-staple_thickness)
								,0
								,(height-staple_thickness)
							);
					}

					translate([0,depth/2,height]) {
						rotate([90,0,90]) {
							difference() {
								linear_extrude(height=width,center=false,convex=10) {
									polygon(points=[
										[-mount_width/2,-adj]
										,[-mount_width/2,0]
										,[-l2/2,mount_height]
										,[-dia2/2-slot_chamfer,mount_height]
										,[-dia2/2,mount_height-slot_chamfer]
										,[-dia2/2,mount_height-l1-dia1/2]
										,[dia2/2,mount_height-l1-dia1/2]
										,[dia2/2,mount_height-slot_chamfer]
										,[dia2/2+slot_chamfer,mount_height]
										,[l2/2,mount_height]
										,[mount_width/2,0]
										,[mount_width/2,-adj]
									]);
								}
								translate([0,offset+dia1/2,-adj]) {
									cylinder(r=dia1/2,h=width+adj*2,$fn=fn);
								}

							}
						}
					}
				}

				if ( testprint==0 ) {
					translate([-adj,-adj,-adj])
						cube([width+adj*2,depth+adj*2,height+mount_height+adj*2]);
				} else {
					translate([-adj,mount_width/2,height+adj])
						cube([width+adj*2,depth-mount_width,mount_height+adj*2]);
				}
			}
		}
	}

}

mesh_panel_wall_mount(wire_diameter,clearance,panel_offset,testprint,quantity);

```


[User]
Hey there, I'm looking to create a tool for calibrating the XY skew on my 3D printer, and I've seen a design that I really like but I'd like it to have a few more options and be more flexible. It's based on two strips that you print out, and then align them using a piece of filament. One strip has a standard 1mm scale, and the other one has a 0.9mm vernier scale which allows for more precise measurement of skew.

Here's the breakdown of what I need:

**Core Functionality (already provided in the existing script, needs reimplementation):**

*   Two calibration strips: A main "bisector" strip, and an "orthogonal" strip.
*   The strips should be rotated according to the bed dimensions (X and Y).
*   They need an alignment hole at one end for inserting a filament piece to help align strips.
*   Each strip needs a center measurement mark
*   One strip needs a 1mm scale with marks at every 5mm and intermediate marks.
*   The other strip needs a vernier scale (0.9mm scale) with corresponding marks at every 5mm and intermediate marks.
*   The length of the strips is determined by bed size and max skew settings.

**Parametric Requirements:**

1.  **Bed Dimensions:** I need to be able to specify `bedX` and `bedY` so the strips are the right size.

2.  **Filament Diameter:** This should be a variable `filamentDiameter` (1.75mm and 2.85mm are the most common).

3.  **Extrusion Width:** `extrusionWidth` needs to be parametric so I can tune for my nozzle size.

4.  **Layer Height:** `layerHeight` is also important for calculating the model's height.

5.  **Strip Width:** `stripWidth` should be calculated from extrusion width (e.g., `stripWidth = 6 * extrusionWidth`).

6.  **Strip Height:**  `stripHeight` should be derived from layer height (e.g., `stripHeight = 4 * layerHeight`).

7.  **Scale Spacing:** The spacing of the scale markings should be an adjustable parameter. Perhaps `scaleSpacing`.

8.  **Origin Alignment Spacing:**  The placement of the alignment pin is another thing that should be set with a variable.

9. **Maximum Skew:** `maximumSkew` needs to be an adjustable parameter to set the maximum skew amount the strip is designed to measure. This will affect the strip length.

10. **Orthogonal Strip Selection:** I need a way to choose whether the vernier scale is on the orthogonal strip or on the bisector. This can be a simple 0/1 variable called `generateOrthogonalBisector`.

**New Features and Changes:**

1.  **Expanded Scale Options:** Could I get an option for specifying scale increments, not just using every 5mm? So like, `majorScaleIncrement` and `minorScaleIncrement` that defaults to 5 and 1 respectively.

2.  **Clearer Vernier Scale:** Is there any way to make the vernier scale easier to read? Maybe like, make the lines thicker or something? I'm open to suggestions here. Maybe having the lines 'fill in' the gap between the strip and measure mark would be helpful.

3.  **Multiple Alignment Pins:** Could I have an option for the number of alignment pins on either end, and their diameter? Let's say `alignmentPinCount` and `alignmentPinDiameter`.

4.  **Fillet Option:** Would it be possible to add a fillet on the edges of the strip to reduce warping? A simple `filletRadius` option that defaults to 0 would be great.

5. **Use Libraries:** Are there any libraries that could be useful? It looks like `polyhole` uses a somewhat complex method for creating polyholes, so maybe there's an existing module in a library to take care of that? Or for doing the fillets?

**Additional Notes:**
* I'd like this to be reasonably accurate so that I can get a good calibration on my printer.
* The existing code includes some echo statements for debug output -- that's also something I'd like to see included.
* I prefer metric units.

I think that covers everything, let me know if you have any questions. Thanks!

[Assistant]
bedSkewCalibration-fiveangle.scad:
```
// model: Bed XY Skew Calibration Strips
//        Generates calibration strips that allow you to determine approximate level of skew in XY axes for 3D printers with Cartesian gantry systems.
// filename: bedSkewCalibration-fiveangle.scad
// original: http://www.thingiverse.com/thing:1873549
// author: fiveangle@gmail.com
// date: 2016nov05
// ver: 0.9.1
// notes: Set generateOrthogonalBisector to "True" to generate second calibration strip. Insert a segment of filament into the hole end of printed calibration strip to align them; read the resulting skew on the vernier scale on the other end. If center marks are aligned, XY axes are square within the resolution of your extrusion width.  If they are off.  Adjust, wash, rinse, repeat. I'll probably update again shortly, so please send me bugfixes/improvement (and your history entry) if you wish, and I will incorporate/atribute.
// printing notes:
//     * Perform all other normal calibrations first (decent summary here: https://www.3dhubs.com/talk/thread/howto-calibrate-tune-and-fine-tune-your-printer-and-filament)
//     * Print with one shell
//     * Print with PLA
//     * Print with lowest temperature possible
//     * If printing on heated bed, wait for bed to get close to room temperature before removing print
//     * Use a filament color with good reflectivity for easiest reading of vernier scale (silver, for example).
// todo: Fix scaling for greater than 1mm, add math to maximumize available bed length, currently testing different methods to produce clearer verniers
// history:
//     -0.9.1 - 2016nov12 - fiveangle@gmail.com - Fixed Customizer bugs:
//                                                    - apparently Customizer doesn't work with Boolean value/comment pairs
//                                                    - fixed filamentDiameter Customizer value/comment pairs transposed
//                                              - Changed maximumSkew math to account for +1 value of vernier for
//                                              - Reduced maximum skew from 11mm to 6mm (if your bed is more than that, you got problems :)
//                                              - Fixed 3mm filament diameter to the true value of 2.85mm (I've never owned a printer that used it myself)
//
//     -0.9.0 - 2016nov05 - fiveangle@gmail.com - Released on thingiverse in order to facilitate ongoing XY calbiration discussion at https://github.com/MarlinFirmware/Marlin/issues/5116

// adjust to increase/decrease polygon count at expense of processing time (above 100 is probably useless)
$fn = 100;
bedX = 250;
bedY = 210;

// Which diagonal to make (you need to generate one of each) ?
generateOrthogonalBisector = 1; // [0:XY Bisector Diagonal, 1:XY Orthogonal Diagonal]

filamentDiameter = 1.75; // [1.75:1.75mm, 2.85:2.85mm]

// Should be at least the Extrusion Width set in your slicer or the measurement marks will not print. +0.02 to +0.04 mm seems to work well to allow most slicers to generate correct markings
extrusionWidth = 0.42;
layerHeight = 0.2;
stripWidth = 6 * extrusionWidth;
stripHeight = 4 * layerHeight;

// Math to auto-adjust for spacing other than 1 extrusion width is not implemented yet so this currently works for only "1"
scaleSpacing = 1;

originAlignmentSpacing = 4;

bufferLength = 2 * stripWidth; // to ensure we don't run out of bed. With new alignment method of using a piece of filament, probably need to make this calculation more rigorous to support all printers (e.g. ones with 1.2mm nozzles, etc) but this should be enough for most typical printers, while still using most of the bed to get highest accuracy.

// WARNING: Calibration strip length will be optimized to measure no more than this amount of skew between axes.  Set to as small as possible maximize the distance being measured accross your bed, but this should be no smaller than the maximum physical skew size possible.  If you are confident your printer is pretty square, feel free to drop this lower.  If you go too small on this value, there may not be enough measurement marks available on the XY bisector strip needed in order to read the vernier scale, so you'll have re-Customize setting this larger.
maximumSkew = 6;

// polyhole cylinder fitment method: http://hydraraptor.blogspot.com/2011/02/polyholes.html
module polyhole(h, d) {
    n = max(round(2 * d), 3);
    rotate([0, 0, 180])
    cylinder(h = h, r = (d / 2) / cos(180 / n), $fn = n);
}
bisectorLength = pow(pow(bedX - (maximumSkew-1), 2) + pow(bedY - (maximumSkew-1), 2), 1 / 2) - 2 * pow(2, 1 / 2) * 4 * extrusionWidth;

// output length of calibration strip to console during compile (for sanity check)
echo("bisectorLength", bisectorLength);

module calibrationStrip() {
    difference() {
        union() {
            // main strip
            translate([(filamentDiameter + 4 * extrusionWidth) / 2, 0, 0])
                cube([bisectorLength - (filamentDiameter + 4 * extrusionWidth) / 2, stripWidth, stripHeight]);
            translate([(4 * extrusionWidth + filamentDiameter) / 2, stripWidth / 2, 0])
                cylinder(d = filamentDiameter + extrusionWidth * 6, h = stripHeight);
        }
        translate([(4 * extrusionWidth + filamentDiameter) / 2, stripWidth / 2, 0])
            polyhole(stripHeight, filamentDiameter);
    }

    // alignment pins (now just a single one used for visual confirmation of filament method)
    for (i = [0])
        translate([originAlignmentSpacing * extrusionWidth * (i) + 3 * extrusionWidth + filamentDiameter, 0, stripHeight])
    cube([2 * extrusionWidth, stripWidth, 10 * layerHeight]);
    // abandoned alignment pin method that generated interlocking pins that would snap together, but it resulted in slight offsets - may revisit
    //for(i=[(generateOrthogonalBisector ? 1 : 0):4])
    //    translate([originAlignmentSpacing*extrusionWidth*(i)-(generateOrthogonalBisector ? extrusionWidth : 0),0,stripHeight])
    //        cube([extrusionWidth,stripWidth,3*layerHeight]);

    // center measure
    translate([bisectorLength - (20 + 2 * (maximumSkew-1)) / 2 - extrusionWidth - extrusionWidth / 2, -extrusionWidth / 2, stripHeight])
        cube([extrusionWidth, stripWidth + extrusionWidth, 8 * layerHeight]);

    // major measures
    for (i = [0: (10 + (generateOrthogonalBisector ? 0 : (maximumSkew-1))) / 5])
        translate([bisectorLength - (20 + 2 * (maximumSkew-1)) / 2 - extrusionWidth, 0, 0]) {
            translate([(generateOrthogonalBisector ? i * 0.9 * scaleSpacing * 5 : i * scaleSpacing * 5) - extrusionWidth / 2, 0, stripHeight])
                cube([extrusionWidth, stripWidth, 6 * layerHeight]);
            mirror([1, 0, 0]) // I first tried to nest a for loop to generate the other half of measures (and minor measures) but it didn't work so just copy/paste/mirror made quick work of it (in case it was an OpenSCAD issue) :)
                translate([(generateOrthogonalBisector ? i * 0.9 * scaleSpacing * 5 : i * scaleSpacing * 5) - extrusionWidth / 2, 0, stripHeight])
                    cube([extrusionWidth, stripWidth, 6 * layerHeight]);
        }

    // minor measures
    for (i = [0: (10 + (generateOrthogonalBisector ? 0 : (maximumSkew-1)))])
        translate([bisectorLength - (20 + 2 * (maximumSkew-1)) / 2 - extrusionWidth, 0, 0]) {
            translate([(generateOrthogonalBisector ? i * 0.9 * scaleSpacing : i * scaleSpacing) - extrusionWidth / 2, (generateOrthogonalBisector ? extrusionWidth : 0), stripHeight])
                cube([extrusionWidth, stripWidth - extrusionWidth, 4 * layerHeight]);
            mirror([1, 0, 0]) // ibid
                translate([(generateOrthogonalBisector ? i * 0.9 * scaleSpacing : i * scaleSpacing) - extrusionWidth / 2, (generateOrthogonalBisector ? extrusionWidth : 0), stripHeight])
                    cube([extrusionWidth, stripWidth - extrusionWidth, 4 * layerHeight]);
        }
}

rotate((generateOrthogonalBisector ? -1 : 1) * atan(bedY / bedX)) calibrationStrip(); // rotate model to correct angle since most slicers won't auto-center/align correctly for models longer than longest X or Y axis
```


[User]
I'd like a parametric OpenSCAD design for a Christmas present ornament. It should have a boxy main body with a hollowed-out center and a bow tie on top.

Here are the specifics:

*   **Main Body:** The main part should be a cube, but with a hollowed-out inner cube, so it looks like a box frame. It should also have a raised cross shape across the front - basically like ribbon on the sides of a present. I'd like to add polka dot spheres on the faces of the box.
*   **Bow Tie:** The bow tie should be made of a circle with a cylindrical hole in the middle, and two loops on either side. The loops should be created using a hollowed-out sphere shape, with a cylinder cutout. They should be connected to the main middle part of the bow tie.
*   **Customization:** I need these parameters to be adjustable:
    *   Overall size of the ornament (affects the entire design proportionally).
    *   Render quality for preview or production (affects `$fn`).
    *   Option to render only the main present, the main part of the bow, one of the loops, or a full assembled view (all of the parts together).

I'm hoping this can be created in a modular and parametric way, like the previous example, so I can easily make modifications later and render the parts I need. I don't need any special libraries, just the standard OpenSCAD language.

[Assistant]
LB-christmas_ornament_2.scad:
```
// The following paramters can be changed in customizer

//Begin Customizer

//Use draft to preview / production to print
Render_Quality=30; // [30:Draft, 60:Production]

//Approximate size of present with bow tie
Project_Size=75; // [75:150]

//Choose which parts to render *if the assembled view is printed then the bow tie might droop without modifications*
parts_to_render=5; //[1: Main Present, 2: Main hole of bow tie, 3: Loop of bow tie, 4: 2nd loop of bow tie, 5:Assembled view]

// End Customizer

//
//The following parameters cannot be changed in customizer

  $fn=Render_Quality;
  rotate ([0,0,45])
    scale ([Project_Size/75,Project_Size/75,Project_Size/75]){
      if (parts_to_render==1){  // present box
            box ();
      }
      if (parts_to_render==2) { // main hole of bow tie
          hole();
      }
      if (parts_to_render==3) { // first loop of bow tie
         loop1();
      }
      if (parts_to_render==4) { // second loop of bow tie
          loop2();
      }
      if (parts_to_render==5) { // assembled view
          box();
       rotate ([90,0,0]){
       translate ([0,33,0]){
          hole();
       }
   }
        rotate([90,-30,0]){
	    translate ([35,22,0]){
                loop1();
        }
    }
    rotate ([90,30,0]){
   translate ([-35,22,0]){
                loop2();
   }
   }

      }
  }

    module box () {
          difference(){

	             cube ([50,50,50], center=true);
	             cube ([35,35,35], center=true);
	                }
			 // main present hollowed out

	                translate ([0,0,.4])
	             cube ([51,16,50], center=true );
	                // horziontal tie

	                translate([0,0,.45])
	            cube ([16,51,50], center=true);             				// vertical tie finish of the box shape

	for (i=[0:2:2])
	     {
	        for (u=[0:1:2])
	     {
	            translate ([(i*17)-17,25,(u*17)-15])
	            scale ([1,.2,1])
	          sphere(r=4);
	     }
	     }
	        // side one of the polka dots
	   for (i=[0:2:2])
	    {
	        for (u=[0:1:2])
	    {
	            translate ([-25,(i*17)-18,(u*17)-17])
	            scale ([.2,1,1])
	        sphere(r=4);
	    }
	    }
	           // second side of polka dots
	  for (i=[0:2:2])
	    {
	        for (u=[0:1:2])
	    {
	            translate ([(i*17)-17,-25,(u*17)-15])
	            scale ([1,.2,1])
	         sphere(r=4);
	    }
	    }
	            //third side of polka dots
	  for (i=[0:2:2])
	    {
	        for (u=[0:1:2])
	    {
	            translate ([25,(i*17)-18,(u*17)-17])
	            scale ([.2,1,1])
	        sphere(r=4);
	    }
	    }
	            // fourth side of polka dots
	  for (i=[0:1:1])
	     {
	        for (u=[0:1:1])
	    {
	            translate ([(i*30)-13,(u*30)-15,25])
	            scale ([1,1,.2])
	         sphere(r=4);
	    }
	    }
    }
	         //polka dots on top of the box
   module hole(){

              difference (){
	             scale ([.75,.75,.66])
	          sphere (d=20,center=true);
	          cylinder(d=6,h=40, center=true);

         }
	         // circle in the middle with hole for traditional wire hook
    }
	module loop1() {
          difference (){
	            scale([1.4,1.1,1])
	          sphere (d=20,center=true);
	             scale ([1.4,1.1,5])
	         cylinder (h=10, r=5.4, center=true);}
	  	       // created hollow loop
         }

  module loop2() {
           difference (){
	            scale([1.4,1.1,1])
	         sphere (d=20,center=true);
	            scale ([1.4,1.1,5])
	        cylinder (h=15, r=5.4,center=true);
	       }
       }
	         //finish of the bow tie

```


[User]
I'm looking to create a parametric air scoop for a race car, similar to the one I have a design for, but I'd like to have it generated as an OpenSCAD design. It's meant to be connected to a flexible duct and direct airflow to the driver, so a smooth interior surface is important.

The basic shape is a bent tube. I have a few parameters that define the scoop and I would like to be able to change those. I’d like the following parameters to be modifiable:

*   `dia`: The outer diameter of the main tube.
*   `wall`: The wall thickness of the tube.
*   `fn`: The number of facets for curves.
*   `scoop`: The length of the initial straight section of the scoop.
*   `scooptract`: A multiplier used to increase the diameter at the end of the first section of the scoop before the bend.
*   `outlet`: The length of the straight section after the bend.
*   `mnthole`: The diameter of mounting holes.
*   `has_support`: A boolean to include or exclude a support structure.
*   `supwall`: The thickness of the support walls.

The design should incorporate a smooth transition between the two straight sections via a curved bend, and it should be hollow on the inside to allow airflow. I would like to have two mounting holes. These should be cylindrical and extend through the scoop body. If `has_support` is true, include a support structure that consists of a series of thin walls to provide support to the overhanging sections during printing.

I am not familiar with all the nuances of OpenSCAD, so I would appreciate you taking care of the details. I'm not looking to use any external libraries right now, either, so let's stick with only the built-in functions in OpenSCAD for now.

[Assistant]
airscoop.scad:
```
//
//  fresh air scoop for race car
//
//  design by egil kvaleberg, 1 august 2016
//

// outer diameter
dia = 58.0;
wall = 1.5;
fn=60;
// length of scoop part
scoop = 20.0;
scooptract = 1.3;
outlet = 20.0;
mnthole = 6.5;

// should support be added
has_support = 0; // [0, 1]
supwall = 0.7;

d = 1*0.1;

module bend(len1,len2,dia,cdia) {
    rotate([90,0,0]) cylinder(d1=dia, d2=dia*scooptract, h=len1, $fn=fn);
    intersection() {
        translate([cdia, 0, 0]) rotate_extrude(convexity=2,$fn=fn) translate([cdia, 0, 0]) circle(d=dia,$fn=fn);
        translate([-cdia/2-d,-d,-cdia/2]) cube([cdia*1.5+2*d,cdia*1.5+2*d,cdia]);
    }
    translate([cdia,cdia,0]) rotate([90,0,90]) cylinder(d=dia, h=len2, $fn=fn);
}

module m(dy) {
    translate([0,dy,0]) rotate([0,90,0]) {
        cylinder(d=mnthole, h=dia*0.8, $fn=15);
        cylinder(d=2*mnthole, h=dia*0.56, $fn=15);
    }
}

difference () {
    union() {
        bend(scoop, outlet, dia, dia);
        translate([dia*0.4,-scoop,-dia*0.3/2]) cube([dia*0.22,scoop+dia*0.6,dia*0.3]);

        // support
        if (has_support) {
            for (dz = [-dia*0.32:5:dia*0.32])
    translate([dia*0.8,-scoop,dz]) cube([dia*0.2+outlet,scoop+dia*0.8,supwall]);
            translate([dia*0.9+outlet/2,-scoop,-dia*0.32]) cube([supwall,dia*0.45+outlet,2*dia*0.32]);
            translate([dia*0.7,-scoop,-dia*0.32]) cube([dia*0.3+outlet,supwall,2*dia*0.32]);
        }
    }
    union() {
        color("red") bend(scoop+d, outlet+d, dia-2*wall, dia);
        m(-scoop/2);
        m(dia*0.1);
    }
}

```


[User]
Okay, I'm looking to create a fully customizable box for a project, and I want to be able to control pretty much every aspect of its size and shape. I need a parametric OpenSCAD design for this.

Specifically, I need to be able to set the following parameters:

*   **Overall Dimensions:**  I need to specify the box's width, length, and height. I need the internal dimensions to adjust accordingly based on wall thickness.
*   **Thickness:** I need to define the thickness of the box's walls and the bottom.
*   **Lid/Top:** The box should have a separate lid or top piece. I need to control the height of this top piece and also set a tolerance value between the top and the bottom part.
*   **Text:** I want to add three lines of text to the top of the box, and I need to control the text size. This text is to be engraved into the top.

So, to summarize, I need the following parameters to be adjustable: `width`, `length`, `heigth`, `bottom` thickness, `wall` thickness, `top_heigth`, `tolerance` between the top and bottom, three lines of text (e.g. `text_box1`, `text_box2`, `text_box3`), and the `text_size`. The units should all be in millimeters.

I'm thinking the design should be made in such a way that the lid sits on top of the base box, with a slight tolerance. I'd prefer to have the text on one side of the lid only for this design.

I don't have any existing code or files I can provide for this project. Can you generate the full set of OpenSCAD files needed to make this design? I'd really appreciate it. Thanks!

[Assistant]
Full_customize_box_V1.scad:
```
//Choose width of the box
width=60; //[10:1:300]
//Choose length of the box
length=60; //[10:1:300]
//Choose heigth of the box
heigth=20; //[10:.5:300]
//Choose bottom thikness of the box
bottom=2; // [1:1:6]
//Choose the wall thickness of the box
wall=4; //[1:..5:6]
//Choose the height of the top
top_heigth=3;//[1:.5:150]
//Choose the tolerance between top and bottom part
tolerance=.6; //[0:.05:1]

    // Enter your text Line 1
    text_box1 = "Line 1";
    // Enter your text Line 1
    text_box2 = "Line 2";
    // Enter your text Line 1
    text_box3= "Line 3";
    // Enter text size
    text_size= 3;

difference(){
//difference outer shell
difference(){
//OUTER SHELL
  cube([width,length,heigth]);
translate([wall,wall,bottom])
cube ([width-2*wall,length-2*wall,heigth]);
}

difference () {
//INNER SHELL
translate([0,0, heigth-top_heigth])
cube([width, length, top_heigth]);
translate([wall/2,wall/2, heigth-top_heigth])
cube([width-(wall), length-wall, top_heigth]);
}
}
//TOP
difference () {

translate([width+10,0, 0])
cube([width, length, bottom+top_heigth]);
translate([width+10+(wall/2)-tolerance/2,(wall/2)-tolerance/2,bottom])
cube([width-wall+tolerance, length-wall + tolerance, top_heigth]);
//TEXT DIFFERENCE

font1 = "Archivo Black"; // here you can select other font type

translate ([width*1.5+10,length/2-(text_size/2),heigth]) {
rotate([0,180,0])
linear_extrude(height = 60) {
text(text_box2, font = font1, size = text_size, halign="center",  direction = "ltr", spacing = 1 );
    ;
}}
translate ([width*1.5+10,length/2+(text_size/2)*2,heigth]) {
rotate([0,180,0])
linear_extrude(height = 60) {
text(text_box1, font = font1, size = text_size, halign="center",  direction = "ltr", spacing = 1 );
    ;
}}
translate ([width*1.5+10,length/2-(text_size*2),heigth]) {
rotate([0,180,0])
linear_extrude(height = 60) {
text(text_box3, font = font1, size = text_size, halign="center",  direction = "ltr", spacing = 1 );
    ;
}}

}
//}

//text difference end
//}
//}
```


[User]
Hey, I'm looking to get some help designing a parametric cannon in OpenSCAD. I've seen a few examples, and I'm aiming for something that has a similar level of customizability, but I need to be able to adjust a number of things using parameters. The cannon should have a barrel made of several segments with different diameters and lengths, wheels, and a carriage-like body.

For the barrel, I need to define the diameter and length of each segment, and be able to control the barrel hole diameter and depth. For the wheels, I'd like to control the diameter, thickness, hub diameter, number of spokes and their offset, and the overall spoke width. I'd also need to control the fragments used to render the cylinders, in case I want a lower poly model. The cannon body needs to have a main width, side thickness, width of the ground contact points and their thickness, as well as a width and height for the cannon support structure and it's angled portion. There needs to be parameters for the wheel mounting points, as well as the cannon to body connection. It needs to also have clearance parameters.

Could you generate the necessary .scad files for the cannon, cannon body, and wheels as separate modules? The main assembly module should include the individual parts with the proper positioning. I'm not sure if it will help but some useful parameters could be:

**Wheel Parameters:**

*   `wheelDiameter`: Diameter of the wheel.
*   `wheelThickness`: Thickness of the wheel.
*   `wheelHubDiameter`: Diameter of the wheel's central hub.
*   `wheelHubDiameterClearance`: Clearance between the hub and axle.
*   `numberOfSpokes`: Number of spokes in the wheel.
*   `spokeOffset`: Offset of the spokes from the wheel's edge and hub.
*   `spokeMaxWidth`: Maximum width of the spoke opening.
*   `wheelCylinderFragments`: Number of fragments for the wheel's cylinder.

**Cannon Barrel Parameters:**

*   `D1a`, `D1b`, `L1`: Diameter and Length for Barrel Segment 1.
*   `D2a`, `D2b`, `L2`: Diameter and Length for Barrel Segment 2.
*   `D3a`, `D3b`, `L3`: Diameter and Length for Barrel Segment 3.
*   `D4a`, `D4b`, `L4`: Diameter and Length for Barrel Segment 4.
*   `D5a`, `D5b`, `L5`: Diameter and Length for Barrel Segment 5.
*   `D6a`, `D6b`, `L6`: Diameter and Length for Barrel Segment 6.
*   `D7a`, `D7b`, `L7`: Diameter and Length for Barrel Segment 7.
* `cannonMountHoleDiameter`: Diameter of the pin connecting the cannon to the body.
* `cannonMountHoleDiameterClearance`: Clearance for the mounting pin.
*   `BarrelDiameter`: Diameter of the barrel bore.
*   `BarrelHoleLength`: Length of the barrel bore.
*   `cannonCylinderFragments`: Number of fragments for the cannon's cylinders.

**Cannon Body Parameters:**

*   `wheelShoulderDiameter`: Diameter of the wheel shoulder.
*   `wheelShoulderThickness`: Thickness of the wheel shoulder.
*   `CannonBodyWidth`: Overall width of the cannon body.
*   `CannonBodyInternalWidth`: Internal width of the cannon body.
*   `CannonBodyOffset`: Thickness of the cannon body sides.
*   `CannonWheelOffset`: How much the wheel is offset from the edge of the cannon body.
*   `baseWidth`: Width of the base of the cannon body.
*   `baseThickness`: Thickness of the base of the cannon body.
*   `cannonSupportWidth`: Width of the cannon body's support.
*   `cannonSupportHeight`: Height of the cannon body's support.
*   `cannonBodyAngleLength`: Length of the angled portion of the cannon body.

I don't need any libraries for this, just vanilla OpenSCAD modules. Could you also include a parameter to select which part should be rendered (the whole assembly, the body, the wheel, or just the cannon)?

Thanks so much!

[Assistant]
Cannon.scad:
```
/***********************************************************************
Name ......... : Cannon.scad
Description....: Cannon
Author ....... : Garrett Melenka
Version ...... : V1.0 2016/11/04
Licence ...... : GPL
***********************************************************************/

partSelect = 1; //[1:Cannon Assembly, 2:Cannon Body,  3:Cannon Wheel, 4:Cannon]

//*********************************************************************
//Wheel Dimensions
//*********************************************************************
//Wheel Diameter
wheelDiameter = 76.2;
//Wheel Thickness
wheelThickness = 6.35;
//Internal Wheel Hub Diameter
wheelHubDiameter = 6.35;
//Clearance so wheel rotates
wheelHubDiameterClearance = 0.2;
//Number of Wheel spokes
numberOfSpokes = 15;
//Offset of wheel spokes from outer and inner hubs
spokeOffset = 3.175;
//Maximum width of the spoke opening
spokeMaxWidth = 10;

//Number of fragements for outer wheel circle. Reduce to 12 for a low poly wheel
wheelCylinderFragments = 50;

//**********************************************************************
//Cannon Dimensions
//**********************************************************************
//Barrel Segment 1 Diameter 1
D1a = 19.05;
//Barrel Segment 1 Diameter 2
D1b = 15.875;
//Barrel Segment 1 Length
L1 = 6.35;

//Barrel Segment 2 Diameter 1
D2a = D1b;
//Barrel Segment 2 Diameter 2
D2b = 20.995;
//Barrel Segment 2 Length
L2 = 50.4;

//Barrel Segment 3 Diameter 1
D3a = 22;
//Barrel Segment 3 Diameter 2
D3b = 22;
//Barrel Segment 3 Length
L3 = 3;

//Barrel Segment 4 Diameter 1
D4a = 20.995;
//Barrel Segment 4 Diameter 2
D4b = 20.995;
//Barrel Segment 4 Length
L4 = 19.05;
//Barrel Segment 5 Diameter 1
D5a = 22;
//Barrel Segment 5 Diameter 2
D5b = 22;
 //Barrel Segment 5 Length
L5 = 3;

//Barrel Segment 6 Diameter 1
D6a = 20.995;
//Barrel Segment 6 Diameter 2
D6b = 20.995;
//Barrel Segment 6 Length
L6 = 50.4;
//Barrel Segment 7 Diameter 1
D7a = 15.875;
//Barrel Segment 7 Diameter 2
D7b = 15.875;
//Barrel Segment 7 Length
L7 = 12.7;

diameters = [D1a,D1b,D2a,D2b,D3a,D3b, D4a,D4b,D5a,D5b,D6a,D6b, D7a,D7b];

//Diameter of pin to connect Cannon to Cannon Body
cannonMountHoleDiameter = 6.35;
//Clearance for mounting pin
cannonMountHoleDiameterClearance = 0.5;
//Diamter of barrel hole
BarrelDiameter = 6.0;
BarrelHoleLength = L1+L2;
//Number of fragments to make cannon cylinder. Use 6 for a low poly version
cannonCylinderFragments = 100;

//***********************************************************************
//Cannon Body Dimensions
//***********************************************************************
//Diameter of wheel shoulder
wheelShoulderDiameter = 12.7;
//Thickness of wheel shoulder
wheelShoulderThickness = 6.35;
//Overall width of cannon body
CannonBodyWidth = 38.1;
//Internal width of body
CannonBodyInternalWidth = max(diameters) + 5;
//Thickness of cannon body sides
CannonBodyOffset = 3.175;

CannonWheelOffset = 3.175;
//Width of cannon body which contacts the ground
baseWidth = 19.05;
//Thickness of cannon body that contacts the ground
baseThickness = 12.7;
//Width of cannon body at the cannon support
cannonSupportWidth = 28.575;
//Hight of cannon body at the cannon support
cannonSupportHeight = 25.4;
//Length of the angular portion of cannon body
cannonBodyAngleLength = 63.5;

maxHeight = cannonSupportHeight + wheelDiameter*0.5 - CannonWheelOffset;

module CannonAssembly()
{

    rotate([90,0,0])
    {

    CannonBody();
    }

    translate([-(cannonBodyAngleLength+cannonSupportWidth*0.5), CannonBodyWidth*0.5+wheelThickness*0.5 + wheelShoulderThickness, wheelDiameter*0.5+CannonWheelOffset]){
    rotate([90,0,0])
    {

    CannonWheel();
    }
    }

    translate([-(cannonBodyAngleLength+cannonSupportWidth*0.5), -(CannonBodyWidth*0.5+wheelThickness*0.5 + wheelShoulderThickness), wheelDiameter*0.5+CannonWheelOffset]){
    rotate([90,0,0])
    {

    CannonWheel();
    }
    }

    translate([-(L1+L2+L3+L4*0.5)-(cannonBodyAngleLength+cannonSupportWidth*0.5),0,maxHeight-cannonMountHoleDiameter*0.5*1.5]){

    rotate([0,90,0])
    {
    rotate([0,0,90]){
    Cannon();
    }
    }
    }
}

module CannonBody()
{

    difference()
    {

    linear_extrude(height = CannonBodyWidth, center = true){
    polygon(points = [[0,0], [baseWidth,0], [baseWidth, baseThickness], [0,baseThickness], [-cannonBodyAngleLength,maxHeight], [-(cannonBodyAngleLength+cannonSupportWidth), maxHeight], [-(cannonBodyAngleLength+cannonSupportWidth), wheelDiameter*0.5-CannonWheelOffset], [-cannonBodyAngleLength, wheelDiameter*0.5-CannonWheelOffset]]);
    }

    linear_extrude(height = CannonBodyInternalWidth, center = true){
    polygon(points = [[0,CannonBodyOffset], [baseWidth,0+CannonBodyOffset], [baseWidth, baseThickness+CannonBodyOffset], [0,baseThickness+CannonBodyOffset], [-cannonBodyAngleLength,maxHeight+CannonBodyOffset], [-(cannonBodyAngleLength+cannonSupportWidth), maxHeight+CannonBodyOffset], [-(cannonBodyAngleLength+cannonSupportWidth), wheelDiameter*0.5-CannonWheelOffset+CannonBodyOffset], [-cannonBodyAngleLength, wheelDiameter*0.5-CannonWheelOffset+CannonBodyOffset]]);
    }

    //echo(wheelDiameter*0.5-CannonWheelOffset+CannonBodyOffset);

    translate([-(cannonBodyAngleLength+cannonSupportWidth*0.5), maxHeight-cannonMountHoleDiameter*0.5*1.5, 0])
    {

    cylinder(r = cannonMountHoleDiameter*0.5 + cannonMountHoleDiameterClearance, h = CannonBodyWidth+5, center = true);
    }

    }

    //Wheel Hubs
    translate([-(cannonBodyAngleLength+cannonSupportWidth*0.5), wheelDiameter*0.5+CannonWheelOffset, CannonBodyWidth*0.5+CannonBodyOffset*0.5]){
    cylinder(r = wheelShoulderDiameter*0.5, h = wheelShoulderThickness, center = true);
    }

    translate([-(cannonBodyAngleLength+cannonSupportWidth*0.5), wheelDiameter*0.5+CannonWheelOffset, CannonBodyWidth*0.5+CannonBodyOffset*0.5+ wheelShoulderThickness]){
    cylinder(r = wheelHubDiameter*0.5, h = wheelThickness, center = true);
    }

    translate([-(cannonBodyAngleLength+cannonSupportWidth*0.5), wheelDiameter*0.5+CannonWheelOffset, -(CannonBodyWidth*0.5+CannonBodyOffset*0.5)]){
    cylinder(r = wheelShoulderDiameter*0.5, h = wheelShoulderThickness, center = true);
    }

    translate([-(cannonBodyAngleLength+cannonSupportWidth*0.5), wheelDiameter*0.5+CannonWheelOffset, -(CannonBodyWidth*0.5+CannonBodyOffset*0.5+ wheelShoulderThickness)]){
    cylinder(r = wheelHubDiameter*0.5, h = wheelThickness, center = true);
    }

}

//Cannon Wheel Module
module CannonWheel()
{

    difference(){
    cylinder(r = wheelDiameter*0.5, h= wheelThickness, center = true, $fn = wheelCylinderFragments);

    cylinder(r = wheelHubDiameter*0.5+wheelHubDiameterClearance, h=wheelThickness+2, center = true, $fn = 100);

    for(i=[1:1:numberOfSpokes])
    {
      rotate([0,0, (360/numberOfSpokes)*i])
        {
        linear_extrude(height = wheelThickness+2, center = true){
            polygon(points = [[0, wheelThickness*0.5+spokeOffset], [spokeMaxWidth*0.5,wheelDiameter*0.5-spokeOffset], [-spokeMaxWidth*0.5,wheelDiameter*0.5-spokeOffset]]);
    }
    }

    }

}
}

//Cannon Module
module Cannon()
{

    difference()
    {
    union()
    {
    cylinder(r1=D1a*0.5, r2=D1b*0.5, h=L1, center = false, $fn = cannonCylinderFragments);

    translate([0,0,L1]){
    cylinder(r1=D2a*0.5, r2 = D2b*0.5, h = L2, center = false, $fn = cannonCylinderFragments);
    }

    translate([0,0,L1 + L2]){
    cylinder(r1=D3a*0.5, r2=D3b*0.5, h = L3, center = false, $fn = cannonCylinderFragments);
    }

    translate([0,0,L1 + L2 + L3]){
    cylinder(r1=D4a*0.5,r2=D4b*0.5, h = L4, center = false, $fn = cannonCylinderFragments);
    }

    translate([0,0,L1 + L2 + L3 + L4]){
    cylinder(r1=D5a*0.5,r2=D5b*0.5, h = L5, center = false, $fn = cannonCylinderFragments);
    }

    translate([0,0,L1 + L2 + L3 + L4 + L5]){
    cylinder(r1=D6a*0.5,r2=D6b*0.5, h = L6, center = false, $fn = cannonCylinderFragments);
    }

    translate([0,0,L1 + L2 + L3 + L4 + L5 + L6]){
    cylinder(r1=D7a*0.5,r2=D7b*0.5, h = L7, center = false, $fn = cannonCylinderFragments);
    }
    }

    holeLength = max(diameters);

    translate([0,0,L1+L2+L3+L4*0.5])
    {
    rotate([0,90,0]){
    cylinder(r = cannonMountHoleDiameter*0.5, h = holeLength, center = true, $fn = 100);
    }
    }

    cylinder(r = BarrelDiameter*0.5, h = BarrelHoleLength, center = false, $fn = cannonCylinderFragments);

    }

}

//***********************************************************************
//Display Cannon Components
//***********************************************************************

if (partSelect == 1)
{
    CannonAssembly();
}

if (partSelect == 2)
{
    rotate([90,0,0])
    {

    CannonBody();
    }
}

if (partSelect == 3)
{
    CannonWheel();
}

if (partSelect == 4)
{
    Cannon();
}
```


[User]
Okay, I'm looking to create a customizable fidget spinner using OpenSCAD, and I've got some specific ideas on how I'd like it to work. I really want to be able to tweak this for different bearing sizes, so that's my main priority.

Here's the gist: I need a spinner with a central bearing and a number of outer bearings, all held in place by arms. The number of arms (and thus, outer bearings) should be adjustable. So should the thickness of the material around the bearings, and the length of those arms. I also need some control over how the arms are shaped.

Here's a more detailed breakdown of what I need for parameters:

*   **General:**
    *   `numberOfLegs`: The number of arms, and outer bearings (e.g., 3, 4, 5...). 0 should just create the center holder.
    *   `hThick`: The thickness of the walls around the bearings.
    *   `legLength`: The distance from the center bearing to the center of each outside bearing.
    *   `curveScale`: A scaling factor that affects how much the sides of the arms are carved out, to make them less boxy.

*   **Bearing Dimensions:**
    *   `outsideBearingRadius`: The radius of the outer bearings.
    *   `insideBearingRadius`: The radius of the center bearing.
    *   `bearingHeight`: The height of the bearings (assuming they are all the same for now).

*   **Adjustments:**
    *   `hPlay`: The amount added to the bearing radii to allow for a better fit (tolerance).
    *   `vPlay`: The amount to add to the bearing height for tolerance.
    *   `roundness`: This controls the bevel on the edges of the arms.
    *   `curveOffset`: This shifts the cutouts on the sides of the arms in or out.
    *   `curveSizeAdjust`: This controls the size of the cutouts on the sides of the arms.

I'd really like the code to use some functions for rounded cylinders and inversely rounded cylinders, using the `hull()` function as in the example I provided for the rounded ones. This is important for how the design looks.

I also want a parameter `centerHolder` to disable/enable the center holder, just in case I want to test fit my bearing without the rest.

I don't think I need any other libraries besides the standard OpenSCAD stuff. Could you generate the OpenSCAD files for this? I don't really need any comments in the code but I do need for the parameters to be included so I can tweak everything easily.

[Assistant]
bearingSpinner_v3.scad:
```
/* [General parameters] */
// 0 will just create the center holder, which can be useful for testing the fit for your bearing!
numberOfLegs = 3; // [6]
// Thickness of the walls around the bearings
hThick = 2; // [0.5:.25:5]
// Space from the center bearing to the center of each outside bearing
legLength = 30; // [80]
// Sketchy way of carving out the side of the fidget toy
curveScale = 1.5; // [0:0.1:2]

/* [Bearing dimensions] */
// Radius of the outside bearing
outsideBearingRadius = 11; // [5:30]
// Radius of the center bearing
insideBearingRadius = 11; // [5:30]
// For now, just a uniform height is given. If you're using different size bearings, put the larger height of the two.
bearingHeight = 7; // [3:0.5:15]

/* [Adjustments] */
// Amount added to the bearing radii for allowing a better fit
hPlay = 0.1; // [0:0.1:1]
// Will add additional height
vPlay = 0; // [0:0.1:1]
// Affects the beveled edge
roundness = 1.5; // [0:0.1:2.5]
// Moves the 'cutouts' farther out with positive values, closer in with negatives
curveOffset = 0; // [-5:0.1:5]
// Adjusts the size of the 'cutouts', positive increasing, negative decreasing
curveSizeAdjust = 0; // [-5:0.1:5]

/* [Hidden] */
// Anything below will not be visble in the customizer.
$fa = 0.5; // lower = finer large radius
$fs = 0.75; // lower = finer small radius

// Extraneous
buffer = 0.01; // Internal variable that I use for preview to avoid 0-thickness walls

// Derived/utility
oHeight = bearingHeight + vPlay; // Height with adjustments
oRadius = outsideBearingRadius + hPlay; // Bearing radius with adjustments
iHeight = bearingHeight + vPlay;
iRadius = insideBearingRadius + hPlay;
curveRadius = min((legLength - iRadius - oRadius), max(iRadius, oRadius)) * curveScale + curveSizeAdjust;
curveOffsetX = (legLength - oRadius + iRadius)/2; // midpoint between the two bearings
curveOffsetY = ((iRadius + oRadius)/2 + hThick) * curveScale + curveOffset;
legAngle = 360/numberOfLegs;

// Future versions
point = 0;
bInnerR = 4 - hPlay; // inside radius
centerHolder = true;
insideBearingHeight = 7;

// Main object
bearingSpinner();

module bearingSpinner() {
  difference() {
    union() {
      for (i = [0:numberOfLegs-1]) {
        difference() {
          union() {
            hull() { // External
              rotate([0,0,i*(legAngle)]) translate([legLength,0,0])
                rCylinder(r=oRadius+hThick, h=oHeight); // leg
              rCylinder(r=iRadius+hThick, h=iHeight); // inside
            }
            if (point != 0) { // Point generation TODO
              rotate([0,0,i*(legAngle)]) translate([legLength+oRadius,-oRadius/2,1.5])
                cube([10,oRadius,oHeight-1.5*2]);
            }
          }
          for (j = [-1:2:1]) { // Carve out the sides
            rotate([0,0,i*(legAngle)])
              translate([curveOffsetX,curveOffsetY*j,-buffer])
                irCylinder(r=curveRadius, h=oHeight+buffer*2);

          }
          if (point != 0) {
            for (j = [-1:2:1]) { // Point generation TODO - Carve out the points
              rotate([0,0,i*(legAngle)])
                translate([legLength+oRadius+hThick/2,(oRadius-hThick+point)*j,-buffer])
                  irCylinder(r=curveRadius+point, h=oHeight+buffer*2);
            }
          }
        }
      }
    }
    for (i = [0:numberOfLegs-1]) {
      // Cut out the outside bearing slots
      rotate([0,0,i*(legAngle)]) translate([legLength,0,0])
        translate([0,0,-buffer]) cylinder(r=oRadius, h=oHeight+buffer*2);
    }
    // Cut out the center bearing
    translate([0,0,-buffer]) cylinder(r=iRadius, h=iHeight+buffer*2);

  }
}

// Rounded cylinder module
module rCylinder(r, h) {
  hull() {
    cylinder(r=r-roundness, h=h);
    translate([0,0,roundness]) cylinder(r=r, h=h-roundness*2);
  }
}
// Inverse rounded cylinder (spool shaped sort've)
module irCylinder(r, h) {
  union() {
    cylinder(r=r, h=h);
    translate([0,0,0]) cylinder(r1=r+roundness, r2=0, h=h);
    translate([0,0,0]) cylinder(r1=0, r2=r+roundness, h=h);
  }
}
//irCylinder(r=bRadius+hThick, h=oHeight);
//translate([0,(bRadius+hThick)*2,0])
//  rCylinder(r=bRadius+hThick, h=oHeight);

```


[User]
I'd like to create a custom cookie cutter generator using OpenSCAD. I want to be able to select from several different shapes: a star, a regular polygon, a circle, and a rectangle. I need to be able to adjust the dimensions of these shapes, and I also need to be able to control the thickness of the cutting edge, the width and height of a support pad at the bottom, and the total depth of the cutter.

For the shapes themselves, I need to set:

*   For stars: the outer radius, inner radius, and number of points.
*   For polygons: the radius and number of sides.
*   For circles: the radius.
*   For rectangles: the width and height.

Then, for the cutter itself, the parameters I need to control are:

*   `thickness`: The thickness of the cutting edge.
*   `pad_width`: The width of the support pad at the bottom.
*   `pad_height`: The height of the support pad.
*   `depth`: The overall height of the cookie cutter.

I need the generated code to have a user-friendly way to control these parameters, like with comments and sliders. I would also like it if the core cutter functionality was encapsulated into a module to make it easy to use with other shapes in the future if I needed to.

Could you provide the OpenSCAD code for this? I expect to have at least two `.scad` files, one to generate the shapes and one that is more of a library that contains the `templatify` module and related functions.

[Assistant]
Template_maker.scad:
```
shape = 1; //[1: star, 2: polygon, 3: circle, 4: rectangle]

// For stars, polygons and circle
radius = 20;

// For stars and polygons, 3 sided star does not work.
sides = 5;

// For stars only
inner_radius = 10;

// For rectangle
width = 20;

// For rectangle
height = 20;

/*[Adjust]*/
// Thickness of the cutting edge
thickness = 0.8;
// Width of the padding at the bottom
pad_width = 5;
// Height of the padding at the bottom
pad_height = 1;
// Height of the overall cutter
depth = 10;

/* [Hidden] */

if(shape == 1) {
    templatify(star(radius, inner_radius, sides));
}
else if(shape == 2) {
    templatify(ngon(radius, sides));
}
else if(shape == 3) {
    templatify(ngon(radius, radius * 6));
}
else if(shape == 4) {
    templatify([[0,0],[width,0],[width,height],[0,height]]);
}

function star(r_out, r_in, sides) =
    let(a = 360 / (sides*2))
    [for(i = [0:(sides*2-1)])
        let(r = i%2 ? r_out : r_in)
        [cos(a*i+a/2) * r, sin(a*i+a/2) * r]];

function ngon(r, sides) = star(r, r, sides / 2);

function circ(r) = star(r, r, 48);

function get(points, i, cp) =
    (i<0) ? points[cp+i%cp] : points[i%cp];

function dist(p) = sqrt(p[0]*p[0] + p[1]*p[1]);
function slope(p1, p2) = (p2[1]-p1[1])/(p2[0]-p1[0]);
function getderiv(p1, p2) = let(diff = p2-p1) diff / dist(diff);
function getperp(p1, p2) =
    let(deriv = getderiv(p1, p2))
    [deriv[1], -deriv[0]];

function offset(p, c, n, off) =
    let(
        pp = getperp(p, c),
        pcp = c + pp * off,
        ppp = p + pp * off,
        np = getperp(c, n),
        ncp = c + np * off,
        nnp = n + np * off,

        x1 = ppp[0], y1 = ppp[1],
        x2 = pcp[0], y2 = pcp[1],
        x3 = ncp[0], y3 = ncp[1],
        x4 = nnp[0], y4 = nnp[1],

        d = (x1-x2) * (y3-y4) - (y1-y2) * (x3-x4),
        a = (x1*y2 - y1*x2),
        b = (x3*y4 - y3*x4)
    )

    [
        (a * (x3-x4) - (x1-x2) * b) / d,
        (a * (y3-y4) - (y1-y2) * b) / d

    ];

module templatify(
    points,
    depth = depth,
    thickness = thickness,
    pad_width = pad_width,
    pad_height = pad_height,
    convexity = 4
) {
  cp = len(points);

  prev = [for(i=[0:cp-1]) get(points, i-1, cp)];
  next = [for(i=[0:cp-1]) get(points, i+1, cp)];
  cur = points;

  bord = [for(i=[0:cp-1])
       offset(prev[i], cur[i], next[i], thickness)
  ];

  pad = [for(i=[0:cp-1])
       offset(prev[i], cur[i], next[i], pad_width)
  ];

  difference() {
    union() {
        linear_extrude(height = depth, convexity=convexity)
        polygon(bord, convexity=convexity);

        linear_extrude(height = pad_height, convexity=convexity)
        polygon(pad, convexity=convexity);
    }

    translate([0, 0, -0.1])
    linear_extrude(height = depth+0.2, convexity=convexity)
    polygon(points, convexity=convexity);
  }
}

```
Template.scad:
```

// Thickness of the cutting edge
thickness = 0.8;
// Width of the padding at the bottom
pad_width = 5;
// Height of the padding at the bottom
pad_height = 1;
// Height of the overall cutter
depth = 10;

function dist(p) = sqrt(p[0]*p[0] + p[1]*p[1]);
function slope(p1, p2) = (p2[1]-p1[1])/(p2[0]-p1[0]);
function getderiv(p1, p2) = let(diff = p2-p1) diff / dist(diff);
function getperp(p1, p2) =
    let(deriv = getderiv(p1, p2))
    [deriv[1], -deriv[0]];

function offset(p, c, n, off) =
    let(
        pp = getperp(p, c),
        pcp = c + pp * off,
        ppp = p + pp * off,
        np = getperp(c, n),
        ncp = c + np * off,
        nnp = n + np * off,

        x1 = ppp[0], y1 = ppp[1],
        x2 = pcp[0], y2 = pcp[1],
        x3 = ncp[0], y3 = ncp[1],
        x4 = nnp[0], y4 = nnp[1],

        d = (x1-x2) * (y3-y4) - (y1-y2) * (x3-x4),
        a = (x1*y2 - y1*x2),
        b = (x3*y4 - y3*x4)
    )

    [
        (a * (x3-x4) - (x1-x2) * b) / d,
        (a * (y3-y4) - (y1-y2) * b) / d

    ];

//public functions

module templatify(
    points,
    depth = depth,
    thickness = thickness,
    pad_width = pad_width,
    pad_height = pad_height,
    convexity = 4
) {
  cp = len(points);

  prev = [for(i=[0:cp-1]) get(points, i-1, cp)];
  next = [for(i=[0:cp-1]) get(points, i+1, cp)];
  cur = points;

  bord = [for(i=[0:cp-1])
       offset(prev[i], cur[i], next[i], thickness)
  ];

  pad = [for(i=[0:cp-1])
       offset(prev[i], cur[i], next[i], pad_width)
  ];

  difference() {
    union() {
        linear_extrude(height = depth, convexity=convexity)
        polygon(bord, convexity=convexity);

        linear_extrude(height = pad_height, convexity=convexity)
        polygon(pad, convexity=convexity);
    }

    translate([0, 0, -0.1])
    linear_extrude(height = depth+0.2, convexity=convexity)
    polygon(points, convexity=convexity);
  }
}

function star(r_out, r_in, sides) =
    let(a = 360 / (sides*2))
    [for(i = [0:(sides*2-1)])
        let(r = i%2 ? r_out : r_in)
        [cos(a*i+a/2) * r, sin(a*i+a/2) * r]];

function ngon(r, sides) = star(r, r, sides / 2);

function circ(r) = star(r, r, 48);

function get(points, i, cp) =
    (i<0) ? points[cp+i%cp] : points[i%cp];

```


[User]
I need a parametric OpenSCAD design for a two-part casting ring. It should be similar in concept to the design I've seen in the casting_ring2.scad file. Basically, I want two halves that fit together to form a cylinder that can be filled with molding sand for casting metal. I'd like to be able to control the overall height of the assembled ring, the diameter, and the tolerance between the two halves. The wall thickness should also be adjustable, but I don't expect to change it often.

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

*   `heightOverall`: The total height of the assembled ring.
*   `diameter`: The inner diameter of the ring.
*   `tolerance`: The gap between the two halves where they join. This should be adjustable so that I can get a good fit for my printer.
*   `wallThickness`: The thickness of the ring walls. This will probably be set once and not changed.
* `fn`: The number of facets for the cylinder's circumference.

The design should create two ring halves that are mirror images of each other (although I understand that I will have to rotate one half 180 degrees after slicing). Each half should be a hollow cylinder with a stepped interior: a wider section for the main body and a smaller step at the joining face. When joined, these steps will provide a small gap for air to escape during the casting process and to compensate for printing variances and allow for a good fit.

Also, please include comments in the code explaining the different parts and parameters. Use $fn for the cylinder facet count, to improve smoothness when necessary.

[Assistant]
casting_ring2.scad:
```
// Round Casting Form by Willie Beckmann 2016
//
heightoverall=50; // height over all mm - change to your needs, not < 20
diameter=70; // diameter mm - change to your needs
//
tolerance=0.2; // change accordingly to your printer
height=heightoverall+10;
wandstaerke=3; // normaly no need to change
wandhalb=wandstaerke/2+tolerance; // do not change

// Ring1
rotate([0,180,0]) {
translate([diameter/2+5,0,-height/2]) {
        difference() {
            difference() {
                cylinder(height/2,diameter/2+wandstaerke,diameter/2+wandstaerke,$fn=60);
                cylinder(height/2+1,diameter/2,diameter/2,$fn=60);
                         }
            difference() {
                cylinder(10,diameter/2+wandstaerke,diameter/2+wandstaerke,$fn=60);
                cylinder(11,diameter/2+wandhalb,diameter/2+wandhalb,$fn=60);
                         }
                      }
                    }
            }

// Ring2
rotate([0,180,0]) {
translate([-diameter/2-5,0,-height/2]) {
        difference() {
            difference() {
                cylinder(height/2,diameter/2+wandstaerke,diameter/2+wandstaerke,$fn=60);
                cylinder(height/2+1,diameter/2,diameter/2,$fn=60);
                         }
            difference() {
                cylinder(10,diameter/2+wandhalb,diameter/2+wandhalb,$fn=60);
                cylinder(11,diameter/2,diameter/2,$fn=60);
                         }
                      }
                    }
            }
```


[User]
I want to design a customizable miniature escalator, and I need an OpenSCAD model. It should be parametric, allowing me to adjust different aspects.

The escalator will be made of chain links connected to form a loop around two pulleys. Some of these links should form the steps. There will also be a chassis to hold the pulleys in place, a crank for manual operation, and a handle. I’ll need to be able to adjust these parameters:

**Chain:**
*   `link_number`: The total number of links in the chain. This should be a multiple of `links_per_step`.
*   `links_per_step`: The number of links that form one step.
*   `links_per_pulley`:  The number of links that will be bent around each pulley. This should affect the pulley radius.
*   `alpha`: The angle of the escalator, in degrees, relative to the horizontal.
*   `chain_length_correction`: An adjustment for the overall chain length to tighten or loosen it.

**Chain Link:**
*   `length`: The overall length of each chain link.
*   `width`: The width of the chain link.
*   `breadth`:  The thickness of the chain link.
*   `joint_size`: The size of the joint connecting two links together.
*   `joint_hole_size`: The size of the hole on a link that accepts the joint from another link.
*   `wall_thickness`: The thickness of the walls of the link.
*    `cavity_depth`: The depth of the cavity that connects to the pulley
*   `cavity_breath`: The width of that cavity.

**Chassis:**
*   `chassis_thickness`: The thickness of the chassis.
*   `axis_radius`:  The radius of the axis that the pulleys rotate on.
*   `axis_length`: How far the axis extends into the pulley.
*  `crank_length`: The length of the crank.
*  `crank_thickness`: The thickness of the crank.
* `handle_length`: The length of the handle

**Tolerances and various:**
*  `tolerance`: A general tolerance for fitting parts.
* `pin_height`: The height of the pins connecting the parts.
* `pin_radius`: The radius of the pins.
* `pin_tolerance`: Tolerance for the pin holes
*   `resolution`: The resolution for large parts.
*  `resolution_small`: The resolution for small parts.

**Display:**

*   `part`: A string parameter that allows me to select which part to display, from `"all"` to  `"chain_link1"`, `"chain_link2"`, `"stepv"`, `"steph"`, `"pulley1"`, `"pulley2"`, `"chassis1"`, `"chassis2"`, `"crank"`, `"handle"`, and `"pin"`.
*  `build_plate_selector`: An integer for selecting the build plate preset or "manual" mode.
* `build_plate_manual_x`: When "manual" build plate is selected, this is the x dimension of the build plate.
* `build_plate_manual_y`: When "manual" build plate is selected, this is the y dimension of the build plate.

I'll need the following libraries for this: `pins/pins.scad` and `utils/build_plate.scad`.

Could you create the necessary OpenSCAD files for this? Thanks.

[Assistant]
escalator.scad:
```
use <pins/pins.scad>
use <utils/build_plate.scad>
// preview[view:north east, tilt:top diagonal]

/* [chain] */
// Number of chain links, should be a multiple of links per step
link_number = 30; // [15:1:50]
// How many links are connected for one step
links_per_step = 2; // [1:1:4]
// Should not be bigger than about half the link number. With more links per steps this should increase or the chain might not be able to bend enough around the pulley.
links_per_pulley = 10; // [6:1:20]
// Angle of escalator, when it derives from 45° strongly, the length or links per step should be increased or the steps will become too narrow. Otherwise it could be used as a conveyor belt without the steps.
alpha = 45; // [0:0.1:90]
// When the chain sits too tight use positive values, otherwise negative values if it is too loose
chain_length_correction = 0; // [-10:0.1:10]

/* [chain link] */
length = 12; // [10:0.1:30]
width = 20; // [10:0.1:200]
// The length should be increased alongside the breadth
breadth = 3.5; // [3:0.1:5]
// Needs to be less or equal than the hole
joint_size = 2.25; // [1.5:0.05:4]
// Should be smaller than the breadth
joint_hole_size = 2.75; // [1.5:0.05:4]
// Width should be increased when increasing this value
wall_thickness = 3; // [1:0.1:5]
// The cavity connects to the pulley, should be smaller than breadth
cavity_depth = 2.5; // [1:0.01:4]
// Should be smaller than length-2*breadth
cavity_breath = 3.5; // [2:0.01:5]

/* [chassis] */
chassis_thickness = 7.5; // [3:0.1:15]
// Radius of axis that connects the pulleys
axis_radius = 6.5; // [5:0.1:10]
// How deep the axis permeates into the pulley
axis_length = 5; // [3:0.1:20]
crank_length = 70; // [30:0.1:100]
crank_thickness = 7.5; // [5:0.1:10]
handle_length = 20; // [5:0.1:50]

/* [tolerances and various] */
// Tolerance for links and chassis
tolerance = 0.3; // [0.1:0.01:0.4]
// Height of pin connectors
pin_height = 7.5; // [0.5:0.1:15]
pin_radius = 3; // [2:0.1:5]
pin_tolerance = 0.4; // [0.2:0.01:0.6]
// Resolution of big parts
resolution = 100; // [30:1:200]
// Resolution of small parts
resolution_small = 30; // [10:1:100]

/* [display] */
// Which part to display
part = "all"; // [all:all parts,chain_link1:chain link 1,chain_link2:chain link 2,stepv:vertical step,steph:horizontal step,pulley1:pulley 1,pulley2:pulley 2,chassis1:chassis part 1,chassis2:chassis part 2,crank:crank,handle:handle,pin:pin]
// for display only, doesn't contribute to final object
build_plate_selector = 0; // [0:Replicator 2,1: Replicator,2:Thingomatic,3:Manual]
// when Build Plate Selector is set to "manual" this controls the build plate x dimension
build_plate_manual_x = 100; // [100:1:400]
// when Build Plate Selector is set to "manual" this controls the build plate y dimension
build_plate_manual_y = 100; // [100:1:400]

build_plate(build_plate_selector, build_plate_manual_x, build_plate_manual_y);

$fn = resolution;

width_s = width - 2 * wall_thickness;
joint_radius = joint_size / 2;
hole_radius = joint_hole_size / 2;

effective_length = length - breadth;
pulley_radius = links_per_pulley * effective_length / (2 * PI) - breadth / 2 + cavity_depth - tolerance;

vertical = sin(alpha) * effective_length * links_per_step + breadth * 1.5;
horizontal = cos(alpha) * effective_length * links_per_step + breadth * 1.5;

pulley_distance_x = sin(alpha) * (effective_length * (link_number - links_per_pulley) / 2 - chain_length_correction / 2);
pulley_distance_y = cos(alpha) * (effective_length * (link_number - links_per_pulley) / 2 - chain_length_correction / 2);

pulley_margin = links_per_pulley * effective_length / (2 * PI) + breadth + max(vertical, horizontal);

axis_square = axis_radius / sqrt(2);

module male(width) {
    translate([breadth / 2, tolerance, 0]) cube([breadth / 2, width - tolerance * 2, breadth]);
    translate([breadth / 2, tolerance, breadth / 2]) rotate([-90, 0, 0]) cylinder(d = breadth, h = width - tolerance * 2, $fn = resolution_small);
    translate([breadth / 2, tolerance, breadth / 2]) sphere(joint_radius, $fn = resolution_small);
    translate([breadth / 2, width - tolerance, breadth / 2]) sphere(joint_radius, $fn = resolution_small);
}

module female(width) {
    width_s = width - 2 * wall_thickness;
    difference() {
        union() {
            translate([breadth / 2, 0, 0]) cube([breadth / 2, width, breadth]);
            translate([breadth / 2, 0, breadth / 2]) rotate([-90, 0, 0]) cylinder(d = breadth, h = wall_thickness, $fn = resolution_small);
            translate([breadth / 2, width - wall_thickness, breadth / 2]) rotate([-90, 0, 0]) cylinder(d = breadth, h = wall_thickness, $fn = resolution_small);
        }
        translate([0.01, wall_thickness, -0.01]) cube([breadth + 0.01, width_s, breadth + 0.02]);
        translate([breadth / 2, wall_thickness, breadth / 2]) sphere(hole_radius, $fn = resolution_small);
        translate([breadth / 2, width - wall_thickness, breadth / 2]) sphere(hole_radius, $fn = resolution_small);
    }
}

module round_corner() {
    difference() {
        cube([breadth / 2, width + 0.02, breadth / 2], center = true);
        cube([breadth / 2 + 0.02, width_s - tolerance * 2, breadth / 2 + 0.02], center = true);
        translate([-breadth / 4, 0, breadth / 4]) rotate([-90, 0, 0]) cylinder(d = breadth, h = width + 0.04, center = true, $fn = resolution_small);
    }
}

module rounding_cylinder() {
    rotate([-90, 0, 0]) cylinder(d = breadth, h = width, $fn = resolution_small);
}

module tooth(width) {
    polyhedron(points = [
        [0, width / 8, cavity_depth],
        [0, width * 7 / 8 - wall_thickness * 2, cavity_depth],
        [-cavity_breath / 2, 0, -0.01],
        [-cavity_breath / 2, width - wall_thickness * 2, -0.01],
        [cavity_breath / 2, 0, -0.01],
        [cavity_breath / 2, width - wall_thickness * 2, -0.01]
    ], faces = [
        [0, 2, 3, 1],
        [0, 1, 5, 4],
        [2, 4, 5, 3],
        [0, 4, 2],
        [1, 3, 5]
    ]);
}

module pinhole_elevated(elevated = false) {
    if (elevated == true) {
        translate([0, 0, chassis_thickness - pin_height]) pinhole(h = pin_height, t = pin_tolerance, r = pin_radius);
    } else {
        difference() {
            translate([0, 0, chassis_thickness - 0.01]) cylinder(r = 5, h = width + wall_thickness * 2 + tolerance * 4 + 0.02);
            translate([0, 0, width + wall_thickness * 2 + tolerance * 4 + chassis_thickness - pin_height]) pinhole(h = pin_height, r = pin_radius);
        }
    }
}

module difference_or_union(diff = false) {
    if (diff) {
        difference() {
            children(0);
            for (i = [1: $children - 1]) {
                children(i);
            }
        }
    } else {
        children();
    }
}

module chain_link(connector = true) {
    difference() {
        translate([breadth - 0.01, 0, 0]) cube([length - breadth * 2 + 0.02, width, breadth * (connector ? 2 : 1)]);
        if (connector) {
            translate([breadth - 0.02, wall_thickness, breadth]) cube([length - breadth * 2 + 0.04, width_s, breadth + 0.01]);
            translate([length / 2, wall_thickness, breadth * 1.5]) sphere(hole_radius, $fn = resolution_small);
            translate([length / 2, width - wall_thickness, breadth * 1.5]) sphere(hole_radius, $fn = resolution_small);
            translate([breadth * 1.25 - 0.02, width / 2, breadth * 1.75 + 0.01]) rotate([0, 180, 0]) round_corner();
        }
        translate([length - breadth * 1.25 + 0.02, width / 2, breadth * (connector ? 1.75 : 0.75) + 0.01]) rotate([0, -90, 0]) round_corner();
        translate([length - breadth * 1.25 + 0.02, width / 2, breadth * 0.25 - 0.01]) round_corner();
        translate([length / 2, wall_thickness, 0]) tooth(width);
    }
    female(width);
    translate([length, wall_thickness, breadth]) rotate([0, 180, 0]) male(width_s);
}

module vertical_step() {
    translate([breadth - 0.01, 0, 0]) cube([vertical - breadth * 1.5 - effective_length / 2 + 0.02, width, breadth]);
    translate([vertical - effective_length / 2 - breadth / 2, 0, breadth / 2]) rounding_cylinder();
    female(width);
    difference() {
        union() {
            translate([vertical - effective_length / 2 - breadth * 0.5 - 0.01, wall_thickness + tolerance, 0]) cube([effective_length / 2 - breadth * 0.5 + 0.02, width_s - tolerance * 2, breadth]);
            translate([vertical, wall_thickness, breadth]) rotate([0, 180, 0]) male(width_s);
        }
        translate([vertical - breadth + 0.01, (width - width_s / 2 - breadth) / 2, -0.01]) cube([breadth, width_s / 2 + breadth, breadth + 0.02]);
        translate([vertical - effective_length / 2, (width - width_s / 2 - breadth) / 2 + wall_thickness, -0.01]) cube([effective_length / 2 + 0.01, width_s / 2 + breadth - 2 * wall_thickness, breadth + 0.02]);
    }
    translate([vertical, (width - width_s / 2) / 2 - breadth / 2, breadth]) rotate([0, 180, 0]) female(width_s / 2 + breadth);
}

module horizontal_step() {
    translate([breadth * 1.5 - 0.01, 0, 0]) cube([horizontal - effective_length / 2 - breadth * 2 + 0.02, width, breadth]);
    translate([breadth - 0.01, wall_thickness + tolerance, 0]) cube([breadth / 2 + 0.02, width_s - tolerance * 2, breadth]);
    translate([breadth * 1.5, 0, breadth / 2]) rounding_cylinder();
    translate([horizontal - effective_length / 2 - breadth / 2, 0, breadth / 2]) rounding_cylinder();
    translate([horizontal - effective_length / 2 - breadth / 2 - 0.01, (width - width_s / 2 - breadth) / 2 + wall_thickness + tolerance, 0]) cube([effective_length / 2 - breadth * 0.5 + 0.02, width_s / 2 + breadth - 2 * wall_thickness - tolerance * 2, breadth]);
    translate([0, wall_thickness, 0]) male(width_s);
    translate([horizontal, (width - width_s / 2 - breadth) / 2 + wall_thickness, breadth]) rotate([0, 180, 0]) male(width_s / 2 + breadth - 2 * wall_thickness);
}

module pulley(part2 = false) {
    difference() {
        union() {
            cylinder(r = pulley_radius - cavity_depth, h = width + wall_thickness * 2 + tolerance * 2);
            cylinder(r1 = pulley_radius - cavity_depth + wall_thickness, r2 = pulley_radius - cavity_depth, h = wall_thickness);
            translate([0, 0, width + wall_thickness + tolerance * 2]) cylinder(r1 = pulley_radius - cavity_depth, r2 = pulley_radius - cavity_depth + wall_thickness, h = wall_thickness);
            for (i = [0: 1: links_per_pulley - 1]) rotate([0, 0, 360 * i / links_per_pulley]) {
                translate([0, pulley_radius - cavity_depth - tolerance, width]) rotate([-90, 0, 0]) tooth(width - 2 * tolerance);
                translate([-cavity_breath / 2, 0, wall_thickness * 2 + tolerance * 2]) cube([cavity_breath, pulley_radius - cavity_depth - tolerance + 0.01, width_s - 2 * tolerance]);
            }
        }
        translate([0, 0, axis_length - 0.01 + tolerance]) rotate([180, 0, 0]) cylinder(r = axis_radius + tolerance, h = axis_length + tolerance);
        if (part2) {
            translate([0, 0, width + wall_thickness * 2 + tolerance - axis_length + 0.01]) cylinder(r = axis_radius + tolerance, h = axis_length + tolerance);
        } else {
            translate([0, 0, width + wall_thickness * 2 + tolerance * 2 - pin_height - axis_length]) pinhole(h = pin_height, t = pin_tolerance, r = pin_radius);
            translate([-axis_square - tolerance, -axis_square - tolerance, width + wall_thickness * 2 + tolerance * 2 - axis_length + 0.01]) cube([axis_square * 2 + tolerance * 2, axis_square * 2 + tolerance * 2, axis_length]);
        }
    }
}

module chassis(part2 = false) {
    p1 = [0, ((alpha > 45) ? (2 - tan(90 - alpha)) : 1) * pulley_margin];
    p2 = [pulley_distance_x + ((alpha < 45) ? (0 + tan(alpha)) : 1) * pulley_margin, pulley_distance_y + pulley_margin * 2];
    translate([pulley_distance_x + pulley_margin, pulley_distance_y + pulley_margin, chassis_thickness - 0.01]) cylinder(r = axis_radius, h = axis_length);
    difference_or_union(part2) {
        linear_extrude(height = chassis_thickness) polygon(points = [
            [0, 0], p1, p2, [pulley_distance_x + pulley_margin * 2, pulley_distance_y + pulley_margin * 2],
            [pulley_distance_x + pulley_margin * 2, 0]
        ]);
        if (part2) {
            translate([pulley_margin, pulley_margin, -0.01]) cylinder(r = axis_radius + tolerance, h = chassis_thickness + 0.02);
        } else {
            translate([pulley_margin, pulley_margin, chassis_thickness - 0.01]) cylinder(r = axis_radius, h = axis_length);
        }
        translate([6 + wall_thickness, 6 + wall_thickness, 0]) pinhole_elevated(part2);
        translate([pulley_distance_x / 2 + pulley_margin, pulley_distance_y / 2 + pulley_margin, 0]) pinhole_elevated(part2);
        translate([pulley_distance_x + pulley_margin * 2 - 6 - wall_thickness, pulley_distance_y + pulley_margin * 2 - 6 - wall_thickness, 0]) pinhole_elevated(part2);
        translate([pulley_distance_x + pulley_margin * 2 - 6 - wall_thickness, 6 + wall_thickness, 0]) pinhole_elevated(part2);
    }
}

module crank() {
    difference() {
        union() {
            translate([-axis_square, -axis_square, chassis_thickness + tolerance + crank_thickness + 8.01]) cube([axis_square * 2, axis_square * 2, axis_length]);
            cylinder(r = axis_radius, h = chassis_thickness + tolerance + crank_thickness + 8.01);
            translate([0, 0, crank_thickness + 3]) cylinder(r1 = axis_radius, r2 = axis_radius + 3, h = 5);
            translate([-axis_radius, 0, 0]) cube([axis_radius * 2, crank_length - 2 * axis_radius, crank_thickness]);
            translate([0, crank_length - axis_radius * 2, 0]) cylinder(r = axis_radius, h = crank_thickness);
        }
        translate([0, 0, chassis_thickness + tolerance + crank_thickness + axis_length - pin_height + 8]) pinhole(h = pin_height, t = pin_tolerance, r = pin_radius);
        translate([0, crank_length - axis_radius * 2, pin_height]) rotate([180, 0, 0]) pinhole(h = pin_height, t = pin_tolerance, r = pin_radius);
    }
}

module handle() {
    difference() {
        cylinder(r = axis_radius, h = handle_length + 0.01);
        translate([0, 0, handle_length - pin_height]) pinhole(h = pin_height, t = pin_tolerance, r = pin_radius);
    }
}

if (part == "all") {
    translate([pulley_radius * 2 + 5, 0, 0]) {
        chain_link();
    }
    translate([pulley_radius * 2 + 5, width + 5, 0]) {
        chain_link(connector = false);
    }
    translate([pulley_radius * 2 + length + 10, 0, 0]) {
        vertical_step();
    }
    translate([pulley_radius * 2 + length + 10, width + 5, 0]) {
        horizontal_step();
    }
    translate([pulley_radius, pulley_radius + wall_thickness + 5, 0]) {
        pulley();
    }
    translate([pulley_radius, pulley_radius * 3 + wall_thickness * 3 + 10, 0]) {
        pulley(part2 = true);
    }
    translate([-pulley_distance_x - pulley_margin * 2 - 5, 0, 0]) {
        translate([0, -pulley_distance_y / 2 - pulley_margin]) {
            chassis();
        }
    }
    translate([-pulley_distance_x - pulley_margin * 2 - 5, -5, 0]) {
        translate([0, -pulley_distance_y / 2 - pulley_margin]) {
            mirror([0, 90, 0]) chassis(part2 = true);
        }
    }
    translate([axis_radius + 5, -crank_length + axis_radius - 5, 0]) {
        crank();
    }
    translate([axis_radius * 4 + 10, -axis_radius - 5, 0]) {
        handle();
    }
    translate([axis_radius * 6 + 15, -pin_height - 5, 0]) {
        pinpeg(h = pin_height * 2, r = pin_radius);
    }
} else if (part == "chain_link1") {
    translate([-length / 2, -width / 2, 0]) {
        chain_link();
    }
} else if (part == "chain_link2") {
    translate([-length / 2, -width / 2, 0]) {
        chain_link(connector = false);
    }
} else if (part == "stepv") {
    translate([-vertical / 2, -width / 2, 0]) {
        vertical_step();
    }
} else if (part == "steph") {
    translate([-horizontal / 2, -width / 2, 0]) {
        horizontal_step();
    }
} else if (part == "pulley1") {
    pulley();
} else if (part == "pulley2") {
    pulley(part2 = true);
} else if (part == "chassis1") {
    translate([-pulley_distance_x / 2 - pulley_margin, -pulley_distance_y / 2 - pulley_margin]) {
        chassis();
    }
} else if (part == "chassis2") {
    translate([-pulley_distance_x / 2 - pulley_margin, pulley_distance_y / 2 + pulley_margin]) {
        mirror([0, 90, 0]) chassis(part2 = true);
    }
} else if (part == "crank") {
    translate([0, -crank_length / 2 + axis_radius, 0]) {
        crank();
    }
} else if (part == "handle") {
    handle();
} else if (part == "pin") {
    pinpeg(h = pin_height * 2, r = pin_radius);
}

```