[User]
Hi! I'm looking to generate a design for a sort of coral-like structure, but made of tubes. I've seen some designs that are similar, but I want something that I can customize easily.

Ideally, I'd like to be able to control the number of tubes, the "roughness" of the tube surface, and whether the tubes have a uniform height or random heights. It would be good if there was a preview mode that didn't require super high-quality rendering.

Here's the details I'm thinking of:

*   **Tubes:**
    *   The tubes should radiate outwards in a spiral pattern from a central point using a phyllotaxis arrangement. I think that using the golden angle is a good idea. I'm open to using other arrangements but this is what I'm familiar with.
    *   Each tube should be a cylinder, but with some surface variation to make it appear more like a natural sponge.
    *   The base of each tube should have a smooth curve as it transitions from the base, and this curve should be adjustable.
    *   The tubes should be placed on some sort of a base, but it should have a rough, organic look like a rock.
*   **Customization:**
    *   I need parameters to control the *number of tubes*.
    *   I also need parameters to control the *rugosity* or roughness of the tubes, controlling how "bumpy" the surface is.
    *   I need a way to select whether the tubes have a *standard uniform height* or *random heights*, with a slider for the random range.
    *   It would be really nice if there's a way to select between a *low-poly preview mode* for faster rendering and a *high-quality render mode*.
    *   I would also like to be able to adjust the radius of the tubes, the height of each tube, and the curvature at the base of each tube, individually if possible, or at least as a global setting.

I think that would cover most of what I'm looking for. I'm not sure of the exact functions necessary but I've seen `polyhedron`, `noise` function in previous openSCAD projects.

Could you create this design in OpenSCAD? I don't need any specific libraries beyond what's included in a standard OpenSCAD installation.

[Assistant]
tube_sponge_thingiverse.scad:
```
//
//    Coral Tubular
//    Fernando Jerez 2017
//    License: CC Attributtion only
//

// PART: Previes / Render
part = "preview"; // [preview:Low Poly for faster preview, render: High Quality for render ]

// Number of tubes
tubes = 10; // [1:20]

// Surface rugosity of tubes
rugosity = 5; // [0:10]

// Height of tubes (standard/random)
tube_heights = "standard"; // [standard: standard ,random: Random]

/* [Hidden] */

noiseZoom = 0.2; // Detalle (zoom) del ruido

stepz = (part=="preview") ? 5:2;
stepa = (part=="preview") ? 20:5;

// Phyllotaxis
c = tubes*0.6;
num = tubes;
phy = 137.5;

angle = 0;
rot = 0;

ini = (tubes==1)?0:1;
end = (tubes==1)?0:num;

translate([0,0,2+tubes]){
    for(i=[ini:end]){
        r = c*sqrt(i);
        h = (tube_heights=="random") ? 10*round(rands(4,20,1)[0]) : 20+(num-i)*15;//
        curve = i / (num*2);
        rad = 5+round((num-i)*0.5);
        rx = 0;
        ry = 0;//i*0.25;
        rz = phy*i;
        //echo([rad,h,curve,rz]);
        rotate([rx,ry,rz]){
            translate([r,0,0]){
                rotate([0,i*2,0]){
                    tubular(rad,50+h,curve,rugosity,0.5,stepz,stepa);
                }
            }
        }
    }
}

color("Orange")
difference(){
    scale([1,1,0.55]) randomRock(10+15*sqrt(num),2,70);
    translate([0,0,-(50+rugosity)]) cube([300,300,100],center = true);
}

// Tubular branch

module tubular(
    rad = 10, // radio
    height=70, // Altura
    curve = 0.5, // curva en la parte baja (something between [0:1]
    noiseScale = 4, // Grosor del ruido
    flatlevel = 0.5, // Corte para la zona plana

    zstep = 4, // incremento de altura por nivel
    astep = 6, // increento de angulo (como $fn)
    )
    {

    Seed=rands(1000,10000,1)[0];
    sides = 360/astep;
    levels =floor(height/zstep);
    // Some sort of cylinder made vertex by vertex, my own version from scratch
    puntos = [
    for(z = [0:zstep:height])
        for(ang = [0:astep:360-astep])
            let(
                rot = 180/height,
                r = max(rad,rad + 0.5*rad*cos(z*rot)),
                noi = ((rugosity==0) || (z+zstep*2)>height/2  )?0: min((height-z)*0.1,noiseScale) * cos(z*rot)* max(flatlevel,Noise((ang)*noiseZoom ,z*noiseZoom *2 ,0,Seed)),

                px = -(noi+r) * cos(ang), //invert the x to move back the 0 seam
                py = (noi+r) * sin(ang),
                pz = z + (z*cos(z*rot)),

                // Apply rotation on Y axis
                // (https://es.wikipedia.org/wiki/Matriz_de_rotaci%C3%B3n)

                a =  (-90+60*(sin(pz*rot)))*curve,
                npx = (px*cos(a)-pz*sin(a)),
                npz = (px*sin(a)+pz*cos(a))
            )

            [npx,py,npz]

    ];

    caras = concat(
    [
    for(z = [0:levels-1])
        for(s = [0:sides-1])
            let(
                // clockwise from left-down corner
                f1 = s + sides*z,
                f2 = s + sides*(z+1),
                f3 = ((s+1) % sides) + sides*(z+1),
                f4 = ((s+1) % sides) + sides*z
            )

            [f1,f2,f3]

    ],
    [
    for(z = [0:levels-1])
        for(s = [0:sides-1])
            let(
                // clockwise from left-down corner
                f1 = s + sides*z,
                f2 = s + sides*(z+1),
                f3 = ((s+1) % sides) + sides*(z+1),
                f4 = ((s+1) % sides) + sides*z
            )

            [f3,f4,f1]

    ],
    [
        for(s = [0:sides-1])
            let(
                // clockwise from left-down corner
                f1 = s ,
                f2 = ((s+1) % sides),
                f3 = (((s+1) % sides)) + sides*(levels),
                f4 = s+ sides*(levels)
            )
            [f1,f2,f3]
    ],
    [
        for(s = [0:sides-1])
            let(
                // clockwise from left-down corner
                f1 = s ,
                f2 = ((s+1) % sides),
                f3 = (((s+1) % sides)) + sides*(levels),
                f4 = s+ sides*(levels)
            )

            [f3,f4,f1]

    ]
        );

    polyhedron (points=puntos,faces = caras);

}

// NOISE FUNCTIONS

function Noise(x=1,y=1,z=1,seed=1)=let(SML=octavebalance())(Sweetnoise(x*1,y*1,z*1,seed)*SML[0]+Sweetnoise(x/2,y/2,z/2,seed)*SML[1]+Sweetnoise(x/4,y/4,z/4,seed)*SML[2]);
function lim31(l,v)=v/len3(v)*l;
function octavebalance()=lim31(1,[40,150,280]);
function len3(v)=sqrt(pow(v[0],2)+pow(v[1],2)+pow(v[2],2));
function Sweetnoise(x,y,z,seed=69840)=tril(SC3(x-floor(x)),(SC3(y-floor(y))),(SC3(z-floor(z))),Coldnoise((x),(y),(z),seed),Coldnoise((x+1),(y),(z),seed),Coldnoise((x),(y+1),(z),seed),Coldnoise((x),(y),(z+1),seed),Coldnoise((x+1),(y),(z+1),seed),Coldnoise((x),(y+1),(z+1),seed),Coldnoise((x+1),(y+1),(z),seed),Coldnoise((x+1),(y+1),(z+1),seed));
function tril(x,y,z,V000,V100,V010,V001,V101,V011,V110,V111)=
    V000*(1-x)*(1-y)*(1-z)+
    V100* x*(1-y)*(1-z)+
    V010*(1-x)*y*(1-z)+
    V001*(1-x)*(1-y)*z+
    V101* x*(1-y)*z+
    V011*(1-x)*y*z+
    V110* x*y*(1-z)+
    V111* x*y*z;

function Coldnoise(x,y,z,seed=69940)=
((3754853343/((abs((floor(x+40))))+1))%1+(3628273133/((abs((floor(y+44))))+1))%1+(3500450271/((abs((floor(z+46))))+1))%1+(3367900313/(abs(seed)+1))/1)%1;
function SC3(a)=(a*a*(3-2*a));
function un(v)=v/max(len3(v),0.000001)*1;

// https://openscadsnippetpad.blogspot.com.es/2017/05/1-dimensional-noise.html
function single_noise_1d(i)=
let(
a=floor(i),
b=ceil(i),
c=smooth_curve(i-a),
arnd=rnd(1,0,a),
brnd=rnd(1,0,b),
out=lerp(arnd,brnd,c)
)
out
;

function  noise_1d(i,
low_range=1/4,mid_range=1,hi_range=8,
low_magnitude=1/2,mid_magnitude=0.25,hi_magnitude=0.5)=
 (
single_noise_1d(i/low_range)*low_magnitude+
single_noise_1d(i/mid_range)*mid_magnitude+
single_noise_1d(i/hi_range)*hi_magnitude

)/(low_magnitude+mid_magnitude+hi_magnitude);

function smooth_curve(a) =let (b = clamp(a))(b * b * (3 - 2 * b));
function clamp(a, b = 0, c = 1) = min(max(a, b), c);
function lerp(start, end, bias) = (end * bias + start * (1 - bias));
function rnd(a = 1, b = 0, s = []) =
  s == [] ?
   (rands(min(a, b), max(   a, b), 1)[0])
  :
   (rands(min(a, b), max(a, b), 1, s)[0])
  ;

// Module randomRock : draws a random rock
module randomRock(radius,corner_size,number_of_corners){
    // Draw rock
    hull(){
        // Make a hull..
        for(i=[0:number_of_corners]){
            // random position in sphere
            y = rands(0,360,1)[0];
            z = rands(0,360,1)[0];
            rotate([0,y,z])

            // translate radius (minus half of corner size)
            translate([radius-corner_size*0.5,0,0])

            // draw cube as corner
            rotate([rands(0,360,1)[0],rands(0,360,1)[0],rands(0,360,1)[0]]) // random rotation
            cube(rands(corner_size*0.5,corner_size,1)[0],center = true);

        }
    }

    // Done
}
```


[User]
Hi, I'm looking to design some 3D printable parts for my Raspberry Pi camera setup and I need some help with OpenSCAD.

First, I need an adapter to attach a CS-mount lens to my Raspberry Pi Camera v1.3. The camera module has two mounting holes for M2 screws, and the lens has a 1" diameter CS-mount with 32 threads per inch. I also want to include a central cutout for the sensor, which is about 5.2mm high by 8mm square, but it needs to be wider than 8mm, say 12.5 x 22 to give clearance. I want to keep this cutout at a consistent depth relative to the mounting face, so it needs to be 0.5mm below the plane the board will be attached to. The base of the adaptor where it sits on the board should be around 6mm tall. I'd like this adapter to also have an M12x0.5 mounting hole in the center as a future option, but for now it just needs to be a 12mm hole, no threads.

The base should be about 25x20mm and have the M2 screw holes centered 10.5mm apart on the X axis, 8mm along the Y axis, and they need to be recessed 3.5mm down to account for the 0.95mm board height. The CS-mount part should be a 1" diameter cylinder, 1mm tall, with the threaded section 5mm tall starting 1mm above the cylindrical base. For the threads themselves, you'll need to use the `threads` library since I'm doing a non-metric thread. I also need to cut a 12mm through hole through the center of everything.

Second, I also want to design a desk lamp mount for a cylindrical lens, which has a 50mm diameter. I'd like this mount to have a circular loop around the lens with a couple of mounting points. The loop should be about 8mm tall. I'd like it to have a sort of arm extending outwards, which is then connected to a hook-like structure. The arm needs to be 25mm long, and have a cross section the same as the loop in it's thickness(8mm tall) but needs to be 10mm wide. The hook itself should be a rectangular shape, 12mm wide and 10mm long and 16mm tall at the inner face (the outer face needs to be 8mm taller, 24mm total). The thickness of the hook material should be 8mm. The hook should have two 3.2mm holes for M3 screws to hold the mount to the lamp. I'd like the holes to be offset 3mm inward from the edge, and they need to be 25mm deep to make sure they can accommodate a screw. The main loop needs to be parametric in size, and should have a radius of 25.5mm, plus 3mm padding for the outer part of the loop and 2mm for the inner part to sit in the mount.

Could you generate the necessary OpenSCAD files for me? Thanks!

