[User]
I'd like to design a parametric card holder for a board game, specifically Settlers of Catan. I have a basic design in mind, but I want it to be fully customizable. Here's what I'm thinking:

The card holder should have a base plate, four long walls, and four short walls to hold the cards.  The card dimensions should be parameters so I can use this for other card games. Let's call these `card_x` for the short side and `card_y` for the long side. The default sizes would be 54mm and 80mm respectively. I also need a `card_space` parameter to define the gap between cards and the walls, and a `wall_thickness` parameter for the wall thickness.  The base plate should have a `plate_height` parameter, and the walls a `wall_height` parameter.

I'd like to have an option for a logo on the base. This should be a simple "C" shape, and controlled with a boolean parameter named `show_logo`.

Here's where it gets more interesting.  I need connectors so multiple holders can be connected to each other. I want to be able to specify the connector types on each side of the holder with a `connectors` parameter, which can take the values "both", "none", "female", or "male". So, I could, for example, have a card holder that has male connectors on one side and female on the other.

The male and female connectors will have specific dimensions, I have those:

*   The "female" part should be 21mm at the widest point and 12.5mm at the narrowest and 10mm deep.
*   The "male" part should be 19.8mm at the widest point and 10.46mm at the narrowest and 11.4mm long.
The connectors should be tapered on the sides.

I expect to use libraries to help with the math of the connectors, specifically the `BOSL` library would be helpful for the more complex shapes. I expect the final shape to be a single part, I'll be printing these in one go.

Could you generate the OpenSCAD code for this?

[Assistant]
card_holder.scad:
```
//Settlers game card holder
// 1 to 1 copy of previous blender version but with parameters for changeing dimention

//Constants
// Card short side in mm (Default settlers card 54mm)
card_x = 54;

// Card long side in mm (Default settlers card 80mm)
card_y = 80;

show_logo = "yes"; // [yes,no]

connectors = "both";  // [both,none,female,male]

// Gap between card and the walls of the holder
card_space = 2; //original 2
wall_thickness = 3; //original 2
plate_height = 3; //original 2
wall_height = 12; //original 12
shortwall_cut = card_x/(card_y/card_x);
shortwall = (card_x-shortwall_cut)/2+wall_thickness+card_space/2;

//Connecting piece
//the "female" part is 21mm at the biggest point and 12.5mm at the smallest and 10mm deep
//the "male" part is  19.8mm at the biggest point and 10.46mm at smallest and 11.4mm long
//the odd numbers are because i used a manualy freehand modifed box with no real grid snapping, and some random scaling
// ignore variable values
female_con_x = 10+1-1;
female_con_y1 = 21+1-2;
female_con_y2 = 12.5+1-1;
male_con_x = 11.4+1-1;
male_con_y1 = 19.8+1-1;
male_con_y2 = 10.46+1-1;
angle = atan( ((female_con_y1-female_con_y2)/2) / female_con_x ); // same for both

union() {

	difference() {
		//Base plate
		cube(size = [card_x+card_space+wall_thickness*2, card_y+card_space+wall_thickness*2,plate_height], center = true);
		//Round Cut
		// was made with a cylinder with radius=32 scaled in x and y by 0.8, resulting in R=25.6 and that is aprox card_x
		translate([0,card_y/1.27,-card_x/4])
		cylinder(card_x/2, card_x/2, card_x/2, $fa=2);
		translate([0,-card_y/1.27,-card_x/4])
		cylinder(card_x/2, card_x/2, card_x/2, $fa=2);

		//Logo
		if (show_logo == "yes") {
			union() {
				translate([0, -4.5, 0])
				cube(size = [19,9,10], center = true);
				difference() {
					translate([-4.5, 0.5 ,0])
					cube(size = [10,19,10], center = true);
					translate([0.5, 12 ,0])
					rotate([0, 0, 45])
					cube(size = [10,12,11], center = true);
					translate([-9.5, 12 ,0])
					rotate([0, 0, 45])
					cube(size = [12,10,11], center = true);
				}
			}
		}

		//female con
		if (connectors == "both" || connectors == "female") {
			translate( [ (card_x/2) - female_con_x + card_space/2 + wall_thickness +0.01 , -female_con_y1/2, -plate_height ] ) //0.01 is for overlapping
			difference() {
				cube(size = [female_con_x, female_con_y1, plate_height*2], center = false);
				translate( [ 0,female_con_y1,-1 ] )
				rotate([0, 0, -angle])
				cube(female_con_x*2);
				translate( [ 0,0,-1 ] )
				rotate([0, 0, angle-90])
				cube(female_con_x*2);
			}
		}
	}

	//male con
	if (connectors == "both" || connectors == "male") {
		translate( [ -(card_x/2) - card_space/2 - wall_thickness - male_con_x, -male_con_y1/2, -plate_height/2 ] )
		difference() {
			cube(size = [male_con_x, male_con_y1, plate_height], center = false);
			translate( [ 0,male_con_y1,-1 ] )
			rotate([0, 0, -angle])
			cube(male_con_x*2);
			translate( [ 0,0,-1 ] )
			rotate([0, 0, angle-90])
			cube(male_con_x*2);
		}
	}

	//Cards for reference
	//%cube(size = [card_x,card_y,9], center = true);
	//%cube(size = [card_y,card_x,9], center = true);

	//%cube(size= [shortwall_cut, 100,20], center = true);

	// Long wall 1 of 4
	translate([  (card_x+card_space+wall_thickness*2)/2 , (card_y+card_space+wall_thickness*2)/2 ,plate_height/2])
	rotate([0,0,180])
	cube(size = [wall_thickness,(card_y-card_x)/2+wall_thickness+card_space/2,wall_height] ,center = false);

	// Long wall 2 of 4
	translate([  -(card_x+card_space+wall_thickness*2)/2 +wall_thickness , (card_y+card_space+wall_thickness*2)/2 ,plate_height/2])
	rotate([0,0,180])
	cube(size = [wall_thickness,(card_y-card_x)/2+wall_thickness+card_space/2,wall_height] ,center = false);

	// Long wall 3 of 4
	translate([  (card_x+card_space+wall_thickness*2)/2 -wall_thickness, -(card_y+card_space+wall_thickness*2)/2 ,plate_height/2])
	rotate([0,0,0])
	cube(size = [wall_thickness,(card_y-card_x)/2+wall_thickness+card_space/2,wall_height] ,center = false);

	// Long wall 4 of 4
	translate([  -(card_x+card_space+wall_thickness*2)/2 , -(card_y+card_space+wall_thickness*2)/2 ,plate_height/2])
	rotate([0,0,0])
	cube(size = [wall_thickness,(card_y-card_x)/2+wall_thickness+card_space/2,wall_height] ,center = false);

	//Shortwall 1 of 4
	//the cut to make the space between the walls was originaly 37mm
	translate([  -(card_x+card_space+wall_thickness*2)/2  , (card_y+card_space+wall_thickness*2)/2 ,plate_height/2])
	rotate([0,0,270])
	cube(size = [wall_thickness, shortwall , wall_height] ,center = false);

	//Shortwall 2 of 4
	//the cut to make the space between the walls was originaly 37mm
	translate([  (card_x+card_space+wall_thickness*2)/2 , -(card_y+card_space+wall_thickness*2)/2 ,plate_height/2])
	rotate([0,0,90])
	cube(size = [wall_thickness, shortwall , wall_height] ,center = false);

	//Shortwall 3 of 4
	//the cut to make the space between the walls was originaly 37mm
	translate([  -(card_x+card_space+wall_thickness*2)/2 , -(card_y+card_space+wall_thickness*2)/2 +wall_thickness ,plate_height/2])
	rotate([0,0,270])
	cube(size = [wall_thickness, shortwall , wall_height] ,center = false);

	//Shortwall 4 of 4
	//the cut to make the space between the walls was originaly 37mm
	translate([  (card_x+card_space+wall_thickness*2)/2 , (card_y+card_space+wall_thickness*2)/2 -wall_thickness ,plate_height/2])
	rotate([0,0,90])
	cube(size = [wall_thickness, shortwall , wall_height] ,center = false);

}

```


[User]
I'd like to create a text-based design for 3D printing, where each letter is connected to form a single, solid object.  I need the following features and parameters:

**Text & Font:**

*   The text should be customizable, so I can type in any string I want. Let's call this `textstring`.
*   I'd like a wide variety of font options to choose from. Can we use a dropdown list for this? The existing code has a long list that would work as a starting point, but if there's a way to get even more fonts, that'd be fantastic. Let's name this `fontname`.
*   I need to be able to adjust the size of the text. This should be a parameter called `textsize` and should be in millimeters.
*   The height of the extruded text, also in millimeters, should be adjustable with a parameter called `textheight`.

**Base & Connection:**

*   I need two options for how the letters are connected: either a rounded base that blends the letters together, or a flat bar that connects the base of each letter. I’d like to be able to switch between these using a parameter called `RoundedBase`. It should be set to 0 for the flat bar and 1 for the rounded base.
*   For the flat bar option:
    *   The height of the connecting bar (the extrusion) should be a percentage of the total text height, specified by a parameter called `baseheight_percent`. I'd like the actual height calculated and stored in a variable called `baseheight`.
    *   The thickness of the bar, in the printing plane (not the extrusion), should also be a percentage of the text size. This parameter should be called `basethickness_percent`, and the actual thickness should be `basethickness`.
*   For the rounded base option:
     *   The base should be enlarged to make the letters touch, this should be specified as a percent of `textsize` by the parameter `base_radius_add_percent`. The result should be calculated and stored in `base_radius_add`.
*   The wall thickness should be adjustable with a parameter called `wall`, to create a hollow object. This will create the inner walls.
*   If any of the letters are i or j, I'd like to be able to automatically adjust the vertical position of the text to connect the dots, especially for fonts that don't already include connected dots. This should use a parameter called `do_shift_font` which allows the options "automatic," "yes," and "no" . Let's add an internal calculation that uses `shift_font_percent` of `textsize` to move the text up or down if needed, storing it in a variable called `shift_font`.

I believe this is enough information to get started. Thanks!

