All projects

Fern

A quiet minute a day for a stronger pelvic floor.

BusinessApp Store2026
View on the App Store

Problem

Pelvic floor exercise is recommended to a lot of people, but it is hard to keep up and easy to do wrong. You lose track of when to squeeze and when to rest, you are not sure you are using the right muscles, and many of the apps for it feel clinical, store private health details, or make it obvious on your phone what they are for.

Solution

Fern turns it into a calm exercise timer. A circle contracts when you squeeze and opens when you rest, and gentle vibration paces every rep, so you can follow a whole session with the screen off and the phone in your pocket. It has three levels and a custom program, a short video guide on technique, a light streak, and one optional daily reminder that never says what it is for. There are no medical claims, nothing is stored off the device, and it is a one time app with no ads or subscriptions.

What it is

A minimal iPhone app that guides pelvic floor exercise sessions, pacing each squeeze and rest with an animated circle and gentle vibration, entirely on the device.

Design process

01

General research

Pelvic floor exercise is widely recommended, and I read the published guidance for it, slow holds to build endurance and quick pulses for the fast muscles. The real problem is not the exercise, it is doing it consistently and correctly.

02

Market validation

I looked at this women's health space and chose the lowest risk, most honest version of it. An exercise timer that makes no medical claims and stores no sensitive data, so it is safe for the person using it and clean for App Review.

03

Ideation

I reduced the whole thing to a calm timer you can follow without looking. A circle that contracts and opens, gentle vibration that paces each rep, and a discreet reminder that never says what it is for.

04

Testing

I ran a full UX and UI audit pass, tested the sessions and the storage, and verified the app through a real web preview build driven headlessly, since there is no Xcode on my machine.

05

Iteration

I hardened the timer so it survives pausing and backgrounding, hardened the storage so bad data can never crash it, and softened the wording to remove any implied medical claim. I also added a fully dark, touch locked Pocket Mode you can follow by feel.

06

Build

I built the guided session with the animated circle and haptics, three levels and a custom program, a video technique guide, a light streak and week view, and one optional daily reminder.

07

Test

I checked every screen, fixed the icon that App Store rejected for transparency, and re did the guide videos so they use one consistent presenter with no watermark.

08

Release

Fern is live on the App Store, a one time app with no ads or subscriptions, with a marketing site at fern-pelvic.vercel.app.

Technical breakdown

TypeScriptReact NativeExpo SDK 57expo-hapticsexpo-videoexpo-notificationsAsyncStorageEAS Build

Fern is a React Native app built with Expo, in TypeScript. It has no navigation library, just a small state machine that shows onboarding, a session, or the tab shell. Everything is stored on the device with AsyncStorage, no account and no network. The session engine expands a program into prepare, squeeze, rest, and pulse phases, and runs on the wall clock, so pausing or backgrounding never drifts the timing, while it animates the circle and fires the haptics for each phase.

Architecture

No navigation library, just a state machine

Fern has no router. App.tsx is a small state machine, if not onboarded show onboarding, if in a session show the session, otherwise a hand rolled tab shell of Today, Learn, Progress, and Settings. For an app this size a navigation library would be more surface area than it saves. When the states are few and clear, an explicit state machine is simpler to reason about than a routing framework.

Timing

A wall-clock timer that never drifts on pause or background

A session paces squeeze and rest phases, and a timer that accumulates ticks drifts whenever you pause or the phone sleeps, because the ticks simply stop coming. So the session engine reads the wall clock with Date.now and computes which phase you should be in, rather than counting elapsed ticks, so pausing or backgrounding never desyncs the count. For anything timed that must survive interruption, derive the state from a timestamp, do not accumulate it from a ticker.

Accessibility

A session you can follow entirely by feel

The whole point is a session you can do with the screen off and the phone in your pocket, so the haptics carry the pacing, not the screen. Pocket Mode is a fully dark, touch locked cover with a deliberate haptic vocabulary, a double tap for squeeze start, a tick for each second of the hold, a soft tap for release, and a two second long press to wake. Designing a real vocabulary of distinct haptics lets the body follow an exercise without the eyes.

Reliability

Storage that repairs bad data instead of crashing

Loading settings and the session log runs through a repair path, so old or malformed data on the device is corrected rather than crashing the app on launch. The loader must never throw. On device persistence outlives your schema, so the load path has to treat stored data as something that might be from an older, broken version of your own app.

Build pipeline

Building and verifying iOS with no Xcode on the machine

There is no Xcode or simulator on my machine, only the command line tools, so every iOS build runs in the cloud on EAS Build. I verify the app through its real Expo web build driven headlessly, and even capture the App Store screenshots from that web UI with Playwright rather than a simulator. You can develop and ship a real iOS app without a local Xcode, if you lean on cloud builds and verify against the web target.

App Review

The opaque-icon rejection, and generating a flat icon

Apple rejected the icon under ITMS-90717 for containing transparency, because iOS icons must be fully opaque. So the asset generator flattens the alpha channel and outputs an opaque icon, and it passed. A surprising number of first submissions die on icon and asset rules, so generate the assets to spec rather than exporting them by hand.

Media pipeline

Getting five consistent guide videos out of AI tools

The Learn tab needed short technique clips, but the video generators refuse lone person, body focused exercise footage as a whole category, and the early clips carried a watermark and used different presenters. I stripped the watermark with an ffmpeg delogo pass, scaled and silently boomerang looped the clips, and later regenerated all five with one consistent presenter through an image to video pipeline, all bundled on the device so the app still makes no network calls. Producing consistent AI media is its own engineering problem, with real tool constraints to design around.

Shipping

Driving the whole App Store submission over the API

The submission runs over Apple's App Store Connect API with my own small Node tools that mint ES256 JWTs and drive the age rating, the copyright, the review contact in E.164 format, and the release, so I can ship without clicking through the website. The gotchas, that the age rating moved to appInfos and that App Privacy is UI only, are written down so the next release is faster. Automating the store submission turns a nervous manual ritual into a repeatable command.

Links