[Assistant]
cs_adaptor.scad:
```
use <threads.scad>

$fn = 200;

difference()
{
    union()
    {
        difference()
        {
            // main base
            cube([25,20,6],center=true);

            // m2 screw holes, board is 0.95mm tall
            union()
            {
                translate([10.5,8,-3.5]) cylinder(d=2,h=5);
                translate([-10.5,8,-3.5]) cylinder(d=2,h=5);
            }

            // centre cutout, sensor is 5.2mm high by 8 square
            translate([0,0,-0.5]) cube([12.5,22,5.2],center=true);
        }

        // 1" diameter, 32tpi cs-mount adaptor
        translate([0,0,3]) cylinder(d=28,h=1);
        translate([0,0,4])
        {
            difference()
            {
                cylinder(d=28,h=5);
                english_thread(1, 32, 0.25, internal=true);
            }
        }
    }

    // m12 0.5 pitch adaptor
    cylinder(d=12,h=20,center=true);
}

```
lamp_mount.scad:
```
$fn = 200;
hook_h = 16; // height of metal 14mm
hook_w = 12; // width of metal
hook_l = 10; // length of metal
wall = 8;
hole_r = 25.5;
hole_h = 8;
screw_d = 3.2; // m3 bolt

// loop
difference()
{
    cylinder(h=hole_h, r=hole_r+3, center=true); // outer must be <57mm
    cylinder(h=hole_h+2, r=hole_r, center=true); // inner must be ~50mm
}

// arm
translate([hole_r+2,-hook_l/2,-hole_h/2]) cube(size=[25,hook_l,hole_h]);

// hook
translate([hole_r+2+25,-hook_l/2,-hook_h-wall/2])
{
    difference()
    {
        cube(size=[hook_w+wall,hook_l,hook_h+wall]);
        translate([wall/2,-wall/2,-wall/2]) cube(size=[hook_w,hook_l+wall,hook_h+wall]);

        // screw holes
        rotate([0,90,0]) translate([-3,hook_l/2,-3]) cylinder(h=25, d=screw_d);
    }
}

// TODO: add 2-3 M3 screw holes to clamp the lens to the loop

```


[User]
Hey, I need some help designing an encoder wheel. I'd like to be able to adjust a few key parameters to generate different wheel variations.

Here's what I'm looking for:

*   **Wheel Diameter:** I need to be able to set the overall diameter of the wheel.
*   **Wheel Thickness:**  I'd like to control the thickness of the wheel.
*   **Number of Slots:** This should control how many slots are cut into the wheel.
*   **Rim Distance:**  I need to set the distance between the outer edge of the slots and the outer edge of the wheel.
*   **Slot Length:** I need control over how long each slot is.

Then, for the center bore:

*   **Bore Shape:** This should let me choose the shape of the center hole, like a circle, triangle, square, hexagon, or an oval.
*   **Bore Size:** I need to set the basic size of the center bore.
*   **Oval Width:** If I choose an oval bore, I need to set the oval's width.

Finally, I'd like to be able to output a 2D version of the design.

*   **2D Export:** There should be an option to generate a 2D projection of the wheel for exporting as either SVG or DXF.

I need the code to be in OpenSCAD, and it needs to be fully parametric. Also, I'd like to keep all the code in a single .scad file.

[Assistant]
encoder_wheel.scad:
```
/* Encoder Wheel / Disc*/

/* [Basic Settings] */
Wheel_Diameter = 25;
Wheel_Thickness = 1;
Number_of_Slots = 32;
// distance from rim side of slots to outer edge of wheel
rim = 1;
Slot_Length = 2;

/* [Bore Size and Shape]*/

Bore_Shape = "Hole"; // [Hole, Triangle, Square, Hex, Oval]
Bore = 5; // To edit bore shape edit bore()
//Oval width will only work when Bore shape is set to oval
Oval_Width = 2;

/* [2d Image for laser cutting] */

//set to true if you want to export as .svg or .dxf
SVG = false; /* set to true if you want to export as a 2d immage (SVG or DXF)
  File > Export > Export as DXF...
*/

/*[Hidden]*/
$fn = 100;
deg = 360 / (Number_of_Slots * 2) ;
dist = (Wheel_Diameter / 2) - rim - Slot_Length;
slot_width = (tan(deg) * (Wheel_Diameter / 2));

if (SVG == true)
{
  projection(cut = true) Wheel();
}
else
{
  Wheel();
}

module Wheel()
{
  difference()
  {
    cylinder (h = Wheel_Thickness, d = Wheel_Diameter, center = false);
    bore();

    for (i = [0:(Number_of_Slots) - 1])
    {
      rotate([0, 0, i * (deg * 2)])
      {

        if (rim == 0)
        {
          intersection()
          {
            wedge();
            difference()
            {
              cylinder(h = Wheel_Thickness, d = Wheel_Diameter * 2);
              cylinder(h = Wheel_Thickness, d = Wheel_Diameter - (rim * 2) - (2 * Slot_Length));
            }
          }
        }
        if (rim > 0)
        {
          intersection()
          {
            wedge();
            difference()
            {
              cylinder(h = Wheel_Thickness, d = Wheel_Diameter - (rim * 2));
              cylinder(h = Wheel_Thickness, d = Wheel_Diameter - (rim * 2) - (2 * Slot_Length));
            }
          }
        }

      }
    }
  }
}

module wedge()
{
  hull()
  {
    cube([Wheel_Diameter, 0.1, Wheel_Thickness ]);
    rotate([0, 0, deg])cube([Wheel_Diameter, 0.1, Wheel_Thickness ]);
  }
}

module bore()
{
  if (Bore_Shape == "Hole"  )
  {
    cylinder (h = Wheel_Thickness, d = Bore, center = false, $fn = 60);
  }

  else if (Bore_Shape == "Triangle")
  {
    nut = (Bore / 3) * 4;
    cylinder(h = Wheel_Thickness, d = nut, $fn = 3);
  }

  else if (Bore_Shape == "Square")
  {
    cube([Bore, Bore, Wheel_Thickness * 2], center = true);
  }

  else if (Bore_Shape == "Hex")
  {
    nut = 2 * ((Bore / 2) / cos(30));
    cylinder(h = Wheel_Thickness, d = nut, $fn = 6);
  }

  else if (Bore_Shape == "Oval")
  {
    intersection()
    {
      cylinder (h = Wheel_Thickness, d = Bore, center = false, $fn = 60);
      cube([Oval_Width, Bore * 2, Wheel_Thickness * 2], center = true);
    }
  }
}
```
encoder_wheel.scad:
```
/* Encoder Wheel / Disc*/

/* [Basic Settings] */
Wheel_Diameter = 25;
Wheel_Thickness = 1;
Number_of_Slots = 32;
// distance from rim side of slots to outer edge of wheel
rim = 1;
Slot_Length = 2;

/* [Bore Size and Shape]*/

Bore_Shape = "Hole"; // [Hole, Triangle, Square, Hex, Oval]
Bore = 5; // To edit bore shape edit bore()
//Oval width will only work when Bore shape is set to oval
Oval_Width = 2;

/* [2d Image for laser cutting] */

//set to true if you want to export as .svg or .dxf
SVG = false; /* set to true if you want to export as a 2d immage (SVG or DXF)
  File > Export > Export as DXF...
*/

/*[Hidden]*/
$fn = 100;
deg = 360 / (Number_of_Slots * 2) ;
dist = (Wheel_Diameter / 2) - rim - Slot_Length;
slot_width = (tan(deg) * (Wheel_Diameter / 2));

if (SVG == true)
{
  projection(cut = true) Wheel();
}
else
{
  Wheel();
}

module Wheel()
{
  difference()
  {
    cylinder (h = Wheel_Thickness, d = Wheel_Diameter, center = false);
    bore();

    for (i = [0:(Number_of_Slots) - 1])
    {
      rotate([0, 0, i * (deg * 2)])
      {

        if (rim == 0)
        {
          intersection()
          {
            wedge();
            difference()
            {
              cylinder(h = Wheel_Thickness, d = Wheel_Diameter * 2);
              cylinder(h = Wheel_Thickness, d = Wheel_Diameter - (rim * 2) - (2 * Slot_Length));
            }
          }
        }
        if (rim > 0)
        {
          intersection()
          {
            wedge();
            difference()
            {
              cylinder(h = Wheel_Thickness, d = Wheel_Diameter - (rim * 2));
              cylinder(h = Wheel_Thickness, d = Wheel_Diameter - (rim * 2) - (2 * Slot_Length));
            }
          }
        }

      }
    }
  }
}

module wedge()
{
  hull()
  {
    cube([Wheel_Diameter, 0.1, Wheel_Thickness ]);
    rotate([0, 0, deg])cube([Wheel_Diameter, 0.1, Wheel_Thickness ]);
  }
}

module bore()
{
  if (Bore_Shape == "Hole"  )
  {
    cylinder (h = Wheel_Thickness, d = Bore, center = false, $fn = 60);
  }

  else if (Bore_Shape == "Triangle")
  {
    nut = (Bore / 3) * 4;
    cylinder(h = Wheel_Thickness, d = nut, $fn = 3);
  }

  else if (Bore_Shape == "Square")
  {
    cube([Bore, Bore, Wheel_Thickness * 2], center = true);
  }

  else if (Bore_Shape == "Hex")
  {
    nut = 2 * ((Bore / 2) / cos(30));
    cylinder(h = Wheel_Thickness, d = nut, $fn = 6);
  }

  else if (Bore_Shape == "Oval")
  {
    intersection()
    {
      cylinder (h = Wheel_Thickness, d = Bore, center = false, $fn = 60);
      cube([Oval_Width, Bore * 2, Wheel_Thickness * 2], center = true);
    }
  }
}
```


[User]
I'd like to create a customizable stand for displaying small, rectangular objects like handheld game consoles. I want to be able to adjust several key dimensions and features.

Here's what I have in mind:

*   **Overall Width:** I need to be able to set the width of the stand as viewed from the front. Let's call this `stand_width`.
*   **Bottom Depth:** I need to control the depth of the flat area where the object will rest, named `bottom_depth`.
*   **Backrest Height:** I need to specify the height of the backrest portion of the stand, which we'll call `backrest_height`.
*  **Lean Angle:** The backrest should lean back at an adjustable angle. The angle itself we'll call `lean_angle`.
*   **Base Distance:** I also want to be able to define the horizontal distance between the base of the prop that's holding up the backrest and the point where it joins the backrest. We'll call that `base_distance`.
*   **Join Height:** The height where the prop intersects with the backrest will be named `join_height`.
*   **Lip Height:** I need a small lip at the front of the base, and its height should be adjustable using `lip_height`.
*   **Thickness:** All parts of the stand should have an adjustable thickness, called `structure_thickness`.
*   **Edge Holders:** I'd like to optionally add side edge holders, either on the left, right, or both sides. This should be a setting called `edge_holder` that can be set to `0` for none, `1` for left, `2` for right, and `3` for both.

I think this can be accomplished by creating a `stand()` module that uses `linear_extrude` and `hull` to create the basic forms. I also expect that the edge holders are going to be made by using `linear_extrude` on the same set of points as the main shape, just translated in one direction.

Could you generate an OpenSCAD file for me that implements all of this with these parameters? I don't need anything that requires additional external libraries.

[Assistant]
stand.scad:
```
//CUSTOMIZER VARIABLES

// The width of the stand when looking from the front
stand_width = 50;

// The depth of the spot in which the stood object sits
bottom_depth = 50;

// The height of the stand measured up the backrest
backrest_height = 150;

// The angle that the stood object leans back
lean_angle = 20;

// The distance between the points of contact when the stand is leaned back
base_distance = 100;

// The height at which the prop intersects with the backrest
join_height = 100;

// The height of the lip
lip_height = 10;

// The thickness of all parts of the stand
structure_thickness = 15;

// Whether to place an edge holder on the side(s) of the stand
edge_holder = 0; // [0:None, 1:Left, 2:Right, 3:Both]

//CUSTOMIZER VARIABLES END

module stand(width=stand_width, depth=bottom_depth, height=backrest_height, angle=lean_angle, base=base_distance, join=join_height, lip=lip_height, thickness=structure_thickness, edge=edge_holder) {
    backrest_top = [-(thickness/2),height-(thickness/2),0];
    backrest_bottom = [-(thickness/2),-(thickness/2),0];
    holder_front = [depth+(thickness/2),-(thickness/2),0];
    lip_top = [depth+(thickness/2),lip -(thickness/2),0];
    prop_join = [-(thickness/2),join-(thickness/2),0];
    prop_bottom = [-cos(angle) * base + (thickness/2),sin(angle) * base - (thickness/2),0];

    // Add some width to accomodate the edges, if included
    total_width = width + ((edge == 1 || edge == 3) ? thickness : 0) + ((edge == 2 || edge == 3) ? thickness : 0);

    // Flip the whole thing over for easier printing if there's a holder on the left side
    rotate_all = edge == 1 ? [0, 180, 0] : [0, 0, 0];
    translate_all = edge == 1 ? [0, 0, total_width] : [0, 0, 0];

    translate(translate_all) rotate(rotate_all) {
        linear_extrude(height = total_width)
        {
            // Backrest
            hull() {
                translate(backrest_top) circle(d=thickness);
                translate(backrest_bottom) circle(d=thickness);
            }
            // Stand
            hull() {
                translate(prop_join) circle(d=thickness);
                translate([prop_join[0],max(prop_join[1]-thickness/2, -thickness/2),prop_join[2]]) circle(d=thickness);
                translate(prop_bottom) circle(d=thickness);
            }
            // Holder
            hull() {
                translate(backrest_bottom) circle(d=thickness);
                translate(holder_front) circle(d=thickness);
            }
            // Lip
            hull() {
                translate(holder_front) circle(d=thickness);
                translate(lip_top) circle(d=thickness);
            }
        }
        // Left edge holder
        if (edge == 1 || edge == 3) {
            translate([0, 0, total_width - thickness]) linear_extrude(height = thickness)
            hull() {
                translate(backrest_top) circle(d=thickness);
                translate(backrest_bottom) circle(d=thickness);
                translate(holder_front) circle(d=thickness);
                translate(lip_top) circle(d=thickness);
            }
        }
        // Right edge holder
        if (edge == 2 || edge == 3) {
            linear_extrude(height = thickness)
            hull() {
                translate(backrest_top) circle(d=thickness);
                translate(backrest_bottom) circle(d=thickness);
                translate(holder_front) circle(d=thickness);
                translate(lip_top) circle(d=thickness);
	        }
        }
    }
}

stand();

```


