Gravity Pin Puzzle Box
A puzzle box with a secret that uses nothing but gravity: the lid slides in a 45 deg dovetail groove, and a loose pin inside the ridge on the lid drops into a hole in the top of the end wall, so the lid will not move while the box is upright. Turn the box over, the pin falls back into the lid, and the lid slides out. Three printed parts, no springs or magnets. The default inner space is 60 x 40 x 25 mm, giving a box of 75 x 50 x 30 mm; the print layout with the lid and pin beside it is 87 x 105 x 30 mm. The box prints standing on its floor (the dovetail undercut is 45 deg), the lid top side up and the pin standing; no supports. Inner size, wall thickness, pin diameter and the lid clearance are parameters, and a closed view shows the locked box with the fit checked.
# Gravity Pin Puzzle Box - a sliding dovetail lid that only opens upside down
#
# The lid slides in a 45 deg dovetail groove along the two long walls and enters
# from one end. A loose pin sits in a blind channel inside the handle ridge on the
# lid; with the box upright the pin drops into a hole in the top of the thick end
# wall and the lid cannot move. Turn the box over, the pin falls back into the lid,
# and the lid slides out. Three printed parts, no springs or magnets. The box
# prints standing on its floor (the dovetail undercut is 45 deg), the lid prints
# top side up (the pin channel is a small blind hole bridged from below) and the pin
# prints standing. `view` shows the parts for printing, or the closed box with the
# pin in its lock hole (checked with clear()).
@param 40..120 step:5 group:"Size" desc:"Inner length along the slide (mm)"
$in_l = 60
@param 30..90 step:5 group:"Size" desc:"Inner width (mm)"
$in_w = 40
@param 15..60 step:5 group:"Size" desc:"Inner height (mm)"
$in_h = 25
@param 4.5..6 step:0.5 group:"Walls" desc:"Side wall thickness, holds the dovetail (mm)"
$wall = 5
@param 2..3 step:0.5 group:"Walls" desc:"Floor thickness (mm)"
$floor_t = 2
@param 3..5 step:0.5 group:"Lock" desc:"Pin diameter (mm)"
$pin_d = 4
@param 0.2..0.5 step:0.05 group:"Fit" desc:"Clearance of the lid in its groove, per side (mm)"
$fit = 0.3
@param choices:["print", "closed"] group:"Output" desc:"Print layout, or the closed and locked box"
$view = "print"
$lid_t = 3 # lid plate thickness
$dt_top = 1 # dovetail: tongue reaches this far into the wall at the top face
$dt_bot = $dt_top + $lid_t # ... and this far at the bottom (45 deg flanks)
assert $dt_bot + 0.8 <= $wall # the wall keeps 0.8 mm outside the groove
$end_t = $pin_d + 6 # the lock end wall is thick enough for the pin hole
$lip = 1.5 # the groove stops this short of the lock end: the lid's stop
$x_h = $end_t / 2 + 1 # pin hole centre, inside the end wall top
$drop = 3 # how far the pin drops into the end wall
$pin_l = 8
$ch_depth = $pin_l + $drop + 0.5 # the pin channel: the pin fully retracted plus 0.5
$handle_h = $ch_depth + 1.5 - ($lid_t - 2 * $fit) # ridge on the lid that houses the channel, 1.5 mm roof
assert $handle_h >= 4
$handle_w = $pin_d + 4
$L = $in_l + $end_t + $wall # -X end is the lock wall, +X end is where the lid enters
$W = $in_w + 2 * $wall
$H = $in_h + $floor_t + $lid_t
$lid_z = $H - $lid_t # underside of the lid
# --- Box -------------------------------------------------------------------
$outer = box $L $W $H center:(false, true, false)
$cavity = box $in_l $in_w $in_h center:(false, true, false) | translate $end_t 0 $floor_t
# dovetail groove along X from the lip at the lock end to the entry end: trapezoid in the
# YZ plane, wide at the lid underside. The lock end wall top is cut down with it, the
# lid passes over the wall and the pin hole is drilled in that wall top.
$gw_bot = $in_w + 2 * $dt_bot
$gw_top = $in_w + 2 * $dt_top
$groove = workplane YZ
| polyline [(-$gw_bot / 2, $lid_z), ($gw_bot / 2, $lid_z), ($gw_top / 2, $H + 0.01), (-$gw_top / 2, $H + 0.01)]
| extrude ($L - $lip + 1)
| translate $lip 0 0
$lock_hole = cylinder (($pin_d + 0.6) / 2) ($drop + 1) | floor | translate $x_h 0 ($lid_z - $drop)
assert $x_h - ($pin_d + 0.6) / 2 > $lip + 1.5 # hole stays inside the lock wall
assert $x_h + ($pin_d + 0.6) / 2 < $end_t - 1.5
$box = $outer - $cavity - $groove - $lock_hole
assert $box.solids == 1
assert $box.bbox.x ~ $L
assert $box.bbox.y ~ $W
assert $box.bbox.z ~ $H
# --- Lid: dovetail plate plus the handle ridge with the pin channel ---------------
$lid_x0 = $lip + $fit # the closed lid runs from the lip to the entry end
$lid_l = $L - $lid_x0
$lw_bot = $gw_bot - 2 * $fit
$lw_top = $gw_top - 2 * $fit
$lid_plate = workplane YZ
| polyline [(-$lw_bot / 2, $lid_z + $fit), ($lw_bot / 2, $lid_z + $fit), ($lw_top / 2, $H - $fit), (-$lw_top / 2, $H - $fit)]
| extrude $lid_l
| translate $lid_x0 0 0
$handle = box $handle_w ($lw_top - 4) $handle_h center:(true, true, false) | translate $x_h 0 ($H - $fit)
| edges =Y | fillet 1.5
$channel = cylinder (($pin_d + 0.6) / 2) $ch_depth | floor | translate $x_h 0 ($lid_z + $fit - 0.01)
$lid = ($lid_plate + $handle) - $channel
assert $lid.solids == 1
assert $lid.bbox.x ~ $lid_l
assert $lid.bbox.z ~ ($lid_t - 2 * $fit + $handle_h)
assert $x_h - $handle_w / 2 >= $lid_x0 # the handle sits on the plate
print "pin channel depth" $ch_depth
# --- Pin --------------------------------------------------------------------
$pin = cylinder ($pin_d / 2) $pin_l | floor | faces >Z | chamfer 0.6
assert $pin.bbox.z ~ $pin_l
# --- Closed, locked: lid in its groove, pin dropped into the end wall ----------------
$lid_closed = $lid
$pin_locked = $pin | translate $x_h 0 ($lid_z - $drop + 0.3)
assert clear($box, $lid_closed)
assert clear($box, $pin_locked)
assert clear($lid_closed, $pin_locked)
assert $pin_locked.bbox.max[2] > $lid_z + 2 # the pin reaches well into the lid channel
$closed = union [$box, $lid_closed, $pin_locked]
assert $closed.bbox.x ~ $L
# --- Print layout: box, lid top up beside it, pin standing ----------------------------
$lid_print = $lid | translate (-$lid_x0) ($W / 2 + $lw_bot / 2 + 8) (-$lid_z - $fit)
$pin_print = $pin | translate ($L + 10) 0 0
$print = union [$box, $lid_print, $pin_print]
assert $print.solids == 3
assert $lid_print.bbox.min[2] ~ 0 tol:0.01
if $view == "closed" then $closed else $print