Open build · senku.im

A machine that carries steel balls up a metre and drops them.

Every part here was printed without a slicer. No CAD, no mesh — a Python program writes the printer's motion directly, so each shape below is the toolpath. The diagrams on this page are drawn from the exact files that printed, not sketched afterwards.

What it is

A cleated belt runs between two pulleys. Balls sit in the cleats, ride up, and fall out at the top. The frame is 1/4 inch bamboo skewers held by printed joints.

Belt2.41 mfolded onto one 350 mm plate as a closed space-filling curve, then unfolded
Lift1.14 mvertical at 90°, 0.99 m at a 60° tilt where no side wall is needed
Balls14 mmsteel, 11 g each — one per cleat: 25 on the 2.41 m loop, clustered on the straight runs (gaps 25–309 mm, not uniform)
Material~195 gthe whole machine

The parts

Each diagram is drawn from the real printed path, seen from above — one layer, except the weighted foot, which shows its first eight so the cavity is visible.

Top view of the drive hub toolpath: a 60mm rim with three curved spokes reaching a central bore

Drive hub

What you turn. The bore is printed round — push it onto the motor shaft while the part is still hot and the plastic moulds itself to the shaft's flat. The shaft is the mould, so the fit is exact and can't be misaligned.

60 mm · round 6.25 bore · 6.9 g
Top view of the belt pulley toolpath: a 40mm rim with spokes and a central bore

Belt pulley ×2

Slightly barrel-shaped — 0.6 mm fatter in the middle. A flat belt always climbs toward the widest part, so the bulge keeps it centred instead of walking off the end.

40 mm · +0.6 crown · 8.6 g
Top view of the bracket toolpath: two bores joined by a solid body, filled with concentric contours

Bracket

Holds the pulley axle out from a bamboo upright, with 4.7 mm of clearance so a 40 mm pulley spins past the stick. Filled with rings rather than criss-cross infill — every pass follows the load around the holes instead of cutting across it.

axle 6 mm · stick 6.35 mm · 32 mm apart
Top view of the coupler toolpath: two concentric rings forming a tube wall

Coupler

Joins two skewers end to end so the frame can be any height. A plain tube — two walls, one unbroken line.

14.35 mm outside · 6.6 bore · 3.9 wall
Top view of the spacer toolpath: two bores in one plate

Spacer

Holds two uprights parallel. Use them in pairs — one plate sets the spacing but acts as a hinge, so a single spacer lets the sticks splay. Two, spread apart, fix the angle.

2 / 3 / 4 bores · 32 mm pitch
Found by building it, not by design.
Top view of the adapter toolpath: concentric rings around a central bore

Adapter

Motor shaft at one end, bamboo at the other. The shaft end goes at the bottom so that going up, the hole only ever gets bigger — nothing has to print over thin air.

6 mm shaft → 6.35 mm stick · 20 mm long
First eight layers of the weighted foot: solid concentric rings for the floor, then a thin ring pair once the cavity opens

Weighted foot

A 1 m ladder with a belt running up it wants to walk. So the foot is printed as a shell with a floor and an open mouth — you fill it with sand and gypsum after printing. Sand alone damps well, because the grains rub and eat energy; the gypsum sets it so it stops migrating and becomes structural.

It is lighter to print and heavier to own: the shell is about a third of the plastic, and filled it beats solid PLA outright — sand+gypsum is roughly 1.8 g/cm³ against PLA's 1.24. Mass is the point, because it drags the whole structure's natural frequency down away from the belt's.

36.35 mm · 25 mm tall · 2.4 mm shell · ~15 cm³ of fill
Open at the top on purpose — a roof would need to bridge over the cavity, and there is no support and no bridging anywhere in this toolchain.

One plate, every part

First two layers of the 15-part plate: couplers, brackets, feet, spacers and a fit gauge packed in shelves across a 350 mm bed

Each part used to be its own file — which meant six heat-ups, six homings, and six chances to start a print onto a plate that had not been cleared. The whole frame now goes down in one run: 15 parts across 315 mm, packed into shelves tallest-first.

The catch is the brim. Every part's brim reaches brim_gap + brim × bead = 4.98 mm past its outline, so two neighbours need 11.16 mm between them or the brims merge and the parts come off the plate welded together — with the join hidden underneath a brim that is supposed to snap away. The first plate generated here used an 8 mm gap and would have done exactly that. It is now a check that refuses to emit the file, which is the only reason it was caught before the bed and not after.

Before you assemble: the gauge decides everything

Every bore in this build is modelled at stick + 0.25 mm, because a printed hole comes out about a quarter of a millimetre smaller than modelled. That figure is confirmed at 6 mm and was extrapolated to a 6.35 mm (¼″) stick — so one part on the plate is a gauge that tests it, and it is the first thing to pick up.