[User]
Hi, I'm looking for help designing a parametric filament spool holder spacer for the TUSH spool holder. I've got a couple of existing SCAD files that I've been using, but they're a bit limited and I want something more flexible and robust, and I'd like a unified design instead of two separate files.

Essentially, it's a spacer that sits between the two uprights of the TUSH holder, and it needs to accommodate different spool widths and allow for optional additional features. Here's a breakdown of the key parts and parameters I need:

**Core Structure:**

*   **Block:** The design should have two identical blocks, one on each end, that are cuboids with adjustable width (`Breite_Block`), depth (`Tiefe_Block`), and height (`Hoehe_Grundflaeche`). The blocks are separated by a central connector.
*   **Connector:** There's a flat connector between the two blocks, a cuboid with adjustable depth (`Tiefe_Verbindung`) and height (`Hoehe_Verbinder`). It bridges the two blocks. The overall distance between blocks and width of the connector is dictated by the overall spool width, which I'll call `Abstand`. The width of this connector and the spacing of the blocks is not defined directly but instead computed based on the `Abstand`, `Breite_Block` and `Dicke_Wand`.
*   **Walls:** There are walls on the sides of each block that extend upwards with adjustable thickness (`Dicke_Wand`) and height (`Hoehe_Wand`). These are built off the top of `Hoehe_Grundflaeche`.
*   **Text:** I need the ability to put text on the connector, in the center. The text should be customizable (`Text`) with configurable font (`Schriftart`), size (`Schriftgroesse`), and spacing between characters (`Buchstaben_Abstand`). It should be horizontally and vertically centered on the connector.

**Optional Features:**

*   **Double Spacer:** I'd like to be able to optionally add a second complete spacer unit that's identical to the first. This second unit should have its own distance from the first, adjustable by a `Abstand_tush_Verbinder` parameter. It should also have its own connector.
*   **Mid Text:** If I use the double spacer feature, I would also want to add text, centered along the length of the connector between the two spacers. This should also have adjustable font (`Schriftart`), size (`Schriftgroesse`), and spacing (`Buchstaben_Abstand`), and customizable content (`Text_Mitte`).

**General:**

*   **Fineness:** I want to control the fineness/smoothness of the curves using `$fn`.
*   **Units:** I'm working in millimeters.
*   **Parametric:** Everything should be fully parametric, allowing me to change all the parameters via the customizer.

**Specific parameters I'd like to be exposed to the user are:**

*   `Feinheit` (for `$fn`)
*   `Breite_Block`
*   `Tiefe_Block`
*   `Tiefe_Verbindung`
*   `Hoehe_Grundflaeche`
*   `Hoehe_Verbinder`
*   `Abstand`
*   `Dicke_Wand`
*   `Hoehe_Wand`
*   `Text`
*   `Schriftart`
*   `Schriftgroesse`
*   `Buchstaben_Abstand`
*   `Doppelter_Spacer` ("yes" or "no" toggle)
*   `Abstand_tush_Verbinder`
*   `Text_Mitte`

Could you please create an OpenSCAD file (or files) that implements this? I'm not using any particular libraries, but I'm open to suggestions if you have any.

[Assistant]
Filamenthalter_Verbinder_neu.scad:
```
/* [Spacer] */

// fineness($fn)
Feinheit=30; // [10:200]

// width block
Breite_Block = 20.6;

// depth block
Tiefe_Block = 30;

// depth connector
Tiefe_Verbindung = 15;

// height footprint
Hoehe_Grundflaeche = 20;

// height connector footprint
Hoehe_Verbinder = 2;

// distance
Abstand = 58;

// thickness wall
Dicke_Wand = 2.4;

// height wall
Hoehe_Wand = 15;

Text = "58 mm";

// font
Schriftart="Roboto";

// fontsize
Schriftgroesse=5; // [2:25]

// font spacing
Buchstaben_Abstand=1; // [1:0.1:3]

/*[Optional features]*/
    //Doppelter Spacer
Doppelter_Spacer     = "yes";  // [yes, no]

// distance_tush_connector
Abstand_tush_Verbinder = 80;

Text_Mitte = "Kaisertech";

/* [hidden] */
$fn=Feinheit;

{
Breite_Verbindung = Abstand-(2*Breite_Block+4*Dicke_Wand)/2;
}

{
    //Block links
cube([Breite_Block+2*Dicke_Wand,Tiefe_Block,Hoehe_Grundflaeche]);
    //Block rechts
translate([Breite_Block+2*Dicke_Wand+Breite_Verbindung,0,0]) cube([Breite_Block+2*Dicke_Wand,Tiefe_Block,Hoehe_Grundflaeche]);
    //Verbinder
translate([Breite_Block+2*Dicke_Wand,Tiefe_Block/2-Tiefe_Verbindung/2,0]) cube([Breite_Verbindung,Tiefe_Verbindung,Hoehe_Verbinder]);
    //linke Wand links
translate([0,0,Hoehe_Grundflaeche]) cube([Dicke_Wand,Tiefe_Block,Hoehe_Wand]);
    //rechte Wand links
translate([Breite_Block+Dicke_Wand,0,Hoehe_Grundflaeche]) cube([Dicke_Wand,Tiefe_Block,Hoehe_Wand]);
    //linke Wand rechts
translate([Breite_Block+2*Dicke_Wand+Breite_Verbindung,0,Hoehe_Grundflaeche]) cube([Dicke_Wand,Tiefe_Block,Hoehe_Wand]);
    //rechte Wand rechts
translate([Breite_Block+2*Dicke_Wand+Breite_Verbindung+Breite_Block+2*Dicke_Wand-Dicke_Wand,0,Hoehe_Grundflaeche]) cube([Dicke_Wand,Tiefe_Block,Hoehe_Wand]);
}
translate([Breite_Block+2*Dicke_Wand+Breite_Verbindung/2,Tiefe_Block/2,Hoehe_Verbinder]) linear_extrude(1) text(Text,size=Schriftgroesse,font=Schriftart,halign="center",valign="center",spacing=Buchstaben_Abstand);

if(Doppelter_Spacer == "yes")
{  //Spacer2
translate([0,Abstand_tush_Verbinder,0])
{
    //Block links
cube([Breite_Block+2*Dicke_Wand,Tiefe_Block,Hoehe_Grundflaeche]);
    //Block rechts
translate([Breite_Block+2*Dicke_Wand+Breite_Verbindung,0,0]) cube([Breite_Block+2*Dicke_Wand,Tiefe_Block,Hoehe_Grundflaeche]);
    //Verbinder
translate([Breite_Block+2*Dicke_Wand,Tiefe_Block/2-Tiefe_Verbindung/2,0]) cube([Breite_Verbindung,Tiefe_Verbindung,Hoehe_Verbinder]);
    //linke Wand links
translate([0,0,Hoehe_Grundflaeche]) cube([Dicke_Wand,Tiefe_Block,Hoehe_Wand]);
    //rechte Wand links
translate([Breite_Block+Dicke_Wand,0,Hoehe_Grundflaeche]) cube([Dicke_Wand,Tiefe_Block,Hoehe_Wand]);
    //linke Wand rechts
translate([Breite_Block+2*Dicke_Wand+Breite_Verbindung,0,Hoehe_Grundflaeche]) cube([Dicke_Wand,Tiefe_Block,Hoehe_Wand]);
    //rechte Wand rechts
translate([Breite_Block+2*Dicke_Wand+Breite_Verbindung+Breite_Block+2*Dicke_Wand-Dicke_Wand,0,Hoehe_Grundflaeche]) cube([Dicke_Wand,Tiefe_Block,Hoehe_Wand]);
}

{
    //Spacer_Verbinder
translate([Breite_Block+2*Dicke_Wand+Breite_Verbindung/2-Tiefe_Verbindung/2,Tiefe_Block/2+Tiefe_Verbindung/2,0]) cube([Tiefe_Verbindung,Abstand_tush_Verbinder,Hoehe_Verbinder]);

    //Text Mitte
translate([Breite_Block+2*Dicke_Wand+Breite_Verbindung/2,Tiefe_Block/2+Abstand_tush_Verbinder/2,Hoehe_Verbinder])rotate([0,0,90]) linear_extrude(1) text(Text_Mitte,size=Schriftgroesse,font=Schriftart,halign="center",valign="center",spacing=Buchstaben_Abstand);
}}
```
Filamenthalter_Verbinder_mit_Text_modifiziert.scad:
```
/* [Spacer] */

// fineness($fn)
Feinheit=30; // [30:100]

// width block
Breite_Block = 20.6;

// depth block
Tiefe_Block = 30;

// depth connector
Tiefe_Verbindung = 15;

// height footprint
Hoehe_Grundflaeche = 2;

// distance
Abstand = 63;

// thickness wall
Dicke_Wand = 3;

// height wall
Hoehe_Wand = 15;
Text = "Janbex";

// font
Schriftart="Roboto";

// fontsize
Schriftgroesse=5; // [2:25]

// font spacing
Buchstaben_Abstand=1; // [1:0.1:3]

/* [hidden] */
$fn=Feinheit;

{
Breite_Verbindung = Abstand-Breite_Block;
}

{
cube([Breite_Block,Tiefe_Block,Hoehe_Grundflaeche]);
translate([Breite_Block+Breite_Verbindung,0,0]) cube([Breite_Block,Tiefe_Block,Hoehe_Grundflaeche]);
translate([Breite_Block,Tiefe_Block/2-Tiefe_Verbindung/2,0]) cube([Breite_Verbindung,Tiefe_Verbindung,Hoehe_Grundflaeche]);
translate([0,0,Hoehe_Grundflaeche]) cube([Dicke_Wand,Tiefe_Block,Hoehe_Wand]);
translate([Breite_Block-Dicke_Wand,0,Hoehe_Grundflaeche]) cube([Dicke_Wand,Tiefe_Block,Hoehe_Wand]);
translate([Breite_Block+Breite_Verbindung,0,Hoehe_Grundflaeche]) cube([Dicke_Wand,Tiefe_Block,Hoehe_Wand]);
translate([Breite_Block+Breite_Verbindung+Breite_Block-Dicke_Wand,0,Hoehe_Grundflaeche]) cube([Dicke_Wand,Tiefe_Block,Hoehe_Wand]);
}
translate([Breite_Block+Breite_Verbindung/2,Tiefe_Block/2,Hoehe_Grundflaeche]) linear_extrude(1) text(Text,size=Schriftgroesse,font=Schriftart,halign="center",valign="center",spacing=Buchstaben_Abstand);
```


[User]
I'm looking to create a parametric tool for threading elastic bands and cords, like those used in waistbands or hoodies. I need an OpenSCAD file that can adjust to different band widths and thicknesses.

Here's a breakdown of what I'm envisioning:

*   **Core Shape:** The tool will have three main longitudinal sections or "pötkylä" as I called them - two rounded edge pieces on the sides and a rectangular center piece that connect at a slight angle.
*   **Band Channel:** There needs to be a channel running the length of the tool where the band or cord will sit. This channel needs to be configurable for band width and thickness.
*   **Rounded Ends:** The tool should have smooth, rounded ends for easy insertion into the garment tunnels and have a slightly pointed tip for easier threading.
*   **Guiding Reika/Holes:** the tool will have a guiding reika (hole) in each of the side pieces and a guiding reika in the middle pötkylä. These reikat need to have a thickness slightly greater than the band thickness, and a width slightly greater than the band width. The guiding reikas will have a slight "hull" effect where they appear to be holes that have been punched into the solid model rather than cut all the way through.

**Parameters:**

*   `band_width`: The width of the band/cord in millimeters.
*   `band_thickness`: The thickness of the band/cord in millimeters.

I'd like the design to be flexible enough to handle a range of band widths (say, 1mm to 50mm) and thicknesses (0.2mm to 5mm). The specific measurements for the guiding reikas should also be derived from these parameters, as per my example code.

I'd prefer to use a library for the hull effect if one is appropriate. Can you help me generate the OpenSCAD files for this?

