· 9 min
Four platforms in four months
Lovable, a Capacitor wrap, Expo, then native SwiftUI: how a baby-face predictor became a native iOS app, and what each step taught me.
Part 1 of 7 in the Building ProbaBaby series.
ProbaBaby is a pregnancy, newborn and postpartum tracker for iPhone, iPad and Apple Watch, in 32 languages. I designed and built it, with my wife Esma as its first user and daily tester. It went live on the App Store on 14 May 2026, and about a week later it had its two most demanding users: the two of us, with a newborn.
It didn’t start as any of that. It started on 29 September 2025 as a web app that guessed what a baby might look like from two parents’ photos, and it reached native iOS by way of three other platforms. This series is the honest version of how it got built: the platforms, the bugs, the AI that wrote most of the commits, and the baby that rewrote the roadmap. Part 1 is the platforms.
14 May · App Store
- Lovable web app 29 Sep 2025 – 25 Jan 2026
- Expo, inside Lovable 1 Oct 2025, 09:20–09:30 UTC
- Capacitor wrap 4 Oct – 10 Nov 2025
- Expo, a separate project deleted, so no dates survive
- Native SwiftUI from 10 Nov 2025
The diagram, step by step:
- 29 Sep 2025: Lovable writes a React web app, 721 commits in its first two weeks.
- 1 Oct: Expo, for a morning. Three build errors in three minutes, swapped out by 09:30.
- 4 Oct: Capacitor wraps the web app in an iOS frame.
- Expo again, in a separate project. I deleted it, so no dates survive.
- 10 Nov: a second repository, for native SwiftUI. The photo bug is gone on its first night.
- 25 Jan 2026: the web app is deleted. 14 May: ProbaBaby is on the App Store.
The idea came first
The spec I started from, dated 29 September 2025, called the app BabyVision AI: a “Mobile-first Baby Face Prediction App” on React Native and Expo, with images from fal.ai and genetics worked out with Punnett squares. It sold predictions one at a time, from $0.99 for a photo-only guess up to a $7.99 monthly plan. Its roadmap promised a monolith, deployed in eight weeks.
It was a product idea, not a personal one. Our own pregnancy came second, and it’s what later turned a predictor into a pregnancy, newborn and postpartum tracker. That story is Part 4.
Lovable: 721 commits in two weeks
I didn’t start with React Native. I started with Lovable, an AI app builder that writes a React web app from a conversation and commits every change to git as it goes. The first commit landed on 29 September 2025: Vite, React, shadcn and a Supabase backend that Lovable provisioned for me.
In its first two weeks Lovable made 721 commits. On 30 September alone it made 140, and that is still the busiest day in the repository’s history; my own busiest day, months later, was 67. By mid-October the web app had a four-tier prediction flow, grandparent genetics, generated images, a PDF report, a video flow, credits, an admin panel and translations.
The commit log reads like someone fixing things in a hurry. 429 of Lovable’s 867 commits start with “Fix”. “Fix PDF generation error” appears four times in a row. On 30 September, four differently worded fixes for stages that kept resetting landed within twelve minutes.
That speed was the point, and it was real: within days I had a flow I could tap through and show people. What Lovable couldn’t give me was a native app. It also left things behind that I only found months later, such as a generated database migration with the prototype project’s address and a service key written inline into a scheduled job. I redacted it in May 2026.
Day three: Expo, for a morning
The spec said Expo, so on 1 October Lovable tried to turn the web app into React Native Web. At 09:20 UTC it added Expo’s gradient and icon packages, Reanimated and React Navigation. Within three minutes it had three build errors. By 09:30 it had swapped the Expo packages for web equivalents: a CSS gradient, lucide-react, framer-motion. The note it wrote that morning says the goal was “enabling future iOS/Android export via Capacitor”.
After that, the screens were ordinary React again. Most of the leftover packages came out on 19 October.
The port: a website in a frame
Lovable added Capacitor on 4 October. Its first config pointed the iOS app at the Lovable preview URL, with Lovable’s badge hidden. The “iOS app” was a web view showing the hosted site, and Lovable’s instructions promised that “changes in Lovable will reflect on your device automatically!”
13 October is when git shows the first real iOS build: a proper app ID, an app icon, a black screen on launch, a crash when picking a photo. I kept the native ios/ folder out of git, so my first commit from my own machine was a .gitignore change.
Then came the bug that decided everything. A photo picked into the prediction flow didn’t appear on screen until you locked and unlocked the phone. Between 14 and 19 October, about two-thirds of my 63 commits were about photo display, validation or face detection. On 17 October the titles escalate over twelve minutes, in my local time: “CRITICAL FIX” at 00:38, “NUCLEAR FIX” at 00:44, “ULTIMATE RADICAL FIX” at 00:50. That last one says: “This is the FINAL solution to the 3-day photo display issue.” It wasn’t. Two days later the bug got its own document, with a section titled “Attempted Solutions (All Failed)”.
At the time, that document blamed React state synchronization, and the fixes followed the theory: force the component to re-mount, add dynamic keys, then remove the dynamic keys again. By November the troubleshooting documents were blaming the frame instead: the web view cached image data aggressively, it blocked access to local files, and iOS kept serving an old JavaScript bundle. Around all that sat nearly 30 commits fighting safe areas, the status bar and spacing, with titles like “fix: make DRAMATIC spacing reductions for clear visibility”.
One commit from that same night reached for the native side. At 01:06 on 17 October I added a Capacitor plugin that would check faces with Apple’s Vision framework. Its message promised 300–800 ms, against 2–5 seconds for the JavaScript path. Thirteen minutes later I was debugging why the app couldn’t find the plugin and kept falling back to the web path, and two days later face validation came out altogether. The native API was right there, and the frame stood in front of it.
| time | what happened |
|---|---|
| 00:38 | CRITICAL FIX |
| 00:44 | NUCLEAR FIX |
| 00:50 | ULTIMATE RADICAL FIX |
| 01:06 | a Vision plugin, promising 300–800 ms against 2–5 s |
| 01:19 | debugging: the app can’t find the plugin |
| 19 Oct | face validation comes out altogether |
The diagram, step by step:
- 00:38, my local time: “CRITICAL FIX”.
- 00:44: “NUCLEAR FIX”.
- 00:50: “ULTIMATE RADICAL FIX”, “the FINAL solution to the 3-day photo display issue”. It wasn’t.
- 01:06: a Capacitor plugin to check faces with Apple’s Vision framework.
- 01:19: the app can’t find the plugin, and keeps falling back to the web path.
- Two days later, face validation comes out altogether.
A plan for a team I didn’t have
On 22 October a migration plan went into the repository: three documents, 3,047 lines. It recommended full native SwiftUI and priced it for a funded company: “6-9 months with 2-3 iOS developers”, a minimum team of two senior iOS developers, a QA engineer and a project manager, and a budget of $400K–700K. (The commit message says “K-700K”; my shell most likely ate the “$400”.)
It also had an opinion about the middle path: “React Native is better than Capacitor but still not truly native. If you’re going to rewrite, go fully native for maximum benefit.” And: “Don’t halfway commit.”
The same day, I moved the backend off Lovable’s Supabase project to one I own. Leaving Lovable’s sandbox and planning for native started on the same day.
Expo, properly
Somewhere in those weeks, with the Capacitor wrap showing its limits, I also gave Expo a proper try, in a separate project. It didn’t last. It was dependency issues from start to finish, my head was full of packages instead of the app, and honestly, it made me angry. So I deleted it, the whole project. That’s why nothing of it survives in git.
The night it switched
The web view held on until 10 November. At three minutes past midnight, local time, I committed “Revert to simple photo upload approach for iOS stability”, together with 17 troubleshooting documents (FINAL_FIX_HARD_RESET.md, XCODE_STEPS_FINAL.md and fifteen more). Its message says the upload now “works reliably with lock/unlock workaround on iOS”, and adds: “Preparing for native iOS migration (keep React for web/Android)”.
Ten minutes later, at 00:13, I created a second repository for the native app. It started as a copy of the web project, troubleshooting documents and all. At 02:14 came its second commit, “Add native iOS app foundation with SwiftUI”, and one line of its message reads: “Added photo upload view with native UIImageView (fixes WKWebView cache issue)”. The bug that had eaten four weeks in the web view was gone on the first night of native.
Five weeks in a second repository
The main repository then went quiet for 37 days, its longest silence. The work hadn’t stopped; it had moved. The second repository holds 127 commits from 10 November to 15 December. Mid-November brought the TrueDepth depth scan and prediction steps built to Figma designs. Early December brought the results page, the PDF report, StoreKit 2 credits and 21 free tools. Cursor was in the loop: one commit carries its co-author line, and one file still says “Created by Cursor on 28.11.2025”.
Some habits came along from October. Between 02:38 and 03:04 on 29 November, five commits fixed naming conflicts and missing braces, and the fourth was titled “fix: Add missing GeometryReader closing brace - FINAL FIX”. On 7 December there were 29 commits, most of them nudging the PDF’s layout, down to “Reduce footer area spacing from 90px to 70px”.
The native app came back to the main repository on 18 December, three days after the last push to the second one, in a single commit with a remarkably plain title, “Update main source: clean up documentation, update components and features, add new assets and migrations”: 489 files and 96,517 added lines, among them 233 Swift files holding 72,747 lines. That is the second repository’s final state, file for file.
The web app becomes the port
Claude Code made its first commit on 27 December. The next day Lovable had its last session, and the roles had flipped: Claude Code wrote a nine-phase set of instructions for Lovable to restyle the web app to match the Swift app, and Lovable carried it out in 34 commits, seventeen of them titled just “Changes”. Native was now the reference, and the web app was the port.
At 14:00 on 25 January 2026 I pushed a snapshot of the whole repository to an archive. At 14:05 I deleted the web app from the main one: “Remove web/React codebase, focus on native iOS”, 845 files and 173,909 lines. That evening I built the Emergency Birth module, in Swift.
The estimate against what happened
| the plan | what happened | |
|---|---|---|
| Team | two to three iOS developers, a QA engineer and a project manager | me with AI tools, and Esma as its daily QA |
| Time | six to nine months | the native prediction flow, results page, PDF and credits within five weeks of the switch; the App Store on 14 May 2026, about six months after it |
| Money | $400K–700K | about $75–100 a month for servers and the website, plus the AI subscriptions; $32 of revenue so far |
| Decision | “go fully native”; “Don’t halfway commit.” | native SwiftUI, from 10 November 2025 |
The diagram, step by step:
- Team: two to three iOS developers, a QA engineer and a project manager. It was me with AI tools, and Esma as its daily QA.
- Time: six to nine months. The App Store came about six months after the switch.
- Money: $400K–700K. Servers and the website cost about $75–100 a month.
- The decision: go fully native. That part was right.
Size today. About 495,000 lines of Swift in 1,549 files, 21 Swift packages, 48 edge functions, 306 database migrations and 32 languages. 486 people have signed up; about 110 use it every day and 360 every month.
What I’d tell myself in September 2025
A prototyping tool buys you the idea, not the product. Lovable got me from nothing to a flow I could test within days. The moment the product needed the camera, the photo picker and the lock screen, it had nothing more to give.
A web view is a website in a frame. By November, the bugs I was fighting belonged to the frame, not to the app.
Count the fixes that are about the container. Caches, safe areas, stale bundles, plugins that won’t register: when most of your commits are about the wrapper rather than the product, the wrapper is the problem. The bug that ate four weeks in mine was gone on native’s first night.
Don’t let the estimate decide for you. The plan was wrong about the cost, because it priced a team I would never hire. It was right about the decision.
What made a developer and a daily tester enough was AI that wrote most of the code, and a set of rules that grew around it, one mistake at a time. That’s Part 2.