01 — Wave to begin

Navigate this page with your hand.

Open palm, swipe sideways: change slide. Pinch thumb and index, then move up or down: scroll. Nothing leaves your machine — the camera feed is processed in the browser.

Open palm swipe

Show five fingers and flick left or right. Fast, deliberate moves work best.

Pinch drag

Touch thumb to index and move your hand vertically to pull the page along.

Keyboard

Prefer hands off the camera? and still work.

02 — How it reads a hand

Twenty-one points, thirty times a second.

MediaPipe's hand landmarker returns 21 3D points per hand. Everything here is derived from a handful of distances between them: whether a fingertip sits above its knuckle, how far the thumb is from the index tip, and how quickly the wrist travels horizontally.

Finger extension is a comparison of tip and middle-joint height. Pinch is the thumb-to-index distance normalized by palm size, so it holds up whether your hand is near the lens or far from it. Swipes need a wrist velocity above threshold plus an open palm, with a cooldown so one flick doesn't fire twice.

Coordinates arrive normalized to 0–1 and are mirrored on the x axis, because the preview is mirrored and moving right should mean right.

03 — Tuning

Three numbers to play with.

PINCH_RATIO

0.38 by default. Lower it if pinches trigger by accident, raise it if they never register.

SWIPE_SPEED

1.15 screen-widths per second. Raise for deliberate flicks only, lower for gentler gestures.

SCROLL_GAIN

2200 pixels per full-frame hand travel. This one is pure feel.

All three sit at the top of the script, above the detection loop.

04 — Running it

Serve it, don't open it.

Browsers only grant camera access on secure origins, so double-clicking the file will fail. From the folder containing it, run python3 -m http.server 8000 and visit localhost:8000.

Good light in front of you, not behind. One hand in frame. Keep it roughly upright — extension is measured vertically, so a sideways hand reads as a fist.

Idle