[Assistant]
parametrinen_kuminauhanpujotin2.scad:
```
// band width[mm]
nauhanleveys = 10; // [1:1:50]
// band thickness[mm]
nauhanpaksuus = 1; // [0.2:0.1:5]

module takareika(){
hull(){
translate([1.25+nauhanleveys/20,-5,4])
cube([nauhanleveys+0.5,0.1,nauhanpaksuus+0.5,]);
translate([1.25+nauhanleveys/20,4,14])
cube([nauhanleveys+0.5,0.1,nauhanpaksuus+0.5,]);
}}

module etureika(){
hull(){
translate([1.25+nauhanleveys/20,-5,12.75+nauhanpaksuus+nauhanleveys/4])
cube([nauhanleveys+0.5,1,nauhanpaksuus+0.5]);
translate([1.25+nauhanleveys/20,4,12.75+nauhanpaksuus+nauhanleveys/4])
cube([nauhanleveys+0.5,1,nauhanpaksuus+0.5]);
}}

$fn = 30;

difference(){
hull(){  // vasen reuna
translate([0,0,0.5])
cylinder(h=1, r=1.5+nauhanleveys/20, center=true);
translate([1.5+nauhanleveys/20,0,50])
cylinder(h=1, r=0.5+nauhanleveys/20, center=true);
}
// viiste
hull(){
translate([0,-5,51])
cube([1.5+nauhanleveys/20,10,1]);
translate([-10,-5,40])
cube([10,10,1]);
}
etureika();
takareika();
}

difference(){
hull(){ // oikea reuna
translate([nauhanleveys+3+nauhanleveys/10,0,0.5])
cylinder(h=1, r=1.5+nauhanleveys/20, center=true);
translate([nauhanleveys+1.5+nauhanleveys/20,0,50])
cylinder(h=1, r=0.5+nauhanleveys/20, center=true);
}
//viiste
hull(){
translate([1.5+nauhanleveys+nauhanleveys/20,-5,51])
cube([10,10,1]);
translate([3+nauhanleveys+nauhanleveys/10,-5,40])
cube([10,10,1]);
}
etureika();
takareika();
}

difference(){
hull(){ // keskipötkylä
translate([0,-1.5-nauhanleveys/20,0])
cube([nauhanleveys+3+nauhanleveys/10,3+nauhanleveys/10,1]);

translate([1.5+nauhanleveys/20,-0.5-nauhanleveys/20,50])
cube([nauhanleveys,1+nauhanleveys/10,1]);
}

etureika();
takareika();
}

// kärki:

hull(){
translate([1.5+nauhanleveys/20,-0.5-nauhanleveys/20,50])
cube([nauhanleveys,1+nauhanleveys/10,1]);

translate([1+nauhanleveys/2+nauhanleveys/20,-0.5-nauhanleveys/20,58])
cube([1,1+nauhanleveys/10,1]);
}

```


[User]
I'm looking to create a customizable enclosure for a PCB, and I really like the idea of a weighted base for stability. I was inspired by the "Leadfoot" design I found online, but I need something that's fully parametric and I'd like it to be generated from scratch.

Here's what I'm envisioning. The enclosure will have two main parts: the main body and a plug for the ballast hole. The main body needs to accommodate a PCB with adjustable dimensions (width, depth, and thickness) and rounded corners. The case itself should have a configurable thickness, with the option for either rounded or right-angled corners. I want the option to add a "lead foot," meaning a hollow space in the bottom that can be filled with sand or some other ballast. The height of this ballast space should also be adjustable.

I'd also like the flexibility to add ledgers (or standoffs) along the edges of the PCB to properly support it. I want to configure whether these ledgers are on the right/left and front/rear sides independently, and adjust their widths.

Mounting holes for the PCB are crucial. I need to be able to choose between drilled holes and pegs, control their distance from the PCB edge, and set the height of the spacers between the PCB and the base. If I choose drilled holes, it should be possible to add recesses for threaded hex nuts on the bottom of the case. I should be able to specify if these are needed, their wrench size, and also the drill diameter of the mounting holes, spacer diameter and spacer height.

Finally, I'd like a simple way to customize any text displayed on the side of the enclosure.

I'd like to control the tolerance as a variable, and to avoid any unnecesary small numbers, please define a value eps as 0.001.

I'd like to use the `BOSL2` library, so please ensure that's included. I would like the output to be in multiple files for better organization. Also, could the file be written so it allows using custom fonts?

[Assistant]
leadfoot.scad:
```
// Lead Foot PCB enclosure
// by Stellar Innovation
// http://www.thingiverse.com/stellarinnovation/about
// under Creative Commons License, Attribution (BY)
//
// The bottom of the box is hollow. It's filled with sand to make
// it heavy and stable.

/*[PCB Dimensions]*/
pcb_width = 80;                 // [5:160]
pcb_depth = 50;                 // [5:100]
pcb_thickness = 1.6;            // [0.8:0.1:2.0]
pcb_corner_radius = 3;          // [0:0.1:10]

/*[Case]*/
case_thickness = 1.6;           // [1:0.1:5]
// round or right-angled corners
case_with_radius = 1;           // [0:no, 1:yes]
// Size of "lead foot" (space for ballast)
lead_foot_height = 8;           // [2.5:0.1:20]
ledger_width = 3.5;             // [0:0.1:5]
with_right_and_left_ledger = 1; // [0:no, 1:yes]
with_front_and_rear_ledger = 1; // [0:no, 1:yes]

/*[Mounting Holes]*/
mounting_holes = 1;             // [0:none, 1:drilled, 2:pegs]
// distance from edge of pcb
mounting_hole_distance = 3.5;   // [1:0.1:10]
// distance between pcb and "floor"
spacer_height = 2;              // [0:0.1:10]
spacer_diam = 6;                // [0:0.1:10]
drill_diam = 2.8;               // [0:0.1:3.5]
// Holes for threaded nuts on the bottom
with_hex_nut = 1;               // [0:no, 1:yes]
// distance between flats (5mm for M2.5 nut, 6.35mm=1/4" for UNC 4-40)
hex_wrench_size = 5;            // [3:0.1:10]

//
// This is what we build...
//

CustomizableLeadFootCase();

//
// This is how it's done...
//

/*[Hidden]*/
tol = 0.1;      // tolerance, 0.1mm is a tight fit
eps = 0.001;
infinity = 1/0;

hex_nut_outer_diam = hex_wrench_size*2/sqrt(3);  // diameter of circumcircle

// case
floor_thickness = (lead_foot_height==0)? 0 : 0.8;
drilled_mounting_holes = 1;
mounting_pegs = 2;
sane_spacer_diam = (mounting_holes==drilled_mounting_holes && spacer_diam <= drill_diam)?
                      0 : spacer_diam;
sane_spacer_height = (sane_spacer_diam>0)? spacer_height : 0;
case_height = case_thickness + lead_foot_height + floor_thickness
             + sane_spacer_height + pcb_thickness + tol;
case_corner_radius = (case_with_radius==0)? 0 : pcb_corner_radius + case_thickness;

// CustomizableLeadFootCase
//
// Adds spacers to a BasicLeadFootCase

module CustomizableLeadFootCase() {
  // (x0, y0) is at lower left mounting hole
  x0 = pcb_width/2 - mounting_hole_distance;
  y0 = pcb_depth/2 - mounting_hole_distance;
  board_z = case_height - pcb_thickness - tol;
  floor_z = board_z - sane_spacer_height;

  difference() {
    union() {
      BasicLeadFootCase();

      // spacers
      if (sane_spacer_height > 0) {
        for (x = [x0, -x0], y = [y0, -y0])
          translate([x, y, 0]) {
            // actual spacer
            cylinder(d=spacer_diam, h=board_z, $fn=30);
          }
      }

      // walls around hex nut
      if (with_hex_nut && hex_wrench_size > 0) {
        hex_diam = hex_nut_outer_diam + 2*tol + 2*case_thickness;
        for (x = [x0, -x0], y = [y0, -y0])
          translate([x, y, 0])
            cylinder(d=hex_diam, h=floor_z, $fn=6);
      }
    }

    if (mounting_holes==drilled_mounting_holes && drill_diam > 0) {
      for (x = [x0, -x0], y = [y0, -y0])
        translate([x, y, 0]) {
          cylinder(d=drill_diam, h=case_height, $fn=30);

          if (with_hex_nut==1) {
            // hole for hex nut
            cylinder(d=hex_nut_outer_diam + 2*tol, h=floor_z - case_thickness, $fn=6);
          }
        }
    }
  }

  if (mounting_holes==mounting_pegs && drill_diam > 4*tol) {
    for (x = [x0, -x0], y = [y0, -y0])
      translate([x, y, board_z]) {
        cylinder(d=drill_diam - 2*tol, h=pcb_thickness, $fn=20);
        translate([0,0,pcb_thickness])
          cylinder(d1=drill_diam - 2*tol, d2=drill_diam - 4*tol, h=2*tol, $fn=20);
      }
  }
}

// BasicLeadFootCase
//
// BasicCase with an empty space for sand/ballast, a support structure, a logo on the side
// and a plug

module BasicLeadFootCase() {
  // cutout for PCB
  w = pcb_width + 2*tol;
  d = pcb_depth + 2*tol;
  h = pcb_thickness + tol;

  thick_wall = 4;
  smallest_useful_space = 2.5; // don't want smaller empty space

  difference() {
    BasicCase();

    // any space left for sand/ballast?
    if (lead_foot_height >= smallest_useful_space
      && pcb_width > 2*thick_wall
      && pcb_depth > 2*thick_wall) {
      translate([0, 0, case_thickness]) {
        // hollow interior
        round_box(pcb_width + 2*case_thickness - 2*thick_wall,
                   pcb_depth + 2*case_thickness - 2*thick_wall,
                   lead_foot_height,
                   pcb_corner_radius);

        // round hole (where the sand goes)
        translate([0, 0, lead_foot_height/2])
          rotate([0, 90])
            cylinder(d=lead_foot_height, h=w + case_thickness, $fn=30);
      }

      // logo on the side
      text_size = min(0.8*case_height, 0.6*pcb_width);
      text_thickness = 1;
      if (text_size >= 4)
        translate([-0.8*text_size, -d/2-case_thickness+text_thickness, (case_height - text_size)/2])
          rotate([90, 0])
            linear_extrude(height=text_thickness)
              text("Pb'", size=text_size);
    }
  }

  if (lead_foot_height >= smallest_useful_space) {
    // build support needed
    support_forest(w + 2*case_thickness - 2*thick_wall,
                   d + 2*case_thickness - 2*thick_wall,
                   lead_foot_height+case_thickness,
                   grid=5);

    // ...and a plug for the hole
    some_space = 2;
    translate([w/2 + case_thickness + lead_foot_height/2 + some_space, 0])
      cylinder(d1=lead_foot_height - 1*tol, d2=lead_foot_height - 3*tol, h = case_thickness, $fn=30);
  }
}

// BasicCase
//
// case with rounded corners, a ledger and stand-off between PCB and "floor"

module BasicCase() {
  // cutout for PCB
  w = pcb_width + 2*tol;
  d = pcb_depth + 2*tol;
  h = pcb_thickness + tol;

  difference() {
    // actual case
    round_box(w + 2*case_thickness,
               d + 2*case_thickness,
               case_height,
               case_corner_radius);

    // cutout for PCB
    translate([0, 0, case_height-h])
      round_box(w, d, h, pcb_corner_radius);

    // space between pcb and floor (as specified by spacer_height)
    sane_ledger_width = (with_right_and_left_ledger || with_front_and_rear_ledger)?
      ledger_width : 0;
    w_less_ledger = w-2*sane_ledger_width;
    d_less_ledger = d-2*sane_ledger_width;
    h_less_ledger = case_height-sane_spacer_height-h;

    translate([0, 0, h_less_ledger]) {
      round_box(w_less_ledger, d_less_ledger, case_height, pcb_corner_radius - sane_ledger_width);

      if (!with_right_and_left_ledger && sane_ledger_width > 0) {
        translate([-w/2, -d_less_ledger/2])
          cube([w, d_less_ledger, case_height]);
      }

      if (!with_front_and_rear_ledger && sane_ledger_width > 0) {
        translate([-w_less_ledger/2, -d/2])
          cube([w_less_ledger, d, case_height]);
      }
    }
  }
}

// round_box
//
// dimensions width x depth x height
// radius is the corner radius

module round_box(width, depth, height, radius) {
  x0 = width/2 - radius;
  y0 = depth/2 - radius;

  if (radius > 0) {
    for (x = [-x0,+x0], y=[-y0, y0])
      translate([x,y])
        cylinder(r=radius, h=height, $fn=30);
    translate([-x0, -depth/2])
      cube([2*x0, depth, height]);
    translate([-width/2, -y0])
      cube([width, 2*y0, height]);
  }
  else
    translate([-width/2, -depth/2])
      cube([width, depth, height]);
}

// direction(n) direction of the tree branches
//
// +1 for even n, -1 for odd n.
function direction(n) = (n == 2*floor(n/2))? +1 : -1;

// length(n) length of the tree branches
//
// Returns 2**(k+1) - 1, where 2**k is the greatest power of two of which n is a multiple
// For instance
// length(1) = 1,  power of two 1 = 2**0, so k=0 and 2**(k+1) - 1 = 1
// length(2) = 3,  k = 1
// length(3) = 1,  k = 0
// length(4) = 7,  k = 2
//
// length(0) is unbounded, generalized for negative numbers: length(-n) = length(1-n)
// so length(-1) is unbounded, length(-2) = 1, length(-3) = 3 and so on.

function length_helper(n, d) = (n == 0 || n == -1)? infinity
                                                     : (let (n_2 = floor(n/2), d_2 = direction(n_2))
                                                       (d == d_2)? 1 + 2*length_helper(n_2, d_2)
                                                                   : 1);

function length(n) = length_helper(n, direction(n));

// support_forest
//
// Creates a branching support structure ("forest of trees").
// [width, depth, height]  specifies the dimension of the support structure
//                          supporting walls and a floor is assumed
// grid                     specifies spacing of leaves
// thickness                thickness of branches

module support_forest(width, depth, height, grid, thickness=1.15) {
  C = floor(width/grid/2 - 0.5);
  R = floor(depth/grid/2 - 0.5);

  if (C > 0 && R > 0) {
    height_grid = grid/sqrt(2);
    extraLength = thickness/sqrt(2);  // to make a flat cut at top and bottom
    maxLength = height/height_grid + extraLength;

    intersection() {
      // bounding cube
      translate([-width/2, -depth/2, 0])
        cube([width, depth, height]);

      // the actual forest
      translate([0, 0, height]) {
        for (r = [-R-1:R], c = [-C-1:C]) {
          x = grid*(c+0.5);
          y = grid*(r+0.5);
          dx = direction(c);
          dy = direction(r);
          l = min(length(c), length(r), maxLength)*grid;
          //echo("(x,y) = (", x, ",", y, ")");
          //echo("direction(",c,",",r,") = (", direction(c), ",", direction(r), ")");
          //echo("length(",c,",",r,") = ",l);

          // translate top of branch to [x, y, z] and rotate it according to [dx, dy]
          // the branches vary in length and either terminate at the bottom of the bounding cube
          // or at a joining branch, which is longer.
          translate([x, y, 0])
            rotate(a=45, v=[dy, -dx, 0])
              translate([-thickness/2, -thickness/2, -l])
                cube([thickness, thickness, l+extraLength]);
        }
      }
    }
  }
}

```


