[User]
I'm looking to create a parametric design for a connector "shell" that can be arranged in either a single or double row configuration. I have a basic idea, but need help coding it up in OpenSCAD.

The basic shell should be a rectangular prism with a few key features:

*   **Main Body:** A rectangular prism that is hollowed out. The inner hollow should also be a rectangular prism, so the shell has consistent wall thickness.
*   **Pin Hole:** A cylindrical hole going all the way through the shell. This hole should have a four-sided polygon profile, and be rotated 45 degrees.
*   **Chamfer:**  A 45-degree chamfer on the top of the pin hole, implemented as a truncated cone with the same 4-sided polygon profile.
*   **Tab Hole:** A rectangular prism cutout at the bottom of the main body.
*  **Tab:** A small rectangular prism protruding from the bottom of the main body that would interface with the tab hole in another shell.

I want to be able to specify the following parameters:

*   **`count`:** The number of shells in a single row (e.g., 10).
*   **`dual`:** A boolean parameter, with options "TRUE" or "FALSE" to select if the shells should be laid out in one or two rows. If `dual` is "TRUE", then a second row of shells will be laid out, offset and rotated to interlock with the first row.
*   **Dimensions:** The specific dimensions for the main body, inner hollow, pin hole, chamfer, tab hole and tab. I can provide these. For the first iteration, let's set the following:
    *  Main body:  2.5 x 2.5 x 14 (centered)
    *  Inner hollow:  2 x 2 x 14 (centered, offset up 1 mm)
    *  Pin hole: 0.8 radius, height 60 (centered)
    *  Chamfer: top radius 2.5, bottom radius 0.8, height 0.5 (centered, offset down 7.1 mm)
    * Tab hole: 1.8 x 1 x 5 (centered, offset down 0.5, offset back 1)
    * Tab: 1.3 x 0.25 x 4.5 (centered, offset back 1.125, offset up 0.8)
* Row Spacing: The spacing between shells in a row will be 2.5 mm.
* Row Offset: The offset of the second row should be 5 mm in height and the shells should be offset in the x direction by 2.5mm.

The design should be fully parametric, so I can adjust dimensions and layout parameters easily later on. I want all code to be generated directly; please do not reference any libraries.

Could you generate the necessary OpenSCAD code?

[Assistant]
shell.scad:
```
// the number of "shells" to make in one row
count = 10;
// row version
dual = "TRUE"; // [FALSE: One row, TRUE: Two rows]

module shell() {
    translate([2.5/2, 7, 2.5/2])
    rotate([90, 0, 0])
    union() {
        difference() {
            cube([2.5, 2.5, 14], center=true);
            // inner hole/hollow
            translate([0, 0, 1])
                cube([2, 2, 14], center=true);
            // pin hole
            rotate([0, 0, 45])
                cylinder(r=0.8, h=60, center=true, $fn=4);
            // chamfer
            translate([0, 0, -7.1]) rotate([0, 0, 45])
                cylinder(r1=2.5, r2=0.8, h=0.5, center=true, $fn=4);
            // tab hole
            translate([0, -1, -0.5])
            cube([1.8, 1, 5], center=true);
        }
        // tab
        translate([0, -1.125, 0.8])
            cube([1.3, 0.25, 4.5], center=true);
    }
}

for(i = [0:count-1])
 {  translate([2.5*i, 0, 0])
        shell();
    if (dual == "TRUE")
        translate([2.5*i+2.5, 0, 5])
        rotate([0, 180, 0])  shell();
 }
```


[User]
Hi, I need an OpenSCAD file to generate a simple foot for IKEA Metod cabinets. I have a basic model in SCAD, but I'd like to make it parametric so I can adjust it more easily.

Essentially, it's a rounded rectangular block with four cylindrical pegs on the top for locating on the cabinet's pre-drilled holes.

Here are the key parameters I want to control:

*   **`foot_height`**: The overall height of the foot (not including the pegs).
*   **`foot_width`**: The width of the rectangular base.
*   **`foot_depth`**: The depth of the rectangular base.
*   **`corner_radius`**: The radius of the rounded corners of the rectangular base.
*   **`peg_diameter`**: The diameter of the main part of the cylindrical pegs.
*   **`peg_shoulder_diameter`**: The diameter of the reduced upper portion of the pegs (the "shoulder").
*   **`peg_height`**: The height of the main part of the cylindrical pegs.
*   **`peg_shoulder_height`**: The height of the reduced "shoulder" of the pegs.
*   **`peg_x_offset`**: The x-coordinate distance of the pegs from the center. The pegs are located at +/- this offset
*   **`peg_y_offset`**: The y-coordinate distance of the pegs from the center. The pegs are located at +/- this offset

The pegs should be located at the four corners.

I'd also like to specify the rendering quality using the `$fn` variable.

Could you please generate an OpenSCAD file with these parameters? Also, can you ensure that the code is well commented, so it’s easy to understand what each section does?

[Assistant]
IKEA_Metod_Foot.scad:
```
//Rendering quality
$fn=128;//[fine:128,coarse:64]

/* [Global] */
//in millimeters without the pins
height=15;

/* [Hidden] */
width=85;
depth=55;

translate([0,0,-height/2])
roundedcube(width,depth,height,10);

translate([32,16,0])
cylinder(h=8,r1=4.8,r2=4.8,center=false);
translate([32,16,8])
cylinder(h=2,r1=4.8,r2=2.8,center=false);

translate([32,-16,0])
cylinder(h=8,r1=4.8,r2=4.8,center=false);
translate([32,-16,8])
cylinder(h=2,r1=4.8,r2=2.8,center=false);

translate([-32,16,0])
cylinder(h=8,r1=4.8,r2=4.8,center=false);
translate([-32,16,8])
cylinder(h=2,r1=4.8,r2=2.8,center=false);

translate([-32,-16,0])
cylinder(h=8,r1=4.8,r2=4.8,center=false);
translate([-32,-16,8])
cylinder(h=2,r1=4.8,r2=2.8,center=false);

module roundedcube(xdim, ydim, zdim, rdim){
    hull(){
    translate([rdim-width/2,rdim-depth/2,-height/2])
        cylinder(r=rdim,h=zdim);
    translate([xdim-rdim-width/2,rdim-depth/2,-height/2])
        cylinder(r=rdim,h=zdim);
    translate([rdim-width/2,ydim-rdim-depth/2,-height/2])
        cylinder(r=rdim,h=zdim);
    translate([xdim-rdim-width/2,ydim-rdim-depth/2,-height/2])
        cylinder(r=rdim,h=zdim);
}
}
```


[User]
I'd like to create a customizable desktop nameplate with two lines of text. I need the design to be parametric so I can easily adjust the text, font, size, and spacing. It should also be able to create a single, printable object, or split parts for dual extrusion. Finally, a flat version without the stand should be an option.

Here's what I'm envisioning:

*   **Text:** I need two lines of customizable text.
*   **Fonts:** I want to be able to specify the font for each line of text individually from the Google Fonts library. I also need to be able to set the style (bold, italic, etc.) for each line.
*   **Sizes:** The font size for each line should be independently adjustable.
*   **Spacing:** I need to be able to control the distance between the two lines of text as well as the distance between the text and the edges of the nameplate. I'd also like to be able to adjust the letter spacing within each line.
*   **Length:** the overall length of the plate should scale to fit the text.
*   **Types:** I need three options:
    *   A "full nameplate" for single extrusion printers, where the base and text are printed as one object. This should have the base with an angled profile.
    *   Separate parts ("dual_extrusion_base_part" and "dual_extrusion_text_part") for dual extrusion printers.
    *  A "flat_nameplate" version that is just a flat tag for sticking on things, without the base.
*   **Text Extrusion:** I should be able to control the extrusion height (thickness) of the text.
*   **Flat Tag Thickness:** If I select the flat tag option, I want to be able to set the thickness of the tag.
*   **Fine Tuning:** Include options to shift the text up or down if needed, and adjust the width of the text as sometimes the font can cause the width calculation to be off.
*   **Libraries:** It seems like this shouldn't require any libraries, but if you use any, please let me know.

Could you generate the necessary OpenSCAD code? Thanks!

