[User]
Okay, I need a custom OpenSCAD design for a spool holder for my Makerbot Replicator. I've been using the ReplicatorSpoolHolder_V2.0, but it's got some limitations and I'd like something more flexible and easier to configure.

Here's what I'm looking for in the new design, and I'll explain the issues I have with the existing one:

**Existing Design Issues (ReplicatorSpoolHolder_V2.0.scad):**

*   **Fixed Offset:** The existing design has a fixed offset for the spool from the back of the printer, which is controlled by the `SpoolPrintOffset` variable. I'd like the offset to be fully parametric so I can position the spool more freely.
*   **Limited Spool Sizes:** While the current design has `SpoolHoleDiameter` and `SpoolDepth`, I find that I'm having to adjust them every time I get a new spool. I would like to make those values dynamic, so they are easily edited in the Customizer.

**Desired Features for the New Design:**

1.  **Parametric Mounting:** The new spool holder should have two main parts: a wall support that clips into the existing holes on the back of the Replicator and a spool mounting tube that slides into this wall support. I need to be able to adjust the offset of the spool tube along the wall support with a parameter.
2.  **Parametric Offset and Position**: The offset and overall position of the spool tube needs to be controlled by a distance along the wall support using a single parameter. I do _not_ want to specify an X/Y coordinate offset but rather control this by a single distance value.
3.  **Parametric Spool Dimensions:**
    *   **Spool Hole Diameter:**  This is the diameter of the hole in the center of the spool, the same as `SpoolHoleDiameter` in the provided example.
    *   **Spool Width (Depth):** This is the width of the spool, similar to `SpoolDepth` in the example.
4.  **Wall Support Clip:** The wall support needs to securely clip into the existing holes on the Replicator. It should have the same basic shape as the existing design (with an inside ledge, a filler for the hole in the replicator, and an external base) but should be fully parametric.
    *   I need parameters for the width, height, and depth of the hole in the replicator wall (`HoleInWallWidth`, `HoleInWallHeight`, and `HoleInWallDepth`, from existing script.)
    *   I also need parameters for the ledge height (`LedgeHeight` in the existing script) and the support thickness (`InsideSupportThickness` in the existing script).
    *   The baseplate of the wall support should have parameters for width, depth and height (`OutsideBaseWidth`, `OutsideBaseDepth` and `OutsideBaseHeight` respectively in the existing script.)
    *   I also want to control the width, height and depth of the side tracks and top guides of the wall support (`SideTrackWidth`, `SideTrackHeight` , `SideTopHeight`, `InnerTrackWidth` from the existing script).
5.  **Spool Tube and Base:** The spool tube and base should be a single part that slides into the wall support. The tube needs to be parameterized by:
    *   The tube thickness (`TubeThickness` in the existing script)
    *   The tube collar width and height (`TubeCollarWidth` and `TubeCollarHeight` in the existing script)
    *   Clearance between the tube and the baseplate (`TubeBaseClearance` in the existing script) and any slippage between the tube baseplate and side rail (`TubeBaseSlippage` in the existing script)
6.  **Printability:** The design should prioritize printability without supports.
7.  **Customizer Integration:** All important parameters should be easily adjustable via the OpenSCAD customizer.
8.  **Color Preview:** It would be nice if the different parts could be rendered in different colors for better visualization in the preview (like the existing design, but optional).

**Specific Libraries:** I'm not looking to use any additional external libraries beyond the core functionality of OpenSCAD (I am not currently using MCAD). However, the existing designs use functions `RoundTopBox`, `tube`, `box`, `dislocateBox`, and `rightTriangle`, which you may be able to reuse or create similar functions.

I think those are all the details. Let me know if you have any questions! I'm really looking forward to being able to generate this for all my different spools!

