Voyage is a free, open-source iPhone study timer that turns a focus session into a flight. You pick a route, and its real flight time becomes your session. You check your tasks as bags, tear the boarding pass to begin, and study while the plane flies. For Shipaton, Voyage gained an airline loyalty program built on the psychology of habit and goals, and Voyage First, a subscription through RevenueCat that sells comfort, never progress. This entry runs on RevenueCat's Test Store, so no money moved.
Inspiration
Starting to study is the hard part, and quitting halfway is the easy part. Airlines have spent decades getting people to come back: status tiers, miles that pile up, a seat up front you can almost reach. I wanted that pull aimed at studying, with the rules pointed the other way. Nobody can buy their way to status, and nothing you need to study is ever behind a paywall.
What it does
- A session is a flight. Pick a destination on the globe; the route's real flight time is your focus time. Leave the app for more than 30 seconds and the flight diverts.
- An if-then plan. Scheduling a departure writes one line, when and where you'll board ("When it's 7:00 PM at the library, I'll board…"). The pass and the boarding call read it back.
- One bag tag per task. Each thing you plan to do prints as its own tag with a three-letter code. Peel the claim check to check them, tear the pass to board.
- Baggage claim. After landing, you tear the stub on each bag you finished. Unclaimed bags are "mishandled": they come back first on your next flight.
- Customs. "Anything to declare?" asks three quick recall questions, no notes. One tap skips it.
- Voyage Miles. Every flight earns miles toward Silver, Gold and Platinum. You start with a 500-mile welcome bonus (every threshold was raised by the same 500, so nobody's real effort changes). The miles still needed show up as a real trip, such as "SFO–SEA 7 times". A tier-up carries your surplus miles into the next bar. Your status lives in the Logbook, so Home stays just the globe.
- Status unlocks perks, free. Silver opens the First Class cabin, Gold unlocks priority bag tags, Platinum unlocks the airline liveries. Fly enough and you get everything without paying.
- The Flight Manual. An in-app page with the research behind each mechanic, cited and linked, plus how Voyage First is sold.
The psychology (cited in the app)
| Mechanic | Finding |
|---|---|
| If-then plan, one tag per task | Implementation intentions had a medium-to-large effect (d = .65) across 94 tests. Gollwitzer & Sheeran, 2006, Advances in Experimental Social Psychology |
| 500-mile welcome bonus | A loyalty card with two stamps already on it gets finished more often than a shorter blank one. Nunes & Drèze, 2006, Journal of Consumer Research |
| Miles to Silver as a real route; surplus carried over after a tier | People speed up as the goal gets closer, and slow down right after a reward. Kivetz, Urminsky & Zheng, 2006, Journal of Marketing Research |
| Customs recall | Recalling without notes beat rereading when students were tested two days and a week later. Roediger & Karpicke, 2006, Psychological Science |
| Tearing the pass | A ritual before a hard task lowered anxiety and improved performance. Brooks et al., 2016, OBHDP |
| Picking the route length | Self-set deadlines helped students. Ariely & Wertenbroch, 2002, Psychological Science |
| What we won't do | Paying people for something they already enjoy can make them enjoy it less, so miles are a record, not a wage. Deci, Koestner & Ryan, 1999, Psychological Bulletin |
How Voyage uses RevenueCat
Status is earned; comfort is for sale. Voyage First is one entitlement, voyage_first, sold as two products in the default offering: voyage_first_annual ($19.99/year with a 7-day free trial, preselected) and voyage_first_monthly ($2.99/month). The prices sit deliberately below RevenueCat's own Education and Productivity medians, because the buyers are students. It opens early what status earns for free: the First Class cabin (free at Silver), priority tags (free at Gold) and the six fictional carriers' livery tags (free at Platinum). It never buys miles, tiers, routes or anything you need to study, and nothing in the app is only for sale.
- The paywall appears at the moment of want, next to the free path. The front cabin opens at Silver. Tap a First seat before you've earned it and an upgrade sheet offers both ways there: Earn it, with your real miles to go and a real route, or Fly Voyage First. Only the second opens the paywall.
- RevenueCat's own paywall, designed in RevenueCat's paywall editor and shown with RevenueCatUI's
PaywallView, so the pitch changes with a dashboard publish, not an App Store release. It says, in its own footer, "Studying stays free. Status can't be bought." - Never mid-flight.
FirstClassPaywallGateallows the paywall at home, at booking and after landing, and never during a flight, a layover or a diversion (unit-tested). Mid-flight is the moment Voyage exists to protect. - State, not a boolean. Membership is
unknown,economyorfirstClass, driven bycustomerInfoStream. A failed refresh never demotes a member, andunknownnever locks anything the free app already does. - Customer Center for managing or cancelling, right in Settings, and a real trial reminder: when a trial starts, Voyage schedules a notification two days before it ends.
- Open-source safe. With no key the SDK stays unconfigured and the membership UI hides, so anyone can clone and run Voyage. Debug carries the public Test Store key; a pre-build script refuses any Release build with a
test_key. - Proven on CI. A UI test on a CI simulator taps a locked First seat, opens the paywall, completes a Test Store purchase, watches the seat unlock and checks that Settings reads "Voyage First · Active". That run is the footage in the video.
What building on RevenueCat taught us (feedback)
- The setup wizard derives the entitlement identifier and never shows it. Typing the display name "Voyage First" silently created the identifier
voyage_first. Our code checkedfirst, so a paid customer would have stayed locked out, and nothing would have crashed to tell us. Fix: show the identifier inline in the wizard, editable, labelled "your code checks this string". - Suggested prices ignore the category you just picked. We chose Education and were offered $79.99/year and $9.99/month. RevenueCat's own report puts Education's yearly price at $44.99. Fix: seed suggestions from the chosen category's medians.
- Test Store prices can't be edited once created. Rico, the dashboard AI, correctly refused to change a price in place. We had to create new products and repoint the offering, which left two orphaned "legacy" products on the entitlement. Fix: allow price edits on Test Store products, which never reach a real store.
- A fresh AI-generated paywall is attached to no offering. It reads "No offering" until you find that dropdown, and the app shows nothing. Fix: attach to the only offering by default, or flag it in the issues badge.
- RevenueCatUI's convenience modifier traps when the SDK was never configured. Open-source and CI builds are exactly the builds with no key. Fix: no-op and log when
Purchases.isConfiguredis false. customerInfoStreamcan't say "I don't know yet". Offline with no cache, it yields nothing. Fix: publish an explicit "no answer yet" state.- Keep: Rico's per-write approvals before touching products; the
test_key prefix, which made "never ship a Test Store key" a one-line build check; and a free tier up to $2,500 in monthly tracked revenue, which works as a startup program for students.
How I built it
SwiftUI on iOS 17+, with one third-party dependency (RevenueCat and RevenueCatUI 5.91.0, pinned exactly), a MIT licence, and an XcodeGen project. Membership follows RevenueCat's own SwiftUI samples in purchases-ios (SampleCat, MagicWeatherSwiftUI). The loyalty rules, the perk ladder, the paywall gate and the membership states are unit-tested. GitHub Actions builds on a macOS runner, runs the tests and records the demo videos on a simulator against RevenueCat's Test Store.
Challenges
- Selling something without selling out the study. The rule that shaped every choice: a paid perk may be comfort, never progress. It's why First seats open free at Silver and the upgrade sheet puts the free path first.
- The identifier mismatch above, caught before it could lock out a paying user.
- A broken Xcode in the last stretch, so every build, test and recording ran on CI.
What's next
Shipping Voyage First in the App Store build (the live App Store version stays free, and its listing is unchanged until the subscription ships), a Web Purchase Link for students who study on a laptop, and a co-pilot mode for studying with a friend.
About the video
All app footage is the real app on an iOS simulator, recorded on GitHub Actions by UI tests (ShipatonDemoUITests, ShipatonFlightUITests). The flight is a shortened demo leg (-VoyageDemoFlight). The purchase is a real RevenueCat Test Store transaction that makes the voyage_first entitlement active; no money moved. The dashboard shots are the Voyage RevenueCat project. Narration is Kokoro text-to-speech. The video was edited as code with HyperFrames. The music and sound effects are original, synthesized for this video.
Since the deadline (added Oct 2, 2026)
Everything in this section was built after Shipaton submissions closed on Sept 30, and it is not part of the judged entry. It ships in Voyage 1.7, which is scheduled to reach the App Store on Oct 13, after judging ends.
- Airplane Mode. Pick the apps that distract you, and Voyage blocks them from takeoff until you land, through Apple's Screen Time (Family Controls). Wi-Fi and the map keep working. The design follows the open-source Foqos app.
- Open skies. A 25-minute flight with no destination. Tap to fly it yourself; let go and the autopilot lands you at a real airport nearby.
- Customs by voice. After landing, three questions are asked out loud from your bags and calendar, on the iPhone.
- Chase camera, widgets and a Live Activity, plus a cleaner seat panel and Settings.
Built With
- github-actions
- revenuecat
- swift
- swiftui
- xcodegen
Log in or sign up for Devpost to join the conversation.