[Assistant]
nameplate_VD.scad:
```
//What type do you want? For single extrusion and filament change, use "Full Nameplate": If your printer supports dual Extrusion, generate the base and text separately. If you just want a flat name tag to stick on a surface, use "Flat name tag".
type= "full_nameplate"; // [full_nameplate:Full Nameplate,dual_extrusion_base_part:For dual extrusion: The base,dual_extrusion_text_part:For dual extrusion: The text,flat_nameplate:A flat name tag]

// What would you like to label?
textstr1 = "Johanna Sophie";

textstr2 = "Chief of Unicorn Division";

//Font name, e.g. "Orbitron", "Bangers", "Luckiest Guy", "Libration Sans", "Aldo", depends on what is available on the platform. In the customizer,choose from about 700 Google Fonts. For an overview please refer: http://www.google.com/fonts - Use e.g. "Segoe Print" or "Noto Sans" if you need special characters in textstring1/2
fontname1="Lato"; //[Lato, Playfair Display SC,Arial,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,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,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,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]

//Set the text 1 font style - but it might be your desired style is not available for the selected font. Just try it and see.
fontstyle1="Bold";//[Regular,Bold,Italic,Bold Italic,Narrow,ExtraBold,Black,Light,Thin,Medium Italic, SemiBold,Condensed,Expanded,Oblique]

// How big? (8-20 are good values)
textsize1 = 12;

//Font name, e.g. "Orbitron", "Bangers", "Luckiest Guy", "Libration Sans", "Aldo", depends on what is available on the platform. In the customizer,choose from about 700 Google Fonts. For an overview please refer: http://www.google.com/fonts - Use e.g. "Segoe Print" or "Noto Sans" if you need special characters in textstring1/2
fontname2="<same as fontname1>"; //[<same as fontname1>,Arial,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,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,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,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]

//Set the text 2 font style - but it might be your desired style is not available for the selected font. Just try it and see.
fontstyle2="<same as fontstyle1>";//[<same as fontstyle1>,Regular,Bold,Italic,Bold Italic,Narrow,ExtraBold,Black,Light,Thin,Medium Italic, SemiBold,Condensed,Expanded,Oblique]

// How big?
textsize2 = 7;

//Distance between the two lines in percentage of the average font height
distance_lines=.5;

//Distance to the border of the name plate, as a percentage of the average font height
distance_border_factor=.8;

// Want to space out the individual letters? Its... 0.9:Tight,1:Default,1.5:Wide
letter_spacing = 1;

// How much space on the ends? This is measured in letters.
end_space = 4;

//Just for correction, if you need to shift the text up/down a bit so it fits nicely
shift_up=0;

//Just for correction, if the width of the text is not proper (its calculated based on the font size and for extremely narrow or wide fonts you might need to change this value):
adjust_width_factor=.66;

//Extrusion height of text in mm
extrude_text=3;

//Only if you chose "Flat name tag", set the thickness of that plate here:
nametag_th=2;

/* [Hidden] */
//-------------------------------------------------------------------------------
/*
Desk Nameplate
Version D, February 2019
*** based on "RLazure" Version of 2014
https://www.thingiverse.com/thing:162367
https://www.thingiverse.com/thing:256837
*** This code is inspired in part by TheNewHobbyist's input parameters and label length calculations

Modified by MC Geisler (mcgenki at gmail dot com)
  - added all new fonts
  - centered the text
  - two lines of text
  - some other improvements

RLazures Introduction Text:
This desktop nameplate is intended to be printed in 2 colours.
Use the Pause @ZPos feature in the Replicator's version 7.3 firmware or other printers change-filament funciton
Version 2 change to allow dualextrusion on the Replicator 2x

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.
*/

fontname2_final = (fontname2=="<same as fontname1>" ? fontname1 : fontname2 );
fontstyle2_final = (fontstyle2=="<same as fontstyle1>" ? fontstyle1 : fontstyle2 );
realtextsize1=textsize1*(textstr1==""?0:(fontname1=="Press Start 2P" || fontname1=="Henny Penny"?1.1:1));
realtextsize2=textsize2*(textstr2==""?0:(fontname2=="Press Start 2P" || fontname2=="Henny Penny"?1.1:1));

two_lines=(textstr1!="" && textstr2!="" ? 1:0);
distance=distance_lines*two_lines;

average_font_size=(realtextsize1+realtextsize2)/2;
distance_two_lines=average_font_size*distance;
distance_to_border=average_font_size*distance_border_factor;
nameplate_height=realtextsize1+realtextsize2+distance_two_lines+2*distance_to_border;
scl= 1/24*nameplate_height;

width1 = (adjust_width_factor*realtextsize1*letter_spacing); // Find width of each character
width2 = (adjust_width_factor*realtextsize2*letter_spacing); // Find width of each character
length_extrude=max(  width1*(len(textstr1)+end_space),  width2*(len(textstr2)+end_space)  );
echo(realtextsize1,realtextsize2);
echo(width1,width2,length_extrude);

///////////////////////////////////////
/////// modules ///////////////////////
//////////////////////////////////////

module writetext(textstr1, textstr2, sizeit1, sizeit2,length_extrude)
{
    halignvalue = "center";

    linear_extrude(height=extrude_text, center = false)
    {
        fullfont1=str(fontname1,":style=",fontstyle1);
        fullfont2=str(fontname2_final,":style=",fontstyle2_final);

        translate([0,-distance_to_border,0])
            text(textstr1,size=sizeit1,font=fullfont1,halign=halignvalue,valign="top");
        translate([0,-distance_to_border-realtextsize1-distance_two_lines,0])
            text(textstr2,size=sizeit2,font=fullfont2,halign=halignvalue,valign="top");
    }
}

module base()
{
//	linear_extrude(length_extrude, center = true, convexity = 10, twist = 0)

    scale([scl,scl,1])
        linear_extrude(height=length_extrude, center = true)
            polygon([[8,0],[0,16],[24,16],[16,0]], [[0,1,2,3]]);  // profile shape
}

module base_plate()
{
    translate([0,0,-length_extrude/2])
        cube([nameplate_height,nametag_th,length_extrude], center = false);
}

module text_plate()
{
    //translate([ w-wall,h-wall-textsize,height ])
    translate([-shift_up,0,0])
        rotate([0,90,90])
        {
            writetext(textstr1, textstr2, textsize1, textsize2, extrude_text);
        }

}

module print_part(type)
				{
//
//  assembly depending on single or dual extruder
//
if (type == "full_nameplate")
		{
			union() {
				base();
				translate([0,16*scl,0])
                    text_plate();
						}
		} else if (type == "dual_extrusion_base_part")
			{
				base();
		} else if (type == "dual_extrusion_text_part")
			{
                translate([0,16*scl,0])
                    text_plate();
		} else if (type == "flat_nameplate")
			{
                base_plate();
				translate([0,nametag_th,0])
                    text_plate();
		}
}

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

// orient on platform

rotate([90,0,270])
    translate([-12,0,0])
        print_part(type);

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

```


[User]
Okay, I'd like to create a parametric crochet hook design in OpenSCAD. I've been using a design I found online, but I want to be able to adjust all the dimensions easily. I need a main file, and if you think it helps, please include any necessary support files or libraries, but don't assume they're already installed. It should be something you can drop in, and it will just work.

Here's the breakdown of what I need:

**Core Shape:**

*   The hook will have a cylindrical shaft. I need to control the overall diameter and length of this cylinder. Let's call these `diameter` and `length`.
*   There will be a hook part at one end, created by intersecting with a cylinder. Let's call the length of the hook that curves `hook_length`. The diameter of the intersecting cylinder will be the same as the shaft.
*   The hook will have a "throat," a narrowed area immediately behind the hook itself.  The narrowing will go from the shaft down to the throat width.  The throat is not a cylinder, but is a kind of "flattened" shape that runs down from the main cylindrical part of the shaft. Let's use `throat_angle` to control the angle of the slope where the throat meets the shaft, and `narrowing_ratio` to control how much the sides of the shaft narrow in to create the throat.
*    There should be a section, `narrowing_slope` long, that slopes to the narrowed width.
*   I also need to control the location of the center of the curved hook.  Let's call the distance from the end of the shaft to the center of the hook `length_above_grip`. The rest of the overall `length` will be the handle below the center of the hook.

**Grip:**

*   The handle should have a thumb grip, which is a flat, raised section along the handle. This grip should be a flat section extruded upwards from the cylinder along the y-axis on either side.
*  The grip should have a length and thickness, which we will call `grip_length` and `grip_thickness`.
*   There should be a short sloping section, `grip_slope` long, from the cylinder to the raised thumb grip and back down to the cylinder again.
* The total width of the grip should not exceed the `diameter`, so the grip will be slightly flattened on the bottom and top.
*   The grip will be centered along the cylinder, a distance of `length_above_grip` away from the hook, which is where the center of the hook section will be placed.

**Parametric Control:**

*   All the dimensions should be controlled by variables at the top of the file. I need to be able to easily change the diameter of the hook, the length, the throat angle, the narrowing ratio, the grip length, grip thickness, grip slope, narrowing length, narrowing slope, hook length, and hook position relative to the grip.

**Output:**

*   The final output should be a single 3D model of the crochet hook.
* I also need to be able to use the `$fn` variable to control the level of detail of the curved sections. It doesn't need to be a parameter for the hook, but needs to be a global variable at the top that's easy to find.  I generally use $fn=30, but being able to change this will be helpful for generating fast previews.

I think that's everything.  Can you generate this for me?

I am not using any libraries, like BOSL, BOLTS, or MCAD, but if you see anything useful, please include it.  I want something I can drop into OpenSCAD, and it will render.

[Assistant]
crochet-hook2.scad:
```
/* [Overall size] */
// The diameter of the hook in mm - see http://www.karpstyles.com/crochet/hook-chart.html for US and UK sizes
diameter = 6;
d = diameter;
r = diameter/2;
length = 150; // [30:300]
/* [Hook and throat] */
// How sharply the throat slopes down from the shaft (in degrees)
throat_angle = 10;
hook_lower_angle = 90 - throat_angle;
// The length of the pointy curled-over bit
hook_length = 5;
// How long the narrowed section at the point is
narrowing_length = 10;
// How long the sloping section from shaft to narrowing is
narrowing_slope = 20;
// How much the throat narrows on each side, as a fraction of the diameter
narrowing_ratio = 0.25; //0.16;
narrowing_depth = d * narrowing_ratio;

echo("narrowing_depth=",narrowing_depth);
echo("throat width=", d - narrowing_depth*2);

/* [Thumb rest] */
// The length of the thumb rest
grip_length = 20;
// How long the sloping sections from shaft and handle to thumb rest are
grip_slope=5;
// How thick the thumb rest is, as a fraction of the diameter
grip_thickness = 0.6;
grip_depth=d * (1 - grip_thickness)/2;
// Distance from the centre-point of the thumb rest to the tip of the point
length_above_grip = 60;
// measured from the centre-point of the thumb rest to the end of the handle
length_below_grip = length - length_above_grip;
/* [Hidden] */
hook_upper_angle = 0;

$fn = 30;

// Right-angled triangle with interior angle <angle>.
module triangle(radius, angle)
{
  o=radius*sin(angle);
  a=radius*cos(angle);
  polygon(points=[[0,0], [a,0], [a,o]]);
}

// module triangle_prism() copied from:
// https://github.com/elmom/MCAD/blob/master/regular_shapes.scad
module triangle_prism(height, radius, angle)
{
  linear_extrude(height=height, center = true) triangle(radius, angle);
}

module trapezium_prism(trap_height, flat_width, slope_width, height)
{
  max_x = slope_width + flat_width/2;
  linear_extrude(height=height, center=true)
    polygon(points=[[-max_x, 0],
                    [-flat_width/2, trap_height],
                    [flat_width/2, trap_height],
                    [max_x, 0]]);
}

module grip_side()
{
	trapezium_prism(grip_depth, grip_length, grip_slope, d);
}

module grip()
{
        translate([0, r, 0])
                rotate(a=[0, 90, 180])
                        grip_side();
        translate([0, -r, 0])
                rotate(a=[0, 90, 0])
                        grip_side();
}

module narrowing_side()
{
	trapezium_prism(narrowing_depth, narrowing_length, narrowing_slope, d);
}

module narrowing()
{
        translate(v=[r, 0, length_above_grip])
                rotate(a=[-90, 90, 0])
                        narrowing_side();
        translate(v=[-r, 0, length_above_grip])
                rotate(a=[-90, 90, 180])
                        narrowing_side();
}

module outer_shell()
{
        union()
        {
                translate (v=[0, 0, length_above_grip])
                        scale([1.0, 1.0, 2.0])
                        sphere(r = r, anglesteps = 10, sweepsteps = 10);
                translate (v=[0, 0, -length_below_grip])
                        cylinder(r = r, h = length);
        }
}

module throat()
{
        translate (v= [0 , -r/4, length_above_grip])
                rotate(a=[270, 0, 90])
                difference() {
                        triangle_prism(d, 4*d, hook_lower_angle);
                        triangle_prism(d, 4*d, hook_upper_angle);
                }
}

module hook()
{
        intersection() {
                outer_shell();
                translate(v=[0, r, length_above_grip - hook_length])
                        cylinder(h=hook_length, r1=0, r2=r, center=false);
        }
}

rotate(a=[90, 0, 0]) {
  //intersection() {
        difference() {
                union() {
                        difference()
                        {
                                outer_shell();
                                throat();
                                grip();
                        }
                        hook();
                }
		// Narrow the head, for Greater Pointiness
                narrowing();
        }
        //color("red")
        *translate([-3/2, -d/2, -(length+20)/2 - 10])
        cube([3, d, (length+20)]);
    //  }
}

```