[Assistant]
ReplicatorSpoolHolder_V2.0_scad.scad:
```
/* Uses OpenSCAD 2012.04.04

Parametric Replicator Spool Holder
==================================

This program renders 2 parts which allow for the mounting of non-standard spools on the Makerbot Replicator.

Part 1 is a left hand side wall support panel which clips into either of the holes at the back of the replicator which are
designed to be used by the Makerbot provided spool holders.  The panel design allows for larger spools to be offset from
the standard spool holder by moving Part 2 along the slot.

Part 2 is a mounting tube and base which slides into the wall support panel and allows for the mounting of
the spool.

Both Part 1 and 2 can be customised for spools by changing the value of variables below.

The main variables which need to be customised are:

	SpoolHoleDiameter
	SpoolDepth

The "Layout" variable can be set to "Both", "Wall" or "Spool" to render the parts required for printing.

The Part 1 wall support panel can be Mirrored in ReplicatorG or Makerware to print for the right hand side spool.

*/

/* [Global] */

// What to you want to print?
part = "Both";										//  [Both:Both, Wall:Wall, Spool:Spool]

//--  Spool Dimensions     <<<<<<<=======   CHANGE THESE TO SUIT YOUR SPOOL.

// SpoolHoleDiameter = 52.0;								// Settings for standard Makerbot Spools.
// SpoolDepth = 80.0;
// SpoolHoleDiameter = 28.25;								// Settings for my PLA Spools.
// SpoolDepth = 76.0;

// Diameter of Hole in Centre of Spool (52.0 for Makerbot)?
SpoolHoleDiameter = 52.0;								// Settings for Makerbot Spools.

// Width of Spool (80.0 for Makerbot)?
SpoolDepth = 80.0;

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

print_part();

module print_part() {
	if (part == "Both") {
		WallSupport();
		SpoolSupport();
	} else if (part == "Wall") {
		WallSupport();
	} else {
		SpoolSupport();
	}
}

/*
=========== Rounded Top Box based on thing:6400
=========== Thanks to IHeartRobotics
*/

module RoundTopBox(pad, box_l, box_w, box_h, round_r, smooth)
{

//  NOTE: This box has a flat bottom unlike thing:6400
//  ====

//  pad 	     	// Padding to maintain manifold
//  box_l			// Length
//  box_w 		// Width
//  box_h			// Height
//  round_		// Radius of round
//  smooth		// Number of facets of rounding cylinder

// To fix the corners cut the main cube with smaller cubes with spheres removed.

  difference() {
	cube([box_l, box_w, box_h], center = true);

	translate([0, -box_w/2+round_r, box_h/2-round_r]) {
		difference() {
			translate([0,-round_r-pad,round_r+pad])
				cube([box_l+2*pad, round_r*2+pad, round_r*2+pad], center = true);
			rotate(a=[0,90,0])
				cylinder(box_l+4*pad,round_r,round_r,center=true,$fn=smooth);
		}
	}
	translate([0, box_w/2-round_r, box_h/2-round_r]) {
		difference() {
			translate([0,round_r+pad,round_r+pad])
				cube([box_l+2*pad, round_r*2+pad, round_r*2+pad], center = true);
			rotate(a=[0,90,0])
				cylinder(box_l+4*pad,round_r,round_r,center=true,$fn=smooth);
		}
	}

// ----

	translate([-box_l/2+round_r, box_w/2-round_r, 0]) {
		difference() {
			translate([-round_r-pad,round_r+pad,0])
				cube([round_r*2+pad, round_r*2+pad, box_h+2*pad], center = true);
			cylinder(box_h+4*pad,round_r,round_r,center=true,$fn=smooth);
		}
	}
	translate([box_l/2-round_r, box_w/2-round_r, 0]) {
		difference() {
			translate([round_r+pad,round_r+pad,0])
				cube([round_r*2+pad, round_r*2+pad, box_h+2*pad], center = true);
			cylinder(box_h+4*pad,round_r,round_r,center=true,$fn=smooth);
		}
	}

	translate([-box_l/2+round_r, -box_w/2+round_r, 0]) {
		difference() {
			translate([-round_r-pad,-round_r-pad,0])
				cube([round_r*2+pad, round_r*2+pad, box_h+2*pad], center = true);
			cylinder(box_h+4*pad,round_r,round_r,center=true,$fn=smooth);
		}
	}
	translate([box_l/2-round_r, -box_w/2+round_r, 0]) {
		difference() {
			translate([round_r+pad,-round_r-pad,0])
				cube([round_r*2+pad, round_r*2+pad, box_h+2*pad], center = true);
			cylinder(box_h+4*pad,round_r,round_r,center=true,$fn=smooth);
		}
	}

// ----

	translate([-box_l/2+round_r, 0, box_h/2-round_r]) {
		difference() {
			translate([-round_r-pad, 0, round_r+pad])
				cube([round_r*2+pad, box_w+2*pad, round_r*2+pad], center = true);
			rotate(a=[0,90,90])
				cylinder(box_w+4*pad,round_r,round_r,center=true,$fn=smooth);
		}
	}
	translate([box_l/2-round_r, 0, box_h/2-round_r]) {
		difference() {
			translate([round_r+pad, 0, round_r+pad])
				cube([round_r*2+pad, box_w+2*pad, round_r*2+pad], center = true);
			rotate(a=[0,90,90])
				cylinder(box_w+4*pad,round_r,round_r,center=true,$fn=smooth);
		}
	}

// ----

	translate([box_l/2-round_r, box_w/2-round_r, box_h/2-round_r]) {
		difference() {
			translate([round_r+pad, round_r+pad, round_r+pad])
				cube([round_r*2+pad, round_r*2+pad, round_r*2+pad], center = true);
			sphere(round_r,center=true,$fn=smooth);
		}
	}
	translate([-box_l/2+round_r, box_w/2-round_r, box_h/2-round_r]) {
		difference() {
			translate([-round_r-pad, round_r+pad, round_r+pad])
				cube([round_r*2+pad, round_r*2+pad, round_r*2+pad], center = true);
			sphere(round_r,center=true,$fn=smooth);
		}
	}
	translate([box_l/2-round_r, -box_w/2+round_r, box_h/2-round_r]) {
		difference() {
			translate([round_r+pad, -round_r-pad, round_r+pad])
				cube([round_r*2+pad, round_r*2+pad, round_r*2+pad], center = true);
			sphere(round_r,center=true,$fn=smooth);
		}
	}
	translate([-box_l/2+round_r, -box_w/2+round_r, box_h/2-round_r]) {
		difference() {
			translate([-round_r-pad, -round_r-pad, round_r+pad])
				cube([round_r*2+pad, round_r*2+pad, round_r*2+pad], center = true);
			sphere(round_r,center=true,$fn=smooth);
		}
	}
}

}

/*
===========  OpenSCAD Shapes Library (www.openscad.at)
===========  Copyright (C) 2009  Catarina Mota <clifford@clifford.at>
*/

module tube(height, radius, wall) {
	difference(){
		cylinder(height, radius, radius,$fa=1);
		cylinder(height, radius-wall, radius-wall);
	}
}

module box(w,h,d) {
	scale ([w,h,d]) cube(1, true);
}

//-----------------------
//MOVES THE ROTATION AXIS OF A BOX FROM ITS CENTER TO THE BOTTOM LEFT CORNER
module dislocateBox(w,h,d){
	translate([w/2,h,0]){
		difference(){
			box(w, h*2, d+1);
			translate([-w,0,0]) box(w, h*2, d+1);
		}
	}
}

module rightTriangle(adjacent, opposite, depth) {
	difference(){
		translate([-adjacent/2,opposite/2,0]) box(adjacent, opposite, depth);
		translate([-adjacent,0,0]){
			rotate([0,0,atan(opposite/adjacent)]) dislocateBox(adjacent*2, opposite, depth);
		}
	}
}
/*
  ==============================================================================
   MAIN CODE
  ==============================================================================
*/

//--  Variables for Hole in Wall.

HoleInWallWidth = 32.0 * 1;									// Size of the hole in the Replicator Wall.
HoleInWallHeight = 17.0 * 1;
HoleInWallDepth = 5.0 * 1;
LedgeHeight = 10.0 * 1;										// Height of inside support ledge.
InsideSupportThickness = 3.0 * 1;								// Thickness of Cube to hold inside Replicator.

//--  Standard Build Variables.

OutsideBaseWidth = 80.0 * 1;									// Size of external support baseplate
OutsideBaseDepth = 4.0 * 1;
SideTrackWidth = 3.0 * 1;
SideTrackHeight = 5.0 * 1;
SideTopHeight = 6.0 * 1;
InnerTrackWidth = 3.0 * 1;
TubeThickness = 4.0 * 1;
TubeCollarWidth = 5.0 * 1;
TubeCollarHeight = 2.0 * 1;
TubeBaseClearance = 3.0 * 1;									// Space between edge of baseplate and tube.
TubeBaseSlippage = 0.5 * 1;									// Slippage between tube base plate and side rail.

//--  Calculated Dimensions

OutsideBaseHeight = SpoolHoleDiameter + (TubeBaseClearance * 2) + (SideTrackWidth * 2) + (TubeBaseSlippage * 2);

SideTrackStart = InsideSupportThickness + HoleInWallDepth + OutsideBaseDepth;
SideTopStart = SideTrackStart + SideTrackHeight;
SideTopWidth = SideTrackWidth + InnerTrackWidth;
UpperTrackStart = OutsideBaseHeight - SideTrackWidth;
UpperTopStart = OutsideBaseHeight - SideTopWidth;

SpoolPrintOffset = 30 * 1;									// Offset of Spool from Wall Support for print layout

SpoolBaseplateDepth = SideTrackHeight - 0.4;
SpoolBaseplateXorY = SpoolHoleDiameter + (TubeBaseClearance * 2);

//-- Wall Support Panel.

module WallSupport() {

//-- Inside Base with holding ledge.

  color("Aqua") translate([0, (LedgeHeight * -1),0])
		 cube([InsideSupportThickness, (HoleInWallHeight + LedgeHeight), HoleInWallWidth]);

//-- Hole in Wall Filler.

  color("CadetBlue") translate([InsideSupportThickness,0,0])
		 cube([HoleInWallDepth,HoleInWallHeight,HoleInWallWidth]);

//-- Outside Base.

  color("RoyalBlue") translate([(InsideSupportThickness + HoleInWallDepth),0,0])
		 cube([OutsideBaseDepth,OutsideBaseHeight,OutsideBaseWidth]);

//-- Bottom Side.

  color("Gray") translate([SideTrackStart,0,0])
		 cube([SideTrackHeight,SideTrackWidth,OutsideBaseWidth]);

//-- Top Side.

  color("Beige") translate([SideTrackStart,UpperTrackStart,0])
		 cube([SideTopHeight,SideTrackWidth,OutsideBaseWidth]);

//-- Lower Top Guide.

  color("LawnGreen") translate([SideTopStart + (SideTopHeight/2.0),SideTopWidth/2.0,OutsideBaseWidth/2.0]) rotate([90,90,90])
		 RoundTopBox( 0.1, OutsideBaseWidth, SideTopHeight, SideTopWidth,  1.5, 20);

//-- Upper Top Guide.

  color("LimeGreen") translate([SideTopStart+ (SideTopHeight/2.0),UpperTopStart + SideTopWidth/2.0,OutsideBaseWidth/2.0])
		 rotate([90,90,90])
		 RoundTopBox( 0.1, OutsideBaseWidth, SideTopHeight, SideTopWidth,  1.5, 20.0);

}

module BasePlate() {

	color("red") translate([SpoolPrintOffset, SideTrackWidth, 0])
	cube([SpoolBaseplateXorY,SpoolBaseplateXorY,SpoolBaseplateDepth]);

}

module MainTube() {

 	difference(){

    	color("Yellow")
		translate([SpoolPrintOffset + (SpoolBaseplateXorY /2.0),SideTrackWidth + (SpoolBaseplateXorY / 2.0),SpoolBaseplateDepth-0.01])
		tube(SpoolDepth + SideTopHeight + 1.0,SpoolHoleDiameter/2.0,TubeThickness);

		color("Orange")
		//  Leave 15mm lower collar to strengthen printing.
    	translate([SpoolPrintOffset,0,15])
		cube([SpoolBaseplateXorY,(SpoolBaseplateXorY  + TubeBaseClearance)/2,SpoolDepth  + SideTopHeight + 1.0 + TubeCollarWidth ]);
  }
}

module UpperCollar() {

	difference(){
    	color("SkyBlue")
 		translate([SpoolPrintOffset + (SpoolBaseplateXorY /2.0),SideTrackWidth + (SpoolBaseplateXorY / 2.0),SpoolDepth  + SideTopHeight + 1.0])
		tube(TubeCollarWidth,(SpoolHoleDiameter + TubeCollarHeight)/2.0,TubeCollarHeight);

    	translate([SpoolPrintOffset,0,0])
		cube([SpoolBaseplateXorY,(SpoolBaseplateXorY  + TubeBaseClearance)/2,SpoolDepth + SideTopHeight + 1.0 +TubeCollarWidth]);
  }
}

module SupportTriangle() {

	color("pink")
	translate([SpoolPrintOffset + (SpoolHoleDiameter /2.0)
			+ TubeBaseClearance,SpoolBaseplateXorY - TubeBaseClearance,SpoolBaseplateDepth-0.01]) rotate ([0,90,180])
	rightTriangle(SpoolDepth,SpoolHoleDiameter - TubeBaseClearance,TubeThickness);

}

//--	Spool Tube and support base.

module SpoolSupport() {

	BasePlate();
	MainTube();
	UpperCollar();
	SupportTriangle();
}

```
ReplicatorSpoolHolder_V2.0.scad:
```
/* Uses OpenSCAD 2012.04.04

Parametric Replicator Spool Holder
==================================

This program renders 2 parts which allow for the mounting of non-standard spools on the Makerbot Replicator.

Part 1 is a left hand side wall support panel which clips into either of the holes at the back of the replicator which are
designed to be used by the Makerbot provided spool holders.  The panel design allows for larger spools to be offset from
the standard spool holder by moving Part 2 along the slot.

Part 2 is a mounting tube and base which slides into the wall support panel and allows for the mounting of
the spool.

Both Part 1 and 2 can be customised for spools by changing the value of variables below.

The main variables which need to be customised are:

	SpoolHoleDiameter
	SpoolDepth

The "Layout" variable can be set to "Both", "Wall" or "Spool" to render the parts required for printing.

The Part 1 wall support panel can be Mirrored in ReplicatorG or Makerware to print for the right hand side spool.

*/

/* [Global] */

// What to you want to print?
part = "Both";										//  [Both:Both, Wall:Wall, Spool:Spool]

//--  Spool Dimensions     <<<<<<<=======   CHANGE THESE TO SUIT YOUR SPOOL.

// SpoolHoleDiameter = 52.0;								// Settings for standard Makerbot Spools.
// SpoolDepth = 80.0;
// SpoolHoleDiameter = 28.25;								// Settings for my PLA Spools.
// SpoolDepth = 76.0;

// Diameter of Hole in Centre of Spool (52.0 for Makerbot)?
SpoolHoleDiameter = 52.0;								// Settings for Makerbot Spools.

// Width of Spool (80.0 for Makerbot)?
SpoolDepth = 80.0;

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

print_part();

module print_part() {
	if (part == "Both") {
		WallSupport();
		SpoolSupport();
	} else if (part == "Wall") {
		WallSupport();
	} else {
		SpoolSupport();
	}
}

/*
=========== Rounded Top Box based on thing:6400
=========== Thanks to IHeartRobotics
*/

module RoundTopBox(pad, box_l, box_w, box_h, round_r, smooth)
{

//  NOTE: This box has a flat bottom unlike thing:6400
//  ====

//  pad 	     	// Padding to maintain manifold
//  box_l			// Length
//  box_w 		// Width
//  box_h			// Height
//  round_		// Radius of round
//  smooth		// Number of facets of rounding cylinder

// To fix the corners cut the main cube with smaller cubes with spheres removed.

  difference() {
	cube([box_l, box_w, box_h], center = true);

	translate([0, -box_w/2+round_r, box_h/2-round_r]) {
		difference() {
			translate([0,-round_r-pad,round_r+pad])
				cube([box_l+2*pad, round_r*2+pad, round_r*2+pad], center = true);
			rotate(a=[0,90,0])
				cylinder(box_l+4*pad,round_r,round_r,center=true,$fn=smooth);
		}
	}
	translate([0, box_w/2-round_r, box_h/2-round_r]) {
		difference() {
			translate([0,round_r+pad,round_r+pad])
				cube([box_l+2*pad, round_r*2+pad, round_r*2+pad], center = true);
			rotate(a=[0,90,0])
				cylinder(box_l+4*pad,round_r,round_r,center=true,$fn=smooth);
		}
	}

// ----

	translate([-box_l/2+round_r, box_w/2-round_r, 0]) {
		difference() {
			translate([-round_r-pad,round_r+pad,0])
				cube([round_r*2+pad, round_r*2+pad, box_h+2*pad], center = true);
			cylinder(box_h+4*pad,round_r,round_r,center=true,$fn=smooth);
		}
	}
	translate([box_l/2-round_r, box_w/2-round_r, 0]) {
		difference() {
			translate([round_r+pad,round_r+pad,0])
				cube([round_r*2+pad, round_r*2+pad, box_h+2*pad], center = true);
			cylinder(box_h+4*pad,round_r,round_r,center=true,$fn=smooth);
		}
	}

	translate([-box_l/2+round_r, -box_w/2+round_r, 0]) {
		difference() {
			translate([-round_r-pad,-round_r-pad,0])
				cube([round_r*2+pad, round_r*2+pad, box_h+2*pad], center = true);
			cylinder(box_h+4*pad,round_r,round_r,center=true,$fn=smooth);
		}
	}
	translate([box_l/2-round_r, -box_w/2+round_r, 0]) {
		difference() {
			translate([round_r+pad,-round_r-pad,0])
				cube([round_r*2+pad, round_r*2+pad, box_h+2*pad], center = true);
			cylinder(box_h+4*pad,round_r,round_r,center=true,$fn=smooth);
		}
	}

// ----

	translate([-box_l/2+round_r, 0, box_h/2-round_r]) {
		difference() {
			translate([-round_r-pad, 0, round_r+pad])
				cube([round_r*2+pad, box_w+2*pad, round_r*2+pad], center = true);
			rotate(a=[0,90,90])
				cylinder(box_w+4*pad,round_r,round_r,center=true,$fn=smooth);
		}
	}
	translate([box_l/2-round_r, 0, box_h/2-round_r]) {
		difference() {
			translate([round_r+pad, 0, round_r+pad])
				cube([round_r*2+pad, box_w+2*pad, round_r*2+pad], center = true);
			rotate(a=[0,90,90])
				cylinder(box_w+4*pad,round_r,round_r,center=true,$fn=smooth);
		}
	}

// ----

	translate([box_l/2-round_r, box_w/2-round_r, box_h/2-round_r]) {
		difference() {
			translate([round_r+pad, round_r+pad, round_r+pad])
				cube([round_r*2+pad, round_r*2+pad, round_r*2+pad], center = true);
			sphere(round_r,center=true,$fn=smooth);
		}
	}
	translate([-box_l/2+round_r, box_w/2-round_r, box_h/2-round_r]) {
		difference() {
			translate([-round_r-pad, round_r+pad, round_r+pad])
				cube([round_r*2+pad, round_r*2+pad, round_r*2+pad], center = true);
			sphere(round_r,center=true,$fn=smooth);
		}
	}
	translate([box_l/2-round_r, -box_w/2+round_r, box_h/2-round_r]) {
		difference() {
			translate([round_r+pad, -round_r-pad, round_r+pad])
				cube([round_r*2+pad, round_r*2+pad, round_r*2+pad], center = true);
			sphere(round_r,center=true,$fn=smooth);
		}
	}
	translate([-box_l/2+round_r, -box_w/2+round_r, box_h/2-round_r]) {
		difference() {
			translate([-round_r-pad, -round_r-pad, round_r+pad])
				cube([round_r*2+pad, round_r*2+pad, round_r*2+pad], center = true);
			sphere(round_r,center=true,$fn=smooth);
		}
	}
}

}

/*
===========  OpenSCAD Shapes Library (www.openscad.at)
===========  Copyright (C) 2009  Catarina Mota <clifford@clifford.at>
*/

module tube(height, radius, wall) {
	difference(){
		cylinder(height, radius, radius,$fa=1);
		cylinder(height, radius-wall, radius-wall);
	}
}

module box(w,h,d) {
	scale ([w,h,d]) cube(1, true);
}

//-----------------------
//MOVES THE ROTATION AXIS OF A BOX FROM ITS CENTER TO THE BOTTOM LEFT CORNER
module dislocateBox(w,h,d){
	translate([w/2,h,0]){
		difference(){
			box(w, h*2, d+1);
			translate([-w,0,0]) box(w, h*2, d+1);
		}
	}
}

module rightTriangle(adjacent, opposite, depth) {
	difference(){
		translate([-adjacent/2,opposite/2,0]) box(adjacent, opposite, depth);
		translate([-adjacent,0,0]){
			rotate([0,0,atan(opposite/adjacent)]) dislocateBox(adjacent*2, opposite, depth);
		}
	}
}
/*
  ==============================================================================
   MAIN CODE
  ==============================================================================
*/

//--  Variables for Hole in Wall.

HoleInWallWidth = 32.0 * 1;									// Size of the hole in the Replicator Wall.
HoleInWallHeight = 17.0 * 1;
HoleInWallDepth = 5.0 * 1;
LedgeHeight = 10.0 * 1;										// Height of inside support ledge.
InsideSupportThickness = 3.0 * 1;								// Thickness of Cube to hold inside Replicator.

//--  Standard Build Variables.

OutsideBaseWidth = 80.0 * 1;									// Size of external support baseplate
OutsideBaseDepth = 4.0 * 1;
SideTrackWidth = 3.0 * 1;
SideTrackHeight = 5.0 * 1;
SideTopHeight = 6.0 * 1;
InnerTrackWidth = 3.0 * 1;
TubeThickness = 4.0 * 1;
TubeCollarWidth = 5.0 * 1;
TubeCollarHeight = 2.0 * 1;
TubeBaseClearance = 3.0 * 1;									// Space between edge of baseplate and tube.
TubeBaseSlippage = 0.5 * 1;									// Slippage between tube base plate and side rail.

//--  Calculated Dimensions

OutsideBaseHeight = SpoolHoleDiameter + (TubeBaseClearance * 2) + (SideTrackWidth * 2) + (TubeBaseSlippage * 2);

SideTrackStart = InsideSupportThickness + HoleInWallDepth + OutsideBaseDepth;
SideTopStart = SideTrackStart + SideTrackHeight;
SideTopWidth = SideTrackWidth + InnerTrackWidth;
UpperTrackStart = OutsideBaseHeight - SideTrackWidth;
UpperTopStart = OutsideBaseHeight - SideTopWidth;

SpoolPrintOffset = 30 * 1;									// Offset of Spool from Wall Support for print layout

SpoolBaseplateDepth = SideTrackHeight - 0.4;
SpoolBaseplateXorY = SpoolHoleDiameter + (TubeBaseClearance * 2);

//-- Wall Support Panel.

module WallSupport() {

//-- Inside Base with holding ledge.

  color("Aqua") translate([0, (LedgeHeight * -1),0])
		 cube([InsideSupportThickness, (HoleInWallHeight + LedgeHeight), HoleInWallWidth]);

//-- Hole in Wall Filler.

  color("CadetBlue") translate([InsideSupportThickness,0,0])
		 cube([HoleInWallDepth,HoleInWallHeight,HoleInWallWidth]);

//-- Outside Base.

  color("RoyalBlue") translate([(InsideSupportThickness + HoleInWallDepth),0,0])
		 cube([OutsideBaseDepth,OutsideBaseHeight,OutsideBaseWidth]);

//-- Bottom Side.

  color("Gray") translate([SideTrackStart,0,0])
		 cube([SideTrackHeight,SideTrackWidth,OutsideBaseWidth]);

//-- Top Side.

  color("Beige") translate([SideTrackStart,UpperTrackStart,0])
		 cube([SideTopHeight,SideTrackWidth,OutsideBaseWidth]);

//-- Lower Top Guide.

  color("LawnGreen") translate([SideTopStart + (SideTopHeight/2.0),SideTopWidth/2.0,OutsideBaseWidth/2.0]) rotate([90,90,90])
		 RoundTopBox( 0.1, OutsideBaseWidth, SideTopHeight, SideTopWidth,  1.5, 20);

//-- Upper Top Guide.

  color("LimeGreen") translate([SideTopStart+ (SideTopHeight/2.0),UpperTopStart + SideTopWidth/2.0,OutsideBaseWidth/2.0])
		 rotate([90,90,90])
		 RoundTopBox( 0.1, OutsideBaseWidth, SideTopHeight, SideTopWidth,  1.5, 20.0);

}

module BasePlate() {

	color("red") translate([SpoolPrintOffset, SideTrackWidth, 0])
	cube([SpoolBaseplateXorY,SpoolBaseplateXorY,SpoolBaseplateDepth]);

}

module MainTube() {

 	difference(){

    	color("Yellow")
		translate([SpoolPrintOffset + (SpoolBaseplateXorY /2.0),SideTrackWidth + (SpoolBaseplateXorY / 2.0),SpoolBaseplateDepth-0.01])
		tube(SpoolDepth + SideTopHeight + 1.0,SpoolHoleDiameter/2.0,TubeThickness);

		color("Orange")
		//  Leave 15mm lower collar to strengthen printing.
    	translate([SpoolPrintOffset,0,15])
		cube([SpoolBaseplateXorY,(SpoolBaseplateXorY  + TubeBaseClearance)/2,SpoolDepth  + SideTopHeight + 1.0 + TubeCollarWidth ]);
  }
}

module UpperCollar() {

	difference(){
    	color("SkyBlue")
 		translate([SpoolPrintOffset + (SpoolBaseplateXorY /2.0),SideTrackWidth + (SpoolBaseplateXorY / 2.0),SpoolDepth  + SideTopHeight + 1.0])
		tube(TubeCollarWidth,(SpoolHoleDiameter + TubeCollarHeight)/2.0,TubeCollarHeight);

    	translate([SpoolPrintOffset,0,0])
		cube([SpoolBaseplateXorY,(SpoolBaseplateXorY  + TubeBaseClearance)/2,SpoolDepth + SideTopHeight + 1.0 +TubeCollarWidth]);
  }
}

module SupportTriangle() {

	color("pink")
	translate([SpoolPrintOffset + (SpoolHoleDiameter /2.0)
			+ TubeBaseClearance,SpoolBaseplateXorY - TubeBaseClearance,SpoolBaseplateDepth-0.01]) rotate ([0,90,180])
	rightTriangle(SpoolDepth,SpoolHoleDiameter - TubeBaseClearance,TubeThickness);

}

//--	Spool Tube and support base.

module SpoolSupport() {

	BasePlate();
	MainTube();
	UpperCollar();
	SupportTriangle();
}

```