boremodelledexpectedwhat it means if this is the one that fits
16.55~6.30shrink is smaller than 0.25 — every other part is loose, reprint with a tighter bore
26.80~6.550.25 is right. Every coupler, bracket and spacer on the plate is correct
37.05~6.80shrink is larger than 0.25 — the others will not accept a stick, reprint wider

Push a real stick into each. The one that grips without splitting is the answer. Ten seconds with one stick either validates the other fourteen parts on that plate or condemns them before you have glued anything.

Why the fits differ on purpose: brackets are bored at zero clearance so they grip the upright and hold their height by friction — that is the tensioner. Spacers get 0.25 mm more so they still slide while you square the frame. Same nominal bore, opposite jobs.

How it goes together

  1. Gauge first, then fill the feetSand and gypsum into the open mouths, about 15 cm³ each, and let it set before standing anything on them — loose fill damps worse than an empty foot.
  2. One upright, one bracket, one pulley — turn it by handBefore building the ladder. A pulley that binds is a ten-second discovery on a single stick and an hour of disassembly on a finished frame.
  3. Stand two uprightsSkewers into feet, joined with couplers for height. Spacers in pairs — one alone is a hinge.
  4. Bracket at each endTop and bottom, carrying the pulley axles clear of the uprights.
  5. Pulleys on the axlesCrowns facing the belt. They self-centre once it's running.
  6. Belt over both, cleats outwardThe cleat side carries the balls.
  7. Hub onto the motor, while hotPress it straight off the plate. It forms its own flat on the shaft.
  8. Tension it by sliding a bracketThere is no separate tensioner. The bracket is a collar on a round stick, so you slide it up until the belt is taut and friction holds it. That only works because its bore is printed at zero clearance — spacers get 0.25 mm more so they still slide while you square the frame. Same part, opposite fit.
  9. Tilt itVertical needs a chute wall beside the belt. At 60° the belt face holds the balls on its own, and you still get 0.99 m of lift.

Two things that were wrong first

Off the plate

The belt finished at 00:14 on 2026-07-26 — 76 minutes, 24.6 m of filament, 2.41 m of belt from a 350 mm plate.

Belt2.41 m25 cleats — the first one
Longer belt4.57 m52 cleats, 2.22 m of lift from the same 350 mm plate — printed overnight in 143 min, 46 m of filament. (The cleated layers measure 4.85 m; the cleat-free rails measure 4.57 m, and it is the rails that go taut and define the loop — so 4.57 is the belt.) This is the longest that still fits a cleat: fold the curve one step further and you get 8.85 m, but the channel narrows to 10 mm and no cleat clears it, so you would have a long belt with nothing to carry a ball.
Rails3 mmcleat-free at each edge — they run 180 mm shorter around the loop, so they take the tension and the cleats never get pulled flat
Cradle2 mmshallower cleats mid-width, so a ball rolls to the centre instead of off the side
Pulleys2 + hubbores confirmed a perfect fit on a 6 mm shaft

Still open

Make it yourself

These are the exact commands. The generator refuses to write a file it cannot verify — it will tell you why rather than hand you something that fails on the plate.

Beltpython3 belt.py --printer k2plus --fold 3 --belt-w 20 --cleats 60 --cleat-h 8 --cleat-w 18 --dish 2 --rail 3 --flow 13 --temp 200 --bed 45
Pulleypython3 pulley.py --printer k1c --od 40 --width 29 --bore 6
Drive hubpython3 pulley.py --printer k1c --od 60 --width 16 --bore 6 --flat 0 --crown 0 --flange 0
Jointspython3 solid.py --part bracket|coupler|spacer2 --stick 6.35 --height 14 --clearance 0
Weighted footpython3 solid.py --part foot --stick 6.35 --height 25 --wall 5 --cavity 2.4 --floor 2.4 --clearance 0
Whole plate at oncepython3 solid.py --printer k2plus --parts "coupler*6,bracket*4,foot*2,gauge,spacer2*2" --stick 6.35 --height 14 --part-gap 12 --layer-h 0.6 --flow 36

Every command above was executed and its output measured before being published here — an earlier version listed --part foot with no cavity arguments, which emits a solid 39 mm puck rather than the shell this page describes, and quoted the TPU belt at 230 °C, which is the temperature that jammed. Note also that the belt generator thins the requested 60 cleats to the 52 that actually fit the straight runs, and says so on every run — the page now quotes what it places, not what it was asked for.

--flat 0 on the hub is deliberate: the bore stays round and you press it onto the motor shaft while the part is still hot, so the shaft moulds its own flat. --clearance 0 grips a stick, 0.25 slides on one.

Take it

The generator that writes these files is open: github.com/olegmlkvorg/crackle — the belt comes out of belt.py, the pulleys out of pulley.py, the brackets and spacers out of solid.py. Every command printed on this page runs against that repo unchanged. Nothing here needs a slicer, a licence, or a workshop — a printer, a spool, and a pack of bamboo skewers.

Ideas, corrections, or a better cleat: take.senku.im