Reference

OpenSCAD boolean operations

Three operators do all the heavy lifting in OpenSCAD modeling: union, difference, and intersection. Master the order rules, learn the printability gotchas, and you'll understand the bones of every parametric part you'll ever write.

union

union() { ... }

Merges all children into one solid. This is the default — if you list shapes side-by-side without wrapping them in another operator, they are implicitly union'd. You almost never need to type union() explicitly.

union() {
  cube([20, 20, 4]);
  translate([10, 10, 4]) cylinder(h=10, d=8);
}

// Equivalent — union is implicit at the top level:
cube([20, 20, 4]);
translate([10, 10, 4]) cylinder(h=10, d=8);

difference

difference() { A; B; C; ... }

Computes A − B − C − ... — the first child is the base, every subsequent child is subtracted. Order matters. If you swap the cylinder above the plate, the plate gets carved out of nothing and you get an empty or inverted result.

// Through-hole plate
difference() {
  cube([40, 40, 4]);                            // base
  translate([20, 20, -1])
    cylinder(h=6, d=6, $fn=48);              // hole
}
Make subtracted geometry 0.1–1 mm bigger than the wall it cuts.

If a subtracted cylinder ends exactly at the plate surface, OpenSCAD can produce a zero-area coplanar face that fails the manifold check. The fix is trivial: start the cylinder 1 mm below the plate and make it 2 mm taller. The AI CAD agent does this automatically for every hole it generates.

intersection

intersection() { ... }

Keeps only the volume shared by all children. Use it to mask one shape with another — get only the part that lies inside both.

// Spherical button cap (sphere ∩ short cylinder)
intersection() {
  sphere(12, $fn=64);
  translate([0, 0, 6]) cylinder(h=10, d=22, $fn=64);
}

Patterns

Shells & hollow parts

Hollow out any solid by subtracting an offset version of itself:

wall = 2;
difference() {
  cube([40, 30, 25]);                               // outer
  translate([wall, wall, wall])
    cube([40-2*wall, 30-2*wall, 25]);          // inner cavity (open top)
}

Screw bosses

Add solid bosses, then subtract clearance holes — order matters but the pattern is rote:

difference() {
  union() {
    cube([40, 30, 4]);
    for (p = [[5,5],[35,5],[5,25],[35,25]])
      translate([p[0], p[1], 4])
        cylinder(h=8, d=6, $fn=32);
  }
  for (p = [[5,5],[35,5],[5,25],[35,25]])
    translate([p[0], p[1], -1])
      cylinder(h=14, d=3.2, $fn=32);
}

Countersunk holes

Subtract both a through-hole cylinder and a tapered cone from the top face:

module csk_hole(d=3.2, head_d=6, head_depth=1.7, plate_t=4) {
  translate([0, 0, -1])
    cylinder(h=plate_t+2, d=d, $fn=32);
  translate([0, 0, plate_t-head_depth])
    cylinder(h=head_depth+0.1, d1=d, d2=head_d, $fn=32);
}

Trim a model to a build volume

intersection() {
  my_model();
  cube([220, 220, 250], center=true);   // generic FDM bed envelope
}

Avoiding non-manifold geometry

  • Holes should overlap their walls. Make subtracted geometry start 1 mm below the surface and end 1 mm above it. Never share an exact plane.
  • Bosses should overlap the plate. Don't put a boss whose base sits exactly on top of a plate's surface — sink it 0.01 mm in so the boolean union actually merges the volumes.
  • Coincident faces are the #1 cause of "the model looks fine but the slicer says it's broken". The PrintPal AI CAD agent runs a manifold + watertight check after every render and flags failures in the Brief panel.

render()

Force OpenSCAD to perform the full CGAL render on a subtree (even in F5 preview). Use when a large boolean is too slow to interact with — render it once, work around the cached mesh.

render(convexity=6) expensive_model();

Manifold issues stop being your problem

The AI CAD agent generates booleans with the right overlaps and runs manifold + printability checks after every render. You just describe the part.

Open the agent