[User]
Okay, I'm looking to design a parametric T-shaped block for a sub-irrigated planter system, similar to the one I found on Thingiverse (linked above as well as in the comments of the file I included). I want to be able to adjust the size and dimensions to fit different sized containers, not just the 5-gallon bucket size the original is designed for. I'm thinking about using a system of nested containers with one holding the water and the other holding the soil with a continuous wick between them.

Here's what I need in the OpenSCAD file:

**Overall Structure:**

*   **T-Shape:** The block should be roughly T-shaped. The top of the 'T' will sit in the bottom of the soil container (the 'pot'), and the base of the 'T' will stick down into the water reservoir. There will be a pass through on each side of the T that allows water to pass to the pot. The water will come up through the middle of the T.
*   **Parametric Design:** Everything needs to be parametric so I can change dimensions easily in the OpenSCAD customizer. This means that I need to be able to set the pot diameter, the T base length and width, and also the internal diameter for the water flow, all separately.
*   **Intersections:**  There will be holes/channels for water to wick from the reservoir up into the soil through the T base. These will need to be created by subtracting cylinders and minkowski sums to provide additional surface area.
*   **Screw/Nut Mount:** A screw and nut should be designed to accommodate a nut and bolt set used for connecting two blocks together. It can be a simple hex nut/bolt arrangement.
*   **Container Radius:** The primary parameter to be set is the radius of the pot that this will be used for. This is based on the size of the container it is to be placed within.

**Specific Parameters:**

*   **`planter_radius`**: The radius of the planter container it is to be placed in. (This is half the diameter. The original file uses the *diameter* instead.)
*   **`t_base_length`**: The length of the base of the 'T' (the part sticking into the reservoir).
*   **`t_base_width`**: The width of the base of the 'T'.
*   **`water_channel_radius`**: The radius of the main water channel through the middle of the 'T'.
*    **`connection_radius`**: The radius of the channel that connects the two sides of the T.
*    **`connection_offset`**: The distance from the base of the T to the center of the connector.
*   **`screw_radius1`**, **`screw_radius2`**, **`screw_n`**, **`screw_height`**, and **`screw_twist`**: Parameters for screw shape used in screw hole.
*   **`nut_radius1`**, **`nut_radius2`**, **`nut_radius3`**, **`nut_sides`**, and **`nut_height`**: Parameters for nut shape used in screw hole.
*   **`bolt_hole_offset_x`**, and **`bolt_hole_offset_y`**: The X and Y offset of the bolt/nut hole from the center of the object.
*   **All dimensions should be in millimeters.**

**Additional Design Notes:**

*   I would like the ability to choose between the two different screw types included in the original code.
*   I would like there to be an option to use a simplified, non-parametric version of the nut and bolt mount.

**Libraries:**

*   I do not expect any particular libraries to be included.

Could you please generate the OpenSCAD code for this? Let me know if you have any questions.

[Assistant]
SIPirrigationBlock.scad:
```
/*
 * Sub-Irrigated Planter (SIP) Continious Irrigation Block
 *
 * By: Mike Creuzer <thingiverse@creuzer.com>
 *
 * http://www.thingiverse.com/thing:20753
 *
 * Version 1.1 - Made pot radius parametric
 */

/* Pot Diameters in MM */
// Soda Bottle = 100 ~ 4.5 inches
// 5 gallon bucket = 254 ~ 10 inches

planter = 254 ;

// Generatet the part
SipBody();

module SipBody()
{
	difference() {
		union() {
			baseblock();
			//cylinder(h =13, r = 3.15);
			screw(2, 3.15, 4, 4, 13, 4);
			minkowski(){ rotate(a=[0,90,0]) cylinder(h =15, r = 5); cylinder(r=2,h=.25);}
			minkowski(){rotate(a=[0,-90,0]) cylinder(h =15, r = 5); cylinder(r=2,h=.25);}

		}
		union() {
			cylinder(h =31, r = 2.1);
			rotate(a=[0,90,0]) translate(v=[0,0,5]) cylinder(h =31, r1 = 3.25, r2 = 3);
			rotate(a=[0,-90,0]) translate(v=[0,0,5]) cylinder(h =31, r1 = 3.25, r2 = 3);

			rotate(a=[0,-90,0]) cylinder(h =32, r = 2.1, center=true);

		}
	}
}

// Nut
intersection() {
	union(){
		translate(v=[19,13,-5]) nut(2, 3.4, 4.25, 6, 6, 4, 6.5, 2);
		difference(){
			translate(v=[19,13,-2]) cylinder(h=6,r1=5.25,r2=8);
			translate(v=[19,13,-2]) cylinder(h=6,r=4.5);
		}
	}
	#translate(v=[18,12,-planter/2 + 1]) sphere( r =planter/2, $fa=1);

}

module baseblock()
{
	difference() {
		minkowski(){
			translate(v=[0,0,5]) cube([15.4, 15.4, 20], center = true);
 			cylinder(r=5,h=1);
		}
		#rotate(a=[90,0,0]) translate(v=[0,planter/2 + 5.5,-15]) cylinder(h =31, r =planter/2, $fa=1);

	}

}

module screw(type = 2, r1 = 15, r2 = 20, n = 7, h = 100, t = 8)
{
	linear_extrude(height = h, twist = 360*t/n, convexity = t)
	difference() {
		circle(r2);
		for (i = [0:n-1]) {
				if (type == 1) rotate(i*360/n) polygon([
						[ 2*r2, 0 ],
						[ r2, 0 ],
						[ r1*cos(180/n), r1*sin(180/n) ],
						[ r2*cos(360/n), r2*sin(360/n) ],
						[ 2*r2*cos(360/n), 2*r2*sin(360/n) ],
				]);
				if (type == 2) rotate(i*360/n) polygon([
						[ 2*r2, 0 ],
						[ r2, 0 ],
						[ r1*cos(90/n), r1*sin(90/n) ],
						[ r1*cos(180/n), r1*sin(180/n) ],
						[ r2*cos(270/n), r2*sin(270/n) ],
						[ 2*r2*cos(270/n), 2*r2*sin(270/n) ],
				]);
		}
	}
}

module nut(type = 2, r1 = 16, r2 = 21, r3 = 30, s = 6, n = 7, h = 100/5, t = 8/5)
{
	difference() {
		cylinder($fn = s, r = r3, h = h);
		translate([ 0, 0, -h/2 ]) screw(type, r1, r2, n, h*2, t*2);
	}
}

```


[User]
Okay, I need a custom fan adapter designed, and I'm hoping you can help me create an OpenSCAD file for it. I've been playing around with a very basic one but it's not very flexible. I want something more parametric, that can handle a variety of fan sizes and configurations, similar to what I've been working on but more refined. Here's what I'm looking for:

**Overall Goal:** I want a script that creates a fan adapter that connects a smaller fan to a larger one. I need to be able to choose different options for how the smaller fan's screws are accessed, and have the whole thing be fully parametric. I would like this to be a single OpenSCAD file if possible, rather than multiple files, I understand if this would be difficult.

**Core Features:**

1.  **Fan Sizes:** The script needs to accept two main parameters: `smallsize` and `largesize`, representing the *nominal* diameters (in mm) of the smaller and larger fans, respectively. These can be the same, but I would like to ensure that the script does not break if both sizes are the same.

2.  **Flanges:**
    *   Each fan connection point should have a flange. These have thicknesses defined by `smallflange` (for the smaller fan) and `largeflange` (for the larger fan) . I also require these to be parametric and in mm.
    *   The flange should have mounting holes, configurable by their spacing (e.g. `smallholes`, `largeholes`) and diameters (e.g. `smallholesize`, `largeholesize`). These should also be parametric in mm.

3.  **Cowling:**
    *   There needs to be a connecting cowling between the flanges. I would like to define the height of this with `cowlingheight` and the thickness of the cowling walls with `wallthickness`. Both are to be measured in mm.
    *   The cowling should be a tapered shape (a truncated cone), connecting the two flanges.