[User]
Okay, I need an OpenSCAD design for a V-slot cover, something like what I've already got in the example file "VslotCover_Cust.scad". The main features I want are:

1.  **Parametric Length:** I need to be able to specify the length of the cover.
2.  **Side Extension:**  I need a parameter to control an extension on one side of the cover. This would essentially be a flat, rectangular piece jutting out from the main body of the cover, and would be set to zero when not needed.
3.  **V-Slot Profile:** The cross-section of the cover needs to match a typical V-slot profile, with the internal void to snap into place. I'll need it to have all of the relevant dimensions: the bottom width, the different levels and widths going up (w1, w2, w3), and the top width with the little additional top-cover portion. I've specified all of that with the variables in my example file.
4.  **Wall Thickness:** The cover needs to have a consistent wall thickness, allowing a void inside so it can snap into the V-slot.
5.  **Top/Bottom Thickness:** The "floor" of the hollowed cover and the "roof" need to also have a controllable thickness (even though I am setting them to zero in my example).

I'd like it designed in such a way that it's easy to adjust all of the dimensions via parameters in OpenSCAD. Please make the design print-friendly. I'm assuming it will print upside-down with no supports. I'm thinking I'd like to use the `linear_extrude` module.

Also, I'm not using any external libraries currently, but if there are any common ones that would help simplify this I'm happy to start using them.

[Assistant]
VslotCover_Cust.scad:
```

length = 50; // [3:0.1:500]

// conver extension on one side
// leave it 0 (zero) if you don't need it
side_extension_width = 0; // [0:0.1:20]

/* HIDDEN */
side_add_w = side_extension_width;

$fn=1*60;

top2_w = 1*9.6;
top_w = 1*10; // 9.2 -v2> 9.6 -v3> 10
w1 = 1*8.4;
w2 = 1*6;
w3 = 1*7.4; // 8 -v2> 7.4
bottom_w = 1*5.8;

h1 = 1*4; // 3.8 -v4> 4.0
h2 = 1*2;
h3 = 1*1.2;
h_top_cover = 1*0.4;

wall_thick = 1*0.8; //
tb_thick = 1*0; // top-bottom thickness 0.8 -v3> 0.4 -v4> 0

// MAIN

rotate([-90,0,0])
linear_extrude(height = length) {
	difference() {
		polygon(points=[[-bottom_w/2, 0],
						[-w3/2, h3],
						[-w2/2, h2],
						[-w1/2, h1],
						[-top_w/2, h1],
						[-top2_w/2, h1 + h_top_cover],
						[top2_w/2 + side_add_w, h1 + h_top_cover],
						[top_w/2 + side_add_w, h1],
						[w1/2, h1],
						[w2/2, h2],
						[w3/2, h3],
						[bottom_w/2, 0]]);

		polygon(points=[[-bottom_w/2 + wall_thick, tb_thick],
						[-w3/2 + wall_thick, h3],
						[-w2/2 + wall_thick, h2],
						[-w1/2 + wall_thick, h1],
						[w1/2 - wall_thick, h1],
						[w2/2 - wall_thick, h2],
						[w3/2 - wall_thick, h3],
						[bottom_w/2 - wall_thick, tb_thick]]);
	}

}

```


[User]
Hi, I'm looking to get some OpenSCAD files generated for model rocket centering rings. I've been using the example file "Centering_ring.scad" as a starting point, and I like how it's structured using `difference()` to create the ring, but I need it to be more flexible and reusable.

Essentially, I need a parametric design that can handle various body tube and engine mount diameters. The current example uses specific diameters as variables, and I’d prefer to pass in body tube *inner* diameter, engine mount *outer* diameter, and ring thickness as parameters. I also want to specify an extra clearance value. For example, If my body tube inner diameter is 24.1mm and my engine mount outer diameter is 18mm I want to see a ring with a center hole just larger than the 18mm diameter and a ring outside diameter just smaller than 24.1mm diameter. I need to be able to specify the amount of extra space between the engine mount and the ring and between the ring and the body tube.

The example file also hardcodes the fact that the ring is centered. I also need to be able to specify if the ring should be centered or if I need to specify a non-centered z-position. I'd like that with another parameter for non-uniform centering if I specify the "center" variable as false.

Finally, I want to be able to specify the overall ring thickness via a parameter and have the code generate two rings of the given thickness, or N rings, if I supply an additional parameter which defaults to 1.

Could you generate an OpenSCAD file or set of files that handles this? I want to be able to easily change the ring dimensions, centering, the number of rings, and the clearance by changing variables. Thanks!

[Assistant]
Centering_ring.scad:
```
ring_inner_diameter = 13;
ring_outer_diameter = 18;
ring_thickness = 1;

difference(){
    cylinder(h=ring_thickness,r=ring_outer_diameter,center=true);
    cylinder(h=ring_thickness+2,r=ring_inner_diameter,center=true);
}
```


[User]
Hi, I'm looking to create a parametric maze generator in OpenSCAD, and I'd like it to be able to produce mazes suitable for use with a 7mm ball bearing. I've seen some maze generators online, but I'd like this one to be a bit different.

Specifically, I'd like the maze paths to be rounded and partially enclosed, kind of like a half-pipe, so the ball bearing can roll along them. I'd also like the option to create the maze in two halves, which can then be glued together to form a complete maze. The original example I was using did this with mirrored extrusions and I think that works well.

Here's a more detailed breakdown of what I'm looking for:

**Core Features:**

*   **Parametric Maze Dimensions:** I need to be able to set the number of rows and columns for the maze, as well as the overall block size and wall thickness.
*   **Rounded Path:** The maze paths should have rounded walls, kind of like a half-pipe shape, rather than sharp corners. This is to allow the ball bearing to roll smoothly. I think minkowski sums with a sphere would work for the path, and the base can be a simple linear extrusion. I also think the extrusion of the entire maze shape needs to be rounded for aesthetics, so the final edge of the maze should be rounded.
*   **Two-Part Construction:** The maze should be designed to be printed in two halves that can be glued together. This means we'll need mirrored generation for a top and bottom section.
*   **Ball Bearing Size:** The maze paths need to be sized correctly to accommodate a 7mm ball bearing. I'd prefer if the path were just a little bit bigger than 7mm in diameter, but have that value be parametric.
*   **Closed-ish walls:** The walls don't need to be fully closed over the ball-bearing paths - the top half and bottom half should combine to create a rounded path. The existing generator makes square path profiles, I need that to be a half-pipe profile.

**Parameters I'd like to control:**

*   `rows`: Number of rows in the maze.
*   `columns`: Number of columns in the maze.
*   `block_width`: Width of a single maze "block" or cell.
*   `wall_thickness`: Thickness of the maze walls.
*   `wall_height`: Height of the maze walls, or the extrusion height for the maze paths.
*   `base_thickness`: Thickness of the base on each half.
*   `ball_bearing_diameter`: Diameter of the ball bearing (default: 7mm).
*   `path_clearance`: Extra space around the ball bearing in the path (e.g., 0.5mm).
*   `fillet_radius`: Radius of the sphere used for the Minkowski sum for the maze walls, and for the overall shape's rounded edge.

**Bonus:**

*   It would be cool if you could include an optional parameter for adding side holes to the maze. Maybe something that sets the hole size and placement on a perimeter wall.

I'm not sure what libraries you'll need for this, but I believe `MCAD` might help with the rounding. I'm mainly concerned with the core features outlined. Can you help me generate this in OpenSCAD? Let me know if you need any clarification.

