21 points / plan instrument

Guide de construction · 19 pages · 13 phases

Ta webcam devient un instrument — et une souris.

Un seul système de suivi des mains qui alimente cinq modes : musique, souris, capture d'écran, raccourcis, gestes personnalisés. Chaque phase a un objectif, des étapes, un prompt de départ pour le vibe coding et un critère de réussite.

Avancement du chantier … / 13 phases terminées
13phases
3parties
21points par main
7–12sessions estimées
HANDLANDMARKER · 2 mains · VIDEORELÂCHÉ
FPS—
PINCEMENT 4→8 / taille—
MIROIRx_écran = 1 − x_caméra
Le squelette, la zone active (20–80 % × 15–70 %) et le rapport pincement normalisé par la taille de la main : les trois idées de la partie A, en mouvement.

Mode d'emploi · commence ici

Lancer le truc en 3 étapes

Pas besoin de lire les 19 pages pour démarrer. Il y a deux morceaux : la page web (la webcam + le son, tout seul dans le navigateur) et le programme Python (souris, capture, raccourcis — il pilote le PC). Ils marchent séparément, ou ensemble via le pont.

  1. Ouvre l'instrument dans le navigateur — rien à installer, la webcam, le théorine, la harpe, la batterie et le looper marchent tout de suite (phases 1 à 4).
    Ouvrir l'instrument →
  2. Lance le programme Python — c'est lui qui pilote la souris, la capture d'écran et les raccourcis (phases 5 à 13).

    Déjà le projet sur ta machine ? double-clique sur python\dist\InstrumentGestuel.exe — tout est embarqué (MediaPipe, modèles, réglages), rien à installer, aucune fenêtre de terminal.

    Première installation, pas à pas (pour n'importe qui, n'importe quelle machine) :
    1. Installe Python 3.10 ou + sur python.org/downloads — sous Windows, coche « Add python.exe to PATH » dans le premier écran d'installation, sinon rien ne marchera après.
    2. Vérifie l'installation : ouvre un terminal (Windows : Win+R puis cmd ; macOS/Linux : Applications → Terminal) et tape python --version — il doit répondre Python 3.1x.x. Sinon, relance l'installateur en cochant la case PATH.
    3. Récupère le dossier du projet (archive .zip à télécharger, ou clône le dépôt) et décompresse-le où tu veux — garde la structure python\ avec models\, config.json et requirements.txt.
    4. Installe les dépendances : ouvre un terminal dans la racine du projet (clic droit dans le dossier → « Ouvrir une fenêtre PowerShell ici ») puis :
      python -m pip install -r python/requirements.txt
    5. Lance le programme :
      python python/main.py
      Une fenêtre vidéo s'ouvre avec les 21 points et « Démarré en mode SOURIS ». Autorise la caméra quand Windows/macOS le demande. Q pour quitter.
    6. Si la mauvaise caméra s'ouvre : python python/main.py --camera 1 (ou 2). Si le son ou la capture ne répond plus, vérifie qu'aucune autre application (Zoom, Teams, Chrome) n'utilise la caméra.

    Option : l'instrument dans le navigateur (indépendant, sans rien installer) — il faut juste Node.js pour servir la page locale :
    npx wrangler dev --port 8788
    # puis ouvre http://127.0.0.1:8788/phase1
    Le démarrage affiche Q pour quitter, et la page se pilote avec les mains (théorine, harpe, batterie, looper).
  3. Branche les deux (le pont) — pour que la page web joue avec la vision Python (phase 12), il faut deux terminaux :
    # terminal 1 — la page locale
    npx wrangler dev --port 8788
    # puis ouvre http://127.0.0.1:8788/phase1
    
    # terminal 2 — Python envoie les 21 points à la page
    .venv\Scripts\python.exe python\main.py
    La page affiche « pont connecté » : elle joue avec les mains vues par Python, sans webcam dans le navigateur.

Les touches, toutes

Dans la fenêtre vidéo de Python — le numéro du mode est toujours affiché en haut à droite.