4.  **Hole Access Options (Key Feature):** I need a way to specify how the screws for the smaller fan are accessed. I would like these access options to be selectable via a string variable (e.g. `holeaccess`). The options I would like to have are:
    *   `"Cowling"`:  The mounting holes for the small fan are accessed through the *inside* of the cowling. This will require bosses on the small flange. These bosses should have a defined diameter (e.g `smallholeboss`) and countersinks with defined diameter (e.g. `smallholecountersink`).
    *   `"External"`: The mounting holes for the small fan are accessed from the *outside* of the adapter. No extra bosses or countersinks are needed for this configuration.
    *  `"Flange"`: No cowling, just a flange with both small and large fan mounting holes. Inefficient flow, but good for very low profile applications.

5.  **Units:** I am expecting all units to be in millimeters.

6.  **Smoothing:** It should be possible to increase `$fn` for smoother curves. I usually use a high value to prevent faceting. I would like to set a default `$fn = 80;`.

7. **Modules:** I would like a module function to create a flange rather than repeating the same shapes, and I am expecting this to use the module provided in the file below.

**Variables I Expect To Use:**
* `holeaccess`: string variable, selectable by a customiser, that defines which hole access option to use. Possible values: `"Cowling"`, `"External"`, `"Flange"`.
* `$fn`: Smoothing of curves, should default to 80.
* `smallsize`: integer, nominal diameter of small fan in mm
* `largesize`: integer, nominal diameter of large fan in mm
* `smallflange`: integer, thickness of small flange in mm
* `largeflange`: integer, thickness of large flange in mm
* `wallthickness`: integer, thickness of the cowling wall in mm
* `cowlingheight`: integer, height of the cowling in mm
* `smallholes`: integer, mounting hole spacing on small flange in mm
* `largeholes`: integer, mounting hole spacing on large flange in mm
* `smallholesize`: integer, diameter of small flange mounting holes in mm
* `largeholesize`: integer, diameter of large flange mounting holes in mm
* `smallholeboss`: integer, diameter of the boss for the small mounting hole in mm, this only applies to the "Cowling" option.
* `smallholecountersink`: integer, diameter of the countersink for the small mounting hole in mm, this only applies to the "Cowling" option.

**Specific libraries:** I don't expect any external libraries or files to be used. Everything should be self-contained within a single file if possible.

**Example Parameters for Testing:**

A good start might be to build the adapter with these values to verify that the program works as intended.
* `holeaccess="Cowling"`
* `$fn = 80;`
* `smallsize=80;`
* `largesize=120;`
* `smallflange=3;`
* `largeflange=4;`
* `wallthickness=2;`
* `cowlingheight=30;`
* `smallholes=71.5;`
* `largeholes=105;`
* `smallholesize=4.5;`
* `largeholesize=4.5;`

I've attached the existing OpenSCAD file I was messing with; please use it as a starting point or reference point, so that I do not need to rewrite all of the modules.
```
/*
    INTRODUCTION

Fan adaptor in scad.

Versions:
1.11    Played around with a module for the flange. Works fine, but some more understanding is needed.
1.1.    Aiming for a more complex version now. I will try and use IF statements to choose between having a lower flange with holes going through the inside or not. Essentially emulating the thruholes and no holes versions of the SWorks files. Geometry still very simple and unrefined. There is a lot of repetition, I should get the hang of using modules and functions I guess.
1.      Very simple, two flanges, cowling, and no special treatment of lower flange holes.

Initial values are 120 to 80.

Very basic appearance at the moment, just testing out the software and getting a feel for it. I may tidy up in later versions and as I learn more about the software.
*/

/*  BASIC SETUP  */
//Select type option. Cowling: Small fan screws accessed through the cowling. External: Small fan screws accessed from outside of the adaptor. Customiser makes the "Cowling" option look messy, but they are fine once created. Flange: A simple flat plate with mounting holes for large and small size but no cowling. Very inefficient flow but a very low profile.
holeaccess="Cowling"; //[Cowling,External,Flange]

//Smoothing of cylindrical faces (Can be ignored under most circumstances)
$fn = 80;

/*  VARIABLES  */
//Nominal fan sizes
//Nominal size of the smaller fan
smallsize=80;
//Nominal size of the larger fan. It is possible to choose the same size for both. This can lead to funky results sometimes.
largesize=120;

//Flange thicknesses
//Small side flange thickness
smallflange=3; //[1:0.2:6]
//Large side flange thickness (flange thickness used for the "Flange" option above)
largeflange=4; //[1:0.2:6]

//Cowling size
//Total height is cowling height plus the flange thicknesses.
//Thickness of the cowling wall
wallthickness=2; //[1:0.2:5]
//Height of the cowling, taller generally leads to better airflow. Total height will be this plus flange thicknesses.
cowlingheight=30;

/*
Mounting hole spacing and size
Size is usually pretty uniform (4.5 mm) due to using standard screws however for smaller sizes the screw holes are likely smaller
*/
//Spacing
//Small fan side mounting hole spacing
smallholes=71.5;
//Large fan side mounting hole spacing
largeholes=105;
//Size
//Diameter of the mounting holes on the small fan side
smallholesize=4.5; //[2:0.25:6]
//Diameter of the mounting holes on the large fan side
largeholesize=4.5; //[2:0.25:6]

/*  MODULES  */
module flange (size_fan,thick_wall,thick_flange,space_mount,size_mount) {
/*
    Creates a flange with or without mounting holes cut.

    VARIABLES
size_fan:       The given nominal size of the fan
thick_wall:     The cowling wall thickness
thick_flange:   The thickness of the flange
space_mount:    The spacing between mounting holes. If 0 then no holes will be cut.
size_mount:     The diameter of the mounting holes
*/

//OPERATION
    //difference() to perform subtractive operations on the base flange piece
    difference(){
        //translate() half flange thickness from initial centre position.
        //This ensures the base small flange is sitting at z=0 on the XY plane.
        translate([0,0,thick_flange/2])
        //Uncut flange shape.
        cube(size=[size_fan+thick_wall*2, size_fan+thick_wall*2, thick_flange], center=true);

        //Cut fan hole
        translate([0,0,thick_flange/2])
        //Hole shape removed by the difference() operation
        cylinder(h=thick_flange, d=size_fan, center=true);

        //Check for mounting hole requirement
        if (space_mount>0) {
            //Cut each hole individually.
            //I haven't yet found a pattern command and mirror doesn't copy as far as I can see.
            //This way will suffice for now.
            translate([space_mount/2, space_mount/2, thick_flange/2])
            cylinder(h=thick_flange, d=size_mount, center=true);

            translate([-space_mount/2, space_mount/2, thick_flange/2])
            cylinder(h=thick_flange, d=size_mount, center=true);

            translate([space_mount/2, -space_mount/2, thick_flange/2])
            cylinder(h=thick_flange, d=size_mount, center=true);

            translate([-space_mount/2, -space_mount/2, thick_flange/2])
            cylinder(h=thick_flange, d=size_mount, center=true);
        } // if (space_mount>0)

        else { /*do nothing*/ } // else

    } // difference
} // module flange

/*
    MODEL CODE
    Starts with an if statement to distinguish between type choices.
    holeaccess variable is user choice.
        Choices are:
        1. Cowling:     Small side hole access from inside the cowling
        2. External:    Small side access from outside the adaptor
        3. Angled:      With an angle between flanges. Hole access is as external.
*/
if (holeaccess=="Cowling") {
/*
    MATHS
*/
//Calculate boss and countersink sizes
smallholeboss=smallholesize*3;
smallholecountersink=smallholesize*1.75;

//difference() to subtract the inner parts and mounting holes from a solid geometry.
difference(){
/*
union() command to join cowling and flanges together and add small side hole bosses.
    Lower flange built centred on the xy plane at z=0
    Cowling built centrally on top of the lower flange
    Upper flange built centrally on top of the cowling

Create geometry:
1. lower flange
2. cowling
3. lower mounting hole bosses
4. upper flange
*/
    union(){
    //1. Lower flange
        translate([0,0,smallflange/2])
        //Uncut flange shape. Centred for ease. The position uses basic maths.
        cube(size=[smallsize+wallthickness*2, smallsize+wallthickness*2, smallflange], center=true);

    //2. Cowling
        translate([0,0,smallflange+cowlingheight/2])
        //tapered cylinder for cowling
        //difference to other tapered cylinder
        cylinder(h=cowlingheight, r1=smallsize/2+wallthickness, r2=largesize/2+wallthickness, center=true);

    //3. Lower mounting hole bosses
        /*
        Extruding the mounting hole bosses.
        I don't know of a way to extrude to a surface, so for now will do it this way.
        Mirror seems to not have a copy option, so I have to recreate each boss for each corner. Again, there is probably a better way to do it, but I will have to learn it.
        */
        translate([smallholes/2,smallholes/2, (cowlingheight+smallflange)/2])
        cylinder(h=cowlingheight+smallflange, d=smallholeboss, center=true);

        translate([-smallholes/2,smallholes/2, (cowlingheight+smallflange)/2])
        cylinder(h=cowlingheight+smallflange, d=smallholeboss, center=true);

        translate([smallholes/2,-smallholes/2, (cowlingheight+smallflange)/2])
        cylinder(h=cowlingheight+smallflange, d=smallholeboss, center=true);

        translate([-smallholes/2,-smallholes/2, (cowlingheight+smallflange)/2])
        cylinder(h=cowlingheight+smallflange, d=smallholeboss, center=true);

    //4. Upper flange
        translate([0,0,smallflange+cowlingheight])
        flange(largesize,wallthickness,largeflange,largeholes,largeholesize);
    } //union

/*
Remove inner geometry:
1. lower flange fan hole
2. cowling
3. lower mounting holes
4. lower mounting hole countersink
*/
    //1. Lower flange fan hole
        translate([0,0,smallflange/2])
        //Uncut flange shape. Centred for ease. The position uses basic maths.
        cylinder(h=smallflange, d=smallsize, center=true);

    //2. Cowling
        translate([0,0,smallflange+cowlingheight/2])
        //tapered cylinder for cowling
        //difference to other tapered cylinder
        cylinder(h=cowlingheight, d1=smallsize, d2=largesize, center=true);

    //3. lower mounting holes
        /*
        Cutting the mounting holes.
        Mirror seems to not have a copy option, so I have to recreate each hole for each corner. Again, there is probably a better way to do it, but I will have to learn it.
        */
        translate([smallholes/2,smallholes/2,(smallflange+cowlingheight+largeflange)/2])
        cylinder(h=smallflange+cowlingheight+largeflange, d=smallholesize, center=true);

        translate([-smallholes/2,smallholes/2,(smallflange+cowlingheight+largeflange)/2])
        cylinder(h=smallflange+cowlingheight+largeflange, d=smallholesize, center=true);

        translate([smallholes/2,-smallholes/2,(smallflange+cowlingheight+largeflange)/2])
        cylinder(h=smallflange+cowlingheight+largeflange, d=smallholesize, center=true);

        translate([-smallholes/2,-smallholes/2,(smallflange+cowlingheight+largeflange)/2])
        cylinder(h=smallflange+cowlingheight+largeflange, d=smallholesize, center=true);

    //4. lower mounting hole countersink
        /*
        Cutting the mounting hole counter sinks.
        Mirror seems to not have a copy option, so I have to recreate each countersink for each corner. Again, there is probably a better way to do it, but I will have to learn it.
        */
        translate([smallholes/2,smallholes/2, (cowlingheight+largeflange)/2+smallflange])
        cylinder(h=cowlingheight+largeflange, d=smallholecountersink, center=true);

        translate([-smallholes/2,smallholes/2, (cowlingheight+largeflange)/2+smallflange])
        cylinder(h=cowlingheight+largeflange, d=smallholecountersink, center=true);

        translate([smallholes/2,-smallholes/2, (cowlingheight+largeflange)/2+smallflange])
        cylinder(h=cowlingheight+largeflange, d=smallholecountersink, center=true);

        translate([-smallholes/2,-smallholes/2, (cowlingheight+largeflange)/2+smallflange])
        cylinder(h=cowlingheight+largeflange, d=smallholecountersink, center=true);

} //difference
} //if

else if (holeaccess=="External") {
/*
1. Begin by revolving the shape of the cowling.
2: Add the lower and upper flanges using the flange() module

1. Revolve the cowling
Draw revolved polygon shape
This requires a polygon following points inside a rotate_extrude
*/

    rotate_extrude(angle=360, convexity=10)
        polygon(points=[[smallsize/2,smallflange],
        [(smallsize/2)+wallthickness,smallflange],
        [(largesize/2)+wallthickness,cowlingheight+smallflange],
        [largesize/2,cowlingheight+smallflange]]);

    //2. Use modules to create the flanges
    //Lower (smaller) flange
    flange(smallsize,wallthickness,smallflange,smallholes,smallholesize);

    //Upper (larger) flange
    translate([0,0,smallflange+cowlingheight])
    flange(largesize,wallthickness,largeflange,largeholes,largeholesize);
} //else if (holeaccess=="External")

else if (holeaccess=="Flange") {
/*
1. Create blank flange according to "largesize"
2. Cut "smallsize" hole into flange blank
3. Drill large size holes (largeholes, largeholesize)
4. Drill small size holes (smallholes, smallholesize)
*/
//1. Create blank flange according to "largesize"
//difference() to perform subtractive operations on the base flange piece
    difference(){
        //translate() half flange thickness from initial centre position.
        //This ensures the base small flange is sitting at z=0 on the XY plane.
        translate([0,0,largeflange/2])
        //Uncut flange shape.
        cube(size=[largesize+largeflange*2, largesize+largeflange*2, largeflange], center=true);
        //2. Cut "smallsize" hole into flange blank
        //Cut fan hole
        translate([0,0,largeflange/2])
        //Hole shape removed by the difference() operation
        cylinder(h=largeflange, d=smallsize, center=true);

//3. Drill large size holes (largeholes, largeholesize)
//4. Drill small size holes (smallholes, smallholesize)
    //Cut each largesize hole individually.
        translate([largeholes/2, largeholes/2, largeflange/2])
        cylinder(h=largeflange, d=largeholesize, center=true);

        translate([-largeholes/2, largeholes/2, largeflange/2])
        cylinder(h=largeflange, d=largeholesize, center=true);

        translate([largeholes/2, -largeholes/2, largeflange/2])
        cylinder(h=largeflange, d=largeholesize, center=true);

        translate([-largeholes/2, -largeholes/2, largeflange/2])
        cylinder(h=largeflange, d=largeholesize, center=true);

        //Cut each smallsize hole individually.
        translate([smallholes/2, smallholes/2, largeflange/2])
        cylinder(h=largeflange, d=smallholesize, center=true);

        translate([-smallholes/2, smallholes/2, largeflange/2])
        cylinder(h=largeflange, d=smallholesize, center=true);

        translate([smallholes/2, -smallholes/2, largeflange/2])
        cylinder(h=largeflange, d=smallholesize, center=true);

        translate([-smallholes/2, -smallholes/2, largeflange/2])
        cylinder(h=largeflange, d=smallholesize, center=true);
                } //difference()
} //else if (holeaccess=="Flange")
```

