Inspiration

Every focus app has a Start button. Nobody has ever loved pressing a Start button.

But everyone remembers the tiny ritual of striking a match — the resistance of the striker, the snap of ignition, the quiet promise that something has begun and will burn for exactly as long as it burns. We wanted starting a focus session to feel like that: a physical ritual, not a UI event. So we built Matchbox — a retro matchbox that lives in your phone.

What it does

  • Strike to ignite. Swipe a 3D match against the striker. Velocity physics, haptic friction and a real "catch" decide when it lights — lazy swipes don't ignite.
  • Focus until it burns out. The match burns down in real time. The countdown fades into the night; tap to peek. To quit, you literally blow into the mic to extinguish the flame.
  • Ten living night scenes. Moonlit snowfields, firefly lakes, night sakura — snow falls, petals drift, shooting stars pass, each scene with its own ambient soundscape.
  • Habits, one match at a time. Completing a daily habit strikes one match. Your box empties as your effort piles up — effort you can see. Streaks included.
  • Collect vintage matchboxes. Letterpress-style matchbox designs (Nordic, café, retro…) earned by showing up.
  • On iOS, Match Block tucks distracting apps into the box (Screen Time / Family Controls) while your match burns.

How we built it

  • iOS: SwiftUI + SceneKit (fully 3D match, box and drawer), Core Haptics for strike friction, mic RMS analysis for blow-out detection, CoreMotion so the box rattles when you shake the phone.
  • Android: Kotlin + Jetpack Compose + SceneView (Filament) — a from-scratch 3D port. Textures are exported pixel-identical from the iOS build via a debug hook, so both flames are literally the same fire.
  • RevenueCat everywhere: one project, iOS + Android apps, a single premium entitlement, one offering with lifetime and weekly packages (no free trial — we don't do surprise charges). Purchases, restores and cross-device entitlement sync just worked, which let a solo dev ship two platforms simultaneously.
  • 27 languages, generated from a single string catalog so iOS and Android never drift apart.
  • Play Store pre-registration ran ahead of launch; both stores went live together on August 1.

Challenges we ran into

  • SceneKit → Filament is not a translation, it's a rewrite. Plane geometry that ignores normals, transparent sprites that break depth sorting, a SceneView that eats every touch event. We rebuilt each scene from the iOS source, face by face.
  • The flame itself. The iOS flame breathes using Ornstein–Uhlenbeck noise. Our first Android port "approximated" it with sine waves — and produced a flame wobbling at ~10–20× the real amplitude. The fix (and the lesson): port the original filter verbatim and verify the stationary variance numerically. A flame's calm is measurable.
  • Strike feel parity. iOS pan velocity is in pt/s; Android gives px/s. Without density conversion the match lit far too easily. One unit bug can ruin a ritual.
  • Blowing out the flame without false positives from ambient noise, and testing purchases when debug builds can't fetch Play products (signature mismatch) — both taught us to test on the real thing, early.

What we learned

Delight is engineering. The difference between "a timer with a match skin" and "a match you'll want to strike every night" lives in velocity thresholds, haptic timing, noise variance and a hundred tiny constants — and none of them can be faked. "Same as iOS" only counts when the numbers match.

What's next

More living scenes and seasonal matchbox designs, richer stats for premium, exploring focus-block options on Android, and listening very carefully to the first thousand people who strike a match tonight.

Built With

  • admob
  • android
  • avfoundation
  • core-haptics
  • core-motion
  • family-controls
  • fastlane
  • filament
  • google-play-billing
  • hilt
  • ios
  • jetpack-compose
  • kotlin
  • revenuecat
  • room
  • scenekit
  • sceneview
  • storekit
  • swift
  • swiftdata
  • swiftui
Share this project:

Updates