[User]
Hi, I'm looking for an OpenSCAD design for a customizable funnel. I've seen some examples out there but want to be able to control the key dimensions. I'd like to be able to specify:

*   The main funnel diameter at the top
*   The diameter of the middle of the funnel where it starts to transition to the pipe
*   The diameter of the pipe at the exit
*   The length of the pipe section
*   The thickness of the walls of the funnel
*   A "brim" that extends outward from the top of the funnel
*   The angle of the main funnel cone

I'd like the design to automatically generate a smooth transition from the main cone to the pipe section and be able to handle a range of sizes. The attached examples show various funnel sizes I've made using other models.

I think the key parameters should be something like:
*  `funnel_diameter`: The diameter of the top of the main cone
*  `mid_diameter`: The diameter where the cone transitions to the pipe
* `pipe_diameter`: The diameter of the pipe exit
*  `pipe_length`:  The length of the pipe section
*  `thickness`: The wall thickness
*  `brim`: The width of the brim around the top of the funnel
* `cone_angle`: The angle of the cone, in degrees

I'd like the design to use `difference()` and `union()` operations to create the solid funnel by subtracting the inside volume from the outside volume of the shape. This should ensure that the walls of the funnel have the specified thickness. I'd also like it to have a smooth transition from the cone to the pipe, and make sure that the very end of the pipe isn't razor-sharp, but has at least a minimum wall thickness of .41mm, as that's something I've had issues with in the past with similar designs.

The examples I included range from a funnel with a 50mm top diameter all the way down to an 18mm top diameter so it would be great if it worked for all those. I'm hoping the design will be fairly straightforward to customize and work well for 3D printing. No special libraries are needed, just plain OpenSCAD functionality. Thanks!

[Assistant]
customizable-funnel.scad:
```
// Customizable Funnel
// by Stellar Innovation
// http://www.thingiverse.com/stellarinnovation/about
// under Creative Commons License, Attribution (BY)

funnel_diameter = 50;    // [1:120]
mid_diameter    =  9;    // [0.5:0.1:30]
pipe_diameter   =  6;    // [0.5:0.1:30]
pipe_length     = 30;    // [10:100]
thickness       =  1.6;  // [0.25:0.05:2.00]
brim            =  4;    // [0:0.1:25]
cone_angle      = 60;    // [45:120]

CustomizableFunnel(funnel_diameter,
                   pipe_length,
		   mid_diameter,
		   pipe_diameter,
		   thickness,
		   brim,
		   cone_angle
                  );

module CustomizableFunnel(funnel_diam,
                          pipe_length,
                       	  pipe_diam1,
                     	  pipe_diam2,
                     	  thickness,
                     	  brim,
                     	  angle,
                     	  min_wall=0.41) {
  // main cone
  top = funnel_diam * 0.5/tan(angle/2);    // top of main cone
  pipe_attachment = top * (1 - pipe_diam1/funnel_diam); // this is where the pipe attaches
  height = pipe_attachment + pipe_length; // height of whole part

  // pipe
  // this is how wide the pipe would be if it extended to the base
  pipe_delta = (pipe_diam1 - pipe_diam2)/pipe_length;
  pipe_diam0 = pipe_diam1 + pipe_delta*pipe_attachment;
  // extra diameter of pipe with given thickness and slope
  extra_pipe_diam = 2*thickness*sqrt(1+pipe_delta*pipe_delta);

  difference() {
    union() {
      // main cone of funnel
      outside_top = top + thickness/sin(angle/2);        // this high with given thickness
      outside_diam = funnel_diam * outside_top/top;   // this wide with given thickness
      cylinder(d1=outside_diam, d2=0, h=outside_top, $fn=90);

      // pipe
      cylinder(d1=pipe_diam0+extra_pipe_diam,
               d2=pipe_diam2+extra_pipe_diam,
               h=height, $fn=90);

      // brim
      cylinder(d=funnel_diam+2*brim, h=thickness, $fn=90);
    }

    // inside of main cone
    cylinder(d1=funnel_diam, d2=0, h=top, $fn=90);

    // inside of pipe
    translate([0, 0, pipe_attachment])
      cylinder(d1=pipe_diam1, d2=pipe_diam2, h=pipe_length, $fn=90);

    // sharp end of pipe
    epsilon = 0.001; // err on the safe side (cut away too much)
    h = 4*thickness;
    d2 = pipe_diam2 + extra_pipe_diam + pipe_delta*h;
    translate([0, 0, height - h])
      difference() {
        cylinder(d=d2, h=h+epsilon, $fn=90);
        cylinder(d1=d2, d2=pipe_diam2+2*min_wall, h=h, $fn=90);
      }
  }
}

```


[User]
Hey! I'm looking to get a parametric bit holder designed in OpenSCAD. I've been tinkering with a few designs but I'd really love something that's easy to customize and fits my needs. I want to be able to control the number of bits it holds in both the X and Y directions, and also how tightly each bit fits into its holder. It'd also be great to add optional magnets for keeping the bits in place!

Here are the main parameters I'm thinking about:

*   **Number of bits in the X direction (`nx`)**: An integer greater than zero.
*   **Number of bits in the Y direction (`ny`)**: An integer greater than zero.
*   **Spacing between bits in the X direction (`spx`)**:  A value that can be positive for spacing or negative to connect the hexagonal shapes.
*   **Spacing between bits in the Y direction (`spy`)**:  A value that can be positive for spacing or negative to connect the hexagonal shapes.
*   **Bit holder depth (`bhh`)**: The depth of the hexagonal hole, should be at least 1mm, I think 6mm or more will probably work better.
*   **Base thickness (`bh`)**: The thickness of the bottom layer connecting all the holders, should be at least 1mm.
*   **Skirt in the negative X direction (`xb1`)**:  A border on the west side, for mounting/labeling, etc. Should be at least 0mm.
*   **Skirt in the positive X direction (`xb2`)**:  A border on the east side, for mounting/labeling, etc. Should be at least 0mm.
*   **Skirt in the negative Y direction (`yb1`)**: A border on the south side, for mounting/labeling, etc. Should be at least 0mm.
*   **Skirt in the positive Y direction (`yb2`)**: A border on the north side, for mounting/labeling, etc. Should be at least 0mm.
*   **Wall thickness (`wt`)**: Thickness of the walls of the hexagonal bit holders, between 0.3mm and 3mm, should take nozzle width into account.
*   **Tightness (`tn`)**: A value from 0 to 100% to control how tight the bits are. 0 is very loose, 100% very tight!
*   **Magnet hole depth (`mht`)**:  Depth of the hole for optional circular magnets. Can be from 0 up to the base thickness. Set to zero for no magnet holes.
*  **Magnet hole diameter (`mhd`)**: Diameter of the magnet holes. Don't forget to add print tolerance! Set to zero for no magnet holes.

I'd like the core shape of the bit holder to be hexagonal, and I want a way to connect the bases between the holders if desired using `spx` and `spy` set to negative values. I also need to include those little "squeezer" features inside the hexagons to help hold the bits more securely, and the tightness parameter needs to control the size of these squeezers.

For the magnet holes, they need to be centered in the hexagonal holders, and obviously only created if `mht` and `mhd` are greater than zero.

I'm not familiar with any particular OpenSCAD libraries, so if you use any I'd appreciate if you could list them.

Thanks a bunch!

[Assistant]
v2.scad:
```

//Number of bits in x-direction [>0]
nx=12;
//Number of bits in y-direction [>0]
ny=2;
//Spacing in x-direction [mm]. Values below 0 will connect the hexagonal shapes.
spx=-1;
//Spacing in y-direction [mm]. Values below 0 will connect.
spy=4;
//Depth of the hexagon shape for the bit [>1mm]. I advise >=6mm.
bhh=7;
//Thickness of the connecting bottom layer [>1mm]
bh=1.5;
//Skirt into the negative x-axis (west) [>0mm] (for fixing, holding down or labelling)
xb1=6;
//Skirt into the positive x-axis (east) [>0mm]
xb2=6;
//Skirt into the negative y-axis (south) [>0mm]
yb1=0;
//Skirt into the positive y-axis (north) [>0mm]
yb2=0;
//Thickness of the walls for the bitholders [0.3-3mm]. Also consider your nozzle-/print-width.
wt=2.5;
//Tightness. [0-100%], 0 is very loose, 100% is very tight!
tn=45;
//Circular magnet hole depth [0-(bh) mm]. Read more in this Things description. If you don't want to add magnets, set to zero.
mht=0;
//Magnet hole diameter [0-6mm]. Don't forget to add a little print tolerance!If you don't want to add magnets, set to zero.
mhd=0;

wallthickness=min(max(wt,0.3), 3);
ex=max(nx,1);
ey=max(ny,1);
bitholderdepth=max(bhh,1);
baseheight=max(bh,1);
yborder1=max(yb1,0);
yborder2=max(yb2,0);
xborder1=max(xb1,0);
xborder2=max(xb2,0);
innerbitradius=6.25+1.35;
sx = max(spx,-1)+innerbitradius+0.9+0.1;
sy = max(spy,-0.85)+innerbitradius+0.1;
tns=max(min(tn,100),0);
magt=max(min(mht, bh), 0);
magd=max(min(mhd, 6), 0);

difference() {
    union() {
        //Baseplate
        translate([-xborder1,-yborder1,0]) {
            minkowski() {
                cube([max((ex-1)*sx+xborder1+xborder2,0.01), max((ey-1)*sy+yborder1+yborder2,0.01), baseheight/2]);
                cylinder(d=7.6+wallthickness, h=baseheight/2, $fn=100);
            }
        }
        //Add the actual hexagonal bit holders
        difference() {
            for (x = [0:1:ex-1]) {
                for (y = [0:1:ey-1]) {
                    translate([x*sx,y*sy, baseheight]) {
                        bit(h=bitholderdepth, r=innerbitradius+wallthickness);
                    }
                }
            }

            for (x = [0:1:ex-1]) {
                for (y = [0:1:ey-1]) {
                    translate([x*sx,y*sy, baseheight]) {
                        bit(h=bitholderdepth+0.5, r=innerbitradius);
                    }
                }
            }
        }

        //Add squeezers to set a nice friction point.
        squeezer=0.05+((tns/100)*0.1);
        for (x = [0:1:ex-1]) {
            for (y = [0:1:ey-1]) {
                for (i=[30,210,-30,150]) {
                    translate([x*sx,y*sy, baseheight]) {
                        rotate(i) {
                            translate([3.35-squeezer,0,bitholderdepth/2]) {
                                cube([squeezer,2,0.3], center=true);
                            }
                        }
                    }
                }
            }
        }
    }

    //Connections between holders
    if (spy<0) {
        p=4;
        for (x = [0:1:ex-1]) {
            translate([-p/2+x*sx, 0, baseheight]) {
                cube([p, (ey-1)*(innerbitradius-0.75), bitholderdepth+0.5]);
            }
        }
    }

    if (spx<0) {
        for (y = [0:1:ey-1]) {
            s=0;
            translate([0, -s/2+y*sy-wallthickness/2, baseheight]) {
                cube([(ex-1)*innerbitradius, s+wallthickness, bitholderdepth+0.5]);
            }
        }
    }

    //Holes for magnets
    if (magt != 0 && magd != 0) {
        for (x = [0:1:ex-1]) {
            for (y = [0:1:ey-1]) {
                if (magt==bh) {
                    translate([x*sx,y*sy, magt/2]) {
                        cylinder(d=magd, h=magt+0.2, center=true, $fn=100);
                    }
                } else {
                    translate([x*sx,y*sy, magt/2-0.05]) {
                        cylinder(d=magd, h=magt+0.1, center=true, $fn=100);
                    }
                }
            }
        }
    }
}

module bit(r,h) {
    translate([0,0,h/2]) {
        cylinder(d=r, $fn=6, h=h, center=true);
    }
}
```


