English · 中文
A walking companion for Meta Ray-Ban Display, in a fighter-jet cockpit HUD.
A web app rendered on the glasses' right-eye display: steps, distance, pace, heading, and GPS trace, laid out through fighter-HUD visual conventions. The Web Apps API only exposes IMU + GPS — no real 6DoF — so this app squeezes every useful signal out of those two channels and puts it on one frame.
Composite for illustration — the cyan HUD is rendered into a real outdoor photo. The actual on-glasses view looks similar: a 600 × 600 panel floats in the centre of your field of view while the world stays visible around it.
Scan this QR with your Meta Ray-Ban Display's camera — the Meta AI app recognizes it as a web-app deep link and opens the app directly:
Or open walk-app-six.vercel.app in any browser — heading tape, step counter, and GPS path can all be simulated through Chrome F12 → Sensors.
The app defaults to English. Tap the small 中 button in the bottom-right of the READY screen to switch to Chinese (the choice persists).
- 🧭 Compass-style heading tape — driven live by
DeviceOrientationEvent.alpha; N / E / S / W scroll under the centre marker as the head turns - 👟 Head-mounted IMU step counter — peak detection on
devicemotion, default threshold 11.4 m/s², 280 ms debounce - 🛰️ GPS distance + path —
navigator.geolocation.watchPosition+ Haversine, with noise filtering (accuracy < 30 m, distance > 3 m, dt > 1 s) - 🗺️ North-up minimap — last ~500 GPS fixes, auto-fit bbox, amber heading cone
- 🎯 RECENTER button — zeros displayed angles to the current pose; auto-recenter also fires on the first orientation event after START
- 💾 Survives mid-walk reload — every state transition writes
localStorage, plus a 5-second checkpoint - 📐 Self-calibrating stride length — after 50 steps,
stepLengthis recomputed from GPS distance ÷ step count - ⏯️ D-pad first — PAUSE / RESUME / END / NEW WALK all reachable through arrows + OK alone
- 🌐 English + 中文 — English default, one-tap toggle, persisted
| READY | ACTIVE |
|---|---|
![]() |
![]() |
- Fighter-HUD layout: data in the four corners, centre kept clear, heading tape across the top — minimize what blocks the real world behind the lens
- Single-hue cyan + amber: the glasses' display has a tight brightness budget; one strong primary, no decorative gradients
- Zero animation, zero transition: walking + animation = distraction
- Per-tick zero allocation: 5 Hz data loop +
requestAnimationFramemotion loop, so head rotation is tracked smoothly - Three-screen state machine: READY / ACTIVE / SUMMARY — no modals, no nested navigation
- Plain HTML + CSS + vanilla JS — no build step, no framework, zero npm dependencies
DeviceMotionEvent/DeviceOrientationEventfor the IMUnavigator.geolocation.watchPositionfor GPS- Canvas 2D for the minimap
localStoragefor persistence- Vercel static deploy
git clone https://github.com/jscmp4/walkpit.git
cd walkpit
node server.js
# → http://localhost:3000No npm install needed — server.js only uses Node's built-in http module.
Open Chrome F12 → Sensors panel:
- Custom Orientation — drag the sliders to watch the heading tape react
- Location — set a position, then nudge lat/lon a few times to draw a path on the minimap
Or open http://localhost:3000/cockpit-dev.html — drag the virtual head in the left panel to simulate orientation, and click MARCH on the right to simulate step IMU pulses without DevTools sensors.
vercel --yes --prodvercel.json explicitly turns Node runtime off — this is a pure static project, and we don't want Vercel auto-detecting server.js as a serverless function.
- Deploy to any HTTPS static host (Vercel / Netlify / Cloudflare Pages all work)
- In the Meta AI mobile app, add the web app via link or QR code
- Put the glasses on, open it
walkpit/
├── index.html # Three screens: READY / ACTIVE / SUMMARY
├── styles.css # Cockpit theme (cyan + amber + dim), all --hud-* variables
├── app.js # State machine, step detector, GPS, HUD renderers, persistence (~750 LOC)
├── server.js # Local static dev server (Node stdlib only)
├── vercel.json # Explicitly disables Node auto-detection
├── package.json # `start` script only, no dependencies
├── .vercelignore # Keeps dev-only files out of the deploy
├── cockpit-dev.html # Local debug harness: D-pad + MARCH + Three.js 3D head
├── CHANGELOG.md # Reverse-chronological changelog
├── DEV_NOTES.md # Developer cheatsheet (debug flags, sign conventions, file map)
└── docs/
├── screenshot-ready.png
├── screenshot-active.jpg
└── _active-shot.html # Screenshot bootstrap (prefills localStorage + fake events)
startWalk pauseWalk
READY ────────────► ACTIVE ─────────► PAUSED
▲ │
└─── resumeWalk ───┘
│ │
└── endWalk ──┐ ┌── endWalk
▼ ▼
SUMMARY ──── newWalk ──→ READY
Every transition syncs to localStorage['current_walk'], plus a 5-second checkpoint. After a mid-walk reload (or a glasses restart), the app restores into ACTIVE or PAUSED automatically.
| Field | Source | Stored in |
|---|---|---|
| Steps | DeviceMotionEvent peak detection (threshold 11.4, debounce 280 ms) |
session.steps |
| PDR distance | steps × stepLength; after 50 steps GPS auto-calibrates stepLength |
session.pdrDistance |
| GPS distance | watchPosition + Haversine (acc < 30 m, d > 3 m, dt > 1 s) |
session.gpsDistance |
| GPS path | watchPosition fixes, capped at 500 points | session.gpsPath |
| Heading | DeviceOrientationEvent.alpha |
hudOrient.alpha (not persisted) |
| Pose ref | First orientation event on ACTIVE / manual RECENTER | session.alphaRef (persisted) |
Set in DevTools Console on a desktop browser (the glasses don't expose one easily):
localStorage.show_debug = '1' // show mag / peak / gps_pdr / αR / αA
localStorage.step_threshold = '11.4' // step-detector sensitivity (default 11.4)
localStorage.lang = 'zh' // force Chinese UI
localStorage.removeItem('current_walk') // wipe the persisted mid-walk sessionαR is alpha from the relative deviceorientation event; αA is alpha from deviceorientationabsolute — used to probe whether the glasses expose absolute (magnetometer-referenced) heading. Many browsers only deliver the relative form.
- Not real 6DoF: the Meta Web Apps API only delivers IMU + GPS — no visual SLAM. This is a pose-aligned instrument panel, not a world-locked AR overlay.
alphais not necessarily true north: in many browsersdeviceorientationreports alpha relative to whatever direction the page loaded in. To compensate, the app auto-recenters to the user's current pose when entering ACTIVE. Binding to true north would requiredeviceorientationabsolute(still being probed on the glasses — see theαAdebug row).- GPS heading is noisy at low speeds: under ~1.5 m/s, the GPS bearing jitters. IMU heading is preferred while moving slowly.
- No on-glasses console: changing a debug flag means re-deploy.
MIT


