Epiphany & ShakeRage
Two SwiftUI apps built back to back — one widget-first capture tool, one motion-driven SceneKit game.

- Type
- Artifact
- Where
- Personal
- When
- Nov 2025 → Feb 2026
- Duration
- 3 mo
- Status
- Shipped
- Source
- GitHub
The problem
I had written a lot of backend and very little native mobile. Two apps in one push was a deliberate choice: one that lives mostly outside the app, and one that is nothing but the app.
What I built
Epiphany is built around WidgetKit — the point is capturing a thought from the home screen without opening anything. SwiftData handles local persistence and App Groups share it with the widget, so content syncs even when the app is never foregrounded. A structured ThemeModel drives custom visual themes, and StoreKit 2 runs a full paywall with purchase restoration and entitlement verification behind a freemium tier.
ShakeRage is the opposite. CoreMotion's CMMotionManager reads real-time device acceleration and turns shake intensity and duration into a competitive score, rendered through SceneKit. Supabase provides auth with JWT session handling, token refresh and Keychain-backed credential storage, and a live leaderboard that syncs over realtime subscriptions rather than polling.
Both follow MVVM over ObservableObject and StateObject, which is the part that actually made two apps in one cycle possible.
Screens



Results
- Two native apps shipped from an empty Xcode project inside one development cycle.
- Widget capture works without ever foregrounding the app, via App Groups and SwiftData.
- Median leaderboard read under 100 ms, from indexed queries plus client-side caching, synced over realtime subscriptions rather than polling.
- Full StoreKit 2 paywall with restoration and entitlement verification.
Architecture
In hindsight
Sharing an auth layer across two apps with genuinely different session needs was the right instinct and the wrong abstraction — a game session and a capture session want different lifetimes. I'd split the token handling and keep only the identity layer common.