← Effekte [ Effekt ]

Effekt · Content

Handlock — Grafiken, die an deinen Fingern kleben

Hand-Tracking für deine Videos: der Prompt, der es baut. Offline, ohne Abo.

Aus „Hype oder echt? #2“ Keyword Motion Aktualisiert am Als Google Doc öffnen ↗

Damit baut dir Claude Code ein echtes Hand-Tracking, das deine Fingerspitzen und Gesten erkennt. Keine App, kein Abo, läuft offline auf deinem Rechner.

So gehst du vor:

  1. Neuen leeren Ordner anlegen, Terminal darin öffnen, claude starten.
  2. Den Block unten komplett reinkopieren und abschicken.
  3. Wenn es fertig ist: npm run live, dann http://localhost:5757 im Browser öffnen.

Du brauchst Node.js (Version 20 oder neuer) und Claude Code. Sonst nichts.


Prompt 1 — Live an der Webcam

Baue mir ein Hand-Tracking, das live über meine Webcam läuft und Grafiken auf meine Hände zeichnet.

Technik:

  • Nutze @mediapipe/tasks-vision (npm) mit dem HandLandmarker im Modus runningMode: "VIDEO", numHands: 2.
  • Lade das Modell einmalig herunter und lege es lokal ab, damit alles offline läuft: https://storage.googleapis.com/mediapipe-models/hand_landmarker/hand_landmarker/float16/1/hand_landmarker.task
  • Die WASM-Dateien kommen aus node_modules/@mediapipe/tasks-vision/wasm.
  • Das Modell liefert 21 Punkte pro Hand mit x/y normalisiert auf 0..1. Rechne sie mit der Canvas-Breite/-Höhe in Pixel um.

Aufbau: Eine HTML-Seite mit einem Canvas, dazu ein winziger Node-Static-Server auf Port 5757, gestartet über npm run live. Zeichne pro Frame das Kamerabild aufs Canvas und die Grafiken darüber.

Diese vier Dinge unbedingt so umsetzen — sie sind die üblichen Stolperfallen:

  1. Die Seite MUSS über http://localhost laufen. Ein direkt geöffnetes file:// scheitert doppelt: getUserMedia braucht einen sicheren Ursprung, und die ES-Module-Importe werden von der CORS-Policy blockiert. Deshalb der kleine Server.
  2. Das <video>-Element MUSS im DOM hängen (unsichtbar ist ok: position:absolute;width:1px;opacity:0). Ein per createElement erzeugtes, nicht eingehängtes Video bleibt in Chrome mit echter Kamera bei readyState 0 stehen — die Zeichenschleife läuft dann, malt aber nie, und du siehst nur ein schwarzes Bild ohne Fehlermeldung.
  3. Warte auf das loadeddata- bzw. playing-Event UND auf videoWidth > 0, nicht nur darauf, dass play() durchläuft.
  4. detectForVideo() braucht streng steigende Zeitstempel. Nimm performance.now() und überspringe den Frame, wenn der Wert nicht größer ist als beim letzten Mal.

Glättung: Die Rohpunkte zittern ein paar Pixel pro Frame. Lege einen EMA-Filter mit Faktor 0.45 über alle Landmarks und setze ihn zurück, sobald eine Hand aus dem Bild verschwindet — sonst zieht die Grafik beim Wiederauftauchen sichtbar nach.

Gesten — normiere jedes Maß auf die Handflächenlänge dist(0,9), sonst ändert sich der Wert mit dem Abstand zur Kamera:

  • Pinch: dist(4,8) / dist(0,9) < 0.30
  • Finger gestreckt: dist(mcp,tip) / (dist(mcp,pip)+dist(pip,dip)+dist(dip,tip)) > 0.90. Ketten: Zeigefinger 5,6,7,8 · Mittelfinger 9,10,11,12 · Ringfinger 13,14,15,16 · kleiner Finger 17,18,19,20.
  • Hand offen: alle vier Finger gestreckt UND Pinch-Verhältnis > 0.80. Die zweite Bedingung ist nötig, sonst gilt ein Griff mit gestreckten Fingern als offene Hand.
  • Entprelle jeden Zustand über 3–5 Frames, sonst flackert er.

Probiere NICHT die Fingerspreizung (Zeigefingerspitze zu kleiner Fingerspitze) als „Hand offen” — der kleine Finger bleibt beim Greifen gespreizt, das Maß bleibt hoch und der Zustand ist unbrauchbar.

Zeichnen: Eckklammern um jede Hand, ein kleines Quadrat auf jeder Fingerspitze, und zwei Reaktionen: beim Pinch eine Linie zwischen Daumen- und Zeigefingerspitze, bei offener Hand ein Viereck auf der Handfläche. Baue das Viereck aus der Handachse selbst — Hochachse vom Handgelenk (0) zum Mittelfinger-Knöchel (9), Querachse vom Zeigefinger-Knöchel (5) zum Kleinfinger-Knöchel (17). Dann kippt es korrekt mit, statt flach über der Hand zu kleben.

Am Ende: kurze README mit dem Startbefehl.


Prompt 2 — Auf fertiges Videomaterial anwenden

Erst wenn Prompt 1 läuft. Damit werden deine Overlays exakt reproduzierbar, statt live einmalig.

Erweitere das Projekt so, dass ich das Tracking auf eine fertige Videodatei anwenden kann statt auf die Webcam.

Schritt 1: Frames mit ffmpeg extrahieren. Schritt 2: dieselbe HandLandmarker-Logik headless über Playwright drüberlaufen lassen und die Landmarks als eine JSON-Datei speichern (normalisiert 0..1, plus Breite/Höhe/fps). Schritt 3: ein zweites Skript, das aus dieser JSON die Overlays auf die Frames zeichnet und mit ffmpeg wieder zu einem MP4 zusammensetzt.

Zwei Fallen dabei:

  • Lade die Seite per page.goto von deinem lokalen Server, nicht über page.setContent — sonst liegt sie auf about:blank und jedes fetch auf die Frames scheitert am Cross-Origin-Check.
  • Sammle die fertigen Frames NICHT als dataURL in einem Array. Bei ein paar hundert Full-HD-Frames sprengt das den Speicher. Schreib jeden Frame sofort auf die Platte.

Den Ton aus der Quelldatei am Ende wieder dazumuxen, das Video selbst dabei nicht neu kodieren.


Wenn was klemmt

SymptomUrsache
Schwarzes Bild, Status sieht ok aus<video> hängt nicht im DOM (Punkt 2 oben)
Kamera startet gar nichtSeite läuft nicht über localhost, oder eine andere App belegt die Kamera
Grafik zittertEMA-Glättung fehlt oder Faktor zu hoch
Geste flackertEntprellung fehlt
Hand wird nicht erkanntHand ragt aus dem Bild — angeschnittene Hände fallen komplett aus dem Tracking

Fürs Filmen: Hände komplett im Bild lassen, nie am Rand anschneiden. Hände nicht ineinander verschränken — überlappende Hände ergeben nur eine Erkennung. Gesten rund eine Sekunde halten.