[Assistant]
Text_Storage_V3.scad:
```
//Set the text to render
textstring="Lilly";

//Font name. In the list is first a selection of bold fonts. After the dashed line you get a list of thinner fonts, which are not really recommended.
fontname="Holtwood One SC"; //[Holtwood One SC,Alegreya Sans SC Black,Alfa Slab One,Asset,Black Ops One,Bowlby One,Bowlby One SC,Chango,Cinzel Decorative Black,Coustard,Elsie Black,Elsie Swash Caps Black,Erica One,Exo2 Black,Fascinate,Lobster,PassionOne,Plaster,Poller One,Rammetto One,Ruslan Display,Sarpanch Black,Sigmar One,Sonsie One,Titan One,Ultra,Hanalei,---------,ABeeZee,Abel,Abril Fatface,Aclonica,Acme,Actor,Adamina,Advent Pro,Aguafina Script,Akronim,Aladin,Aldrich,Alef,Alex Brush,Alice,Alike,Alike Angular,Allan,Allerta,Allerta Stencil,Allura,Almendra,Almendra Display,Almendra SC,Amarante,Amaranth,Amatic SC,Amethysta,Amiri,Anaheim,Andada,Andika,Angkor,Annie Use Your Telescope,Anonymous Pro,Antic,Antic Didone,Antic Slab,Anton,Arapey,Arbutus,Arbutus Slab,Architects Daughter,Archivo Black,Archivo Narrow,Arimo,Arizonia,Armata,Artifika,Arvo,Asap,Asset,Astloch,Asul,Atomic Age,Aubrey,Audiowide,Autour One,Average,Average Sans,Averia Gruesa Libre,Averia Libre,Averia Sans Libre,Averia Serif Libre,Bad Script,Balthazar,Bangers,Basic,Battambang,Baumans,Bayon,Belgrano,Belleza,BenchNine,Bentham,Berkshire Swash,Bevan,Bigelow Rules,Bigshot One,Bilbo,Bilbo Swash Caps,Bitter,Black Ops One,Bokor,Bonbon,Boogaloo,Bowlby One,Bowlby One SC,Brawler,Bree Serif,Bubblegum Sans,Bubbler One,Buda,Buenard,Butcherman,Butterfly Kids,Cabin,Cabin Condensed,Cabin Sketch,Caesar Dressing,Cagliostro,Calligraffitti,Cambay,Cambo,Candal,Cantarell,Cantata One,Cantora One,Capriola,Cardo,Carme,Carrois Gothic,Carrois Gothic SC,Carter One,Caudex,Cedarville Cursive,Ceviche One,Changa One,Chango,Chau Philomene One,Chela One,Chelsea Market,Chenla,Cherry Cream Soda,Cherry Swash,Chewy,Chicle,Chivo,Cinzel,Cinzel Decorative,Clicker Script,Coda,Coda Caption,Codystar,Combo,Comfortaa,Coming Soon,Concert One,Condiment,Content,Contrail One,Convergence,Cookie,Copse,Corben,Courgette,Cousine,Coustard,Covered By Your Grace,Crafty Girls,Creepster,Crete Round,Crimson Text,Croissant One,Crushed,Cuprum,Cutive,Cutive Mono,Damion,Dancing Script,Dangrek,Dawning of a New Day,Days One,Dekko,Delius,Delius Swash Caps,Delius Unicase,Della Respira,Denk One,Devonshire,Dhurjati,Didact Gothic,Diplomata,Diplomata SC,Domine,Donegal One,Doppio One,Dorsa,Dosis,Dr Sugiyama,Droid Sans,Droid Sans Mono,Droid Serif,Duru Sans,Dynalight,Eagle Lake,Eater,EB Garamond,Economica,Ek Mukta,Electrolize,Elsie,Elsie Swash Caps,Emblema One,Emilys Candy,Engagement,Englebert,Enriqueta,Erica One,Esteban,Euphoria Script,Ewert,Exo,Exo 2,Expletus Sans,Fanwood Text,Fascinate,Fascinate Inline,Faster One,Fasthand,Fauna One,Federant,Federo,Felipa,Fenix,Finger Paint,Fira Mono,Fira Sans,Fjalla One,Fjord One,Flamenco,Flavors,Fondamento,Fontdiner Swanky,Forum,Francois One,Freckle Face,Fredericka the Great,Fredoka One,Freehand,Fresca,Frijole,Fruktur,Fugaz One,Gabriela,Gafata,Galdeano,Galindo,Gentium Basic,Gentium Book Basic,Geo,Geostar,Geostar Fill,Germania One,GFS Didot,GFS Neohellenic,Gidugu,Gilda Display,Give You Glory,Glass Antiqua,Glegoo,Gloria Hallelujah,Goblin One,Gochi Hand,Gorditas,Goudy Bookletter 1911,Graduate,Grand Hotel,Gravitas One,Great Vibes,Griffy,Gruppo,Gudea,Gurajada,Habibi,Halant,Hammersmith One,Hanalei,Hanalei Fill,Handlee,Hanuman,Happy Monkey,Headland One,Henny Penny,Herr Von Muellerhoff,Hind,Homemade Apple,Homenaje,Iceberg,Iceland,IM Fell Double Pica,IM Fell Double Pica SC,IM Fell DW Pica,IM Fell DW Pica SC,IM Fell English,IM Fell English SC,IM Fell French Canon,IM Fell French Canon SC,IM Fell Great Primer,IM Fell Great Primer SC,Imprima,Inconsolata,Inder,Indie Flower,Inika,Irish Grover,Istok Web,Italiana,Italianno,Jacques Francois,Jacques Francois Shadow,Jim Nightshade,Jockey One,Jolly Lodger,Josefin Sans,Josefin Slab,Joti One,Judson,Julee,Julius Sans One,Junge,Jura,Just Another Hand,Just Me Again Down Here,Kalam,Kameron,Kantumruy,Karla,Karma,Kaushan Script,Kavoon,Kdam Thmor,Keania One,Kelly Slab,Kenia,Khand,Khmer,Khula,Kite One,Knewave,Kotta One,Koulen,Kranky,Kreon,Kristi,Krona One,La Belle Aurore,Laila,Lakki Reddy,Lancelot,Lateef,Lato,League Script,Leckerli One,Ledger,Lekton,Lemon,Liberation Sans,Libre Baskerville,Life Savers,Lilita One,Lily Script One,Limelight,Linden Hill,Lobster,Lobster Two,Londrina Outline,Londrina Shadow,Londrina Sketch,Londrina Solid,Lora,Love Ya Like A Sister,Loved by the King,Lovers Quarrel,Luckiest Guy,Lusitana,Lustria,Macondo,Macondo Swash Caps,Magra,Maiden Orange,Mako,Mallanna,Mandali,Marcellus,Marcellus SC,Marck Script,Margarine,Marko One,Marmelad,Martel Sans,Marvel,Mate,Mate SC,Maven Pro,McLaren,Meddon,MedievalSharp,Medula One,Megrim,Meie Script,Merienda,Merienda One,Merriweather,Merriweather Sans,Metal,Metal Mania,Metamorphous,Metrophobic,Michroma,Milonga,Miltonian,Miltonian Tattoo,Miniver,Miss Fajardose,Modak,Modern Antiqua,Molengo,Molle,Monda,Monofett,Monoton,Monsieur La Doulaise,Montaga,Montez,Montserrat,Montserrat Alternates,Montserrat Subrayada,Moul,Moulpali,Mountains of Christmas,Mouse Memoirs,Mr Bedfort,Mr Dafoe,Mr De Haviland,Mrs Saint Delafield,Mrs Sheppards,Muli,Mystery Quest,Neucha,Neuton,New Rocker,News Cycle,Niconne,Nixie One,Nobile,Nokora,Norican,Nosifer,Nothing You Could Do,Noticia Text,Noto Sans,Noto Serif,Nova Cut,Nova Flat,Nova Mono,Nova Oval,Nova Round,Nova Script,Nova Slim,Nova Square,NTR,Numans,Nunito,Odor Mean Chey,Offside,Old Standard TT,Oldenburg,Oleo Script,Oleo Script Swash Caps,Open Sans,Open Sans Condensed,Oranienbaum,Orbitron,Oregano,Orienta,Original Surfer,Oswald,Over the Rainbow,Overlock,Overlock SC,Ovo,Oxygen,Oxygen Mono,Pacifico,Paprika,Parisienne,Passero One,Passion One,Pathway Gothic One,Patrick Hand,Patrick Hand SC,Patua One,Paytone One,Peddana,Peralta,Permanent Marker,Petit Formal Script,Petrona,Philosopher,Piedra,Pinyon Script,Pirata One,Plaster,Play,Playball,Playfair Display,Playfair Display SC,Podkova,Poiret One,Poller One,Poly,Pompiere,Pontano Sans,Port Lligat Sans,Port Lligat Slab,Prata,Preahvihear,Press Start 2P,Princess Sofia,Prociono,Prosto One,PT Mono,PT Sans,PT Sans Caption,PT Sans Narrow,PT Serif,PT Serif Caption,Puritan,Purple Purse,Quando,Quantico,Quattrocento,Quattrocento Sans,Questrial,Quicksand,Quintessential,Qwigley,Racing Sans One,Radley,Rajdhani,Raleway,Raleway Dots,Ramabhadra,Ramaraja,Rambla,Rammetto One,Ranchers,Rancho,Ranga,Rationale,Ravi Prakash,Redressed,Reenie Beanie,Revalia,Ribeye,Ribeye Marrow,Righteous,Risque,Roboto,Roboto Condensed,Roboto Slab,Rochester,Rock Salt,Rokkitt,Romanesco,Ropa Sans,Rosario,Rosarivo,Rouge Script,Rozha One,Rubik Mono One,Rubik One,Ruda,Rufina,Ruge Boogie,Ruluko,Rum Raisin,Ruslan Display,Russo One,Ruthie,Rye,Sacramento,Sail,Salsa,Sanchez,Sancreek,Sansita One,Sarina,Sarpanch,Satisfy,Scada,Scheherazade,Schoolbell,Seaweed Script,Sevillana,Seymour One,Shadows Into Light,Shadows Into Light Two,Shanti,Share,Share Tech,Share Tech Mono,Shojumaru,Short Stack,Siemreap,Sigmar One,Signika,Signika Negative,Simonetta,Sintony,Sirin Stencil,Six Caps,Skranji,Slabo 13px,Slabo 27px,Slackey,Smokum,Smythe,Sniglet,Snippet,Snowburst One,Sofadi One,Sofia,Sonsie One,Sorts Mill Goudy,Source Code Pro,Source Sans Pro,Source Serif Pro,Special Elite,Spicy Rice,Spinnaker,Spirax,Squada One,Sree Krushnadevaraya,Stalemate,Stalinist One,Stardos Stencil,Stint Ultra Condensed,Stint Ultra Expanded,Stoke,Strait,Sue Ellen Francisco,Sunshiney,Supermercado One,Suranna,Suravaram,Suwannaphum,Swanky and Moo Moo,Syncopate,Tangerine,Taprom,Tauri,Teko,Telex,Tenali Ramakrishna,Tenor Sans,Text Me One,The Girl Next Door,Tienne,Timmana,Tinos,Titan One,Titillium Web,Trade Winds,Trocchi,Trochut,Trykker,Tulpen One,Ubuntu,Ubuntu Condensed,Ubuntu Mono,Ultra,Uncial Antiqua,Underdog,Unica One,UnifrakturCook,UnifrakturMaguntia,Unkempt,Unlock,Unna,Vampiro One,Varela,Varela Round,Vast Shadow,Vesper Libre,Vibur,Vidaloka,Viga,Voces,Volkhov,Vollkorn,Voltaire,VT323,Waiting for the Sunrise,Wallpoet,Walter Turncoat,Warnes,Wellfleet,Wendy One,Wire One,Yanone Kaffeesatz,Yellowtail,Yeseva One,Yesteryear,Zeyada]

//Use a rounded base to connect all letters or use a connecting bar?
RoundedBase=0; //[0, 1]

//Shift the font up/down to connect i and j dots? Select "no" if you have no i or j in your text.
do_shift_font="automatic"; //[automatic,yes,no]

//Set font size in mm
textsize=25;

//Text height (extrusion) in mm
textheight=10;

//wall thickness
wall=1;

//Connecting bar height (extrusion in print direction) in percent of the text height
baseheight_percent=.33;
baseheight=textheight*baseheight_percent;

//Connecting bar thickness in percent of the font size
basethickness_percent=0.1;
basethickness=textsize*basethickness_percent;

//Amount to shift the font up/down to connect i and j dots for printing.
shift_font_percent=0.07;
shift_font=textsize*shift_font_percent;

//Only for a rounded base: Base increase size to make letters meet, in percent of the textsize
base_radius_add_percent=.1;
base_radius_add=textsize*base_radius_add_percent;

/* [Hidden] */
//-------------------------------------------------------------------------------

iorj = [ for (i = [0 : len(textstring) - 1]) if (textstring[i]=="i" || textstring[i]=="j") 1 ];

dummy_cutoutlen=len(textstring)*textsize;

/*
Text Storage
Version 3, March 2015
Written by MC Geisler (mcgenki at gmail dot com)

If you need to store Stuff in letters, this is the way to go.

Each letter and also the dots of 'i' and 'j' are connected together, so after printing it will not fall apart.

Have fun!

License: Attribution 4.0 International (CC BY 4.0)

You are free to:
    Share - copy and redistribute the material in any medium or format
    Adapt - remix, transform, and build upon the material
    for any purpose, even commercially.
*/

module writetext(textstr, sizeit)
{
    text(textstr,size=sizeit*.9,font=fontname,halign="center",valign="baseline");
}

module RiseText(textstr, textsize,textheight)
{
    difference()
    {
        union()
        {
            linear_extrude(height=textheight,convexity = 32)
                writetext(textstr, textsize);

            //create base
            if(RoundedBase==0)
            {
                //base line to connect
                linear_extrude(height=baseheight, twist=0, slices=1, $fn=32, convexity = 15)
                    hull()
                        intersection()
                        {
                            writetext(textstr, textsize);

                            //translate([0,-textsize/2+basethickness/2+base_offset,0])
                            translate([0,basethickness/2,0])
                               square([dummy_cutoutlen,basethickness],center=true);
                        }

                if ( (do_shift_font=="automatic" && iorj[0]==1 && fontname!="Holtwood One SC") || do_shift_font=="yes")
                {
                    //connect i and j dots
                    intersection()
                    {
                        union()
                        {
                            translate([0,-shift_font,0])
                                linear_extrude(height=baseheight/2,convexity = 15)
                                    writetext(textstr, textsize);

                            translate([0,shift_font,0])
                                linear_extrude(height=baseheight/2,convexity = 15)
                                    writetext(textstr, textsize);
                        }

                        //TODO: Fix font size and this below for text function
                         translate([0,textsize/2,baseheight/2])
                            cube([dummy_cutoutlen,textsize,baseheight],center=true);
                   }
               }

            }
            else
            {
                        linear_extrude(height=baseheight, twist=0, slices=1, $fn=32, convexity = 15)
                            offset(r = base_radius_add)
                            {
                                writetext(textstr, textsize);
                            }
            }
        }

        translate([0,0,wall])
            linear_extrude(height=textheight+2,convexity = 32)
                offset(delta=-wall)
                    writetext(textstr, textsize);
    }
}

RiseText(textstring,textsize,textheight);

```


[User]
Okay, I'm looking to design a parametric belt gear that I can attach to a stepper motor shaft. I've already got a basic design in mind, but it needs to be fully parameterized and I want to build in some flexibility for different belt sizes, motor shafts, etc. I will need the following features:

First, the gear will need to have a circular base with a toothed perimeter to engage with a timing belt. I need to be able to specify the tooth size, number of teeth, and belt width. The tooth profile should be roughly rectangular.

Second, I need a hub at the center with a hole to fit onto the motor shaft. I need to specify the diameter of the motor shaft.

Finally, the model should have a way to secure the gear to the motor shaft. I'm thinking a small, cylindrical section extending out and perpendicular to the shaft with a hole through it for a set screw would work.

For parameters, I need to be able to control:

*   `tb`: Tooth size of the belt (e.g. 1mm)
*   `tn`: Number of teeth on the wheel
*   `b`: Width of the belt (plus some extra for clearance)
*   `hd`: Diameter of the motor shaft
*  `h_overhang`: Height of the hub which extends past the top of the teeth
* `h_shaft`: Height of the shaft cylinder
* `screw_r`: Radius of the screw cylinder that intersects the hub
* `screw_h`: Height of the screw cylinder

I'd also prefer to not use `$fn` to control the mesh resolution, so any required circles or cylinders should have an appropriate function for controlling the mesh based on radius as described in the BOSL library. This way, the mesh resolution will be linked to the size of the model. The `BOSL2` library is also preferred as a source for functions used to define 3D shapes. I'm thinking this should be doable as one .scad file, right?

[Assistant]
BeltGear.scad:
```
/* [Global] */

// Tooth size of belt
tb=1;

// Number of teeth on wheel
tn=20;

// Width of belt (add a bit)
b=6;

// diameter of motor axis
hd=5;

/* [Hidden] */

u=2*tb*tn;
r=u/PI/2;
a=360/tn;

$fn=64;

difference() {
  union() {
    cylinder(2.01,r+2.0,r);

    translate([0,0,2])
    difference() {
      cylinder(b,r,r);
      for (x = [0 : tn-1]) {
        rotate([0,0,x*a]) translate([r-tb,-tb/2,-0.1]) cube([tb*2,tb,b+0.2]);
      }
    }

    translate([0,0,b+1.99]) cylinder(2.01,r,r+2);
    translate([0,0,b+3.99]) cylinder(hd,hd/2+2,hd/2+2);
  }

  translate([0,0,b+4+hd/2]) rotate([0,90,0]) cylinder(hd/2+3,1.4,1.4);
  translate([0,0,-0.01]) cylinder(b+hd+4.1,hd/2,hd/2);
}

```


[User]
Hi, I'm looking to create a customizable Easter bunny model using OpenSCAD, and I'd like your help in designing the code. I've seen some examples with a lot of adjustable parameters, and that's exactly what I'm hoping for.

The key features I'd like to be able to control are:

*   **Body Shape:** I want to be able to adjust how "fat" the bunny is, going from very slim to very fat.
*   **Head Size:** The head should be adjustable in size, from small to large, and maybe even have a "baby look" with a particularly large head.
*   **Head Orientation:** I'd like to be able to tilt the head up or down (headnick), rotate it left or right (headyaw) and bend it sideways (headroll).
*   **Ear Length:** I need to be able to adjust the length of the ears, from very short to very long.
*   **Ear Spread:** I want to control the angle at which the ears spread apart.
*   **Ear Type:** I'd like to have a choice between curved (flex) and straight ears.
*   **Eye Size:**  Adjustable eye size, from very small to big and "baby" style.
*   **Neck Size:** I want to be able to adjust the neck radius, from no neck at all to a very large neck.
*   **Seat Depth:** The ability to change the level of the seat, so it looks like the bunny is sitting in different "depths" of water.
*  **Tail Size:** I would like a parameter to modify the size of the tail
*   **Body Wall Thickness:**  I also need a way to adjust the thickness of the body wall to make the model lighter or sturdier.

Ideally, the body and head should be hollow to save on material. The final design should allow me to generate various bunnies with unique characters, sizes, and styles. I don't need any special libraries for this project.

[Assistant]
10-14_easterbunny_customizer.scad:
```
//**********************************************
//               my Parametric Easter Bunny
//  (C) 2015  Henning Stoecklein  (hestoeck@gmx.de)
//       Version 14-OCT-2015 optimized for CUSTOMIZER
//
//   Source code and printed objects based on it
//   may be used freely for private purposes only.
//**********************************************

//************ begin of customizable variables **********
// Body Shape
bodyfat  = 0.75 ;	// [0.68:Very slim, 0.75:Slim, 0.85:Medium, 0.93:Fat, 1.0:Very fat]

// Head Size
headsize = 1.1 ;	// [0.9:Small, 1.0:Standard, 1.1:Big, 1.2:Baby look]

// Head up/down direction
headnick = 15 ; // [-15:25]

// Head right/left direction
headyaw  = 0 ; // [-40:40]

// Head sidewards bending
headroll = 0 ; 	// [-20:20]

// Ear length
earlen    = 0.9 ; // [0.7:Very short, 0.8:Short, 0.9:Medium, 1.0:Long, 1.1:Very long]

// Ear Spread Angle
earspread = 5 ; // [0:30]

// Ear shape
eartype    = "FLEX" ; // ["FLEX":Curved, "STD":Straight]

// Eye size
eyeradius  = 0.9; // [0.68:Very small, 0.75:Small, 0.8:Medium, 0.9:Big, 1.0:Baby Eyes]

// Neck Size
neckradius = 1.5;	// [0:None, 1.5:Small, 2.0:Standard, 2.9:Big]

// Seat depth water level
seatlevel  = 1;	// [-3:6]

// Tail Size
tailradius  = 2; // [0.8:Very tiny, 1.2:Tiny, 2:Medium, 2.5:Big, 3:Very big]

// Body wall thickness
bodywall  = 0.7; // [0.5:Ultra thin, 0.7:Thin, 0.9:Standard, 1.1:Thick, 1.2:Ultra thick]

//************** end of customizable area ************
//  change lines below only if you know what you're doing...

module hase()
{
  // Körper
  difference() {
    union() {
      translate ([14.8,0,1]) sphere (r=tailradius, $fn=20, center=true) ;		// tail
  	translate ([-2.5,0,14]) rotate ([headroll,-headnick, headyaw])
		scale ([headsize,  headsize, headsize]) kopf() ;					// head
  	translate ([-2.5,0,13.5]) rotate ([0,-headnick,0]) hals() ;  				// neck

      scale ([1,bodyfat,1]) { 											// body
        hull () {
          translate ([5,0,0]) sphere (r=10, $fn=75, center=true) ;
          translate ([1,0,6]) sphere (r=5, $fn=40, center=true) ;
        }
      }
    }
    scale ([1,bodyfat,1])   							// make body and neck hollow
	  translate ([5,0,0]) sphere (r=10-bodywall, $fn=50, center=true) ;
    translate ([0.3,0,-5+14]) rotate ([0,-15-8,0])
	   scale ([1,bodyfat,1]) cylinder (r=2.0, h=6, $fn=20, center=true) ;
  }
}

module halbkugel(rad)								// inner ball half of eye background
{
   difference() {
      sphere (r=rad, $fn=25, $center=true) ;
      translate ([0,25,0]) cube ([50, 50, 50], center=true) ;
   }
}

module flexohrsection(dir, shift, rot, rad1, rad2)		// do 1 slice of the flex ear
{
   height = 1.2;
   translate ([0,dir*shift,0]) rotate ([-rot*dir,0,0])
     difference() {
        translate ([0,0,0])  cylinder (r1=rad1, r2=rad2,h=height, $fn=30, center=true) ;
        translate ([-1,0,0]) cylinder (r1=rad1-0.5, r2=rad2-0.5, h=height+0.1, $fn=30, center=true) ;
        translate ([-5.5,0,0]) cube ([10,20,height+1], center=true) ;
     }
}

module flexohr(dir)								// do the complete flex ear
{
      translate ([0,0,00]) flexohrsection(dir, 0.02, 0, 2.0, 2.03);
      translate ([0,0,01]) flexohrsection(dir, 0.05, 2, 2.03, 2.1);
      translate ([0,0,02]) flexohrsection(dir, 0.12, 7, 2.1, 2.2);
      translate ([0,0,03]) flexohrsection(dir, 0.27, 10, 2.2, 2.33);
      translate ([0,0,04]) flexohrsection(dir, 0.45, 12.5, 2.30, 2.43);
      translate ([0,0,05]) flexohrsection(dir, 0.7, 16.3, 2.43, 2.5);
      translate ([0,0,06]) flexohrsection(dir, 1.02, 19.5, 2.5, 2.56);
      translate ([0,0,07]) flexohrsection(dir, 1.40, 20.5, 2.57, 2.6);
      translate ([0,0,08]) flexohrsection(dir, 1.8, 21.5, 2.61, 2.59);
      translate ([0,0,09]) flexohrsection(dir, 2.2, 21.7, 2.60, 2.47);
      translate ([0,0,10]) flexohrsection(dir, 2.6, 22, 2.48, 2.27);
      translate ([0,0,11]) flexohrsection(dir, 3.0, 22, 2.28, 2.06);
      translate ([0,0,12]) flexohrsection(dir, 3.4, 22, 2.08, 1.77);
      translate ([0,0,13]) flexohrsection(dir, 3.8, 22, 1.8, 1.46);
      translate ([0,0,14]) flexohrsection(dir, 4.2, 22, 1.5, 1.05);
      translate ([0,0,15]) flexohrsection(dir, 4.6, 22, 1.1, 0.55);
      translate ([0,dir*4.7,15.3]) sphere (r=0.62, $fn=20, center=true);
}

module ohrsection(rad1, rad2)						// do 1 slice of the standard ear
{
   height = 1;
   difference() {
      cylinder (r1=rad1, r2=rad2,h=height, $fn=30, center=true) ;
      translate ([-1,0,0]) cylinder (r1=rad1-0.5, r2=rad2-0.5, h=height+0.1, $fn=30, center=true) ;
      translate ([-5.5,0,0]) cube ([10,20,height+1],center=true) ;
   }
}

module ohr()										// do the complete standard ear
{
      translate ([0,0,00]) ohrsection(2.0, 2.03);
      translate ([0,0,01]) ohrsection(2.03, 2.1);
      translate ([0,0,02]) ohrsection(2.1, 2.2);
      translate ([0,0,03]) ohrsection(2.2, 2.33);
      translate ([0,0,04]) ohrsection(2.33, 2.43);
      translate ([0,0,05]) ohrsection(2.43, 2.5);
      translate ([0,0,06]) ohrsection(2.5, 2.56);
      translate ([0,0,07]) ohrsection(2.56, 2.6);
      translate ([0,0,08]) ohrsection(2.6, 2.6);
      translate ([0,0,09]) ohrsection(2.6, 2.5);
      translate ([0,0,10]) ohrsection(2.5, 2.3);
      translate ([0,0,11]) ohrsection(2.3, 2.08);
      translate ([0,0,12]) ohrsection(2.08, 1.8);
      translate ([0,0,13]) ohrsection(1.8, 1.5);
      translate ([0,0,14]) ohrsection(1.5, 1.1);
      translate ([0,0,15]) ohrsection(1.1, 0.6);
      translate ([0,0,15.3]) sphere (r=0.62, $fn=20, center=true);
}

module minko_ohr()		// do not use without number cruncher CPU...
{
   minkowski() {
      ohr() ;
      sphere (r=0.2, $fn=7, center=true) ;
   }
}

module schnauze(dia)		// do the nose "Y"
{
    translate ([0,0,-2]) rotate ([0,0,0]) cylinder (r=dia, h=4, $fn=15, center=true) ;
    translate ([0,-1.5,1.1]) rotate ([60,0,0]) cylinder (r=dia, h=4, $fn=15, center=true) ;
    translate ([0,+1.5,1.1]) rotate ([-60,0,0]) cylinder (r=dia, h=4, $fn=15, center=true) ;
}

module hals()				// do the neck
{
  difference() {			// absolute position like the head
      translate ([1.2,0,-4.5]) scale ([1.3,0.9,1]) cylinder (r=neckradius, h=4, $fn=30, center=true) ;
      translate ([1.2,0,-5]) rotate ([0,-6,0]) scale ([1.1,0.8,1])
			cylinder (r=neckradius*2/2.75, h=6.1, $fn=20, center=true) ;
  }
}

module kopf()			// do the head
{
  difference() {			// double diff to allow half domes as eye background
    union() {
      difference() {
        union() {
           hull () {
            scale ([1.3,0.85,1]) sphere (r=4.9, $fn=50, center=true) ;
            translate ([-2.0,0,0]) scale ([1.3,0.85,1]) sphere (r=3.8, $fn=50, center=true) ;
            translate ([0.73,0,-2-0.5*headnick/15]) scale ([1.3,0.9,1]) sphere (r=3.8, $fn=50, center=true) ;
          } // hull
       } // union

       // Hohlkopf
       scale ([1.3,0.85,1]) sphere (r=4.4, $fn=30, center=true) ;

       // Schnauzen-Y abziehen
       translate ([-6.7,0,-0.5]) rotate ([0,-10,0]) scale ([0.5,0.5,0.5]) schnauze(0.5) ;
     } // diff

     // Innenseite der Augen
     translate ([-1.5,-3.5,1.1]) rotate([10,0,169]) halbkugel(eyeradius*1.5) ;
     translate ([-1.5, 3.5,1.1]) rotate([10,0, 11]) halbkugel(eyeradius*1.5) ;
   } // union

   // Augen vertieft
   translate ([-1.5,3.8,1.2]) sphere (r=eyeradius, $fn=15, center=true) ;
   translate ([-1.5,-3.8,1.2]) sphere (r=eyeradius, $fn=15, center=true) ;
  } // diff

  if (eartype == "FLEX")
  {
    // Flex-Ohren
    translate ([3.3,-2.2,2.6]) rotate ([35,10,75-earspread]) scale ([0.8,0.8,earlen]) flexohr(-1) ;
    translate ([3.3,+2.2,2.6]) rotate ([-35,10,-75+earspread]) scale ([0.8,0.8,earlen]) flexohr(1) ;
  } else
  {
     // Gerade Ohren
     translate ([2.5,-2.2,1.2]) rotate ([5,6,10+earspread]) scale ([0.8,0.8,earlen]) ohr() ;
     translate ([2.5,+2.2,1.2]) rotate ([-5,6,-10-earspread]) scale ([0.8,0.8,earlen]) ohr() ;
  }
}

module sitzhase() 			// do the complete bunny with flat seated body
{
  difference() {
    hase();
    translate ([0,0,seatlevel-17]) cube ([100,100,20], center=true) ;
//    translate ([0,50,0]) cube ([100,100,100], center=true) ; 		// Cutaway for body debugging...
//    translate ([0,0,24.7]) cube ([100,100,20], center=true) ; 	// Cutaway for head debugging...
  }
}

//ohr() ;								// single ear for debugging
//translate ([0, 8, 0]) flexohr() ;		// single flex ear for debugging

sitzhase() ;							// bunny alive!

```
04-01_hst_easterbunny.scad:
```
//**********************************************
//               my Parametric Easter Bunny
//  (C) 2015  Henning Stoecklein  (hestoeck@gmx.de)
//                 Version 01-APR-2015
//
//   Source code and printed objects based on it
//   may be used freely for private purposes only.
//**********************************************

//************ begin of customizable variables **********
//                    [xx] = default values to start with
bodyfat  = 0.75 ;			// [0.75]		0.70 = slim body,  1.00 = fat body
headnick = 15 ;			// [15]		25 = Head looks downwards, 15 = level, -15 = up
headyaw  = 00 ;			// [00]		0 = Head looks forward, 40 = to left, -40 to right
headroll = 00 ;			// [00]		0 = Head is straight up, 20 = bent to left, -20 to right
earlen    = 0.95 ;			// [0.95]		1.1 = long ears, 0.7 = short ears
earspread = 10 ;			// [10]		0 = ears in parallel, 30 = ears spread apart
eartype    = "FLEX" ;		// ["FLEX"]	FLEX = curved ears, STD = straight ears
eyeradius  = 0.85;		// [0.85]		0.70 = small eyeballs, 1.0 = big "baby" eyes
neckradius = 0;			// [00]		2.75 = visible neck, 0 = no neck
seatlevel  = 0;			// [00]		5 = sit in deep water, 0 = medium, -2 = no seat flat
tailradius  = 2;			// [02]		1 = tiny tail, 2 = medium, 3 = big tail
bodywall  = 0.75;			// [0.75]		0.5 = ultra thin body wall, 1.2 = thick wall

//************** end of customizable area ************
//  change lines below only if you know what you're doing...

module hase()
{
  // Körper
  difference() {
    union() {
      translate ([14.8,0,1]) sphere (r=tailradius, $fn=20, center=true) ;		// tail
  	translate ([-2.5,0,14]) rotate ([headroll,-headnick, headyaw]) kopf() ;  // head
  	translate ([-2.5,0,14]) rotate ([0,-15,0]) hals() ;		  				// neck

      scale ([1,bodyfat,1]) { 											// body
        hull () {
          translate ([5,0,0]) sphere (r=10, $fn=75, center=true) ;
          translate ([1,0,6]) sphere (r=5, $fn=40, center=true) ;
        }
      }
    }
    scale ([1,bodyfat,1])   							// make body and neck hollow
	  translate ([5,0,0]) sphere (r=10-bodywall, $fn=40, center=true) ;
    translate ([0.3,0,-5+14]) rotate ([0,-15-8,0])
	   scale ([1,bodyfat,1]) cylinder (r=2.0, h=6, $fn=20, center=true) ;
  }
}

module halbkugel(rad)								// inner ball half of eye background
{
   difference() {
      sphere (r=rad, $fn=25, $center=true) ;
      translate ([0,25,0]) cube ([50, 50, 50], center=true) ;
   }
}

module flexohrsection(dir, shift, rot, rad1, rad2)		// do 1 slice of the flex ear
{
   height = 1.2;
   translate ([0,dir*shift,0]) rotate ([-rot*dir,0,0])
     difference() {
        translate ([0,0,0])  cylinder (r1=rad1, r2=rad2,h=height, $fn=30, center=true) ;
        translate ([-1,0,0]) cylinder (r1=rad1-0.5, r2=rad2-0.5, h=height+0.1, $fn=30, center=true) ;
        translate ([-5.5,0,0]) cube ([10,20,height+1], center=true) ;
     }
}

module flexohr(dir)								// do the complete flex ear
{
      translate ([0,0,00]) flexohrsection(dir, 0.02, 0, 2.0, 2.03);
      translate ([0,0,01]) flexohrsection(dir, 0.05, 2, 2.03, 2.1);
      translate ([0,0,02]) flexohrsection(dir, 0.12, 7, 2.1, 2.2);
      translate ([0,0,03]) flexohrsection(dir, 0.27, 10, 2.2, 2.33);
      translate ([0,0,04]) flexohrsection(dir, 0.45, 12.5, 2.30, 2.43);
      translate ([0,0,05]) flexohrsection(dir, 0.7, 16.3, 2.43, 2.5);
      translate ([0,0,06]) flexohrsection(dir, 1.02, 19.5, 2.5, 2.56);
      translate ([0,0,07]) flexohrsection(dir, 1.40, 20.5, 2.57, 2.6);
      translate ([0,0,08]) flexohrsection(dir, 1.8, 21.5, 2.61, 2.59);
      translate ([0,0,09]) flexohrsection(dir, 2.2, 21.7, 2.60, 2.47);
      translate ([0,0,10]) flexohrsection(dir, 2.6, 22, 2.48, 2.27);
      translate ([0,0,11]) flexohrsection(dir, 3.0, 22, 2.28, 2.06);
      translate ([0,0,12]) flexohrsection(dir, 3.4, 22, 2.08, 1.77);
      translate ([0,0,13]) flexohrsection(dir, 3.8, 22, 1.8, 1.46);
      translate ([0,0,14]) flexohrsection(dir, 4.2, 22, 1.5, 1.05);
      translate ([0,0,15]) flexohrsection(dir, 4.6, 22, 1.1, 0.55);
      translate ([0,dir*4.7,15.3]) sphere (r=0.62, $fn=20, center=true);
}

module ohrsection(rad1, rad2)						// do 1 slice of the standard ear
{
   height = 1;
   difference() {
      cylinder (r1=rad1, r2=rad2,h=height, $fn=30, center=true) ;
      translate ([-1,0,0]) cylinder (r1=rad1-0.5, r2=rad2-0.5, h=height+0.1, $fn=30, center=true) ;
      translate ([-5.5,0,0]) cube ([10,20,height+1],center=true) ;
   }
}

module ohr()										// do the complete standard ear
{
      translate ([0,0,00]) ohrsection(2.0, 2.03);
      translate ([0,0,01]) ohrsection(2.03, 2.1);
      translate ([0,0,02]) ohrsection(2.1, 2.2);
      translate ([0,0,03]) ohrsection(2.2, 2.33);
      translate ([0,0,04]) ohrsection(2.33, 2.43);
      translate ([0,0,05]) ohrsection(2.43, 2.5);
      translate ([0,0,06]) ohrsection(2.5, 2.56);
      translate ([0,0,07]) ohrsection(2.56, 2.6);
      translate ([0,0,08]) ohrsection(2.6, 2.6);
      translate ([0,0,09]) ohrsection(2.6, 2.5);
      translate ([0,0,10]) ohrsection(2.5, 2.3);
      translate ([0,0,11]) ohrsection(2.3, 2.08);
      translate ([0,0,12]) ohrsection(2.08, 1.8);
      translate ([0,0,13]) ohrsection(1.8, 1.5);
      translate ([0,0,14]) ohrsection(1.5, 1.1);
      translate ([0,0,15]) ohrsection(1.1, 0.6);
      translate ([0,0,15.3]) sphere (r=0.62, $fn=20, center=true);
}

module minko_ohr()		// do not use without number cruncher CPU...
{
   minkowski() {
      ohr() ;
      sphere (r=0.2, $fn=7, center=true) ;
   }
}

module schnauze(dia)		// do the nose "Y"
{
    translate ([0,0,-2]) rotate ([0,0,0]) cylinder (r=dia, h=4, $fn=15, center=true) ;
    translate ([0,-1.5,1.1]) rotate ([60,0,0]) cylinder (r=dia, h=4, $fn=15, center=true) ;
    translate ([0,+1.5,1.1]) rotate ([-60,0,0]) cylinder (r=dia, h=4, $fn=15, center=true) ;
}

module hals()				// do the neck
{
  difference() {			// absolute position like the head
      translate ([1.2,0,-4.5]) scale ([1.3,0.9,1]) cylinder (r=neckradius, h=5, $fn=30, center=true) ;
      translate ([1.2,0,-5]) rotate ([0,-6,0]) cylinder (r=neckradius*2/2.75, h=5.1, $fn=20, center=true) ;
  }
}

module kopf()			// do the head
{
  difference() {			// double diff to allow half domes as eye background
    union() {
      difference() {
        union() {
           hull () {
            scale ([1.3,0.85,1]) sphere (r=4.9, $fn=50, center=true) ;
            translate ([-2.0,0,0]) scale ([1.3,0.85,1]) sphere (r=3.8, $fn=50, center=true) ;
            translate ([0.73,0,-2]) scale ([1.3,0.9,1]) sphere (r=3.8, $fn=50, center=true) ;
          } // hull
       } // union

        // Hohlkopf
        scale ([1.3,0.85,1]) sphere (r=4.3, $fn=30, center=true) ;

        // Schnauzen-Y abziehen
       translate ([-6.7,0,-0.5]) rotate ([0,-10,0]) scale ([0.5,0.5,0.5]) schnauze(0.5) ;
     } // diff

     // Innenseite der Augen
     translate ([-1.5,-3.4,1.1]) rotate([0,0,170]) halbkugel(eyeradius*1.5) ;
     translate ([-1.5, 3.4,1.1]) rotate([0,0, 10]) halbkugel(eyeradius*1.5) ;
   } // union

   // Augen vertieft
   translate ([-1.5,3.8,1.2]) sphere (r=eyeradius, $fn=15, center=true) ;
   translate ([-1.5,-3.8,1.2]) sphere (r=eyeradius, $fn=15, center=true) ;
  } // diff

  if (eartype == "FLEX")
  {
    // Flex-Ohren
    translate ([3,-2.2,2.1]) rotate ([35,10,75-earspread]) scale ([0.8,0.8,earlen]) flexohr(-1) ;
    translate ([3,+2.2,2.1]) rotate ([-35,10,-75+earspread]) scale ([0.8,0.8,earlen]) flexohr(1) ;
  } else
  {
     // Gerade Ohren
     translate ([2.5,-2.2,1.2]) rotate ([5,6,10+earspread]) scale ([0.8,0.8,earlen]) ohr() ;
     translate ([2.5,+2.2,1.2]) rotate ([-5,6,-10-earspread]) scale ([0.8,0.8,earlen]) ohr() ;
  }
}

module sitzhase() 			// do the complete bunny with flat seated body
{
  difference() {
    hase();
    translate ([0,0,seatlevel-17]) cube ([100,100,20], center=true) ;
//    translate ([0,50,0]) cube ([100,100,100], center=true) ; 		// Cutaway for body debugging...
//    translate ([0,0,24.7]) cube ([100,100,20], center=true) ; 	// Cutaway for head debugging...
  }
}

//ohr() ;								// single ear for debugging
//translate ([0, 8, 0]) flexohr() ;		// single flex ear for debugging

sitzhase() ;							// bunny alive!

```


