[User]
I need a parametric case design for Raspberry Pi 3 and 4 models, specifically designed to accommodate a zigbee module and its antenna adapter. I've been using this design I found online but want a fresh design.

Here's a breakdown of the requirements:

*   **Compatibility:** The case needs to work for both Raspberry Pi 3B and 4 models. I want a parameter to select which model.
*   **Zigbee Module:** It needs to be designed to fit the [CC2652P2 zigbee module](https://shop.codm.de/automation/zigbee/33/zigbee-cc2652p2-raspberry-pi-module), which means enough internal height is needed for this module.
*   **Antenna Adapter:**  There should be a built-in holder for this [antenna adapter](https://shop.codm.de/antennen/2.4ghz/7/u.fl-sma-antennenadapter-10cm), with parameters for the position of the holder, how far it sticks out, the connector diameter, and extra spacing for the connector.
*   **Cutouts:** I need parameters to enable or disable cutouts for:
    *   Power Over Ethernet (POE)
    *   Camera connector
    *   Display connector
*   **Tolerances:** I would like a global tolerance parameter to adjust the fit of the case and cutouts.
*   **Fan Mount:** Provide parameters for fan mounting, including:
    *   Diameter of the fan holes
    *   Position of the fan from the right and top
    *   Distance between the mounting holes.
*   **General Parameters:**
    *   Board thickness (for reference and can be used in calculations)
    *   Minimum space for components underneath the board
    *   Case thickness
    *   Length and width of the Pi board itself (these should be configurable)
*   **Circular components:** I want to be able to specify the detail of circular components using `$fn`.

The design should generate separate top and bottom pieces of the case, as well as a full case option for debugging. Use a subtractive design approach for creating the main cavity, rather than a construction approach. I would like a `render_part` parameter to choose between generating the "top", "bottom", or "all" parts of the case.

I don't have any existing code; please provide me with the full set of OpenSCAD files I need to generate this case.

[Assistant]
rpi_case.scad:
```
// Raspberry pi 3 / 4 model case by pkoehlers

// Original copyright / license notice:
// Raspberry pi 4 model case by George Onoufriou (Raven, GeorgeRaven, Archer) C 2019-06-30
// please see licence in project root https://github.com/DreamingRaven/RavenSCAD/blob/master/LICENSE

// |-=========---------| <-The back right of the board is the point everything else is relative to
// | o            o    |
// | o            o    |
// ||_|----------------|

/* [General] */

// currently only RPI3b and 4 are supported: RPI3b is supported as 3, any other value is for RPI4
// Raspberry Pi model
rpi_model = 4; // [3, 4]
render_part = "top"; // ["top", "bottom", "all"]

// Further value e.g. for the pi will be increased by this tolerance to make it fit more easily
tolerance = 1.2;

// how detailed the circular components are
$fn = 80;

// add holder for the external zigbee antenna
antenna_connector_enabled=true;

/* [Advanced measures] */

// the space for the board itself only
board_thickness = 1.5;
// the min space that the throughhole components require underneath
pin_space = 3;
//thickness of the case
case_thickness = 2;
// this is the length of the pi board only
pil = 85.5;
// this is the width / depth of the pi board only
pid = 56;

/* [fan mount options] */
// the diameter of the fan holes
fan_pin_diam = 3.5;
// the offset of the fan from the right
fan_position_x = 44.3;
// the offset of the fan from the top
fan_position_y = 17;
// the distance between the mount holes
fan_pin_distance = 32;

/* [antenna options] */
// defines how far from the edge of the case the holder will be placed
antenna_position_y=11;
// how far the holder will stand out
antenna_holder_length = 27;
// diameter of the antenna connector
antenna_connector_diameter = 8;
// extra space for the connector
antenna_connector_spacing = 1.5;

/* [cutout options] */
poe_cutout_enabled = false;
camera_cutout_enabled = false;
display_cutout_enabled = false;

module __Customizer_Limit__ () {}

extension = 50; // extension to lengths so case can be subtractiveley created
inhibitionzone_height = 22; // creates an inhibition zone for surface components

pih = board_thickness;
sd_height = pin_space + case_thickness + board_thickness; // is how tall the sd card part sticking out is so if you increase it will cut more out for case
mount_pin_height = 2*board_thickness + 2*case_thickness + pin_space + inhibitionzone_height;//31; // this is the most awkward one of the set as it sets the mount point pin size

antenna_connector_case_width=antenna_connector_diameter+(antenna_connector_spacing*2);

if (render_part == "top") {
    topCase();
}
if (render_part == "bottom") {
    bottomCase();
}
if (render_part == "all") {
    full_case_for_debugging();
}

module topCase() {
    difference() {
     translate([0,0,inhibitionzone_height + case_thickness + board_thickness]) rotate([0,180,0]) intersection(){ // top of case
      rpi4_case();
      topSelector();
    }
    topCaseTolerance();
    translate([0, pid + case_thickness, 0])
    topCaseTolerance();
}
}
module bottomCase() {
    translate([30,0,case_thickness]) rotate([0,-90,0])
    difference(){ // bottom of case
      rpi4_case();
      topSelector();
    }
}

module full_case_for_debugging() {
    translate([-pil,pid+case_thickness*2+5]) rpi4_case(); // the whole unsplit case
    translate([extension+17.44,pid+case_thickness*2+5,0]) rpi4(); // the raspberry pi 4 and associated tolerances
}

// here follows all the modules used to generate what you want.
module topSelector()
{
  difference(){ // this difference selects the top and bottom parts of the case with a small lip for the IO
    translate([-case_thickness,0,0]) cube([tolerance*2+pil+2*case_thickness+antenna_holder_length,pid+tolerance*2,pin_space+inhibitionzone_height+case_thickness+tolerance]);  // test hull
    translate([-case_thickness,0,0]) cube([case_thickness,pid+case_thickness*2,board_thickness]);
  }
}

module topCaseTolerance() {
    translate([0,0,inhibitionzone_height]) rotate([0,180,0])
    translate([-case_thickness,0,-case_thickness*2])
      color ("#F00") cube([pil+case_thickness*2+tolerance+2,tolerance/2,inhibitionzone_height+case_thickness*2+tolerance*2]);
}

module rpi4_case()
{
  difference(){ // subtracts the rpi4 model from a cube to generate the case
    translate([-case_thickness,-case_thickness,-(case_thickness + pin_space)])
     union() {
             cube([pil+(2*case_thickness)+tolerance*2,
      pid+(2*case_thickness)+tolerance*2,
      pin_space+inhibitionzone_height+board_thickness+(2*case_thickness)+tolerance*2]); // the case itself
      if( antenna_connector_enabled) {
         translate([pil+tolerance*2, antenna_position_y, inhibitionzone_height+board_thickness-(antenna_connector_diameter)+(2*case_thickness) + tolerance*2])
        cube([antenna_holder_length,antenna_connector_case_width,antenna_connector_case_width]);
                  //antenna holder outer body
      }
     }

    union(){
      rpi4();
      pins(); // generating the pins themselves so the holes can be inhibited
    }
  }
}

module rpi4(){

  difference(){ // this creates the mount holes

    translate([0,0,board_thickness]){ // two translations cancel out but make maths simpler before they do
      translate([0,0,-(board_thickness)]) // the translation which ^ cancels out
      {
        cube([pil+tolerance*2,pid+tolerance*2,board_thickness+tolerance*2]); // the board only (not the underpins)
      }
      scale([1.03,1.03,1.03]) {
      // these are the big surface level components
      usb_width = 14.7;
      ethernet_width = 17.9;

      if (rpi_model == 3) {

          translate([-(2.81+extension),2.15,0]) cube([17.44+extension,usb_width,15.6]);  // USB 3.0
          translate([-(2.81+extension),22.6-(ethernet_width-usb_width),0]) cube([17.44+extension,usb_width,15.6]);  // USB 2.0
          translate([-(2.81+extension),39.6-(ethernet_width-usb_width),0]) cube([21.3+extension,ethernet_width,13.6]);   // Ethernet port
          translate([67.1,55,0]) cube([12.2,7.4+extension,4.5]);                     // USB micro power
          translate([42.3,50,0]) cube([17.5,7.8+extension,7.4]);                    // HDMI

      } else {
          translate([-(2.81+extension),2.15,0]) cube([21.3+extension,ethernet_width,13.6]);   // Ethernet port
          translate([-(2.81+extension),22.6,0]) cube([17.44+extension,usb_width,15.6]);  // USB 3.0
          translate([-(2.81+extension),39.6,0]) cube([17.44+extension,usb_width,15.6]);  // USB 2.0
          translate([67.1,55,0]) cube([12.2,7.4+extension,4.5]);                     // USB type c power
          translate([54.5,50,0]) cube([8.5,7.8+extension,4.5]);                    // Micro HDMI0
          translate([40.7,50,0]) cube([8.5,7.8+extension,4.5]);                    // Micro HDMI1
      }
      translate([27.36,1,0]) cube([40.7,5.0,8.6+extension]);                    // GPIO pins
      if(poe_cutout_enabled) {
          translate([21,7.15,0]) cube([5.0,5.0,8.6+extension]);                     // Power over ethernet pins
      }
      translate([48.0,16.3,0]) cube([15.0,15.0,2.5]);                           // cpu
      translate([67.5,6.8,0]) cube([10.8,13.1,1.8]);                            // onboard wifi

      if(display_cutout_enabled) {
          translate([79,17.3,0]) cube([2.5,22.15,5.4+extension]);                   // display connector
      }
      if(camera_cutout_enabled) {
          translate([37.4,34.1,0]) cube([2.5,22.15,5.4+extension]);                 // CSI camera connector
      }
      translate([26.9,43.55,0]) cube([8.5,14.95+extension,6.9]);                  // Audio jack
      translate([85,22.4,-(board_thickness+sd_height)]) cube([2.55+extension,11.11,sd_height+tolerance]); // SD card (poking out)
      }
      //following lines are the cutout for the antenna holder
      if(antenna_connector_enabled) {
        antenna_holder_cutout();
      }
      translate([fan_position_x,fan_position_y,0]) cylinder(extension,d=fan_pin_diam, center=false);                            // fan mount top-r
      translate([fan_position_x,fan_position_y+fan_pin_distance,0]) cylinder(extension,d=fan_pin_diam, center=false);                 // fan mount bot-r
      translate([fan_position_x+fan_pin_distance,fan_position_y,0]) cylinder(extension,d=fan_pin_diam, center=false);                 // fan mount top-l
      translate([fan_position_x+fan_pin_distance,fan_position_y+fan_pin_distance,0]) cylinder(extension,d=fan_pin_diam, center=false);      // fan mount bot-l
      translate([fan_position_x+0.5*fan_pin_distance,fan_position_y+0.5*fan_pin_distance,0]) cylinder(extension,d=fan_pin_distance+fan_pin_diam, center=false);      // fan air hole
      translate([53,7.8,0]){ scale([10,1,1]){

        translate([0,0,-extension-board_thickness-pin_space])  cylinder(extension,d=5, center=false);      // under-side air hole
        translate([0,10,-extension-board_thickness-pin_space]) cylinder(extension,d=5, center=false);      // under-side air hole
        translate([0,20,-extension-board_thickness-pin_space]) cylinder(extension,d=5, center=false);      // under-side air hole
        translate([0,30,-extension-board_thickness-pin_space]) cylinder(extension,d=5, center=false);      // under-side air hole
        translate([0,40,-extension-board_thickness-pin_space]) cylinder(extension,d=5, center=false);      // under-side air hole
             translate([pil, 0, inhibitionzone_height+board_thickness+case_thickness-(antenna_connector_case_width)])
            rotate([0,90,0])
            translate([-antenna_connector_diameter /2 - 1, antenna_connector_diameter /2 + 1,0])
            cylinder(h=antenna_holder_length, r = antenna_connector_diameter/2);
      }
      }

      difference(){ // this creates the mount points around the mount holes esp the underneath ones
        union(){
          translate([0,0,0]) cube([pil+tolerance*2,pid+tolerance*2,inhibitionzone_height]);                           // cpu
          translate([0,0,-(pin_space+board_thickness)]) cube([pil+tolerance*2,pid+tolerance*2,pin_space]); // underpins only
        }
        mounts(); // the material which is above and below the board to keep it in place which the pins go through
      }
    } // end of translation cancel
  pins(); // the hole which will be screwed into to put both halves of the case and board together

  }

}
module antenna_holder_cutout() {
    pos_x = pil - case_thickness + tolerance;
    pos_y = antenna_position_y + antenna_connector_diameter/4 + antenna_connector_spacing;
    pos_z = inhibitionzone_height+board_thickness+case_thickness-(antenna_connector_diameter) + antenna_connector_spacing / 2 + tolerance*2;
    height = antenna_holder_length + case_thickness;
    diameter = antenna_connector_diameter;

    translate([pos_x, pos_y, pos_z])
    rotate([0,90,0])
    cylinder(h=height, d = diameter);

    translate([pos_x - 6, pos_y, pos_z])
    rotate([0,90,0])
    cylinder(h=height - 2.5, d = diameter+ 2.5);
}
module mounts(){
  translate([1.25 + tolerance,1.25 + tolerance,(0.5*mount_pin_height)-(board_thickness+case_thickness+pin_space)]){ // this is to move all the pins
          translate([22.2,2,0]) cylinder(mount_pin_height,d=6, center=true);     // mount top-r
          translate([22.2,51.1,0]) cylinder(mount_pin_height,d=6, center=true);  // mount bot-r
          translate([80.2,2,0]) cylinder(mount_pin_height,d=6, center=true);     // mount top-l
          translate([80.2,51.1,0]) cylinder(mount_pin_height,d=6, center=true);  // mount bot-l
        }
}

module pins(){
  translate([1.25 + tolerance,1.25 + tolerance,(0.5*mount_pin_height)-(board_thickness+case_thickness+pin_space)]){ // this is to move all the pins
    translate([22.2,2,0]) cylinder(mount_pin_height,d=3.2, center=true);     // hole  top-r
    translate([22.2,51.1,0]) cylinder(mount_pin_height,d=3.2, center=true);  // hole  bot-r
    translate([80.2,2,0]) cylinder(mount_pin_height,d=3.2, center=true);     // hole  top-l
    translate([80.2,51.1,0]) cylinder(mount_pin_height,d=3.2, center=true);  // hole  bot-l
  }
}

```


[User]
Hey, I'm looking for an OpenSCAD design for a shim, specifically for the Anycubic Photon Mono X printer's Z-axis. It's meant to be a spacer between the Z-axis and the linear rail. I've seen a few around, but I need something parametric so I can adjust the thickness.

Essentially, I need a rectangular block with two screw holes, similar to the existing "anycubic_mono_x_spacer.scad" file, but designed from scratch. Here are the parameters I'd like to be able to adjust:

*   **shimThick:** The thickness of the spacer. This is the most important one for me to be able to modify.
*   **shimLength:** The length of the spacer.
*   **shimWidth:** The width of the spacer.
*   **holeDiam:** The diameter of the screw holes.
*   **hole1X:**  The X position of the first hole's center.
*   **hole1Y:** The Y position of the first hole's center.
*   **hole2X:** The X position of the second hole's center.
*   **hole2Y:** The Y position of the second hole's center.

I'd like to avoid any reliance on specific external libraries like MCAD, BOSL, etc., keeping it as simple as possible with standard OpenSCAD primitives. I need the final output to be a single .scad file. Please use the `difference` primitive to create the holes. And, it would be great if you could include comments describing what each parameter represents.

[Assistant]
anycubic_mono_x_spacer.scad:
```
// title      : Anycubic Photon Mono X shim
// author     : Darragh Broadbent darraghbr.co.uk
// license    : Creative Commons CC BY 4.0
// revision   : 0.1
// file       : anycubic_mono_x_spacer.scad

// Thickness of the shim
shimThick = 1;

/* [Hidden] */

shimLength = 8;
shimWidth = 13;
holeDiam = 4;

$fn=100;

difference(){
    cube([shimLength ,shimWidth ,shimThick]);
    translate([4 ,3]) cylinder(h = shimThick, d = holeDiam);
    translate([4 ,10]) cylinder(h = shimThick, d = holeDiam);
}
```


[User]
Hey, I need a parametric OpenSCAD design for a case for an SPF5189Z LNA board. I've got an example .scad file that I made myself, but I need a version that's actually parametric and easier to customize.

Here's what I'm looking for:

*   **Overall Design:** It's a simple rectangular case with a top and bottom piece. The bottom houses the LNA board, and the top acts as a lid that screws down.
*   **Key Dimensions:** The current dimensions are based on the layout in my provided .scad file (see it for details).  Ideally, the parametric version will allow me to easily adjust the overall size and position of the different elements, such as the cutouts for the SMA connectors and mounting screws.
*   **Connector Cutouts:** It needs cutouts for the two SMA connectors (RF in and RF out).  These need to be customizable in position and offset from the board.
*   **Screw Holes:** There should be four screw holes for mounting the lid. The positions of these need to be easily customizable.
*   **Board Outline:** The internal area where the LNA board sits needs to be precisely sized, ideally with an adjustable tolerance.
*   **Text:** I'd like the option to add text (like the LNA model name and connector labels) to the case and have the text depth also adjustable.
*   **Separate Parts:** The design should generate separate STL files for the base and the lid to enable printing them as separate objects.
*   **Flexibility:** I want to be able to adjust the tolerances for a snug fit, as well as adjust dimensions in case I want to use this for other boards later on.
*   **Libraries:** I think we should probably use the `MCAD` library for some of the more advanced stuff, and possibly `BOSL` or `BOSL2` if you think that makes the code simpler or cleaner.

I'm not looking for a completely universal case that fits every possible version of this board, but rather something that can be easily adapted to minor variations or different boards altogether.  The example file should give a good idea of the starting dimensions and overall design intent; please use that as your initial reference point.  I need the files to be easily editable in a normal text editor, so that I can make adjustments on my own.

[Assistant]
spf_case.scad:
```

tolerance = 0.6;
conoffset = 2;
rfinoffset = 0;
rfoutoffset = 0;
screwradius = 1.1;
body = true;
cap = true;
txt = true;
txtdepth = 0.7;

difference(){
    // case
    union(){
        if (body){
            color("cyan")
            translate([0,17.5,0])
            cube([28.5,2,12],center=true);

            color("cyan")
            translate([-10.75,0,-1.25])
            cube([3,33,7],center=true);

            color("cyan")
            translate([10.75,11,-1.25])
            cube([3,11,7],center=true);

            color("cyan")
            translate([13.25,0,0])
            cube([2,33,12],center=true);

            color("cyan")
            translate([-13.25,0,0])
            cube([2,33,12],center=true);

            color("cyan")
            translate([-12.25,0,4])
            cube([4,33,4],center=true);

            color("cyan")
            translate([12.25,0,4])
            cube([4,33,4],center=true);

            color("cyan")
            translate([-12.25,0,-4])
            cube([4,33,4],center=true);

            color("cyan")
            translate([12.25,0,-4])
            cube([4,33,4],center=true);

            color("cyan")
            translate([0,1,5])
            cube([28.5,35,2],center=true);

            color("cyan")
            translate([0,1,-5])
            cube([28.5,35,2],center=true);

        }

        if (cap){
            color("lime")
            translate([0,-17.5,0])
            cube([28.5,2,12],center=true);
        }
    }

    // SPF body
    translate([0,0,-1.25])
    union(){

            if (txt){
                translate([-1,-16,7.26-txtdepth])
                rotate([0,0,90])
                linear_extrude(height=txtdepth)
                text(text="SPF5189Z", font="DejaVu Sans:style=Bold", size=4.4);

                translate([5,-16,7.26-txtdepth])
                rotate([0,0,90])
                linear_extrude(height=txtdepth)
                text(text="RFout", font="DejaVu Sans:style=Bold", size=3);

                translate([5,8,7.26-txtdepth])
                rotate([0,0,90])
                linear_extrude(height=txtdepth)
                text(text="RFin", font="DejaVu Sans:style=Bold", size=3);
            }

        color("red")
        translate([-12.25,-13,5.25])
        rotate([90,0,0])
        cylinder(r1=screwradius,h=12,r2=screwradius,center=true);

        color("red")
        translate([12.25,-13,5.25])
        rotate([90,0,0])
        cylinder(r1=screwradius,h=12,r2=screwradius,center=true);

        color("red")
        translate([-12.25,-13,-4+1.25])
        rotate([90,0,0])
        cylinder(r1=screwradius,h=12,r2=screwradius,center=true);

        color("red")
        translate([12.25,-13,-4+1.25])
        rotate([90,0,0])
        cylinder(r1=screwradius,h=12,r2=screwradius,center=true);

        union(){
            color("green")
            cube([24.5+tolerance,33.01,1.5+tolerance], center=true);

            union(){
                color("silver")
                translate([8.65,12.9,0])
                cylinder(r1=1.5, r2=1.5, h=2, center=true);

                color("silver")
                translate([-8.65,12.9,0])
                cylinder(r1=1.5, r2=1.5, h=2, center=true);

                color("silver")
                translate([8.65,-12.9,0])
                cylinder(r1=1.5, r2=1.5, h=2, center=true);

                color("silver")
                translate([-8.65,-12.9,0])
                cylinder(r1=1.5, r2=1.5, h=2, center=true);
            }
        }

        color("silver")
        translate([0,0,2])
        cube([15,19,3], center=true);

        translate([-0.75+rfinoffset,17.25,1.25])
         union(){
            color("gold")
            cube([6.5+tolerance+conoffset,5,6.5+tolerance*2], center=true);

            color("gold")
            translate([0,0.75,0])
            rotate([-90,0,0])
            cylinder(r1=3, r2=3, h=8);
        }

        translate([-0.75+rfoutoffset,-17.25,1.25])
        rotate([180,0,0])
        union(){
            color("gold")
            cube([6.5+tolerance+conoffset,5,6.5+tolerance*2], center=true);

            color("gold")
            translate([0,0.75,0])
            rotate([-90,0,0])
            cylinder(r1=3, r2=3, h=8);

            color("gold")
            translate([9-rfoutoffset,0,-1])
            cube([4,5,3], center=true);
        }
    }

}
$fn = 50;
```


[User]
Okay, I'm looking for an OpenSCAD design for a garden stake, something that's easy to print and reusable. I'd like it to have a low-profile pull loop at the top so it's easy to grab, and the option to have teeth or barbs along the legs to help it grip the soil.

Here's what I need:

*   **Overall Structure:** The stake will have a head, two legs, and the pull loop. The legs should be tapered, thicker at the top and thinner at the bottom. The whole thing should be designed to print flat, without needing supports.
*   **Head:**
    *   `Head_Width`: This is the overall width of the top part, let's start with 30mm.
    *   `Head_Thick`: The thickness of the head, about 5.2mm would be good.
    *   `Head_Hgt`: The height of the head, maybe 7mm, but it needs to be enough so the bottom of the handle isn’t exposed.

*   **Pull Loop:**
    *   `finger_radius`: The radius of the loop, maybe 10mm to start.
    *   `finger_thick`: The thickness of the loop, it should be the same as the `Head_Thick`.

*   **Legs:**
    *   `legheight`: The length of the legs, maybe 90mm.
    *   `legtopradius`: The radius of the leg at the top, let's start with 3mm.
    *   `legbotradius`: The radius at the bottom of the leg, I'm thinking about 1.5mm for now.
    *   `leg_rotation`: The legs should be slightly rotated to make a flat print, so maybe a -.7 value for that.

*   **Teeth:** (Optional)
    *   `withteeth`: A variable to toggle teeth on or off; it should be a simple yes/no.
    *   `tooth_percent`: Let's start with 1.85 as a percentage of the leg width where the tooth is located
    *   `tooth_thick`: The depth/thickness of the tooth, 3.5mm should be good to start.
    *   `first_tooth_percent_high`: The percentage distance from the top of the leg that the first tooth should be. Start with .75.
    *   `tooth_qty`: Number of teeth down the leg, maybe 5.

*   **Size Label:** (Optional)
    *   `withsize`: A variable to toggle a text label on the stake.

*   **Parametric Design:** It's important that all of these values should be changeable using the customizer in OpenSCAD, with labels of course.

*   **Printing:**  I want to make sure that the code generates a flat surface to print the part without supports.

It would be really great if the code included some comments that explained how to change the parameters and if there were any important relationships between parameters. I'd like to be able to vary the length, width, the number of teeth, and everything else easily. Also, it would be helpful to know if there are any weak points or printing considerations.

For libraries, please make sure to use `BOSL2` if you require any external libraries.

[Assistant]
Fence-Stake_Ground-Stake.scad:
```
// Garden / Fence Stakes
// Re-usable stake featuring a low profile pull loop so you can see and pull the stake.
// Option to print with and without teeth.
// Soil typs vary and you may need to customize it.
// You can control, length, diameters, widths, size and qty of teeth

//Printing Notes:
// NO SUPPORTS NEEDED.  With sufficiently thick legs, no brimming required.
// Printed fine at .4 nozzle with layer of .2 or smaller.

//===================== Author ====================
//Initial version created by  AlwaysTinkering 7/2021  https://www.youtube.com/channel/UC27SvMnOzIKx8oxlgZc5AEQ   https://www.thingiverse.com/alwaystinkering/designs https://www.prusaprinters.org/social/116733-alwaystinkering/prints

//=========== Versioning ===========
// V1.1 9/27/2021 adjusted the leg offset for better alignment in wierd combinations of dimensions

// =========== How to run this code ================
// This is an openscad file.  The program is open source and available at https://www.openscad.org/downloads.html
// Press F5 to refresh.  View and uncheck "Hide Customizer" to see customizer input screen.
// OpensCAD program F6 to generate/render and then STL export
// Slice your STL in your slicer and print

// ============== Observations ================
// pushing into soil that is dense or width obstructions can pressure the legs to twist
// With insufficient fill this can cause a break at the top
// maybe a future version with some swivel play at the top of the legs.

// Customizer weirdness... If you cannot enter a decimal to an attribute in customizer, add teh value with the decimal to the attribute in the code on the left, press F5 and it will update customizer.

//////////////// START of Parameters, Customizer Compliant //////////////

//Print the Forks with Teeth
withteeth = "yes"; //[yes, no]

//Print the Size Label on it
withsize = "yes"; //[yes, no]

// Head width = widht of stake
Head_Width = 30;

// Head depth... watch propotion to leg radius
Head_Thick = 5.2;

//Head Height, 7 is the minimum w/o exposing the bottom of the handle at finger_radius = 10
Head_Hgt = 7;

// Radius of pull at the top
finger_radius = 10;

//Thickness of Pull should equal the Head_Thick unless you want
finger_thick = Head_Thick;

//length of the legs
legheight = 90;

//Leg TOP RADIUS... observer the proportion with Head_Thick
legtopradius=3.2;

//Leg BOTTOM Radius
legbotradius =1.5 ;

//Leg Rotation.  To cut the flat print surface the legs are rotated to one side.  You may need to change this if you change the ratios.  Watch the cut.
leg_rotation = -.7;

//The tooth width is a percentage of the leg width at the calculated point it exists... or a guess... 1.65 worked well
tooth_percent  = 1.85;

//thickness/depth of tooth.  Watch the bottom tooth hieght as you change this.
tooth_thick = 3.5;

//how far down should the first tooth appear
first_tooth_percent_high = .75;

//how many teeth do you want
tooth_qty = 5;

/* [Hidden] */

////////// END OF INPUT OPTIONS ///////////////

pi =  3.1415926535;

// just some conversion to more coordinate alias naming... not that it helps get it right.
y = legheight;
x = (legtopradius * 2 - legbotradius)/2;

echo( "x=", x, "y=",y);

echo("tan= " , 90-atan(y/x));

//rotate so it is print ready
rotate([90,0,0])
{
    difference(){
        returnfork("yes");

        //Produce Flat surface to print
        translate([Head_Width ,-Head_Thick +.1,0])
        cube([Head_Width *3 ,Head_Thick, legheight * 2 + Head_Hgt], center = true);

    }
    if (withsize=="yes")labelsize();
}
    //add text to top
module labelsize(){
    translate([Head_Width/2, Head_Thick/2 ,legheight/2 - Head_Hgt/2 ])
    rotate([90,0,180])
    linear_extrude( .5 )
     text(str(Head_Width,  "x", legheight , "" )  ,size=5,font="Century Gothic:style=Bold", halign="center",valign="center");
}

module addtooths(){
    if (withteeth == "yes"){

       startoffset = (legheight * first_tooth_percent_high) / 2 ;
       toothstep = (startoffset +  (legheight/2 -Head_Hgt))  / tooth_qty;
           start_thick = (legtopradius - legbotradius) * first_tooth_percent_high ;
            echo ("startoffset= ", startoffset, " toothstep=", toothstep, " start_thick=", start_thick);

      //loop through printing teeth
      for (i = [1 : tooth_qty ]){

          // next thick =
            echo("x=",legtopradius, " y=", -(start_thick - (start_thick * i / tooth_qty ) +legbotradius)  , " z=", startoffset -Head_Hgt - (toothstep * i));

         // atemtp to auto calculate depth
        //   translate([legtopradius, -(start_thick - (start_thick * i / tooth_qty ) +legbotradius) , startoffset -Head_Hgt - (toothstep * i) ])

         // just set the tooth to the bottom?... but it will move... so set it deep
            translate([legtopradius, -Head_Thick/2 -.1 , startoffset -Head_Hgt - (toothstep * i) ])
        // translate([0,0, startoffset -Head_Hgt - (toothstep * i) ])
           rotate([-90,-30,-0])
           cylinder(r= (start_thick*2 * (tooth_qty - i) / tooth_qty  +legbotradius) * tooth_percent  , h= tooth_thick , $fn=3, center=false);

          // cylinder(r= start_thick * (tooth_qty - i) / tooth_qty * tooth_percent   , h= tooth_thick , $fn=3, center=false);
      }
    }

}

module returnfork(hole_in_center = "no"){
    //top cube
    translate([Head_Width/2 -0 ,0,legheight/2 - Head_Hgt/2])
    cube([Head_Width,Head_Thick,Head_Hgt], center=true);

    // get the top of leg distance to the side from its center
    leg_center_to_side = legtopradius * cos( pi * 6);   // 6 is sides in a hex

    echo("leg_center_to_side=", leg_center_to_side);
    //leg1
    translate([ legtopradius  ,  -(Head_Thick - legtopradius)/2  , -Head_Hgt  ])
    rotate([leg_rotation,0,0])
    cylinder(h=legheight, r1= legbotradius, r2=legtopradius, $fn=6, center=true);

    //leg2
    translate([Head_Width - legtopradius , -(Head_Thick - legtopradius)/2 ,-Head_Hgt])
    rotate([leg_rotation,0,0])
    cylinder(h=legheight, r1= legbotradius, r2=legtopradius, $fn=6, center=true);

    //finger pull
    translate([Head_Width/2 -0 ,0 ,legheight/2 + Head_Hgt/2])
    rotate([90,0,0])
    difference(){
             cylinder(h=finger_thick, r= finger_radius, $fn=905, center=true);

       if(hole_in_center=="yes"){

           translate([0, 0,- finger_thick * .25])
                cylinder(h=finger_thick* .75, r1= finger_radius * .95, r2=finger_radius * .5, $fn=45, center=true);
                 cylinder(h=finger_thick* 1.1, r=finger_radius * .5, $fn=45, center=true);

            }else{
            translate([0, 0,- finger_thick * .25])
            cylinder(h=finger_thick * .75, r1= finger_radius * .95, r2=finger_radius * .5, $fn=45, center=true);
        } //if
    }// diff

    rotate([leg_rotation,0,0])
    addtooths();

    //add second ite
    translate([Head_Width - legtopradius * 2 ,0, 0])
   rotate([leg_rotation,0,0])
    addtooths();

}

```


[User]
Hey, I'm looking to design a chainring guide for my bike, and I'd like to use OpenSCAD to make it parametric so I can tweak it for different setups. I've got some general ideas and measurements to start with, and I'd like the ability to customize it further through a customizer.

Here's what I have in mind:

**Core Structure:**

*   It should have a main circular plate with a certain thickness.
*   There should be a cutout in the center of the plate, creating a kind of wall.
*   I want to be able to specify the outer diameter of the plate, and the inner diameter of the cutout.
*   I'd like to specify how thick the main plate should be.
*   The main plate should sit flush on the chainring and chain, and a cylinder of a specific depth will act as a guide for the chain.

**Arms:**

*   The design will include several arms extending inward from the main plate's inner edge to help guide the chain.
*   I'd like to control the number of arms.
*   Each arm should have a variable width at the outer edge (where it meets the main plate) and a variable width at the inner edge where the arm ends.
*   I'll need to control the length of the arms, and the position at which the arms are attached to the plate wall.
*   Each arm should have a screw hole at the inner edge. I should be able to control the radius of this hole, or remove them entirely by setting the radius to zero.
*   I'd also like to include holes for zip ties on each arm. I should be able to remove them by setting the zip tie dimensions to zero. I should be able to control the width and height of these zip tie holes. They should be located at the inner edge of the arm.

**Customization:**

*   All dimensions should be easily adjustable through the OpenSCAD customizer.
*   The design should be easy to print with no supports needed, so it should be designed with that in mind.
*   I'd like to specify how far away the mounting should be from the outer edge.

I think that about covers everything for now. I am a little new to OpenSCAD, so if you could generate a single file that uses the built-in OpenSCAD libraries for basic shapes, that would be great! Let me know if you need more info or clarification.

[Assistant]
chainring_guard_v105.scad:
```

// fn resolution
$fn=100; //[100:360]

/* [Arm Settings] */
// the number of arms
armCount = 5; // [3:8]
// the width of the arm closer to the edge
armWidth1 = 10;
// width of the arm closer to the centre
armWidth2 = 7;
// the length of the arm in mm + armWidth1/2 + armWidth2
armLength=10;

// screw hole size. 0 to remove screw holes
screwHoleRadius = 2;

// zip tie holes.  0 to remove zip tie holes
zipTieWidth = 3;
zipTieHeight = 2;

/* [Plate Settings] */
// how thick is the main plate
plateThickness = 2.4;
// the diameter of the main plate radius
outerPlateDiameter = 176/2;
// the cutout for the inside radius of the main plate.  outerplatediameter - innerplatediameter = how tall the wall is
innerPlateDiameter = 140/2;
// how far away the mounting should be from the outer edge
insetDepth=5;

// --------------- CODE ----------------------
rotationAngle = 360/armCount;

// plate wall
Plate(thickness=plateThickness, id=innerPlateDiameter, od=outerPlateDiameter);

// inset ring so actually support the chain
difference(){
    cylinder(h=insetDepth, r=(innerPlateDiameter + plateThickness ) );

    // cutout
    translate([0,0,-1])
        CutOut(t=plateThickness, id=innerPlateDiameter);

}

// draw the arms
DrawArms();

//----------------- MODULES --------------------

module Plate(thickness, id, od)
{
// outer plate
difference(){
        cylinder(h=thickness, r=od );

        // cutout
        translate([0,0,-1])
            CutOut(t=thickness, id=id);
    }
}

module CutOut(t, id)
{
    cylinder(t+ 50, r=id);
}

module DrawArm()
{
    difference ()
    {
        hull(){
            cylinder(h=insetDepth, r=armWidth1);

            translate([0,-(armLength) - armWidth2,0])
                cylinder(h=insetDepth, r=armWidth2);
        }

        // screw hole
        translate([0,-(armLength) - armWidth2,-1])
            cylinder(h=insetDepth + 50, r=screwHoleRadius, center=true );

        // ziptie hole
        translate([-250,-(armLength) - armWidth2 - zipTieWidth/2,(insetDepth)/2 - zipTieHeight/2] )
            cube([500, zipTieWidth, zipTieHeight]);

    }

}

module DrawArms()
{
    difference(){
        for(i = [0 : armCount])
            rotate(i * rotationAngle)
                translate([0, innerPlateDiameter,0])
                    DrawArm();

        Plate(thickness=insetDepth, id=innerPlateDiameter, od=outerPlateDiameter);
    }
}

```


[User]
I'm looking to create a customizable shelf system, similar to the "Riser Shelf (Customizable)" design on Thingiverse (ID 4217583).  I need an OpenSCAD file that allows me to adjust the overall length, the width of each shelf, the height of each step, the wall thickness, and the number of shelves.

Here are the specific parameters I need to control:

*   **Total Length:**  The total length of the shelf unit.
*   **Shelf Width:** The width of each individual shelf.
*   **Shelf Height:** The vertical height of each step between shelves.
*   **Wall Thickness:** The thickness of the material used for the vertical supports and shelves.
*   **Number of Shelves:** The total number of shelves/steps in the unit.

I'm imagining a stepped design where each shelf is supported by vertical walls at either end. The lowest shelf would be resting directly on the bottom surface. The shelves should all be the same width and the steps should all be the same height. All of the vertical walls should be the same thickness. I want to be able to change all of these parameters within OpenSCAD.

Could you generate the OpenSCAD code for this?

[Assistant]
shelf_customizer.scad:
```
//Total length of shelf
length = 200; // [50:10:300]
//Width of each shelf
shelf_width = 30; // [15:5:60]
//Height of each step
shelf_height = 25; // [10:5:60]
//Wall thickness
thickness = 5; // [2:.5:10]
//Number of steps
num_shelves = 3; // [2:1:6]

cube([length,thickness,shelf_width]);
translate([0,thickness,0]) {
    cube([thickness,shelf_height - thickness,shelf_width]);
}

translate([length - thickness,thickness,0]) {
    cube([thickness,shelf_height - thickness,shelf_width]);
}

for (i = [2:num_shelves]) {
    x = (i-1)*shelf_height+thickness;
    y = shelf_width*(i-1);
    y2 = y + thickness;
    z = shelf_height - thickness;
    translate([0, (i-1)*shelf_height ,0]) {
        cube([length,thickness,i*shelf_width]);
    }

    translate([0,x,0]) {
        cube([thickness,z,i*shelf_width]);
    }

    translate([length-thickness,x,0]) {
        cube([thickness,z,i*shelf_width]);
    }
}

```


[User]
Hi, I'm looking to design a smartphone holder that attaches to a shopping cart. I have a basic idea of what I want, and I'd like to create it using OpenSCAD. I want it to be parametric, so I can easily adjust it for different phone sizes and shopping cart bar diameters.

The holder should consist of two main parts: a phone box that cradles the phone, and a cart clip that attaches to the shopping cart bar. The phone box should have a hinge so it can tilt. The cart clip should attach to the phone box.

Here are some parameters I want to control:

*   **`smartphone_width`**: The width of the smartphone.
*   **`smartphone_thickness`**: The thickness of the smartphone.
*   **`height`**: The overall height of the holder.
*   **`cart_grid_dia`**: The diameter of the metal bar on the shopping cart.
*   **`wall`**: The thickness of the walls of the holder.
*  **`extra_wall_width`**: Extra width on the sides of the cart clip for stability.

I'm also going to need a few "expert" parameters to control some internal aspects. These can probably have default values if they aren't changed.
*   **`phone_clip_gap`**: The gap between the phone box and the cart clip. This will also be used for the joint axis.
*   **`generic_chamfer`**: A general-purpose chamfer for inner cutouts.
*   **`stop_chamfer`**: A chamfer used to fix the smartphone holder at a certain angle.
*   **`mini_chamfer`**: A small chamfer for some outside edges.

The phone box should have rounded corners. It will be important to have the correct axis of rotation between the phone holder and the cart clip.

The cart clip needs to securely grip the shopping cart bar. I think an arch-like design with a cutout would work. I want a small stop chamfer to provide some stability.

I'm also going to need a few derived values, as in the original project:
*   **`axis_dia`**: diameter for the joint axis
*   **`axis_z`**: position of the joint axis
*   **`lhcc`**: lower height cart clip
*   **`lhpb`**: lower height phone box

For the modules, I need:
* **`ChamferZCube(w=1,h=10, d=0)`**: cube which can be used to chamfer along the z axis
* **`ChamferXCube(w=1,h=10, d=0)`**: cube which can be used to chamfer along the x axis
* **`ChamferYCube(w=1,h=10, d=0)`**: cube which can be used to chamfer along the y axis
*   **`CenterCube(dim, ChamferBody = 0, ChamferBottom=0, ChamferTop=0)`**: A cube which is centered along the z axis but is placed on the z=0 plane. This should have optional chamfering.
*   **`Archoid(r=10, b=20, l=30)`**: A chest-like element with a half-cylinder on top, used for the cart clip.
*   **`TriangularPrism(bottom = [10,10], h=7, fh=0, fd=0)`**: A triangular prism, used for the stop chamfer.
*  **`copy_mirror(vec=[0,1,0])`**: A module to copy and mirror elements
*   **`phone_box()`**: A module to generate the phone box
*   **`cart_clip()`**: A module to generate the cart clip

Finally, I want to assemble these with a `union` module at the end, and rotate the cart clip along the X-axis so it connects to the phone holder.

I think I've provided all the details needed for this. Could you generate the necessary OpenSCAD code for me? I'd prefer that you not use any external libraries. Let me know if you need more details.

[Assistant]
shopping_cart_smartphone_holder.scad:
```
/*

  shopping_cart_smartphone_holder.scad

  (c) olikraus@gmail.com

  This work is licensed under the Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License.
  To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-sa/4.0/.

  8 Nov 2021 (https://github.com/olikraus/scad/issues/1)
    - Make cart clip side walls thicker (add 1 mm on both sides)
    - Increase height as suggested in the thingiverse comments (63-->65)

  16 Jan 2022
    - Increased stop champfer (4.6 --> 5.0)
    - Increased stability of cart holder stopper (extra big champfer)

*/

/* [basic] */

// Width (in mm) of the smartphone. Add 1 or more millimeters here.
smartphone_width = 83;

// Thickness (in mm) of the smartphone. Add 1 to 3 millimeters.
// This value must be between 13 and 20
smartphone_thickness = 14;

/* [advanced] */

// Height (in mm) of the shopping cart holder
height = 65;

// Diameter of the metal bar of the shopping cart
// Defaults to 11 mm
cart_grid_dia = 11;

// Wall width (in mm), should be thin enough to bend the material and thick enough to be stable
wall = 2;

// Extra width for the side walls of the card clip
// this can be between 0 and 2 mm
extra_wall_width = 1;

/* [expert] */

// Gap between the phone box and the cart clip. Half this value for each side. Also used for the joint axis.
phone_clip_gap = 1;

// Generic_chamfer (in mm), used for inner cut outs
generic_chamfer = 1;

// Stop_chamfer / triangle which fixes the smartphone holder at a specific angle
stop_chamfer = 5.0;

// Small chamfer (in mm), which is used for some outside walls
mini_chamfer = 0.5;

/* [hidden] */

$fn=32;

extra_wall_radius = 4;

/* more or less derived values */
axis_dia = smartphone_thickness-5;  // diameter for the joint axis
axis_z = axis_dia/2+wall*2;  // position of the joint axis
lhcc = 20;    // lower height cart clip
lhpb = lhcc-wall*1.5;    // lower height phone box

/*
n = 3;
nstep = smartphone_width / n;
nfirst = nstep / 2;
nwidth = nstep - 10;
*/

/*
  ChamferZCube(w=1,h=10)

  A cube, which can be used to chamfer along the z axis

  Args:
    w: The width of the cube is sqrt(2)*w
    h: Height of the cube
    d: The cube has a descent below z=0 plane and an ascent beyond h by this value
  Notes:
    The cube is centered around z-axsis and placed on z=0 plane.

*/
module ChamferZCube(w=1,h=10, d=0) {
  translate([0,0,h/2])
  rotate([0,0,45])
  cube([sqrt(2)*w,sqrt(2)*w,h+2*d], center=true);
}

module ChamferXCube(w=1,h=10, d=0) {
  rotate([45,0,0])
  cube([h+2*d,sqrt(2)*w,sqrt(2)*w], center=true);
}

module ChamferYCube(w=1,h=10, d=0) {
  rotate([0,45,0])
  cube([sqrt(2)*w,h+2*d,sqrt(2)*w], center=true);
}

/*
  CenterCube(dim, ChamferBody = 0, ChamferBottom=0, ChamferTop=0)

  A cube which is centered along z axis but is placed on z=0 plane
  Optionally allows chamfer along z axis.

  Args:
    dim: Same as for cube(dim)
    ChamferBody: The amount to chamfer for edges parallel to z axis
    ChamferBottom: The amount to chamfer for edges in z=0 plane
    ChamferTop: The amount to chamfer for edges in z=dim[2] plane
  Example:
    CenterCube([10, 20, 5]);

    // create a rectangle bowl
    // thanks to chamfer no support is required with 3d print
    difference() {
      wallthickness=2;
      xwidth = 10;
      ywidth = 20;
      height = 5;
      CenterCube(
        [xwidth+2*wallthickness, ywidth+2*wallthickness, height],
        ChamferBottom = wallthickness);
      translate([0,0,wallthickness])
      CenterCube([xwidth,ywidth,height]);
    }

*/

module CenterCube(dim, ChamferBody = 0, ChamferBottom=0, ChamferTop=0) {
  difference() {
    translate([0,0,dim[2]/2])
    cube(dim, center=true);

    if ( ChamferBody > 0 ) {
      translate([dim[0]/2,dim[1]/2,0])
      ChamferZCube(w=ChamferBody,h=dim[2],d=0.01);

      translate([-dim[0]/2,dim[1]/2,0])
      ChamferZCube(w=ChamferBody,h=dim[2],d=0.01);

      translate([-dim[0]/2,-dim[1]/2,0])
      ChamferZCube(w=ChamferBody,h=dim[2],d=0.01);

      translate([dim[0]/2,-dim[1]/2,0])
      ChamferZCube(w=ChamferBody,h=dim[2],d=0.01);
    }

    if ( ChamferBottom > 0 )
    {
      translate([-dim[0]/2,0,0])
      ChamferYCube(w=ChamferBottom,h=dim[1],d=0.01);

      translate([dim[0]/2,0,0])
      ChamferYCube(w=ChamferBottom,h=dim[1],d=0.01);

      translate([0,-dim[1]/2,0])
      ChamferXCube(w=ChamferBottom,h=dim[0],d=0.01);

      translate([0,dim[1]/2,0])
      ChamferXCube(w=ChamferBottom,h=dim[0],d=0.01);
    }

    if ( ChamferTop > 0 )
    {
      translate([-dim[0]/2,0,dim[2]])
      ChamferYCube(w=ChamferTop,h=dim[1],d=0.01);

      translate([dim[0]/2,0,dim[2]])
      ChamferYCube(w=ChamferTop,h=dim[1],d=0.01);

      translate([0,-dim[1]/2,dim[2]])
      ChamferXCube(w=ChamferTop,h=dim[0],d=0.01);

      translate([0,dim[1]/2,dim[2]])
      ChamferXCube(w=ChamferTop,h=dim[0],d=0.01);
    }

  }
}

/*
  Archoid(r=10, b=20, l=30)

  A chest like element with a half cylinder on the top
  and a box as a base.
  If used with difference, the result is a archway.

  Args:
    r: Radius of the half-cylinder
    b: height of the base block
    l: length of the chest in x direction.
    $fn: resolution of the half cylinder
  Notes:
    The width of the chest is 2*r, the height is b+r.
    Archoid(r=10, b=20, l=30, $fn=4) becomes a house.

*/
module Archoid(r=10, b=20, l=30) {
  union() {
    translate([0,0,b])
    difference() {
      rotate([0,90,0])
      cylinder(r=r,h=l,center=true);
      translate([0,0,-r])
      cube([2*l,2*l,2*r], center=true);
    }
    translate([0,0,b/2])
    cube([l,2*r,b+0.01], center=true);
  }
}

/*
  TriangularPrism(bottom = [10,10], h=7, fh=0, fd=0)

  Args:
    buttom: Bottom square (width, height)
    h: Distance of the top square/peak to z=0 plane
    fh: front height (lowest x)
    fd: triangle peak as offset from the lowers x position
  Notes:
    The bottom square is placed in the z=0 plane.
    The square is centered around z axis.
  Example:
    TriangularPrism(bottom = [10,10], fh=0, h=7, fd=0);
      This is a ramp with, the triangle peak is at -5
    TriangularPrism(bottom = [10,10], fh=0, h=7, fd=5);
      A real triangular prism, the peak is at x=0
    TriangularPrism(bottom = [10,10], fh=7, h=7, fd=5);
      The ramp goes from x=5 to x=0.
      There is another top square from x=0 to x=-5
*/

module TriangularPrism(bottom = [10,10], h=7, fh=0, fd=0)
{
  lx = bottom[0];
  ly = bottom[1];
  p = [
    [ -lx/2, -ly/2,  0 ],  //0
    [ lx/2,  -ly/2,  0 ],  //1
    [ lx/2,  ly/2,  0 ],  //2
    [ -lx/2,  ly/2,  0 ],  //3
    [ -lx/2, -ly/2,  fh ],  //4
    [ -lx/2+fd,  -ly/2,  h ],  //5
    [ -lx/2+fd,  ly/2,  h ],  //6
    [ -lx/2,  ly/2,  fh ]]; //7

  f = [
    [0,1,2,3],  // bottom
    [4,5,1,0],  // front
    [7,6,5,4],  // top
    [5,6,2,1],  // right
    [6,7,3,2],  // back
    [7,4,0,3]]; // left
  polyhedron( p, f );
}

module copy_mirror(vec=[0,1,0]) {
    children();
    mirror(vec)
    children();
}

module phone_box() {
  translate([0,0,-axis_z])
  difference() {
    CenterCube([smartphone_width+2*wall, smartphone_thickness+2*wall, height],
      ChamferBody=mini_chamfer,ChamferTop=mini_chamfer);
    translate([0,0,wall])

    CenterCube([smartphone_width, smartphone_thickness, height],
              ChamferBody = generic_chamfer, ChamferBottom=generic_chamfer, ChamferTop=generic_chamfer
    );
    //translate([0,-wall-0.01,lh])
    //CenterCube([smartphone_width, smartphone_thickness, height]);

    translate([0,-wall+0.01-smartphone_thickness,lhpb])
    CenterCube([smartphone_width+2*wall+0.02, smartphone_thickness+2*wall, height]);
    translate([0,0,wall])

    translate([0,-wall+0.01-smartphone_thickness/2,lhpb-wall])
    CenterCube([smartphone_width, smartphone_thickness+2*wall, height]);
    translate([0,0,wall])

    translate([0,0,axis_z])
    rotate([0,90,0])
    cylinder(d=axis_dia, h=smartphone_width+2*wall+0.01, center=true);

    for( z=[5:6.5:(height-5)] ) {
      for( x=[-(smartphone_width-10)/2:(smartphone_width-10)/10:(smartphone_width-10)/2] ) {
        translate([x,smartphone_thickness/2,z])
        rotate([90,0,0])
        cylinder(d=5, h=wall*3, center=true, $fn=16);
      }
    }
    for( z=[5:6.5:(lhpb-5)] ) {
      for( x=[-(smartphone_width-10)/2:(smartphone_width-10)/10:(smartphone_width-10)/2] ) {
        translate([x,-smartphone_thickness/2,z])
        rotate([90,0,0])
        cylinder(d=5, h=wall*3, center=true, $fn=16);
      }
    }
  }
}

module cart_clip() {
  height_correction = 1;
  translate([0,0,-axis_z])
  union() {
    difference() {
      union() {
        difference() {
          /* not sure why, but the clip is a little bit to high, so remove 1 mm from height */
          CenterCube([smartphone_width+4*wall+2*extra_wall_width+phone_clip_gap, smartphone_thickness+2*wall, height-height_correction], ChamferTop=mini_chamfer);

          /* remove inner lower block */
          translate([0,0,-0.01])
          CenterCube([smartphone_width+2*wall+phone_clip_gap, smartphone_thickness+0*wall, lhcc+0.02]);

          /* remove inner upper block */
          translate([0,5,lhcc+wall])
          /* generic_chamfer */
          /* generic_chamferBody = 0, generic_chamferBottom=0, generic_chamferTop=0 */
          CenterCube([smartphone_width+2*wall+phone_clip_gap, smartphone_thickness+0*wall+10, height+0.02],
            ChamferBody = generic_chamfer, ChamferBottom=generic_chamfer+3, ChamferTop=generic_chamfer);

          /* remove full front wall */
          translate([0,smartphone_thickness-0.01,-0.01])
          CenterCube([smartphone_width+2*wall+phone_clip_gap, smartphone_thickness+0*wall, height+0.02]);

          /* remove lower back wall */
          translate([0,+wall-smartphone_thickness,-height+lhcc])
          CenterCube([smartphone_width+2*wall+phone_clip_gap, smartphone_thickness+0*wall, height+0.02]);

          translate([0,generic_chamfer-smartphone_thickness+3,lhcc+wall])
          CenterCube([smartphone_width-16,smartphone_thickness, height-lhcc-cart_grid_dia ]);
          /*
          for( x=[nfirst:nstep:smartphone_width] ) {
            translate([x-smartphone_width/2,-smartphone_thickness/2-wall,0])
            cylinder(d=smartphone_thickness*1.5, h=height-cart_grid_dia-4+0.01);
            //CenterCube([nwidth, smartphone_thickness*1.2, height-cart_grid_dia-4+0.01]);
          }
          */

        }
        translate([0,smartphone_thickness/2-stop_chamfer/2,lhcc])
        rotate([180,0,0])
        rotate([0,0,90])
        TriangularPrism(bottom = [stop_chamfer,smartphone_width], h=stop_chamfer, fh=0, fd=stop_chamfer/2);

      } // union

      /* Create slide in gap for phone_box */
      copy_mirror([1,0,0])
      translate([(smartphone_width)/2+wall-stop_chamfer/2+phone_clip_gap/2,wall,-0.01])
      CenterCube([stop_chamfer, smartphone_thickness+2*wall, height+0.02], ChamferBody=generic_chamfer);

      /* shopping cart connection */

      translate([0,-1,height-height*0.33-cart_grid_dia])
      Archoid(r=cart_grid_dia/2, b=height*0.3,l=smartphone_width+4*wall+2*extra_wall_width+phone_clip_gap+0.01);

      translate([0,-smartphone_thickness/2,height-height*0.33-cart_grid_dia])
      CenterCube([smartphone_width+4*wall+2*extra_wall_width+phone_clip_gap+0.01, smartphone_thickness+0*wall, 9]);

      /* remove the wall extra thickness from the lower part of the chart clip */

      copy_mirror([1,0,0])
      translate([-(smartphone_width+4*wall+phone_clip_gap+2*extra_wall_radius+2*extra_wall_width)/2+extra_wall_width,0,0])
      rotate([0,0,90])
      Archoid(r=extra_wall_radius, b=lhcc,l=smartphone_thickness+2*wall+0.01);

    }

    /* lower axis */

    difference() {
      /* phone_clip_gap/2 shift is an experimental value */
      translate([0,phone_clip_gap/2,axis_z+phone_clip_gap/2])
      rotate([0,90,0])
      cylinder(d=axis_dia-phone_clip_gap, h=smartphone_width+4*wall+phone_clip_gap+0.01, center=true);

      translate([0,0,-0.01])
      CenterCube([smartphone_width-3, smartphone_thickness+0*wall, lhcc+0.02]);

      copy_mirror([1,0,0])
      translate([0,-(smartphone_thickness+2*wall)/2,(smartphone_thickness+2*wall)/2])
      rotate([-90,0,0])
      translate([smartphone_width/2-0.5,0,0])
      TriangularPrism(bottom = [4,smartphone_thickness+2*wall], h=smartphone_thickness+2*wall, fh=0, fd=0);
    }

    /* upper enforcement */
    translate([0,-smartphone_thickness/2,height-2*wall-1])
    rotate([0,90,0])
    cylinder(r=wall, h=smartphone_width-4*wall, center=true);

  }

}

/*
difference() {
  union() {
    phone_box();
    rotate([37,0,0])
    cart_clip();
  }
  translate([-50,0,0])
  cube([50, 100, 100], center=true);
}
*/

translate([0,0,axis_z])
union() {
translate([0,1.7*smartphone_thickness,0])
phone_box();

translate([0,0,-(axis_z-(smartphone_thickness+2*wall)/2)])
rotate([90,0,0])
cart_clip();
}

```


[User]
I'd like to design a dust collection funnel that can be integrated into a workbench. I need it to have a few parts: the funnel itself, a lid, and a sieve that fits inside. I’m aiming for a parametric design so I can easily adjust the dimensions later.

Here's what I'm thinking for the funnel:

*   It should have a rectangular opening at the top, with parameters for `funnel_width` and `funnel_length`. I need to also specify a `funnel_border_thikness` to define the thickness of that top part.
*   The funnel should transition to a circular tube at the bottom, with a `dust_collection_diam` for the diameter of the circular opening, and a `tube_length` for how long that tube extends downward.
*   There will be a `funnel_height`, which controls the height of the transition piece between rectangular opening and the tube.
*   I’d like a `funnel_border` which will extend from the top edges of the funnel, creating a lip for the whole thing.
*   I want to be able to specify the screw type I'll use to mount the funnel; this will change the size and dimensions of the screw holes on the funnel. It needs to be a choice between: M3.5, M3.8, M4.2, or M4.8. I should call this `screw_type` and use an enum for those options.

For the lid:

*   The lid should have the same rectangular dimensions as the top of the funnel.
*   It should have a `lid_top_thikness` for its overall height, as well as a step that fits into the funnel opening that is `lid_step_height`.

And the sieve:

*   The sieve should also fit inside the top of the funnel and have the same rectangular dimensions as the lid (minus the lip that extends out).
*   It should have a `sieve_height`.
*   It needs to have holes across its surface, defined by a `sieve_hole_radius`. I should be able to change the size of these.

I’d like to be able to select which part is rendered with a `part` variable, choosing between "funnel," "lid," "sieve," or "all" for displaying all parts together in their relative positions.

Could you create an OpenSCAD file for this? I would like to be able to easily adjust any of the above parameters. I think this might use functions and modules for each of the parts, and I believe `polyhedron` would be useful for the transition of the funnel. I don't think you'll need any external libraries for this.

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

// Which one would you like to see?
part = "all"; // ["funnel":"Funnel Only",lid:"Lid Only","sieve":"Sieve Only","all":"All parts"]

/* [All] */
funnel_width = 50;//[10:100]
funnel_length=200;//[10:250]
funnel_border_thikness=4;//[2:8]
/* [Funnel] */
funnel_border=20;//[10:30]
dust_collection_diam = 50;//[35,50,63,100]
funnel_height=20;//[10:100]
tube_length=50;//[10:200]
screw_type=1;//[1:"M3,5",2:"M3,8",3:"M4,2",4:"M4,8"]
/* [Lid] */
lid_top_thikness=4;//[2:8]
lid_step_height=4;//[2:8]
/* [Sieve] */
sieve_hole_radius=2.5;//[2.0:10.0]
sieve_height = 4;//[2:10]

function point_x(a=0,s=0)=(dust_collection_diam-s)/2*cos(a);
function point_y(a=0,s=0)=(dust_collection_diam-s)/2*sin(a);
/* [Hidden] */
point_0_a=225;
point_1_a=315;
point_2_a=45;
point_3_a=135;
sides=360;

CubePoints = [
  [  point_x(point_0_a),point_y(point_0_a),  tube_length ],  //0
  [ point_x(point_1_a),  point_y(point_1_a),  tube_length ],  //1
  [ point_x(point_2_a),  point_y(point_2_a),  tube_length ],  //2
  [  point_x(point_3_a),  point_y(point_3_a),  tube_length ],  //3
  [  -funnel_length/2,  -funnel_width/2,   tube_length+funnel_height ],  //4
  [ funnel_length/2,  -funnel_width/2,  tube_length+funnel_height ],  //5
  [ funnel_length/2,  funnel_width/2,  tube_length+funnel_height ],  //6
  [ -funnel_length/2,  funnel_width/2,  tube_length+funnel_height ]]; //7

CubeFaces = [
  [0,1,2,3],  // bottom
  [4,5,1,0],  // front
  [7,6,5,4],  // top
  [5,6,2,1],  // right
  [6,7,3,2],  // back
  [7,4,0,3]]; // left

  print_part();

module print_part() {
	if (part == "funnel") {
        highlight("Funnel");
		ReadyFunnel();
	} else if (part == "lid") {
        highlight("Lid");
		Lid();
	} else if (part == "sieve") {
        highlight("Sieve");
		Sieve();
	} else {
		All();
	}
}
  module All()
{
    ReadyFunnel();
  translate([0,funnel_width+20,0])
  {
     Lid();
  }
   translate([0,-funnel_width-20,0])
  {

      Sieve();
  }

}
 module ReadyFunnel(){
     union(){
  difference(){

      Funnel();
      scale([0.98,0.9,1]){Funnel(false);}
  FunnelHole(funnel_length-15);
      FunnelHole(-funnel_length+15);

  }
  FunnelBorder();
  }
  }
  module FunnelBorder(){
  translate([0,0,tube_length+funnel_height+funnel_border/2]){
      difference(){
  cube([funnel_length,funnel_width,funnel_border], center=true);
          cube([funnel_length-funnel_border_thikness,funnel_width-funnel_border_thikness,funnel_border], center=true);
      }
  }
  }

  module Lid(){
       cube([funnel_length,funnel_width,lid_top_thikness], center=true);
      translate([0,0,lid_top_thikness])
      {
              cube([funnel_length-funnel_border_thikness,funnel_width-funnel_border_thikness,lid_step_height], center=true);
      }
      }
module Sieve(){
     difference(){
      color("red"){
      cube([funnel_length-funnel_border_thikness,funnel_width-funnel_border_thikness,sieve_height], center=true);
      }
          translate([-(funnel_length-funnel_border_thikness)/2,-(funnel_width-funnel_border_thikness)/2,0]){
          for( i=[1:1:floor((funnel_length-funnel_border_thikness)/(sieve_hole_radius*3))])
          {
              for( j=[1:1:floor((funnel_width-funnel_border_thikness)/(sieve_hole_radius*3))-1]){
                  if((i+1)*(sieve_hole_radius*3)<(funnel_length-funnel_border_thikness)){
                      if((j+1)*(sieve_hole_radius*3)<(funnel_width-funnel_border_thikness)){
              translate([i*(sieve_hole_radius*3),j*(sieve_hole_radius*3),0])
              {

                  cylinder(h=sieve_height,r1=sieve_hole_radius,r2=sieve_hole_radius,center=true,$fn=sides);
              }
          }
          }
          }
          }
     }
      }
    }

module Funnel(flaps=true){
    union(){
polyhedron( CubePoints, CubeFaces );
if(flaps){
Flap(funnel_length-30);
Flap(-funnel_length);  }
cylinder(h=tube_length+funnel_height, r1=dust_collection_diam/2, r2=dust_collection_diam/2,$fn=sides);
      }
    }
module Flap(leng){
    translate([leng/2,-funnel_width/2,tube_length+funnel_height-5]){
    cube([15,funnel_width,5]);
    }
    }
module FunnelHole(leng)
{
   translate([leng/2,0,tube_length+funnel_height]){
          if(funnel_width<27)
            {
                Hole(screw_type,funnel_height+1);
            }else{
                y = (funnel_width-3*9)/2;
                x=9/2+y/2;
                translate([0,x,0.2]){
                    Hole(screw_type,funnel_height+1);
                }
                translate([0,-x,0.2]){
                    Hole(screw_type,funnel_height+1);
                }
            }
          }
}

module Hole(screw_type,depth)
{
    translate([0,0,-depth]){
    if(screw_type==1){
        diam=3.6;
    cylinder(h=depth-6, r1=diam/2,r2=diam/2,$fn=sides);

    translate([0,0,depth-6.2])
    {
        cylinder(h=6.2, r1=diam/2, r2=9/2,$fn=sides);
    }
}
if(screw_type==2){
        diam=4;
    cylinder(h=depth-6, r1=diam/2,r2=diam/2,$fn=sides);

    translate([0,0,depth-6])
    {
        cylinder(h=6.2, r1=diam/2, r2=9/2,$fn=sides);
    }
}
if(screw_type==3){
        diam=4.4;
    cylinder(h=depth-6, r1=diam/2,r2=diam/2,$fn=sides);

    translate([0,0,depth-6])
    {
        cylinder(h=6.2, r1=diam/2, r2=9/2,$fn=sides);
    }
}
if(screw_type==4){
        diam=5;
    cylinder(h=depth-6, r1=diam/2,r2=diam/2,$fn=sides);

    translate([0,0,depth-6])
    {
        cylinder(h=6.2, r1=diam/2, r2=9/2,$fn=sides);
    }

}}
}

```


[User]
I'm looking to create a customizable hook system for my keyhole shelving unit, similar to the one I have, but I need it to be more flexible. I have a basic design in mind, but I want to make it fully parametric, and I'd like to be able to adjust lots of different measurements so that I can fine-tune it for different situations.

Here’s what I envision:

**Core Functionality:**

*   The design needs to have mounting hooks that fit into the keyhole slots of standard shelving units. I'd like to specify how many mounting hooks there are, as well as the distance between them.
*   I need the system to include hanging hooks that extend outwards to hang items. The number of these, their spacing, how far they extend out, and their thickness should all be customizable. Also, the position of the hanging hooks between the mounting hooks is important. It'd be great if I could set this as a ratio of the mounting hook spacing, so it can easily be adjusted.
*   I want to be able to set the overall thickness of the hook, the width of the hook, and the height of the hook.
*   I'd also like to be able to set the thickness of the shelving metal so I get a snug fit.

**Parametric Requirements:**

*   **Mounting Hooks:**
    *   Number of mounting hooks.
    *   Distance (pitch) between mounting hooks.
    *   Width of the mounting slot.
    *   Thickness of the shelving sheet metal.
    *   How far the mounting hook tab hangs down.
    *   Thickness of the mounting hook itself.
*   **Hanging Hooks:**
    *   Number of hanging hooks.
    *   Distance (pitch) between hanging hooks.
    *   Height of the outer section of the hanging hook.
    *   Thickness of the hanging hook.
    *   Width of the hanging hook.
    *   The position of the first hanging hook relative to the mounting hooks, specified as a ratio (e.g., 0.25 would place it a quarter of the way up between the mounting hooks).
*   **General Dimensions:**
    *   Thickness of the entire hook structure.
    *   Height of the hook itself.

**File Structure:**

I think it would be useful to have everything in one `.scad` file, but using modules so that I can easily re-use the mounting hook and the hanging hook structures.

**Details:**

*   The mounting hook should have a circular section that fits into the keyhole, with rectangular sections to grip onto the shelf.
*   The hanging hook should have a rounded base, a straight section and rounded outer section.
*   I'd like to have a single, solid body, joining all the hooks together using the main thickness.
*   I don’t need the mounting hooks to be joined with anything.

Would it be possible to design an OpenSCAD file that does this? I'd prefer not to use any external libraries for this design - I don't think I need any.

[Assistant]
hammerlock-hook.scad:
```
//
// Hook for use with hammerlock shelves
//

/* [Hanging Hook] */

// Thickness of hook, affects strength.
hook_thickness = 6.0; // [2:0.01:10]

// Hook width
hook_width = 15.0; // [2:0.01:50]

// Height of outer section of hanging hook.
hook_extension = 10.0; // [0:0.01:50]

// Number of hanging hooks
hook_count = 1;

// Gap between hanging hooks
hook_pitch = 40.0;

// Position between mounting hooks to place hanging hooks, for first hanging hook, measured from bottom-most position.
hook_offset_ratio = 0.25; // [0:0.01:1]

/* [Shelving Slots] */

// Distance between mounting hooks.
slot_pitch = 32.4545;

// Width of mounting slot. Set a little lower than actual width for a snug fit.
slot_width = 6.0; // [2:0.01:10]

// Thickness of shelving sheet metal, set a litter higher for a good fit.
slot_thickness = 1.3; // [0:0.01:4]

/* [Mounting Hooks] */

// How far mounting hook hangs down, don't make too large otherwise it may not fit in the shelving slot.
mounting_hook_tab_length = 7.0; // [0:0.01:50]
mounting_hook_thickness = 4.0; // [1:0.01:15]
mounting_hook_count = 2;

//
// end of customizable parameters
//

hook_offset = hook_offset_ratio * slot_pitch;

// we'll call this height from now on, since it's printed along the Z axis
height = slot_width;

module hook(width, extension, thickness, height) {
    r_inner = width / 2;
    r_outer = r_inner + thickness;

    translate([r_outer, 0, -height/2]) {
        difference() {
            // outer hook
            cylinder(height, r_outer, r_outer, $fn=50);

            // subtract inside of hook
            translate([0, 0, -0.01]) // avoid z fighting
                cylinder(height + 0.02, r_inner, r_inner, $fn=30);

            // remove top half
            translate([-r_outer, 0, -0.01])
                cube([2 * r_outer, r_outer, height + 0.02]);
        }

        // add hook straight section, outside section
        translate([r_inner, 0, 0])
            cube([thickness, extension, height]);

        // end of hook, make round
        translate([r_inner + thickness/2, extension, 0])
            cylinder(height, thickness/2, thickness/2, $fn=20);
    }
}

// single mounting hook
module mounting_hook (width, sheet_thickness, mounting_hook_thickness) {
    radius = width / 2;
    hook_capture_length =  mounting_hook_tab_length; // from centre

    translate([0, 0, 0])
        rotate([0,90, 0])
            translate([0, 0, -sheet_thickness]) {
                translate([0,0,-mounting_hook_thickness])
                    cylinder(sheet_thickness + 2 * mounting_hook_thickness, radius, radius, $fn=30);

                // inner mount
                translate([-radius, -hook_capture_length - radius, -mounting_hook_thickness])
                    cube([radius * 2, hook_capture_length + radius, mounting_hook_thickness]);

                // outer mount
                translate([-radius, -hook_capture_length - radius, sheet_thickness])
                    cube([radius * 2, hook_capture_length + radius, mounting_hook_thickness]);

                //  covers the top of the cylinders
                translate([-radius, 0, -mounting_hook_thickness])
                    cube([radius * 2, radius, 2 * mounting_hook_thickness + sheet_thickness]);
            }
}

module mounting_hooks (count, pitch) {
    // mounting hooks
    for (i = [0:count - 1]) {
        translate([0, i*slot_pitch, 0])
            mounting_hook(slot_width, slot_thickness, mounting_hook_thickness);
    }

    connecting_bar_length = pitch * (count-1) + 2 * slot_width / 2 + mounting_hook_tab_length;

    // join mounting hooks together using hook thickness
    translate([0, -mounting_hook_tab_length - slot_width / 2, -height / 2])
        cube([hook_thickness, connecting_bar_length, height]);
}

module hanging_hooks (count, pitch) {
    translate([0, hook_offset, 0])
        for (i = [0:count - 1]) {
            translate([0, i * pitch, 0])
                hook(hook_width, hook_extension, hook_thickness, height);
        }
}

mounting_hooks(mounting_hook_count, slot_pitch);
hanging_hooks(hook_count, hook_pitch);

```


[User]
I'd like to design a customizable name tag using OpenSCAD. I need it to be parametric so I can easily change the text and the tag will resize to fit.

Here are the basic requirements:

*   **Text:** The tag should support up to two lines of text. I need to be able to define the text for each line as variables. If only one line of text is provided, the design should adjust appropriately.
*   **Text Size:** The text should be a fixed size, I'm thinking size 6 using "Courier New:style=Bold" font.
*   **Tag Size:** The tag should automatically adjust its length to fit the text, with a small amount of padding on the sides. The height of the tag should adjust if a second line of text is present.
*   **Thickness:** The tag itself should be 2mm thick and the text should be depressed by 1mm.
*   **Hole:** There should be a circular hole at one end of the tag for attaching it to a keyring or lanyard, it should be sized for a 2.5mm radius and it should also adjust its vertical position based on whether one or two lines of text are present.
*   **Padding:** Add padding on the sides of the tag based on the length of the longest text line.
*   **Rounding:** The edges of the tag should be rounded. I'd like you to use `minkowski()` for this effect.

Could you generate the OpenSCAD file(s) for this design? I'm not using any libraries at the moment but I'm open to using them if it makes the code cleaner or easier to maintain.

[Assistant]
Name_Tag.scad:
```
//Text to be printed on the tag
Tag_Text_Line_1 = "John Smith";
Tag_Text_Line_2 = "555-555-5555";
//Render quality
$fn=50;

//find longest line to calculate tag length
longest_text = (len (Tag_Text_Line_1)>len(Tag_Text_Line_2) ? Tag_Text_Line_1 : Tag_Text_Line_2);

//echo (len(Tag_Text_Line_1));
offset = 5.8 + ((len(longest_text)/48)/10);
//echo("offset");
//echo(offset);
tag_length = (len(longest_text)* offset) + 11;
//echo(tag_length);

tag_width = (Tag_Text_Line_2 == "" ? 18 : 18+10);
text1_y = (Tag_Text_Line_2 == "" ? 7 : 7+10);
text2_y = (Tag_Text_Line_2 == "" ? 0 : 7);

hole_y = (Tag_Text_Line_2 == "" ? 10 : 10+5);

difference()
{
// Main body
minkowski(){
    cube ([tag_length,tag_width,1]);
    cylinder(r=2, h=.99);
}
//Hole
translate ([4,hole_y,-0.01]) cylinder(h=2, r=2.5);

//Text 1
translate([11, text1_y,1]) linear_extrude(height = 1){text(Tag_Text_Line_1, size=6, font="Courier New:style=Bold", spacing=1.2);};

//Text 2
if (Tag_Text_Line_2 != "")
{
    translate([11, text2_y,1]) linear_extrude(height = 1){text(Tag_Text_Line_2, size=6, font="Courier New:style=Bold", spacing=1.2);};

}

}

```


[User]
Hey, I'm looking to get a parametric OpenSCAD design for generating bed leveling test prints. I've seen some that are just squares or circles, but I'd like a bit more flexibility. Here's what I'm thinking:

I need to be able to specify the size of the main test object, its type, and its height. The object types should include at least Circle, Square, Triangle, Hexagon, Octagon, Nested Square, Nested Circle, Spiral Square, and Text.

For the nested shapes (Nested Square and Nested Circle), I'd like parameters for the number of nested shapes and their thickness. So, for instance, with a nested square, I could specify that I want 3 nested squares with each layer being 2mm thick.

For the Spiral Square I'd like a parameter to define the thickness of the spiral lines.

And for the text, I need to be able to set the text that is displayed.

I think that's it for now, but being able to easily add more shapes down the road would be ideal. I'm not requesting any libraries at this time. Could you give me the code?

[Assistant]
Customizable_Bed_Level_Test.scad:
```
/* [ Test Object ] */
Test_Object_Size = 20;
Test_Object_Type = "Nested Circle"; // ["Circle", "Square", "Triangle", "Hexagon", "Octagon", "Nested Square", "Nested Circle", "Spiral Square", "Text"]
Test_Object_Height = 0.3;

//Only Applies When Nested Square/Circle Is Selected
Number_Of_Nested_Objects = 2;
//Only Applies When Nested Square/Circle Is Selected
Nested_Object_Thicnkess = 2;
//Only Applies When Text Is Selected
Text = "@";
//Only Applies When Spiral Square/Circle Is Selected
Spiral_Thickness = 2;

module nestedSquare(t, g)
{
    difference()
    {
        cube([Test_Object_Size-(Nested_Object_Thicnkess*(t-1))-g, Test_Object_Size-(Nested_Object_Thicnkess*(t-1))-g, Test_Object_Height], true);
        cube([Test_Object_Size-(Nested_Object_Thicnkess*(t))-g, Test_Object_Size-(Nested_Object_Thicnkess*(t))-g, Test_Object_Height+0.2], true);
    }
}

module nestedCircle(t, g)
{
    $fn = 60;
    difference()
    {
        cylinder(Test_Object_Height, (Test_Object_Size-(Nested_Object_Thicnkess*(t-1))-g)/2, (Test_Object_Size-(Nested_Object_Thicnkess*(t-1))-g)/2, true);
        cylinder(Test_Object_Height+0.2, (Test_Object_Size-(Nested_Object_Thicnkess*(t))-g)/2, (Test_Object_Size-(Nested_Object_Thicnkess*(t))-g)/2, true);
    }
}

module spiral(type)
{
    if (type=="square")
    {
        for (i=[0:Test_Object_Size/(Spiral_Thickness*4)])
        {
            difference()
            {
                cube([Test_Object_Size-(Spiral_Thickness*4*i), Test_Object_Size-(Spiral_Thickness*4*i), Test_Object_Height], true);
                cube([Test_Object_Size-Spiral_Thickness*2-(Spiral_Thickness*4*i), Test_Object_Size-Spiral_Thickness*2-(Spiral_Thickness*4*i), Test_Object_Height+2], true);
                translate([Test_Object_Size/2-Spiral_Thickness/2-(Spiral_Thickness*i*2), Spiral_Thickness+(Spiral_Thickness*i*2), 0]) cube([Spiral_Thickness, Test_Object_Size, Test_Object_Height+2], true);
            }
            translate([Test_Object_Size/2-Spiral_Thickness*1.5-(Spiral_Thickness*i*2), Spiral_Thickness, 0]) cube([Spiral_Thickness, Test_Object_Size-Spiral_Thickness*2-(Spiral_Thickness*i*4), Test_Object_Height], true);
        }
    }
}

module object()
{
    if (Test_Object_Type == "Circle")
    {
        cylinder(Test_Object_Height, Test_Object_Size/2, Test_Object_Size/2);
    }
    else if (Test_Object_Type == "Square")
    {
        cube([Test_Object_Size, Test_Object_Size, Test_Object_Height], true);
    }
    else if (Test_Object_Type == "Triangle")
    {
        cylinder(Test_Object_Height, Test_Object_Size/2, Test_Object_Size/2, $fn=3);
    }
    else if (Test_Object_Type == "Hexagon")
    {
        cylinder(Test_Object_Height, Test_Object_Size/2, Test_Object_Size/2, $fn=6);
    }
    else if (Test_Object_Type == "Octagon")
    {
        cylinder(Test_Object_Height, Test_Object_Size/2, Test_Object_Size/2, $fn=8);
    }
    else if (Test_Object_Type == "Nested Square")
    {
        for(i = [0 : Number_Of_Nested_Objects])
        {
            nestedSquare(i+2, Test_Object_Size/(Nested_Object_Thicnkess+Number_Of_Nested_Objects+1)*(i)-Nested_Object_Thicnkess);
        }
    }
    else if (Test_Object_Type == "Nested Circle")
    {
        for(i = [0 : Number_Of_Nested_Objects])
        {
            nestedCircle(i+2, Test_Object_Size/(Nested_Object_Thicnkess+Number_Of_Nested_Objects+1)*(i)-Nested_Object_Thicnkess);
        }
    }
    else if (Test_Object_Type == "Spiral Square")
    {
        spiral("square");
    }
    else if (Test_Object_Type == "Text")
    {
        linear_extrude(Test_Object_Height) text(Text, font="Arial:style=Regular", size=Test_Object_Size, halign="center", valign="center");
    }
}

object();
```


[User]
Okay, I'd like to design a set of custom measuring spoons using OpenSCAD. I have a fertilizer that I need to accurately dose, and I'd like to create spoons specifically for my containers.

Here's the information about my fertilizer:

*   **Volume:** 425 milliliters
*   **Weight:** 500 grams
*   **Nitrogen (N) content:** 13%

I want to create up to four different spoons, each for a specific mixing container size and target PPM. Here are the details:

*   **Container 1:** 1 Gallon, 75 PPM
*   **Container 2:** 5 Gallons, 75 PPM
*   **Container 3:** 1 Gallon, 125 PPM
*   **Container 4:** 5 Gallons, 125 PPM

I'd like the spoon design to have the following characteristics:

*   **Smoothness:** I'd like to use `$fn=120` to ensure they're relatively smooth.
*   **Bowl Wall Thickness:** 1mm
*   **Handle Width:** 10mm
*   **Handle Thickness:** 1.6mm
*   **Handle Length:** 5mm beyond the bowl
*   **Center Ring Diameter:** 25mm

I'd like each spoon to have a label, engraved on the handle, showing the container size (including the unit of measure) and the target PPM. I'd also like to engrave an "N" plus the fertilizer's N number on the handle to indicate the fertilizer's nitrogen strength. If the number is 100 or higher, do not engrave.

The units for my mixing containers are US gallons. I'm not too concerned about having a variety of unit options on the spoons (I only use gallons).

I also need a separate center ring with no handle which is printed separately from the spoons, so that the user knows the spoons all belong to the same set.

Could you please generate the OpenSCAD files for this?

[Assistant]
measuring_spoon.scad:
```
// measuring_cup.scad
//
// A set of scoops for measuring a desired amount of fertilizer for mixing
//
// Given information about a fertilizer,
// compute the size of a measuring spoon required to
// dose the water to a specified dilution in a given container size.
//
// Steps:
// 1) Enter the weight and volume of fertilizer, and the Nitrogen (N) number.
// 2) Enter the sizes and desired dosages of the mixing containers (up to 4).
// 3) Render and print.
//
// For example, I will use a custom mix of MSU Orchid Fertilizer, 13-3-5.
// I put a measuring cylinder on a scale, zeroed it, then added fertilizer
// When the scale read 500 grams, the cylinder indicated 425 ml.  I could also
// have filled a 500 ml cup and measured the weight in grams.
// I want a 125PPM mixture of nitrogen to water.
// I have a 10 gallon container, but sometimes it's partially full, so I want a
// variety of measuring scoops.
// I could also have one scoop at 75PPM, one at 100PPM,
// one at 125PPM, and one at 150PPM.

/* [Fertilizer] */

fertilizer_volume = 425;
fertilizer_volume_units = 0; // [0:milliliter, 1:liter, 2:Gallon-US, 3:Quart-US, 4:Pint-US, 5:Cup-US, 6:Ounce-US, 7:Gallon-Imp, 8:Quart-Imp, 9:Pint-Imp, 10:Gill-Imp, 11:Ounce-Imp]
fertilizer_weight = 500;
weight_units = 0; // [0:grams, 1:ounces, 2:pounds]
// For fertilizer, enter the N number. Enter 100 for full strength mixes of non-fertilizers, such as pesticides.
percent_strength = 13;

/* [Mixing containers] */
// Mixing container units of measure
mixing_container_volume_units = 2; // [0:milliliter, 1:Liter, 2:Gallon-US, 3:Quart-US, 4:Pint-US, 5:Cup-US, 6:Ounce-US, 7:Gallon-Imp, 8:Quart-Imp, 9:Pint-Imp, 10:Gill-Imp, 11:Ounce-Imp]
// Volume of water in each container
container_volume = [1,5,1,5];
// Desired PPM of each container
container_ppm = [75, 75, 125, 125];

/* [Advanced - Technical spoon details] */
// Smoothness of spoon
$fn=120;  // [30,60,90,120,180]
bowl_wall = 1; // [1:.1:2]
handle_w = 10; // [5:20]
handle_t = 1.6; // [1:.1:3]
handle_l = 5; // [5:50]
ring_dia = 25; // [10:50]

/* [Hidden] */
unit_label = ["ML", "LTR","GAL","QT","PT","CUP","OZ","GAL","QT","PT","GILL","OZ"];
mass_conversions = [1, 28.34952, 453.5924];

ml_p_unit = [1, 1000, 3785.4, 3785.4/4, 3785.4/8, 3785.4/16, 3785.4/128, 4546.0, 4546.0/4, 4546.0/8, 4546.0/32, 4546.0/160];

density = (fertilizer_weight*mass_conversions[weight_units]) / (fertilizer_volume*ml_p_unit[fertilizer_volume_units]);

// diameter of a sphere given a desired volume?
// new syntax doesn't yet work on thingiverse, gotta use the old pow() function.
//function sphere_dia(volume) = (6*(volume*2)/PI)^(1/3)*10;
function sphere_dia(volume) = pow((6*(volume*2)/PI),(1/3))*10;

// bowl to hold the volume
module bowl(volume, label) {  // volume in ml
  bowl_dia=sphere_dia(volume);
  difference() {
    sphere(d=bowl_dia+bowl_wall*2);
    sphere(d=bowl_dia);
    translate([0,0,-bowl_dia*2])
      cube(bowl_dia*4,center=true);
  }
}

// Center ring, with the fertilizer strength printed on it
module ring(ring_d){
    difference() {
        cylinder(d=ring_d,h=handle_t);
        translate([0,0,-0.01])
        cylinder(d=ring_d/2,h=handle_t+0.02);
    }

}

// Gussets to support the bowl-handle interface
module gusset(l,w,h) {
 difference()
  {
    cube([l,w,h]);
    translate([0,-0.01,0])
    rotate([0,-atan(h/l),0])
      color("green")
      cube([l*2,w+0.02,h]);
  }
};

// One scoop with handle, printed with container volume & dilution
module scoop(volume,container_vol,container_unit,strength,ppm) {
    if (volume > 0.1) {
        dia = sphere_dia(volume);
        handle_wide=min(handle_w,dia);
        handle_len = dia*.5+handle_l+ring_dia/2;
        ring_offset=ring_dia*.1;
        handle_start = ring_dia/2-ring_offset;
        translate([handle_start,0,0])
            difference() {
                // solid parts of handle
                translate([0,-handle_wide/2,0]) {
                  cube([handle_len+(dia/2), handle_wide, handle_t]);
                  // Gussets
                  if (handle_wide==handle_w) {
                    translate([ring_offset,0,handle_t])
                    gusset(handle_len-ring_offset+(dia/2), 1, dia/4-handle_t);
                    translate([ring_offset,handle_wide-1,handle_t])
                    gusset(handle_len-ring_offset+(dia/2), 1, dia/4-handle_t);
                  }
                }
            // Remove gusset/handle from inside bowl
            translate([handle_len+(dia/2),0,0])
                sphere(d=dia);

            // Engrave lettering on handle
            translate([handle_len-bowl_wall-3,0,0.4])
              rotate([180,0,90])
              color("black")
              linear_extrude(1)
            {

              text(font="Liberation Mono:style=Bold", str(container_vol),size=3, halign="center", valign="center");
              translate([0,-3.5,0])
              text(font="Liberation Mono:style=Bold", unit_label[container_unit],size=3, halign="center", valign="center");
              translate([0,-7.5,0])
              text(font="Liberation Mono:style=Bold", str(ppm),size=3, halign="center", valign="center");
              translate([0,-11,0])
              text(font="Liberation Mono:style=Bold", "PPM",size=3, halign="center", valign="center");
                if (strength<100) {
                  translate([0,-14.5,0])
                  text(font="Liberation Mono:style=Bold", str("N",round(strength)),size=3, halign="center", valign="center");
                }
            }

        }
        translate([handle_start+handle_len+(dia/2),0,0])
            bowl(volume);
    }
}

function spoon_needed(container_no) = ((container_volume[container_no]<.1) ? 0 : 1);

// Render center ring
ring(ring_dia);

num_containers=spoon_needed(0)+spoon_needed(1)+spoon_needed(2)+spoon_needed(3);
// Render each scoop
for (container_no = [0 : num_containers-1]) {
  if (spoon_needed(container_no)) {
    // Compute required scoop volume to provide dose volume
    ppm = container_ppm[container_no];
    container_vol_ml = container_volume[container_no]*ml_p_unit[mixing_container_volume_units];
    // divide container by PPM density
    parts=container_ppm[container_no]/(1000000*density);
    strength=(percent_strength/100);
    // # parts divided by strength of fertilizer
    gm_p_ml = parts/strength;

    // computed dose for container, in milliliters
    dose = gm_p_ml*container_vol_ml;

    // Render scoop
//    rotate([0,0,container_no*90])
    rotate([0,0,(360/num_containers)*container_no])
    scoop(dose,container_volume[container_no],mixing_container_volume_units,percent_strength,container_ppm[container_no]);
  }
}

```


[User]
Hey, I'm looking to get some OpenSCAD files for a parametric LED strip clip. I've seen a few designs, but I want one that I can customize for different LED strip widths.

Basically, it's a clip that's designed to be attached to a surface using a thumbtack. The thumbtack head sits in a recessed area of the clip, and a small hole allows the tack pin to pass through. Then there are arms (for lack of a better word) that come up on both sides of the strip to hold it in place.

Here are the main things I need to be able to change:

*   `led_strip_width`: This will be the width of the LED strip itself.
*   `led_strip_height`: The thickness of the LED strip.
*   `tack_head_diameter`: The diameter of the thumbtack head.
*   `tack_head_height`: The height of the thumbtack head.
*   `tack_head_offset`: How far down from the top of the clip to put the thumbtack head recess.
*   `clip_width`: The overall width of the base of the clip.
*  `clip_length`: The overall length of the base of the clip.
* `clip_height`: The overall height of the clip.

I'd like the thumbtack head recess to have some extra space so that it is easier to push the tack in, say an extra 50% in diameter, and for the pin hole to go down to the base of the clip. The arms holding the LED strip should extend at least partway up the sides of the strip, and a bit above to make sure it doesn't pop out.

I'm not sure how to handle the file structure, but I think I'd like to keep the main variables at the top and then some modules for the different components.

Could you help me generate the OpenSCAD file(s) for this? I'm not using any specific libraries other than the standard OpenSCAD functionality.

[Assistant]
light_strip_clip.scad:
```
tack_head_diameter = 11;
tack_head_height = 1.8;
tack_head_offset = 1;
led_strip_width = 12;//this is probably the main variable you want to change
led_strip_height = 1.5;
clip_width = 25;
clip_length = tack_head_diameter * 2;
clip_height = tack_head_height * 2;

$fn=25;

final();

module final() {
    main_block();

    //left side
    translate([clip_width/2 - led_strip_width/2 - 2,0,clip_height])
        strip_holder();

    //right side
    translate([clip_width/2 + led_strip_width/2 + 2,clip_length,clip_height])
        rotate([0,0,180])
            strip_holder();
}

module strip_holder() {
    cube([2,clip_length,led_strip_height]);
    translate([0,0,led_strip_height]) cube([3,clip_length,2]);
}

module main_block() {
    difference() {
        cube([clip_width, clip_length, clip_height]);

        //hole for tack head
        translate([clip_width/2-tack_head_diameter/2,0,tack_head_offset])
            cube([tack_head_diameter,tack_head_diameter*1.5,tack_head_height]);

        //hole for tack pin
        translate([clip_width/2 - 0.5,0,0])
            cube([1,tack_head_diameter,tack_head_offset]);

        //hole for tack head pushing
        translate([clip_width/2,clip_length/2,clip_height-tack_head_height])
            cylinder(h=tack_head_height, d=tack_head_diameter/2);
    }
}
```


[User]
I'm looking to create a fully parametric twin-slot shelf bracket system in OpenSCAD, but something more robust than the design I've seen online. I need to be able to adjust all the critical dimensions so I can use it with different shelving systems and for different load requirements.

My current twin slot uprights have slots that are roughly 18mm long, spaced vertically at 32mm centers, and horizontally at 6mm centers. I would like the system to support the following parameters:

*   **Slot Dimensions:** The ability to set slot length, vertical spacing, and horizontal spacing.
*   **Key Profile:** I want the key profile (the part that inserts into the slot) to be fully customizable. I need to be able to adjust the thickness and depth as well as the overall shape via a list of points to define the profile as a polygon.
*   **Backbone Width:** The width of the bracket immediately adjacent to the key.
*   **Bracket Length:** The total length of the bracket arm (the part that supports the shelf).
*   **Bracket Height:** The height of the bracket arm.
*   **Bracket Arm Profile:** The profile of the bracket arm should be customizable with a list of 2D points, similar to the key profile.
*   **Shelf Fixing Holes:** Options to include and position fixing holes for securing the shelf to the bracket. These should allow for specifying the hole diameter, countersink diameter (if required), center distance from the bracket end, and the number of holes.
*   **Material Thickness:** Ability to adjust the overall material thickness of the bracket, and also apply that thickness in the key profile.
*   **Rounded Edges:** A parameter to round the outer edges of the key and bracket arm, using a radius parameter.

I think this would be best broken down into a main file, and a separate file for some of the shape-defining modules, like key profiles and arm profiles, to keep the code organized. Please use comments throughout so that I can understand what's going on.

I'd like this to be designed from scratch in OpenSCAD, rather than trying to improve on an existing design. If possible, I would prefer to use BOSL2 for things like edge rounding, but I'm flexible about libraries if needed.

[Assistant]
Twin-slot_Shelf_Bracket.scad:
```
/* Light-duty shelf bracket for a Twin Slot Shelving System.
  Author: dave8888
  Thingiverse thing:5014148
  Version 1.0  October 2021

  This shelf support is only intended for very lightweight use with a small shelf!
  ** Do not use with heavy items! **

  I designed this to make a small display shelf between my normal heavy duty metal shelf brackets

  Supports are needed to print the keys section.

*/

key_thick = 2.50;		// Thickness of the bracket slot key (mm)
slot_gap=6.0;		    // slot to slot gap of the upright (mm)
key_width = 18;         // [14:22] width of the key section (mm)

backbone = 10;          // width of the backbone section (the section next to the key)(mm)
bracket_l = 110;        // total bracket length (excluding the key section)(mm)
bracket_h = 48;			// Shelf bracket arm height (mm) (ideally same as key height = 48mm)

screw_holes = true;      // (true or false) Provide shelf fixing screw-holes
screw_hole = 3.4;        // shelf fixing screwhole diameter (mm)
access_hole = 6;         // screwdriver access hole diameter for screws (mm)
fixing_t  = 5;           // screw fixing thickness within the bracket (mm)
$fn=60;                  // screw hole smoothness

//=========================================== main =========================================================

difference() {
	union() {
        // Bottom key
		translate([0,0,0]) keyprofile();
        // Top Key
        translate([0,0,slot_gap + key_thick ])  keyprofile();

		// key backbone

        translate([0,key_width,0]) cube([bracket_h,backbone,slot_gap + key_thick*2 ]);

        // the bracket arm
        arm();

        }
        // Bracket holes
        holes();
    }

//==========================================================================================================

// shelf bracket key profile

/* If you want to modify the key profile, try using the OpenSCAD polygon editor (single HTML file) by "Daid"    https://www.thingiverse.com/thing:14200
    Paste the polygon points line below into the local html file using a web browser
    and you can view or edit the profile.

*/
module keyprofile() {
	linear_extrude(height=key_thick)
	 polygon(points=[[16,14],[18,13],[26,13],[26,8],[42,6],[42,13],[48,13],[48,22],[0,22],[0,5],[2,2],[5,0],[15,0],[16,1],[16,9],[15,10],[12,10],[12,14]]);
}

//=============================================================================================================

// Bracket arm
arm_l = bracket_l - backbone; // calculate the arm length

arm_points = [[bracket_h,0],[5,arm_l],[0,arm_l],[0,0]];  //arm profile (end point is made blunt by 5mm)

module arm() {
    arm_t = slot_gap + key_thick *2;		// Calculate shelf bracket arm thickness

	// set arm offset from backbone + key
	translate([0,key_width + backbone,0])

	// set arm thickness
	linear_extrude(height = arm_t)
	// make a triangle
		polygon(arm_points);
}
//=========================================================================================================

// Shelf fixing holes (if required)
module holes() {
    if (screw_holes)
                {

    // Screw hole 1
    ho1_offset = key_width + backbone + 0.25 * arm_l;
    translate([-1,ho1_offset,key_thick+slot_gap/2]) color("red") rotate([90,0,90]) cylinder(r=screw_hole/2,h=120);
    //Screwdriver access section
	translate([fixing_t,ho1_offset,key_thick+slot_gap/2]) color("silver") rotate([90,0,90]) cylinder(r=access_hole/2,h=120);

    // Screw hole 2
    ho2_offset = key_width + backbone + 0.75 * arm_l;
    translate([-1,ho2_offset,key_thick+slot_gap/2]) color("red") rotate([90,0,90]) cylinder(r=screw_hole/2,h=120);
    //Screwdriver access section
	translate([fixing_t,ho2_offset,key_thick+slot_gap/2]) color("silver") rotate([90,0,90]) cylinder(r=access_hole/2,h=120);
                }
}
```