[Assistant]
maze_generator_with_base_mp.scad:
```
//random maze generator with back
//Mark G. Peeters added back and commnents 1-12-16
//http://www.thingiverse.com/thing:1264082
//Original work by JustinSDK
//https://www.thingiverse.com/thing:1185425
//preview[view:south, tilt:top]
//Y direction
rows = 7;
//x direction
columns = 7;

wall_thickness = 7;
wall_height = 8;
block_width = 8;
base_thickness=5;
fillet_radius = 3.5;

/*hidden*/
echo("maze size X=",columns*block_width+wall_thickness);
echo("maze size Y=",rows*block_width+wall_thickness);
echo("maze path width=",block_width-wall_thickness);

/*
 * constants, for clearness
 *
 */

// random directions, for picking up a direction to visit the next block
function PERMUTATION_OF_FOUR() = [
    [1, 2, 3, 4],
    [1, 2, 4, 3],
    [1, 3, 2, 4],
    [1, 3, 4, 2],
    [1, 4, 2, 3],
    [1, 4, 3, 2],
    [2, 1, 3, 4],
    [2, 1, 4, 3],
    [2, 3, 1, 4],
    [2, 3, 4, 1],
    [2, 4, 1, 3],
    [2, 4, 3, 1],
    [3, 1, 2, 4],
    [3, 1, 4, 2],
    [3, 2, 1, 4],
    [3, 2, 4, 1],
    [3, 4, 1, 2],
    [3, 4, 2, 1],
    [4, 1, 2, 3],
    [4, 1, 3, 2],
    [4, 2, 1, 3],
    [4, 2, 3, 1],
    [4, 3, 1, 2],
    [4, 3, 2, 1]
];

function NO_WALL() = 0;
function UP_WALL() = 1;
function RIGHT_WALL() = 2;
function UP_RIGHT_WALL() = 3;

function NOT_VISITED() = 0;
function VISITED() = 1;

/*
 * modules for creating a maze
 *
 */

// give a [x, y] point and length. draw a line in the x direction
module x_line(point, length, thickness = 1) {
    offset = thickness / 2;
    translate([point[0] - offset, point[1] - offset, 0])
        square([length + thickness, thickness]);
}

// give a [x, y] point and length. draw a line in the y direction
module y_line(point, length, thickness = 1) {
    offset = thickness / 2;
    translate([point[0] - offset, point[1] - offset, 0])
        square([thickness, length + thickness]);
}

// create the outer wall of maze
module maze_outer_wall(rows, columns, block_width = 5, wall_thickness = 1) {
    x_line([0, rows * block_width], columns * block_width, wall_thickness);
    y_line([rows * block_width, 0], columns * block_width, wall_thickness);
    y_line([0, 0], (rows - 1) * block_width, wall_thickness);
    y_line([0, block_width], (rows - 1) * block_width, wall_thickness);
}

// create the inner wall of maze
module maze_inner_wall(maze, block_width = 5, wall_thickness = 1) {
    for(i = [0:len(maze) - 1]) {
        cord = maze[i];
        x = (cord[0] - 1) * block_width;
        y = (cord[1] - 1) * block_width;
        v = cord[3];

        if(v == 1 || v == 3) {
            x_line([x, y], block_width, wall_thickness);
        }
        if(v == 2 || v == 3) {
            y_line([x + block_width, y], block_width, wall_thickness);
        }
    }
}

// create a maze
module maze(rows, columns, maze_vector, block_width = 5, wall_thickness = 1) {
     maze_outer_wall(rows, columns, block_width, wall_thickness);
     maze_inner_wall(maze_vector, block_width, wall_thickness);
}

/*
 * utilities functions
 *
 */

// comare the equality of [x1, y1] and [x2, y2]
function cord_equals(cord1, cord2) = cord1 == cord2;

// is the point visited?
function not_visited(cord, vs, index = 0) =
    index == len(vs) ? true :
        (cord_equals([vs[index][0], vs[index][1]], cord) && vs[index][2] == 1 ? false :
            not_visited(cord, vs, index + 1));

// pick a direction randomly
function rand_dirs() =
    PERMUTATION_OF_FOUR()[round(rands(0, 24, 1)[0])];

// give a index (exclusivly), slice a vector
function head_to(i, vs) =
    i >= len(vs) ? vs : (
        i == 0 ? [] : concat(head_to(i - 1, vs), [vs[i - 1]])
    );

// give a index (exclusivly), slice a vector
function tail_from(i, vs, index = 0, new_vs = []) =
    i >= len(vs) ? [] : (
        index < i ? tail_from(i, vs, index + 1) : (
            index < len(vs) ? tail_from(i, vs, index + 1, concat(new_vs, [vs[index]])) : new_vs
        )
    );

// replace v1 in the vector with v2
function replace(v1, v2, vs, index = 0) =
    index == len(vs) ? vs : (
        vs[index] == v1 ? concat(concat(head_to(index, vs), [v2]), tail_from(index + 1, vs)) : replace(v1, v2, vs, index + 1)
    );

/*
 * functions for generating a maze vector
 *
 */

// initialize rows of a maze
function init_row(n, length) =
    length == 0 ? [] : concat(init_row(n, length - 1), [[length, n, 0, UP_RIGHT_WALL()]]);

// initialize a maze
function init_maze(rows, columns) =
    rows == 0 ? [] : concat(init_maze(rows - 1, columns), init_row(rows, columns));

// find a vector in the maze vector
function find(i, j, maze_vector, index = 0) =
    index == len(maze_vector) ? [] : (
        cord_equals([i, j], [maze_vector[index][0], maze_vector[index][1]]) ? maze_vector[index] : find(i, j, maze_vector, index + 1)
    );

////
// NO_WALL = 0;
// UP_WALL = 1;
// RIGHT_WALL = 2;
// UP_RIGHT_WALL = 3;
function delete_right_wall(original_block) =
    original_block == NO_WALL() || original_block == RIGHT_WALL() ? NO_WALL() : UP_WALL();

function delete_up_wall(original_block) =
    (original_block == NO_WALL() || original_block == UP_WALL()) ? NO_WALL() : RIGHT_WALL();

function delete_right_wall_of(vs, is_visited, maze_vector) =
    replace(vs, [vs[0], vs[1] , is_visited, delete_right_wall(vs[3])] ,maze_vector);

function delete_up_wall_of(vs, is_visited, maze_vector) =
    replace(vs, [vs[0], vs[1] , is_visited, delete_up_wall(vs[3])] ,maze_vector);

function go_right(i, j, rows, columns, maze_vector) =
    go_maze(i + 1, j, rows, columns, delete_right_wall_of(find(i, j, maze_vector), VISITED(), maze_vector));

function go_up(i, j, rows, columns, maze_vector) =
    go_maze(i, j - 1, rows, columns, delete_up_wall_of(find(i, j, maze_vector), VISITED(), maze_vector));

function visit(v, maze_vector) =
    replace(v, [v[0], v[1], VISITED(), v[3]], maze_vector);

function go_left(i, j, rows, columns, maze_vector) =
    go_maze(i - 1, j, rows, columns, delete_right_wall_of(find(i - 1, j, maze_vector), NOT_VISITED(), maze_vector));

function go_down(i, j, rows, columns, maze_vector) =
    go_maze(i, j + 1, rows, columns, delete_up_wall_of(find(i, j + 1, maze_vector), NOT_VISITED(), maze_vector));

function go_maze(i, j, rows, columns, maze_vector) =
    look_around(i, j, rand_dirs(), rows, columns, visit(find(i, j, maze_vector), maze_vector));

function look_around(i, j, dirs, rows, columns, maze_vector, index = 0) =
    index == 4 ? maze_vector :
        look_around(
            i, j, dirs,
            rows, columns,
            build_wall(i, j, dirs[index], rows, columns, maze_vector),
            index + 1
        );

function build_wall(i, j, n, rows, columns, maze_vector) =
    n == 1 && i != columns && not_visited([i + 1, j], maze_vector) ? go_right(i, j, rows, columns, maze_vector) : (
        n == 2 && j != 1 && not_visited([i, j - 1], maze_vector) ? go_up(i, j, rows, columns, maze_vector)  : (
            n == 3 && i != 1 && not_visited([i - 1, j], maze_vector) ? go_left(i, j,rows, columns,  maze_vector)  : (
                n == 4 && j != rows && not_visited([i, j + 1], maze_vector) ? go_down(i, j, rows, columns, maze_vector) : maze_vector
            )
        )
    );

module maze_half(rows, columns, maze_vector, block_width = 5, wall_thickness = 1) {

    difference() {
    /*

        union() {
            linear_extrude(wall_height)
            maze(rows, columns, maze_vector, block_width, wall_thickness);
            translate([-wall_thickness/2,-wall_thickness/2,0])
            cube([
                columns*block_width+wall_thickness,
                rows*block_width+wall_thickness,
                base_thickness
            ]);
        }

    */
        difference() {
            translate([-wall_thickness/2,-wall_thickness/2,0])
            cube([
                columns*block_width+wall_thickness,
                rows*block_width+wall_thickness,
                wall_height+(fillet_radius*0.95)
            ]);
            minkowski() {
                difference() {
                    translate([-wall_thickness/2,-wall_thickness/2,0])
                    cube([
                        columns*block_width+wall_thickness,
                        rows*block_width+wall_thickness,
                        wall_height
                    ]);
                    union() {
                        linear_extrude(wall_height)
                        maze(rows, columns, maze_vector, block_width, wall_thickness);
                        translate([-wall_thickness/2,-wall_thickness/2,0])
                        cube([
                            columns*block_width+wall_thickness,
                            rows*block_width+wall_thickness,
                            base_thickness
                        ]);
                    }
                };
                sphere(r=fillet_radius, $fa=15, $fs=0.1);
            };
        };

        translate([wall_thickness/2,wall_thickness/2,-wall_height/2])
            cylinder(h=wall_height, r=fillet_radius, $fa=15, $fs=0.1);
        translate([(columns-1)*block_width+wall_thickness/2,(rows-1)*block_width+wall_thickness/2,-wall_height/2])
            cylinder(h=wall_height, r=fillet_radius, $fa=15, $fs=0.1);
    }
}

union() {
    maze_half(rows, columns,
        go_maze(
            1,
            1,
            rows,
            columns,
            replace(
                [columns, rows, 0, UP_RIGHT_WALL()],
                [columns, rows, 0, UP_WALL()],
                init_maze(rows, columns)
            )
        ),
        block_width,
        wall_thickness);
    scale([1,1,-1]) translate([0,0,0.1])
    maze_half(rows, columns,
        go_maze(
            1,
            1,
            rows,
            columns,
            replace(
                [columns, rows, 0, UP_RIGHT_WALL()],
                [columns, rows, 0, UP_WALL()],
                init_maze(rows, columns)
            )
        ),
        block_width,
        wall_thickness);

}
```


[User]
Hey, I'm looking to design a parametric ball bearing in OpenSCAD, specifically for a filament spool adapter. I've got some parameters I'd like to be able to adjust, and I'd like the design to be printable.

The basic idea is this: I need an inner part that will have a hole through the center and an outer part that will fit around it, with ball bearings between the two. I need to be able to adjust the following:

*   **Inner Diameter (INNER_DIA):** The diameter of the hole in the center of the inner part.
*   **Inner Width (INNER_WIDTH):** The width of the inner part.
*   **Outer Diameter (OUTER_DIA):** The outer diameter of the outer part.
*  **Outer Width (OUTER_WIDTH):** The width of the outer part.
*   **Ball Diameter (BALL_DIA):** The diameter of the ball bearings.
*   **Ball Gap (BALL_GAP):** The extra space around each ball. This is important for fit.
*   **Cap Diameter (CAP_DIA):** The diameter of the stop cap on the wider part (either inner or outer, depending on which is wider).
*   **Cap Width (CAP_WIDTH):** The width of the stop cap.
*   **Cap Gap (CAP_GAP):** The gap between the stop cap and the counter part.
*   **Spike Diameter (SPIKE_DIA):** The diameter of the spikes on the outer part.
*  **Spike Count (SPIKE_CNT):** The number of spikes on the outer part.
*   **Spike Width (SPIKE_WIDTH):** The width of the spikes on the outer part.
*   **Precision (PRESISION):** The precision of the drawing operations, basically the `$fn` value.

I'd like to be able to render just the inner part, just the outer part, or both together (with an optional separation between them). So there should be a parameter for the `PART` which can be set to `"inner"`, `"outer"`, or `"both"`.  I also need a `SEPARATE` parameter which controls how much the two parts are separated when both are shown.  It should default to a negative value, like -30.

I'm not looking for anything too complex in terms of the rendering. Just basic cylinders and the ability to cut out a path for the balls using `rotate_extrude` with circles. I don't need any external libraries to be included in this design. Can you generate the code for this? Thanks!

