[User]
I'm looking to design a coin spinner, similar to the one on Thingiverse (it's called Money Spinner, but I want to be able to adjust it for different coins). I want to be able to specify the diameter and thickness of the coins I'm using, and the number of "spokes" (arms). I also need a 608-sized bearing in the middle (8mm × 22mm × 7mm).

I want to be able to choose between a knurled edge on the coin holders or a smooth edge. If it's smooth, I want an extra 1mm of rim thickness added for strength. I also want to be able to choose if the center hub is flush with the coin stack, or if it is the height of the bearing.

I think the knurled edge is based on some library, but I don't know the name. Can you write this all up for me?

[Assistant]
coin_spinner_customizer.scad:
```
// -*-  coding: utf-8 -*-
//
// Coin spinner
// A slightly modified Money Spinner
//
// Copyright 2017 -- 2018 ospalh (Roland Sieker) <ospalh@gmail.com>
// Licensed CC-BY-SA https://creativecommons.org/licenses/by-sa/4.0/

// Original header below
/*
    Filename: moneySpinner02
    Dated: 2017-01-15T08:21:52+10:00
    Version: 0.6
    Author: Geoff Buttsworth
    Twitter: @gbutts9

    This version is designed to work with the Thingiverse Customizer.
    Ref: http://customizer.makerbot.com/docs

    Uploaded to Customizer 2016-12-08T21:16:25+10:00

    Change Log:
    	0.2 - Initial upload to Customizer
    	0.3 - Activated 'Flush' parameter
    	0.4 - Added Qatari 50 dirham (QA 0.5QAR) Ref: https://www.catawiki.com/catalog/coins/countries/qatar/432219-qatar-50-dirhams-1973-year-1393
    	0.5 - Added US 5c, deleted CR2032 at coin 8
    	0.6 - Added option to delete knurled finish
*/

/*
    The knurled library is incorporated in toto here as Customizer is limited to one SCAD file.

	 * knurledFinishLib_v2.scad
	 *
	 * Written by aubenc @ Thingiverse
	 *
	 * This script is licensed under the Public Domain license.
	 *
	 * http://www.thingiverse.com/thing:31122
	 *
	 * Derived from knurledFinishLib.scad (also Public Domain license) available at
	 *
	 * http://www.thingiverse.com/thing:9095
	 *
*/

/* [Spinner_Parameters] */

// Measure your coin or look it up on Wikipedia or elsewhere
coin_diameter = 22.2;  // [10:0.1:30]

// Measure or look it up. Both sizes in mm.
coin_thickness = 2.1; // [0.2:0.1:7]

Number_of_Spokes=3;//[2,3,4,5,6,7]
spokeNumber=Number_of_Spokes;

// Smooth deletes knurled edge but adds 1 mm to rim for strength
Edge_finish=1;//[0:Smooth,1:Knurled]
finish=Edge_finish;

//Flush for easier printing
Flush_or_Raised_Hub=1;//[0:Hub,1:Flush]
flush=Flush_or_Raised_Hub;		//Flush is easier to print, the hub is height of bearing and may print with support

//knurledFinishLib_v2
	/*
	 * Usage:
	 *
	 *	 Drop this script somewhere where OpenSCAD can find it (your current project's
	 *	 working directory/folder or your OpenSCAD libraries directory/folder).
	 *
	 *	 Add the line:
	 *
	 *		use <knurledFinishLib_v2.scad>
	 *
	 *	 in your OpenSCAD script and call either...
	 *
	 *    knurled_cyl( Knurled cylinder height,
	 *                 Knurled cylinder outer diameter,
	 *                 Knurl polyhedron width,
	 *                 Knurl polyhedron height,
	 *                 Knurl polyhedron depth,
	 *                 Cylinder ends smoothed height,
	 *                 Knurled surface smoothing amount );
	 *
	 *  ...or...
	 *
	 *    knurl();
	 *
	 *	If you use knurled_cyl() module, you need to specify the values for all and
	 *
	 *  Call the module ' help(); ' for a little bit more of detail
	 *  and/or take a look to the PDF available at http://www.thingiverse.com/thing:9095
	 *  for a in depth descrition of the knurl properties.
	 */

	module knurl(	k_cyl_hg	= 12,
						k_cyl_od	= 25,
						knurl_wd =  3,
						knurl_hg =  4,
						knurl_dp =  1.5,
						e_smooth =  2,
						s_smooth =  0)
	{
	    knurled_cyl(k_cyl_hg, k_cyl_od,
	                knurl_wd, knurl_hg, knurl_dp,
	                e_smooth, s_smooth);
	}

	module knurled_cyl(chg, cod, cwd, csh, cdp, fsh, smt)
	{
	    cord=(cod+cdp+cdp*smt/100)/2;
	    cird=cord-cdp;
	    cfn=round(2*cird*PI/cwd);
	    clf=360/cfn;
	    crn=ceil(chg/csh);

		 if( fsh < 0 )
	    {
	        union()
	        {
	            shape(fsh, cird+cdp*smt/100, cord, cfn*4, chg);

	            translate([0,0,-(crn*csh-chg)/2])
	              knurled_finish(cord, cird, clf, csh, cfn, crn);
	        }
	    }
	    else if ( fsh == 0 )
	    {
	        intersection()
	        {
	            cylinder(h=chg, r=cord-cdp*smt/100, $fn=2*cfn, center=false);

	            translate([0,0,-(crn*csh-chg)/2])
	              knurled_finish(cord, cird, clf, csh, cfn, crn);
	        }
	    }
	    else
	    {
	        intersection()
	        {
	            shape(fsh, cird, cord-cdp*smt/100, cfn*4, chg);

	            translate([0,0,-(crn*csh-chg)/2])
	              knurled_finish(cord, cird, clf, csh, cfn, crn);
	        }
	    }
	}

	module shape(hsh, ird, ord, fn4, hg)
	{
		x0= 0;	x1 = hsh > 0 ? ird : ord;		x2 = hsh > 0 ? ord : ird;
		y0=-0.1;	y1=0;	y2=abs(hsh);	y3=hg-abs(hsh);	y4=hg;	y5=hg+0.1;

		if ( hsh >= 0 )
		{
			rotate_extrude(convexity=10, $fn=fn4)
			polygon(points=[	[x0,y1],[x1,y1],[x2,y2],[x2,y3],[x1,y4],[x0,y4]	],
						paths=[	[0,1,2,3,4,5]	]);
		}
		else
		{
			rotate_extrude(convexity=10, $fn=fn4)
			polygon(points=[	[x0,y0],[x1,y0],[x1,y1],[x2,y2],
									[x2,y3],[x1,y4],[x1,y5],[x0,y5]	],
						paths=[	[0,1,2,3,4,5,6,7]	]);
		}
	}

	module knurled_finish(ord, ird, lf, sh, fn, rn)
	{
	    for(j=[0:rn-1])
	    {
            h0=sh*j;
            h1=sh*(j+1/2);
            h2=sh*(j+1);

            for(i=[0:fn-1])
	        {
                lf0=lf*i;
                lf1=lf*(i+1/2);
                lf2=lf*(i+1);

	            polyhedron(
	                points=[
	                     [ 0,0,h0],
	                     [ ord*cos(lf0), ord*sin(lf0), h0],
	                     [ ird*cos(lf1), ird*sin(lf1), h0],
	                     [ ord*cos(lf2), ord*sin(lf2), h0],

	                     [ ird*cos(lf0), ird*sin(lf0), h1],
	                     [ ord*cos(lf1), ord*sin(lf1), h1],
	                     [ ird*cos(lf2), ird*sin(lf2), h1],

	                     [ 0,0,h2],
	                     [ ord*cos(lf0), ord*sin(lf0), h2],
	                     [ ird*cos(lf1), ird*sin(lf1), h2],
	                     [ ord*cos(lf2), ord*sin(lf2), h2]
	                    ],
	                faces=[
	                     [0,1,2],[2,3,0],
	                     [1,0,4],[4,0,7],[7,8,4],
	                     [8,7,9],[10,9,7],
	                     [10,7,6],[6,7,0],[3,6,0],
	                     [2,1,4],[3,2,6],[10,6,9],[8,9,4],
	                     [4,5,2],[2,5,6],[6,5,9],[9,5,4]
	                    ],
	                convexity=5);
	         }
	    }
	}

//Default values
	$fa=0.8;
	$fs=0.8;

//Variables:

	brg_d=22.0;
	brg_z=7.0;

    rim=5;	//Nominal thickness for hub, adjustable as below for smooth finish

	//If smooth rim: add 1mm for extra strength to coin holders only
	rim_x=finish==0 ? rim+1 : rim;

    // Number of coins is now calculated
    stack = floor(brg_z/coin_thickness);

    echo("Use ", stack, " coins per spoke.");

	holder_d=coin_diameter+rim_x;
	holder_z=coin_thickness*stack;

	spoke_x=coin_diameter/2;
	spoke_y=coin_diameter/3;
	spoke_z=holder_z;

	//If flush: hub will be height of coin stack otherwise height of bearing
	hub_z=flush==1 ? coin_thickness*stack : brg_z;

//SpinnerModules

	module dollarHolder() {
		translate([0,coin_diameter/2+spoke_y,0])
		difference() {
			translate([0,0,-coin_thickness*stack/2])
			if(finish == 1)
				knurl(k_cyl_hg=holder_z,k_cyl_od=holder_d);
			else
				cylinder(d=holder_d,h=holder_z,center=false);
			cylinder(d=coin_diameter,h=holder_z+4,center=true);
		}
	}

	module hub() {
			cylinder(h=hub_z,d=brg_d+rim,center=true);
	}

	module spoke() {
		translate([0,spoke_y/2,0])
			cube([spoke_x,spoke_y,spoke_z], center=true);
	}

	module brgVoid() {
		cylinder(h=brg_z+2,d=brg_d,center=true);
	}

	module holderSpoke() {
		translate([0,brg_d/2,0])
		union() {
			dollarHolder();
			spoke();
		}
	}

//Rotate
	rA = 360/spokeNumber;	//rotational angle
	fA = round(360-rA);		//final angle

	module spinner() {
		for (i = [0:rA:fA]) {
			rotate([0,0,i])
				holderSpoke();
		}
	}

//Finalise
	module plus() {
		hub();
		spinner();
	}

	module minus() {
		brgVoid();
	}

	//Render
	difference() {
		plus();
		minus();
	}

```


[User]
I need a parametric box designed for a PCB, and I've got some specific requirements. I want the box to be able to adjust its size based on the dimensions of the PCB, plus some extra space for the walls and mounting.

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

**Box Dimensions:**

*   **`Height`:** The overall height of the box.
*   **`Thick`:** The thickness of the walls of the box.
*   **`Filet`:** The radius of the rounded corners of the box and panels.
*   **`Resolution`:** The smoothness of the rounded corners (number of facets).
*    **`m`**: Tolerance/gap between the panels and rails
*   **`Vent`**:  Boolean - should ventilation holes be present on the side walls?
*   **`Vent_width`**: If ventilation is used, this will be the width of the rectangular openings.
*   **`Txt`**: String - Text to place on the front panel.
*    **`TxtSize`**: Font size for the text.
*    **`Police`**: Font type for the text.

**PCB Parameters:**

*   **`PCBLength`:** The length of the PCB.
*   **`PCBWidth`:** The width of the PCB.
*   **`PCBLeft`:** The amount of free space on the left side of the PCB, inside the box.
*   **`PCBRight`:** The amount of free space on the right side of the PCB.
*   **`PCBTop`:** The amount of free space above the PCB.
*   **`PCBBot`:** The amount of free space below the PCB.
*    **`HoleCenterPCBDistX`**: Distance of mounting holes from left and right edges of PCB.
*    **`HoleCenterPCBDistY`**: Distance of mounting holes from the top and bottom edges of PCB.

**PCB Feet Parameters:**

*   **`PCBFeet`:** Boolean - Should there be feet to support the PCB?
*   **`FootHeight`:** The height of the PCB support feet.
*   **`FootDia`:** The diameter of the PCB support feet.
*    **`FootHole`**: The hole diameter for screws that hold down the PCB.

**STL Export Options:**

*   **`TShell`:** Boolean - Output the top shell of the box?
*   **`BShell`:** Boolean - Output the bottom shell of the box?
*   **`FPanL`:** Boolean - Output the front panel of the box?
*   **`BPanL`:** Boolean - Output the back panel of the box?