[User]
I'm looking to design a parametric replacement for an LM8UU linear bearing using standard ball bearings, specifically either 693ZZ (3x8x4) or 623ZZ (3x10x4) bearings. I've already done a version of this, which I've attached (693ZZ_bushing.scad), but I'd like to generalize it and make it more robust. Here’s the basic idea:

The core of the design should be a housing that holds three ball bearings. These bearings should be arranged so that they contact a rod or shaft, acting as a linear guide. This is for a 3D printer Y axis.

Here are the parameters I’d like to control:

*   **Bearing Type**: This should switch between the 693ZZ and 623ZZ bearings, adjusting all necessary dimensions based on the selected bearing. This will drive the diameter of the bearing pockets and the overall dimensions of the bearing assembly. The radius of each bearing is 4 and 5 respectively but need a trim factor to accommodate the fit, see below.
*   **Trim**:  I need to be able to trim the radius of the rod, as a negative number which can reduce the radius of the rod fit. The goal here is to control the tightness of the fit of the inner rod. Allow negative values.
*  **Mounting Holes**: I'll need mounting holes for M3 screws or similar. The position should be parametric and should allow the orientation of the design to mount either to the top or the bottom of a plane.
*   **Number of screws**:  The design should incorporate 4 screws in the Y axis and two nuts for the top face.

Also, I'd like the design to be modular, meaning, I should be able to generate a "top" version with nuts, and a "bottom" version without them. The nuts should be hexagonal.

Finally, could you please use the BOSL2 library for any of the functions related to fasteners/nuts/screws? If not in BOSL2, then use the most appropriate library. I'm aiming for a clean and efficient design, and of course, fully parametric. I'm thinking two files are needed: one for the bearing module and one for the housing.

Let me know if you need any further details.

[Assistant]
693ZZ_bushing.scad:
```
// bearing model : 693zz (3x8x4)  or 623zz (3x10x4)
bearing = "693zz"; // ["693zz", "623zz"]
// play with this value to trim the radius of the rod (negative value = reduce the radius)
trim = -0.05; //[-0.15,-0.1, -0.05, 0, 0.05, 0.1]
// which thing ? top or bottom ?
part = "top"; // ["bottom", "top"]
// do you want intermediate nuts ?
nuts = "no" ; //["yes","no"]

/* [Hidden] */
$fn = 100;
diam_vis = 3.1;
epsilon = 0.1;

// perform a test and assign a variable (if statement does not work ...)
bearing_radius =   ((bearing == "693zz") ? 4 : 5) +trim ;

module 693ZZ() {
    union () {
        #cylinder (d=9, h = 4,center = true);
   difference() { translate ([10-4.5,0,0] )  cube([22,2*bearing_radius+1,5.5], center = true);

       translate  ([0,0,2.55])cylinder(d=5, h = 1, center = true);
       translate  ([0,0,-2.55])cylinder(d=5, h = 1, center = true);
   }    // end diff
   } // end union

       # cylinder (d=3, h = 19, center = true);
    }

module top_bearings() {
  rotate ([90,0,120]) translate  ([4+bearing_radius,0,0])  693ZZ();

rotate ([90,0,-120]) translate  ([4+bearing_radius,0,0])  693ZZ();

    *rotate ([90,0,0]) translate  ([4+bearing_radius,0,0])  693ZZ();

    }

    module bottom_bearing() {
  *rotate ([90,0,120]) translate  ([4+bearing_radius,0,0])  693ZZ();

*rotate ([90,0,-120]) translate  ([4+bearing_radius,0,0])  693ZZ();

    rotate ([90,0,0]) translate  ([4+bearing_radius,0,0])  693ZZ();

    }

module four_screws(diam, faces) {
    translate  ([0,12,9]) rotate ([0,90,0]) cylinder(d= diam, h = 30, center = true, $fn =faces);
 translate  ([0,12,-9]) rotate ([0,90,0]) cylinder(d= diam, h = 30, center = true, $fn =faces);
 translate  ([0,-12,9]) rotate ([0,90,0]) cylinder(d= diam, h = 30, center = true, $fn =faces);translate  ([0,-12,-9]) rotate ([0,90,0]) cylinder(d= diam, h = 30, center = true, $fn =faces);
}

module top(){
difference(){
rotate ([0,0,-90])cube ([32,22,29],center = true);
 top_bearings();

 four_screws(diam_vis, 100);
 if (nuts == "yes") translate  ([14.5,0,0])   four_screws(6.1, 6);

cylinder (d=9, h = 50,center = true);

  translate([12,0,0])  cube ([20,50,50],center = true);
  translate([10,0,0])  cube ([20,9,50],center = true);
}
}
module bottom (){
difference(){
rotate ([0,0,-90])cube ([32,23,29],center = true);
 bottom_bearing();

 four_screws(diam_vis, 100);

cylinder (d=9, h = 50,center = true);

  translate([-8+epsilon,0,0])  cube ([20,50,50],center = true);
    translate([11,12,0])  cube ([10,10,50],center = true);
    translate([11,-12,0])  cube ([10,10,50],center = true);
}
}

if (part == "top") { rotate([0,-90,0])top();}
else {rotate([0,-90,0])bottom();}

```


[User]
I'm looking to design a custom lid for a Weizenbier glass (that's a wheat beer glass). It needs to fit snugly on the glass rim, which has an 80mm diameter, but I'd like to be able to adjust that parameter.

Here's what I envision: The lid itself should be fairly thin, maybe 0.6mm thick, but it should have a raised edge to help it stay in place, like a lip. The edge should extend about 1mm above the main lid surface. I'd also like to add some text to the top of the lid; let's start with "my name" as placeholder text. This text should be raised, maybe 0.4mm high, and I'd like to control the size and starting position of the text for easy customization. I was also hoping to add a second, negative text on the bottom but that may only work if the lid is thick enough.

Also, I'd like a small "clip" on the lid that would wrap around the glass handle, if there is one. This clip will need to rotate on a small hinge. I need to be able to choose if I want the clip printed, since some of the glasses don't have handles, but I also need to be able to vary the hinge's height, since not all glasses are perfect cylinders.

Ideally the whole design would be parametric with a bunch of variables at the top of the file, so I can easily adjust everything. I also want to be able to choose if I'd like the lid or the clip to be printed. I'd prefer to use the "Leckerli One" font, or be able to pick a different font easily. And finally I'd like it to be high resolution, so let's start with a `$fn=50`.

Can you create this in OpenSCAD, keeping all of this in mind?

[Assistant]
weizenbierglasdeckel_v5.4.scad:
```
glasdurchmesser=80;//Durchmesser oberer Rand
deckelhoehe=0.6;//wie dick soll der Deckel sein
schrifthoehe=0.4;//wie erhaben soll die Schrift sein. Ein Layer
randhoehe=1.0;//hoehe des Deckelrandes von der Deckelhoehe aus
TextOben="mein Name";//Text auf dem Deckel
LinkeEckeOben=37;//Abstand des Textanfangs zum Mittelpunkt, um den Text zu zentrieren
SchriftGroesseOben=11;//Schriftgroesse oben, bei langen Namen verringern
TextUnten="";//Text auf Unterseite, negativ
LinkeEckeUnten=30;//Abstand des Textanfangs zum Mittelpunkt, um den Text zu zentrieren
SchriftGroesseUnten=16;//Schriftgroesse unten, bei langen Namen verringern
font1 = "Leckerli One"; // here you can select other font type
$fn=50;
//was soll gedruckt werden? 0/1
klammer_drucken=0;
deckel_drucken=1;

// scharnierhoehe bei Weizenglas 0
// bei Sprudelglas 1.5
scharnierhoehe=0;

if(deckel_drucken==1){
difference(){
  union(){
    translate([0,0,0])cylinder(r=glasdurchmesser/2+2,h=deckelhoehe);
    difference(){
      translate([0,0,deckelhoehe])cylinder(r=glasdurchmesser/2+2,h=randhoehe);
      translate([0,0,deckelhoehe-0.1])cylinder(r=glasdurchmesser/2,h=randhoehe+0.2);
    }
    translate([0,glasdurchmesser/2-0.5,0])cylinder(r=10,h=deckelhoehe+randhoehe);
    translate([-7,glasdurchmesser/2,0])cube([14,25,deckelhoehe]);
    translate([0,glasdurchmesser/2+23,0])cylinder(r=8,h=3);
    translate([-7,glasdurchmesser/2-6.5,0])cube([14,29,3]);
    translate([-7,glasdurchmesser/2-6.5,1.5])rotate([0,90,0])cylinder(r=1.5,h=14);
    rotate([0,0,45]){
      translate([LinkeEckeOben*-1,SchriftGroesseOben/2*-1,deckelhoehe]){
        schrift(TextOben,SchriftGroesseOben,schrifthoehe);
    }
  }
  }
  translate([-3.2,glasdurchmesser/2-8,-0.1])cube([6.4,31,deckelhoehe+3]);
  translate([-5.3,glasdurchmesser/2+3,-0.1])cube([0.6,20,deckelhoehe+3]);
  translate([4.7,glasdurchmesser/2+3,-0.1])cube([0.6,20,deckelhoehe+3]);
  translate([-2.4,glasdurchmesser/2,7])cube([4.8,10,10]);
  mirror()rotate([0,0,180]){
    translate([LinkeEckeUnten*-1,15/2*-1,0]){
      schrift(TextUnten,SchriftGroesseUnten,schrifthoehe);
    }
  }
}

difference(){
  union(){
    translate([4.1,glasdurchmesser/2+12,1.5])sphere(r=2.2);
    translate([-4.1,glasdurchmesser/2+12,1.5])sphere(r=2.2);
  }
  translate([-10,glasdurchmesser/2+10,-2])cube([20,7,2]);
  translate([-10,glasdurchmesser/2+10,3])cube([20,7,2]);
  translate([-2.7,glasdurchmesser/2+10,0])cube([5.4,7,3]);
  translate([-5.3,glasdurchmesser/2+3,-0.1])cube([0.6,20,deckelhoehe+3]);
  translate([4.7,glasdurchmesser/2+3,-0.1])cube([0.6,20,deckelhoehe+3]);
}
}

if(klammer_drucken==1){
translate([20,55,0])klammer();
//um die Lage zu pruefen
//translate([-3,glasdurchmesser/2-2,deckelhoehe+-3])rotate([8,0,0])rotate([0,90,0])klammer();
//translate([-3,glasdurchmesser/2+19,-11])rotate([115,0,0])rotate([0,90,0])klammer();
}

module klammer(){
  difference(){
    union(){
      rotate([0,0,40])rotate_extrude(angle=280,convexity = 10){
        translate([2,0,0]){
          square([3,6]);
        }
      }
      translate([1.5,1,0])cube([20,3,6]);
      translate([21,2.3,0])cylinder(r=2,h=6);
      translate([1.5,-4,0])cube([20,3,6]);
      translate([21,-2.3,0])cylinder(r=2,h=6);
      translate([-2-scharnierhoehe,14,0])rotate([0,0,0])cylinder(r=6,h=6);
      translate([-5,0,0])cube([7,12,6]);
    }
    translate([-2-scharnierhoehe,14,-1])sphere(r=2.5);
    translate([-2-scharnierhoehe,14,7])sphere(r=2.5);
    translate([0,0,-1])rotate([0,0,0])cylinder(r=2.5,h=8);
    translate([0.5,-1,-0.1])cube([18,2,6.2]);
  }
}

module schrift(zeichen,groesse,hoehe){
  color("red")linear_extrude(height = hoehe) {
    text(zeichen, font = font1, size = groesse, direction = "ltr",  spacing = 1 );
  }
}

```


[User]
Hi, I'm looking for an OpenSCAD design for a guitar nut, specifically one that can be easily customized. I've seen a few designs out there, but I need one that I can tweak very precisely. I've got some specific needs.

Here are the things that need to be adjustable:

*   **Number of Strings:** I need to be able to specify how many strings the nut has slots for. This could range from 1 to 8 strings.
*   **Nut Width:** The overall width of the nut needs to be adjustable in millimeters.
*   **Nut Height Padding:** There should be a parameter to control the thickness of the horizontal part of the nut at its base.
*  **Nut Depth:** The depth of the nut, the dimension along the strings' direction, also needs to be adjustable.
*   **String Angle:** I need to be able to set the angle of the string slots within the nut.
*   **String Widths:** The width of each string slot needs to be independently adjustable. I need to specify a different width for each of the possible 8 strings.

The design should have the following features:

*   The string slots should have rounded bottoms for a better fit.
*   The small horizontal "lip" at the bottom should be a vertical bevel.

Basically, I want something that I can modify quickly to fit different guitars or basses I'm working on. I have a pretty good idea of how all the variables should work, so I'm not looking for anything super complicated or fancy here.

I'm also not looking to use any external libraries at this time.