[Assistant]
ball.bearing-printable-0.13.scad:
```
/*
 * Copyright (C) 2019 by Amir Guindehi <amir@datacore.ch>
 */

// The part to render
PART="both"; // [inner, outer, both]
// The diameter of the hole in the inner part
INNER_DIA=32.4;
// The width of the inner part
INNER_WIDTH=20;
// The diameter of the ring of the outer part
OUTER_DIA=50.1;
// The width of the outer part
OUTER_WIDTH=16;
// The diameter of the balls
BALL_DIA=6;
// The extra gap for the balls
BALL_GAP=0.16;
// The diameter of the stop cap on the wider part
CAP_DIA=45;
// The width of the stop cap on the wider part
CAP_WIDTH=1.4;
// The gap between the stop cap and the counter part
CAP_GAP=0.8;
// The diameter of the spikes on the outer part
SPIKE_DIA=5;
// The number of the spikes on the outer part
SPIKE_CNT=6;
// The width of the spikes on the outer part
SPIKE_WIDTH=2;
// The precision of the drawing operations
PRESISION=256;

/* [Hidden] */
SEPARATE=-30;

 module cylinder_outer(d,h,fn,center=false) {
    fudge = 1 / cos(180 / fn);
    cylinder(d=d*fudge,h=h,center=center,$fn=fn);
}

module circle_outer(d,fn) {
    fudge = 1/cos( 180 / fn);
    circle(d=d*fudge,$fn=fn);
}

module ballbearing(part="both", inner_dia, inner_width, outer_dia, outer_width, spike_dia, spike_width, spike_cnt, cap_dia, cap_width, cap_gap, ball_dia, gap=0.2, separate=-4, precision=32) {
    a = 2 * asin(ball_dia/((inner_dia+outer_dia)/2));
    b = round(360 / a);
    count = round(360 / b);
    width=max(inner_width,outer_width);

    echo("Needed balls with diameter ball_dia: ", count);

    $fn=precision;
    translate([0,0,(part=="both")?-separate/2:0])
        union() {
            if ((part == "outer") || (part == "both")) {
                difference() {
                    union() {
                        difference() {
                            // outer part body
                            cylinder(d=outer_dia,h=outer_width,center=true);
                            // make hole
                            cylinder_outer((outer_dia+inner_dia+ball_dia)/2,outer_width,precision,center=true);
                            // remove ball path
                            rotate_extrude()
                                translate([(inner_dia+outer_dia)/4, 0, 0])
                                    circle_outer(ball_dia+2*gap,precision);
                        }
                        if (outer_width >= inner_width) {
                            // outer part stop ring
                            translate([0,0,outer_width/2]) {
                                difference() {
                                    cylinder(d=outer_dia,h=cap_width);
                                    cylinder_outer(cap_dia,cap_width,precision);
                                }
                            }
                        }
                        // outer spikes
                        for(i=[0:1:spike_cnt-1]) {
                            rotate([0,0,round(360/spike_cnt*i)])
                                translate([0,outer_dia/2,-outer_width/2])
                                    cylinder(d=spike_dia,h=spike_width);
                        }
                    }
                    // create insert slit
                    translate([(inner_dia+outer_dia)/4,0,0])
                        cylinder_outer(ball_dia+2*gap,width/2,precision);
                }
            }
            if ((part == "inner") || (part == "both")) {
                // translate to origin if showing inner alone
                translate([0,0,(part=="both")?separate:0]) {
                    difference() {
                        union() {
                            difference() {
                                // inner part body
                                cylinder(d=(outer_dia+inner_dia-ball_dia)/2,h=inner_width,center=true);
                                // make hole
                                cylinder_outer(inner_dia,inner_width,precision,center=true);
                                // remove ball path
                                rotate_extrude()
                                    translate([(inner_dia+outer_dia)/4, 0, 0])
                                        circle_outer(ball_dia+2*gap,precision);
                            }
                            if (inner_width >= outer_width) {
                                // inner part stop ring
                                translate([0,0,-inner_width/2-cap_gap]) {
                                    difference() {
                                        cylinder(d=cap_dia,h=cap_width);
                                        cylinder_outer(inner_dia,cap_width,precision);
                                    }
                                }
                            }
                        }
                        // create insert slit
                        translate([(inner_dia+outer_dia)/4,0,0])
                            cylinder_outer(ball_dia+2*gap,width/2,precision);
                    }
                }
            }
        }

}

ballbearing(PART, INNER_DIA, INNER_WIDTH, OUTER_DIA, OUTER_WIDTH, SPIKE_DIA, SPIKE_WIDTH, SPIKE_CNT, CAP_DIA, CAP_WIDTH, CAP_GAP, BALL_DIA, BALL_GAP, SEPARATE, PRESISION);
```


[User]
I'd like to design a parametric, stackable tray for small parts, similar to the one I described in the `part_tray.scad` file I'm about to give you. I want it to be customizable in terms of the number of rows and columns, the height of the cells, and whether the floor of the cells are rounded or flat. I also want options for adding joints for stacking and adding edges to keep square notes inside the compartments.

Here are the specific features and parameters I need:

*   **Cell Height:**  A parameter to control the inner height of the cells (e.g., `height`). This will be adjustable and should be in the range of 2 to 128.
*   **Rows & Columns:** Parameters for the number of rows (`rows`) and columns (`columns`). Should be integers between 1 and 8.
*   **Inner Edge Radius:** A parameter (`radius`) to round off the inner edges of each cell. Allow for values between 0 and 8.
*   **Stacking Joints:** An option (`addJoint`) to add interlocking joints on the edges for stacking. This will be a boolean option, 0 for no and 1 for yes. When enabled, the joints should have a specific thickness, width, and height I can parameterize (perhaps `jt`, `jw`, `jh`).
*   **Rounded Floor:** A boolean option (`roundFloor`) to control whether the bottom of the cells are rounded (0 or 1). If true, a sphere segment should be used to create the rounded floor.
*   **Edges for Square Notes:** A boolean option (`addEdges`) to add small, raised corners to help keep square notes in place. Also 0 or 1.
*   **Internal Dimensions:** The compartments should be sized to hold a Raspberry Pi and also 3.5 inch square sticky notes, which is about a 90mm internal compartment. There should be some wall thickness (`wt`) between the compartments, and a total floor length of around 92mm.
*   **Tolerances:** I need a way to specify tolerance (`tl`) in the joints, so that it is easy to stack.

I also need the design to be able to be used upside down as a lid.

I don't need any particular libraries for this, just the core OpenSCAD language. Let me know if you have any questions!

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

/* [Main Settings] */
// The Inner Height of the Cells
height=4;  // [2,3,4,6,8,12,16,24,32,48,64,96,128]

// Number of Rows
rows=2;   // [1:8]

// Number of Columns
columns=2;   // [1:8]

// Radius Used to Round Off Inner Edges
radius=2;  // [0:8]

/* [Enable Features] */
// Add Joints to the Next Tray
addJoint=1; // [0:No, 1:Yes]

// Round the Floor of the Cells
roundFloor=1; // [0:No, 1:Yes]

// Add Corners to Keep Square Notes
addEdges=0; // [0:No, 1:Yes]

/* [Hidden] */
fl=92; // floor length
wt=1;  // wall thickness
jt=2;  // joint thickness
jw=20; // joint width
jh=3;  // joint height
tl=0.1; // toleranz
el=8;  // edge length

ih=height;
n=rows;
m=columns;
rr=radius+0.001;
ro=fl/2-rr;
ri=fl/2+wt/2;
$fn=16;

module joint(y, a, t) {
    rotate(a)
        translate([fl/2+wt+jt/2+t,y,(jh+wt+ih)/2-0.001])
            cube([jt-2*t,jw-2*t,jh+wt+ih+0.002],center=true);
}

module rounding_inner()
    if (roundFloor) translate([0,0,rr+wt]) {
        sphere(r=rr);
        cylinder(r=rr, h=ih-rr+0.001);
    } else translate([0,0,wt])
        cylinder(r=rr, h=ih+0.001);

module rounding_outer() {
    cylinder(r=rr+wt+jt-0.001, h=ih+wt);
}

difference() {
    union() {
        difference() {
            hull() for (x=[-1:2:1]) for (y=[-1:2:1])
                translate([x*ro,y*ro,0]) rounding_outer();
            for (x=[0:n-1]) for (y=[0:m-1])
                hull() for (i=[0:1]) for (j=[0:1])
                    translate([-ri+2*ri*(x+i)/n + (1-2*i)*(wt/2+rr), -ri+2*ri*(y+j)/m + (1-2*j)*(wt/2+rr),0])
                        rounding_inner();
        }
        if (addJoint) {
            joint(0, 0, tl);
            joint(jw, 90, tl);
            joint(-jw, 90, tl);
            joint(0, 180, tl);
            joint(jw, 270, tl);
            joint(-jw, 270, tl);
        }
        if (addEdges) translate([0,0,ih]) linear_extrude(height=wt)
            for (x=[-1:2:1]) for (y=[-1:2:1])
                polygon([[x*fl/2,y*fl/2],[x*fl/2,y*(fl/2-el)],[x*(fl/2-el),y*fl/2]]);
    }
    joint(jw, 0, -tl);
    joint(-jw, 0, -tl);
    joint(0, 90, -tl);
    joint(jw, 180, -tl);
    joint(-jw, 180, -tl);
    joint(0, 270, -tl);
}

```


[User]
I'm looking for an OpenSCAD design for a customizable banana plug cable organizer, and I've got some specific requirements in mind. I've seen a couple of designs that get close but I need to be able to tweak a few things.

First, I need to be able to control the number of horizontal and vertical pegs that hold the cables. I'd like to specify those with parameters called `NumHorizontal` and `NumVertical`, with `NumHorizontal` having a reasonable range of 1 to 30 and `NumVertical` ranging from 1 to 20, where the vertical should be incremented by 2 in the user interface.

The distance between the pegs should also be a parameter, let's call it `Distance`, with a range of 13 to 30. I'll need to adjust the peg geometry as well, so let's make the inner and outer diameters of both the small and large walls of the pegs customizable. These should be `SmallWallInner` (3.5 to 5.5), `SmallWallOuter` (5.0 to 7.0), `BigWallInner` (8.5 to 10.0) and `BigWallOuter` (10.5 to 13.0).

The whole thing will need a base plate. Let's define the thickness of this plate with `Thiccness`, ranging from 1 to 5. The peg height will be defined by `WallHeight` which should range from 5 to 20.

I also need to put in some screw holes for mounting, and these should also have a customizable diameter, which we'll call `ScrewHoleDia` and give it a range from 1 to 6. I'd also like a parameter, a yes/no toggle, to determine if these holes should be chamfered, called `ChamferHoles`.

For the baseplate, I want to have some extra space on the sides for mounting, so add `Framelength` as a parameter, and set that to 20, but we don't need to be able to change that through the customizer.

One of the designs I saw had alternating peg rows, I don't think I want that for this design, so we should just keep them all lined up. Also, the peg design I want will have chamfers on both sides of the inner and outer walls.

I think that should cover it. I'd like to have the code generated as a single OpenSCAD file, and please make sure to use the `minkowski()` function and `circle()` to draw the baseplate instead of a simple `square()` or `cube()`. Also, add comments that make the code easy to read and understand, I may want to modify it in the future.

[Assistant]
BananaHolderNew.scad:
```
//Number of horizontal pegs
NumHorizontal = 5; 	//[1:30]
//Number of vertical pegs
NumVertical = 2;		//[2:2:20]
//Distance between pegs
Distance = 17;			//[13:30]
ScrewHoleDia = 4;		//[1:0.1:6]
//Height of the ground plate
Thiccness = 3;			//[1:0.1:5]
//Height of the pegs
WallHeight = 15;		//[5:0.1:20]
//Should the screw holes be chamfered?
ChamferHoles = "Yes";	//[Yes, No]

//Inner diameter of the small wall, smaller is tighter
SmallWallInner = 4.4;	//[3.5:0.1:5.5]
//Outer diameter of the small wall, bigger is tighter
SmallWallOuter = 5.8;	//[5.0:0.1:7.0]
//Inner diameter of the big wall, smaller is tighter
BigWallInner = 9.2;		//[8.5:0.1:10.0]
//Outer diameter of the big wall, is just for stability
BigWallOuter = 10.5;	//[10.5:0.1:13.0]