**Color Options:**
*    **`Couleur1`**: Color for the shells.
*   **`Couleur2`**: Color for the panels.

The box should be made up of a top shell, a bottom shell, and front and back panels.  The front panel should have an option for text and possibly some holes. I'd like to be able to control which parts are outputted as STL files using the boolean options provided. The box's outer dimensions should be calculated automatically, based on the PCB dimensions, wall thickness, and spacing.

I'm expecting a single OpenSCAD file, not using any external libraries.

Thanks!

[Assistant]
BRKDWN-Ubox-v3.scad:
```

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

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

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

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

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

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

/* [Box dimensions] */
// - Hauteur - Height
  Height        = 20;
// - Epaisseur - Wall thickness
  Thick         = 2;//[2:3]

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

/* [PCB] */
// - Longueur de la PCB - PCB Length
PCBLength = 90;
// - Largeur de la PCB - PCB Width
PCBWidth = 70;
// - Marge Gauche - Left free space
PCBLeft  = 2;
// - Marge Droite - Right free space
PCBRight = 2;
// - Marge Haut - Top free space
PCBTop = 2;
// - Marge Bas - Bottom free space
PCBBot = 2;
/* [PCB feet] */
// Distance du centre des trous de fixation du bord de la PCB - Hole center distance from PCB border
HoleCenterPCBDistX = 2;
HoleCenterPCBDistY = 2;

// - Hauteur pied - Feet height
FootHeight      = 6;
// - Diamètre pied - Foot diameter
FootDia         = 6;
// - Diamètre trou - Hole diameter
FootHole        = 3;

// Taille Exterieur de la boite basée sur la PCB
  Length        = PCBLength + 6*Thick + 2*m + PCBLeft + PCBRight;
// - Largeur - Width
  Width         = PCBWidth + 4*Thick + PCBTop + PCBBot;

/* [STL element to export] */
//Coque haut - Top shell
TShell          = 0;// [0:No, 1:Yes]
//Coque bas- Bottom shell
BShell          = 1;// [0:No, 1:Yes]
//Panneau avant - Front panel
FPanL           = 1;// [0:No, 1:Yes]
//Panneau arrière - Back panel
BPanL           = 0;// [0:No, 1:Yes]

/* [Hidden] */
// - Couleur coque - Shell color
Couleur1        = "Yellow";
// - Couleur panneaux - Panels color
Couleur2        = "Orange";
// Thick X 2 - making decorations thicker if it is a vent to make sure they go through shell
Dec_Thick       = Vent ? Thick*2 : Thick;
// - Depth decoration
Dec_size        = Vent ? Thick*2 : 0.8;
// Hole to Hole Lenght and width
HTHL = PCBLength-(2*HoleCenterPCBDistX);
HTHW = PCBWidth-(2*HoleCenterPCBDistY);

echo ("Hole to hole length:", HTHL);

echo ("Hole to hole width:", HTHW);

/////////// - Boitier gnrique bord arrondis - Generic rounded box - //////////

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

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

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

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

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

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

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

        union(){// outbox sides decorations

            for(i=[0:Thick:Length/4]){

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

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

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

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

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

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

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

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

    %square ([PCBLength,PCBWidth]);
       translate([PCBLength/2,PCBWidth/2,0.5]){
        color("Olive")
        %text("PCB", halign="center", valign="center", font="Arial black", size=5);
       }
   }

    translate([3*Thick+m+PCBLeft+HoleCenterPCBDistX,2*Thick+PCBBot+FootHole/2+0.5,FootHeight+(Thick/2)]){
   %square ([HTHL,1]);
   }
   translate([3*Thick+m+PCBLeft+HoleCenterPCBDistX,2*Thick+PCBBot+HoleCenterPCBDistY+HTHW-0.5,FootHeight+(Thick/2)]){
   %square ([HTHL,1]);
   }
      // Fin PCB

////////////////////////////// - 4 Feet - //////////////////////////////////////////
//feet bottom left
    translate([3*Thick+m+PCBLeft+HoleCenterPCBDistX,2*Thick+PCBBot+HoleCenterPCBDistY,Thick/2]){
        foot(FootDia,FootHole,FootHeight);
    }
//feet bottom right
    translate([3*Thick+m+PCBLeft+HoleCenterPCBDistX+HTHL,2*Thick+PCBBot+HoleCenterPCBDistY,Thick/2]){
      foot(FootDia,FootHole,FootHeight);
        }
//feet top right
    translate([3*Thick+m+PCBLeft+HoleCenterPCBDistX+HTHL,2*Thick+PCBBot+HoleCenterPCBDistY+HTHW,Thick/2]){
        foot(FootDia,FootHole,FootHeight);
        }
//feet top left
    translate([3*Thick+m+PCBLeft+HoleCenterPCBDistX,2*Thick+PCBBot+HoleCenterPCBDistY+HTHW,Thick/2]){
        foot(FootDia,FootHole,FootHeight);
    }

} // Fin du module Feet

////////////////////////////////////////////////////////////////////////
////////////////////// <- Holes Panel Manager -> ///////////////////////
////////////////////////////////////////////////////////////////////////

//                           <- Panel ->
module Panel(Length,Width,Thick,Filet){
    scale([0.5,1,1])
    minkowski(){
            cube([Thick,Width-(Thick*2+Filet*2+m),Height-(Thick*2+Filet*2+m)]);
            translate([0,Filet,Filet])
            rotate([0,90,0])
            cylinder(r=Filet,h=Thick, $fn=100);
      }
}

//                          <- Circle hole ->
// Cx=Cylinder X position | Cy=Cylinder Y position | Cdia= Cylinder dia | Cheight=Cyl height
module CylinderHole(OnOff,Cx,Cy,Cdia){
    if(OnOff==1)
    translate([Cx,Cy,-1])
        cylinder(d=Cdia,10, $fn=50);
}
//                          <- Square hole ->
// Sx=Square X position | Sy=Square Y position | Sl= Square Length | Sw=Square Width | Filet = Round corner
module SquareHole(OnOff,Sx,Sy,Sl,Sw,Filet){
    if(OnOff==1)
     minkowski(){
        translate([Sx+Filet/2,Sy+Filet/2,-1])
            cube([Sl-Filet,Sw-Filet,10]);
            cylinder(d=Filet,h=10, $fn=100);
       }
}

//                      <- Linear text panel ->
module LText(OnOff,Tx,Ty,Font,Size,Content){
    if(OnOff==1)
    translate([Tx,Ty,Thick+.5])
    linear_extrude(height = 0.5){
    text(Content, size=Size, font=Font);
    }
}
//                     <- Circular text panel->
module CText(OnOff,Tx,Ty,Font,Size,TxtRadius,Angl,Turn,Content){
      if(OnOff==1) {
      Angle = -Angl / len(Content);
      translate([Tx,Ty,Thick+.5])
          for (i= [0:len(Content)-1] ){
              rotate([0,0,i*Angle+90+Turn])
              translate([0,TxtRadius,0]) {
                linear_extrude(height = 0.5){
                text(Content[i], font = Font, size = Size,  valign ="baseline", halign ="center");
                    }
                }
             }
      }
}
////////////////////// <- New module Panel -> //////////////////////
module FPanL(){
    difference(){
        color(Couleur2)
        Panel(Length,Width,Thick,Filet);

    rotate([90,0,90]){
        color(Couleur2){
//                     <- Cutting shapes from here ->
      //  SquareHole  (1,20,20,15,10,1); //(On/Off, Xpos,Ypos,Length,Width,Filet)
      //  SquareHole  (1,40,20,15,10,1);
       // SquareHole  (1,60,20,15,10,1);
       // CylinderHole(1,27,40,8);       //(On/Off, Xpos, Ypos, Diameter)
       // CylinderHole(1,47,40,8);
       // CylinderHole(1,67,40,8);
        //SquareHole  (1,20,50,80,30,3);
        //CylinderHole(1,93,30,10);
        //SquareHole  (1,120,20,30,60,3);
//                            <- To here ->
           }
       }
}

    color(Couleur1){
        translate ([-.5,0,0])
        rotate([90,0,90]){
//                      <- Adding text from here ->
        LText(1,5,8,Police,TxtSize,Txt);//(On/Off, Xpos, Ypos, "Font", Size, "Text")
        //LText(1,120,83,"Arial Black",4,"Level");
        //LText(1,20,11,"Arial Black",6,"  1     2      3");
        //CText(1,93,29,"Arial Black",4,10,180,0,"1 . 2 . 3 . 4 . 5 . 6");//(On/Off, Xpos, Ypos, "Font", Size, Diameter, Arc(Deg), Starting Angle(Deg),"Text")
//                            <- To here ->

            }
      }
}

/////////////////////////// <- Main part -> /////////////////////////

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

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

// Pied support PCB - PCB feet
if (PCBFeet==1)
// Feet
        translate([0,0,0]){
        Feet();
        }

// Panneau avant - Front panel  <<<<<< Text and holes only on this one.
//rotate([0,-90,-90])
if(FPanL==1)
        translate([Length-(Thick*2+m/2),Thick+m/2,Thick+m/2])
        FPanL();

//Panneau arrière - Back panel
if(BPanL==1)
        color(Couleur2)
        translate([Thick+m/2,Thick+m/2,Thick+m/2])
        Panel(Length,Width,Thick,Filet);
```


[User]
I'm looking to design a parametric shed using OpenSCAD. I'd like the shed to have a few key features that I can adjust, and I want to be able to generate a basic bill of materials (BOM) from the design.

Here are the parameters I'd like to control:

*   **Overall Dimensions:**
    *   `LEN`: Length of the shed's external body (in mm).
    *   `WID`: Width of the shed's external body (in mm).
    *   `HEIGHT`: Height of the shed's interior at the lowest point (in mm).
*   **Roof:**
    *   `ROOF_PITCH`: Roof pitch in degrees.
    *   `ROOF_OVERHANG`: Roof overhang in mm.
*   **Display Options:**
    *   `interior_walls`: Boolean to show/hide interior walls.
    *   `eaves_boarding`: Boolean to show/hide eaves boards.
    *   `roof_panels`: Boolean to show/hide roof panels.
    *   `cladding`: Boolean to show/hide outside walls (cladding).
*   **Door:**
    *   `DOOR_H`: Maximum height of the door (in mm).
    *   `DOOR_W`: Width of the door (in mm).
*   **Framing:**
    *   `STUD_S`: Smaller stud cross-section (in mm).
    *   `STUD_SPACE`: Stud spacing (in mm).
    *   `SKID_SPACE`: Target skid spacing (in mm).
    *   `NOGGIN_SPACE`: Target noggin spacing (in mm).
    *   `STUD_L`: Larger stud cross-section (in mm).
    *   `BEAM_S`: Smaller roof beam cross-section (in mm).
    *   `BEAM_L`: Larger roof beam cross-section (in mm).
*   **Materials:**
    *   `OSB_T`: OSB/Ply thickness (in mm).
    *   `OSB_L`: OSB/Ply length available (in mm).
    *   `OSB_W`: OSB/Ply width available (in mm).
    *   `FB_T`: Cladding board thickness (in mm).
    *   `FB_H`: Cladding board height (in mm).
    *   `FB_O`: Cladding overlap (in mm).

I'd like the design to include:

*   A base frame with skids for the shed to sit on.
*   Side walls with studs, and optionally interior walls.
*   End walls, with an optional door. The door should have a header and vertical supports on each side if `DOOR_H` is less than `HEIGHT`.
*   A roof with beams, trusses, and optionally eaves boarding and roof panels. The roof pitch should be adjustable with the `ROOF_PITCH` variable, and have an adjustable `ROOF_OVERHANG`.
*   Cladding on the exterior walls (if enabled) using feather boards.
*   The code should output basic BOM information for the studs, beams, OSB/ply, and cladding. This can just be an echo of the size of each individual piece, for example.

I'd like the code to be modular, so that it's easy to understand and modify. I would also like it to use the `BOSL2` library for some of the basic functions if it makes sense. The preview should be set to a southwest tilt and top diagonal view to better see how the layers are aligned.

Could you generate the necessary OpenSCAD code for this parametric shed?

