This is the project repo for this video.
Written with Claude Code. Essentially all of the code in this repo was generated by Claude.
Flick a model up out of your monitor, carry it across the wall by hand, and drop it on your 3D printer to print it.
A projector covers the desk surface between a monitor and a Bambu Lab X2D. A webcam watches your hands. Flick upward at the screen and the model on the plate leaves the monitor and arrives on the wall as a physical object — it falls, bounces, and can be pinched out of the air and carried. Drop it on the printer and a countdown starts; let it finish and the plate is sliced headlessly and sent to the printer over LAN.
The object you throw is the real geometry from the Bambu Studio plate, not a placeholder — what flies across the wall is what would come out of the printer.
Hardware
- A webcam that can hold 30fps. Frame rate is a hard requirement, not a nicety: the
gesture detectors measure rates over short time windows, so below ~25fps they run
out of samples and stop firing entirely. A dim room makes a webcam lengthen its
exposure and quietly halve your frame rate — see
--exposurebelow. - A projector covering the surface between monitor and printer.
- A Bambu Lab X2D in LAN Only Mode with a USB stick inserted. Other Bambu models
will need
model_idand the print URL scheme changed.
Software
- Python 3.14 (3.11+ should work; 3.14 is what this is developed against)
- Bambu Studio, for headless slicing
pip install -r requirements.txt
The MediaPipe hand model is not in the repo (7.5MB blob). Download it:
curl -L -o models/hand_landmarker.task https://storage.googleapis.com/mediapipe-models/hand_landmarker/hand_landmarker/float16/1/hand_landmarker.taskFour steps, in order. Each writes a config file the next one reuses, so none can be skipped — but steps 1–3 need no printer, and step 4 needs no projector.
python tools/flick_test.pyA camera window that flashes when it sees an upward index flick. Tune until it fires
when you mean it and never when you don't; press p to save config/flick.json.
Everything downstream depends on this feeling right.
python tools/calibrate.py --display 1Three phases. First drag the four corners until the projected outline looks like a straight rectangle on the wall — this defines wall space and absorbs the projector's keystone. Then put a fingertip on each projected target and hold still until the ring fills, nine times. Then verify: a ring follows your hand live, and per-point residuals are printed so a fumbled capture can be spotted and redone.
Writes config/calibration.json. Only needs redoing if the projector or camera
physically moves.
The camera is aimed at you and never sees the projection, so the usual project-a-pattern-and-find-it calibration is impossible. The correspondences have to come from your hand instead.
python tools/wall.py --display 1 --set-anchorsPoint-and-hold to set the computer anchor (where the monitor's top edge meets the
projected area), then the printer anchor and its catch radius, then trace the route
the data wire takes between them. Optionally place a signpost pointing at a second
printer. Writes config/anchors.json.
Redo this if you move the monitor or printer on the desk.
python tools/send_to_printer.py --initWrites config/printer.example.json's fields into config/printer.json. Fill in
host and serial. Do not put the access code in the file — it is gitignored,
but the environment variable is better:
export BAMBU_ACCESS_CODE=xxxxxxxxBAMBU_HOST and BAMBU_SERIAL work the same way and win over the file.
On the printer: enable LAN Only Mode. While cloud-bound, the firmware rejects every locally-issued print command at the verification layer, identically for all payload forms — so it looks like a bug in this code and is not.
Then work up the ladder, each rung doing more than the last:
python tools/send_to_printer.py --check # config + connectivity, sends nothing
python tools/send_to_printer.py --dry-run # slices, uploads nothing
python tools/send_to_printer.py --no-print # slices and uploads, does not start
python tools/send_to_printer.py # starts a physical printpython tools/wall.py --display 1Useful flags:
| flag | what it does |
|---|---|
--desk |
draw the wall in a window on this monitor — no projector needed |
--debug |
camera view with live gesture readouts and loop timings |
--pretend |
rehearse the whole gesture; never starts a real print |
--background |
drop the monitor window so Bambu Studio keeps focus |
--exposure -6 |
pin camera exposure so room light can't set your frame rate |
--physics float |
air-hockey glide instead of gravity |
--mute |
silence the audio cues |
--no-telemetry |
stop polling the printer for progress |
--desk plus --pretend is the whole interaction with no projector and no printer,
which is the fastest way to see whether any of this is for you.
Gestures
| flick up at the monitor | model leaves the screen, arrives on the wall |
| pinch | grab the object; pinch again to release, or throw it |
| drop on the printer | countdown, then slice and print |
| pinch it back out | cancel an armed countdown |
| pull both hands apart | open the inspect view |
| swipe while inspecting | turn the part half a turn |
| clap | close the inspect view |
Nothing starts an unattended print without the hold-to-confirm countdown, which is
cancellable by pinching the object back out of the drop zone. Carrying an object past
the printer does nothing — only a released object that lands overlapping the printer
arms anything. Use --pretend while you are learning the gestures.
gesture/ reusable gesture stack — no projector or printer concepts
app/ interaction logic: the carry state machine, drawing, rendering, sound
ui/ display and camera-preview concerns
printer/ slice and send: Bambu Studio CLI, FTPS upload, MQTT control
tools/ the four setup/run entry points above
tests/ synthetic; no camera, projector or printer needed
app/carry.py is pure logic — it takes a hand position in wall coordinates plus a
pinch state and decides everything, physics included. That is what makes the paths
that must not start a print testable without hardware.
python -m pytestDeveloped against one X2D on one desk. The LAN protocol details were established
empirically against the real machine and several of them are not in any documentation
— if you are porting this to another Bambu model, the print URL scheme and model_id
are where to start looking.
by almostinventor
0 comments
log in to comment.