/*MyValues

SmallWallInner = 4.4+0;
SmallWallOuter = 5.8+0;
BigWallInner = 9.2+0;
BigWallOuter = 10.5+0;
*/

//Fixed Resolution
$fa=6+0;
$fs=0.4+0;
//Fixed Variables
Framelength = 20+0;

//Prototypes

//Draw the Pegs depending on selected number of vertical/horizontal Num variables
//The for loop uses i and j as multipliers in the translation while drawing the pegs
for(j = [0 : NumVertical-1]){

		for(i = [0 : NumHorizontal-1]){
			if (j%2==0) {
				translate([((Distance*i)), (Distance)*j, 0]) peg();
			} else {
				translate([((Distance*i)+Distance/2), (Distance)*j, 0]) peg();
			}
		}

}

//Plate with Screwholes
difference(){
	translate([-(Distance+Framelength)/2, -(Distance/2), -Thiccness]){
		linear_extrude(Thiccness){
			minkowski() {
				circle(3);
				//Plate

					square([Distance*NumHorizontal+Framelength+Distance/2, Distance*NumVertical]);
					//cube([Distance*NumHorizontal+Framelength+Distance/2, Distance*NumVertical, Thiccness]);
			}
		}
	}
	//Screwholes
	//If more than one vertical peg is drawn we put a screwhole in each corner
	if (NumVertical > 1){
		translate([(-(Distance+Framelength)/2)+Framelength/3-3,
			-(Distance/2)+Framelength/3-3,
			-Thiccness-0.1])
				drill();
		translate([(-(Distance+Framelength)/2)+Framelength/3-3,
			(Distance*(NumVertical-1)+Distance*0.5)-Framelength/3+3,
			-Thiccness-0.1])
				drill();
		translate([(Distance*(NumHorizontal-1)+(Distance+Framelength)/2)-Framelength/3+Distance/2+3,
			-(Distance/2)+Framelength/3-3,
			-Thiccness-0.1])
				drill();
		translate([(Distance*(NumHorizontal-1)+(Distance+Framelength)/2)-Framelength/3+Distance/2+3,
			(Distance*(NumVertical-1)+Distance*0.5)-Framelength/3+3,
			-Thiccness-0.1])
				drill();
	//if only one vertical peg is drawn we only need a single screwhole on each side
	} else {
		translate([(-(Distance+Framelength)/2)+Framelength/3,
			0,
			-Thiccness-0.1])
				drill();
		translate([(Distance*(NumHorizontal-1)+(Distance+Framelength)/2)-Framelength/3,
			0,
			-Thiccness-0.1])
				drill();
			}
		}

//Modules
module peg() {
	//Inner Wall
	difference(){
		cylinder(h=WallHeight, d=SmallWallOuter);
		cylinder(h=100, d=SmallWallInner, center=true);
	}
	//Outer Wall
	difference(){
		cylinder(h=WallHeight, d=BigWallOuter);
		cylinder(h=100, d=BigWallInner, center=true);
	}
	//innermost chamfer
	rotate([180,0,0]) {
		rotate_extrude(){
			translate([SmallWallInner/2,0,0]) {
				chamferpiece(3);
			}
		}
	}
	//outermost chamfer
	rotate([180,0,0]) {
		rotate_extrude(){
			translate([BigWallOuter/2,0,0]) {
				rotate([0,180,0]){
					chamferpiece(5);
				}
			}
		}
	}
}

module drill(){
	if(ChamferHoles == "Yes"){
	cylinder(h=Thiccness+0.2, d1=ScrewHoleDia, d2=(ScrewHoleDia+2*tan(45)*Thiccness+0.2));
	} else {
		cylinder(h=Thiccness+0.5, d=ScrewHoleDia);
	}
}

module chamferpiece(Size) {
	rotate([0,0,0]) {
		translate([-Size/2, -Size/2, 0]) {
			intersection() {
				difference() {
					square([Size,Size], center=true);
					circle(Size/2, center=true);
				}
				square([Size,Size]);
			}
		}
	}
}

```
BananaHolderV3.scad:
```
//Number of horizontal pegs
NumHorizontal = 10; 	//[1:30]
//Number of vertical pegs
NumVertical = 2;		//[1:30]
//Distance between pegs
Distance = 13;			//[13:30]
ScrewHoleDia = 4;		//[1:0.1:6]
//Height of the ground plate
Thiccness = 2;			//[1:0.1:5]
//Height of the pegs
WallHeight = 15;		//[5:0.1:20]
//Should the screw holes be chamfered?
ChamferHoles = "Yes";	//[Yes, No]

//Inner diameter of the small wall, smaller is tighter
SmallWallInner = 4.4;	//[3.5:0.1:5.5]
//Outer diameter of the small wall, bigger is thighter
SmallWallOuter = 5.8;	//[5.0:0.1:7.0]
//Inner diameter of the big wall, smaller is tighter
BigWallInner = 9.2;		//[8.5:0.1:10.0]
//Outer diameter of the big wall, is just for stability
BigWallOuter = 10.5;	//[10.5:0.1:13.0]

/*MyValues

SmallWallInner = 4.4+0;
SmallWallOuter = 5.8+0;
BigWallInner = 9.2+0;
BigWallOuter = 10.5+0;
*/

//Fixed Resolution
$fa=5+0;
$fs=0.5+0;
//Fixed Variables
Framelength = 20+0;

//Draw the Pegs depending on selected number of vertical/horizontal Num variables
//The for loop uses i and j as multipliers in the translation while drawing the pegs
for(j = [0 : NumVertical-1]){
	for(i = [0 : NumHorizontal-1]){
		translate([Distance*i, Distance*j, 0]) peg();
	}
}

//Plate with Screwholes
difference(){
	//Plate
	translate([-(Distance+Framelength)/2, -(Distance/2), -Thiccness])
		cube([Distance*NumHorizontal+Framelength, Distance*NumVertical, Thiccness]);

	//Screwholes
	//If more than one vertical peg is drawn we put a screwhole in each corner
	if (NumVertical > 1){
		translate([(-(Distance+Framelength)/2)+Framelength/3,
			-(Distance/2)+Framelength/3,
			-Thiccness-0.1])
				drill();
		translate([(-(Distance+Framelength)/2)+Framelength/3,
			(Distance*(NumVertical-1)+Distance*0.5)-Framelength/3,
			-Thiccness-0.1])
				drill();
		translate([(Distance*(NumHorizontal-1)+(Distance+Framelength)/2)-Framelength/3,
			-(Distance/2)+Framelength/3,
			-Thiccness-0.1])
				drill();
		translate([(Distance*(NumHorizontal-1)+(Distance+Framelength)/2)-Framelength/3,
			(Distance*(NumVertical-1)+Distance*0.5)-Framelength/3,
			-Thiccness-0.1])
				drill();
	//if only one vertical peg is drawn we only need a single screwhole on each side
	} else {
		translate([(-(Distance+Framelength)/2)+Framelength/3,
			0,
			-Thiccness-0.1])
				drill();
		translate([(Distance*(NumHorizontal-1)+(Distance+Framelength)/2)-Framelength/3,
			0,
			-Thiccness-0.1])
				drill();
			}
		}
//Modules
module peg() {
	//Inner Wall
	difference(){
		cylinder(h=WallHeight, d=SmallWallOuter);
		cylinder(h=100, d=SmallWallInner, center=true);
	}
	//Outer Wall
	difference(){
		cylinder(h=WallHeight, d=BigWallOuter);
		cylinder(h=100, d=BigWallInner, center=true);
	}
}

module drill(){
	if(ChamferHoles == "Yes"){
	cylinder(h=Thiccness+0.2, d1=ScrewHoleDia, d2=(ScrewHoleDia+2*tan(45)*Thiccness+0.2));
	} else {
		cylinder(h=Thiccness+0.2, d=ScrewHoleDia);
	}
}

```


[User]
Okay, I need a parametric OpenSCAD design for a router support foot, similar to the one I saw on Thingiverse, but I'd like it to be more configurable. I'll be using this with a Makita RT0700 router, but ideally it would be adaptable for other routers as well.

Here's the breakdown of what I'm looking for:

**Overall Structure:**

The support foot should consist of three main parts: a foot that slides into the router's guide holder, a base that extends beyond the foot to provide stability, and a shoe that rests on the surface being routed.

**Foot:**

*   It needs to fit into the Makita RT0700's guide holder opening. I need to be able to set the width (w) and length (l) of this main foot part.
*   The foot should have a wall thickness (thn), which I also need to control.
*   It should have a countersunk screw hole for attaching it to the guide holder. This hole needs to be parametrically defined by the screw diameter (d_screw) and the screw head diameter (d_screw_head). It should also have a definable screw head thickness (thn_head). I need to be able to set these independently, as I might be using different types of screws (e.g., a hex screw or the Makita lock screw).
*   The screw hole should be centered along the width of the foot and have a given offset from the front edge.

**Base:**

*   The base is an extension to the foot, acting as a stabiliser.
*   I need the base to be a rounded triangular shape, extending away from the main foot.
*   The width of the base needs to conform to the width of the foot (w), but have an extra definable thickness (d_base), extending out to the left and right.
*   I would also like the ability to define how far it extends below the foot itself (d_base).
*   The thickness of the base should also be parametric (also d_base).

**Shoe:**

*   The shoe is the part that makes contact with the material being routed.
*   It should have a definable length (l_shoe) and thickness (thn_shoe).
*   It should be attached to the foot, and have the ability to be offset from the foot by a definable thickness (thn * 2) when extruding.
*   The shoe should extend both in front of and behind the main foot by an equal amount, and it should have angled ends at both sides.

**Parameters:**

I'd like all of the following to be configurable parameters:

*   `w` (width of foot/guide holder opening)
*   `l` (length of foot)
*   `thn` (foot wall thickness)
*   `d_screw` (screw diameter)
*   `d_screw_head` (screw head diameter)
*   `thn_head` (screw head thickness)
*   `l_shoe` (length of shoe)
*   `thn_shoe` (shoe thickness)
*   `d_base` (thickness of the stabilizer, and amount base extends from the bottom of the main foot)

**Libraries**

I'm not expecting any external libraries for this project.

Could you please generate the OpenSCAD file for this design? I would appreciate if all parameters were included as variables at the beginning of the file, and the code was structured logically, as it will help me understand it. Also, I would appreciate some comments in the code too, where it makes sense.

[Assistant]
Makita_Router_Support_Foot.scad:
```
//
// Design by: MrFuzzy
// License: CC BY-NC 3.0
// Router support foot
//  - Fits into guide holder of Makita RT0700 router
//  - Can be used with adapter for other routers (and brands)
//

// width of foot / guide holder opening
w = 25;

// length of foot
l = 70;

// foot: wall thickness
thn = 8;

