Inspiration
CueSpot started with a video I wanted to record for myself. I had written a short script, maybe sixty seconds of talking, and I figured recording it would be the easy part. It wasn't. I either had to learn the whole thing by heart, which took longer than writing it, or I put the script on my laptop next to the phone and kept glancing over to read it. In every take you could see my eyes drift away from the lens. After far too many attempts I had a video I didn't like and an evening I wasn't getting back.
Then I noticed something about the phone I was filming with: the front camera sits inside the Dynamic Island, which means there is a spot on the screen physically adjacent to the lens. If the script lived exactly there, reading and eye contact would stop being a trade-off. But I didn't want some floating overlay bolted on top of iOS. The solution had to feel like it belonged to the device, respecting Apple's design language instead of fighting it. So CueSpot grows the teleprompter out of the sensor housing itself, concentric with the display corners, the way a Live Activity expands. It looks like something the system might do, and that was the point.
What it does
CueSpot is a teleprompter that records you while your script scrolls in a panel anchored around the Dynamic Island, directly under the lens.
- Write or import a script (typing, paste, .txt/.md files, or a share extension), then tune speed, text size, width, color, and panel opacity against a live preview that uses the exact same rendering as the real prompter.
- Record with a countdown and a configurable lead-in delay, so takes never start mid-thought. The script is an on-screen overlay and never appears in the recorded video.
- Control it without touching the screen: volume-down taps play or pause the text, holding volume-down temporarily speeds it up (it springs back on release), and volume-up jumps back a line. Everything also works on-screen, and the camera behaves like the system Camera app: tap to focus, drag the sun for exposure, pinch to zoom.
- Stay private: no account, no login, scripts stay on device, recordings go only to your own Photos library. Analytics and crash reporting are strictly opt-in, EU-hosted, and anonymous. The App Privacy label is 100 % "Data not linked to you."
Monetization runs on RevenueCat: every install gets 3 free days with everything unlocked, then a paywall offers a weekly subscription or a lifetime unlock.
How we built it
Native SwiftUI on iOS 26, Swift 6 with strict concurrency, SwiftData for persistence, and a hand-built AVFoundation capture pipeline (recording, resolution switching, focus, exposure, zoom, interruption recovery), all driven through a single serial session queue so the main thread never touches the camera.
The prompter geometry is the interesting part. There is no public API for the Dynamic Island's position, so CueSpot ships a per-device calibration table (cutout size, display corner radius, concentric insets) with a measured fallback for notched phones. Same story for the hardware buttons: the coach-mark arrows that point at the physical volume buttons use bezel measurements per device family, because iOS has no notion of off-screen hardware coordinates.
RevenueCat handles the entire purchase layer through Purchases,
customerInfoStream, and the RevenueCatUI paywall and Customer Center. The
3-day trial is deliberately local: keychain-backed so it survives
delete-and-reinstall, with a clock-rollback defense that stamps every launch.
And because judges read this: there is exactly one import StoreKit in the
app, and it exists for the system review prompt.
Crash reporting (Sentry, EU) and product analytics (PostHog, EU) are consent-gated and data-minimal by construction. The analytics event set is a closed enum where every property is a count, an enum case, or a bucket.
Challenges we ran into
- The opacity slider that froze the app. CueSpot fades the live camera in
behind the editor while you drag the panel's opacity, so you can judge the
value against a real room. Mounting the camera preview while the session was
still spinning up made the preview layer's attach block the main thread
behind
startRunning()'s internal lock. The fix: keep the preview permanently mounted and attach the layer exactly once while the session is idle. - Per-frame string processing. The prompter recomputed its paragraph and word tables on every display-link tick. Invisible with short scripts, jank with long ones. Now cached and invalidated only when the text changes.
- App Store validation vs. static frameworks. Sentry's static xcframework left a stub binary in the bundle that failed signing validation. Switching to the dynamic variant, which Xcode embeds and signs itself, fixed the upload.
- Fighting AVFoundation and losing. Hand-picking capture formats, color spaces, and codecs consistently measured worse than letting the system choose. The final pipeline sets a session preset and mirroring, and nothing else.
Accomplishments that we're proud of
- The core illusion works: people look at their videos and see themselves making eye contact while reading every word.
- A guided first run that ends with a real recorded take in Photos within about two minutes of install. An arrow points to a pre-written demo script, a short tour explains the editor, coach marks explain the viewfinder, done.
- 97 unit tests, a share extension, full English and German localization, and a privacy posture (opt-in EU diagnostics, all-anonymous label) that survived an honest audit rather than a hopeful one.
- Shipping all of it solo, from capture pipeline to paywall to legal pages.
What we learned
- Physical geometry is a feature. The best UI decision in the app wasn't drawn, it was measured with a screen ruler against the sensor housing.
- On iOS, the main thread and
AVCaptureSessionmust never share a lock. Every stability bug worth telling a story about came down to that rule. - Trust is a product surface. Making analytics consent exactly as easy to refuse as to accept, and keeping the app account-free, shaped the architecture more than any framework choice.
- Doing purchases through RevenueCat instead of raw StoreKit meant the entire
monetization layer (trial gate, paywall, restore, customer center) stayed a
thin, testable shell around one
hasFullAccessflag.
What's next for CueSpot
- Launch and iterate during the Shipaton window, then measure conversion and retention, improve the App Store listing, and build a repeatable creator-focused growth loop.
- Growth: localized App Store metadata, ASO experiments, short-form product demos, and a Product Hunt launch.
- Product: Camera Control support on newer iPhones, more languages beyond English and German, and smarter pacing. The prompter already knows your words per minute; next it should listen and follow you.
Built With
- claude
- posthog
- revenuecat
- sentry
- swift
Log in or sign up for Devpost to join the conversation.