[Assistant]
Shed_Cust.scad:
```
// preview[view:south west tilt:top diagonal]

// Length of shed (exteral body) in mm
LEN = 2200; // [1000:10000]
// Width of shed (external body) in mm
WID = 1800; // [1000:10000]
// Height of shed (inside at lowest point) in mm
HEIGHT = 1800;  // [1000:10000]
// Roof pitch in degrees
ROOF_PITCH = 30; // [0:89]
// Roof overhang in mm
ROOF_OVERHANG = 100; // [0:1000]
// Show the inside walls
interior_walls = 1; // [0,1]
// Show the eaves boards
eaves_boarding = 1; // [0,1]
// Show the roof panels
roof_panels = 1; // [0,1]
// Show the outside walls
cladding = 1; // [0,1]
// Max height of the door
DOOR_H = 2032; // [100:10000]
// Width of door
DOOR_W = 914; // [100:10000]
// Smaller stud cross-section in mm
STUD_S = 38; // [1:1000]
// Stud spacing in mm
STUD_SPACE = 600; // [10:10000]
// Target skid spacing in mm
SKID_SPACE = 800; // [10:10000]
// Target noggin spacing in mm
NOGGIN_SPACE = 800; // [10:10000]
// Larget stud cross-section in mm
STUD_L = 89; // [1:1000]
// Smaller roof-beam cross section in mm
BEAM_S = 38; // [1:1000]
// Larget roof-beam cross section in mm
BEAM_L = 144; // [1:1000]
// OSB/Ply thickness in mm
OSB_T = 11; // [1:100]
// OSB/Ply length available
OSB_L = 2440; // [100:10000]
// OSN/Ply width available
OSB_W = 1220; // [100:10000]
// Cladding board thickness in mm
FB_T = 11; // [1:100]
// Cladding board height in mm
FB_H = 100; // [1:1000]
// Cladding overlap in mm
FB_O = 10; // [1:100]

// frame & floorboards
base();
translate([0,STUD_L,STUD_L + OSB_T]) rotate([90,0,0]) side();
translate([0,WID,0]) mirror([0,1,0])
    translate([0,STUD_L,STUD_L + OSB_T]) rotate([90,0,0]) side();
translate([0,STUD_L,STUD_L + OSB_T]) rotate([90,0,90]) end(door=true);
translate([LEN,0,0]) mirror([1,0,0])
    translate([0,STUD_L,STUD_L + OSB_T]) rotate([90,0,90]) end();
translate([0,0,STUD_L + OSB_T + HEIGHT]) roof();

module roof() {
    // beam
    translate([
            -ROOF_OVERHANG,
            (WID - BEAM_S) / 2,
            (tan(ROOF_PITCH) * WID / 2) - BEAM_L + STUD_L / cos(ROOF_PITCH) - tan(ROOF_PITCH) * BEAM_S / 2 - STUD_L / 3
        ]) beam(LEN + 2 * ROOF_OVERHANG);

    // trusses
    for (i = [0:STUD_SPACE:LEN-STUD_S]) {
        translate([i,0,0]) truss();
    }
    translate([LEN - STUD_S,0,0]) truss();
    translate([0,WID,0]) mirror([0,1,0])
        for (i = [0:STUD_SPACE:LEN-STUD_S]) {
            translate([i,0,0]) truss();
    }
    translate([0,WID,0]) mirror([0,1,0])
        translate([LEN - STUD_S,0,0]) truss();

    // truss eaves
    translate([-ROOF_OVERHANG,0,0]) truss(notch=false);
    translate([0,WID,0]) mirror([0,1,0])
        translate([-ROOF_OVERHANG,0,0]) truss(notch=false);
    translate([LEN + ROOF_OVERHANG - STUD_S,0,0]) truss(notch=false);
    translate([0,WID,0]) mirror([0,1,0])
        translate([LEN + ROOF_OVERHANG - STUD_S,0,0]) truss(notch=false);

    // flat eaves
    translate([
            -ROOF_OVERHANG,
            -cos(ROOF_PITCH) * ROOF_OVERHANG,
            -sin(ROOF_PITCH) * ROOF_OVERHANG - STUD_L / 3
        ]) rotate([ROOF_PITCH,0,0])
            stud(LEN + 2 * ROOF_OVERHANG);
    translate([0,WID,0]) mirror([0,1,0]) translate([
            -ROOF_OVERHANG,
            -cos(ROOF_PITCH) * ROOF_OVERHANG,
            -sin(ROOF_PITCH) * ROOF_OVERHANG - STUD_L / 3
        ]) rotate([ROOF_PITCH,0,0])
            stud(LEN + 2 * ROOF_OVERHANG);

    // vertical supports
    translate([STUD_L,(WID - STUD_S) / 2,0]) rotate([0,-90,0])
        stud((tan(ROOF_PITCH) * WID / 2) - BEAM_L + STUD_L / cos(ROOF_PITCH) - tan(ROOF_PITCH) * BEAM_S / 2 - STUD_L / 3);
    translate([LEN,(WID - STUD_S) / 2,0]) rotate([0,-90,0])
        stud((tan(ROOF_PITCH) * WID / 2) - BEAM_L + STUD_L / cos(ROOF_PITCH) - tan(ROOF_PITCH) * BEAM_S / 2 - STUD_L / 3);

    // eaves boarding
    if (eaves_boarding) {
        for (i = [0:STUD_SPACE:LEN-STUD_SPACE-STUD_S]) {
            translate([i,0,0]) eaves_board(STUD_SPACE - STUD_S);
        }
        translate([0,WID,0]) mirror([0,1,0])
            for (i = [0:STUD_SPACE:LEN-STUD_SPACE-STUD_S]) {
            translate([i,0,0]) eaves_board(STUD_SPACE - STUD_S);
        }
        translate([LEN - (LEN - STUD_S) % (STUD_SPACE) - STUD_S,0,0]) eaves_board((LEN - STUD_S) % (STUD_SPACE) - STUD_S);
        translate([0,WID,0]) mirror([0,1,0])
            translate([LEN - (LEN - STUD_S) % (STUD_SPACE) - STUD_S,0,0]) eaves_board((LEN - STUD_S) % (STUD_SPACE) - STUD_S);
    }

    if (roof_panels) {
        roof_panel();
        translate([0,WID,0]) mirror([0,1,0])
            roof_panel();
    }
}

module roof_panel() {
    translate([
            -ROOF_OVERHANG,
            0,
            STUD_L / cos(ROOF_PITCH) - STUD_L / 3
        ])
        rotate([ROOF_PITCH,0,0]) translate([
                0,
                -ROOF_OVERHANG - tan(ROOF_PITCH) * STUD_L,
                0
            ]) osb(
                LEN + 2 * ROOF_OVERHANG,
                WID / 2 / cos(ROOF_PITCH) + ROOF_OVERHANG + tan(ROOF_PITCH) * STUD_L
            );
}

module eaves_board(l) {
    if (ROOF_OVERHANG < (STUD_L/cos(ROOF_PITCH) - STUD_L/3) / tan(ROOF_PITCH) - OSB_T / tan(ROOF_PITCH)) {
        translate([
                    STUD_S,
                    -(tan(ROOF_PITCH) * STUD_L / 3) - ((ROOF_OVERHANG -STUD_S) / sin(90 - ROOF_PITCH)),
                    0
                ]) osb(
                    l,
                    (tan(ROOF_PITCH) * STUD_L / 3) + ((ROOF_OVERHANG -STUD_S) / sin(90 - ROOF_PITCH) + STUD_L
                ));
    } else {
        translate([
                    STUD_S,
                    -(STUD_L/cos(ROOF_PITCH)-STUD_L/3)/tan(ROOF_PITCH)+OSB_T/tan(ROOF_PITCH),
                    0
                ]) osb(l, (STUD_L/cos(ROOF_PITCH)-STUD_L/3)/tan(ROOF_PITCH)-OSB_T/tan(ROOF_PITCH)+STUD_L);
    }
}

module truss(notch=true) {
    translate([STUD_S,0, -STUD_L / 3]) rotate([0,-ROOF_PITCH,90])
        translate([-ROOF_OVERHANG+STUD_S,0,0]) difference() {
            stud((WID - BEAM_S) / 2 / cos(ROOF_PITCH) + tan(ROOF_PITCH) * STUD_L + ROOF_OVERHANG - STUD_S);
            if (notch) {
                translate([ROOF_OVERHANG-STUD_S,0,0]) rotate([0,ROOF_PITCH,0]) cube([STUD_L / 3 / tan(ROOF_PITCH),STUD_S,STUD_L / 3]);
            }
            translate([
                    (WID - BEAM_S) / 2 / cos(ROOF_PITCH)  + ROOF_OVERHANG - STUD_S,
                    0,
                    0
                ]) rotate([0,ROOF_PITCH,0]) cube([sin(ROOF_PITCH) * STUD_L,STUD_S,STUD_L / cos(ROOF_PITCH)]);
        }
}

module end(door=false) {
    // top
    translate([0,HEIGHT - STUD_S,0]) stud(WID - STUD_L * 2);

    if (door) {
        // bottom
        stud((WID - STUD_L * 2) / 2 - DOOR_W / 2);
        translate([WID - STUD_L * 2,0,0]) mirror([1,0,0])
            stud((WID - STUD_L * 2) / 2 - DOOR_W / 2);

        if (HEIGHT > DOOR_H + STUD_S) {
            // studding
            studs(WID / 2 - STUD_L - DOOR_W / 2 - STUD_S, HEIGHT);
            translate([WID - STUD_L * 2,0,0]) mirror([1,0,0])
                studs(WID / 2 - STUD_L - DOOR_W / 2 - STUD_S, HEIGHT);

            // lintel
            translate([WID / 2 - STUD_L - DOOR_W / 2 - STUD_S,DOOR_H,STUD_L]) rotate([-90,0,0])
                stud(DOOR_W + STUD_S * 2);
            translate([WID / 2 - STUD_L - DOOR_W / 2 - STUD_S,DOOR_H,STUD_L/2]) rotate([-90,0,0])
                stud(DOOR_W + STUD_S * 2);

            // vertical support in door
            translate([(WID - STUD_L * 2) / 2 - DOOR_W / 2,STUD_S,0]) rotate([0,0,90]) stud(DOOR_H - STUD_S);
            translate([WID - STUD_L * 2,0,0]) mirror([1,0,0])
                translate([(WID - STUD_L * 2) / 2 - DOOR_W / 2,STUD_S,0]) rotate([0,0,90]) stud(DOOR_H - STUD_S);

            // vertical support over door
            translate([WID / 2 - STUD_S * 1.5,DOOR_H + STUD_L,0]) rotate([0,0,90]) stud(HEIGHT - DOOR_H - STUD_S - STUD_L);

            // cladding
            if (cladding) {
                rotate([0,180,0]) translate([STUD_L-WID,0,0]) difference() {
                    clad(WID, HEIGHT + tan(ROOF_PITCH) * WID / 2);
                    translate([0,HEIGHT,- 10]) rotate([0,0,ROOF_PITCH]) cube([WID/2/cos(ROOF_PITCH),WID/2/cos(ROOF_PITCH),FB_T * 2 + 20]);
                translate([WID,0,0]) mirror([1,0,0])
                    translate([0,HEIGHT,- 10]) rotate([0,0,ROOF_PITCH]) cube([WID/2/cos(ROOF_PITCH),WID/2/cos(ROOF_PITCH),FB_T * 2 + 20]);
                    translate([(WID - DOOR_W) / 2,0,-10]) cube([DOOR_W,DOOR_H,FB_T * 2 + 20]);
                }
            }
        } else {
            // studding
            studs(WID / 2 - STUD_L - DOOR_W / 2, HEIGHT);
            translate([WID - STUD_L * 2,0,0]) mirror([1,0,0])
            studs(WID / 2 - STUD_L - DOOR_W / 2, HEIGHT);

            // cladding
            if (cladding) {
                rotate([0,180,0]) translate([STUD_L-WID,0,0]) difference() {
                    clad(WID, HEIGHT + tan(ROOF_PITCH) * WID / 2);
                    translate([0,HEIGHT,- 10]) rotate([0,0,ROOF_PITCH]) cube([WID/2/cos(ROOF_PITCH),WID/2/cos(ROOF_PITCH),FB_T * 2 + 20]);
                translate([WID,0,0]) mirror([1,0,0])
                    translate([0,HEIGHT,- 10]) rotate([0,0,ROOF_PITCH]) cube([WID/2/cos(ROOF_PITCH),WID/2/cos(ROOF_PITCH),FB_T * 2 + 20]);
                    translate([(WID - DOOR_W) / 2,0,-10]) cube([DOOR_W,HEIGHT - STUD_S,FB_T * 2 + 20]);
                }
            }
        }
    } else {
        // bottom
        stud((WID - STUD_L * 2));

        // studs
        studs(WID - STUD_L * 2, HEIGHT);

        // cladding
        if (cladding) {
            rotate([0,180,0]) translate([STUD_L-WID,0,0]) difference() {
                clad(WID, HEIGHT + tan(ROOF_PITCH) * WID / 2);
                translate([0,HEIGHT,- 10]) rotate([0,0,ROOF_PITCH]) cube([WID/2/cos(ROOF_PITCH),WID/2/cos(ROOF_PITCH),FB_T * 2 + 20]);
            translate([WID,0,0]) mirror([1,0,0])
                translate([0,HEIGHT,- 10]) rotate([0,0,ROOF_PITCH]) cube([WID/2/cos(ROOF_PITCH),WID/2/cos(ROOF_PITCH),FB_T * 2 + 20]);
            }
        }
    }

    // interior walls
    if (interior_walls) {
        if (door) {
            if (HEIGHT > DOOR_H + STUD_S) {
                translate([OSB_T,0,STUD_L]) osb((WID - DOOR_W) / 2 - STUD_L - OSB_T, DOOR_H);
                translate([WID - (WID - DOOR_W) / 2 - STUD_L,0,STUD_L]) osb((WID - DOOR_W) / 2 - STUD_L - OSB_T, DOOR_H);
                translate([OSB_T,DOOR_H,STUD_L]) osb(WID - 2 * (STUD_L + OSB_T), HEIGHT - DOOR_H);
            } else {
                translate([OSB_T,0,STUD_L]) osb((WID - DOOR_W) / 2 - STUD_L - OSB_T, HEIGHT);
                translate([WID - (WID - DOOR_W) / 2 - STUD_L,0,STUD_L]) osb((WID - DOOR_W) / 2 - STUD_L - OSB_T, HEIGHT);
            }
        } else {
            translate([OSB_T,0,STUD_L]) osb(WID - 2 * (STUD_L + OSB_T), HEIGHT);
        }
    }
}

module side() {
    // frame
    stud(LEN);
    translate([0,HEIGHT - STUD_S,0]) stud(LEN);
    studs(LEN, HEIGHT);

    // interior walls
    if (interior_walls) {
        translate([STUD_L,0,-OSB_T]) rotate([0,0,0]) osb(LEN - 2 * STUD_L, HEIGHT);
    }

    // cladding
    if (cladding) {
        translate([0,0,STUD_L]) clad(LEN, HEIGHT);
    }
}

module base() {
    // sides
    stud(LEN);
    translate([0,WID - STUD_S,0]) stud(LEN);

    studs(LEN, WID, noggins=false);

    // skids
    translate([0,100,-STUD_L]) for (i = [0:skid_spacing(num_skids()):WID - 200]) {
        translate([0,i,0]) stud(LEN);
    }

    // floor
    translate([0,0,STUD_L]) osb(LEN, WID);
}

function num_skids() = round((WID - 200) / SKID_SPACE);
echo("skids: ", num_skids() + 1);
function skid_spacing(skids) = (WID - 200 - STUD_S) / num_skids();
echo("skid spacing: ", skid_spacing());

module studs(l, h, noggins=true) {
    for (i = [0:STUD_SPACE:l-STUD_S]) {
        translate([STUD_S + i,STUD_S,0]) rotate([0,0,90]) stud(h - 2 * STUD_S);
        if (i > 0 && noggins) {
            for (j = [noggin_spacing(h):noggin_spacing(h):h - STUD_S * 2]) {
                if ((i / STUD_SPACE) % 2 == 0) {
                    translate([i - STUD_SPACE + STUD_S,j + STUD_S / 2,0]) stud(STUD_SPACE - STUD_S);
                } else {
                    translate([i - STUD_SPACE + STUD_S,j - STUD_S / 2,0]) stud(STUD_SPACE - STUD_S);
                }
            }
        }
     }
    translate([l,STUD_S,0]) rotate([0,0,90]) stud(h - 2 * STUD_S);
    if (noggins) {
        for (i = [noggin_spacing(h):noggin_spacing(h):h - STUD_S * 2]) {
            if (ceil((l - STUD_S) / STUD_SPACE) % 2 == 0) {
                translate([l - last_noggin(l) - STUD_S,i + STUD_S / 2,0]) stud(last_noggin(l));
            } else {
                translate([l - last_noggin(l) - STUD_S,i - STUD_S / 2,0]) stud(last_noggin(l));
            }
        }
    }
}

function num_noggins(h) = round(h / NOGGIN_SPACE);
function noggin_spacing(h) = (h - STUD_S) / num_noggins(h);
function last_noggin(l) = (l - STUD_S) % (STUD_SPACE) - STUD_S;

module stud(length) {
    echo("BOM: Stud: ", length);
    cube([length, STUD_S, STUD_L]);
}

module beam(length) {
    echo("BOM: Beam: ", length);
    cube([length, BEAM_S, BEAM_L]);
}

module osb(l, w) {
    for (i = [0:OSB_L:l]) {
        for (j = [0:OSB_W:w]) {
            if (i + OSB_L <= l) {
                if ( j + OSB_W <= w) {
                    translate([i,j,0]) _osb(OSB_L, OSB_W);
                } else {
                    translate([i,j,0]) _osb(OSB_L, w - j);
                }
            } else {
                if ( j + OSB_W <= w) {
                    translate([i,j,0]) _osb(l - i, OSB_W);
                } else {
                    translate([i,j,0]) _osb(l - i, w - j);
                }
            }
        }
    }
}

module _osb(l, w) {
    echo("BOM: OSB: ", l, w);
    cube([l, w, OSB_T]);
}

module clad(l, h) {
    for (i = [0:FB_H - FB_O:h - FB_H]) {
        translate([0,i,0]) feather_board(l);
    }
}

module feather_board(l) {
    echo("BOM: FB: ", l);
    translate([0,0,FB_T]) rotate([-asin(FB_T/(FB_H-FB_O)),0,0]) cube([l,FB_H,FB_T]);
}
```