I look forward to seeing what you come up with!

[Assistant]
vents_simple4.scad:
```
/*
    INTRODUCTION

Fan adaptor in scad.

Versions:
1.11    Played around with a module for the flange. Works fine, but some more understanding is needed.
1.1.    Aiming for a more complex version now. I will try and use IF statements to choose between having a lower flange with holes going through the inside or not. Essentially emulating the thruholes and no holes versions of the SWorks files. Geometry still very simple and unrefined. There is a lot of repetition, I should get the hang of using modules and functions I guess.
1.      Very simple, two flanges, cowling, and no special treatment of lower flange holes.

Initial values are 120 to 80.

Very basic appearance at the moment, just testing out the software and getting a feel for it. I may tidy up in later versions and as I learn more about the software.
*/

/*  BASIC SETUP  */
//Select type option. Cowling: Small fan screws accessed through the cowling. External: Small fan screws accessed from outside of the adaptor. Customiser makes the "Cowling" option look messy, but they are fine once created. Flange: A simple flat plate with mounting holes for large and small size but no cowling. Very inefficient flow but a very low profile.
holeaccess="Cowling"; //[Cowling,External,Flange]

//Smoothing of cylindrical faces (Can be ignored under most circumstances)
$fn = 80;

/*  VARIABLES  */
//Nominal fan sizes
//Nominal size of the smaller fan
smallsize=80;
//Nominal size of the larger fan. It is possible to choose the same size for both. This can lead to funky results sometimes.
largesize=120;

//Flange thicknesses
//Small side flange thickness
smallflange=3; //[1:0.2:6]
//Large side flange thickness (flange thickness used for the "Flange" option above)
largeflange=4; //[1:0.2:6]

//Cowling size
//Total height is cowling height plus the flange thicknesses.
//Thickness of the cowling wall
wallthickness=2; //[1:0.2:5]
//Height of the cowling, taller generally leads to better airflow. Total height will be this plus flange thicknesses.
cowlingheight=30;

/*
Mounting hole spacing and size
Size is usually pretty uniform (4.5 mm) due to using standard screws however for smaller sizes the screw holes are likely smaller
*/
//Spacing
//Small fan side mounting hole spacing
smallholes=71.5;
//Large fan side mounting hole spacing
largeholes=105;
//Size
//Diameter of the mounting holes on the small fan side
smallholesize=4.5; //[2:0.25:6]
//Diameter of the mounting holes on the large fan side
largeholesize=4.5; //[2:0.25:6]

/*  MODULES  */
module flange (size_fan,thick_wall,thick_flange,space_mount,size_mount) {
/*
    Creates a flange with or without mounting holes cut.

    VARIABLES
size_fan:       The given nominal size of the fan
thick_wall:     The cowling wall thickness
thick_flange:   The thickness of the flange
space_mount:    The spacing between mounting holes. If 0 then no holes will be cut.
size_mount:     The diameter of the mounting holes
*/

//OPERATION
    //difference() to perform subtractive operations on the base flange piece
    difference(){
        //translate() half flange thickness from initial centre position.
        //This ensures the base small flange is sitting at z=0 on the XY plane.
        translate([0,0,thick_flange/2])
        //Uncut flange shape.
        cube(size=[size_fan+thick_wall*2, size_fan+thick_wall*2, thick_flange], center=true);

        //Cut fan hole
        translate([0,0,thick_flange/2])
        //Hole shape removed by the difference() operation
        cylinder(h=thick_flange, d=size_fan, center=true);

        //Check for mounting hole requirement
        if (space_mount>0) {
            //Cut each hole individually.
            //I haven't yet found a pattern command and mirror doesn't copy as far as I can see.
            //This way will suffice for now.
            translate([space_mount/2, space_mount/2, thick_flange/2])
            cylinder(h=thick_flange, d=size_mount, center=true);

            translate([-space_mount/2, space_mount/2, thick_flange/2])
            cylinder(h=thick_flange, d=size_mount, center=true);

            translate([space_mount/2, -space_mount/2, thick_flange/2])
            cylinder(h=thick_flange, d=size_mount, center=true);

            translate([-space_mount/2, -space_mount/2, thick_flange/2])
            cylinder(h=thick_flange, d=size_mount, center=true);
        } // if (space_mount>0)

        else { /*do nothing*/ } // else

    } // difference
} // module flange

/*
    MODEL CODE
    Starts with an if statement to distinguish between type choices.
    holeaccess variable is user choice.
        Choices are:
        1. Cowling:     Small side hole access from inside the cowling
        2. External:    Small side access from outside the adaptor
        3. Angled:      With an angle between flanges. Hole access is as external.
*/
if (holeaccess=="Cowling") {
/*
    MATHS
*/
//Calculate boss and countersink sizes
smallholeboss=smallholesize*3;
smallholecountersink=smallholesize*1.75;

//difference() to subtract the inner parts and mounting holes from a solid geometry.
difference(){
/*
union() command to join cowling and flanges together and add small side hole bosses.
    Lower flange built centred on the xy plane at z=0
    Cowling built centrally on top of the lower flange
    Upper flange built centrally on top of the cowling

Create geometry:
1. lower flange
2. cowling
3. lower mounting hole bosses
4. upper flange
*/
    union(){
    //1. Lower flange
        translate([0,0,smallflange/2])
        //Uncut flange shape. Centred for ease. The position uses basic maths.
        cube(size=[smallsize+wallthickness*2, smallsize+wallthickness*2, smallflange], center=true);

    //2. Cowling
        translate([0,0,smallflange+cowlingheight/2])
        //tapered cylinder for cowling
        //difference to other tapered cylinder
        cylinder(h=cowlingheight, r1=smallsize/2+wallthickness, r2=largesize/2+wallthickness, center=true);

    //3. Lower mounting hole bosses
        /*
        Extruding the mounting hole bosses.
        I don't know of a way to extrude to a surface, so for now will do it this way.
        Mirror seems to not have a copy option, so I have to recreate each boss for each corner. Again, there is probably a better way to do it, but I will have to learn it.
        */
        translate([smallholes/2,smallholes/2, (cowlingheight+smallflange)/2])
        cylinder(h=cowlingheight+smallflange, d=smallholeboss, center=true);

        translate([-smallholes/2,smallholes/2, (cowlingheight+smallflange)/2])
        cylinder(h=cowlingheight+smallflange, d=smallholeboss, center=true);

        translate([smallholes/2,-smallholes/2, (cowlingheight+smallflange)/2])
        cylinder(h=cowlingheight+smallflange, d=smallholeboss, center=true);

        translate([-smallholes/2,-smallholes/2, (cowlingheight+smallflange)/2])
        cylinder(h=cowlingheight+smallflange, d=smallholeboss, center=true);

    //4. Upper flange
        translate([0,0,smallflange+cowlingheight])
        flange(largesize,wallthickness,largeflange,largeholes,largeholesize);
    } //union

/*
Remove inner geometry:
1. lower flange fan hole
2. cowling
3. lower mounting holes
4. lower mounting hole countersink
*/
    //1. Lower flange fan hole
        translate([0,0,smallflange/2])
        //Uncut flange shape. Centred for ease. The position uses basic maths.
        cylinder(h=smallflange, d=smallsize, center=true);

    //2. Cowling
        translate([0,0,smallflange+cowlingheight/2])
        //tapered cylinder for cowling
        //difference to other tapered cylinder
        cylinder(h=cowlingheight, d1=smallsize, d2=largesize, center=true);

    //3. lower mounting holes
        /*
        Cutting the mounting holes.
        Mirror seems to not have a copy option, so I have to recreate each hole for each corner. Again, there is probably a better way to do it, but I will have to learn it.
        */
        translate([smallholes/2,smallholes/2,(smallflange+cowlingheight+largeflange)/2])
        cylinder(h=smallflange+cowlingheight+largeflange, d=smallholesize, center=true);

        translate([-smallholes/2,smallholes/2,(smallflange+cowlingheight+largeflange)/2])
        cylinder(h=smallflange+cowlingheight+largeflange, d=smallholesize, center=true);

        translate([smallholes/2,-smallholes/2,(smallflange+cowlingheight+largeflange)/2])
        cylinder(h=smallflange+cowlingheight+largeflange, d=smallholesize, center=true);

        translate([-smallholes/2,-smallholes/2,(smallflange+cowlingheight+largeflange)/2])
        cylinder(h=smallflange+cowlingheight+largeflange, d=smallholesize, center=true);

    //4. lower mounting hole countersink
        /*
        Cutting the mounting hole counter sinks.
        Mirror seems to not have a copy option, so I have to recreate each countersink for each corner. Again, there is probably a better way to do it, but I will have to learn it.
        */
        translate([smallholes/2,smallholes/2, (cowlingheight+largeflange)/2+smallflange])
        cylinder(h=cowlingheight+largeflange, d=smallholecountersink, center=true);

        translate([-smallholes/2,smallholes/2, (cowlingheight+largeflange)/2+smallflange])
        cylinder(h=cowlingheight+largeflange, d=smallholecountersink, center=true);

        translate([smallholes/2,-smallholes/2, (cowlingheight+largeflange)/2+smallflange])
        cylinder(h=cowlingheight+largeflange, d=smallholecountersink, center=true);

        translate([-smallholes/2,-smallholes/2, (cowlingheight+largeflange)/2+smallflange])
        cylinder(h=cowlingheight+largeflange, d=smallholecountersink, center=true);

} //difference
} //if

else if (holeaccess=="External") {
/*
1. Begin by revolving the shape of the cowling.
2: Add the lower and upper flanges using the flange() module

1. Revolve the cowling
Draw revolved polygon shape
This requires a polygon following points inside a rotate_extrude
*/

    rotate_extrude(angle=360, convexity=10)
        polygon(points=[[smallsize/2,smallflange],
        [(smallsize/2)+wallthickness,smallflange],
        [(largesize/2)+wallthickness,cowlingheight+smallflange],
        [largesize/2,cowlingheight+smallflange]]);

    //2. Use modules to create the flanges
    //Lower (smaller) flange
    flange(smallsize,wallthickness,smallflange,smallholes,smallholesize);

    //Upper (larger) flange
    translate([0,0,smallflange+cowlingheight])
    flange(largesize,wallthickness,largeflange,largeholes,largeholesize);
} //else if (holeaccess=="External")

else if (holeaccess=="Flange") {
/*
1. Create blank flange according to "largesize"
2. Cut "smallsize" hole into flange blank
3. Drill large size holes (largeholes, largeholesize)
4. Drill small size holes (smallholes, smallholesize)
*/
//1. Create blank flange according to "largesize"
//difference() to perform subtractive operations on the base flange piece
    difference(){
        //translate() half flange thickness from initial centre position.
        //This ensures the base small flange is sitting at z=0 on the XY plane.
        translate([0,0,largeflange/2])
        //Uncut flange shape.
        cube(size=[largesize+largeflange*2, largesize+largeflange*2, largeflange], center=true);
        //2. Cut "smallsize" hole into flange blank
        //Cut fan hole
        translate([0,0,largeflange/2])
        //Hole shape removed by the difference() operation
        cylinder(h=largeflange, d=smallsize, center=true);

//3. Drill large size holes (largeholes, largeholesize)
//4. Drill small size holes (smallholes, smallholesize)
    //Cut each largesize hole individually.
        translate([largeholes/2, largeholes/2, largeflange/2])
        cylinder(h=largeflange, d=largeholesize, center=true);

        translate([-largeholes/2, largeholes/2, largeflange/2])
        cylinder(h=largeflange, d=largeholesize, center=true);

        translate([largeholes/2, -largeholes/2, largeflange/2])
        cylinder(h=largeflange, d=largeholesize, center=true);

        translate([-largeholes/2, -largeholes/2, largeflange/2])
        cylinder(h=largeflange, d=largeholesize, center=true);

        //Cut each smallsize hole individually.
        translate([smallholes/2, smallholes/2, largeflange/2])
        cylinder(h=largeflange, d=smallholesize, center=true);

        translate([-smallholes/2, smallholes/2, largeflange/2])
        cylinder(h=largeflange, d=smallholesize, center=true);

        translate([smallholes/2, -smallholes/2, largeflange/2])
        cylinder(h=largeflange, d=smallholesize, center=true);

        translate([-smallholes/2, -smallholes/2, largeflange/2])
        cylinder(h=largeflange, d=smallholesize, center=true);
                } //difference()
} //else if (holeaccess=="Flange")
```


