A posture-driven, zero-UI spatial compass. Set an anchor for home or your car, text a link into a group chat, and everyone who joins sees each other on the same dial — built for places like a crowded concert where the point-and-walk matters more than a map.
Built with Flutter, Material 3, and iOS-26 liquid-glass surfaces. iOS + Android.
The whole app is one continuous canvas that morphs by how you hold the phone (the "posture", derived live from the accelerometer):
| Posture | Pitch | What you see |
|---|---|---|
| Flat | 0–30° | True-OLED-black dial. Markers ride a hairline rim at their real-world bearing; the blank center shows distance to the nearest one. Double-tap center to drop an anchor. |
| Tilt → AR | 30–60° | The dial cross-fades into a live camera window as you raise the phone. |
| AR | 60–90° | Camera passthrough; markers become glowing eye-level orbs (people) or sky-beams (anchors) with billboard distance tags. |
| screen-off guide | The haptic engine is the interface — a 60→140 BPM heartbeat means on-course and closing in; a single cold click means wrong way. |
- Social — a friend in a shared session (neon cyan / magenta / lime dot + initials).
- Anchor — a personal waypoint you drop (pure-white dot; 🏠 home, 🚗 car…). Persisted on-device, fully offline.
- Lagging — derived: when a friend falls beyond 1.5× the group's median spread, their dot turns red and pins to 6 o'clock with a distance chip and an alert banner.
The compass, the distance/bearing math, and your anchors are 100% on-device and offline — GPS tells your phone where it is, and that's all the solo experience needs.
But "everyone sees each other" is different: for your phone to draw a friend's dot, their coordinates have to physically travel to you. GPS can't do that — it only ever reports your own position. So the sharing half needs some transport. The good news is a coordinate is ~16 bytes, so even a congested concert network carries it fine; this isn't a bandwidth problem.
That transport is fully implemented using a custom Node.js Socket.io backend. Most importantly, it features military-grade End-to-End Encryption (E2EE).
When a session is created, the Host generates a 256-bit AES GroupKey. When Guests join, they perform an Elliptic-Curve Diffie-Hellman (X25519) handshake to securely receive the GroupKey.
Every location update (lat, lng) is encrypted using AES-GCM before leaving the device.
The backend routing server cannot read your location data, making this safe for open-source self-hosting and deployment on untrusted servers.
This repository comes fully equipped for open-source contribution and deployment:
- CI/CD Built-In: GitHub Actions automatically run
flutter analyzeandflutter teston every PR. - Automated Releases: Pushing a new version tag automatically compiles the Android APK and creates a GitHub Release.
lib/
models/ geo math (haversine/bearing), markers, postures, sessions
services/ location · heading · motion · haptics · anchors(persist)
session_service(⇐ the transport seam) · deep_links
state/ compass_controller — fuses every stream into ResolvedMarkers
theme/ Material 3 dark theme + liquid-glass surfaces
ui/ root_shell (posture morph) · dial · ar · pocket · sheets
- State: a single
CompassController(ChangeNotifier+provider) is the only thing the UI reads. It fuses location + heading + motion, owns anchors and the active session, and resolves everything toResolvedMarkers for the painters. - Sensors:
geolocator(position),flutter_compass(heading),sensors_plus(pitch → posture),vibration(haptic patterns). - Deep links:
app_linkshandlescompass://ping?token=…(1-to-1 "find me") andcompass://join?session=…(group), registered on both platforms.
The signaling server requires Node.js.
cd backend
npm install
npm startThe server runs on port 8080 by default.
flutter pub get
# Inject your backend URL at compile time
flutter run --dart-define=COMPASS_API_URL=http://localhost:8080
flutter test # geo + posture unit tests
flutter analyzeDeep-link test:
adb shell am start -a android.intent.action.VIEW -d "compass://join?session=DEMO42"(Android)xcrun simctl openurl booted "compass://ping?token=xyz&name=AK"(iOS sim)