Skip to content
Sign in

Documentation

Common patterns

Copy-paste recipes: rounded boxes, screw holes, arrays, shells, chamfers, text.

The hull of four corner cylinders is a rounded rectangle; a module makes it reusable.

PPSCAD
mod rbox(w, d, h, r) {
  hull {
    translate(r, r, 0) cylinder(h: h, r: r)
    translate(w - r, r, 0) cylinder(h: h, r: r)
    translate(r, d - r, 0) cylinder(h: h, r: r)
    translate(w - r, d - r, 0) cylinder(h: h, r: r)
  }
}

rbox(60, 40, 20, 3)

A through hole and a cone on top; the cone runs a tenth past the face so the cut is clean.

PPSCAD
mod screw_hole(d, h, cs_d, cs_depth) {
  // The through hole
  cylinder(h: h, r: d / 2)
  // The countersink
  translate(0, 0, h - cs_depth)
    cylinder(h: cs_depth + 0.1, r1: d / 2, r2: cs_d / 2)
}

// An M3 countersunk screw through a 5 mm plate
difference {
  cube(20, 20, 5)
  translate(10, 10, -0.5)
    screw_hole(3.4, 6, 6.5, 1.8)
}

Two nested loops over the two x and the two y positions make four holes.

PPSCAD
mod mount_holes(w, d, h, hole_r, inset) {
  for (x in [inset, w - inset]) {
    for (y in [inset, d - inset]) {
      translate(x, y, -0.5)
        cylinder(h: h + 1, r: hole_r)
    }
  }
}

difference {
  cube(60, 40, 3)
  mount_holes(60, 40, 3, 1.7, 5)
}

A square with a cylinder taken out of its corner is a concave fillet; lay it along the wall.

PPSCAD
mod fillet(r, h) {
  difference {
    cube(r, r, h)
    translate(r, r, -0.1)
      cylinder(h: h + 0.2, r: r)
  }
}

// A standing wall with a fillet at its foot
cube(40, 2, 20)
fillet(3, 20)

Rotate, then move out along x: the same part at every angle around the origin.

PPSCAD
param count: int = 8 [3:24] "Number of items"
param radius: float = 25 [10:50] "Array radius (mm)"

for (i in [0:count - 1]) {
  let angle = i * 360 / count
  rotate(0, 0, angle)
    translate(radius, 0, 0)
      cylinder(h: 10, r: 3)
}

A loop over the count, each step moved along by the spacing.

PPSCAD
param count: int = 5 [1:20] "Count"
param spacing: float = 15 [8:30] "Spacing (mm)"

for (i in [0:count - 1]) {
  translate(i * spacing, 0, 0) cube(10, 10, 10)
}

The inner box is the outer one minus the wall on every side, and runs out through the top.

PPSCAD
param w: float = 60 [20:150] "Width (mm)"
param d: float = 40 [20:100] "Depth (mm)"
param h: float = 25 [10:60] "Height (mm)"
param wall: float = 2 [1.2:4:0.2] "Wall (mm)"

difference {
  cube(w, d, h)
  translate(wall, wall, wall)
    cube(w - wall * 2, d - wall * 2, h)
}

A box turned 45 degrees and placed on the edge cuts a chamfer off it.

PPSCAD
param size: float = 30 [10:60] "Size (mm)"
param chamfer: float = 2 [0.5:5] "Chamfer (mm)"

difference {
  cube(size, size, size)
  translate(-0.5, 0, size - chamfer)
    rotate(45, 0, 0)
      cube(size + 1, chamfer * 2, chamfer * 2)
}

Extrude the text and add it for a raised label, or take it away inside a difference for a sunken one. The font is built in and plain.

PPSCAD
param text_depth: float = 1 [0.4:3:0.2] "Text height (mm)"

cube(50, 20, 2)
translate(5, 5, 2)
  extrude(text_depth)
    text("HELLO", size: 10)

A cantilever arm with a hook at its end; the thickness decides how stiff it is.

PPSCAD
param length: float = 10 [5:20] "Clip length (mm)"
param width: float = 5 [3:10] "Clip width (mm)"
param thickness: float = 1 [0.8:2:0.1] "Thickness (mm)"
param hook: float = 1.5 [0.5:3:0.5] "Hook depth (mm)"

// The arm
cube(length, width, thickness)
// The hook at its end
translate(length - thickness, 0, -hook)
  cube(thickness, width, hook + thickness)

A bar with one round slot per cable, each slot a cylinder turned to lie across the bar.

PPSCAD
param cables: int = 6 [2:12] "Number of cables"
param cable_d: float = 5 [3:10:0.5] "Cable diameter (mm)"
param wall: float = 2 [1.5:4:0.5] "Wall (mm)"
param depth: float = 8 [5:15] "Depth (mm)"

let slot = cable_d + wall
let total_w = cables * slot + wall

difference {
  cube(total_w, depth, cable_d + wall * 2)
  for (i in [0:cables - 1]) {
    translate(wall + i * slot + slot / 2, -0.5, wall + cable_d / 2)
      rotate(-90, 0, 0)
        cylinder(h: depth + 1, r: cable_d / 2)
  }
}

Five holes a tenth apart; print it once and read off the clearance your printer needs.

PPSCAD
// Five clearances, a tenth of a millimetre apart
for (i in [0:4]) {
  let clearance = 0.1 + i * 0.1
  translate(i * 12, 0, 0) {
    difference {
      cube(10, 10, 5)
      translate(5, 5, -0.5)
        cylinder(h: 6, r: 3 + clearance)
    }
  }
}