[User]
Okay, I'd like to design a screwable box, and I'm looking for an OpenSCAD file that's highly parametric. I've seen a few examples, but I want to be able to easily adjust things like the size, screw thread density, and the gap between the inner and outer parts.

Here’s the basic idea: The box consists of two cylindrical "cups" that screw together. One cup has a smaller diameter and acts as the interior, while the other is slightly larger and fits over it. Both cups will have screw threads around the outside, but one will be internal (as in a nut) and one external (as in a bolt)

Here's a breakdown of the parameters I'd like to control:

*   **`h`**: The overall height of the box, excluding the thread overlap.
*   **`nw`**:  The number of "starts" on the screw thread. A value of 1 is a standard screw thread, 2 would be a double helix, and so on. This affects how far you turn the top to get a certain amount of travel.
*   **`cr`**:  The radius of the main cylinder of the inner cup, *before* threads are added.
*   **`w`**: The radial offset or "thickness" of the thread. This should be adjustable, it would affect both the size of the screw thread and overall diameter of each half.
*   **`t`**: The thickness of the walls of both cups, I imagine this would mostly be for strength.
*   **`g`**:  An small vertical gap between the inner and outer cup at the top.
*   **`gap`**: The radial gap between the outside of the inner cup and the inside of the outer cup, this might need to be a small amount larger than the tolerance of your printer.
*   **`step`**:  The angular increment in degrees when generating screw threads. Lower numbers will result in denser and therefore more detailed threads, higher values will speed up rendering and reduce details.
*   **`max`**: This will mostly be set automatically by the `step` parameter; it's `360-step` to specify where the threads should end.

I'm imagining that the threads are created using a for loop to rotate and extrude small circles along a helical path, and each cup has a difference operation to cut away the core.

So in short, I need:

*   Two cylindrical parts that screw together
*   Thread generation via linear extrudes and rotation, that is, no use of any thread libraries
*   All parameters described above
*   A comment indicating that the design has been tested and is functional, that indicates the tolerance used for the `gap` and the infill/layer settings.

I'm *not* looking for any specific libraries like MCAD or BOSL for this one. This is also a fairly simple design, so I don't see a need for any "helpers" from other libraries, either.

I'm looking for a simple parametric script that I can easily adjust. Could you help me with this?

[Assistant]
screwable-box.scad:
```
// Parametric screwable box

h=100;
nw=1;
cr=40;
w=30;
t=1;
g=0.01;
gap=0.5;	// gap between inner and outer

step=45; // degrees
max=360-step;

module cup(r2,h) {
	echo("cup radius ",r2);
	difference() {
		for (a = [0:step:max]) {
			rotate([0,0,a]) linear_extrude(height = h, center = false, convexity = 10, twist = nw*360)
				translate([w, 0, 0]) circle(r = r2);
			}
		difference() {
			for (a = [0:step:max]) {
				rotate([0,0,a]) linear_extrude(height = h+g, center = false, convexity = 10, twist = nw*360)
					translate([w, 0, 0]) circle(r = r2-t);
				}
			cylinder(r=r2+w,h=t);
			}
		}
	}

translate([-cr-w-5,0,0]) cup(cr,h);
translate([cr+w+5,0,0]) cup(cr+t+gap,h+t+g);
```


[User]
Okay, I'm looking for an OpenSCAD design for a toothpaste tube key, and I'd like it to be fully parametric so I can easily adjust it for different tube sizes. I have a basic design in mind, but I want to make it a little more robust and flexible.

Here's what I'm thinking:

**Core Functionality:**
The key should have two main parts: a handle section for grip and a barrel section that clamps onto the tube. The barrel section will have a slot to roll the tube.

**Parameters I Need to Control:**
*   **`barrel_diameter`**: The diameter of the barrel that clamps on the toothpaste tube.
*   **`barrel_flats`**: The thickness/height of the flat section of the barrel where the handle attaches, as well as how wide the key will effectively be when you're done winding up the tube. This also helps determine the handle cross-section.
*  **`slot_width`**: The width of the slot in the barrel for the rolled-up toothpaste tube.
*   **`slot_length`**: The length of the slot in the barrel. This influences how much tube can be rolled up at once.
*   **`key_width`**: The overall width of the handle.
*   **`key_height`**: The overall height of the handle.
*   **`hole_diameter`**: The diameter of the hole that will be in the handle. This will usually be a hole on either side of the handle, for strength.
*   **`overlap`**: A small tolerance value to ensure parts fit correctly.

**Design Details I'd Like Included:**
*   The handle should have a solid, comfortable feel. I’d like a rounded, sort of oval, cross-section for the handle which is flat on the bottom where it connects to the barrel.
*   I'd like two holes going through the handle, from top to bottom, as shown in the example code. I guess this is for strength but it is also what the handle feels like in my hand from using one like this before. I guess we need to cut the holes out of the handle.
*   The barrel should be able to grip the tube effectively. I'd like a slot cut into the circular barrel, so that the user can slide the tube in.
*   I want the design to be printable without supports, which means avoiding overhangs greater than 45 degrees.
*   I'd also like to be able to adjust the number of `fn` in the OpenSCAD design.

**Libraries:**
I don't need any specialized libraries, I think this should be able to be constructed from the basic primitives.

**What I Expect:**
I'm looking for a single OpenSCAD file that defines a module for the toothpaste tube key, with all the parameters I've mentioned. I'd expect the main part of the script to instantiate the module with some default values, so it generates a default example design. I should be able to recompile the design after changing the parameters.

Here is my design which is close to what I want:
```
//////
// Tooth-paste/Paint Tube Key
//
// http://www.thingiverse.com/thing:21410
// By: Alan Yates <thingiverse@alanyates.com>
//////

// geometry
barrel_diameter = 9.0;
barrel_flats = 8.0;
slot_width = 2.5;
slot_length = 50.0;
key_width = 35.0;
key_height = 15.0;
hole_diameter = 8;

// tolerances
overlap = 1;
$fn = 50;

translate([0, 0, barrel_flats/2])
	rotate(-90, [0, 0, 1]) rotate(-90, [1, 0, 0])
		tube_key(barrel_diameter, barrel_flats, slot_width, slot_length, key_width, key_height, hole_diameter);

module tube_key(bd, bf, sw, sl, kw, kh, hd) {
	union() {
		translate([0, 0, kh/2])
			rotate(90, [1, 0, 0]) {
				difference() {
					hull() {
						translate([kw/2 - kh/2, 0, 0])
							cylinder(r = kh/2, h = bf, center = true);
						translate([- kw/2 + kh/2, 0, 0])
							cylinder(r = kh/2, h = bf, center = true);
					}
#					translate([-kh/2, 0, -bf/2-overlap])
						cylinder(r = hd/2, h = bf + 2*overlap);
#					translate([kh/2, 0, -bf/2-overlap])
						cylinder(r = hd/2, h = bf + 2*overlap);
#					translate([0, -4*kh/5, -bf/2-overlap])
						cylinder(r = kh/2, h = bf + 2*overlap);
				}
			}
		translate([0, 0, kh - overlap])
			difference() {
				cylinder(r = bd/2, h = sl + bd);

#				translate([-sw/2, -bd/2 - overlap, bd/2])
					cube([sw, bd + 2*overlap, sl]);
#				translate([-bd/2 - overlap, bf/2, -overlap])
					cube([bd + 2*overlap, bd/2, sl + bd + 2*overlap]);
#				translate([-bd/2 - overlap, -bf/2 - bd/2, -overlap])
					cube([bd + 2*overlap, bd/2, sl + bd + 2*overlap]);
			}
	}
}
```
I’m looking forward to seeing your solution!

[Assistant]
toothpaste-key.scad:
```
//////
// Tooth-paste/Paint Tube Key
//
// http://www.thingiverse.com/thing:21410
// By: Alan Yates <thingiverse@alanyates.com>
//////

// geometry
barrel_diameter = 9.0;
barrel_flats = 8.0;
slot_width = 2.5;
slot_length = 50.0;
key_width = 35.0;
key_height = 15.0;
hole_diameter = 8;

// tolerances
overlap = 1;
$fn = 50;

translate([0, 0, barrel_flats/2])
	rotate(-90, [0, 0, 1]) rotate(-90, [1, 0, 0])
		tube_key(barrel_diameter, barrel_flats, slot_width, slot_length, key_width, key_height, hole_diameter);

module tube_key(bd, bf, sw, sl, kw, kh, hd) {
	union() {
		translate([0, 0, kh/2])
			rotate(90, [1, 0, 0]) {
				difference() {
					hull() {
						translate([kw/2 - kh/2, 0, 0])
							cylinder(r = kh/2, h = bf, center = true);
						translate([- kw/2 + kh/2, 0, 0])
							cylinder(r = kh/2, h = bf, center = true);
					}
#					translate([-kh/2, 0, -bf/2-overlap])
						cylinder(r = hd/2, h = bf + 2*overlap);
#					translate([kh/2, 0, -bf/2-overlap])
						cylinder(r = hd/2, h = bf + 2*overlap);
#					translate([0, -4*kh/5, -bf/2-overlap])
						cylinder(r = kh/2, h = bf + 2*overlap);
				}
			}
		translate([0, 0, kh - overlap])
			difference() {
				cylinder(r = bd/2, h = sl + bd);

#				translate([-sw/2, -bd/2 - overlap, bd/2])
					cube([sw, bd + 2*overlap, sl]);
#				translate([-bd/2 - overlap, bf/2, -overlap])
					cube([bd + 2*overlap, bd/2, sl + bd + 2*overlap]);
#				translate([-bd/2 - overlap, -bf/2 - bd/2, -overlap])
					cube([bd + 2*overlap, bd/2, sl + bd + 2*overlap]);
			}
	}
}
```


[User]
Okay, I'm looking to create a mold with a series of offset circular holes, similar to a honeycomb pattern, but arranged in rows and columns. I have a basic idea from an existing SCAD file, but I need a more flexible and robust parametric design. I want to be able to easily adjust things like the spacing, the depth of the mold, and the number of holes in both the rows and columns. The existing file, `hole_mold.scad` provides a starting point but it needs some improvements.

Here's what I need in the new OpenSCAD file:

1.  **Parametric Design:** The design should be fully parametric, allowing me to define:
    *   `hole_diameter`: The diameter of each hole.
    *   `mold_height`: The overall height of the mold (and the depth of the holes)
    *   `rows`: The number of rows of holes.
    *   `cols`: The number of columns of holes.
    *   `row_spacing`: The distance between the centers of holes in adjacent rows. I would prefer to specify the spacing in this case, and not rely on multiplying the diameter and adding to it as in the original code.
    *   `col_spacing`: The distance between the centers of holes in adjacent columns. This should be similarly defined as above.
    *   `shell_thickness`: The thickness of the mold's outer walls.

2.  **Offset Hole Arrangement:** The holes should be offset in a staggered pattern, as in the original `hole_mold.scad`. Specifically, every other row of holes needs to be shifted along the row axis to achieve this effect. In the original file, if the `rows` variable is 1, then no offsetting takes place. This should be corrected so that even if the variable `rows` is equal to 1, an offset occurs. This means that the row offset will be half the column spacing.

3.  **Mold Construction:** The mold should be created by subtracting the hole cylinders from a solid shell. I would like a Minkowski operation on the outline of the cylinder and the cylinder itself with a radius defined by `shell_thickness` to make the outer shell of the mold as in the original `hole_mold.scad`.

4.  **Variable Precision:** I want to be able to adjust the precision of the circles. The original file used `$fa=6`. I'd like to have a variable called `$circle_segments`, allowing me to use `$fa = 360 / $circle_segments;` to increase or decrease the resolution.
    *   If this is not possible I'd like the default value to be 36.

5.  **Comments:** Please include comments throughout the code to explain what each section does.

I want this to be a self-contained OpenSCAD file; I don't need any additional external library dependencies.

In summary, I need a clean, parametric OpenSCAD file for creating molds with offset circular holes that I can easily configure using the parameters I've specified. Thank you!

