Files
mirror-os-flutter/CLAUDE.md
T
2026-07-11 21:51:34 -05:00

99 lines
3.0 KiB
Markdown

# Mirror OS
Smart mirror app platform built with Flutter for a hacked Lululemon Mirror (BOE panel + Vizio driver board + Raspberry Pi 4).
## Architecture
Melos mono-repo with two apps sharing packages:
- `apps/display` — Flutter Linux desktop app, runs fullscreen on Pi 4 (1080x1920 portrait)
- `apps/remote` — Flutter mobile app (iOS/Android), phone remote control
- `packages/mirror_protocol` — WebSocket message types and serialization
- `packages/mirror_core` — Shared business logic, API clients (workout-player, YouTube)
- `packages/mirror_ui` — Dark theme, shared widgets, animations
- `services/` — Python sidecars for voice (OpenWakeWord + Whisper) and motion (PIR/GPIO)
- `deploy/` — Pi setup scripts, systemd units, labwc compositor config
## Prerequisites
- Flutter SDK 3.24+ (stable channel)
- Dart SDK 3.5+
- Melos: `dart pub global activate melos`
## Setup
```bash
melos bootstrap
```
## Development
```bash
# Run display app (macOS/Linux desktop for development)
cd apps/display && flutter run -d macos
# Run remote app on iOS simulator
cd apps/remote && flutter run
# Run both and test WebSocket communication:
# 1. Start display app (starts WS server on :9090)
# 2. Start remote app, connect to localhost:9090
# Analyze all packages
melos run analyze
# Format all packages
melos run format
```
## Hardware
- **Panel**: BOE DV430FHM-NN5, 43" 1080p IPS, portrait orientation (1080x1920)
- **Driver board**: Vizio mainboard (HDMI passthrough → LVDS → panel)
- **Compute**: Raspberry Pi 4 (4GB)
- **Control**: Phone over same WiFi network
- **Rotation**: Pi handles via `wlr-randr --output HDMI-A-1 --transform 90`
## Communication
Display app runs a WebSocket server on port 9090. Phone remote connects as a client.
Protocol: JSON messages, typed via sealed Dart classes in `mirror_protocol` package.
- Server → Client: `StateSync` (full state on connect), `StatePatch` (deltas)
- Client → Server: `NavigateCommand`, `PlaybackCommand`, `WorkoutCommand`
## External Services
- **Workout Player**: http://192.168.86.172:8091 — REST API for video library, streaming, progress
- **OpenWeather**: API key needed for dashboard weather widget
- **Google Calendar**: OAuth for dashboard calendar widget
- **Plex**: Local server on same LAN
## Build for Pi 4
```bash
# On the Pi (with Flutter installed):
cd apps/display
flutter build linux --release
# Output: build/linux/arm64/release/bundle/
# Deploy: rsync bundle to /opt/mirror-os/display/ on the Pi
```
## Testing
```bash
# Unit tests
melos exec -- dart test
# Integration: start display app, connect remote, verify state sync
```
## Key Design Decisions
- Riverpod for state management (no code generation needed for basic use)
- Single `DisplayState` as source of truth on the Pi, broadcast to all remotes
- media_kit (mpv) for media playback with V4L2 hardware decoding
- Python sidecars for voice/motion (communicate via Unix domain sockets)
- No touch input on mirror — all interaction via phone remote