ToucheCe qu'elle fait
0Pause — plus rien ne bouge, même les gestes.
1Souris — l'index déplace le curseur, pincer = clic, pincer long = glisser, 2 doigts = défilement.
2Capture — deux mains en « L » pour cadrer la zone, maintiens 1 s pour prendre la capture.
3Raccourcis — poing = play/pause, 1/2 doigts = diapo, 3/4 = volume, main ouverte = bureau.
4Gestes — R enregistre un geste (30 échantillons), S change de slot, P active la reconnaissance.
5Dessin — l'index seul trace dans l'air, F sauvegarde en PNG + JSON.
VVisage — clignement volontaire = clic, pencher la tête = défilement (droite : bas, gauche : haut).
X / UArrêt d'urgence / reprise — coupe ou relance tout, même depuis l'autre app (écoute globale).
QQuitter le programme.
Sans clavierGeste de mode : deux mains à plat devant la caméra 0,5 s, puis 1 à 5 doigts levés = mode 1 à 5.

1 · Vision du projet

Un seul suivi des mains, cinq usages

La webcam capte, MediaPipe retrouve 21 points par main, et tout le reste — son, curseur, capture, raccourcis — se déduit de ces 21 points. Le projet se construit en trois morceaux, chacun utilisable seul.

Mode musique

Un instrument

Théorine, harpe invisible, batterie aérienne, looper, effets — tout en Web Audio.

Mode souris

Le curseur

L'index déplace le curseur, le pincement clique, deux doigts font défiler.

Mode capture

Le viseur

Un geste de cadrage avec les deux mains capture une zone de l'écran.

Mode raccourcis

Le pupitre

Gestes pour changer de bureau, régler le volume, piloter des diapositives.

Mode libre

Gestes personnalisés

Tu enregistres un geste en 30 secondes et tu l'associes à une action.

Règle d'or : ne passe à la phase suivante que lorsque le critère de réussite de la phase en cours est validé.

2 · Pourquoi deux technologies

Le navigateur fait le son, Python pilote la machine

Un navigateur ne peut pas déplacer la vraie souris, simuler des clics ni lancer des raccourcis système, pour des raisons de sécurité. En revanche il est excellent pour l'audio, les visuels et l'interface. D'où l'architecture finale :

Côté navigateur (partie A), tu peux te passer de Python : la vision tourne directement dans la page avec MediaPipe Tasks Vision, et l'audio est natif. C'est la voie rapide pour un projet montrable.

Côté Python (partie B), tu récupères les mêmes landmarks pour agir sur le système : PyAutoGUI pour la souris et le clavier, mss pour la capture, pynput pour l'arrêt d'urgence, websockets pour la page.

ContenuTechnoDurée estimée
AInstrument dans le navigateurHTML/JS, MediaPipe Tasks Vision, Web Audio2 à 4 sessions
BContrôle du PCPython, MediaPipe, OpenCV, PyAutoGUI, mss3 à 5 sessions
CFusion et interfacePython + WebSocket + page web2 à 3 sessions

4 · Notions à comprendre avant de coder

Six réglages qui décident de tout

La moitié des bugs de gestes viennent de ces six choses. Prends les cinq minutes de les lire avant d'écrire la première ligne.

4.1 · Les 21 points

Chaque main, en 21 repères