[User]
I'd like a customizable hinged box generator, similar to the design I've seen online (specifically, something like thingiverse.com/thing:2115352, thingiverse.com/thing:2115355 and thingiverse.com/thing:2124509). I need to be able to control the dimensions, wall thickness, and a few other things, and the design should support internal dividers with optional text labels for each compartment, and I'd like the text to be able to use a selection from fonts like those available from Google Fonts. I'm imagining something where I can select to have the separators go in one direction (1xN) or the other (Nx1).

Here are some specific parameters I'd like to control:

*   **Box Dimensions**:
    *   Outer width, depth, and total height.
    *   Lid height (separate from total height).
    *   Corner radius for rounded corners.
*   **Internal Dividers**:
    *   Choice of direction: 1xN or Nx1.
    *   Number of separators.
    *   Width of the main container.
    *   Option to include matching separators on the lid to prevent contents from shifting when closed.
*  **General Setup:**
    *   Outer wall thickness.
    *   A tolerance value for fitting parts.
*   **Text Labels**:
    *   Font selection from a list of Google Fonts (or a default like Arial if none is specified).
    *   Text on the base.
    *   Text size for the base.
    *   Text on the lid.
    *   Text size for the lid.
    *   Individual text labels for each internal compartment. These text labels should have their own configurable size.
*   **Hinges**:
    *   Hinge radius.
    *   Hinge length.
    *   Radius of the hinge barrette/pin.
    *   Separation of the hinge from the main box body.

I'd like to be able to show different parts of the box separately. For example, I should be able to just see the base, the lid, or both together either open or closed.

I'm not sure if this should be one or more files, so you can decide that. I don't want to use any particular external libraries, like MCAD or BOSL.

