design: device-first onboarding + soft trial paywall prototype (Graphite / Aurora)
What changed and why
A clickable design prototype (not production code) of a device-first first-run flow, in two visual directions, for Nik to review. Proposed with Reid Moncada.
- Pairing gates onboarding. Right after sign-in we ask "Do you have your Omi?". Yes → find → pair → the existing steps (name, language, permissions, voice intro). It's on the way / I don't have one → buy the pendant ($129, was $179) → order summary → a waiting room whose only way forward is pairing; a delivery push deep-links back into pairing.
- Soft paywall at the end of onboarding, where intent peaks: Free vs Unlimited, a trial timeline, Yearly preselected, and "Continue with Free" always visible.
- Trial-length test: the same paywall at 3 / 7 / 14 / 30 days (
TrialLengthinlib/src/content.dart); headline, button, caption and reminder day follow the length. - Two directions: Graphite (black, white, SF-style) and Aurora (black with a violet→amber "listening" glow, pill buttons). Every visual reads from one token class (
DfTheme), so mapping a direction ontoOmiColors/OmiTypelater is mechanical.
It lives in prototypes/device_first_onboarding/ as a standalone Flutter package that depends only on Flutter. It does not touch app/, so it can't affect the shipping app. The app/lib UX contract and ARB localisation rules don't apply until a direction moves into the app; the README describes that path. Opened as a draft for direction/feedback, not to merge as is.
Figma: "Omi — Paywall Redesign", pages E · Device-first · Graphite and F · Device-first · Aurora.
Product invariants affected
none
How it was verified
Flutter can't be installed in my sandbox, so I ran checks on GitHub Actions in my fork (Flutter 3.44.5, matching mobile-app-checks.yml), on a fork-only branch whose sole workflow is the check below:
cd prototypes/device_first_onboarding
flutter pub get
dart format --line-length 120 lib test # no changes
flutter analyze # No issues found
flutter test --exclude-tags screenshots # 90 tests, all passed
flutter test --tags screenshots --update-goldens # rendered all 40 screens with Roboto
I reviewed the rendered screens (below) for both directions. Not verified: running on a physical device. To try it: flutter create --platforms=ios,android,web . && flutter run inside the folder; the launcher picks direction and trial length.
Tests
test/flow_test.dart:
- every screen in both directions at 390×844 and 375×667 with no layout overflow (80 cases)
- the has-an-Omi path from Welcome through pairing and onboarding to a started trial
- the no-Omi path (buy → checkout → waiting room → pairing) and the on-the-way path (waiting room → delivery push → pairing)
- each trial arm's copy and "Continue with Free"
- choosing Monthly
- "See my plan" stays disabled until setup completes
- the launcher
test/screenshots_test.dart (tag screenshots) renders review images only.
UI evidence
UI-Evidence: none -- standalone prototype outside app/; screens rendered by flutter test in CI and shown below.
Graphite

Aurora

Open questions for review
- Is requiring a paired device before the rest of onboarding the right call, versus letting phone-mic users through?
- Monthly Unlimited price (shown as $29.99), shipping price and delivery window, and whether Plus belongs on this paywall.
- Trial plumbing: Stripe
trial_period_daystoday, or App Store / Play intro offers.
Failure-Class: none
🤖 Generated with Claude Code