[Assistant]
Guitar_Nut.scad:
```
/* [Nut Settings] */
// Number of strings to use. All equally spaced.
String_Count = 6; // [1:8]

// Width of entire nut in millimeters
Nut_Width = 43; // [10:100]

// Thickness of horizontal part in millimeters
Nut_Height_Padding = 2; // [0:10]

// Depth of nut, measured in the direction of the strings, in millimeters
Nut_Depth = 6; // [1:10]

// Angle of strings within nut
String_Angle = 20; // [0:60]

/* [String Widths] */
// Width of string #1 in millimeters
String_Width_1 = 1.25; // [0.1:10]

// Width of string #2 in millimeters
String_Width_2 = 1.15; // [0.1:10]

// Width of string #3 in millimeters
String_Width_3 = 0.85; // [0.1:10]

// Width of string #4 in millimeters
String_Width_4 = 0.60; // [0.1:10]

// Width of string #5 in millimeters
String_Width_5 = 0.45; // [0.1:10]

// Width of string #6 in millimeters
String_Width_6 = 0.40; // [0.1:10]

// Width of string #7 in millimeters
String_Width_7 = 0.35; // [0.1:10]

// Width of string #8 in millimeters
String_Width_8 = 0.30; // [0.1:10]

/* [Hidden] */
String_Spacing = (Nut_Width / String_Count);
String_Padding = String_Spacing / 2;

/*
	Guitar nut for acoustic guitar
*/

function GetStringWidth(i) =
	lookup
	(
		i,
		[
			[0, String_Width_1],
			[1, String_Width_2],
			[2, String_Width_3],
			[3, String_Width_4],
			[4, String_Width_5],
			[5, String_Width_6],
			[6, String_Width_7],
			[7, String_Width_8]
		]
	);

module MakeGaps()
{
	for (i = [0:(String_Count - 1)])
	{
		translate([4.5 + Nut_Height_Padding, String_Padding + (String_Spacing * i), (-0.75)])
			rotate([0, (-String_Angle), 0])
				union()
				{
					cylinder(h = (Nut_Depth + 4), d = GetStringWidth(i), $fn = 60);
					translate([5, 0, (Nut_Depth / 2) + 2])
						cube([10, GetStringWidth(i), (Nut_Depth + 4)],center = true);
				}
	}
}

module Main()
{
	difference()
	{
		// The base cube
		cube([6 + Nut_Height_Padding, Nut_Width, Nut_Depth]);

		// Cutting off the end in angle
		translate([2.5 + Nut_Height_Padding, (Nut_Width / 2), (Nut_Depth + 2.6)])
			rotate(a = [0, 10, 0])
				cube([9, Nut_Width + 1, 6], center = true);

		// Gaps for the strings
		MakeGaps();
	}
}

Main();
```


[User]
I'd like a parametric design for a 3D-printable cuff, kind of like the one described in the provided code, but I need it to be a bit more flexible in its design. I'll be printing this in two halves, hinged together, and I want it to be lockable with a padlock.

Here's what I'm looking for in terms of parameters:

*   **Inner Diameter (inner_d):** This should be the diameter of the opening for the wrist/ankle.
*   **Thickness (thickness):** The overall thickness of the cuff material.
*   **Height (height):** The height of the cuff.
*   **Chamfer (chamfer):** The radius of the chamfer on the outer edges of the cuff. It should not be greater than half of the thickness.
*   **Cuff Gap (cuff_gap):** The space between the two halves of the cuff when it's open.
*   **Hinge Gap (hinge_gap):** The space between the hinge parts, for smooth movement.
*   **Hinge Height (hinge_height):** The height of the hinge portion.
*   **Pin Diameter (pin_dia):** The diameter of the pin used for the hinge.
*   **Pin Head Diameter (pin_head):** The diameter of the head of the hinge pin.
*  **Shackle Diameter (shackle_dia):** The diameter of the padlock shackle that will fit into the hasp.
*   **Shackle Offset (shackle_offset):** The distance between the outside of the cuff and the center of the shackle hole.
*  **Shackle Hasp Thickness (shackle_hasp_thickness):** The radial thickness of the loop that retains the padlock shackle.
*   **Shackle Hasp Height (shackle_hasp_height):** The thickness of the material around the shackle hole, this is the height of the loop that retains the lock.
*   **Pin Hinge Thickness (pin_hinge_thickness):** The wall thickness of the loops that form the hinge.

The design should include a hinge mechanism using a cylindrical hinge with an internal pin. The hinge parts need to have some space between them so that they can move freely. The cuff needs to be lockable with a padlock, using a hasp system. It's important that the padlock has some room to move freely after being locked, hence the shackle offset parameter.

I also want the code to generate the two halves of the cuff separately. It might be nice if you could comment out the copy_mirror function (or similar) so that we can test one half at a time.

I don't need any complex libraries - just standard OpenSCAD functions for cylinders, cubes, circles, and so on.

Let me know if you need any other info.

[Assistant]
cuff_v1.scad:
```
/*
*   Procedural Cuff
*   CudaTox, http://cudatox.ca/l/
*   @cudatox
*
*   Aug 18, 2017
*
*
* Copyright 2017 Cudatox
*
* Redistribution and use in source and binary forms, with or without modification, are permitted provided that
* the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the
* following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the
* following disclaimer in the documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*
*/

//Inner diameter
inner_d = 75;
//Thickness of the cuff
thickness = 7;
//Height of the cuff
height = 25;
//Radius of the chamfer around the cuff. Cannot be greater than thickness/2
chamfer = 2;
//Gap between halves of the cuff (where the cuff opens)
cuff_gap = 0.5;
//Gap between parts of the hinge
hinge_gap = 0.5;
//height of the hinge
hinge_height = 21.5;
//Diameter of the hinge pin
pin_dia = 6.4;
pin_head = 10;
//Diameter of the lock shackle
shackle_dia = 8.4;
//Distance of the shakle hole to the cuff. This leaves some room between the outside of the cuff and the hole for the padlock so that the padlock can move freely
shackle_offset = 1;
//This is the radial thickness of the loop that retains the lock
shackle_hasp_thickness = 5;
//This is the thickness of each peice that retains the shackle
shackle_hasp_height = 8;
//Wall thickness of the loops that make the hinge
pin_hinge_thickness=4;

//These are not user-adjustable parameters
hinge_diameter = pin_dia + pin_hinge_thickness * 2;
hasp_dia = shackle_hasp_thickness*2 + shackle_dia;

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

module rounded_rect(x, y, rad){

    copy_mirror(vec=[1,0,0]) copy_mirror(vec=[0,1,0]){
            union(){
                translate([x/2 - rad, y/2 - rad, 0]) circle(rad, true, $fn=50);
                square([x/2, y/2 - rad], false);
                square([x/2 - rad, y/2], false);
                }
    }

}

module half_cyl(h, d){
    difference(){
        cylinder(h=h, d=d, center=true, $fn=50);
        translate([-d/2,0,-h/2])cube([d,d,h]);
    }
}

module hinge_triangle(a, h){
    linear_extrude(height=h, center=true)
    polygon([
        [inner_d/2 + hinge_diameter, 0],
        [(inner_d/2 + thickness) * cos(a), (inner_d/2 + thickness)* sin(a)],
        [inner_d/2, 0],
        [inner_d/2 + hinge_diameter, 0]
    ]);

}

union(){
    difference(){
        rotate_extrude($angle=10, $convexity=2, $angle=180, $fn=100)
            translate([thickness/2 + inner_d/2, 0, 0])
                rounded_rect(thickness, height, chamfer);
        union(){
            //registration
            //TODO: make this work with all sizes of cuff.
            translate([-inner_d/2 - thickness, hasp_dia/2, 0])
                cube([thickness * 2.01, cuff_gap, height / 2], false);
            translate([-inner_d/2 - thickness, -hasp_dia/2 -cuff_gap, -height/2])
                cube([thickness * 2.01, cuff_gap, height / 2], false);
            translate([-inner_d/2, 0, 0])
                cube([thickness * 2.01, hasp_dia + cuff_gap * 2, cuff_gap], true);
            //Cut to remove section of cuff that intersects with inside of hinge
            //TODO: OpenSCAD complains about the object not being a 2-manifold when
            //this feature is enabled.
            translate([inner_d/2+hinge_diameter/2,0,0])
                cylinder(d=pin_dia, h=height, center=true, $fn=50);
            //Cutaway parts where hinge barrell should not touch cuff.
             hinge_cut = (pin_dia + 2 * pin_hinge_thickness + 2 * hinge_gap);
            translate([inner_d/2+hinge_diameter/2,0,0]){

                difference(){
                    half_cyl(height, hinge_cut);
                    half_cyl(hinge_height/3 - hinge_gap, hinge_cut);
                }
                mirror([0,1,0]) half_cyl(hinge_height/3 + hinge_gap, hinge_cut);
                //Remove remaining bits of cuff over the hinge
                translate([0,0,height/2])
                    cylinder(h=(height - hinge_height), d = hinge_cut, center=true);
                translate([0,0,-height/2])
                    cylinder(h=(height - hinge_height), d = hinge_cut, center=true);
            }

        }
    }

    //Hinge v2
    //reinforcement

    difference(){

        union(){
            difference(){
                hinge_triangle(30, hinge_height);
                //the 1.01 multiple is a kluge to fix the object not being a 2-manifold.
                hinge_triangle(30, hinge_height/3 + hinge_gap*1.01);
            }

            mirror ([0,1,0])hinge_triangle(30, hinge_height/3 - hinge_gap);
        }

        //Remove bits inside the hole for the pin.
        translate([inner_d/2+hinge_diameter/2,0,0])
            cylinder(d=pin_dia, h=height, center=true, $fn=50);
        //Remove any bits inside the cuff
        cylinder(d=inner_d, h=height, center=true, $fn=50);
    }

    translate([inner_d/2+hinge_diameter/2,0,0]) difference(){
        union(){
        //overall length = hinge length
        hinge_barrel_dia = (pin_dia+pin_hinge_thickness*2);
        cylinder(h=hinge_height, d=(pin_dia+pin_hinge_thickness*2), center=true, $fn=50);
        }
        //Gaps between hinge sections
        translate([0,0,hinge_height/3/2])
            cylinder(d=(pin_dia+pin_hinge_thickness*2), h=hinge_gap, center=true, $fn=50);
        translate([0,0,-hinge_height/3/2])
            cylinder(d=(pin_dia+pin_hinge_thickness*2), h=hinge_gap, center=true, $fn=50);
        //Hole for pin
        cylinder(d=pin_dia, h=height, center=true, $fn=50);
    }

    //Closure
    difference(){
    translate([-inner_d/2 - thickness + shackle_hasp_thickness - hasp_dia/2 - shackle_offset,0,0])
        difference(){
            union(){
                translate([inner_d/4,0,0]) cube([inner_d/2,hasp_dia,shackle_hasp_height * 2], true);
                cylinder(d=hasp_dia, h = 2 * shackle_hasp_height, center=true, $fn=50);
            }
            union(){
                translate([inner_d/4,0,0]) cube([inner_d/2,hasp_dia,hinge_gap], true);
                cylinder(d=hasp_dia, h = cuff_gap, center=true, $fn=50);
                cylinder(d=shackle_dia, h = 2 * shackle_hasp_height, center=true, $fn=50);
            }
        };
    cylinder(d=inner_d + thickness * 2, h = height, center=true);
    }
}
```


[User]
I'm looking to create a customizable Lego Technic beam with perpendicular axle and pin connectors. I need to be able to specify the number of pin holes, which will then determine the overall length of the beam. The beam should have the standard Technic pin hole spacing and dimensions. The pin holes should be able to accept standard Technic axles and pins.

I really like how the provided Lego_Technic-Axle_and_Pin_Connector_Perpendicular_customizable.scad file does it, but I'd like something that is a bit more flexible and doesn't assume that a cross is at the end. I'd like to be able to choose if the beam has those additional connector blocks at the end, and to put them where I choose, not only at the ends. Ideally, I'd specify the locations of the perpendicular pin connectors with a list or array. Also, I'd like to be able to independently customize the beam height, width, and pin hole depth, and be able to specify the dimensions of the mini-cubes that form the perpendicular connectors, and the size of the circle in the center of the pin hole.

So, to recap, I'm looking for a parametric design that lets me specify:

*   **Number of pin holes (and thus, overall length, as this determines that).** The spacing between these holes is fixed at 8 units.
*   **Optional perpendicular pin connectors**. I want to be able to specify the X coordinate location for them, as an array or similar data structure.
*   **Beam height.**
*   **Beam width.**
*   **Pin hole depth.**
*   **Mini-cube offset and width.**
*   **Cross Inner Radius**

I don't need any code directly provided as a response, but please make the generated .scad file use the following modules as part of the design:

*   `drawBeam()` - This should create the main beam with the holes.
*   `drawCross(x)` - This should create an individual perpendicular pin connector at a given X coordinate.
*   `OneCross()`- This is the old way to draw a perpendicular connector, and should be removed.

Please use the BOSL2 library for vector math, specifically for the `vadd` and `vsub` functions. I do not want any other external libraries used.

