Precision wheel alignment measurement in the browser using phone sensors.
Phase 1 is implemented: web app + internal phone sensor (deviceorientation).
- ✅ Measure camber, toe, and caster
- ✅ Rear-wheel baseline workflow (no separate calibration page)
- ✅ Stability detection with progress feedback
- ✅ iOS motion-permission request flow
- ✅ Results table + JSON export
- 🚧 BLE/USB external sensors are planned for Phase 2 (UI placeholders exist)
- React 18 + TypeScript + Vite
- Zustand (global alignment store)
- TailwindCSS
- React Router
- Vitest (unit tests)
src/
components/ # UI building blocks (live display, diagrams, toasts)
hooks/ # Sensor and toast hooks
pages/ # Home, Setup, Measure, Results
store/ # Zustand alignment store
types/ # Shared TypeScript types
utils/ # Math, filters, constants, storage
__tests__/ # Vitest unit tests
- Node.js 18+
- Modern browser with Device Orientation support
- HTTPS or localhost (required for sensor APIs)
npm installnpm run devnpm run build
npm run previewnpm run dev— start development servernpm run build— type-check + production buildnpm run preview— preview production buildnpm run lint— run ESLintnpm run format— run Prettier onsrc/**/*.{ts,tsx,css,md}npm run type-check— TypeScript no-emit checknpm run test— run unit tests oncenpm run test:watch— run tests in watch modenpm run test:coverage— run tests with coverage
- Choose Internal Phone Sensor in Setup
- Measure rear wheel(s) first to establish camber and toe baselines
- For each wheel:
- Vertical phone position for camber
- Horizontal phone position for toe
- For front wheels, capture caster via left/right steering sweep
- Review results and export JSON
All wheel angles are normalized to the rear baseline to reduce floor-slope bias.
- Vertical (Camber): phone upright against wheel, charging port down
- Horizontal (Toe): phone flat, screen up, back facing ground
- App enforces guard checks and waits for stable readings before recording
- iOS requires explicit motion permission (
DeviceOrientationEvent.requestPermission()) - Heading quality can vary by browser/device; toe is computed relatively to baseline
- Avoid strong magnetic interference and long pauses between baseline and front toe reads