// screw diameter: added 0.4 to adjust for printer cut-out precision. Adjust to cut-out precision of your printer
d_screw = 6.4;

// screw head diameter: 10mm (hex head), 12mm (Makita lock screw). Added 0.4 to adjust for printer cut-out precision. Set according to precision of your printe
d_screw_head = 12.4;

// thickness of screw head
thn_head = 4;

// length of shoe
l_shoe = 100;

// shoe thickness
thn_shoe = 5;

foot();
foot_base();
shoe();

module foot() {
    difference() {
        cube([l, w, thn]);

        translate([10, w/2-d_screw/2, 0])
            cube([l-20, d_screw, thn]);

        translate([10-d_screw_head/2, w/2-d_screw_head/2, 0])
            cube([l-20+d_screw_head, d_screw_head, thn_head]);

    }
}

module foot_base() {

    d_base = thn * 0.5;
    translate([l+1,-d_base,0])
    mirror([1,0,0]) {
        hull() {
            cube([1, w+d_base*2,thn+d_base]);
            translate([0,d_base,0])
                cube([d_base,w,thn]);
        }
    }
}

module shoe() {
    translate([0, w/2, 0])
    linear_extrude(thn*2)
    polygon(points = [[l, -l_shoe/2], [l, l_shoe/2],
                      [l+thn_shoe, l_shoe/2-thn_shoe], [l+thn_shoe, -l_shoe/2+thn_shoe]]);
}

```


[User]
I'm looking to design some custom handle scales for a cheap knife I picked up. I've got the basic measurements, and a rough idea of what I want, but I need help with the OpenSCAD code. The scales will be attached with M3 hex-head screws and knurled nuts.

Here's the breakdown:

*   **Overall Shape:** The scales should have a relatively ergonomic, curved shape. I'm not aiming for anything too fancy, but definitely not just a straight block. The included code has a `shapePoints` variable defining the profile of one side of the handle. It's a little complex, but it seems like it's just a series of X and Y coordinates. I need to mirror this across the Y axis. It should be extruded to create the handle.

*   **Attachment:** I'm using M3 screws and knurled nuts. There will be corresponding cutouts for these. The knurled nuts sit *inside* the scale, so the cutout needs to have the right depth and diameter to hold them. The screws will pass through holes on either side of the knife blade.

*   **Chamfer:** There's a chamfer on the top side. The current code defines this with a `chamfer()` module, but it's not parametrically driven - I would like to be able to easily change its shape, including a fillet at the intersection between the chamfer and the main body of the scale.

*   **Parameters:** I need to be able to easily adjust the overall handle thickness and the height of the knurled nut. The minimum handle thickness should be such that 5mm knurled nuts can be accommodated (a minimum of 14 mm overall, with a 3.5mm blade). It would also be great if the screw hole sizes could be parametrically adjusted.

The provided SCAD code is a good starting point and includes key measurements. I'd like you to use the general layout, the `shapePoints`, and the different cutouts specified in the attached SCAD file. I would also like to use the BOSL library.

Could you generate a parametric OpenSCAD file that does all this? I'd like it to be well commented so I can understand what's going on. It would be ideal if the handle profile was easily adjustable, in case I want to modify that at a later date.

[Assistant]
knife_handle.scad:
```
// Full handle width, blade + both scales, mm
HANDLE_THICKNESS = 14.2;

// Height of knurled nut, mm
KNURL_HEIGHT = 5;

/* [Hidden] */

// chamfer height
ch = 4.2;
BLADE_THICKNESS = 3.5;
$fn=90;
h = (HANDLE_THICKNESS - BLADE_THICKNESS) / 2 - ch;
bh = (KNURL_HEIGHT - BLADE_THICKNESS) / 2;
translate([-52, -12, 0]) handle();
translate([-52, 12, 0]) mirror([0, 1, 0]) {
	handle();
}

module handle() {
	zz = h - (h+ch/2 - 2.6);
	difference() {
	fillet();
	translate([-55, -2.5, h+ch+18.2]) rotate([-1, 89.3, 0]) cylinder(d=38, h=90);
	chamfer(-44.29, 1.777, h+ch/2, 5.2);
	translate([-44.29, 1.777, -1]) cylinder(d=5.2, h=h+ch+2);
	chamfer(-33.78, -11.26, h+ch/2, 5.2);
	translate([-33.78, -11.26, -1]) cylinder(d=5.2, h=h+ch+2);
	translate([-29, -2.2, h+ch-3.4]) cylinder(d=5.6, h=10);
	translate([-29, -2.2, h+ch-3.4]) cylinder(d=5.6, h=3);
	translate([-29, -2.2, -1]) cylinder(d=5.6, h=bh+1.1);
	translate([-29, -2.2, bh+.3]) cylinder(d=3.2, h=10);
	translate([33.5, -3.15, h+ch-3.0]) cylinder(d=5.6, h=10);
	translate([33.5, -3.15, -1]) cylinder(d=5.6, h=bh+1.1);
	translate([33.5, -3.15, bh+.3]) cylinder(d=3.2, h=10);
	}
}

module chamfer(x, y, z, d) {
	translate([x, y, z])
	cylinder(d1 = d, d2 = d+7, h=ch);
}

module fillet() {
	sc = [.99, .91];
	a2 = ch/3;
	a1 = ch - a2;
	union() {
		linear_extrude(height=h, convexity=10) shape();
		translate([0, 0, h])
		linear_extrude(height=a1, scale=sc, convexity=10) shape();
		translate([0, 0, h+a1])
		linear_extrude(height=a2, scale=[.98, .8], convexity=10) scale(sc) shape();
	}
}

module shape() {
	translate([40, -12]) scale([1, .995]) polygon(points = shapePoints, convexity=10);
}

shapePoints = [
	[2.106911, -10.49782],
	[0.947201, -8.434299],
	[-0.496173, -6.558208],
	[-2.193433, -4.908251],
	[-4.109563, -3.51847],
	[-6.205033, -2.417536],
	[-8.436611, -1.628163],
	[-10.75826, -1.166637],
	[-13.12208, -1.042478],
	[-15.4793, -1.258248],
	[-17.78129, -1.809497],
	[-19.98056, -2.68485],
	[-21.50094, -3.002483],
	[-23.05403, -2.984215],
	[-24.56651, -2.630906],
	[-27.44633, -1.390109],
	[-30.45769, -0.515647],
	[-33.55418, -0.020995],
	[-36.6881, 0.086227],
	[-39.81116, -0.195634],
	[-42.87524, -0.862235],
	[-44.06583, -0.956748],
	[-45.25724, -0.873184],
	[-46.42298, -0.6134],
	[-46.71896, -0.411004],
	[-46.96743, -0.152492],
	[-47.37883, 0.460169],
	[-47.66541, 0.709325],
	[-48.00201, 0.885107],
	[-48.37025, 0.977901],
	[-48.74996, 0.982631],
	[-49.12039, 0.89904],
	[-49.46128, 0.731699],
	[-49.75397, 0.489761],
	[-50.50119, 0.299692],
	[-51.27165, 0.270382],
	[-52.03115, 0.403134],
	[-52.74598, 0.692054],
	[-52.9464, 0.894098],
	[-53.18852, 1.043662],
	[-53.4589, 1.13245],
	[-53.74256, 1.155537],
	[-54.02374, 1.111642],
	[-54.28686, 1.0032],
	[-54.51732, 0.836227],
	[-54.70233, 0.619984],
	[-54.83164, 0.366467],
	[-54.89806, 0.089739],
	[-55.63, -0.051907],
	[-56.37547, -0.044006],
	[-57.10423, 0.113122],
	[-57.25626, 0.357166],
	[-57.46036, 0.559692],
	[-57.70557, 0.709837],
	[-57.97874, 0.799547],
	[-58.26522, 0.824011],
	[-58.54965, 0.781917],
	[-58.81676, 0.675522],
	[-59.05224, 0.510533],
	[-59.24345, 0.2958],
	[-59.38013, 0.04284],
	[-59.45496, -0.234778],
	[-59.82624, -0.560181],
	[-60.26028, -0.795457],
	[-60.73558, -0.928967],
	[-61.22864, -0.954104],
	[-61.71506, -0.869625],
	[-62.17077, -0.679709],
	[-62.47119, -0.509422],
	[-62.8021, -0.41066],
	[-63.14671, -0.38843],
	[-63.48757, -0.443857],
	[-63.80738, -0.574133],
	[-64.08994, -0.772654],
	[-64.32094, -1.029356],
	[-64.48865, -1.331228],
	[-64.58457, -1.662968],
	[-64.8419, -1.973215],
	[-65.15948, -2.221457],
	[-65.52267, -2.396278],
	[-65.91479, -2.489636],
	[-66.3178, -2.497238],
	[-66.71317, -2.418734],
	[-67.0827, -2.257735],
	[-67.34612, -2.124513],
	[-67.63367, -2.057757],
	[-67.92886, -2.061297],
	[-68.21473, -2.13493],
	[-68.47488, -2.274431],
	[-68.6944, -2.471797],
	[-68.8607, -2.715704],
	[-68.96422, -2.992159],
	[-68.99902, -3.2853],
	[-69.20782, -3.822625],
	[-69.52959, -4.300935],
	[-69.94861, -4.696848],
	[-70.44437, -4.99101],
	[-73.14462, -6.476898],
	[-73.60204, -6.738862],
	[-74.10566, -6.894518],
	[-74.63113, -6.936341],
	[-75.15302, -6.862307],
	[-75.64613, -6.675997],
	[-76.08659, -6.386419],
	[-89.15119, 11.06368],
	[-89.65613, 12.06394],
	[-89.9334, 13.14957],
	[-89.96992, 14.26946],
	[-89.76398, 15.37085],
	[-89.3253, 16.40189],
	[-88.5699, 17.65825],
	[-87.58173, 18.74111],
	[-86.39954, 19.608],
	[-85.06969, 20.22494],
	[-83.64436, 20.56771],
	[-72.25465, 21.30127],
	[-60.84882, 21.7143],
	[-49.43588, 21.80647],
	[-38.02486, 21.5777],
	[-25.81698, 21.1008],
	[-13.61396, 20.51244],
	[-1.416821, 19.81267],
	[-1.022418, 19.52147],
	[-0.683403, 19.16731],
	[-0.409692, 18.76057],
	[-0.203557, 18.61222],
	[0.029887, 18.51219],
	[0.279486, 18.46528],
	[0.533315, 18.47372],
	[0.779248, 18.53711],
	[1.005533, 18.65241],
	[1.20136, 18.81413],
	[1.357372, 19.01453],
	[1.697619, 19.27507],
	[2.089223, 19.44913],
	[2.51061, 19.52712],
	[2.93857, 19.50475],
	[3.349527, 19.38324],
	[3.720845, 19.16929],
	[4.032069, 18.87469],
	[4.368093, 18.25261],
	[4.266055, 18.51567],
	[4.528667, 18.0206],
	[4.738923, 17.83245],
	[4.987263, 17.69851],
	[5.25999, 17.62619],
	[5.542064, 17.61947],
	[5.817927, 17.67871],
	[6.072365, 17.80067],
	[6.291345, 17.9786],
	[6.46279, 18.20269],
	[6.577243, 18.46059],
	[6.775096, 18.74865],
	[7.035858, 18.9813],
	[7.344525, 19.14516],
	[7.683334, 19.2308],
	[8.03279, 19.23329],
	[8.372784, 19.15248],
	[8.68375, 18.99302],
	[8.947795, 18.7641],
	[9.149724, 18.47888],
	[9.277918, 18.15378],
	[9.325, 17.8075],
	[9.926334, 14.12398],
	[10.18149, 10.40044],
	[10.08824, 6.669322],
	[9.647401, 2.96317],
	[8.862813, -0.68571],
	[7.741318, -4.245506],
	[6.292693, -7.685185],
	[4.529567, -10.97476],
	[4.186646, -11.17611],
	[3.80549, -11.2895],
	[3.408271, -11.30834],
	[3.018094, -11.23153],
	[2.657656, -11.06354],
	[2.347923, -10.81413],
];