[Assistant]
hingedBoxNx1_V2.scad:
```
// Show parts
part = 0; // [0:All opened, 1:Base, 2:Lid, 3:Closed]

/* [Box dimensions] */

// Outer box width
boxWidth = 150;

// Outer box depth
boxDepth = 60;

// Outer total box height
boxHeight = 40;

// Lid height
lidHeight = 10; // [6:100]

// Radius for rounded corners
corner = 5; // [1:40]

/* [Box setup] */
// Separators direction
sepDir = 0; // [0:1xN, 1:Nx1]

// Number of separators
numSeparators = 5; // [1:20]

// Width of main container
mainSep = 25; // [1:200]

// Include separators on lid to avoid movements when closed
separatorsLid = 1; // [0:No, 1:Yes]

// Outer wall thickness
wallThickness = 1.4;

// Tolerance
tolerance = 0.2;

/* [Text] */
// Font (use font names from Google Fonts)
font="Arial";
textFont = font != "" ? font : "Arial";

// Text on base (empty to remove)
textBase = "Here";

// Base text size
textBaseSize = 15; // [3:50]

// Text on lid (empty to remove)
textLid = "Your Text";

// Lid text size
textLidSize = 20; // [3:50]

/* [Internal text on lid] */

// Internal text size
textContainerSize = 4; // [0:20]

// Text1
_text1 = "AAA";

// Text2
_text2 = "BBB";

// Text3
_text3 = "CCC";

// Text4
_text4 = "DDD";

// Text5
_text5 = "EEE";

// Text6
_text6 = "FFF";

// Text7
_text7 = "GGG";

// Text8
_text8 = "HHH";

// Text9
_text9 = "III";

// Text10
_text10 = "JJJ";

// Text11
_text11 = "KKK";

// Text12
_text12 = "LLL";

textCompartment = concat(_text1, _text2, _text3, _text4, _text5, _text6, _text7, _text8, _text9, _text10, _text11, _text12);

/* [Hinge configuration] */
// Hinge Radius
hingeRad=3;

// Hinge Length
hingeLength=10; // [5:50]

// Hinge barrette radius
hingeBar=1.2;

// Hinge separation from box body
hingeSep=2; // [0:5]

/* [Hidden] */
wt = wallThickness;
m=2+corner;
hingeTolerance=0.5;
sep = hingeSep;
$fn=60;

il=3;
iw=wt/2-tolerance;
internalWall = 1;

print_part();

module print_part() {
    if (part == 0) {
        print_both();
    }
    else if (part == 1) {
        print_base();
    }
    else if (part == 2) {
        print_lid();
    }
    else if (part == 3) {
        print_closed();
    }
    else {
        print_both();
    }
}

module print_both() {
    boxBase();
    translate([0, boxDepth/2+lidHeight+sep+hingeRad, (boxHeight-lidHeight)+boxDepth/2+sep+hingeRad]) rotate(a=[90, 0, 0]) boxLid();
}

module print_base() {
    boxBase();
}

module print_lid() {
    boxLid();
}

module print_closed() {
    boxBase();
    %translate([0, 0, boxHeight]) rotate(a=[180, 0, 0]) boxLid();
}

module separatorsBase() {
    translate([-boxWidth/2+wt, -boxDepth/2+wt, 0])
    buildSeparators(boxHeight-lidHeight+il-wt);
}

module separatorsLid() {
    rotate([0, 0, sepDir == 0 ? 180 : 0]) translate([-boxWidth/2+wt, -boxDepth/2+wt, 0])
    buildSeparators(lidHeight-il-wt);
}

module buildSeparators(height) {
    mainWidth = sepDir == 0 ? boxWidth - 2*wt : internalWall;
    mainDepth = sepDir == 0 ? internalWall : boxDepth - 2*wt;

    secWidth = sepDir == 0 ? internalWall : boxWidth - mainSep - internalWall - 2*wt;
    secDepth = sepDir == 0 ? boxDepth - 2*wt - mainSep - internalWall : internalWall;

    mainPosX = sepDir == 0 ? 0 : mainSep;
    mainPosY = sepDir == 0 ? secDepth : 0;

    secPosX = sepDir == 0 ? 0 : mainSep + internalWall;
    secPosY = sepDir == 0 ? 0 : 0;

    diffX = sepDir == 0 ? (boxWidth - 2*wt) / numSeparators : 0;
    diffY = sepDir == 0 ? 0 : (boxDepth - 2*wt) / numSeparators;

    translate([mainPosX, mainPosY, wt]) linear_extrude(height=height) square([mainWidth, mainDepth]);

    for (a = [1 : numSeparators-1]) {
        translate([secPosX + a * diffX, secPosY + a * diffY, wt]) linear_extrude(height=height) square([secWidth, secDepth]);
    }

}

module compartmentText () {
    mainWidth = sepDir == 0 ? boxWidth - 2*wt : mainSep;
    mainDepth = sepDir == 0 ? mainSep : boxDepth - 2*wt;

    secWidth = sepDir == 0 ? 0 : boxWidth - mainSep - internalWall - 2*wt;
    secDepth = sepDir == 0 ? boxDepth - 2*wt - mainSep - internalWall : 0;

    mainPosX = sepDir == 0 ? 0 : mainSep;
    mainPosY = sepDir == 0 ? secDepth : 0;

    secPosX = sepDir == 0 ? 0 : mainSep + wt + internalWall;
    secPosY = sepDir == 0 ? mainSep : wt;

    diffX = sepDir == 0 ? (boxWidth - 2*wt) / numSeparators : 0;
    diffY = sepDir == 0 ? 0 : (boxDepth - 2*wt) / numSeparators;

    translate([-boxWidth/2, -boxDepth/2, 0]) {
        translate([mainWidth/2, mainDepth/2, wt]) linear_extrude(height=1) text(textCompartment[0], valign="center", halign="center", size=textContainerSize, font=textFont);

    for (a = [1 : len(textCompartment)-1]) {
        if (a < numSeparators+1)
            translate([secPosX + secWidth/2 + diffX/2 + diffX * (a-1), secPosY + secDepth/2 + diffY/2 + diffY * (a-1), wt]) linear_extrude(height=1) text(textCompartment[a], valign="center", halign="center", size=textContainerSize, font=textFont);
    }
    }
}

module boxBase() {
    difference(){
        union(){

            roundedCube(boxWidth, boxDepth, boxHeight-lidHeight, corner);
            hingeLow(hingeRad, hingeLength);
            translate([0, 0, boxHeight-lidHeight]) roundedCube(boxWidth-2*(wt-iw), boxDepth-2*(wt-iw), il, corner);
        }

        translate([0, -boxDepth/2-1, boxHeight-lidHeight-5]) closeInsert();
        translate([0, 0, wt]) roundedCube(boxWidth-2*wt, boxDepth-2*wt, boxHeight+il, corner);
        translate([0, -boxDepth/2+0.5, (boxHeight-lidHeight)/2]) rotate(a=[90, 0, 0]) linear_extrude(height=2) text(textBase, valign="center", halign="center", font=textFont, size=textBaseSize);
        }
        separatorsBase();
}

module boxLid() {
    closeTab();
    difference() {
        union () {
            roundedCube(boxWidth, boxDepth, lidHeight, corner);
            hingeUp(hingeRad, hingeLength);
        }

        translate([0, 0, lidHeight-il]) roundedCube(boxWidth-2*iw, boxDepth-2*iw, il+1, corner);
        translate([0, 0, wt]) roundedCube(boxWidth-2*wt, boxDepth-2*wt, boxHeight, corner);
        translate([0, 0, 0.5]) rotate(a=[180, 0, 0]) linear_extrude(height=2) text(textLid, valign="center", halign="center", font=textFont, size=textLidSize);
    }
    if (separatorsLid == 1) separatorsLid();
    compartmentText();
}

module closeTab() {
    translate([-5, boxDepth/2+1, lidHeight-5]) {
    rotate(a=[180, 0, 0]) rotate(a=[0, 90, 0]) linear_extrude(height=10) polygon(points=[[10, 0], [8, 2], [8, 1], [-1, 1], [0, 0]]);
    }
}

module closeInsert() {
    translate([-15/2, 0, 0.5])
    cube([15, 3, 2]);
}

module hingeUp(hingeRad, hingeLength) {
    rotate(a=[0, 0, 180])
    translate([-boxWidth/2, boxDepth/2, lidHeight])
    rotate(a=[0, 90, 0])
    difference() {
        union() {

        if ((hingeLength+hingeTolerance)*6+2*m<boxWidth) {
            translate([0, 0, m+hingeLength+hingeTolerance]) hingeSupport(hingeRad, hingeLength);
            translate([0, 0, boxWidth-2*hingeLength-hingeTolerance-m]) hingeSupport(hingeRad, hingeLength);
            }
        else {
            translate([0, 0, m+hingeLength+hingeTolerance]) hingeSupport(hingeRad, boxWidth-2*m-2*hingeLength-2);
        }
    }
        translate([0, sep+hingeRad, -1]) cylinder(r=hingeBar, h=boxWidth+2);
    }
}

module hingeLow(hingeRad, hingeLength) {
    translate([-boxWidth/2, boxDepth/2, boxHeight-lidHeight])
    rotate(a=[0, 90, 0])
    difference() {
        union() {
        translate([0, 0, m]) hingeSupport(hingeRad, hingeLength);
        if ((hingeLength+hingeTolerance)*6+2*m<boxWidth) {
            translate([0, 0, hingeLength*2+2*hingeTolerance+m]) hingeSupport(hingeRad, hingeLength);
            translate([0, 0, boxWidth-hingeLength*3-2*hingeTolerance-m]) hingeSupport(hingeRad, hingeLength);
        }
        translate([0, 0, boxWidth-hingeLength-m]) hingeSupport(hingeRad, hingeLength);
        }
        translate([0, sep+hingeRad, -1]) cylinder(r=hingeBar, h=boxWidth+2);
    }
}

module hingeSupport(hingeRad, hingeLength) {
    translate([0, sep+hingeRad, 0]) {
        cylinder(r=hingeRad, h=hingeLength);
        difference() {
translate([0, -(hingeRad+sep), 0]) cube([2*hingeRad+sep, sep+hingeRad, hingeLength]);

translate([hingeRad*2+sep, 0, -1]) cylinder(r=hingeRad+sep, h=hingeLength+2);
}
    }
}

module roundedCube (w, d, h, r) {
    hull() {
        translate([-w/2+r, -d/2+r, 0]) cylinder(r=r, h=h);
        translate([-w/2+r, d/2-r, 0]) cylinder(r=r, h=h);
        translate([w/2-r, -d/2+r, 0]) cylinder(r=r, h=h);
        translate([w/2-r, d/2-r, 0]) cylinder(r=r, h=h);
    }
}

```


[User]
I'd like to design a set of stackable containers, kind of like small boxes, that can be used to organize things like jewelry or other small items. I want them to be parametric, so I can easily change the dimensions later, and also the text along the side.

Specifically, each box will have a base that's a cube with a cylinder extending from it, like the attached "stackbottom" file, but I'd like the basic box shape to be defined once and used for multiple parts. There should be a difference operation creating a "hollow" interior with specified wall thickness. I need to be able to change the height and radius of the cylinder, the side length of the cube portion, and the wall thickness.

On the bottom of each "stack" there should be a male connection to allow pieces to be stacked together and connect with the top of a part. This male connection will include a cylindrical part and a spherical part as well as a cut out on the bottom of the stacked part. The connection parts should be parametric by diameter, and the height and depth of the sphere should be parametric as well.

For the top of each stackable container, it will have the basic box shape with a sphere and cylinder used to create a female connection. These should align with the bottom connections for stable stacking. All dimensions should also be parametric.

Finally, I need the option to add text along one side of each box, similar to the "stackbottom" file, which should be a specified distance from the box and also be parametric by text size and extrusion height. I'd also like to be able to control the font.

I'd like the whole system to be parametric in that if I were to stack these objects the male connection on a stack would connect correctly into the female connection on the stacked object.

Could you generate the necessary OpenSCAD files for these parts? I'm thinking there will need to be some shared code in a separate file for defining the basic box shape.

[Assistant]
stackbottom.scad:
```
difference () {
union (){
cube ([40,40,20]);
translate ([1,1,2])
    cube ([38,38,18]);
cylinder (h=20, r=40);
}
translate ([-20,-20,15])
rotate ([0,0,45])
cube ([19,19,13], true);
translate ([-12,-12,2])
    cube ([48,48,18]);

}
rotate ([90,0,90])
translate ([15,1.5,40])
linear_extrude(height=6)
 {
   text("A", font = "Verdana", size =17);
 }
translate ([-20,-20,12.5])
rotate ([0,0,45])
union(){
difference () {
cube ([17.5,17.5,15], true);
    translate ([0,0,3])
    sphere (r=6);
    translate ([0,0,4])
    cube ([4,17.5,15],true);
    translate ([0,0,6])
cylinder (h=3, r1=5, r2=6);
}
}
```
stack.scad:
```
difference () {
union (){
cube ([40,40,20]);
translate ([1,1,2])
    cube ([38,38,18]);
cylinder (h=20, r=40);
}
translate ([-20,-20,13])
rotate ([0,0,45])
cube ([19,19,15.5], true);
translate ([-12,-12,2])
    cube ([48,48,18]);
translate ([-20,-20,0])
cylinder (h=20, r=6.5);
}
rotate ([90,0,90])
translate ([15,1.5,40])
linear_extrude(height=6)
 {
   text("A", font = "Verdana", size =17);
 }

```
stackpin.scad:
```
rotate ([180,0,0])
union () {
difference () {
cube ([17.5,17.5,15], true);
    translate ([0,0,3])
    sphere (r=6);
    translate ([0,0,4])
    cube ([4,17.5,15],true);
    translate ([0,0,6])
cylinder (h=3, r1=5, r2=6);
}
translate ([0,0,-12.5])
cylinder (h=5, r=5);
translate ([0,0,-15.5])
sphere (r=5.5);
}

```
stacktop.scad:
```
union (){
cube ([40,40,5]);
cylinder (h=5, r=40);
}
translate ([-20,-20,-5])
union() {
translate ([0,0,10])
cylinder (h=5, r=5);
translate ([0,0,13])
sphere (r=5.5);
}
```


[User]
I'd like a custom keychain generator in OpenSCAD. The design should be a rounded rectangle with customizable dimensions and text on top.

Here are the specific parameters I need to control:

*   **`depth_base`:**  The thickness of the main keychain body. I'd like to be able to adjust this between 1 and 10 mm in 1 mm increments.
*   **`depth_text`:** The thickness of the text that sits on top of the base. It should also be adjustable from 1 to 10 mm in 1 mm increments.
*   **`width`:** The overall width of the keychain. I need to be able to change this from 20 to 150 mm in 10 mm increments.
*   **`height`:** The overall height of the keychain. I'd like to adjust this between 5 and 100 mm in 5 mm increments.
*   **`r`:**  The corner radius of the rounded rectangle. I need to set this between 1 and 50 mm, but I don't need any specific step for this.
*   **`name`:** The text that will be extruded on top. This will just be a string value.

The main body of the keychain should be a rounded rectangle, and if the height is less than or equal to twice the corner radius, then the keychain should be based on a hull of two cylinders, otherwise it should be based on a hull of four cylinders. The text should be placed centered on the top of the base, offset a bit to the right by 4mm. I need a circular hole for the keyring, centered vertically and offset to the left by `width/2 - 7` mm, 6mm in diameter, and extruded all the way through the keychain plus an additional 10mm. Also, the text should be vertically and horizontally centered, and the font size should be equal to `height-6`. I think that's everything.

[Assistant]
keychain.scad:
```
//Base thickness
depth_base = 4; //[1:1:10]
//Text thickness
depth_text = 3; //[1:1:10]
//Keychain width
width = 70; //[20:10:150]
//Keychain height
height = 20; //[5:5:100]
//Corner radius
r = 8; //[1:50]
//Custom Name
name = "Name";

translate([0,0,depth_base/2])
difference(){
union(){
    if(2*r<height)
        hull()
            for(i=[-1,1])
                for(j=[-1,1])
                    translate([i*(width/2 - r), j*(height/2 - r) ,0])
                        cylinder(h = depth_base, r = r, center = true, $fn=48);
    else
        hull()
            for(i=[-1,1])
                translate([i*(width/2 - r), 0 ,0])
                    cylinder(h = depth_base, r = r, center = true, $fn=48);
    translate([4,0,0])
        linear_extrude(depth_base/2+depth_text)
            text(name, size = height-6, valign="center",halign="center");
}
translate([-width/2+7,0,0])
    cylinder(h = depth_text+depth_base+10, d = 6, center = true, $fn=48);
}
```


[User]
Hey, I'm looking to create a customizable ring for a project, kind of like a harness center ring, and I'd like to design it in OpenSCAD. I've got a basic concept in mind, but I need help with making it parametric.

The ring should have a polygonal shape, the number of sides should be adjustable. The corners should be filleted, and I'd like to be able to control the radius of those fillets. There should also be slots around the inside of the ring where straps or belts could pass through. The width and thickness of these slots should be configurable to accommodate different strap sizes. The entire ring should also have a thickness. I'd also like to add some text on the front of the ring, and make the text itself parametric, so I can change what it says, the font, and the font size. Finally, I'd like to be able to rotate the text.

