Maze Gift Box
A two-part puzzle box: a pin inside the outer sleeve must follow a maze groove cut into the inner box, so it only opens if you twist and pull along the right path. Put a gift card or a small present inside and the opening becomes part of the gift. The maze is a 12 x 5 grid defined as a list of edges in the code, with several dead ends and a false goal, and you can rearrange it by editing the lists. Both parts are laid out side by side for printing (146 x 66 x 65 mm together); closed, the box is about 66 mm across and 68 mm tall. Print as exported, inner box on its flange and sleeve upside down, with no supports. You can change the inner box radius, the box and pin clearances to suit your printer, and the row pitch.
# Maze Gift Box (two parts) - a pin in the sleeve must follow the maze groove to open it
# Inner box: cylindrical box with a maze groove cut into its outside (flange at the bottom)
# Outer box: sleeve closed at the top. A pin pointing inward follows the groove.
# The maze is defined as a list of edges on a 12-column (every 30 deg) x 5-row grid; groove tools are made with list comprehensions.
# Print layout: inner box at the origin, outer box top-down on the +X side (two solids on purpose).
@param 22..45 desc:"Inner box outer radius (mm)"
R = 30
@param 0.2..0.8 step:0.05 desc:"Clearance between inner and outer box (radial, mm)"
fit = 0.4
@param 0.3..0.8 step:0.05 desc:"Clearance between pin and groove (per side, mm)"
pin_clear = 0.5
@param 8..14 desc:"Row pitch (mm)"
row_pitch = 10
n_cols = 12 # columns around (every 30 deg)
n_rows = 5 # rows (0 = bottom = goal row)
pin_r = 1.5 # pin radius (3mm dia)
groove_d = 2.0 # groove depth
floor_t = 3 # inner box floor thickness
core_wall = 2.0 # wall between the groove bottom and the inner cavity
flange_h = 5 # height of the flange at the bottom of the inner box
sleeve_t = 2.4 # outer box wall thickness
top_t = 2.4 # outer box top thickness
top_gap = 0.5 # gap between the inner box top and the outer box ceiling when closed
pin_z = 8 # pin center height above the open end of the outer box
w = pin_r * 2 + pin_clear * 2 # groove width
step = 360 / n_cols
z0 = flange_h + pin_z # goal row height (outer box fully closed)
body_top = z0 + (n_rows - 1) * row_pitch + 12
R_s = R + fit # outer box inner radius
R_o = R_s + sleeve_t # outer box outer radius (= flange radius)
half = degrees(w / 2 / R) # half the groove width as an angle (to extend the corners)
# ---- Maze definition (column, row) ----
# Each edge is packed into one integer e(column, row) = row * n_cols + column
# (so the edge lists are plain lists of numbers)
def e(c, r) = r * n_cols + c
# Horizontal edges: e(c, r) joins (c, r) and (c+1, r) (column 11 -> 0 wraps around)
h_edges = [
e(0, 3), e(1, 3), e(2, 4), e(3, 4), e(4, 4), e(3, 2), e(4, 2),
e(3, 1), e(4, 1), e(5, 1), e(6, 1), e(7, 3), e(8, 3), e(9, 0), e(10, 0),
e(1, 1), e(5, 4), e(6, 4), e(11, 3), e(6, 0), e(8, 4), e(9, 4), e(9, 2)
]
# Vertical edges: e(c, r) joins (c, r) and (c, r+1)
v_edges = [
e(0, 3), e(2, 3), e(5, 3), e(5, 2), e(3, 1), e(7, 1), e(7, 2), e(9, 2), e(9, 1), e(9, 0),
e(1, 2), e(1, 1), e(11, 2), e(6, 0), e(8, 3), e(10, 1)
]
entry_col = 0 # entry from the top edge (from the top row of this column upward)
# Solution: entry (0,4) down (0,3) right (2,3) up (2,4) right (5,4) down (5,2) left (3,2) down (3,1) right (7,1) up (7,3) right (9,3) down (9,0) right (11,0) = goal
def zr(r) = z0 + r * row_pitch
# Horizontal groove (edge k = row * n_cols + column): a (depth x width) section swept 30 deg around Z. Both ends extended by half the groove width
def h_groove(k) = workplane XZ
| rect (groove_d + 1) w at:(R - groove_d / 2 + 0.5, zr(k // n_cols))
| revolve Z (step + half * 2)
| rotate 0 0 ((k % n_cols) * step - half)
# Vertical groove (edge k): a box with depth radially and width circumferentially. Top and bottom extended by half the groove width
def v_groove(k) = box (groove_d + 1) w (row_pitch + w)
| translate (R - groove_d / 2 + 0.5) 0 (zr(k // n_cols) + row_pitch / 2)
| rotate 0 0 ((k % n_cols) * step)
h_tools = union [(h_groove k) for k in h_edges]
v_tools = union [(v_groove k) for k in v_edges]
grooves = h_tools + v_tools
entry = box (groove_d + 1) w (body_top - zr(n_rows - 1) + 1)
| floor
| translate (R - groove_d / 2 + 0.5) 0 (zr(n_rows - 1))
| rotate 0 0 (entry_col * step)
# ---- Inner box ----
core = cylinder R body_top | floor
flange = cylinder R_o flange_h | floor
cavity = cylinder (R - groove_d - core_wall) body_top | floor | translate 0 0 floor_t
inner = core + flange - cavity - grooves - entry
# ---- Outer box (built in use orientation, then flipped top-down and placed alongside) ----
sleeve_h = body_top - flange_h + top_gap + top_t
sleeve_out = cylinder R_o sleeve_h | floor
sleeve_in = cylinder R_s (sleeve_h - top_t + 1) | floor | translate 0 0 -1
pin = cylinder pin_r (groove_d - pin_clear + fit + 1.2)
| rotate 0 90 0
| translate (R - groove_d + pin_clear + (groove_d - pin_clear + fit + 1.2) / 2) 0 pin_z
sleeve = sleeve_out - sleeve_in + pin
inner + (sleeve | rotate 180 0 0 | floor | translate (R_o * 2 + 15) 0 0)