[Assistant]
Lego_Technic-Axle_and_Pin_Connector_Perpendicular_customizable.scad:
```
$fn=40;

eps = 0.05*1;

//Nuber of the holes
NrOfHoles = 3;

Pitch = 8*1;
Radius1 = 4.8 / 2;
Radius2 = 6.1 / 2;
Height = 7.8*1;
Depth = 0.8*1;
Width = 7.5*1;
MidThickness = 2*1;
MiniCubeOffset = 1.1*1; // was 0.9
MiniCubeWidth = Radius1 - MiniCubeOffset;
CrossInnerRadius = 1.5*1;

drawBeam();
translate([Pitch*(NrOfHoles/2-1),-Width/2,0])rotate([90,0,90])OneCross();

module drawBeam()
{
	Length = (NrOfHoles - 1) * Pitch;
	Thickness = (Width - 2 * Radius2) / 2;

	difference()
	{
		union()
		{
			cube([Length, Thickness, Height]);
			translate([0, Width-Thickness,0]) cube([Length, Thickness, Height]);
			translate([0, 0, Height/2-MidThickness/2]) cube([Length, Width, MidThickness]);
			for (i = [1:NrOfHoles])
			{
				translate([(i-1)*Pitch, Width/2,0])
				{
					cylinder(r=Width/2, h=Height);
				}
			}
		}

		union()
		{
			for (i = [1:NrOfHoles])
			{
				translate([(i-1)*Pitch, Width/2,0])
				{
					translate([0,0,-eps]) cylinder(r=Radius2,h=Depth+eps);
					translate([0,0,-eps]) cylinder(r=Radius1,h=Height+2*eps);
					translate([0,0,Height-Depth]) cylinder(r=Radius2,h=Depth+eps);
				}
			}
		}
	}
}

module drawCross(x)
{
	translate([x - MiniCubeOffset - MiniCubeWidth, Width/2 + MiniCubeOffset, 0]) cube([MiniCubeWidth, MiniCubeWidth, Height]);
	translate([x + MiniCubeOffset, Width/2 + MiniCubeOffset, 0]) cube([MiniCubeWidth, MiniCubeWidth, Height]);
	translate([x - MiniCubeOffset - MiniCubeWidth, Width/2 - MiniCubeOffset - MiniCubeWidth, 0]) cube([MiniCubeWidth, MiniCubeWidth, Height]);
	translate([x + MiniCubeOffset, Width/2 - MiniCubeOffset - MiniCubeWidth, 0]) cube([MiniCubeWidth, MiniCubeWidth, Height]);
}

module OneCross()
{
	Thickness = (Width - 2 * Radius2) / 2;

	difference()
	{
		union()
		{
			cube([Pitch/2, Thickness, Height]);
            translate([0, Width-Thickness+0.3,0]) cube([Pitch/2, Thickness, Height]);
			translate([0, Width/2+0.15,0])cylinder(r=Width/2+0.15, h=Height);
		}
			difference()
			{
				union()
				{
					translate([0, Width/2,-eps]) cylinder(r=Radius1,h=Height+2*eps);
					translate([0, Width/2 - MiniCubeOffset,-eps]) cube([Width/2, 2* MiniCubeOffset, Height+2*eps]);
				}
					drawCross(0);
			}

	}
}

```


[User]
Hey, I'd like to get a customisable deck box generator in OpenSCAD. I need it to handle multiple card compartments with adjustable sizes and a lid, and also have some text and graphic options. Here's what I have in mind:

**Core Functionality:**

*   **Multiple Compartments:** The box should be able to have multiple card compartments, each with a different specified capacity. I'll provide a list of numbers representing how many cards each compartment needs to hold.
*   **Adjustable Wall Thickness:** I need to be able to specify the thickness of the walls.
*   **Lid:** The box should have a lid that closes securely. The lid should include clips to stay in place.
*   **Window Option:** A parameter to include a rectangular window on the front of the box. This should also be an optional setting.
*   **Card Dimensions:**  The generator should use card dimensions as parameters (width, height, and thickness).
*   **Text:** I want the option to add two lines of text on the lid, each with its own size and content parameters.
*  **Iconography:** I also need to add icons of the MTG mana symbols to the front, this should be a parameter with values which correspond to the combination of mana symbols.

**Specific Requirements and Considerations:**

*   The number of compartments, their card capacity, the wall thickness, the presence of the window, the text content, text size, card dimensions, and mana icons should all be parameters.
*   The compartments should be automatically sized to fit the specified number of cards, based on the card thickness parameter.
*   I'd like to have a little bit of tolerance so the cards will slide in easily.
*   The lid should clip onto the main body using some flexible pieces that press into place.
*   It would be great if the design can be made so that it's easily printable on a standard 3D printer.
*   I'd like to use common fonts such as Arial for the text and the mana symbols, ideally they should be imported using DXF files.
*   Lastly, it would be useful if the output includes a summary of the total depth of the box.
*   A small logo should also be included on the side.

Can you generate an OpenSCAD file (or files if necessary) for this? I don't need any extra libraries, so it can all be written in OpenSCAD directly.

Thanks!

[Assistant]
deckbox.scad:
```

//For a normal deck with sideboard and some tokens: [60, 15, 5]. Or a commander deck: [1, 99]
compartiments = [60, 15, 5];
//Thickness of the walls
wall = 4; // [3, 4, 5, 6, 7, 8]
//Wether you want a window or not (0 for no, 1 for yes)
window = 1; // [0, 1]
//The text above the line
text1 = "MTG";
//The size of this text
size1 = 8;
//The text below the line
text2 = "DECKBOX";
//The size of this text
size2 = 8;

//Card width. (standard ultra-pro MTG sleeve)
cardW = 62;
//Card height. (standard ultra-pro MTG sleeve)
cardH = 91;
//Card thickness. (standard dragon shield MTG double sleeve with card)
cardT = 0.71;

//MTG icons. plain = 1, island = 2, swamp = 4, mountain = 8, forest = 16 (add them together for multiple icons.)
colors = 0;

flexibleClips = true;

deckbox(compartiments, wall, window == 1, true, text1, size1, text2, size2, colors);

module deckbox(
  compartiments = [60],
  wall = 4,
  window = true,
  lid = true,
  text1 = "",
  size1 = 7,
  text2 = "",
  size2 = 5,
  colors = 0){

  // HANDS OFF!!!
  tolerance = 1;
  nComps = len(compartiments);
  $fn = 72;
  sizes = compartiments * cardT;
  totalDepth = sum(sizes) + wall * nComps + wall + tolerance * nComps;
  innerDepth = totalDepth - wall * 2;

  echo("=============================");
  echo(str("                TOTAL DEPTH: ", totalDepth, "mm          "));
  echo("=============================");

  difference(){
    union(){
      translate([wall, wall, 0])
      minkowski(){
        cube([cardW, innerDepth, cardH + wall - 1]);
        cylinder(r = wall, h = 1);
      }

      if(lid){
        difference(){
          translate([wall, wall, wall + cardH])
          minkowski(){
            cube([cardW, innerDepth, wall - 1]);
            cylinder(r = wall, h = 1);
          }

          difference(){
            translate([wall, -1, wall + cardH])
            cube([cardW, totalDepth + 2, wall * 1 + 1]);

            translate([wall * 0.83, wall / 2, cardH + wall * 1.5])
            sphere(r = wall / 3);

            translate([cardW + wall * 1.17, wall / 2, cardH + wall * 1.5])
            sphere(r = wall / 3);

          }

          translate([wall / 2, wall, wall + cardH])
          rotate([0, 27, 0])
          cube([wall, totalDepth + 2, wall * 2]);

          translate([cardW + wall * 1.5, totalDepth + wall, wall + cardH])
          rotate([0, 27, 180])
          cube([wall, totalDepth, wall * 2]);
        }
      }
    }
    translate([cardW / 2 + wall, -1, cardH + wall])
    rotate([-90, 0, 0])
    cylinder(h = totalDepth + 2, d = 20);

    for(i = [0 : (nComps - 1)]){
      translate([wall, sum(sizes, 0, i) + (i * wall) + wall + i * tolerance, wall])
      cube([cardW, sizes[i] + tolerance, cardH + 1]);
    }

    if(window){
      translate([(cardW + wall * 2 - 54) / 2, -1, cardH - 51 + wall * 1.5])
      cube([54, wall + 2, 53]);

      translate([(cardW + wall * 2 - 54) / 2, -1, cardH - 51 + wall * 1.5])
      rotate([-22.5, 0, 0])
      cube([54, wall + 2, wall]);
    }

    if(colors > 0){
        b = bin(colors, 5);
        n = binHigh(b);
        pos = [0, cardW / 5, cardW / 5 * 2, cardW / 5 * 3, cardW / 5 * 4];
        if(binMatch(b, bin(1, 5))){
            translate([cardW / 5 * (((5 - n) / 2) + n - binHigh(b, 4)) + 2, 1, 11])
            rotate([90, 0, 0]){
                linear_extrude(height = 2)
                scale(0.8)
                import("plain.dxf");
            }
        }
        if(binMatch(b, bin(2, 5))){
            translate([cardW / 5 * (((5 - n) / 2) + n - binHigh(b, 3)) + 3, 1, 13])
            rotate([90, 0, 0]){
                linear_extrude(height = 2)
                scale(0.8)
                import("island.dxf");
            }
        }
        if(binMatch(b, bin(4, 5))){
            translate([cardW / 5 * (((5 - n) / 2) + n - binHigh(b, 2)) + 3, 1, 13])
            rotate([90, 0, 0]){
                linear_extrude(height = 2)
                scale(0.8)
                import("swamp.dxf");
            }
        }
        if(binMatch(b, bin(8, 5))){
            translate([cardW / 5 * (((5 - n) / 2) + n - binHigh(b, 1)) + 3, 1, 12])
            rotate([90, 0, 0]){
                linear_extrude(height = 2)
                scale(0.8)
                import("mountain.dxf");
            }
        }
        if(binMatch(b, bin(16, 5))){
            translate([cardW / 5 * (((5 - n) / 2) + n - binHigh(b, 0)) + 2, 1, 12])
            rotate([90, 0, 0]){
                linear_extrude(height = 2)
                scale(0.8)
                import("forest.dxf");
            }
        }

    }

    translate([70, 20])
    mirror()
    logo(16);

  }

  if(lid){
    margin = 0.2;
    translate([cardW + wall * 2 + 5, 0, 0])
    // translate([wall / 2 + 0.25, 0, cardH + wall]) //  <-- Lid in place. Don't print this way
    difference(){

      translate([wall / 2, wall, 0])
      minkowski(){
        cube([cardW - margin, innerDepth, wall - 1 - margin]);
        cylinder(r = wall, h = 1);
      }

      cube([wall / 2, wall, wall]);

      translate([wall * 0.5, wall / 2, wall / 2])
      sphere(r = wall / 3);

      translate([-wall - 0.4, 0, 0])
      rotate([0, 27, 0])
      cube([wall, totalDepth, wall * 2]);

      translate([cardW + wall / 2 - margin, 0, 0])
      cube([wall / 2, wall, wall]);

      translate([cardW + wall * 0.5 - margin, wall / 2, wall / 2])
      sphere(r = wall / 3);

      translate([cardW + wall * 2 + 0.4 - margin, totalDepth, 0])
      rotate([0, 27, 180])
      cube([wall, totalDepth, wall * 2]);

      translate([(cardW + wall - margin) / 2, (totalDepth) / 2, wall - 1])
      linear_extrude(height = 1.3){
        text(text1, halign = "center", valign = "center", size = size1, font="Arial:style=Bold");
      }

      translate([wall - margin / 2, (totalDepth) / 2 - size1 / 2 - 2, wall - 1])
      cube([cardW - wall, 1, 1.3]);

      translate([(cardW + wall - margin) / 2, (totalDepth) / 2 - size1 - size2 / 2, wall - 1])
      linear_extrude(height = 1.3){
        text(text2, halign = "center", valign = "center", size = size2, font="Arial:style=Bold");
      }

      if(flexibleClips){
          translate([wall, 0, 0])
          cube([1, 8, wall + 1]);

          translate([cardW - margin - 1, 0, 0])
          cube([1, 8, wall + 1]);
      }

    }
  }
}

module logo(size = 22, height = 1){
    scl = size / 22;
    linear_extrude(height = height){
        union(){
            text("3", scl * 14);

            translate([scl * 10, 0, 0])
            text("D", size);

            translate([scl * 31, scl * 12, 0])
            text("endrowen", scl * 10);

            translate([scl * 31, 0, 0])
            text("printing", scl * 10);
        }
    }
}
function sum(array, from = 0, to = 2000000000) = (from < to  && from < len(array) ? array[from] + sum(array, from + 1, to) : 0);

function bin(num, len=-1, v=[]) =
	len(v) == len || (num == 0 && len == -1) ? v :
	num == 0 && len != -1 ? bin(0, len, concat(0, v)) :
	bin(floor(num/2), len, concat(num%2, v));

function binMatch(bin1, bin2, s = 0) = bin1[s] == 1 && bin2[s] == 1 ? true : min(len(bin1), len(bin2)) - 1 == s ? false : binMatch(bin1, bin2, s + 1);

function binHigh(bin, s = 0) = (bin[s] == 1 ? 1 : 0) + (s + 1 == len(bin) ? 0 : binHigh(bin, s + 1));

```