Real-time head-tracked 3D point-of-view for Visual Pinball X — pure Rust, zero-install, self-calibrating.
Move your head, the table's perspective follows — the fish-tank VR effect that makes a flat screen feel like a real cabinet. An open-source, cross-platform alternative to BAM, that works from a plain webcam or a Kinect v1 / v2.
A real pincab (Attack from Mars): the tracking rig on the backbox, and the cabinet reference frame the model detects.
Head tracking for pinball isn't new. Doing it without asking the user to calibrate anything is. That's the whole bet of this project:
-
Zero manual calibration. The cabinet itself is the calibration target. The lockbar and the two side rails form a known rectangle of the playfield. Seen in perspective, that's enough to recover the camera's focal length and its pose relative to the table — from the image alone. No checkerboard, no wizard, no "look here and press space".
The reference frame the model finds: lockbar (box) + the two side rails → camera pose, automatically.
-
3D from a plain webcam. No depth sensor required: the recovered focal turns a single camera into a metric 3D head tracker. Kinect depth is a bonus, not a requirement.
-
Zero install for the end user. One plugin binary. No Microsoft SDK, no Python, no drivers to hunt down —
libfreenect/libfreenect2and the ONNX runtime are all statically linked. -
100 % Rust, cross-platform (Linux · Windows · macOS), GPL-3.0.
flowchart LR
CAM[Webcam / Kinect] --> HEAD[BlazePose<br/>head landmarks]
CAM --> ANCHOR[anchor model<br/>lockbar + rails]
ANCHOR --> CAL[Auto-calibration<br/>focal + camera pose]
HEAD --> POSE[Head position in mm]
CAL --> POSE
POSE --> VPX[VPX plugin<br/>live POV update]
VPX --> TABLE[Table perspective follows your head]
Two ONNX models run per frame through ort: BlazePose
finds the head (~7 ms), and the anchor model locates the cabinet's reference
frame. A pure-Rust decoder turns that frame into the camera's focal length and
pose (vanishing points + single-plane homography), then every head pixel
deprojects into real millimetres and drives the table's point of view.
The auto-calibration toolkit — draw a few lines on cabinet photos, get an ONNX
model — lives in tools/anchor/ with its own guide.
Every backend works, but the sweet spot is a used Kinect v2 (Xbox One) — and it's absurdly cheap since Microsoft discontinued it:
- From ~€20 on leboncoin / eBay / your local classifieds — there are tons of listings (both links are pre-filtered, cheapest first).
- It tracks on its infrared stream: the sensor lights the scene itself, so you get full 30 fps in a pitch-dark game room where a webcam struggles.
- Real depth sensor → your head distance is measured in millimetres, not estimated.
⚠️ Budget for the Kinect Adapter (power + USB 3.0, ~€29 new) unless the listing includes it — check before buying. Total ~€50 all-in.- Plug it into a dedicated USB 3.0 port on the motherboard's back panel (it won't enumerate behind a shared hub).
- Mounting on the cab: a 1/4"-20 screw assortment kit (~€11 for 40 stainless pieces — 7 lengths from 5/16" to 1", spacers and wrench included) is all it takes to fix the sensor on top of the backglass or the topper. Both are collected in a ready-made Amazon "Headtracking" list — and they ship with Prime, so next-day delivery for the impatient. And the sensor itself? leboncoin hand-to-hand pickup can put a Kinect in your cab the very same day if you hustle. 😄
Important
The Kinect v2 devours USB bandwidth. It streams everything at once: colour 1920×1080 @ 30 fps (JPEG on the wire), infrared 512×424 @ 30 fps and depth 512×424 @ 30 fps — those last two as raw uncompressed phase data — plus the 4-microphone audio array. That's close to saturating a USB 3.0 link on its own. So before blaming the camera or the adapter: make sure it's on a dedicated USB 3.0 root port on the motherboard — no hub, no front-panel port, no cheap extension cable.
The Kinect v1 (Xbox 360) is even cheaper and field-tested too — lower resolution but perfectly usable. And a plain webcam costs nothing if you already have one: auto-calibration recovers real 3D from it (that's the whole point of this project) — the Kinect's IR just wins in a dark cabinet.
Building a minicab? The short player-to-camera distance changes the picks — see the dedicated notes: 🇬🇧 Minicab notes · 🇫🇷 Notes minicab.
This is early development, released as beta. It builds for Linux, Windows and macOS, and the full chain — camera → auto-calibration → live POV inside a running VPX — is now field-validated on a real Linux pincab (Kinect v2, Kinect v1 and webcam, Window view mode). Windows and macOS runs are exactly what we need testers for.
Caution
To let this project access a Kinect, the bundled driver setup replaces Microsoft's official Kinect driver with a generic WinUSB one. This breaks everything built on the Microsoft Kinect SDK — including a working BAM head-tracking setup — until you restore the original driver (Device Manager → the "Xbox NUI" devices → uninstall our driver, rescan, or reinstall the Kinect SDK/runtime). Only run the Kinect driver setup if you accept that trade. Webcam users are not affected.
| Piece | State |
|---|---|
| VPX plugin loads & builds (Linux/Windows/macOS) | ✅ |
| Kinect v2 capture + head blob | ✅ operational |
| Kinect v1 capture | ✅ |
| Webcam capture (SDL3) | ✅ |
| BlazePose head tracking (ONNX, ~7 ms) | ✅ proven on real captures |
| Standalone demo + fish-tank parallax window | ✅ headtracking-demo |
| Auto-calibration maths (focal + pose) | ✅ validated to ±0–3 % vs tape measure |
anchor training pipeline (lines → ONNX) |
✅ validated end-to-end |
Trained, generalizing anchor model |
🚧 needs annotated photos |
| Live POV inside VPX, end-to-end | ✅ field-validated on a real Linux pincab |
| In-game settings (F12 → Plugin Settings), live tuning | ✅ |
| Windows / macOS real-world runs | 🚧 needs testers |
This is the project's #1 bottleneck, and anyone with a pincab can fix it. The auto-calibration model currently knows exactly one cabinet: ours. To learn what every lockbar and rail look like — every wood tone, lighting, camera angle — it needs to see real cabinets. Yours.
- Download
headtracking-demofrom the latest release — a single binary, nothing to install. - Point your webcam or Kinect at the playfield, select it in the demo.
- Click 🎁 Contribute and confirm.
That's it. The demo uploads a capture set (colour image + what the detector saw + depth/IR when a Kinect is there) to a write-only drop, and it becomes training data.
What we extract from your capture: the lockbar's two edges, the two side rails, and their 6 intersection points — the cabinet's reference frame.
What gets shared, honestly: the images show your cabinet and whatever is around it — check the preview before accepting. Uploads need no account and carry no identity; each capture has a printed ID you can quote on Discord to have it removed. Empty cab or mid-game, day or night, every variation helps — captures with a player standing at the cab are the rarest and most valuable.
If the upload can't go through (a firewall, a proxy, an antivirus that
intercepts HTTPS), the demo says so in red before you capture and keeps the
capture in a folder it names on screen. Send that folder on Discord — it is
worth exactly as much as an upload. headtracking-demo --upload-test answers
in one line whether this machine can reach the server at all.
This project needs a small crew to go from "the hard parts work" to "you can install it and play". If any of this sounds like your kind of fun, jump in — no permission needed, open an issue or say hi on Discord.
- 📸 Send a capture of your pincab (biggest lever, no coding — see
above), or go one
step further and annotate photos: trace 4 lines per photo in a browser
tool (
tools/anchor/). More cabinets = a model that generalizes. - 🦀 Rust / systems — the VPX plugin glue, the calibration decoder, the
filter/POV mapping. Clean
cdylib, no async soup. - 👁️ Computer vision / ML — improve the head + anchor models, the vanishing-point/homography solver, webcam focal recovery.
- 🎛️ VPX & pinball folks — test the plugin on real tables, sanity-check the POV feel, tell us what a good cabinet setup needs.
- 🪟 Windows / macOS testers — it builds everywhere; it has run on Linux. Help us prove the other two.
New to the codebase? CLAUDE.md is a full architecture tour, and the
issues tagged good first issue are a soft landing.
git clone --recurse-submodules https://github.com/Le-Syl21/headtracking
cd headtracking
# Build the plugin (pick your backend)
cargo build --release --features kinect-v2 # or: all-trackers
# Try the trackers + fish-tank parallax window, no VPX needed
cargo run --release -p headtracking-demo --features kinect-v2No user-facing dependencies to install: libfreenect, libfreenect2,
libjpeg-turbo and the ONNX runtime are vendored and statically linked. You need a
recent Rust (2024 edition), cmake, libclang (for bindgen) and libusb-1.0.
Full install / VPX config / per-OS Kinect setup: docs/INSTALL.md.
Drop the built library into VPX's (10.8.1+) plugin folder:
<VPX_install>/plugins/headtracking/
├── plugin.cfg
├── headtracking.dll # Windows
├── libheadtracking.so # Linux
└── libheadtracking.dylib # macOS
Then in a table press F12 → Plugin Settings → Head Tracking → Enable.
Every setting (gain, smoothing, camera…) is tunable live from that page —
full walkthrough in docs/INSTALL.md.
Don't want to build? Besides the
releases, every
commit on main uploads fresh dev builds (plugin + demo, all platforms)
as artifacts on the
Actions tab
— unsigned, GitHub login required.
flowchart TD
subgraph host["VPX host"]
VP[plugin manager] -->|C ABI| DL
end
subgraph plugin["headtracking cdylib (Rust)"]
DL[plugin/ffi.rs] --> TR[tracker thread]
TR --> KV2[Kinect v2 · libfreenect2]
TR --> KV1[Kinect v1 · libfreenect]
TR --> WC[Webcam · SDL3]
TR --> CV[BlazePose + anchor · ort/ONNX]
TR -->|ArcSwap Pose| CAM[camera/mapping to POV]
CAM --> DL
end
The tracker runs on its own thread and publishes the latest pose through an
ArcSwap; the VPX frame callback reads it without blocking. Everything crossing
the FFI boundary is #[repr(C)] and catch_unwind-guarded. Details in
CLAUDE.md.
Bug reports, help, and beta testing happen on Discord — come say hi:
Part of the wider Le-Syl21 Tools community.
GPL-3.0-or-later. See LICENSE.
🇬🇧 English · 🇫🇷 Français
Head tracking POV temps réel pour Visual Pinball X, en Rust pur. Tu bouges la tête, la perspective de la table suit — l'effet fish-tank VR qui donne à un écran plat la profondeur d'un vrai cab. Alternative open-source à BAM, multi-plateforme, qui marche depuis une simple webcam ou une Kinect v1 / v2.
C'est LE goulot du projet, et n'importe quel possesseur de pincab peut le débloquer. Le modèle d'auto-calibration ne connaît pour l'instant qu'un seul cab : le nôtre. Pour apprendre à reconnaître toutes les lockbars et tous les rails — chaque bois, chaque éclairage, chaque angle de caméra — il doit voir de vrais cabs. Le vôtre.
- Téléchargez
headtracking-demodepuis la dernière release — un binaire unique, rien à installer. - Pointez votre webcam ou Kinect vers le plateau, sélectionnez-la dans la démo.
- Cliquez 🎁 Contribute et confirmez.
C'est tout. La démo envoie un relevé (image couleur + ce que le détecteur a vu
- depth/IR si Kinect) vers un dépôt en écriture seule, et ça devient des données d'entraînement.
Ce qui est partagé, honnêtement : les images montrent votre cab et ce qu'il y a autour — vérifiez l'aperçu avant d'accepter. L'envoi ne demande aucun compte et n'embarque aucune identité ; chaque relevé a un identifiant affiché que vous pouvez citer sur Discord pour demander sa suppression. Cab vide ou en pleine partie, jour ou nuit, toute variation aide — les relevés avec un joueur devant le cab sont les plus rares et les plus précieux.
Si l'envoi ne peut pas passer (pare-feu, proxy, antivirus qui intercepte
le HTTPS), la démo le dit en rouge avant la capture et garde le relevé dans
un dossier dont elle affiche le chemin. Envoyez ce dossier sur Discord : il
vaut exactement autant qu'un upload. headtracking-demo --upload-test répond
en une ligne si la machine atteint le serveur.
Ce qui le rend unique :
- Zéro calibration manuelle. Le cab EST la mire : la lockbar + les 2 rails latéraux forment un rectangle connu du plateau. Vu en perspective, ça suffit à retrouver la focale et la pose de la caméra — depuis l'image seule. Pas de mire à damier, pas d'assistant, rien à régler.
- 3D depuis une simple webcam — pas besoin de capteur de profondeur ; la focale récupérée transforme une caméra unique en tracker 3D métrique.
- Zéro install côté utilisateur — un seul binaire plugin, aucun SDK Microsoft, tout est lié statiquement.
- 100 % Rust, Linux · Windows · macOS.
🎥 Quelle caméra ? Une Kinect v2 d'occasion. Tous les backends marchent,
mais le meilleur rapport qualité/prix est une Kinect v2 (Xbox One)
d'occasion — dès ~20 € sur leboncoin / eBay
(recherches pré-filtrées, moins chères d'abord — les annonces pullulent
depuis l'arrêt par Microsoft). Elle tracke sur son flux infrarouge (le
capteur éclaire lui-même la scène : 30 fps plein pot dans un game room
noir) et son capteur de profondeur mesure la distance de tête en vrais
millimètres.
Important
La Kinect v2 dévore la bande passante USB. Elle transfère tout en même temps : couleur 1920×1080 @ 30 fps (JPEG sur le câble), infrarouge 512×424 @ 30 fps et profondeur 512×424 @ 30 fps — ces deux-là en données de phase brutes non compressées — plus le réseau de 4 micros. À elle seule, elle frôle la saturation d'un lien USB 3.0. Donc avant d'accuser la caméra ou l'adaptateur : vérifiez qu'elle est sur un port USB 3.0 racine dédié de la carte mère — pas de hub, pas de port de façade, pas de rallonge douteuse.
Minicab ? La faible distance joueur-caméra change les choix — voir les notes dédiées : 🇫🇷 Notes minicab · 🇬🇧 Minicab notes.
État : début de développement, publié en beta. Ça compile pour Linux,
Windows et macOS, et la chaîne complète — caméra → auto-calibration → POV
live dans VPX — est validée sur le terrain sur un vrai pincab Linux
(Kinect v2, Kinect v1 et webcam, mode Window, réglages live via F12). Les
retours Windows/macOS sont exactement ce qu'on cherche. Voir le tableau
d'état plus haut. En bonus : chaque commit sur main publie des dev builds
fraîches (plugin + démo, toutes plateformes) dans l'onglet
Actions
— non signées, compte GitHub requis.
Caution
Pour que ce projet accède à une Kinect, l'installeur de pilote fourni remplace le pilote Kinect officiel de Microsoft par un pilote WinUSB générique. Ça casse tout ce qui repose sur le SDK Kinect Microsoft — y compris un head tracking BAM fonctionnel — jusqu'à restauration du pilote d'origine (Gestionnaire de périphériques → périphériques « Xbox NUI » → désinstaller notre pilote puis re-scanner, ou réinstaller le SDK/runtime Kinect). Ne lancez l'installeur Kinect que si vous acceptez cet échange. Les utilisateurs webcam ne sont pas concernés.
On cherche des contributeurs — aucune permission requise, ouvre une issue ou passe sur le Discord :
- 📸 Envoyer un relevé de son pincab (le plus utile, sans coder — voir
ci-dessus), ou aller plus loin et annoter des photos : tracer 4 lignes
par photo dans un outil navigateur (
tools/anchor/). Plus de cabs = un modèle qui généralise. C'est la priorité. - 🦀 Rust / systèmes, 👁️ vision / ML, 🎛️ pinball & VPX (tester sur vraies tables), 🪟 testeurs Windows / macOS.
Nouveau ? CLAUDE.md est la visite guidée complète de l'architecture.
Support & beta-test sur Discord :