CalmCheck — Panic help in 60 seconds, fully offline

Inspiration

Mental-health apps are built for maintenance — daily check-ins, streaks, dashboards. The moment that actually matters is different: someone is in distress right now and needs to know exactly what to do in the next 60 seconds. That moment has no bandwidth for menus, accounts, or spinners over a dead wifi logo.

CalmCheck answers it in two halves:

  1. Calm yourself — a guided panic flow: paced breathing with synchronized haptics and voice, plus 5-4-3-2-1 sensory grounding.
  2. Be ready for someone else — Care Cards: a structured, shareable offline profile for a person you look after, readable by any caregiver or stranger in seconds via QR code.

Everything works in airplane mode, on principle.

What we learned

The breathing pacing had to be grounded in physiology, not taste. Slow breathing near resonance frequency (~6 breaths/min) maximizes parasympathetic influence:

$$T_{\text{cycle}} = 4\,\text{s} + 6\,\text{s} = 10\,\text{s} \;\Rightarrow\; f = \frac{60}{10} = 6\ \text{breaths/min}$$

Haptic pulses are scheduled on a phase function, not a fixed timer, so the pacer stays in sync even if the event loop stalls:

$$\phi(t) = \frac{t \bmod T_{\text{cycle}}}{T_{\text{cycle}}}, \qquad \text{haptic at } \phi = 0,\ 0.4$$

Other lessons:

  • An app that promises "no internet, no data collection" must prove it — ML Kit quietly re-added INTERNET to our release build.
  • Offline-first is a hard constraint, not a feature flag. The result is a ~24–28 MB minified APK that needs nothing at runtime.
  • The "Field Card" design system was developed across 9 structured design sessions, ending with a dedicated accessibility pass.

How we built it

  • Flutter, offline-first, ~226 tests, flutter analyze clean.
  • Billing via in_app_purchase; free tier genuinely includes one free card, plus a giveback mechanic.
  • Store-ready: signed release builds, R8-minified, iOS 14+ / Android 7+, with a full submission checklist.
  • A render-shots test outputs a dozen screens as PNGs with real bundled fonts, so QA can look at builds, not only assert on them.

Challenges

Before shipping, a full production-readiness audit surfaced 37 findings the tooling couldn't catch — including a free-tier bug that paywalled every new user, cold starts silently granting Pro, crisis "Call" buttons doing nothing on tablets without telephony, and a location timeout that expired while the OS permission dialog was still open — exactly on the panic path.

Three taught us the most:

  • Entitlements are a race. Pro must survive store-query latency and be revocable on refund — both directions of the same rule: never trust stale or unknown entitlement state.
  • Safety-critical flows need failure design. Silent no-ops on "Call" and first-press location were the least acceptable places for our app to fail.
  • Release builds break differently. Missing R8 rules crashed reminders in release only; every debug test was green.

All 37 findings were fixed, and the app was walked end-to-end on a minified release build on a real emulator before submission.

Accomplishments that we're proud of

What we learned

What's next for CalmCheck

Built With

Share this project:

Updates

Submission history