MediaPipe renvoie 21 points par main, avec x et y normalisés entre 0 et 1 (relatifs à l'image) et z (profondeur relative au poignet). Les indices que tu utiliseras tout le temps :

0Poignet
4Bout du pouce
8Bout de l'index
12Bout du majeur
16Bout de l'annulaire
20Bout de l'auriculaire
5, 9, 13, 17Bases MCP des doigts
6, 10, 14, 18Articulations PIP
4.2 · Effet miroir

« Main à droite » ≠ « curseur à droite »

Pour que « main à droite » signifie « curseur à droite » à l'écran, inverse l'axe x. Attention : MediaPipe étiquette la main Left ou Right du point de vue de l'image non miroir — si tu retournes l'image, l'étiquette est inversée.

x_écran = 1 − x_camera

// teste avec un console.log et ta
// vraie main DROITE avant de te
// fier à l'étiquette
4.3 · Normaliser

Diviser par la taille de la main

Une distance en pixels change quand tu t'approches de la caméra. Normalise toujours par une longueur de référence : la distance poignet → base du majeur. Ainsi un pincement se mesure par un rapport indépendant de la distance.

taille    = distance(p[0], p[9])
pincement = distance(p[4], p[8]) / taille
4.4 · Hystérèse

Deux seuils, pas un

Si tu déclenches un clic sous 0.25, la valeur oscillera autour du seuil et produira des clics parasites. On passe à « pincé » sous 0.25, on repasse à « relâché » seulement au-dessus de 0.35. Cette technique s'applique à tous les gestes.

if (!pince && r < 0.25) pince = true;
if (pince  && r > 0.35) pince = false;
4.5 · Lissage

Le filtre One Euro

Une moyenne mobile est soit trop tremblante, soit trop lente. Le filtre One Euro adapte son lissage à la vitesse : fort quand la main est presque immobile, faible quand elle bouge vite.

min_cutoff ≈ 1.0   // plus bas = plus lisse à l'arrêt
beta        ≈ 0.007 // plus haut = moins de retard
4.6 · Zone active

Ne pas lever le bras

Tu ne veux pas tendre le bras jusqu'aux bords de l'image pour atteindre les coins de l'écran. Définis un rectangle dans l'image et convertis-le linéairement vers tout l'écran — et rends ce rectangle visible et réglable à l'écran de contrôle.

x : 20 % → 80 %  de l'image
y : 15 % → 70 %  de l'image
   ↓ conversion linéaire
tout l'écran

3 à 13 · Le chantier

Les 13 phases, une par une

Chaque phase : l'objectif, les étapes, les points techniques, un prompt de départ copiable en un clic, et le critère qui autorise à passer à la suivante.

Partie A — l'instrument dans le navigateur

HTML/JS · MediaPipe Tasks Vision · Web Audio · 2 à 4 sessions
Phase01

La vision web

ObjectifAfficher la webcam et dessiner les points de la main en temps réel.

  • Crée index.html avec une balise video, un canvas superposé et un bouton « Démarrer » (les navigateurs exigent un clic pour l'audio, et c'est plus propre pour la caméra).
  • Demande la caméra avec getUserMedia({ video: { width: 640, height: 480 } }) — 640×480 suffit et reste très rapide.
  • Charge MediaPipe Tasks Vision via le CDN, module ES, version fixée, et le modèle hand_landmarker.task.
  • Crée le HandLandmarker avec runningMode: "VIDEO", numHands: 2, seuils de confiance à 0.5 environ.
  • Dans une boucle requestAnimationFrame, appelle detectForVideo(video, performance.now()) et dessine les 21 points et leurs connexions.
  • Affiche les FPS à l'écran. Objectif : 30 FPS ou plus.
Points techniques
  • Serve la page via un petit serveur local (python -m http.server ou Live Server) : caméra et modules ES sont bloqués sur file://.
  • Le délégué GPU (delegate: "GPU") accélère la détection, avec repli automatique sur CPU.
  • N'appelle detectForVideo que si video.currentTime a changé : pas de calcul deux fois sur la même image.
Prompt de départ
Crée un fichier HTML unique qui ouvre la webcam (640x480), utilise MediaPipe Tasks Vision (HandLandmarker, 2 mains, mode VIDEO, chargé depuis jsDelivr avec une version fixée) et dessine les 21 landmarks et leurs connexions sur un canvas superposé, en miroir. Affiche les FPS et indique pour chaque main si elle est gauche ou droite. Un bouton Démarrer lance tout.

Ouvrir la démo live de cette phase →

Critère de réussite — tu vois ton squelette de main suivre tes mouvements avec moins de 100 ms de retard perçu et plus de 25 FPS.

Phase02

Le théorine

ObjectifUn son continu dont la hauteur dépend de la position de ta main droite et le volume de ta main gauche.

  • Crée l'AudioContext au clic sur Démarrer (sinon il reste suspendu).
  • Chaîne : OscillatorNode → GainNode → BiquadFilterNode → destination.
  • Main droite : position verticale → note MIDI entre 48 et 84, puis f = 440 × 2^((n − 69) / 12).
  • Main gauche : hauteur → volume, de 0 à 0.5 maximum, jamais au-delà de 1.
  • Toutes les modifications de paramètres via setTargetAtTime(valeur, currentTime, 0.03) : zéro craquement.
  • Si une main disparaît, volume vers 0 progressivement, jamais coupé net.
Gammes (demi-tons depuis la tonique)
GammeIntervalles
Pentatonique mineure0, 3, 5, 7, 10
Pentatonique majeure0, 2, 4, 7, 9
Majeure0, 2, 4, 5, 7, 9, 11
Mineure naturelle0, 2, 3, 5, 7, 8, 10
Blues0, 3, 5, 6, 7, 10

Quantification : pour une note brute, choisis la note de gamme la plus proche. Prévois un mode « glissando » (sans quantification) et un mode « notes » (quantifié).

Prompt de départ
Ajoute à la page un théorine : la main droite contrôle la hauteur (axe vertical, 3 octaves, quantifiée sur une gamme pentatonique mineure choisissable dans un menu) et la main gauche contrôle le volume. Web Audio API avec oscillateur, gain, et filtre passe-bas. Tous les changements de paramètres utilisent setTargetAtTime. Affiche la note jouée à l'écran et une grille verticale montrant les zones de notes sur la vidéo.

Critère de réussite — tu joues une mélodie simple (« Au clair de la lune ») sans fausse note involontaire.

Phase03

Enrichir l'instrument

ObjectifSix modules indépendants — à ajouter un par un, sans toucher au théorine.

  • 3.1 Timbres — formes d'onde (sine, square, sawtooth, triangle), synthèse additive avec oscillateurs désaccordés de 5 à 10 cents, enveloppe ADSR, vibrato lent à 5 Hz dont la profondeur dépend de la vitesse de la main.
  • 3.2 Effets — delay + feedback (≤ 0.4 pour ne pas partir en larsen), réverbération par ConvolverNode avec réponse impulsionnelle (bruit blanc, décroissance 2–3 s), distorsion WaveShaper tanh, filtre piloté par l'écart entre les deux mains.
  • 3.3 Harpe invisible — 8 à 12 cordes verticales ; une corde se déclenche quand l'index change de côté entre deux frames, le volume vient de la vitesse de franchissement. Synthèse Karplus-Strong, ou triangle à décroissance rapide. Recharge de 80 ms par corde.
  • 3.4 Batterie aérienne — 4 à 6 zones (grosse caisse, caisse claire, charleston, tom). Un « coup » = vitesse verticale de l'index qui dépasse un seuil puis s'inverse. Sons synthétisés (grosse caisse : sinus 150 → 40 Hz en 0.2 s), flash dans la zone touchée.
  • 3.5 Looper — poing fermé 1 s = enregistrement, main ouverte = fin de boucle. Enregistre les événements (timestamp, note, durée, volume) plutôt que l'audio : légers, modifiables, empilables. Métronome BPM réglable, quantification, bouton muet et supprimer par couche.
  • 3.6 Contrôle par l'écart entre les mains — distance entre les deux poignets, normalisée, vers une cible au choix : filtre, réverb, vibrato, BPM. Menu d'assignation par axe (gauche x/y, droite x/y, distance, pincement).
Prompt de départ (par module)
Ajoute un module [harpe / batterie / looper] à l'instrument existant, activable par un sélecteur de mode. Ne modifie pas le code du théorine. [Spécifications du module.]

Critère de réussite — tu peux jouer une petite boucle de trois couches (basse, mélodie, batterie) sans que le son sature.

Phase04

Les visuels

ObjectifQue l'instrument soit beau, pas seulement fonctionnel. De la plus simple à la plus ambitieuse :

  • Traînées lumineuses derrière les bouts de doigts (canvas 2D, couche semi-transparente qui s'estompe).
  • Particules émises à chaque note — teinte HSL selon la hauteur, taille selon le volume.
  • Spectrogramme ou forme d'onde en direct via AnalyserNode.getByteFrequencyData().
  • Shader plein écran (WebGL ou WebGPU) dont les uniforms reçoivent l'énergie des basses, médiums, aigus et la position des mains.
  • Fond 3D (Three.js) qui réagit à la musique.
Règle d'architecture

Sépare le code visuel du code audio. Le module visuel reçoit uniquement un objet d'état { mains, notes, niveauxFrequence } et ne touche jamais à l'audio.

Critère de réussite — tu peux filmer une démonstration de 30 secondes qui donne envie de l'essayer.

Partie B — contrôler le PC en Python

Python · MediaPipe · OpenCV · PyAutoGUI · mss · 3 à 5 sessions
Phase05

La vision en Python

ObjectifReproduire la phase 1 en Python.

  • cv2.VideoCapture(0) ; sous Windows, ajoute cv2.CAP_DSHOW pour un démarrage plus rapide. Résolution 640×480.
  • mp.solutions.hands avec max_num_hands=2, model_complexity=0 pour la rapidité, détection et suivi à 0.6.
  • Convertis les images BGR → RGB avant MediaPipe.
  • Dessine les points avec OpenCV, fenêtre de contrôle avec les FPS.
  • Capture dans un thread dédié qui garde toujours la dernière image : pas de retard qui s'accumule.
  • Quitte proprement sur Échap.
Prompt de départ
Écris un script Python qui lit la webcam (640x480, DirectShow sur Windows) dans un thread dédié, détecte jusqu'à 2 mains avec MediaPipe Hands (model_complexity 0), dessine les landmarks en miroir dans une fenêtre OpenCV avec les FPS, et quitte avec Échap. Structure le code en classes : CameraThread, HandTracker.

Critère de réussite — plus de 25 FPS stables, sans retard qui s'accumule.

Phase06

La souris

ObjectifL'index déplace le curseur de manière fluide et précise.

  • Taille de l'écran avec pyautogui.size(), conversion de l'index (point 8, miroir) via la zone active (4.6).
  • Filtre One Euro sur x et y.
  • pyautogui.moveTo(x, y, _pause=False), pyautogui.PAUSE = 0, et FAILSAFE = True conservé : la souris dans un coin lève une exception — ton arrêt d'urgence.
  • Sous Windows, ctypes.windll.shcore.SetProcessDpiAwareness(2) avant tout appel, sinon les coordonnées sont décalées à 125 % ou 150 %.
  • Suivi actif uniquement quand le geste d'activation est détecté — sinon tu perds le contrôle de ta vraie souris.
  • Mode « ralenti » quand index et majeur sont tendus ensemble : déplacement divisé par 3 pour viser les petits boutons.
Gestes de commandement
  • Activer : main ouverte, doigts écartés, maintenue 1 seconde (jauge de progression affichée).
  • Pause : poing fermé maintenu 1 seconde.
  • Arrêt d'urgence : F12 écouté globalement avec pynput, même sans focus, en plus du failsafe PyAutoGUI.
Prompt de départ
Ajoute au script un module de contrôle de souris : l'index (point 8) contrôle le curseur à travers une zone active rectangulaire réglable, avec un filtre One Euro (min_cutoff et beta réglables au clavier), DPI awareness sur Windows, failsafe PyAutoGUI, arrêt d'urgence F12 via pynput. Le contrôle s'active par une main ouverte maintenue 1 seconde et se met en pause par un poing maintenu 1 seconde, avec un retour visuel.

Critère de réussite — tu peux cliquer sur un bouton de 30 pixels avec ta vraie souris posée, sans trembler, sans faux départ.

Phase07

Clic, glisser-déposer, défilement

ObjectifRemplacer entièrement la souris physique pour les actions courantes.

  • Clic gauche : pincement pouce-index, mouseDown à l'entrée et mouseUp à la sortie de l'état « pincé », avec hystérèse (0.25 / 0.35).
  • Pincement court (< 300 ms) = clic, pincement long = glisser-déposer : même mécanisme, rien de spécial à coder.
  • Clic droit : pincement pouce-majeur. Double-clic : deux pincements en moins de 400 ms.
  • Dérive du curseur en pinçant — trois solutions : mémoriser la position 100 ms avant, utiliser le milieu de la paume (point 9), ou geler le curseur les 150 premières millisecondes.
  • Défilement : index et majeur tendus, les autres repliés → mouvement vertical → pyautogui.scroll, vitesse proportionnelle à la vitesse de la main, avec zone morte.
Hors périmètre de départ

Clavier virtuel et saisie de texte : extension possible plus tard, un clavier affiché à l'écran où tu pinceras les touches.

Prompt de départ
Ajoute la détection de pincement avec hystérèse (seuils 0.25 et 0.35 normalisés par la taille de la main) : pouce-index = clic gauche avec mouseDown/mouseUp pour permettre le glisser-déposer, pouce-majeur = clic droit. Gèle le curseur 150 ms au début du pincement pour éviter la dérive. Ajoute le défilement avec index et majeur tendus.

Critère de réussite — tu ouvres un dossier, tu sélectionnes un fichier, tu le déplaces et tu fais défiler une page web uniquement avec tes mains.

Phase08

La capture d'écran par geste

ObjectifCadrer une zone avec les deux mains et la capturer.

  • Les deux mains forment un « L » (pouce et index tendus, les autres doigts repliés).
  • Les deux index définissent les coins opposés du rectangle, converti en coordonnées d'écran.
  • Le rectangle apparaît en direct dans une fenêtre transparente par-dessus l'écran (tkinter sans bordure, -transparentcolor sous Windows) — ou, plus simple pour commencer, dans la fenêtre de contrôle OpenCV.
  • Maintiens 1 seconde (compte à rebours visuel), ou pince les deux mains en même temps pour valider.
  • Capture avec mss : fichier PNG horodaté dans captures/, copie dans le presse-papiers (win32clipboard + DIB via Pillow), notification discrète, flash blanc de 100 ms.
Le bout de code central
with mss.mss() as sct:
    zone = {"left": x1, "top": y1,
            "width": x2 - x1, "height": y2 - y1}
    image = sct.grab(zone)
    mss.tools.to_png(image.rgb, image.size,
                     output="captures/capture_2026-10-29_14h30.png")
Variantes

Capture plein écran (les deux mains en cadre de la taille de l'écran), capture de fenêtre via pygetwindow.

Prompt de départ
Ajoute un mode capture : quand les deux mains forment un L (pouce et index tendus), calcule le rectangle défini par les deux index, converti en coordonnées d'écran, l'affiche dans la fenêtre de contrôle, et le capture avec mss après 1 seconde de maintien avec une jauge de progression. Sauvegarde en PNG horodaté dans captures/ et copie dans le presse-papiers.

Critère de réussite — tu captures une zone précise de ton écran en moins de 3 secondes, sans toucher au clavier.

Phase09

Raccourcis et contrôle média

ObjectifDes gestes qui remplacent des raccourcis clavier.

GesteActionImplémentation
Swipe rapide vers la droiteDiapo ou bureau suivantpress('right') ou hotkey('ctrl','win','right')
Swipe rapide vers la gauchePrécédentpress('left')
Trois doigts tendusLecture / pausepress('playpause')
Paume vers la caméra puis fermerValider (Entrée)press('enter')
PoingVolumevolumeup / volumedown, ou pycaw pour un volume précis
Pouce levéFermer la fenêtrehotkey('alt','f4') — avec confirmation !
Distance pouce-index (une main)Alt+Tabhotkey('alt','tab')
Détection & sécurité
  • Swipe : vitesse horizontale du poignet sur une fenêtre glissante de 200 à 300 ms ; déplacement > 35 % de la largeur avec trajectoire presque horizontale. Recharge de 700 ms.
  • Doigts levés : le bout (8, 12, 16, 20) est plus loin du poignet que son articulation PIP (6, 10, 14, 18) ; pour le pouce, compare x(4) et x(2) selon la main.
  • Sécurité : les actions destructrices demandent toujours un second geste de confirmation ; chaque action a un temps de recharge.
  • Mode présentation (utile pour le Grand Oral) : deux gestes seulement (suivant / précédent) pour réduire les faux positifs, avec un voyant à l'écran.
Prompt de départ
Ajoute un mode raccourcis : swipe horizontal du poignet sur 250 ms (seuil 35 % de la largeur, recharge 700 ms) pour diapo suivante/précédente, poing maintenu pour le volume, trois doigts tendus pour lecture/pause, avec confirmation par second geste pour l'action destructive. Expose chaque geste et son action dans config.json.

Critère de réussite — tu fais défiler un PowerPoint de 10 diapositives avec uniquement des swipes, sans erreur.

Phase10

Gestes personnalisés

ObjectifEnregistrer un nouveau geste sans écrire de code.

  • Mode apprentissage : tu tiens le geste devant la caméra, l'application prend 30 échantillons.
  • Pour chaque échantillon, calcule un vecteur invariant de position et d'échelle : les 21 points recentrés sur le poignet et divisés par la taille de la main (42 valeurs), ou des distances entre paires clés + angles des doigts.
  • Stocke la moyenne et la dispersion dans config.json.
  • En fonctionnement, compare au vecteur courant (distance euclidienne ou k-NN) : si la distance minimale passe le seuil et reste stable 5 frames consécutives, le geste est reconnu.
  • Dans l'interface, associe chaque geste à une action : touche, raccourci, commande, lancement de programme.
Variantes
  • Avancé : petit MLP (scikit-learn ou TensorFlow Lite) entraîné sur les échantillons, ou MediaPipe Model Maker pour un Gesture Recognizer personnalisé — seulement si la version simple ne suffit pas.
  • Gestes dynamiques (cercle, « Z ») : enregistre la trajectoire du bout de l'index sur 1 seconde, rééchantillonne à 32 points, compare avec un $1 recognizer.
Prompt de départ
Ajoute un mode apprentissage de geste : 30 échantillons, vecteur = 21 points recentrés sur le poignet divisés par la taille de la main, moyenne et écart-type stockés dans config.json, reconnaissance si distance sous le seuil et stable 5 frames. Interface pour associer chaque geste enregistré à une action.

Critère de réussite — tu crées un geste inédit en 30 secondes et il se déclenche de manière fiable plus de 9 fois sur 10.

Partie C — la fusion

Python + WebSocket + page web · 2 à 3 sessions
Phase11

Modes et machine à états

ObjectifUn seul programme qui bascule entre musique, souris, capture et présentation.

  • Une classe Mode avec on_enter(), on_exit(), update(mains), draw(frame).
  • Un gestionnaire de modes qui reçoit les landmarks et les transmet au mode actif.
  • Gestes globaux (tous modes) : changer de mode — deux mains à plat, paumes vers la caméra, puis un nombre de doigts levés pour choisir —, pause générale, arrêt d'urgence.
  • Un config.json avec les seuils, la zone active, les gestes personnalisés et les assignations.
  • Transition de mode : une courte animation et un son pour savoir toujours où tu es — les erreurs de mode sont la première cause de frustration.
Phase12

Pont WebSocket vers l'interface web

ObjectifUtiliser ta page web (audio, visuels, réglages) avec la vision et les actions du programme Python.

  • Python lance un serveur websockets sur localhost:8765.
  • À chaque frame (ou 30 fois par seconde), Python envoie {"mains": [...], "gestes": [...], "mode": "musique"}.
  • La page reçoit les landmarks à la place de MediaPipe web, et fait le son et les visuels.
  • Dans l'autre sens : changer de mode, modifier un seuil, enregistrer un geste.
  • Réglages modifiables en direct depuis la page : curseurs pour le lissage, la zone active, les seuils.
Points d'attention
  • N'envoie que le nécessaire : 21 points × 2 mains arrondis à 3 décimales.
  • Écoute localhost uniquement, jamais l'adresse publique — personne d'autre ne doit pouvoir piloter ton PC.
  • Reconnexion automatique côté web.

Critère de réussite — tu joues de l'instrument dans la page web alimentée par la vision Python, et tu bascules vers le mode souris avec un geste.

Phase13

Extensions optionnelles

ObjectifÀ prendre une fois les 12 premières phases validées — chacune utile seule.

  • Visage ✓ : clignement volontaire = clic, pencher la tête = défilement — fait (Face Landmarker, touche V ou --visage, une image sur deux pour garder les FPS).
  • Regard : curseur grossier, affiné par les mains.
  • Voix (speech_recognition ou Web Speech API) combinée aux gestes — dire « capture » puis cadrer.
  • Clavier virtuel gestuel avec prédiction de mots.
  • Dessin dans l'air ✓ : l'index seul trace, le tracé s'affiche et s'enregistre — fait (touche 5, F pour sauver en PNG + JSON dans python/captures/).
  • Export MIDI ✓ : le looper écrit un fichier .mid — fait (bouton « Exporter en MIDI », format 1, une piste par couche, tempo de la boucle).
  • Ambiance : lampes connectées ou LED via HTTP/MQTT.
  • Application de bureau ✓ : python\dist\InstrumentGestuel.exe — fait (PyInstaller, un seul fichier de ~118 Mo, modèle et réglages embarqués, testé à 30 FPS).

Reste à faireRegard, voix, clavier virtuel, ambiance — chacune est indépendante et aucune n'est nécessaire pour les 12 premières phases, qui sont toutes terminées.

5 · Pièges fréquents

Quand ça merde, c'est l'une de ces lignes

Le tableau de diagnostic : symptôme, cause, correction. À garder ouvert pendant le développement.

ProblèmeCauseSolution
Curseur qui tremblePas de lissageFiltre One Euro, ajuster min_cutoff
Curseur qui traîneLissage trop fort ou latence caméraAugmenter beta, baisser la résolution, thread dédié
Clics parasitesSeuil uniqueHystérèse, temps de recharge
Curseur décaléMise à l'échelle WindowsDPI awareness
Gauche et droite inverséesEffet miroirTester l'étiquette de main, inverser si besoin
Main perdue souventMauvaise lumière, arrière-plan chargéLumière de face, fond uni, baisser le seuil de détection
Son qui craqueChangement brutal de paramètresetTargetAtTime ou rampes
LarsenHaut-parleurs et micro, feedback trop fortÉcouteurs, feedback sous 0.5
Audio muet au démarrageAudioContext suspenduresume() après un clic
Fatigue du brasZone active trop grande ou trop hauteZone basse et petite, coude appuyé sur la table
Caméra occupéeUne autre application l'utiliseFermer les autres applications
Latence audio élevéeBluetooth, grosse mémoire tamponCasque filaire, latencyHint: "interactive"
Faux positifs de gestesPas de confirmationMaintien de 5 frames, geste d'activation
Script impossible à arrêterSouris contrôlée par le scriptFailsafe, F12, geste de pause

6 · Méthode de vibe coding

Sept règles pour ne pas perdre le fil

Ce qui fait qu'un projet de gestes avance au lieu de stagner en boucle sur le même bug.

  1. Un module par conversation — ne demande jamais « fais tout le projet ».
  2. Toujours donner le contexte : le code existant pertinent, l'OS, la version de Python, le navigateur.
  3. Demander des journaux activables : ça aide énormément à déboguer les gestes.
  4. Tester chaque ajout immédiatement, et faire un commit Git avant chaque nouvelle fonctionnalité pour pouvoir revenir en arrière.
  5. En cas de bug : message d'erreur complet, ce que tu as fait juste avant, et ce que tu attendais.
  6. Demander d'abord les réglages exposés (seuils dans config.json) plutôt que des valeurs écrites en dur : tu ajusteras à la main sans redemander du code.
  7. Garder un NOTES.md : décisions prises, valeurs de seuils qui marchent, problèmes connus.

7 · Checklist de tests

À refaire après chaque grosse modification

  • Bonne lumière, mauvaise lumière, contre-jour.
  • Main gauche seule, main droite seule, deux mains, mains qui se croisent.
  • Main qui entre et sort du champ.
  • Gestes rapides et gestes lents.
  • Plusieurs minutes d'utilisation continue (surchauffe, fuite mémoire, FPS qui baissent).
  • Arrêt d'urgence fonctionnel dans chaque mode.
  • Écran externe et mise à l'échelle différente.
  • Lancement à froid : tout démarre sans intervention manuelle.

8 · Feuille de route

Dix étapes, un résultat visible chacune

L'ordre conseillé, du squelette de main dans le navigateur jusqu'à l'empaquetage en .exe.

ÉtapeContenuRésultat visible
1Phase 1Squelette de main dans le navigateur
2Phase 2Premier son, théorine jouable
3Phase 3 (un module)Harpe ou batterie
4Phase 3 (looper) et 4Démo filmable
5Phases 5 et 6Curseur contrôlé par l'index
6Phase 7Clic, glisser, défilement
7Phase 8Capture par geste
8Phases 9 et 10Raccourcis et gestes personnalisés
9Phases 11 et 12Programme unifié avec interface web
10Phase 13Extensions au choix, empaquetage

Conseil final : arrête-toi à l'étape 4 si tu veux d'abord un projet montrable (portfolio, démo en classe), puis continue vers le contrôle du PC. Chaque étape est utile seule.

9 · Ressources utiles

La documentation à garder sous la main