```


[User]
Hey, I'm looking to get a parametric OpenSCAD file created for a NEMA 17 stepper motor spacer.  I want to replace the individual standoffs on my Ultimaker Original with a single, solid piece.

The basic idea is a square with a standoff at each corner that's intended to attach to the motor itself.  The standoffs should be cylindrical, and I need to be able to adjust the height of those cylinders (the *space* variable in the provided code). There also should be a base that they sit on (the *plate* variable in the code). There needs to be a through-hole in each standoff for a screw.

In addition to the standoffs, there's a circular cutout in the center of the base that's meant to fit around the motor's flange.  The old code calls that a *flansch*, which I'm fine with. I need that diameter and depth to be adjustable separately from other parameters.

Ideally, I'd like to be able to control the diameter of the cylindrical standoffs and the size of the base square, including the distance between each of the standoffs. The screw holes need to be adjustable for diameter and depth separately, too. Also, the baseplate needs to have its own adjustable thickness.

Could you create this for me, please? I am assuming everything is in millimeters.

[Assistant]
NEMA-17_spacer_V2.scad:
```
//NEMA 17 spacer
//20190203 P. de Graaff
//20190219 Aussparung für Motorflansch

//outer diameter in mm
outerDiameter=10;

$fn=100;
//height of baseplate in mm
plate=2;

//total height with baseplate included in mm
space=11;

//right
difference(){
    hull(){
        translate([31/2,-31/2,0])cylinder(d=outerDiameter,h=plate);
        translate([31/2,31/2,0])cylinder(d=outerDiameter,h=plate);
    }
    translate([31/2,-31/2,-1])cylinder(d=3.2,h=plate+2);//drill for screw
    translate([31/2,31/2,-1])cylinder(d=3.2,h=plate+2);
    flansch();
}
difference(){
    translate([31/2,-31/2,0])cylinder(d=outerDiameter,h=space);
    translate([31/2,-31/2,-1])cylinder(d=3.2,h=space+2);
}
difference(){
    translate([31/2,31/2,0])cylinder(d=outerDiameter,h=space);
    translate([31/2,31/2,-1])cylinder(d=3.2,h=space+2);
}
//bottom
difference(){
    hull(){
        translate([31/2,-31/2,0])cylinder(d=outerDiameter,h=plate);
        translate([-31/2,-31/2,0])cylinder(d=outerDiameter,h=plate);
    }
    translate([31/2,-31/2,-1])cylinder(d=3.2,h=plate+2);
    translate([-31/2,-31/2,-1])cylinder(d=3.2,h=plate+2);
    flansch();
}
difference(){
    translate([-31/2,-31/2,0])cylinder(d=outerDiameter,h=space);
    translate([-31/2,-31/2,-1])cylinder(d=3.2,h=space+2);
}
//left
difference(){
    hull(){
        translate([-31/2,-31/2,0])cylinder(d=outerDiameter,h=plate);
        translate([-31/2,31/2,0])cylinder(d=outerDiameter,h=plate);
    }
    translate([-31/2,-31/2,-1])cylinder(d=3.2,h=plate+2);
    translate([-31/2,31/2,-1])cylinder(d=3.2,h=plate+2);
    flansch();
}
difference(){
    translate([-31/2,31/2,0])cylinder(d=outerDiameter,h=space);
    translate([-31/2,31/2,-1])cylinder(d=3.2,h=space+2);
}
module flansch (){
    translate([0,0,-1])cylinder(d=23,h=20,$fn=100);
}
```


[User]
Hi! I'm looking to design a parametric pen holder that hangs from a shelf. I have a specific shelf in mind, it's a standard 20mm thick shelf, though I'd want to make this adaptable for other thicknesses as well. The core of the design should be a rectangular box with a grid of holes to hold pens. The holes should be uniform, and the dimensions of the box and the grid should be adjustable. I'd also like clips that grab the shelf to hold the pen holder in place.

Here are the specific parameters I need:

*   **rows:** The number of rows of pen holes.
*   **columns:** The number of columns of pen holes.
*   **size:** The diameter of each pen hole.
*   **innerThickness:** The space between pen holes in the grid.
*   **depth:** The depth of the pen holder box (how far it extends down from the shelf).
*   **clipWidth:** The width of the clips that hold onto the shelf.
*   **angle:** The downward angle of the clips.
*   **shelfThickness:** The thickness of the shelf it is designed to hang on.

I'd also like the design to orient itself for printing, rotating and translating it so it is printed "right side up" without any special work on my part.

I'd really appreciate it if you could generate a single OpenSCAD file for this design. The file should use standard OpenSCAD primitives, I don't think I need any external libraries for this, but I'm also not totally sure what's available out there. Thanks!

[Assistant]
shelfpenHolder.scad:
```
// Parameteric Shelf-hanging pen holder - made to work with shelves from the Container Store
// Created by Michael S. Scherotter
// @Synergist on Thingiverse
// @Synergist on Twitter
// @TravelArtJournalist on Instagram
// Updated 7/19/2020

// preview[view:north west, tilt:bottom]

// Number of rows
rows = 4; // [1:15]

// Number of columns
columns = 10; // [2:15]

// Size of each cell in mm
size = 12; // [10:20]

// Thickness space between each cell in mm
innerThickness = 1.5; // [1.5:4]

// Depth of each cell in mm
depth = 80; // [40:100]

// Width of each clip in mm
clipWidth = 10; // [10:20]

// Downward tilt angle
angle = 10; // [10:14]

// Shelf thickness in mm
shelfThickness = 20; //[10:30]

width = (columns * size)  + innerThickness * (columns + 1);
height = (rows * size)  + innerThickness * (rows + 1);

module model()
{
	union(){
		difference() {
           body();
						holes();
					}
		}
	          clip();
            translate([width-clipWidth,0,0])
            {
                clip();
            }

		//}

//    difference() {
//        union()
//        {
//            body();
//            clip();
//            translate([width-clipWidth,0,0])
//            {
//                clip();
//            }
//        }
//        holes();
//    }
}

orientForPrint();

module orientForPrint()
{
    rotate([180,0,0])
    {
        translate([-width/2,-height/2,-depth])
        {
            model();
        }
    }
}

module body()
{
    cube([width, height, depth], center=false);
}

module clip(){
    clipHeight = cos(angle) * (shelfThickness + 20);
    clipDepth = sin(angle) * (shelfThickness + 20);
    union()    {
        translate([0, -(shelfThickness + 10), depth - clipDepth -3])    {
            rotate([-angle,0,0])            {
                union() {
                    cube([clipWidth, shelfThickness + 20, 10], center=false);
                    translate([0,0,-40]) {
                        cube([clipWidth, 10, 40], center=false);
                    }
                    translate([0,shelfThickness + 10,-40]){
                        cube([clipWidth, 10, 40], center=false);
                    }
                }
            }
        }
        translate([0, -clipHeight + 12, depth - 10])
        {
            cube([clipWidth, clipHeight, 10], center=false);
        }
    }
}

module createCell(row, col)
{
    translate([
        innerThickness + row * (size + innerThickness),
        innerThickness + col * (size + innerThickness),
        innerThickness])
    {
        cube([size, size, depth], center=false);
    }
}

module holes() {
    union()
    {
        for (row = [0: rows-1])
            for (col = [0: columns-1])
                createCell(col, row);
    }
}
```


[User]
I want to design a mount for my Nintendo Switch that attaches to a car sun visor. I've seen some designs that use straps or glue, but I'd like one that friction-fits onto the visor and holds the Switch securely, without requiring any other hardware.

I'm envisioning a design that has two mirrored "clamp" pieces, one on each side of the visor. These clamps should have a section that grabs the visor and a section that supports the Switch. It needs to be adjustable, since visors can vary in thickness, and I want to be able to set that as a parameter in OpenSCAD.

The basic shape of each clamp would involve a flat section against the visor and then some vertical sections to grab the edges of the visor. The part that holds the Switch should be elevated above the visor. It would be great to have the clamp on each side use small cylinders to keep the switch from moving around, and some side bars to hold the switch from falling out to the side.

Could you design this in OpenSCAD? I'd prefer to have it be completely parametric so I can change the visor thickness, along with the overall length of the clamp. I think it would be helpful to set the visor thickness and clamp length as top level variables. I do not think I need anything beyond the standard libraries.

[Assistant]
SwitchVisorMount.scad:
```
// Nintendo Switch mount for car visor

$fn=50;
width=30;   // [7:1:50]

// right side
    union() {
        translate([0,42,0]) cube([9,103,1.5]);
        translate([0,143.5,0]) cube([9,3,20]);
        translate([1,42,1.5]) cube([7,35,3]);
        translate([0,42,3]) cube([9,35,2]);
        translate([3,2,0]) cube([4,40,7]);
        translate([5,2,0]) cylinder(r=2,h=7);
        translate([5,0,0]) cube([width,4,7]);
        translate([width+3,2,0]) cube([4,28,7]);
        translate([width+5,2,0]) cylinder(r=2,h=7);
        translate([width+5,30,0]) cylinder(r=2,h=7);
    }

// left side
    union() {
        translate([width*2+10,42,0]) cube([9,103,1.5]);
        translate([width*2+10,143.5 ,0]) cube([9,3,20]);
        translate([width*2+11,42,1.5]) cube([7,35,3]);
        translate([width*2+10,42,3]) cube([9,35,2]);
        translate([width*2+12,2,0]) cube([4,40,7]);
        translate([width*2+14,2,0]) cylinder(r=2,h=7);

        translate([width+14,0,0]) cube([width,4,7]);
        translate([width+12,2,0]) cube([4,28,7]);
        translate([width+14,2,0]) cylinder(r=2,h=7);
        translate([width+14,30,0]) cylinder(r=2,h=7);
    }

```