A working SwiftUI prototype of four shipping-ready iOS features for Parrot (YC F25): a hands-free audio review mode, an on-device pronunciation drill, a Home Screen widget, and a Lock Screen Live Activity.
Built unsolicited as a tangible answer to the open Founding Mobile Engineer posting. Each feature is wired against a real gap I found in App Store reviews or the public product surface — not invented from scratch.
The current Parrot daily loop is screen-bound: morning video, lunch repeat-aloud, evening review. The features below extend the loop to commute time, lock screen, and home screen — surfaces where engagement compounds streaks without asking for more thumb-time.
| Feature | Gap it closes | Evidence |
|---|---|---|
| Hands-free audio review | No way to practice while walking / driving / dishes — biggest unmet use case for a comprehensible-input app once vocab exists | Pimsleur owns this segment; Duolingo doesn't. Parrot's video format precludes it today. |
| On-device pronunciation drill | "Parrot-back" today is honor-system. No objective signal whether a learner is matching the target. | App Store review patterns; Krashen's i+1 needs output feedback to advance. |
| Home Screen widget (3 sizes + Lock Screen accessory) | No widget today. Daily-streak apps lose retention without a passive surface. | App Store review "Widget for iPhone home screen" by Zoievande18 (May 4) — explicit request. |
| Live Activity + Dynamic Island | Streak/next-review state is invisible until you open the app. | Same Zoievande18 request implicitly + general iOS 16+ user expectation. |
ParrotCompanion/
├── ParrotCompanion/ # Main app target
│ ├── ParrotCompanionApp.swift
│ ├── Models/
│ │ ├── Phrase.swift # Codable phrase + demo seed
│ │ └── PhraseStore.swift # Leitner SRS, App Group-backed
│ ├── Audio/
│ │ ├── AudioReviewEngine.swift # AVSpeechSynthesizer + MPNowPlayingInfo
│ │ └── PronunciationScorer.swift # SFSpeechRecognizer + Levenshtein scoring
│ └── Views/
│ ├── ContentView.swift
│ ├── ReviewSessionView.swift # Audio player UI
│ └── PronunciationDrillView.swift
├── ParrotWidget/ # WidgetKit + Live Activity extension
│ └── ParrotWidget.swift # Widget + ActivityConfiguration + DynamicIsland
└── ParrotLiveActivity/ # Shared between app + extension
└── StreakAttributes.swift
AVSpeechSynthesizerwithes-MXanden-USvoices, rate tuned 0.92x defaultAVAudioSessionconfigured for.playback/.spokenAudiowith.duckOthers— keeps speaking through screen lock, ducks Spotify- Now Playing center wired so the lock screen / CarPlay shows current phrase as track title, English meaning as artist, "Parrot Review — 4/12" as album
- Remote command center handles play / pause / next from AirPods stem + CarPlay buttons
- Phrase loop: Spanish → 1.2s gap → English → Spanish repeat → record SRS pass → next
SFSpeechRecognizer(locale: es-MX)withrequiresOnDeviceRecognitionopt-in when supported- Live partial transcripts during listening
- Blended score: 55% Levenshtein on normalized strings + 45% word-overlap (diacritic-insensitive, punctuation-stripped). Survives the common "¿" / accent-mark drops
- 0-100 score gates the SRS box decision (≥70 → promote; <70 → demote)
Swap point: if you want phoneme-level prosody scoring, the similarity(_:target:) static is the only place to replace — Azure Cognitive Services / Whisper-based scoring drops in cleanly.
- Five families:
systemSmall,systemMedium,systemLarge,accessoryRectangular,accessoryInline - Reads shared
PhraseStorevia App Group; refreshes every 30 min - Each size shows: today's Spanish phrase, English meaning, current streak, minutes-until-next-review
- Tap-through deeplinks into the app (the
widgetURLis left as an integration point — wire to your existing universal link router)
- Lock Screen: 🦜 + next phrase + streak + countdown
- Dynamic Island compact: parrot + streak day count
- Dynamic Island expanded: phrase, streak, minutes-to-next
- Stale-date 2h; refresh on session completion
These are the seams to swap from the demo's in-memory data to real Parrot data:
PhraseStore— replaceseedIfEmpty()andphrasesgetter with a fetch from Parrot's user vocab endpoint. Keep the App Group write-through so the widget/Live Activity stay accurate.PhraseStore.record(_:recalled:)— currently writes to UserDefaults. Replace body with a POST to your SRS endpoint; keep the local optimistic write for offline.AudioReviewEngine.say(_:lang:)— usesAVSpeechSynthesizerso it's $0 and runs offline. If you want native-speaker audio that matches your videos, replace the utterance creation with a clip lookup againstphrase.videoClipIDand play extracted audio viaAVAudioPlayer. The Now-Playing wiring stays.ParrotWidget.getTimeline— uses 30-min refresh. Once you wire a server-side push of "due now" counts via background refresh, you can move to.neverpolicy and refresh on push.- Streak source of truth — currently local. Swap
markPracticedToday()to call your server.
- App Groups —
group.com.parrotapp.companionenabled on both main app + widget extension target - Background Modes — Audio (for hands-free playback)
- Push Notifications — only if you want server-pushed Live Activity updates later
- Info.plist keys on main app:
NSMicrophoneUsageDescription— "We listen so you can hear how close your pronunciation is."NSSpeechRecognitionUsageDescription— "Speech recognition runs on-device to score your pronunciation."
See docs/PROJECT_SETUP.md for the 5-minute Xcode wire-up.
A few things I'd want to instrument before claiming any of this lifted retention:
- Streak D7 delta for users who add the widget vs. matched users who don't (Mixpanel cohort)
- Session count per user/day: audio mode is additive — we'd want to see total daily sessions ↑, not video sessions ↓ (cannibalization risk)
- Pronunciation score → next-day return correlation — if drill users return more often, that's the active-recall flywheel Krashen's framework predicts but Parrot doesn't measure today
- A/B: replace AVSpeechSynthesizer voice with a real native-speaker clip cut from the existing video library — does same-voice consistency improve adherence?
- Apple Watch companion —
WKInterfaceControllerto skip/replay during runs; Watch already has the AirPods stem so the value is "see the phrase + heart-rate context" - Spotify-style "Daily Spanish" auto-generated podcast — concatenate the day's phrases into a sharable audio file with chapters; ties into the YC "TikTok for X" angle by making Parrot shareable on Discord/iMessage as audio clips
- iMessage extension — send-a-phrase as a shareable sticker pack to friends learning together
- Voice-cloned native-speaker variants — same phrase rotated through a few cloned voices (varied accents) to prevent vocabulary boredom (#3 review complaint: "same phrases over and over")
Built by Sushanth Tiruvaipati. Reach me at t.sushanth@gmail.com.