So, to summarize, I need these parameters to be adjustable:

*   `n_sides`: Number of sides of the polygon.
*   `outside_radius`: Radius of the corner fillets.
*   `belt_width`: Width of the belt/strap slots.
*   `belt_thickness`: Thickness of the belt/strap slots.
*   `thickness`: Thickness of the ring itself (plastic thickness).
*   `height`: Extrusion height.
*   `font_size`: Size of the text.
*   `font_text`: Text to display.
*   `font`: Font to use for the text.
*    `text_thickness`: How far the text sticks out above the surface
*   `text_rotation`: Rotation of the text.

I think that should cover everything. Can you help me write the OpenSCAD code for this? I am not using any specialized libraries for this project, just vanilla OpenSCAD. Thanks!

[Assistant]
slotted_ring.scad:
```
/*
*   Configurable Harness Center Ring
*   CudaTox, http://cudatox.ca/l/
*   @cudatox
*
*   Feb 21, 2017
*
*   A procedural strap ring for use in novelty body harnesses with text.
*
*   This software and 3D model(s) are experimental and are provided for educational
*   purposes only.
*
*   Use of this software, any of its derivatives, or use of any of the models or
*   parts provided with or created using this software is done at your own risk.
*
*   DO NOT use this part for securing loads. DO NOT use this part in applications
*   that may result in property damage, injury or death. NOT FOR CLIMBING USE.
*
*
*   This software and files are licensed under the Creative Commons
*   Attribution-NonCommercial 3.0 license.
*
*
*/

belt_width = 25;        //Width of the belt you wish to use
belt_thickness = 3;     //Width of the slots.
n_sides = 5;            //Number of sides on the ring. This script uses a distance
                        //approximation that only works well if this is greater than three.
thickness = 5;          //Thickness of the plastic on all sides
outside_radius = 6;     //Radius of the filleted corners.
height = 4;             //Extrusion height. this is the actual thickness of the object.

font_size = 7;
font_text = "SAMPLE";
font = "Arial";
text_thickness = 1;     //How far the text sticks out above the surface
text_rotation = -90;

$fn = 20;

module rounded_polygon(n_sides, radius, hypotenuse, height){
    //Actual side length does not include the outside radius.

    hull()
    for( i = [0 : n_sides] ){
        translate([hypotenuse * cos(360 * i/n_sides),  hypotenuse * sin(360 * i/n_sides), 0])
            cylinder(h=height, r = radius, center = true);
    }

}

module belt_slot(belt_width, belt_thickness, height){

        hull(){
            translate([0,-belt_width/2,0])
                cylinder(h=height, r = belt_thickness/2, center = true);
            translate([0,belt_width/2,0])
                cylinder(h=height, r = belt_thickness/2, center = true);
        }

}

module belt_slots(n_sides, distance, thickness, belt_width, belt_thickness, height){
    for (i = [0 : n_sides]){
        rotate([0, 0, i * (360 / n_sides) + 180/n_sides])
            translate([distance,0,0])
                belt_slot(belt_width, belt_thickness, height);
    }
}

//inside side virtual length. This is used to calculate how far the belt slots need to be offset.
side_l = belt_width + belt_thickness + thickness;
//Distance to offset the slots.
distance = side_l/2 / tan(180/n_sides);
echo(side_l);
echo(distance);
edge_distance = distance + belt_thickness / 2 + thickness - outside_radius;
hypot = edge_distance / cos(180/n_sides);

difference(){
    union(){
        rounded_polygon(n_sides, outside_radius, hypot, height);
        rotate([0,0,text_rotation])
        color("orange")
        linear_extrude(text_thickness + thickness/2)
            text(font_text, font_size, font, halign="center", valign="center");
    }
    belt_slots(n_sides, distance, belt_width, belt_width, belt_thickness, height);
}
```


[User]
Hey, I'm looking to create a customizable fidget spinner and I think OpenSCAD would be perfect. I'd like a design that's kind of like a multi-armed star, where each arm holds a weight.

Here's what I'm envisioning:

