All projectsJuly 2026· Deployed to GitHub Pages
Presence Scan
A live mmWave radar turns a real person walking my garage into an avatar inside its 3D scan.
- PlayCanvas
- WebGL
- mmWave Radar
- Noise Filtering
- ESP32
- WebSocket
- Gaussian Splatting
This is the deployed answer to the question of what happens when a Gaussian-splat scan and a live radar feed actually get wired together. The clip above is a walkthrough — the live build is linked above if you want to drive it yourself.
Under the hood it's a 3D Gaussian-splat scan of my garage, rendered directly on PlayCanvas (no editor, no app framework — just the engine). A custom-firmware HLK/LD2450 mmWave radar on an ESP32 parses raw sensor frames and serves them over its own WebSocket — no bridge, no ESPHome — one packet per person per tick, in millimetres:
{"targets":[{"x":-820,"y":1740,"speed":-12}]}
The viewer connects straight to that socket, maps sensor space onto splat space through an origin/rotation/scale calibration, and eases an avatar toward wherever you're actually standing in the room. Up to three people track as three independent avatars.
Demo mode
With no one in the room, an avatar walks the garage on its own. It reads the walls and furniture straight out of the scan — a floor grid built from the splats themselves, so obstacles match what you actually see — then plans a path around them with A* and rounds the corners so it moves in smooth curves instead of walking through objects.
Calibrating a real radar to a real room
The trickiest part wasn't the rendering, it was getting sensor-space and splat-space to agree. The settings panel has a dedicated alignment mode: a floor radar overlay with range rings, a live marker on both the texture and the 3D scene, and keyboard controls to pan/rotate/scale the sensor mount until the dot tracks your actual feet. Once it's set, it saves to the session and persists across reloads.
Lint, typecheck, and tests gate the GitHub Pages deploy in CI, so what's embedded above is exactly what shipped.