[Assistant]
hole_mold.scad:
```
/*
 * Parametric Hole Mold
 *
 * By: Mike Creuzer <thingiverse@creuzer.com>
 *
 * http://www.thingiverse.com/thing:22006
 *
 * Version 1.0
 */

// everything is in mm so if you want to use inches, use the following conversion
//inchestomm = 25.4 ;

height    = 5;
// Remember the diameter is twice the radius (full circle size)
diameter = 25; // Remember the diameter is twice the radius (full circle size)

rows   = 1; // Number of rows to have
cols    = 2; // Number of cols to have

difference() {
	shell();
	holes(2); // make 'em taller so we cut right through, otherwise we end up with a thin shell
}

// make the frame of the mould
module shell()
{
	minkowski()
	{
		hull() {
			holes();
		}
		cylinder(r=2);
	}
}

// calculate the series of holes needed to make the mold
module holes( multiplier = 1 )
{
for ( i = [1 : rows] )
{

	for ( j = [1 : cols] )
	{
		if(i % 2 == 1)
		{
			translate([(2 * diameter + 1) * i -  i   , ((2 * diameter + 2) * j) + diameter, 0])
				cylinder(r =diameter, h = height * multiplier, $fa=6, center = true);

		}else
		{
			translate([(2 * diameter + 1) * i - i  , (2 * diameter + 2) * j , 0])
				cylinder(r =diameter, h = height * multiplier, $fa=6, center = true);

		}
	}
}

}
```


[User]
Okay, I've got this idea for a 3D printable project based on a magical device from a video game - the Mini-Hakkero from Touhou Project. I've found an old SCAD file that gets the basic shape, but it's a bit clunky and hard to customize. I'd like your help creating a new version that's more flexible and easier to use.

Here's what I'm envisioning:

**Core Design:**

*   **Hakkero Body:** The base of the Hakkero is an octagon with a central cavity. The current code uses an octagon function, a ring function, and a difference operation. I'd like to keep that basic shape, but I need it to be parametric:
    *   `hakkero_width`: The overall width of the octagon.
    *   `hakkero_height`: The overall height of the Hakkero.
    *   `inner_cavity_width_offset`: How much smaller the inner cavity is than the outer octagon.
    *   `inner_cavity_height`: How high the inner cavity goes; this should be less than the overall `hakkero_height`.
    *   `ring_radius`: The radius of the central ring feature.
    *   `ring_height`: The height of the central ring.
    *   `ring_thickness`: The thickness of the central ring.