*   **Number of Arms:** I need to be able to set the number of arms (or "faces" as they're called in the included file), anything from 2 to 6 would be great, maybe with a parameter so I can easily change it in the code.
*   **Weight Type:** The weight at the end of each arm should also be a parameter. I want to support different types of weights, specifically:
    *   5/16 inch hex nut
    *   3/8 inch hex nut
    *   M8 hex nut
    *   M10 (16mm) hex nut
    *   M10 (17mm) hex nut
    *  M4 square nut
    *   5/16 inch ball bearing
    *   3/8 inch ball bearing
    *   1/2 inch ball bearing
    *   5/8 inch ball bearing
*   **Corner Radius:** I also want to be able to round the edges where the arms connect to the central bearing, like in the original design. I want to be able to set that radius, which should be expressed in mm.

*  **Central Bearing:** The central part of the spinner should be designed to fit a standard 608 bearing.

I don't need any fancy text or extra shapes, just a good, solid design with those parameters. Also, could you calculate and echo the chosen weight dimensions, including the x, y, and z dimensions? In addition, could you echo a parameter called "resolution" whose value depends on which of the weights is selected? This is very useful for debugging.

I'd like to see if you can generate the whole thing as a parametric OpenSCAD file for me!

[Assistant]
surprise-2017-10-04.scad:
```
// lucina
// 2017-04-11

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

// the number of faces
faces = 4; //[2,3,4,5,6]

// the type of weight
whichWeight = "3/8 hex nut";   //[5/16 hex nut, 3/8 hex nut, M8 hex nut, M10 16 hex nut, M10 17 hex nut, M4 square nut, 5/16 ball bearing, 3/8 ball bearing, 1/2 ball bearing, 5/8 ball bearing]

// corner radius in mm; > 0 causes timeout but Create Thing still works
radius = 2;  //[0:.5:3]

/* [Hidden] */
$fn = 60;
x = 0; y = 1; z = 2;
thick = 2.5;
offset = 22;
inch = 25.4;

bearing = [22, 22, 7]; //608 bearing
sae = [.577*inch, .5 * inch, 7]; // 5/16 hex nut
sae38 = [.650*inch,.562*inch, 7];	// 3/8
metric8 = [15, 13, 6.5];   // M8 hex nut
metric10_16 = [18.48, 16, 8.4];   // M10 16 hex nut
metric10_17 = [19.63, 17, 8];   // M10 17 hex nut
metric4sq = [7, 7, 3.2];
ball516 = [5/16*inch, 5/16*inch, 5/16*inch];
ball38 = [3/8*inch, 3/8*inch, 3/8*inch];
ball12 = [1/2*inch, 1/2*inch, 1/2*inch];
ball58 = [5/8*inch, 5/8*inch, 5/8*inch];
weight = (whichWeight == "608 bearing") ? bearing :
   (whichWeight == "5/16 hex nut") ? sae :
   (whichWeight == "3/8 hex nut") ? sae38 :
   (whichWeight == "M8 hex nut") ? metric8 :
   (whichWeight == "M10 16 hex nut") ? metric10_16 :
   (whichWeight == "M10 17 hex nut") ? metric10_17 :
   (whichWeight == "5/16 ball bearing") ? ball516 :
   (whichWeight == "3/8 ball bearing") ? ball38 :
   (whichWeight == "1/2 ball bearing") ? ball12 : ball58;
echo(whichWeight, weight[x], weight[y], weight[z]);

resolution = (whichWeight == "5/16 hex nut") ? 6 :
   (whichWeight == "3/8 hex nut") ? 6 :
   (whichWeight == "1/2 hex nut") ? 6 :
   (whichWeight == "M8 hex nut") ? 6 :
   (whichWeight == "M10 16 hex nut") ? 6 :
   (whichWeight == "M10 17 hex nut") ? 6 :
   (whichWeight == "M4 square nut") ? 4 : 60;
echo("resolution=", resolution);

step = 360 / faces;
stop = (faces-1) * step;
enlarge = 1.8;

module surprise(rad, wt) {
   diam = wt[x]*enlarge;
   eye = diam / 7.5;
   rotate([0, 0, -90])
      difference() {
         fcylinder(bearing[z], diam, rad);
         union() {
            translate([-diam/7.5, diam/4, 0])
               scale([1, 1.2, 1])
                  cylinder(bearing[z]*2, d=eye, center=true);
            translate([diam/7.5, diam/4, 0])
               scale([1, 1.2, 1])
                  cylinder(bearing[z]*2, d=eye, center=true);
            translate([0, -diam/7.75, 0])
               cylinder(bearing[z]*2, d=wt[x], center=true, $fn = resolution);
         }
      }
}

module fcylinder(z, x, rad) {
   translate([0, 0, rad-z/2])
      minkowski() {
         cylinder(h=z-2*rad, d=x-2*rad, center=true);
         sphere(rad);
      }
}

difference() {
   union() {
      for ( angle = [0 : step : stop] ) {
         rotate([0, 0, angle]) {
            fcylinder(bearing[z], bearing[x]+2*thick, radius);
            translate([(bearing[x]+ weight[x]*enlarge)/2+thick/3, 0, 0])
               surprise(radius, weight);
         }
      }
   }
   // bearing hole
   cylinder(h=2*bearing[z], d=bearing[x], center=true);
}

```


[User]
I'd like to design a loaded die, similar to the one described in the provided SCAD code, but I want more flexibility in the design parameters. Basically, I need an OpenSCAD model that generates a standard six-sided die with a cavity for a nut to make it weighted. I need it to be fully parametric.

Here's what I'm looking for:

*   **Die Size:** The edge length of the die should be adjustable.
*   **Nut Cavity:** The cavity should be sized to fit a specific nut. I need to be able to specify the wrench size of the nut and the nut's height. I also need a tolerance value to be applied to the nut cavity so that it's not too tight.
*   **Nut Positioning:** The cavity should be on the face opposite the number chosen to be the most likely to land face up.
*   **Number Selection:** I need a parameter to select the number that will most often be on top when the die is rolled. This should affect which face has the nut cavity.
*   **Layer Height:** I need a parameter for layer height that is used to precisely position the nut cavity and create an indicator layer to show when to insert the nut during printing.
*   **Dot Design:** The dot design should be similar to a standard die - dots should be spherical and of a user definable diameter. Dot spacing should also be parametric. The dots should be subtracted from the die cube.
*   **Rounded Corners:** I would like to have rounded corners using a sphere, similar to the provided code.

I would like the code to be well-commented, and I would like it to be structured using modules, similar to what's provided in the original SCAD file.
I also need this to work using only standard OpenSCAD functions; no libraries needed, such as MCAD, BOSL, BOSL2, dotSCAD, NopSCADlib, or BOLTS. I'd like it in a single .scad file.

[Assistant]
loaded_die_thingiverse.scad:
```
/*
* @author Timo Novak
* @date 2017-03-03
*
* This generates a loaded dice which will have a not-centered center of mass. This ist made by inserting a nut on one side.
*/

//which will more often roll on top
number=6; //[1,2,3,4,5,6]

//of the die in mm (default is 15 mm)
Edge_length=23;
//(in mm)
wrench_size = 17;
//(in mm)
nut_height = 8;

//(in mm) which your print setting is, needed for correct slicing of the indicator
layer_height = .25;

/* [Hidden] */

$fs = 1;
nut_tolerance = .4; //added to wrench size

dot_dia = Edge_length/5;
dot_distance = Edge_length*7/30;

//Height of the nut, fitted to number of layers necessary for it
nut_height_actual = layer_height*ceil(nut_height/layer_height);

//Starting height of the nut, fitted to layer height
start_height = layer_height*ceil((dot_dia/2+1)/layer_height);

//Top height of the nut, fitted to layer height
top_height = start_height+nut_height_actual;

print_part();

module print_part(){
	die();
}

module die(){
		difference(){
			bare_die();
			dots_rotated();
			nut();
			indicator();
		}
}

//Die without dots, corners rounded with a sphere
module bare_die(){
    translate([0,0,Edge_length/2])
	intersection(){
		cube(Edge_length, center = true);
		sphere(d = Edge_length*1.4, $fa = 5);
	}
}

module nut(){
    dia = (wrench_size+nut_tolerance)*2/sqrt(3);
    translate([0,0,start_height])
    cylinder(d = dia, h = nut_height_actual,$fn = 6 );
}

//An indicator to show when you can put in the nut. It is one layer high. When the layer with the indicator is printed, put in the nut. The next layer will cover it.
module indicator(){
	indi_len = wrench_size;
	translate([-indi_len/2,-indi_len/2,top_height-layer_height]){
	cube([indi_len,indi_len,layer_height]);
	}
}

module dots_cropped(){
	intersection(){
		dots_rotated();
		translate([0,0,Edge_length/2])
		cube(Edge_length, center = true);
	}
}

//Dots that are subtracted from the die surfaces. Rotated, so that the nut is opposite from the side which will fall on top.
module dots_rotated(){
		translate([0,0,Edge_length/2]){
		if(number ==6){
			dots();
		}else if(number == 1){
			rotate([0,180,0])
			dots();
		}else if(number == 2){
			rotate([0,90,0])
			dots();
		}else if(number == 5){
			rotate([0,-90,0])
			dots();
		}else if(number == 3){
			rotate([90,0,0])
			dots();
		}else if(number == 4){
			rotate([-90,0,0])
			dots();
		}
	}
}
module dots(){
    //1
    translate([0,0,-Edge_length/2])
        dot_center();
    //6
    translate([0,0,Edge_length/2]){
        dot_topleft();
        dot_centerleft();
        dot_bottomleft();
        dot_topright();
        dot_centerright();
        dot_bottomright();
    }
    //2
    rotate([0,-90,0])
        translate([0,0,Edge_length/2]){
            dot_topright();
            dot_bottomleft();
        }

    //5
    rotate([0,90,0])
        translate([0,0,Edge_length/2]){
            dot_center();
            dot_topleft();
            dot_bottomleft();
            dot_topright();
            dot_bottomright();
        }
    //3
    rotate([-90,0,0])
        translate([0,0,Edge_length/2]){
            dot_center();
            dot_topright();
            dot_bottomleft();
        }
    //4
        rotate([90,0,0])
        translate([0,0,Edge_length/2]){
            dot_topleft();
            dot_bottomleft();
            dot_topright();
            dot_bottomright();
        }
}

module dot_center(){
    scale([1,1,.5])
    sphere(d = dot_dia);
}

module dot_topleft(){
    translate([0,dot_distance,0])
    dot_centerleft();
}

module dot_centerleft(){
    translate([-dot_distance,0,0])
    dot_center();
}

module dot_bottomleft(){
    mirror([0,1,0])
    dot_topleft();
}

module dot_topright(){
    mirror([1,0,0])
    dot_topleft();
}

module dot_centerright(){
    mirror([1,0,0])
    dot_centerleft();
}

module dot_bottomright(){
    mirror([1,0,0])
    dot_bottomleft();
}

```


[User]
Hey, I'm looking to design some parametric thumbwheels for 3D printer bed leveling, and I want something a bit more functional than just a plain cylinder. I've got a basic idea in mind, but I'd like your help generating the OpenSCAD code for it.

Essentially, I need a thumbwheel with the following features:

*   **Basic Shape:** It should be a cylinder with a center hole for a screw.
*   **Outer Diameter and Height:** I'd like these to be parameters, so I can easily change the size. Let's start with a default outer diameter of 25mm and a height of 5mm.
*   **Center Hole:** A center hole, also with a parameter for the diameter. Default to 3.2mm for an M3 screw.
*   **Hex Nut Trap:** I want a hexagonal cutout on the underside (not going all the way through) to trap a nut. The size of this hex (diameter of the inscribed circle), and depth of the cut should also be parameters. Let's make the default hex size 5.5mm (for an M3 nut), and a default hex depth of 3mm. Also, let's make the hex cut out from the bottom of the wheel.
*  **Top Grooves:** I need some grooves on the top surface of the wheel to make it easier to grip and turn. I want these to be radial, and fairly shallow. They can be simple cylinder cuts, let's do four of them to start. The diameter of each groove (the cutout cylinder) and their offset should be parameters, let's go with a default groove diameter of 3mm. I want the grooves to cut into the face, and go deep enough so they will be visible.
*   **Knurled Edge:** The outside edge needs a knurled pattern. I want to specify the number of cutouts for the knurling and the diameter of the cutouts with parameters. Let's start with 20 knurl cutouts, and a cutout diameter of 3mm.

I think that's everything. Could you generate the OpenSCAD files for me, with all those parameters adjustable? I don't need any libraries except the standard OpenSCAD ones (like for cylinders, differences, etc.). Thanks so much!

[Assistant]
thumb_wheel-hj.scad:
```
// ******************************
// *   Parametric thumb wheel   *
// *   by Chris Garrett         *
// *   20-nov-2011              *
// ******************************

// *** Configuration variables ***
// Outer Diameter of the thumb wheel
wheel_d = 20;
// Height of the thumb wheel
wheel_h = 3.5;
// Diameter of center hole
hole_d = 4.5;
// Size of the hex (nut trap - 5.5=m3, 7=m4)
hex_sz = 5.5;

// An M4 nut fits perfectly in a 7mm hex opening made on my Prusa

// Depth of the hex (set this < or = to wheel_h)
hex_d = 2.5;

// Number of cutouts around the wheel
knurl_cnt = 16;

// Diameter of the cutouts
knurl_d = 3;

// *** Code area ***

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

module hexagon(height, depth) {
 boxWidth=height/1.75;
 union() {
  box(boxWidth, height, depth);
  rotate([0,0,60]) box(boxWidth, height, depth);
  rotate([0,0,-60]) box(boxWidth, height, depth);
 }
}

// The thumb wheel

difference() {
 cylinder(h=wheel_h, r=wheel_d/2, $fn=50);
 translate([0,0,-1]) cylinder(h=wheel_h+2, r=hole_d/2, $fn=50);
 if (hex_d >= wheel_h) {
   translate([0,0,-1]) hexagon(height=hex_sz, depth=wheel_d+2);
 } else {
  translate([0,0,wheel_h-hex_d]) hexagon(height=hex_sz, depth=hex_d+1);
 }

  for (i=[0:3]) {
     rotate(v=[0,0,1], a=i*360/8) translate([0,0,-wheel_h/5]) rotate(v=[1,0,0], a=90) translate([0,0,-1.2*(wheel_d/2)]) cylinder(h=wheel_d*1.2, r=knurl_d/2, $fn=50);
 }

 for(i = [0:knurl_cnt-1]) {
  rotate(v=[0,0,1], a=i*360/knurl_cnt) translate([0,wheel_d/2,-1]) cylinder(h=wheel_h+2, r=knurl_d/2, $fn=50);
 }

}
```


[User]
Hey, I'm looking to get a custom coin container designed in OpenSCAD, and I need it to be parametric. I'd like to be able to specify the coin dimensions, how many coins it should hold, the thickness of the walls, and the height of the cap. It should be a simple cylinder with a cap, and I'd like the option to generate just the container, just the cap, or both as a pair.

Specifically, I need to be able to set these parameters:

*   `part`: This should be a string parameter that lets me choose "container only", "cap only", or "both" to generate the corresponding parts.
*   `numberOfCoins`: An integer representing how many coins the container should hold.
*   `coinHeight`: The height of a single coin (in millimeters).
*   `coinDiameter`: The diameter of a single coin (in millimeters).
*   `capHeight`: The height of the cap (in millimeters).
*   `wallThickness`: The thickness of the walls of both the container and the cap (in millimeters).

The container should have a cylindrical body with a wall thickness and a slightly thicker base. The inner diameter of the container should match the coin diameter, and the height should accommodate the specified number of coins stacked vertically. The cap should also be a cylinder with a wall thickness, and it should fit snugly over the top of the container. The cap's inner diameter should be equal to the container's outer diameter. When generating both parts, I want the cap to be positioned to the side of the container, not on top. I'm picturing a simple, clean design. Also, please make sure that the code uses a higher `$fn` value for better circular results. Maybe a value of 100 would be good.

I don't need any fancy features, just a good, solid parametric design that I can easily customize for different coin sizes, etc. Can you help me create this?

[Assistant]
CoinContainer.scad:
```
/*
**  Name:  Customizable Coin Container_3d_model
**  Author:  Chris Benson  @TheExtruder
**  Created:  2/24/2017
*/
part = "both" ; // [first:Container Only,second:Cap Only,both:Container and Cap]

numberOfCoins = 10; //[1:1:100]

//in millimeters
coinHeight = 3;
//in millimeters
coinDiameter = 41;
//in millimeters.  The final height will this value + the wall thickness.
capHeight = 5;

wallThickness = 1;

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

print_part();

module print_part() {
	if (part == "first") {
		//container
        CreateContainer();
	} else if (part == "second") {
		//cap
        CreateCap();
	} else if (part == "both") {
		CreateContainerAndCap();
	} else {
		CreateContainerAndCap();
	}
}

module CreateContainer(){
    CreateCylinder(numberOfCoins * coinHeight, coinDiameter, wallThickness);
}

module CreateCap(){
    CreateCylinder(capHeight, coinDiameter + wallThickness * 2, wallThickness);
}

module CreateContainerAndCap(){
    CreateContainer();
    translate([coinDiameter + wallThickness + 5,0,0])
        CreateCap();
}

module CreateCylinder(height,innerDiameter,wallThinkness){
    union(){
        //bottom
        cylinder(wallThickness, d=innerDiameter + (wallThickness * 2), true);

        translate([0,0,wallThickness]){
            difference(){
                //outer wall
                cylinder(height, d=innerDiameter + (wallThickness * 2), true);
                //inner wall
                cylinder(height, d=innerDiameter, true);
            }
        }
    }
}
```


[User]
I need to create a customizable coin container, and I'd like it to be a bit more sophisticated than the one I have. I'd like to specify the coin type, the number of coins it should hold, and a few other parameters.

Here's what I'm envisioning:

**Coin Types:**
I'll need containers for the following US coins:
   * Pennies
   * Nickels
   * Dimes
   * Quarters
   * Dollar coins (both standard and silver eagle)

**Customization Options:**
   *  *Coin Type*:  As listed above
   *  *Number of Coins*: The total number of coins the container should hold.
   *  *Wall Thickness*: The thickness of the container walls.
   *  *Cap Height*: The height of the cap.
   *  *Clearance*:  A small clearance value between the coins and the inner walls of the container (perhaps defaulted, but modifiable) to ensure coins slide in and out easily.  I would like the clearance to also be applied on the cap.
   *  *Base Thickness*:  The thickness of the base of the container
   *  *Cap Thread Length*:  The thread length for screw-on cap.
    *  *Thread Type*: I need to be able to toggle between a simple cylindrical snap-fit cap and a screw-on threaded cap.

**Functionality and Design:**
   * The container should consist of a cylindrical tube and a cap.
   * The cap should be able to either snap on or screw on. For a screw on cap, I'd like an option to specify the thread length.
   * There should be sufficient inner diameter and height to hold the specified number of coins of the chosen type, along with the specified clearance.
   * I'd like the code to use the `BOSL2` library for threading and other functions, but other than that, keep it as vanilla OpenSCAD as you can.

Could you generate an OpenSCAD file for this? I would prefer a design using multiple .scad files, one for the container module itself, one for the cap module, and the main one that brings them together.

[Assistant]
AmericanCoinContainers.scad:
```
/*
**  Name:  Customizable American Coin Container_3d_model
**  Author:  Chris Benson  @TheExtruder
**  Created:  2/24/2017
*/
coin = "Dollar" ; // [Pennies,Nickels,Dimes,Quarters,Dollar,Silver Eagles]

numberOfCoins = 25;

/* [Hidden] */
$fn = 100;
capHeight = 5;
wallThickness = 1;

print_part();

module print_part() {
	if (coin == "Pennies") {
        CreateContainerAndCap(
            numberOfCoins = numberOfCoins,
            coinHeight = 1.54,
            coinDiameter = 19.07,
            wallThickness = wallThickness,
            capHeight = capHeight
        );
	} else if (coin == "Nickels") {
        CreateContainerAndCap(
            numberOfCoins = numberOfCoins,
            coinHeight = 1.97,
            coinDiameter = 21.23,
            wallThickness = wallThickness,
            capHeight = capHeight
        );
	} else if (coin == "Dimes") {
		CreateContainerAndCap(
            numberOfCoins = numberOfCoins,
            coinHeight = 1.37,
            coinDiameter = 17.93,
            wallThickness = wallThickness,
            capHeight = capHeight
        );
    } else if (coin == "Quarters") {
		CreateContainerAndCap(
            numberOfCoins = numberOfCoins,
            coinHeight = 1.77,
            coinDiameter = 24.28,
            wallThickness = wallThickness,
            capHeight = capHeight
        );
    } else if (coin == "Dollar") {
		CreateContainerAndCap(
            numberOfCoins = numberOfCoins,
            coinHeight = 2.02,
            coinDiameter = 25.7,
            wallThickness = wallThickness,
            capHeight = capHeight
        );
    } else if (coin == "Silver Eagles") {
		CreateContainerAndCap(
            numberOfCoins = numberOfCoins,
            coinHeight = 3,
            coinDiameter = 41,
            wallThickness = wallThickness,
            capHeight = capHeight
        );
	}
}

module CreateContainerAndCap(numberOfCoins, coinHeight, coinDiameter, wallThickness, capHeight){
    CreateCylinder(numberOfCoins * coinHeight, coinDiameter, wallThickness);
    translate([coinDiameter + wallThickness + 5,0,0])
        CreateCylinder(capHeight, coinDiameter + wallThickness * 2, wallThickness);
}

module CreateCylinder(height,innerDiameter,wallThinkness){
    union(){
        //bottom
        cylinder(wallThickness, d=innerDiameter + (wallThickness * 2), true);

        translate([0,0,wallThickness]){
            difference(){
                //outer wall
                cylinder(height, d=innerDiameter + (wallThickness * 2), true);
                //inner wall
                cylinder(height, d=innerDiameter, true);
            }
        }
    }
}
```


[User]
Hey there! I'm looking to create a customizable T-frame system, kind of like the one on Thingiverse (thing:1961848), but I want it to be parametric so I can easily adjust it for my specific needs. I'm thinking this should be a pretty straightforward OpenSCAD project.

Here’s what I need:

1. **Overall Frame Length:** I need to be able to specify the total length of the T-frame system. The code should then calculate how many individual frame segments are needed based on my printer's Z-height. It'll then cut the T-frame up into sections that fit within that height.
2. **Printer Z-Height:** It needs to be aware of the maximum print height of my printer, so the frame segments don't get taller than that and I can actually print them.
3. **Pin/Hole Tolerance:** I want to be able to set a tolerance value to adjust how tightly the pins and holes fit together. This is important for getting good connections, especially if my printer has some backlash or other minor inaccuracies. It should make the holes larger and the pins smaller by the tolerance value.
4. **Automatic Placement:** The individual T-frame segments should be automatically arranged, so the pins and holes line up and I can glue them into a continuous frame.
5. **Print Bed Size (Future):** Ideally, I would eventually like to specify the dimensions of my printer's bed, and the system would arrange the frame segments to fit the bed. For now, I'm happy with a square arrangement. Just keep that in mind for future additions.
6.  **Core Profile:** The main shape of each segment has the following:
    *  A cube of 20x20mm with a center hole of radius 2.5
    *  A groove, with length extending past the main cube, on each side of the cube that is offset 6.1mm from the edge of the 20x20 cube.
    *   The groove contains the following: a 12x12mm cube which has corners cut off. Cut out from this cube on the sides are two cubes that are 6.5mm wide with a 1.5mm wall on the outside.
    *   The groove extends past the end of the 20x20 cube in the z direction.

7.  **Pin and Hole Creation:**
    *    The T-frames that connect should alternate. For each T-frame in the chain there should either be a pin and a matching hole or a hole by itself. For the beginning of the T-frame there should only be a pin on the end. For the very end, there should only be a hole.
    *    The pin is a 5.4x5.4mm cube. The pin height is 7mm.
    *   The hole is a 5.4x5.4mm hole with rounded corners. The corners are made by subtracting a 2mm radius circle. The hole height is 8mm.
8.  **Pin and Hole Placement:** The pins/holes should be centered on top of the T-frames. They should be placed at the very end of the segments.

I'm not looking for anything too fancy. I just want it to work and be easily adjustable. I don't want to use any external libraries for this simple project. Let me know what you think!

[Assistant]
2020Tv1.0.scad:
```
profileLength = 1000;
//printX = 150; Not implemented
//printY = 150; Not implemented
printZHeight = 230;
printTolerance = 0.25; //Change dimensions of pin and hole 0.25mm equals gab of 0.5 mm
spaceBetweenProfiles = 5;
$fa=0.5; // default minimum facet angle is now 0.5
$fs=0.5; // default minimum facet size is now 0.5 mm

if(profileLength <= printZHeight) {
	translate([10,10,profileLength/2]) profile(profileLength);
} else {
	numOfProfiles = ceil(profileLength/(printZHeight-8));
	numOfRow = ceil(sqrt(numOfProfiles));
	currentProfile = 2;
	start = 0;
	translate([start,start,0]) profileWithPin(profileLength/numOfProfiles, printTolerance);
	for(row=[0:numOfRow-1]) {
		for(col=[0:numOfRow-1]) {
			if(row*numOfRow+col < numOfProfiles-1 && row*numOfRow+col > 0) {
				translate([start+row*(20+spaceBetweenProfiles),start+col*(20+spaceBetweenProfiles),0]) profileWithHoleAndPin(profileLength/numOfProfiles, printTolerance);
			} else {
				if(row*numOfRow+col < numOfProfiles) {
					translate([start+row*(20+spaceBetweenProfiles),start+col*(20+spaceBetweenProfiles),0]) profileWithHole(profileLength/numOfProfiles, printTolerance);
					lastProfileDone = 1;
				}
			}
		}
	}
}

module hole(height, size) {
	radius = 1;
	divider = 1.6;
	union() {
		cube([size,size,height], center = true);
		translate([size/2-radius/divider,size/2-radius/divider,0]) cylinder(h=height, r=radius, center = true);
		translate([size/2-radius/divider,-size/2+radius/divider,0]) cylinder(h=height, r=radius, center = true);
		translate([-size/2+radius/divider,size/2-radius/divider,0]) cylinder(h=height, r=radius, center = true);
		translate([-size/2+radius/divider,-size/2+radius/divider,0]) cylinder(h=height, r=radius, center = true);
	}
}

module profileWithPin(length, tolerance) {
	height = 8 - tolerance - 1;
	size = 5.4 - tolerance;
	plunge = 5;
	translate([10,10,length/2]) union() {
		profile(length);
		translate([0,0,length/2+(height+plunge)/2-plunge]) cube([size,size,height+plunge], center = true);
	}
}

module profileWithHole(length, tolerance) {
	height = 8 + tolerance;
	size = 5.4 + tolerance;
	plunge = 1;
	translate([10,10,length/2]) difference() {
		profile(length);
		translate([0,0,length/2-(height+plunge)/2+plunge]) hole(height+plunge, size);
	}
}

module profileWithHoleAndPin(length, tolerance) {
	heightHole = 8 + tolerance;
	heightPin = 7 - tolerance;
	size = 5.4;
	plunge = 1;
	translate([10,10,length/2]) union() {
		difference() {
			profile(length);
			translate([0,0,-length/2+(heightHole+plunge)/2-plunge]) hole(heightHole+plunge, size+tolerance);
		}
		translate([0,0,length/2+(heightPin+plunge)/2-plunge]) cube([size-tolerance,size-tolerance,heightPin+plunge], center = true);
	}
}

module profile(length) { // generate a profile based on length
	difference() {
		// Create main body
		cube([20,20,length], center = true);

		// Create hole in middle
		cylinder(r=5/2, h=length+2, center = true);

		// Create groove
		grooveLength = length + 2;
		lengthOfCenterSide = 5.75;
		gabWidth = 6.5;
		gabDepth = 6.1;
		sizeOfCube = 12;
		gabFrontWallWidth = 1.5;
		sizeOfCornerCube = sqrt(pow(sizeOfCube/2, 2)*2);
		for(i = [0:90:270]) {
			rotate([0,0,i]) translate([sizeOfCube/2-gabDepth+20/2,0,0]) difference() {
				cube([sizeOfCube,sizeOfCube,grooveLength], center = true);
				translate([-sizeOfCube/2,-sizeOfCube/2-lengthOfCenterSide/2,0]) rotate([0,0,45]) cube([sizeOfCornerCube,sizeOfCornerCube,grooveLength+2], center = true);
				translate([-sizeOfCube/2,sizeOfCube/2+lengthOfCenterSide/2,0]) rotate([0,0,45]) cube([sizeOfCornerCube,sizeOfCornerCube,grooveLength+2], center = true);
				translate([gabDepth-gabFrontWallWidth,sizeOfCube/2+gabWidth/2,0]) cube([sizeOfCube,sizeOfCube,grooveLength+2], center = true);
				translate([gabDepth-gabFrontWallWidth,-sizeOfCube/2-gabWidth/2,0]) cube([sizeOfCube,sizeOfCube,grooveLength+2], center = true);
			}
		}
	}
}
//cube([20,20,length]);
```


[User]
I'd like to design a toy train barrel, specifically one that's compatible with Brio and similar wooden train sets. I want it to be customizable, so I'm thinking a parametric OpenSCAD design would be perfect.

Here’s what I have in mind:

The barrel itself should be a cylinder with a few raised rings around it, like a typical barrel. I’d like to be able to adjust the overall height and diameter of the cylinder, as well as the number and position of the rings. The rings should be created via rotate_extrude. There should be a small peg on one side to simulate a handle. Also, I'd like to be able to add text to the barrel and have its position be adjustable. The text should be created using linear_extrude and should be able to be positioned at the top, middle, or bottom of the barrel, based on user input. Finally, it would need to have a central hole going all the way through it, suitable for fitting on a train car.

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

*   **`barrel_height`**: The total height of the barrel.
*   **`barrel_diameter`**: The diameter of the main barrel cylinder.
*   **`ring_count`**: The number of raised rings around the barrel.
*   **`ring_height`**: The height of the raised rings.
*   **`ring_offset`**: Determines where the rings are located along the barrel height (e.g. at equal spacing, or all at one end).
*   **`text_on_barrel`**: The text that will be printed on the barrel.
*   **`text_location`**: Where to place the text, with options like "Top," "Middle," and "Bottom."
*   **`text_size`**: The font size of the text on the barrel.
*  **`peg_diameter`**: The diameter of the small peg handle
*   **`peg_height`**: The height of the small peg handle
*   **`hole_diameter`**: The diameter of the hole through the middle of the barrel.

For the text, I'd like to use Arial Bold font. I would also want the text to be arranged in a circle around the barrel.

I do not have any existing OpenSCAD code to provide as guidance. Please generate this from scratch.

[Assistant]
train_barrel.scad:
```
// Text on barrel
TextOnBarrel="OIL";
// Text position on barrel
TextLocation="Middle"; // [Top, Middle, Bottom]

module ring(dout=32,height=2) {
rotate_extrude(convexity = 10, $fn = 50)
translate([dout/2+0.1, 0, 0])
circle(r = height/2-0.3, $fn = 50);
}

module barrel(hi=35,di=30) {
cylinder(h=hi,d=di,$fn=50);
    translate([0,0,0.5]) {
ring(dout=di-1);
    }
translate([0,0,hi/3]) {
    ring(dout=di-1);
}
translate([0,0,hi*2/3]) {
    ring(dout=di-1);
}
translate([0,0,hi-0.5]) {
    ring(dout=di-1);
}
translate([4,0,hi-1.8]){
cylinder(d=3,h=2,$fn=50);
}
}

module barreltext(txt=TextOnBarrel,deg=14,fsize=3,dia=20) {
    for (v = [0:deg:len(txt)*deg]) {
        rotate([90,0,v]) {;
           translate([0,0,dia]) {
                linear_extrude(height=5) {
                text(txt[v/deg],size=fsize,font="Arial:style=bold",halign="center");
                }
            }
        }
    }

    }

module main() {
    rotate([0,0,-45]) {
difference() {
barrel(hi=23,di=15);
    translate([0,0,-5]) {
    cube([50,50,10],center=true);
    }
}
intersection() {
    if (TextLocation=="Top") {
    translate([0,0,(23*4/5)-1]) {
        barreltext(dia=7,fsize=3,deg=20);
    }
    } else if (TextLocation=="Middle") {
    translate([0,0,23/2-1.5]) {
        barreltext(dia=7,fsize=3,deg=20);
    }
    } else if (TextLocation=="Bottom") {
    translate([0,0,(23/5)-2]) {
        barreltext(dia=7,fsize=3,deg=20);
    }
    }
    cylinder(h=35,d=15.6,$fn=50);
}
}
}

main();
```