[User]
I'd like to design a coin cell battery holder, something I can 3D print. I need it to hold a variable number of cells, and I want to be able to adjust the size of the cells it holds, as well as the wall thicknesses. I'm thinking something relatively robust, suitable for tool box storage.

Here are the parameters I'd like to control:
*   `num_cells`: The number of coin cells the holder should accommodate.
*   `inter_walls`: The thickness of the walls separating each cell slot.
*   `cell_thick`: The thickness of the coin cells (this will also determine the slot height).
*   `cell_round`: The diameter of the coin cells.
*   `radial_gap`: A radial gap around the coin cells within their slots for a loose fit.
*   `end_walls`: The thickness of the outer walls (bottom, sides, and ends).

I also have some additional specifics in mind:
1. The cells should be held in place by friction at the bottom of the slots.
2. There should be a bottom slot to push the cells up to remove them.
3. There should be side-grips at the top for easy removal.
4. One end should be marked with a hole to keep track of the relative state of charge (or for whatever reason, really).

I'd like you to generate an OpenSCAD file that uses these parameters to create the battery holder. The design should be based around using the `MCAD/units.scad` library. Can you also be sure to use variables for everything? I'm not a fan of magic numbers.

[Assistant]
coin_cell_holder.scad:
```
/* Parameters for customizing the build */

/* [Global] */
// the number of coin cells to hold
num_cells = 7;   // [1:100]
// the thickness of the inter-slot walls in mm
inter_walls = 1.75; // [1.5:3]
// How thick the cells are in mm.  The slots will be exactly this size.  Friction fit is good.
cell_thick = 3.2; // [0.5:7]
// The diameter of the cells in mm. Loose fit is important.  The radial_gap will be added to both sides.
cell_round = 20;
// The gap between the cell and the outside walls in mm.
radial_gap = 1; // [0.5:2]
// The thickness of the outside bottom, side and end in mm.
end_walls = 3; // [1:5]

/* [Hidden] */

include <MCAD/units.scad>

module coin_cell_slot(diameter, thickness, offset_x)
{
	hull() {
		cylinder(d=diameter, h=thickness);
		translate([offset_x,0,0])cylinder(d=diameter, h=thickness);
	}
}

module cell_array(num_cells, diameter, thickness, offset_z, offset_x)
{
	for( cell_num = [0:num_cells - 1] ) {
		translate([0,0,cell_num * offset_z]) coin_cell_slot(diameter, thickness, offset_x);
	}
}

cavity_round = cell_round + (2 * radial_gap);
big_width=cavity_round + (2 * end_walls) ;
big_height=cell_round + (1 * end_walls) ;
center_y = big_width/2;
center_z = big_height/2;
side_grip_relief = (big_width - cell_round)/2 +2;
long = end_walls + ((num_cells - 1) * inter_walls) + (num_cells * cell_thick) + end_walls;
thisFont=8bit_polyfont();

difference() {
	translate([-end_walls,-center_y, -center_z]) cube([long,big_width,big_height]);
	rotate ([0,90,0]) {
			cell_array(num_cells, cavity_round, cell_thick, cell_thick + inter_walls, -cell_round);

	}
	translate([-end_walls -epsilon,-(center_y + epsilon), (center_z -cell_round/2 + 1.5) ]) cube([long+2,side_grip_relief, cell_round/2-1]);
	translate([-end_walls -epsilon,+(center_y - side_grip_relief) +epsilon, (center_z -cell_round/2 + 1.5) ]) cube([long+2,side_grip_relief, cell_round/2-1]);
	translate([-end_walls*2, 0, -center_z]) rotate ([0,90,0])
		cylinder(h=long+2*end_walls, d=cell_round*2/3);
 	translate([-(epsilon+end_walls), 0, +center_z/4]) rotate ([0,90,0])
		cylinder(h=(2*epsilon) + end_walls, d=cell_round/3);

};
```


[User]
Hey, I'm looking to generate a 3-piece interlocking cube puzzle in OpenSCAD, similar to a trisection puzzle I saw online. The core concept is that you have three identical pieces that twist together to form a cube. I'd like the design to be parametric, so I can easily adjust some key dimensions.

Here are the parameters I'd like to control:

*   **`edge`**: The length of the cube's edge in millimeters (default around 50 mm, range should allow from 10 to 100 mm).
*   **`twist_angle`**: The angle in degrees that the pieces rotate when assembled (default about 330 degrees, and the range could be between 300 and 720 degrees).
*   **`epsilon`**: A small gap or clearance between the pieces, in millimeters (default like 0.4 mm, and values could go between 0 and 0.5 mm in steps of 0.05, as well as 0.1, 0.15, 0.2, 0.3, and 0.4)

I don't need to include any specific libraries.