*   **Ba-gua Symbols:** There are eight Ba-gua symbols around the central ring, and they should be part of a separate, inlay piece (more on that in a bit). The current code manually specifies each one, but this should be modular and take the parameters of:
    *   `symbol_placement_radius`: The radius at which the Ba-gua symbols are placed (should be smaller than the main Hakkero's width).
    *   `symbol_rod_width`: The width of the individual "rods" in the symbol.
    *   `symbol_rod_height`: The height of each rod.
    *   `symbol_rod_depth`: The depth of each rod.
*   **Yin-Yang Symbol:** There is a Yin-Yang symbol in the center of the device that should be parametric.
    *   `yingyang_width`: The overall width of the yin-yang symbol.
    *   `yingyang_height`: The height of the Yin-Yang, which should probably be the same as the central ring.

**Modularity & Parametric Design:**

*   **Separate Inlay:** I need to be able to print the main body and an inlay separately. The inlay piece should contain the Ba-gua symbols and a simplified version of the central ring. The inlay should have a slight offset on the Z-axis (thickness) to sit flush with the main body when placed.
*   **No Hardcoded Values:** I want as many values as possible to be parametric and adjustable. It should be easy to change the sizes, positions, and numbers of features through variables, not magic numbers.
*   **Clean Code:** The current code has some confusing elements and could be organized better for readability.

**Specific Requests:**

1.  **Create a module for the octagon** with the specified parameters.
2.  **Create a module for the ring** with the specified parameters.
3.  **Create a module for the Ba-gua symbol** with parameters for size and position. The current code uses an array to specify the rod placement, and this should stay the same.
4.  **Create a module for the Yin-Yang symbol** with specified parameters.
5.  **Create two main modules:**
    *   `hakkero_body()`: Creates the main body, with an inner cavity, a space for the central ring, and an area for the Ba-gua inlay.
    *   `hakkero_inlay()`: Creates the inlay piece that contains the Ba-gua symbols and the central ring element.
6.  **Use clear and consistent naming conventions** for variables and modules.
7.  **Use comments** to explain each part of the code.
8.  **The code should be set up to print both pieces**; meaning the inlay should be slightly recessed in the z direction from the body for easy printing.
9.  **Make sure to use `$fn` for smooth circles.**
10. **I'm not using any third party libraries,** so I don't need them included.

I'd like to avoid using any libraries for this project, just the built in OpenSCAD functions.

Can you help me create this updated OpenSCAD file?

[Assistant]
Hakkero.scad:
```
// Coded by Ben Rockhold in 2012
// Inspired by the Touhou Project

// This is the first revision of the code, and it's 5am, so it may not be very stable.
// I am not liable for magical energy explosions caused by the mis-handling of this device.

// If you have a multiple-color capable printer, you should be able to print out the hakkero_body and the hakkero_inlay seperately, and get the two colors needed for accurate reproduction.

hakkero_width = 100;
hakkero_height=30;
$fn=40;

// Comment out the component you do not need when rendering, or it will take forever and then fail!
hakkero_body(hakkero_width,hakkero_height);
hakkero_inlay();

module hakkero_body(width,height){
	color("DimGrey")render()rotate([0,0,22.5]){
		difference(){
			octagon(width,height);
			translate([0,0,height-1])octagon(width-10,6);
			translate([0,0,height-2])ring(width/4-5,3,2.5);
			// Difference out our ba-gua
			translate([0,0,height-2.5])for(i=[
			//   Arrays for Ba_gua
				[1,0,1,0],
				[2,1,1,1],
				[3,0,0,1],
				[4,0,0,0],
				[5,1,0,1],
				[6,1,1,0],
				[7,0,1,1],
				[8,1,0,0]
			]){
				rotate([0,0,45*i[0]+22.5])Ba_gua(i);
				rotate([0,0,-22.5])translate([0,0,1])yingyang(30);
			}
		}
	}
}
//rotate([0,0,180])color("Black")yingyang(30);

module hakkero_inlay(){
	color("White"){
		rotate([0,0,22.5])translate([0,0,hakkero_height-2.5])
					for(i=[
					//   Arrays for Ba_gua
						[1,0,1,0],
						[2,1,1,1],
						[3,0,0,1],
						[4,0,0,0],
						[5,1,0,1],
						[6,1,1,0],
						[7,0,1,1],
						[8,1,0,0]
					]){
						rotate([0,0,45*i[0]+22.5])Ba_gua(i);
				}
		translate([0,0,hakkero_height-2]){
			ring(hakkero_width/4-5,1.5,2.5);
			yingyang(30);
		}
	}
}

module yingyang(width){
	render(){
		translate([0,-width/4,0])cylinder(r=width/8,h=2,center=true);
		difference(){
			translate([0,width/4,0])cylinder(r=width/4,h=2,center=true);
			translate([0,width/4,0])cylinder(r=width/8,h=4,center=true);
		}
		difference(){
			cylinder(r=width/2,h=2,center=true);
			translate([width/2,0,0])cube([width,width,4],center=true);
			translate([0,-width/4,0])cylinder(r=width/4,h=3,center=true);
			translate([0,width/4,0])cylinder(r=width/8,h=4,center=true);
		}
	}
}

module Ba_gua(number){
	render(){
		difference(){
			translate([hakkero_width/2-10,0,0])for(i=[0:2]){
				translate([-7*i,0,0])cube([5,30,5],center=true);
			}
			translate([0,0,-3]){
				rotate([0,0,-112.5])translate([-2.5,0,0])cube([10,hakkero_width/2,6]);
				rotate([0,0,22.5])translate([0,-2.5,0])cube([hakkero_width/2,10,6]);
			}
			// Logic for dividing rods
			if (number[3]){
				translate([hakkero_width/2-10,0,0])cube(6,center=true);
			}
			if (number[2]){
				translate([hakkero_width/2-17,0,0])cube(6,center=true);
			}
			if (number[1]){
				translate([hakkero_width/2-24,0,0])cube(6,center=true);
			}
		}
	}
}

// Small Modules

module ring(radius,height,thickness){
	render()difference(){
		cylinder(r=radius,h=height);
		cylinder(r=radius-thickness,h=height);
	}
}

module octagon(width,height){
	cylinder(r=width/2,h=height,$fn=8);
}
```


[User]
Okay, I'm looking to design a parametric spool holder for my 3D printer, and I've seen some designs that use bearings. I'd like to be able to customize it for different spool sizes and bearing/hardware options. I've got an existing OpenSCAD file I've been working with as a starting point, called "PrintableSpool_Holder.scad", but I'm struggling to make it truly parametric and robust. I'd like your help in designing a better version.

Here's what I'm looking for in the design:

**Core Functionality:**

*   A spool holder that sits on a flat surface (like a desk or shelf).
*   The design should use bearings on which the spool will rotate.
*   It should be parametric, allowing me to easily adjust for different spools and hardware.

**Key Parameters I want to control:**

*   **Spool Dimensions:**
    *   `spool_wall`: Thickness of the spool's side walls.
    *   `spool_width`: Total width of the spool (outer edge to outer edge).
    *   `spool_diameter`: Outer diameter of the spool (where the filament is wrapped).
    *   `hole_diameter`: Diameter of the hole in the center of the spool. (Although it's currently unused in my SCAD, I would like this as an option for future use).
*   **Hardware Dimensions:**
    *   `bearing_diameter`: Outer diameter of the bearing.
    *   `bearing_thickness`: Thickness of the bearing.
    *   `bolt_diameter`: Diameter of the bolt to secure the bearing.
*   **Holder Dimensions:**
    *   `holder_base_length`: Length of the base of the holder. This determines stability.
    *   `holder_base_height`: Thickness/height of the base.
    *   `holder_wall`: Thickness of plastic around the bearing capture.

**Design Considerations:**

*   **Stability:** I want the base to be sufficiently wide and long to keep the spool from toppling over, even when the spool isn't perfectly balanced or it's nearly empty.
*   **Bearing Support:** I'd like the bearing to be held securely on each side. The existing code uses a combination of cylinders and cubes to achieve this, which could be improved upon.
*   **Bolt Holes:** The design needs clearance for the bolt securing the bearing.
*   **Customizability:** I want to easily adjust the dimensions without breaking the design or ending up with impossible geometry.
*   **Ease of Use:** I need a code structure that is easy to understand and modify.
*   **Printability:** Should be easily printable with FDM 3D printing with minimal supports, if any. The holder should be printed in a way that the base is flat on the print bed.

**Libraries:**

* I'd like to use the `BOSL2` library to handle some of the more complex design elements, if possible.

Essentially, I need a flexible OpenSCAD model where I can adjust the dimensions, and the design adapts automatically, providing good stability and proper bearing support.

Can you help me build an improved parametric OpenSCAD file from my starting point, considering the above request?

[Assistant]
PrintableSpool_Holder.scad:
```
//Created by Cid Vilas
//http://www.flickr.com/CidVilas/

//################################################################################
//##                                                                            ##
//##                PLEASE READ INSTRUCTIONS BEFORE MODIFYING                   ##
//##                                                                            ##
//################################################################################

//Specification of the Spool Dimensions:
//		spool_wall = The thickness of the walls of the spool
//		spool_width = The dimension of the spool from outer side to opposite outer side
//		spool_diameter = The diameter of the outer edges of the spool body, not the
//					filament outer diameter (The filament should not extend
//					past this dimension)
//		hole_diameter = The diameter of the hole inside the spool (Currently
//					unused.  Included for just to be thorough)

//Specification of the Hardware:
//		bearing_diameter = The outer diameter of the bearing.  (If you plan on adding
//						a fender washer or lip in the plastic, be sure to offset here)
//		bearing_thickness = The side to side dimension of the bearing.  (If you plan on
//						adding washers, be sure to add to the dimensions)
//		bolt_diameter = This is the diameter of the bolt to be used to secure the bearing
//					and washers to the spool holder.

//Specification of the Spool Holder
//		holder_base_length = In order to properly fit your spool, and maintain stability
//						of the spool holder, be sure this dimension is as wide as
//						possible.  If this value is too small, the spool holder
//						will compare to a football balanced on a Golf Tee.
//		holder_base_height = The thickness of the base of the stand.  Increase for
//						durability, but this will increase pastic usage.
//		holder_wall = This is the thickness of the plastic around the bearing capture.

//NOTE:  The remaining values are not for customization of the stand.  They are used for
//		design.  Adjust at your own risk!

spool_wall = 5;
spool_width = 90 - spool_wall;
spool_diameter = 162.5;
hole_diameter = 37.5;

bearing_diameter = 19;			//Bearing + Fender = 13 + 6 = 19
bearing_thickness = 7;			//Bearing + 2xWasher = 5 + (2) = 7
bolt_diameter = 4.5;

holder_wall = 5;
holder_base_height = 5;
holder_base_width = spool_width + holder_wall;
holder_base_length = 100;

holder_bearing_width = bearing_diameter;
bearing_radius = spool_diameter / 2 + bearing_diameter / 2;
bearing_degree = acos((holder_base_length / 2) / (bearing_radius));
holder_bearing_height = bearing_radius * sin(-bearing_degree)  + spool_diameter/2;

module spool()
{
	rotate([0, 90, 0])
	difference()
	{
	union()
	{
		color([0.1,0.1,0.1])
		translate([0, 0, spool_width / 2])
		cylinder(r = spool_diameter / 2, h = spool_wall, center = true, $fn = 64);
		color([0.1,0.1,0.1])
		translate([0, 0, -(spool_width / 2)])
		cylinder(r = spool_diameter / 2, h = spool_wall, center = true, $fn = 64);
		color([0.5, 0, 0.7])
		translate([0, 0, 0])
		cylinder(r = spool_diameter / 2 - spool_wall, h = spool_width - spool_wall, center = true);
	}
	union()
	{
		color([0.6, 0.6, 0.6])
		cylinder(r = hole_diameter / 2, h = spool_width + spool_wall + 0.1, center = true);
	}
	}
}

module holder()
{
	color([1, 0, 0])
	translate([0, 0, -spool_diameter / 2])
	difference()
	{
	union()
	{
		translate([0, 0, -holder_base_height / 2])
		cube([spool_width + bearing_thickness + holder_wall * 2,
			holder_base_length,
			holder_base_height], center = true);

		translate([spool_width / 2,
				holder_base_length / 2 - bearing_diameter / 2,
				holder_bearing_height])
		union()
		{
			rotate([0, 90, 0])
			cylinder(r = bearing_diameter / 2, h = bearing_thickness + holder_wall * 2, center = true);

			translate([0, 0, -holder_bearing_height / 2])
			cube([bearing_thickness + holder_wall * 2, bearing_diameter, holder_bearing_height], center = true);
		}
		translate([-spool_width / 2,
				holder_base_length / 2 - bearing_diameter / 2,
				holder_bearing_height])
		union()
		{
			rotate([0, 90, 0])
			cylinder(r = bearing_diameter / 2, h = bearing_thickness + holder_wall * 2, center = true);

			translate([0, 0, -holder_bearing_height / 2])
			cube([bearing_thickness + holder_wall * 2, bearing_diameter, holder_bearing_height], center = true);
		}

		translate([spool_width / 2,
				-(holder_base_length / 2 - bearing_diameter / 2),
				holder_bearing_height])
		union()
		{
			rotate([0, 90, 0])
			cylinder(r = bearing_diameter / 2, h = bearing_thickness + holder_wall * 2, center = true);

			translate([0, 0, -holder_bearing_height / 2])
			cube([bearing_thickness + holder_wall * 2, bearing_diameter, holder_bearing_height], center = true);
		}
		translate([-spool_width / 2,
				-(holder_base_length / 2 - bearing_diameter / 2),
				holder_bearing_height])
		union()
		{
			rotate([0, 90, 0])
			cylinder(r = bearing_diameter / 2, h = bearing_thickness + holder_wall * 2, center = true);

			translate([0, 0, -holder_bearing_height / 2])
			cube([bearing_thickness + holder_wall * 2, bearing_diameter, holder_bearing_height], center = true);
		}

	}
	union()
	{
		translate([0, 0, -holder_base_height / 2])
		cylinder(r = holder_base_length / 6, h = holder_base_height + 0.05, center = true);
		for(i = [0 : 3])
		{
			rotate([0, 0, i * 90])
			translate([holder_base_length / 2, 0, -holder_base_height / 2])
			cylinder(r = holder_base_length / 3.5, h = holder_base_height + 0.05, center = true);
		}
		translate([spool_width / 2,
				holder_base_length / 2 - bearing_diameter / 2,
				holder_bearing_height])
		union()
		{
			rotate([0, 90, 0])
			cylinder(r = bolt_diameter / 2, h = spool_wall + bearing_thickness * 2 + 0.1, center = true);

			rotate([0, 90, 0])
			cylinder(r = bearing_diameter / 2 + 1, h = bearing_thickness, center = true);
		}
		translate([-spool_width / 2,
				holder_base_length / 2 - bearing_diameter / 2,
				holder_bearing_height])
		union()
		{
			rotate([0, 90, 0])
			cylinder(r = bolt_diameter / 2, h = spool_wall + bearing_thickness * 2 + 0.1, center = true);

			rotate([0, 90, 0])
			cylinder(r = bearing_diameter / 2 + 1, h = bearing_thickness, center = true);
		}

		translate([spool_width / 2,
				-(holder_base_length / 2 - bearing_diameter / 2),
				holder_bearing_height])
		union()
		{
			rotate([0, 90, 0])
			cylinder(r = bolt_diameter / 2, h = spool_wall + bearing_thickness * 2 + 0.1, center = true);

			rotate([0, 90, 0])
			cylinder(r = bearing_diameter / 2 + 1, h = bearing_thickness, center = true);
		}
		translate([-spool_width / 2,
				-(holder_base_length / 2 - bearing_diameter / 2),
				holder_bearing_height])
		union()
		{
			rotate([0, 90, 0])
			cylinder(r = bolt_diameter / 2, h = spool_wall + bearing_thickness * 2 + 0.1, center = true);

			rotate([0, 90, 0])
			cylinder(r = bearing_diameter / 2 + 1, h = bearing_thickness, center = true);
		}

	}
	}
}

holder();
//spool();
```
PrintableSpool_Holder.scad:
```
//Created by Cid Vilas
//http://www.flickr.com/CidVilas/

//################################################################################
//##                                                                            ##
//##                PLEASE READ INSTRUCTIONS BEFORE MODIFYING                   ##
//##                                                                            ##
//################################################################################

//Specification of the Spool Dimensions:
//		spool_wall = The thickness of the walls of the spool
//		spool_width = The dimension of the spool from outer side to opposite outer side
//		spool_diameter = The diameter of the outer edges of the spool body, not the
//					filament outer diameter (The filament should not extend
//					past this dimension)
//		hole_diameter = The diameter of the hole inside the spool (Currently
//					unused.  Included for just to be thorough)

//Specification of the Hardware:
//		bearing_diameter = The outer diameter of the bearing.  (If you plan on adding
//						a fender washer or lip in the plastic, be sure to offset here)
//		bearing_thickness = The side to side dimension of the bearing.  (If you plan on
//						adding washers, be sure to add to the dimensions)
//		bolt_diameter = This is the diameter of the bolt to be used to secure the bearing
//					and washers to the spool holder.

//Specification of the Spool Holder
//		holder_base_length = In order to properly fit your spool, and maintain stability
//						of the spool holder, be sure this dimension is as wide as
//						possible.  If this value is too small, the spool holder
//						will compare to a football balanced on a Golf Tee.
//		holder_base_height = The thickness of the base of the stand.  Increase for
//						durability, but this will increase pastic usage.
//		holder_wall = This is the thickness of the plastic around the bearing capture.

//NOTE:  The remaining values are not for customization of the stand.  They are used for
//		design.  Adjust at your own risk!

spool_wall = 5;
spool_width = 90 - spool_wall;
spool_diameter = 162.5;
hole_diameter = 37.5;

bearing_diameter = 19;			//Bearing + Fender = 13 + 6 = 19
bearing_thickness = 7;			//Bearing + 2xWasher = 5 + (2) = 7
bolt_diameter = 4.5;

holder_wall = 5;
holder_base_height = 5;
holder_base_width = spool_width + holder_wall;
holder_base_length = 100;

holder_bearing_width = bearing_diameter;
bearing_radius = spool_diameter / 2 + bearing_diameter / 2;
bearing_degree = acos((holder_base_length / 2) / (bearing_radius));
holder_bearing_height = bearing_radius * sin(-bearing_degree)  + spool_diameter/2;

module spool()
{
	rotate([0, 90, 0])
	difference()
	{
	union()
	{
		color([0.1,0.1,0.1])
		translate([0, 0, spool_width / 2])
		cylinder(r = spool_diameter / 2, h = spool_wall, center = true, $fn = 64);
		color([0.1,0.1,0.1])
		translate([0, 0, -(spool_width / 2)])
		cylinder(r = spool_diameter / 2, h = spool_wall, center = true, $fn = 64);
		color([0.5, 0, 0.7])
		translate([0, 0, 0])
		cylinder(r = spool_diameter / 2 - spool_wall, h = spool_width - spool_wall, center = true);
	}
	union()
	{
		color([0.6, 0.6, 0.6])
		cylinder(r = hole_diameter / 2, h = spool_width + spool_wall + 0.1, center = true);
	}
	}
}

module holder()
{
	color([1, 0, 0])
	translate([0, 0, -spool_diameter / 2])
	difference()
	{
	union()
	{
		translate([0, 0, -holder_base_height / 2])
		cube([spool_width + bearing_thickness + holder_wall * 2,
			holder_base_length,
			holder_base_height], center = true);

		translate([spool_width / 2,
				holder_base_length / 2 - bearing_diameter / 2,
				holder_bearing_height])
		union()
		{
			rotate([0, 90, 0])
			cylinder(r = bearing_diameter / 2, h = bearing_thickness + holder_wall * 2, center = true);

			translate([0, 0, -holder_bearing_height / 2])
			cube([bearing_thickness + holder_wall * 2, bearing_diameter, holder_bearing_height], center = true);
		}
		translate([-spool_width / 2,
				holder_base_length / 2 - bearing_diameter / 2,
				holder_bearing_height])
		union()
		{
			rotate([0, 90, 0])
			cylinder(r = bearing_diameter / 2, h = bearing_thickness + holder_wall * 2, center = true);

			translate([0, 0, -holder_bearing_height / 2])
			cube([bearing_thickness + holder_wall * 2, bearing_diameter, holder_bearing_height], center = true);
		}

		translate([spool_width / 2,
				-(holder_base_length / 2 - bearing_diameter / 2),
				holder_bearing_height])
		union()
		{
			rotate([0, 90, 0])
			cylinder(r = bearing_diameter / 2, h = bearing_thickness + holder_wall * 2, center = true);

			translate([0, 0, -holder_bearing_height / 2])
			cube([bearing_thickness + holder_wall * 2, bearing_diameter, holder_bearing_height], center = true);
		}
		translate([-spool_width / 2,
				-(holder_base_length / 2 - bearing_diameter / 2),
				holder_bearing_height])
		union()
		{
			rotate([0, 90, 0])
			cylinder(r = bearing_diameter / 2, h = bearing_thickness + holder_wall * 2, center = true);

			translate([0, 0, -holder_bearing_height / 2])
			cube([bearing_thickness + holder_wall * 2, bearing_diameter, holder_bearing_height], center = true);
		}

	}
	union()
	{
		translate([0, 0, -holder_base_height / 2])
		cylinder(r = holder_base_length / 6, h = holder_base_height + 0.05, center = true);
		for(i = [0 : 3])
		{
			rotate([0, 0, i * 90])
			translate([holder_base_length / 2, 0, -holder_base_height / 2])
			cylinder(r = holder_base_length / 3.5, h = holder_base_height + 0.05, center = true);
		}
		translate([spool_width / 2,
				holder_base_length / 2 - bearing_diameter / 2,
				holder_bearing_height])
		union()
		{
			rotate([0, 90, 0])
			cylinder(r = bolt_diameter / 2, h = spool_wall + bearing_thickness * 2 + 0.1, center = true);

			rotate([0, 90, 0])
			cylinder(r = bearing_diameter / 2 + 1, h = bearing_thickness, center = true);
		}
		translate([-spool_width / 2,
				holder_base_length / 2 - bearing_diameter / 2,
				holder_bearing_height])
		union()
		{
			rotate([0, 90, 0])
			cylinder(r = bolt_diameter / 2, h = spool_wall + bearing_thickness * 2 + 0.1, center = true);

			rotate([0, 90, 0])
			cylinder(r = bearing_diameter / 2 + 1, h = bearing_thickness, center = true);
		}

		translate([spool_width / 2,
				-(holder_base_length / 2 - bearing_diameter / 2),
				holder_bearing_height])
		union()
		{
			rotate([0, 90, 0])
			cylinder(r = bolt_diameter / 2, h = spool_wall + bearing_thickness * 2 + 0.1, center = true);

			rotate([0, 90, 0])
			cylinder(r = bearing_diameter / 2 + 1, h = bearing_thickness, center = true);
		}
		translate([-spool_width / 2,
				-(holder_base_length / 2 - bearing_diameter / 2),
				holder_bearing_height])
		union()
		{
			rotate([0, 90, 0])
			cylinder(r = bolt_diameter / 2, h = spool_wall + bearing_thickness * 2 + 0.1, center = true);

			rotate([0, 90, 0])
			cylinder(r = bearing_diameter / 2 + 1, h = bearing_thickness, center = true);
		}

	}
	}
}

holder();
//spool();
```