For the design, each piece is created by intersecting a rotated cube with a linear extrusion of a specific polygon shape. The polygon itself has points at a calculated distance based on `edge` and a small offset using `epsilon`. Also, the pieces should start with the same rotations as in the example provided, with rotations being around the X, Y, and Z axes at 45, angle (based on atan(1/sqrt(2)), and 30 degrees, respectively. Then each piece should have a further rotation at 120 degree intervals around the Z axis so that there are 3 unique pieces that can form the cube. Finally, the pieces should be different colors (e.g. blue, red, and green) so that they can be more easily distinguished when rendering the assembled cube.

Could you generate the OpenSCAD code for this?

[Assistant]
trisection.scad:
```

//size of the cube (mm)
edge = 50; //[10.0:100.0]

// angle in degrees you'll have to screw the pieces to assemble the cube
twist_angle = 330; //[300:720]

// size of the gap between pieces (mm)
epsilon = 0.4; //[0.0,0.05,0.1,0.15,0.2,0.3,0.4,0.5]

/* [Hidden] */
angle = atan(1/sqrt(2));
diag = edge*sqrt(3);
d = diag/2;

module piece(){
	  intersection(){
		 rotate ([45,angle,30])cube( [edge,edge,edge],center = true);
		translate([0, 0, -diag/2]) linear_extrude(height = diag, center = false, convexity = 10, twist = twist_angle, $fn = 200)
		polygon( points=[[0+epsilon/2,0+epsilon/2],[d+epsilon,-tan(30-epsilon)*d],[d,d],[0+epsilon/2,d]] );
	}
}

rotate ([45,0,-0]) rotate ([-0,-angle,-0]) rotate ([-0,-0,-30])color("blue")piece ();

// remove * to get the complete cube
*rotate ([45,0,-0]) rotate ([-0,-angle,-0]) rotate ([-0,-0,-30]) rotate([0,0,120,]) color("red")piece ("red");

*rotate ([45,0,-0]) rotate ([-0,-angle,-0]) rotate ([-0,-0,-30]) rotate([0,0,240,]) color("green")piece ();

```


[User]
I need to design a customizable spool holder insert for 3D printer filament. I've noticed that inner diameters of spools vary, so I'd like a design that I can easily adjust. Basically, it's a cylinder with a hole through the center, and then a flange at one end. The flange needs to have a fillet where it joins the cylinder body. Also, I need the top edge of the cylinder body to have a fillet.

Specifically:

*   I want to be able to set the height and diameter of the main inner cylinder.
*   I want to be able to set the height and diameter of the flange (outer cylinder).
*   The flange should sit on one end of the inner cylinder.
*   I want to set the radius of both fillets (where the flange meets the inner cylinder body, and the top edge of the inner cylinder).
*   I need to be able to set the diameter of the center hole, which will accommodate the spool holder rod or axle.
*   Finally, I need to control the smoothness of the curves in the design.

I'd like this to be done in OpenSCAD and it would be really helpful if the generated file was parametric. So, I can change all of those parameters and re-render.

I think that's everything. Can you generate an OpenSCAD file for me?

[Assistant]
customizable_spool_holder_insert.scad:
```
inner_cylinder_height = 7.5; // [5.0:15.0]
inner_cylinder_diameter = 59; // [20.0:70.0]
outer_cylinder_height = 4; // [2.0:6.0]
outer_cylinder_diameter = 80; // [30.0:90.0]
fillet_radius = 2; // [0.0:3.0]
axle_diameter = 9; // [3.0:12.0]
smooth = 90; // [16:180]

/* [Hidden] */
pad = 0.1;

difference()
{
  union()
  {
    translate([0,0,outer_cylinder_height])
    {
      cylinder(d=inner_cylinder_diameter, h=inner_cylinder_height, $fn=smooth);
    }
    cylinder(d=outer_cylinder_diameter, h=outer_cylinder_height, $fn=smooth);
  }
  translate([0,0,-pad/2])
    cylinder(d=axle_diameter, h=inner_cylinder_height+outer_cylinder_height + pad, $fn=36);

  // Top fillet
  translate([0,0,inner_cylinder_height+outer_cylinder_height])
    rotate([180,0,0])
      cylinder_fillet(inner_cylinder_diameter/2);

  // Bottom fillet
  cylinder_fillet(outer_cylinder_diameter/2);
}

// http://www.thingiverse.com/thing:6455
module cylinder_fillet(cylinder_r)
{
  difference()
  {
    rotate_extrude(convexity=10, $fn = smooth)
      translate([cylinder_r-fillet_radius+pad,-pad,0])
        square(fillet_radius+pad,fillet_radius+pad);
    rotate_extrude(convexity=10,  $fn = smooth)
      translate([cylinder_r-fillet_radius,fillet_radius,0])
        circle(r=fillet_radius,$fn=smooth);
  }
}
```


[User]
I'm trying to make a tool similar to the "drawing.scad" example, where I can define a 2D shape as a list of points and paths and then extrude it to a certain thickness. However, I want to make the tool more robust and flexible. Specifically, I need to make sure that I can handle multiple shapes. I need to be able to specify multiple closed shapes that will become positive forms, as well as interior shapes that will act as holes. I need a way to represent a sequence of nested shapes, such that a shape drawn inside a shape will be treated as a cutout, a shape inside that cutout will be treated as positive, and so on. Also, instead of defining the points directly as a list of coordinates, I'd like to provide coordinates as a list of variables, and I want to specify the order that these points are connected as paths. I would like to be able to adjust the extrusion thickness as a parameter.

Could you generate an OpenSCAD file for this that allows for multiple shapes and nested holes and lets me define points as named variables?

[Assistant]
drawing.scad:
```
// simple drawmaker

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

thickness = 15;

// Draw one or more closed shapes in the box! If you draw one shape inside another, it will be taken out as a hole.
shape = [[[0,0]],[[0]] ]; //[draw_polygon:100x100]

linear_extrude(thickness)
polygon(points = shape[0], paths = shape[1]);
```


[User]
I'd like a parametric OpenSCAD design for creating 3D text. I need to be able to specify the text itself, the font, the font size, the extrusion height (for the 3D effect), and the spacing between the letters. It would be good if there was an option for a connected web base under the text, with the web base being a bit larger than the text itself ( achieved with offset functions) , to provide a solid base. I'd also like to choose if the text flows left to right or top to bottom.

It should be easy to use for beginners, so please keep the code straightforward, use comments, and make sure it works in the Makerbot Customizer. I’d like to have a list of the standard Google fonts to choose from in a drop down menu, or at least a way to type in the font.

I also want to make sure that all the text parameters are easily changeable, as well as the web thickness (if there is a base) to tweak the final look.

[Assistant]
text.scad:
```
// simple textmaker

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

$fn = 100*1;

text = "Something";

// See http://www.google.com/fonts
font = "Architects Daughter"; //[ABeeZee,Abel,Abril Fatface,Aclonica,Acme,Actor,Adamina,Advent Pro,Aguafina Script,Akronim,Aladin,Aldrich,Alef,Alegreya,Alegreya Sans,Alegreya Sans SC,Alegreya SC,Alex Brush,Alfa Slab One,Alice,Alike,Alike Angular,Allan,Allerta,Allerta Stencil,Allura,Almendra,Almendra Display,Almendra SC,Amarante,Amaranth,Amatic SC,Amethysta,Amiri,Anaheim,Andada,Andada SC,Andika,Angkor,Annie Use Your Telescope,Anonymous Pro,Antic,Antic Didone,Antic Slab,Anton,Antonio,Arapey,Arbutus,Arbutus Slab,Architects Daughter,Archivo Black,Archivo Narrow,Arimo,Arizonia,Armata,Artifika,Arvo,Asap,Asset,Astloch,Asul,Atomic Age,Aubrey,Audiowide,Autour One,Average,Average Sans,Averia Gruesa Libre,Averia Libre,Averia Sans Libre,Averia Serif Libre,Bad Script,Balthazar,Bangers,Basic,Battambang,Baumans,Bayon,Belgrano,Belleza,BenchNine,Bentham,Berkshire Swash,Bevan,Bhavuka,Bigelow Rules,Bigshot One,Bilbo,Bilbo Swash Caps,Bitter,Black Ops One,Bokor,Bonbon,Boogaloo,Bowlby One,Bowlby One SC,Brawler,Bree Serif,Bruno Ace,Bruno Ace SC,Bubblegum Sans,Bubbler One,Buda,Buenard,Butcherman,Butcherman Caps,Butterfly Kids,Cabin,Cabin Condensed,Cabin Sketch,Caesar Dressing,Cagliostro,Calligraffitti,Cambay,Cambo,Candal,Cantarell,Cantata One,Cantora One,Capriola,Cardo,Carme,Carrois Gothic,Carrois Gothic SC,Carter One,Caudex,Cedarville Cursive,Ceviche One,Changa,Changa One,Chango,Chau Philomene One,Chela One,Chelsea Market,Chenla,Cherry Cream Soda,Cherry Swash,Chewy,Chicle,Chivo,Cinzel,Cinzel Decorative,Clara,Clicker Script,Coda,Coda Caption,Codystar,Combo,Comfortaa,Coming Soon,Concert One,Condiment,Content,Contrail One,Convergence,Cookie,Copse,Corben,Courgette,Cousine,Coustard,Covered By Your Grace,Crafty Girls,Creepster,Creepster Caps,Crete Round,Crimson Text,Croissant One,Crushed,Cuprum,Cutive,Cutive Mono,Damion,Dancing Script,Dangrek,Dawning of a New Day,Days One,Dekko,Delius,Delius Swash Caps,Delius Unicase,Della Respira,Denk One,Devonshire,Dhurjati,Dhyana,Didact Gothic,Dinah,Diplomata,Diplomata SC,Domine,Donegal One,Doppio One,Dorsa,Dosis,Droid Arabic Kufi,Droid Arabic Naskh,Droid Sans,Droid Sans Ethiopic,Droid Sans Mono,Droid Sans Thai,Droid Serif,Droid Serif Thai,Dr Sugiyama,Duru Sans,Dynalight,Eagle Lake,Eater,Eater Caps,EB Garamond,Economica,Eczar,Ek Mukta,Electrolize,Elsie,Elsie Swash Caps,Emblema One,Emilys Candy,Encode Sans,Encode Sans Compressed,Encode Sans Condensed,Encode Sans Narrow,Encode Sans Wide,Engagement,Englebert,Enriqueta,Erica One,Esteban,Euphoria Script,Ewert,Exo,Exo 2,Expletus Sans,Fanwood Text,Fascinate,Fascinate Inline,Faster One,Fasthand,Fauna One,Federant,Federo,Felipa,Fenix,Finger Paint,Fira Mono,Fira Sans,Fjalla One,Fjord One,Flamenco,Flavors,Fondamento,Fontdiner Swanky,Forum,Francois One,Freckle Face,Fredericka the Great,Fredoka One,Freehand,Fresca,Frijole,Fruktur,Fugaz One,Gabriela,Gafata,Galdeano,Galindo,Gentium Basic,Gentium Book Basic,Geo,Geostar,Geostar Fill,Germania One,GFS Didot,GFS Neohellenic,Gidugu,Gilda Display,Give You Glory,Glass Antiqua,Glegoo,Gloria Hallelujah,Goblin One,Gochi Hand,Gorditas,Goudy Bookletter 1911,Graduate,Grand Hotel,Gravitas One,Great Vibes,Griffy,Gruppo,Gudea,Gurajada,Habibi,Halant,Hammersmith One,Hanalei,Hanalei Fill,Handlee,Hanuman,Happy Monkey,Headland One,Henny Penny,Hermeneus One,Herr Von Muellerhoff,Hind,Holtwood One SC,Homemade Apple,Homenaje,Iceberg,Iceland,IM Fell Double Pica,IM Fell Double Pica SC,IM Fell DW Pica,IM Fell DW Pica SC,IM Fell English,IM Fell English SC,IM Fell French Canon,IM Fell French Canon SC,IM Fell Great Primer,IM Fell Great Primer SC,Imprima,Inconsolata,Inder,Indie Flower,Inika,Inknut Antiqua,Irish Grover,Irish Growler,Istok Web,Italiana,Italianno,Jacques Francois,Jacques Francois Shadow,Jaldi,Jim Nightshade,Jockey One,Jolly Lodger,Josefin Sans,Josefin Sans Std Light,Josefin Slab,Joti One,Judson,Julee,Julius Sans One,Junge,Jura,Just Another Hand,Just Me Again Down Here,Kadwa,Kalam,Kameron,Kantumruy,Karla,Karla Tamil Inclined,Karla Tamil Upright,Karma,Kaushan Script,Kavoon,Kdam Thmor,Keania One,Kelly Slab,Kenia,Khand,Khmer,Khula,Kite One,Knewave,Kotta One,Koulen,Kranky,Kreon,Kristi,Krona One,La Belle Aurore,Laila,Lakki Reddy,Lancelot,Lateef,Lato,League Script,Leckerli One,Ledger,Lekton,Lemon,Lemon One,Liberation Sans ,Libre Baskerville,Libre Caslon Text,Life Savers,Lilita One,Lily Script One,Limelight,Linden Hill,Lobster,Lobster Two,Lohit Bengali,Lohit Tamil,Londrina Outline,Londrina Shadow,Londrina Sketch,Londrina Solid,Lora,Loved by the King,Lovers Quarrel,Love Ya Like A Sister,Luckiest Guy,Lusitana,Lustria,Macondo,Macondo Swash Caps,Magra,Maiden Orange,Mako,Mallanna,Mandali,Marcellus,Marcellus SC,Marck Script,Margarine,Marko One,Marmelad,Martel Sans,Marvel,Mate,Mate SC,Maven Pro,McLaren,Meddon,MedievalSharp,Medula One,Megrim,Meie Script,Merge One,Merienda,Merienda One,Merriweather,Merriweather Sans,Mervale Script,Metal,Metal Mania,Metamorphous,Metrophobic,Miama,Michroma,Milonga,Miltonian,Miltonian Tattoo,Miniver,Miss Fajardose,Miss Saint Delafield,Modak,Modern Antiqua,Molengo,Molle,Monda,Monofett,Monoton,Monsieur La Doulaise,Montaga,Montez,Montserrat,Montserrat Alternates,Montserrat Subrayada,Moul,Moulpali,Mountains of Christmas,Mouse Memoirs,Mr Bedford,Mr Bedfort,Mr Dafoe,Mr De Haviland,Mrs Sheppards,Mrs Saint Delafield,Muli,Mystery Quest,Nanum Brush Script,Nanum Gothic,Nanum Gothic Coding,Nanum Myeongjo,Nanum Pen Script,NATS,Neucha,Neuton,New Rocker,News Cycle,Niconne,Nixie One,Nobile,Nokora,Norican,Nosifer,Nosifer Caps,Nothing You Could Do,Noticia Text,Noto Sans,Noto Sans Hebrew,Noto Sans Symbols,Noto Sans UI,Noto Serif,Nova Cut,Nova Flat,Nova Mono,Nova Oval,Nova Round,Nova Script,Nova Slim,Nova Square,NTR,Numans,Nunito,Odor Mean Chey,Offside,OFL Sorts Mill Goudy TT,Oldenburg,Old Standard TT,Oleo Script,Oleo Script Swash Caps,Open Sans,Open Sans Condensed,Oranienbaum,Orbitron,Oregano,Orienta,Original Surfer,Oswald,Overlock,Overlock SC,Over the Rainbow,Ovo,Oxygen,Oxygen Mono,Pacifico,Palanquin,Palanquin Dark,Paprika,Parisienne,Passero One,Passion One,Pathway Gothic One,Patrick Hand,Patrick Hand SC,Patua One,Paytone One,Pecita,Peddana,Peralta,Permanent Marker,Petit Formal Script,Petrona,Phetsarath,Philosopher,Piedra,Pinyon Script,Pirata One,Plaster,Play,Playball,Playfair Display,Playfair Display SC,Podkova,Poetsen One,Poiret One,Poller One,Poly,Pompiere,Ponnala,Pontano Sans,Poppins,Porter Sans Block,Port Lligat Sans,Port Lligat Slab,Prata,Preahvihear,Press Start 2P,Princess Sofia,Prociono,Prosto One,PT Mono,PT Sans,PT Sans Caption,PT Sans Narrow,PT Serif,PT Serif Caption,Puralecka Narrow,Puritan,Purple Purse,Quando,Quantico,Quattrocento,Quattrocento Sans,Questrial,Quicksand,Quintessential,Qwigley,Racing Sans One,Radley,Rajdhani,Raleway,Raleway Dots,Ramabhadra,Ramaraja,Rambla,Rammetto One,Ranchers,Rancho,Ranga,Rationale,Ravi Prakash,Redacted,Redacted Script,Redressed,Reenie Beanie,Revalia,Ribeye,Ribeye Marrow,Righteous,Risque,Roboto,Roboto Condensed,Roboto Slab,Rochester,Rock Salt,Rokkitt,Romanesco,Ropa Sans,Rosario,Rosarivo,Rouge Script,Rozha One,Rubik Mono One,Rubik One,Ruda,Rufina,Ruge Boogie,Ruluko,Rum Raisin,Ruslan Display,Russo One,Ruthie,Rye,Sacramento,Sail,Salsa,Sanchez,Sancreek,Sansation,Sansita One,Sarabun,Sarala,Sarina,Sarpanch,Satisfy,Scada,Scheherazade,Schoolbell,Seaweed Script,Sedan,Sedan SC,Sevillana,Seymour One,Shadows Into Light,Shadows Into Light Two,Shanti,Share,Share Tech,Share Tech Mono,Shojumaru,Short Stack,Siamreap,Siemreap,Sigmar One,Signika,Signika Negative,Simonetta,Sintony,Sirin Stencil,Six Caps,Skranji,Slabo 13px,Slabo 27px,Slackey,Smokum,Smythe,Sniglet,Snippet,Snowburst One,Sofadi One,Sofia,Sonsie One,Sorts Mill Goudy,Source Code Pro,Source Sans Pro,Source Serif Pro,Special Elite,Spicy Rice,Spinnaker,Spirax,Squada One,Sree Krushnadevaraya,Stalemate,Stalinist One,Stalin One,Stardos Stencil,Stint Ultra Condensed,Stint Ultra Expanded,Stoke,Strait,Strong,Sue Ellen Francisco,Sunshiney,Supermercado One,Suranna,Suravaram,Suwannaphum,Swanky and Moo Moo,Syncopate,Tangerine,Taprom,Tauri,Teko,Telex,Tenali Ramakrishna,Tenor Sans,Terminal Dosis,Terminal Dosis Light,Text Me One,Thabit,The Girl Next Door,Tienne,Tillana,Timmana,Tinos,Titan One,Titillium Web,Trade Winds,Trocchi,Trochut,Trykker,Tuffy,Tulpen One,Ubuntu,Ubuntu Condensed,Ubuntu Mono,Ultra,Uncial Antiqua,Underdog,Unica One,UnifrakturCook,UnifrakturMaguntia,Unkempt,Unlock,Unna,Vampiro One,Varela,Varela Round,Vast Shadow,Vesper Libre,Vibur,Vidaloka,Viga,Voces,Volkhov,Vollkorn,Voltaire,VT323,Waiting for the Sunrise,Wallpoet,Walter Turncoat,Warnes,Wellfleet,Wendy One,Wire One,Yanone Kaffeesatz,Yellowtail,Yeseva One,Yesteryear,Zeyada]

// font size
size = 20;

// height of letters
extrude = 5;

// for adjusting the space between letters
spacing = 1;

web = 0; //[0:Separate letters,1:Web base connecting letters]

direction = "ltr"; //["ltr":Left to Right,"ttb":Top to Bottom]

// the text
linear_extrude(extrude)
text(   text, size,
        font=font,
        spacing=spacing, direction=direction);

// the base
linear_extrude(web)
offset(r=-size)
offset(r=size)
text(   text, size,
        font=font,
        spacing=spacing, direction=direction);
```


[User]
I'm looking to create a dust cap for a bearing, and I'd like it to be parametric so I can adjust it for different bearing sizes. I have a basic design concept, and I'd like the SCAD code to reflect that.

Essentially, the dust cap will be cylindrical with a slightly more complex profile on the outside. It needs to have a rim that fits snugly over the bearing's outer race, and a wall that forms the main body of the cap. The rim has a slight ridge on both the top and bottom.

Here's a more detailed breakdown:

*   **Main Diameter:** This is the key parameter and will be the diameter that fits over the bearing, it will probably need some slight adjustment to get the right press fit. I'll call this `maindia`. The example code I have used 22.20 for a 608 bearing but I'd like to make this a parameter.
*   **Rim Height:** This is the vertical height of the rim, I'll call it `rimheight`.
*  **Wall Thickness:** This will be the thickness of the main wall of the dust cap, I'll call it `wall`.
*   **Rim Width:** This is the width of the rim itself, I'll call this `rim`.
*   **Ridge:** There needs to be a small ridge on each end of the rim and should be a maximum of 1/4 of `rimheight`, with a minimum of 0.7. I'll call this `ridge`.

The basic shape will be a cylinder with an outer profile that includes the ridges on the rim. The inner part will be hollowed out, and offset by the `rim` parameter to create the walls of the cap.  I guess this will require the use of `difference` and `union` statements.

I would also appreciate it if the code used `$fn = 100` for all cylinder operations to give smooth curves, and would be fully parametric so I can easily adjust it. I won't be using any custom libraries for this, just the built-in OpenSCAD functions should be enough. Could you write that for me please?

[Assistant]
dust_cap.scad:
```
//
//  dust cap for bearing
//  design by egil kvaleberg, 4 april 2015
//

// select for press fit, default is for 608-ZZ bearing, nominally 22mm dia
maindia = 22.20;

// height of rim, based on how much space is available axially
rimheight = 8.4;

// wall thickness of dust cap
wall = 1.2;

// rim width
rim = 1.8;

ridge = min(0.7, rimheight/4);

difference() {
	union() {
		cylinder(r1 = maindia/2-ridge, r2 = maindia/2, h = ridge, $fn=100);
		translate([0, 0, ridge]) cylinder(r = maindia/2, h = rimheight - 2*ridge, $fn=100);
		translate([0, 0, rimheight-ridge]) cylinder(r2 = maindia/2-ridge, r1 = maindia/2, h = ridge, $fn=100);
	}
	translate([0, 0, wall]) cylinder(r = maindia/2-rim, h = rimheight, $fn=100);
}

```


[User]
I'm looking to create a parametric OpenSCAD model of an origami duck. I have a basic design idea, but I need the code written from scratch, and it has to handle some non-planar faces. I want to be able to adjust parameters like the thickness of the "paper," the angles of the body, wings, and head, as well as the resolution of the curves.

Here's a breakdown of what I need:

**Core Structure:**

*   The duck should be built from a series of interconnected faces, like in the provided example, but it shouldn't be limited to the specific point values used in the example. Instead, I should be able to define points in a 3D space and derive the faces from these points. For example, for the current design, I have `p1=[0,0,0]; p2=[4,0,7.5]; p3=[13.8,0,9.8]; p4=[18.2,0,0]; p5=[26,0,11.5]; p6=[7,0,17]; p7=[10.4,0,10.6]; p8=[7,0,0]; p9=[-5,0,13]; p10=[0,0,12.8]; p11=[-0.5,0,16]; p12=[-3.8,0,6];`
*   The model needs to account for the fact that some origami faces are not planar. This will be achieved through additional folds.
*   The base of the duck model should be clipped at a certain height, or placed on a ground plane for printing purposes.
*   The model should be generated using `hull()` and `sphere()` elements to generate solid faces, as in the example.
*   The model should be mirrored about the Y axis, as in the example.

**Key Parameters:**

*   `thickness`:  Thickness of the "paper" (default, say, 1.2).
*   `body_angle`: Angle at which the main body is folded (default, say, 30 degrees).
*   `wing_angle`: Angle at which the wing is folded (default, say, 60 degrees).
*   `head_angle`: Angle at which the head is folded (default, say, 25 degrees).
*   `steps`:  Resolution of curves (default, say, 5).
*  `scale`: Overall scale of model (default, say, 2)

**Faces & Transformations:**

*   I need functions to transform points using rotation, translation, and scaling, along with a function to apply these transforms to an array of points (a "face"). I will also need a function that translates and rotates between coordinate systems defined by an arbitrary normal.
*   There should be modules for a double face, which mirrors a child module about the y-axis, and another module for the "face" that uses hulls and spheres to generate the surface.
*   Specific faces of the duck include the body, wing, neck, head, and beak. These faces will need to be defined by sets of vertices in space. For this specific model, using the aforementioned vertices, they would be, in order: body = `[p12,p5,p1,p4]`, wing=`[p1,p2,p3,p4]`, neck=`[p1,p12,p6,p7,p8]`, head=`[p7,p6,p11,p10]`, and beak=`[p9,p6,p7]`. However, I will need a way to define these points and faces for more arbitrary models. I will also need a way to manage the non-planar nature of some of the faces by defining intermediate points that are derived through rotation.
*   The body, wing, neck, and head should all be rotated along lines to create the folded origami effect. The code should be able to define an arbitrary axis of rotation between 2 arbitrary points in space.

**Libraries:**

*   I don't think I need any external libraries for this.

Could you please generate the necessary OpenSCAD code to accomplish this?

[Assistant]
duck_v.scad:
```
/*
   Origami Duck
   kit wallace

*/
//thickness of 'paper'
thickness=1.2;

body_angle=30;
wing_angle=60;
head_angle=25;

//quality of curves
steps=5;
scale=2;

//  functions for creating the matrices for transforming a single point

function m_translate(v) = [ [1, 0, 0, 0],
                            [0, 1, 0, 0],
                            [0, 0, 1, 0],
                            [v.x, v.y, v.z, 1  ] ];

function m_scale(v) =    [ [v.x, 0, 0, 0],
                            [0, v.y, 0, 0],
                            [0, 0, v.z, 0],
                            [0, 0, 0, 1  ] ];

function m_rotate(v) =  [ [1,  0,         0,        0],
                          [0,  cos(v.x),  sin(v.x), 0],
                          [0, -sin(v.x),  cos(v.x), 0],
                          [0,  0,         0,        1] ]
                      * [ [ cos(v.y), 0,  -sin(v.y), 0],
                          [0,         1,  0,        0],
                          [ sin(v.y), 0,  cos(v.y), 0],
                          [0,         0,  0,        1] ]
                      * [ [ cos(v.z),  sin(v.z), 0, 0],
                          [-sin(v.z),  cos(v.z), 0, 0],
                          [ 0,         0,        1, 0],
                          [ 0,         0,        0, 1] ];

function m_to(centre,normal) =
      m_rotate([0, atan2(sqrt(pow(normal.x, 2) + pow(normal.y, 2)), normal.z), 0])
    * m_rotate([0, 0, atan2(normal.y, normal.x)])
    * m_translate(centre);

function m_from(centre,normal) =
      m_translate(-centre)
    * m_rotate([0, 0, -atan2(normal.y, normal.x)])
    * m_rotate([0, -atan2(sqrt(pow(normal.x, 2) + pow(normal.y, 2)), normal.z), 0]);

function m_rotate_about_line(a,v1,v2) =
      m_from(v1,v2-v1)*m_rotate([0,0,a])*m_to(v1,v2-v1);

function vec3(v) = [v.x, v.y, v.z];
function m_transform(v, m)  = vec3([v.x, v.y, v.z, 1] * m);

function face_transform(face,m) =
     [ for (v = face) m_transform(v,m) ];

module double(axis) {
      union() {
          children();
          mirror(axis) children();
      }
  }
module face(s,t=thickness) {
    hull()
    for (i=[0:len(s) -1])
       translate(s[i]) sphere(t/2);
    }

module ground(size=50) {
   translate([0,0,-size]) cube(2*size,center=true);
}

// vertices
p1=[0,0,0];
p2=[4,0,7.5];
p3=[13.8,0,9.8];
p4=[18.2,0,0];
p5=[26,0,11.5];
p6=[7,0,17];
p7=[10.4,0,10.6];
p8=[7,0,0];
p9=[-5,0,13];
p10=[0,0,12.8];
p11=[-0.5,0,16];
p12=[-3.8,0,6];

$fn=steps;
// faces
body =[p12,p5,p1,p4];
wing=[p1,p2,p3,p4];
neck=[p1,p12,p6,p7,p8];
head=[p7,p6,p11,p10];
beak=[p9,p6,p7];

mbody= m_rotate_about_line(body_angle,p12,p5);
rbody= face_transform(body,mbody);
rwing=face_transform(wing,mbody) ;
mwing = m_rotate_about_line(-wing_angle,rwing[0],rwing[3]);
rrwing = face_transform(rwing,mwing);

mneck = m_rotate_about_line(head_angle,p12,p6);
rp7= m_transform(p7,mneck);  // has to have a kink

mhead = m_rotate_about_line(head_angle,p6,p11);
rhead=face_transform(head,mhead);
mbeak = m_rotate_about_line(head_angle,p6,p9);
rbeak=face_transform(beak,mbeak);

scale(scale)
difference() {
translate([0,0,-0.5])  // to form a better base
rotate([0,2,0])   // in attempt to get it level - gludgy
  double([0,1,0]) {
    color("blue")
        face(rrwing);

    color("green")
        face(rbody);

    color("yellow") {
        face([p12,rp7,p6]);
        face([m_transform(p1,mbody),rp7,p12,m_transform(p8,mbody)]);
    }
    color("red") {
       face(rhead);
       face(rbeak);
   }
  }
  ground();  // clip the base
}
```


[User]
I'd like to create a whiteboard eraser holder that clips onto the bottom edge of a whiteboard. It should also have some holes for storing whiteboard markers and space on the front to add some text using the `write.scad` library.

Here's the general idea of the design:

*   **Overall Shape:** The holder will be a rectangular box, with a front plate and a rear plate. The rear plate will be slightly taller than the front plate. The overall dimensions of the box, as well as the height of the front and rear plates, should be parameters.

*   **Board Clipping:** The holder needs to have a way to clip onto the whiteboard. I envision this as a lip on the top of the holder, that grabs onto the bottom edge of a whiteboard. The thickness of the whiteboard edge needs to be a parameter, and I need a clearance gap for this lip that's also a parameter. This means the rear plate will consist of two connected pieces, so it can clip on.

*   **Marker Holes:** There should be four holes for markers, arranged in a rectangle. The diameter of these holes should be a parameter.

*   **Text Area:** The front of the holder should have a flat surface to add some text. I want to use `write.scad` for this, and the message string, font, and text height should all be parameters. I also need control over the text's vertical position.

*   **Construction:** I think the main body should be a single piece, with the rear lip pieces added on.

*  **Units**: Please assume all measurements are in millimeters.

I need this to be fully parametric so that I can adjust the size of the holder for various applications. Please include comments in the code to explain the different parts.

[Assistant]
eraser-holder.scad:
```
// Laurie Gellatly
// Erase holder
use <write/Write.scad>;

//CUSTOMIZER VARIABLES

//(max 26 characters)
message = "Yvonne`s Board";
// to use
font = "write/orbitron.dxf"; // [write/Letters.dxf,write/BlackRose.dxf,write/orbitron.dxf,write/knewave.dxf,write/braille.dxf]

// Wall thickness
wt=2/1;
// overall of holder
xwidth = 200;	// [50:200]
// overall of holder
ydepth = 70;	// [50:100]
fheight = 15/1;	// front height
rheight = 30/1;	// rear height
// for pens
Hole_diameter = 16;	// [10:20]
hr = Hole_diameter/2;			// hole radius

Whiteboard_edge_thickness = 17;		//[10:30]
gap = Whiteboard_edge_thickness/1;		// gap to fit board

translate([xwidth/-2, gap+ydepth/2-wt,0]) cube ([xwidth, wt, rheight]);		// Rear plate
translate([xwidth/-2,     ydepth/2-2*wt,0]) cube ([xwidth, wt, rheight]);		// Rear plate
difference(){
	union(){
	translate([xwidth/-2, ydepth/-2,0]) cube ([xwidth, wt, fheight]);			// Front plate
	translate([gap+xwidth/-2, gap+ydepth/2-(2+wt),gap+2*wt+1]) cube ([xwidth/4, 2+wt, 3+wt]); // Clip
	for(i=[gap+xwidth/-2:4.4:gap+xwidth/-4]) translate([i,.4+gap+ydepth/2-(2+wt), gap+2*wt+1.6]) rotate([45-180,0,0]) cube([.6,.6,5]);
	translate([xwidth/4-gap , gap+ydepth/2-(2+wt),gap+2*wt+1]) cube ([xwidth/4, 2+wt, 3+wt]);
	for(i=[xwidth/4-gap:4.4:xwidth/2-gap]) translate([i,.4+gap+ydepth/2-(2+wt), .6+gap+2*wt+1]) rotate([45-180,0,0]) cube([.6,.6,5]);
	translate([gap+xwidth/-2,     ydepth/2-2*wt    ,gap+2*wt+1]) cube ([xwidth/4, 2+wt, 3+wt]); // Clip
	for(i=[gap+xwidth/-2:4.4:gap+xwidth/-4]) translate([i,ydepth/2, gap+2*wt+1]) rotate([45-270,0,0]) cube([.6,.6,5]);
	translate([xwidth/4-gap ,     ydepth/2-2*wt    , gap+2*wt+1]) cube ([xwidth/4, 2+wt, 3+wt]);
	for(i=[xwidth/4-gap:4.4:xwidth/2-gap]) translate([i,ydepth/2, gap+2*wt+1]) rotate([45-270,0,0]) cube([.6,.6,5]);
	translate([xwidth/-2, ydepth/-2,0]) cube ([xwidth, ydepth+gap, wt]);
 	translate([0, ydepth/-2,(fheight)/2-.4]) rotate([90,0,0]) write(message,t=.5,h=fheight-2,font="orbitron.dxf",center=true);	// font can be: Letters, orbitron, knewave, BlackRose or braille
	}
	translate([xwidth/-2 +1.5*hr, ydepth/-2+hr+9,-.1]) cylinder (r=hr,h=wt+.2);
	translate([xwidth/ 2 -1.5*hr, ydepth/-2+hr+9,-.1]) cylinder (r=hr,h=wt+.2);
	translate([xwidth/-2 +1.5*hr, ydepth/ 2-(hr+9),-.1]) cylinder (r=hr,h=wt+.2);
	translate([xwidth/ 2 -1.5*hr, ydepth/ 2-(hr+9),-.1]) cylinder (r=hr,h=wt+.2);
	translate([xwidth/-2-.1, gap+ydepth/2-(2+wt),gap+2*wt+1]) rotate([45,0,0]) cube ([xwidth+.2, 4+wt, 3+wt]);
	translate([xwidth/-2-.1,     ydepth/2+2-wt,gap+2*wt+1]) rotate([45,0,0]) cube ([xwidth+.2, 4+wt, 4+wt]);
}

```


[User]
Hi, I'm looking for some help designing a parametric Shabbat candle holder in OpenSCAD. I've seen some designs out there, and I have a general idea of what I'm after, but I need it to be flexible so I can experiment a bit.

Essentially, I want a cylindrical base that tapers slightly inward as it goes up, with a star of David motif around the middle. The top should have a depression to hold the candle. I'd like to control the overall height, the width at the widest part, the height of the middle star area, the size of the star of David elements, and the diameter of the candle recess.

Specifically, I'd like to be able to set:

*   `Top`: The total height of the candle holder.
*   `Middle`: The height at which the star of David elements are placed.
*   `Width`: The diameter at the widest part of the candle holder around the star of David elements.
*  `Star`: The overall size of each star of David element.
*  `Taper`: How much the star of David elements taper inwards as they extend out
*   `Candle`: The diameter of the circular recess at the top for the candle.

The star of David elements should be extruded from the main body, and I'd like them to be kind of thick to make it visually interesting. The whole design should be printable without supports if possible. I'm not sure if that means all the dimensions have to be right so it doesn't overhang too much.

Also I have a feeling that I'll need to use some linear_extrude and rotate_extrude, to generate the shape and stars.

Could you generate an OpenSCAD file that does this? I think I’ll want to be able to adjust all the parameters I listed at the beginning.

[Assistant]
candle_holder.scad:
```
/*
            Shabbat Candle Holder
            Steve Medwin
            April 2015
*/
$fn=100*1.0;
// preview[view:north east, tilt:top diagonal]

// user parameters
// height (mm) =
Top = 50;    // [40:70]
// height (mm) =
Middle = 30;    // [20:40]
// at middle (mm) =
Width = 40;     // [30:80]
// side (mm) =
Star = 20;      // [10:30]
// in star
Taper = 3;   // [1:4]
// diameter (mm) =
Candle = 25.0;  // [9:30]

// other parameters
// star of david
s = Star;
t = 5*1.0;
h = tan(60)*s/2;
h1 = t/sin(30);
h2 = h + t*2;
ztaper = Taper/4;

// polygon profile that is rotated
Xr = Candle/2;
Xa = h2;
Yb = 9.3*1.0;
Xc = 9.3*1.0;
Yd = 18.6*1.0;
Xe = Width/2;
Ye = Middle;
Xf = Xr + 4;
Yf = Top;
Yg = Yf - 4;

difference() {
    rotate_extrude(convexity=10)
    polygon( points=[[0,0],[Xa,0],[Xa,Yb/2],[Xc,Yb/2],[Xc,Yd],[Xe,Ye],[Xf,Yf],[0,Yg]]);
    translate([0,0,Ye]) cylinder(h = Yf, r=Xr, $fn=50);     // subtract cylinder for candle
}

for (i=[0:5]) {
   rotate([0,0,60*i])   translate([0,h2,0])
   linear_extrude(height = Yb, center = false, convexity = 10, twist = 0, scale = ztaper)
   polygon(points=[[s/2,0],[0,h],[-s/2,0],[s/2+h1*cos(30),-t],[0,h+h1],[-s/2-h1*cos(30),-t]], paths=[[0,1,2],[3,4,5]]);
   }

```


[User]
Hey there, I'm looking for an OpenSCAD design for a customizable filament spool holder for my delta printer. I'd like it to be top-mounted, so it should be designed to sit on top of the printer's frame.

I've got a basic idea of the shape, but I need it to be parametric so I can adjust it for different spools. Specifically, I need to be able to change the inner diameter of the spool holder, the overall height, and also the diameter of the lip that keeps the spool from falling off.

I'd prefer the design to be simple, probably using cylinders for the main shapes, something like what I've sketched out below:

*   A base cylinder with a lip (like a wide, short cylinder attached to a taller, thinner cylinder). This is the part that will hold the spool.
*   A hollowed-out center for the spool to sit on
*   Maybe a small chamfer or fillet to the top lip to make it easier to load the spool? That would be nice but is not required.

Could you generate the OpenSCAD files for this, making sure the following parameters are user-definable:

*   `spoolHoleDiameter`: The inner diameter of the spool hole (the part the spool rests on).
*   `spoolHeight`: The height of the spool holder's center cylinder (excluding the base and lip).
*   `lipDiameter`: The outer diameter of the lip on the base.
*   `lipHeight`: the height of the lip on the base.
*   `baseDiameter`: The diameter of the base cylinder.
*   `baseHeight`: the height of the base cylinder.

I'm not super familiar with OpenSCAD libraries, so let's just stick to the core language if that's okay. Thanks a bunch!

[Assistant]
Hatchbox1KGSpooler.scad:
```
// Enter the spool hole diameter in mm
spoolHoleD = 32;

// Enter the thickness of the spool in mm
spoolHeight = 60;

difference()
{
    union()
    {
        cylinder(r = 55, h = 3);
        cylinder(r = (spoolHoleD-2)/2, h = spoolHeight+3);
    }
    cylinder(r = ((spoolHoleD-2)/2)-3, h = spoolHeight+3);
}
$fn = 100;
```


[User]
I'm looking to design a modular shelving system using OpenSCAD, and I'd like it to be highly customizable. I've seen some designs that use interlocking modules, and that's the kind of thing I'm going for.

Here's what I need:

*   **Module Types:** I need to be able to create several different module types, specifically I, L, T, X, BL, BT, BR, FL, FT, and FR modules. Each type should have a different shape based on its name.  BL, BR, and BT will have "bottoms" at one end. FL, FR, and FT will have "bottoms" at the other end.

*   **Parametric Dimensions:**  I need to be able to adjust these parameters:
    *   `module_width`:  The overall width of the module.
    *   `board_thickness`: The thickness of the shelf board that will fit into the module.
    *   `wall_thickness`: The thickness of the module's walls.
    *  `corner_radius`: The radius for rounded corners
    *  `shape_detalization`: Control over the number of facets used for curved surfaces.
    *   `shape_type`:  A way to select different corner shapes. I'd like options like "no shape" (just square corners), "linear" (a straight line cut), "circle" (a rounded cutout), and "arc-in" (an inward-curving arc cutout).
    *   `shape_parameter`: A number to control the size of the corner shape.

*   **Interlocking:** The design should ensure that the modules interlock nicely, with slots for the boards and possibly some interlocking features.

*   **Corner Shapes:** The different `shape_type` options should be implemented parametrically.

*   **Bottoms:** For the "B" and "F" modules, there should be a 'bottom' added to the end where the letters "B" or "F" are, respectively.  These 'bottoms' should be partially circular.

I'd like all of this to be in a single OpenSCAD file (or, if necessary, a main file with includes to helper files). I'm okay with the solution using Minkowski sums and hulls. I don't need any specific libraries.

[Assistant]
shelving_module.scad:
```
/* [Parameters] */

//
module_type = "X-module"; // [I-module, L-module, T-module, X-module, BL-module, BT-module, BR-module, FL-module, FT-module, FR-module]

//
module_width = 50;

//
board_thickness = 10;

//
wall_thickness = 3;

/* [Shape] */
//Open SCAD parameter $fn = 4*detalization. Do not put too big value customizer will stuck.
shape_detalization=4; // default = 15, i.e. $fn = 60

//
corner_radius = 15;

//corner shape type
shape_type = "no shape"; // [no shape, linear, circle, arc-in]

//
shape_parameter = 0;

HH = module_width;
RR = corner_radius;
DD = board_thickness;
r=wall_thickness/2;

PP = shape_parameter;
$fn = 4*shape_detalization;

module side_block(h,d,r) {
 LHH = h-d/2-3*r;
 LDD = d/2+r;
 eps=0.01;

 difference(){
  hull(){
   translate([-LDD,+LDD,-LDD])sphere(r=r,center=true);
   translate([-LDD,-LDD,-LDD])sphere(r=r,center=true);
   translate([LHH,+LDD,-LDD])sphere(r=r,center=true);
   translate([LHH,-LDD,-LDD])sphere(r=r,center=true);
   translate([-LDD,+LDD,LHH])sphere(r=r,center=true);
   translate([-LDD,-LDD,LHH])sphere(r=r,center=true);
   translate([LHH,+LDD,LHH])sphere(r=r,center=true);
   translate([LHH,-LDD,LHH])sphere(r=r,center=true);
  }
  translate([d/2+2*r+eps,-d/2+eps,-d/2])cube([h,d-2*eps,h]);
 }
}

module side_corner(h,d,q,r) {
 LHH = h-d/2-3*r;
 LDD = d/2+r;
 w=d+2*r;

 translate([0,0,-(d/2+r)]){
  translate([q+w/2,q+w/2,0])
  intersection(){
   rotate_extrude(convexity = 2){
    translate([q, 0]) circle(r = r);
    translate([q, HH-2*r]) circle(r = r);
   }
   translate([-q/2-r/2,-q/2-r/2,HH/2-r])
    cube([q+r,q+r,HH],center=true);
  }

  translate([0,0,-r])
  linear_extrude(HH)
  difference(){
   translate([w/2,w/2])square([q,q]);
   translate([+(q+w/2),+(q+w/2)])circle(q);
  }

  linear_extrude(HH-2*r)
  difference(){
   translate([w/2,w/2])square([q,q]);
   translate([+(q+w/2),+(q+w/2)])circle(q-r);
  }
 }
}

module side_plate_line(h,d,q,r){
 LHH = h-d/2-3*r;
 LDD = d/2+r;

 hull()
 {
  translate([LDD,LDD,-LDD])sphere(r=r,center=true);
  translate([LDD,LHH-q,-LDD])sphere(r=r,center=true);
  translate([LHH-q,LDD,-LDD])sphere(r=r,center=true);
 }
}

module side_plate_arcout(h,d,q,r){
 LHH = h-d/2-3*r;
 LDD = d/2+r;

 hull()
 {
  translate([LDD,LDD,-LDD])sphere(r=r,center=true);
  translate([LDD,LHH,-LDD])sphere(r=r,center=true);
  translate([LHH,LDD,-LDD])sphere(r=r,center=true);
  translate([0,0,-(d/2+r)])
  translate([LHH-q,LHH-q,0])
  intersection(){
   rotate_extrude(){
    translate([q, 0])
    intersection(){
     circle(r = r);
     translate([0,-r])square([2*r,2*r]);
    }
   }
   translate([+q/2+r/2,+q/2+r/2,h/2-r])
    cube([q+r,q+r,h],center=true);
  }
 }
}

module side_plate_arcin(h,d,q,r) {
 LHH = h-d/2-3*r;
 LDD = d/2+r;
 w=d+2*r;

 translate([0,0,-(d/2+r)]){
  translate([q+w/2,q+w/2,0])
  intersection(){
   rotate_extrude(convexity = 2){
    translate([q, 0]) circle(r = r);
   }
   translate([-q/2-r/2,-q/2-r/2,HH/2-r])
    cube([q+r,q+r,HH],center=true);
  }

  translate([0,0,-r])
  linear_extrude(2*r)
  difference(){
   translate([w/2,w/2])square([q,q]);
   translate([+(q+w/2),+(q+w/2)])circle(q);
  }
 }
}

module side_plate(h,d,q,r){
 side_corner(h,d,q,r);
 if (shape_type == "linear") side_plate_line(h,d,PP,r);
 if (shape_type == "circle") side_plate_arcout(h,d,PP,r);
 if (shape_type == "arc-in") side_plate_arcin(h,d,h-d-4*r-PP,r);
}

module bottom_sub(h,d,q,r){
 w=d+2*r;
 translate([+(h-w/2),-w/2,0])
 scale([0.8,h/(h-w),1])  //1.5
 translate([0,h-w,0])
 cylinder(r=h-w,h=2*h,center=true,$fn=2*$fn);
}

module bottom_frame(h,d,q,r){
 LHH = h-d/2-3*r;
 LDD = d/2+r;
 w=d+2*r;
 ww = 2*h-w-2*(h-w)*0.8;

 rotate([0,0,180])
 minkowski()
 {
  difference(){
   translate([0,d/2+r,0])
    translate([-ww/2,0,-ww/2])
    cube([h-2*r,LHH-d/2-r,h-2*r]);

   union(){
    rotate([0,  0,0]) bottom_sub(h,d,q,r);
    rotate([0, 90,0]) bottom_sub(h,d,q,r);
    rotate([0,-90,0]) bottom_sub(h,d,q,r);
    rotate([0,180,0]) bottom_sub(h,d,q,r);
   }
  }
  sphere(r=r);
 }
}

module module_BL(h=HH,d=DD,q=RR,r=r){
 w=d+2*r;
 ww = 2*h-w-2*(h-w)*0.8;

 module_L(h,d,q,r);
 translate([(ww-w)/2,0,(ww-w)/2])
 rotate([0,90,0])bottom_frame(h,d,q,r);
}

module module_BR(h=HH,d=DD,q=RR,r=r){
 mirror([1,0,0])module_BL(h,d,q,r);
}

module module_BT(h=HH,d=DD,q=RR,r=r){
 w=d+2*r;
 ww = 2*h-w-2*(h-w)*0.8;

 rotate([0,0,180])module_T(h,d,q,r);
 translate([0,0,(ww-w)/2]){
 rotate([0,0,0])bottom_frame(h,d,q,r);
 rotate([0,90,0])bottom_frame(h,d,q,r);
 }
}

module module_FR(h=HH,d=DD,q=RR,r=r){
 w=d+2*r;
 ww = 2*h-w-2*(h-w)*0.8;

 module_L(h,d,q,r);
 //translate([(ww-w)/2,0,(ww-w)/2])
 translate([(ww-w)/2,0,h-w-2*r-(ww-w)/2])
 rotate([0,180,0])bottom_frame(h,d,q,r);
}

module module_FL(h=HH,d=DD,q=RR,r=r){
 mirror([1,0,0])module_FR(h,d,q,r);
}

module module_FT(h=HH,d=DD,q=RR,r=r){
 w=d+2*r;
 ww = 2*h-w-2*(h-w)*0.8;

 rotate([0,0,180])module_T(h,d,q,r);
 translate([0,0,h-w-2*r-(ww-w)/2]){
 rotate([0,180,0])bottom_frame(h,d,q,r);
 rotate([0,-90,0])bottom_frame(h,d,q,r);
 }
}

module module_I(h=HH,d=DD,q=RR,r=r){
 rotate([0,0,-90])side_block(h, d, r);
 rotate([0,0,+90])side_block(h, d, r);
}

module module_L(h=HH,d=DD,q=RR,r=r){
 side_block(h, d, r);
 rotate([0,0,90])side_block(h, d, r);

 side_plate(h,d,q,r);
}

module module_T(h=HH,d=DD,q=RR,r=r){
 rotate([0,0,0])side_block(h, d, r);
 rotate([0,0,-90])side_block(h, d, r);
 rotate([0,0,180])side_block(h, d, r);

 rotate([0,0,-90])side_plate(h,d,q,r);
 rotate([0,0,180])side_plate(h,d,q,r);
}

module module_X(h=HH,d=DD,q=RR,r=r){
 rotate([0,0,  0])side_block(h, d, r);
 rotate([0,0, 90])side_block(h, d, r);
 rotate([0,0,180])side_block(h, d, r);
 rotate([0,0,270])side_block(h, d, r);

 rotate([0,0,  0])side_plate(h,d,q,r);
 rotate([0,0, 90])side_plate(h,d,q,r);
 rotate([0,0,180])side_plate(h,d,q,r);
 rotate([0,0,270])side_plate(h,d,q,r);
}

if (module_type == "I-module") module_I();
if (module_type == "L-module") module_L();
if (module_type == "T-module") module_T();
if (module_type == "X-module") module_X();
if (module_type == "BL-module") module_BL();
if (module_type == "BT-module") module_BT();
if (module_type == "BR-module") module_BR();
if (module_type == "FL-module") module_FL();
if (module_type == "FT-module") module_FT();
if (module_type == "FR-module") module_FR();

```


[User]
Hey, I'm looking to create a parametric OpenSCAD design for a build plate holder. I've been using a basic one I created, but I want something more robust and flexible. I use it to hold glass build plates, primarily while I'm prepping them - applying tape or hairspray and also for cooling plates after a print, so I can quickly swap to another plate.

I would like the holder to be a two-piece design, and should allow for the following parameters:

*   **`plate_width`**: The width of the build plate in mm.
*   **`plate_length`**: The length of the build plate in mm.
*   **`plate_thickness`**: The thickness of the build plate in mm.
*  **`hole_diameter`**: The diameter of the holes for threaded rods, in mm. This should be sized to accept 6 mm threaded rod, with an appropriate tolerance (e.g., 7.2 mm as in my design.)
*   **`support_height`**: This should be calculated as `plate_thickness + hole_diameter + 5`.
*   **`support_diameter`**: This should be calculated as `plate_thickness * 2.5`.

The holder should be a rectangular block with cylindrical supports at each end, for supporting the build plate itself. There should be cutouts in this base to accommodate the plate, and also holes for threaded rods.

For the cutouts that hold the plate, please make them just a little larger than the plate, so that it doesn't fit too tightly - maybe 0.4mm larger along the width of the plate, and 1mm larger along the length. The cutouts should also be slightly taller than the plate.

The design should also include a wall around the sides of the block and supports, to add some additional support to the model. I was having a corner break off my current version.

I’d also like the holes for the threaded rods to be positioned a quarter of the width from each side and to pass through the full length of the block.

I'd like to avoid any library dependencies (like MCAD). I think we can do this all with primitives.

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

[Assistant]
halfbase.scad:
```
/**
Glass build plate holder 2-piece
**/

/* [Main] */
// Width of build plate (mm)
plate_width = 153; //[100:400]
// Length of build plate (mm)
plate_length = 236; //[100:400]
// Thickness of build plate (mm)
plate_thickness = 5; //[2:8]
/* [Extras] */
// Diameter of holes for threaded rod
hole_diameter = 7.2; //[4:10]
/* [Hidden] */
support_height = plate_thickness+hole_diameter+5;
support_diameter = plate_thickness*2.5;

union() {
  difference() {
    union() {
      cube([plate_width+4,plate_length/4,support_height]);
      translate([3,3,0])
        cylinder(r=support_diameter/2,h=support_height+1);
      translate([(plate_width+4)-3,3,0])
        cylinder(r=support_diameter/2,h=support_height+1);
    }
    translate([1.8,2,(support_height+.5)-plate_thickness])
      cube([plate_width+.4,(plate_length/4)+1,plate_thickness+4]);
    translate([plate_width/4,-.1,(support_height-plate_thickness)/2])
      rotate([270,0,0])
        cylinder(r=hole_diameter/2,h=plate_length);
    translate([plate_width-(plate_width/4),-.1,(support_height-plate_thickness)/2])
      rotate([270,0,0])
        cylinder(r=hole_diameter/2,h=plate_length);
  }
  //translate([plate_width/3,plate_length/8,(support_height-plate_thickness)-1])
  //  cylinder(r=hole_diameter/2,h=3);
  //translate([plate_width-(plate_width/3),plate_length/8,(support_height-plate_thickness)-1])
  //  cylinder(r=hole_diameter/2,h=3);
}

```


[User]
Okay, I'm looking to design a corner support for holding glass build plates. I have a couple of different sizes, so I'd like the design to be parametric so I can adjust it easily. I'm also trying to learn OpenSCAD and I'd like some help getting started.

Here's what I'm thinking: I need a corner piece that will support the edge of a rectangular glass plate. The plate will rest on the top of the support. I want a version of the support for both the left and right corners of the plate - it should be mirrored, basically. The support should have two small cylindrical columns, one near each edge of the plate, that come up along the outside of the plate, providing a bit more security to prevent the plate from sliding off.

The main parameters I need are:
*   `plate_width`: The width of the build plate.
*   `plate_length`: The length of the build plate.
*   `plate_thickness`: The thickness of the build plate, I might want to make this slightly smaller than actual thickness for a slightly loose fit.
*   `side`: either "left" or "right" to specify which side of the plate the support should be for.
*   `hole_diameter`: The diameter of a through-hole for a threaded rod (for future mounting options).

The cylindrical columns should be taller than the plate, by an amount that is derived from the `hole_diameter` and `plate_thickness` values and some additional height.

I'm thinking the support should be roughly a quarter of the size of the plate's length and width - so a `plate_length/4` x `plate_width/4` cube, and then with the two supporting cylinders added and then subtract the appropriate parts.

I also need the two through holes for threaded rod to be placed near the corner edges, one parallel to the length, and one parallel to the width.

Can you help me create the OpenSCAD file for this? I'm not worried about using any libraries, it should all be in a single file.

[Assistant]
cornerbase.scad:
```
/**
Glass build plate holder 4-piece
**/

/* [Main] */
// Width of build plate (mm)
plate_width = 153; //[100:400]
// Length of build plate (mm)
plate_length = 236; //[100:400]
// Thickness of build plate (mm), may want to set this to slightly less than actual thickness
plate_thickness = 5; //[2:8]
// Side of support to print, 2 of each side required for full support
side = "left"; //[left, right]
/* [Extras] */
// Diameter of holes for threaded rod
hole_diameter = 7; //[4:10]
/* [Hidden] */
support_height = plate_thickness+(hole_diameter*2)+5;
support_diameter = plate_thickness*2;

cornerbase();

module cornerbase() {
  difference() {
    union() {
      cube([plate_length/4,plate_width/4,support_height]);
      if (side == "left") {
        translate([plate_thickness*0.2,plate_thickness*0.2,0])
          cylinder(r=support_diameter/2,h=support_height);
      } else if (side == "right") {
        translate([(plate_length/4)-(plate_thickness*0.2),plate_thickness*0.2,0])
          cylinder(r=support_diameter/2,h=support_height);
      } else {
        echo("WARNING: No Support column created, must specify left or right side!");
      }
    }
    translate([-0.1,-0.1,support_height-plate_thickness])
      cube([(plate_length/4)+1,(plate_width/4)+1,plate_thickness+1]);
    translate([plate_length/8,-0.1,(support_height-plate_thickness)/2+(hole_diameter/2)])
      rotate([270,0,0])
        cylinder(r=hole_diameter/2,h=plate_length);
    translate([-0.1,plate_width/8,(support_height-plate_thickness)/2-(hole_diameter/2)])
      rotate([0,90,0])
        cylinder(r=hole_diameter/2,h=plate_length);
  }
}

```


[User]
I need an OpenSCAD design for a hollow cone. The cone should have adjustable parameters for its height, diameter, wall thickness, and the number of facets used to draw the curve. I would like to be able to easily change each of these in the code.

I want the code to generate the hollow cone by subtracting a smaller cone from a larger one. The outer cone will have the parameters I specify. The inner cone should be calculated from the given parameters and will be nested inside, thereby forming the cone's walls.

Specifically, I want these parameters to be user-definable:

*   `conus_height`: The overall height of the cone.
*   `conus_diameter`: The diameter of the base of the outer cone.
*   `conus_thickness`: The thickness of the cone's wall.
*   `conus_fn`: The number of facets used to draw the curved surfaces (should be 3 or more).

The inner cone should then have a height of `conus_height - conus_thickness` and a diameter of `conus_diameter - conus_thickness`.

Could you generate an OpenSCAD file to do this?

[Assistant]
konus.scad:
```
// cone height
conus_height = 30;
// cone diameter
conus_diameter = 30;
// cone thickness
conus_thickness = 2;
// cone fn (>=3)
conus_fn = 50;

conus2_height = conus_height-conus_thickness;
conus2_diameter = conus_diameter-conus_thickness;

difference(){
  cylinder(h=conus_height, d1=conus_diameter, d2=0, $fn=conus_fn);
  cylinder(h=conus2_height, d1=conus2_diameter, d2=0, $fn=conus_fn);
}
```