← All writing
// June 20, 2026

Building FotoCraft: real-time composition guidance on iOS

  • Swift
  • SwiftUI
  • OpenAI Vision
  • iOS

FotoCraft started as a simple frustration: I kept taking photos I thought were well-composed, only to look at them later and realize the framing was off. The “rule of thirds” is easy to read about and hard to feel in the moment. So I built an app that gives you feedback while you’re still holding the camera.

This is a quick tour of the architecture and the decisions that mattered most.

The camera overlay loop

The core experience is a live preview with overlays — rule-of-thirds grid, leading-line hints, a horizon-level indicator — drawn on top of an AVCaptureSession. SwiftUI alone can’t own the camera, so the capture pipeline lives in a UIViewControllerRepresentable wrapping AVCaptureVideoPreviewLayer, and the SwiftUI layer floats above it.

The tricky part was keeping the overlay reactive at 60fps without blocking the main thread. I pipe preview metadata through a Combine subject on a background queue and only marshal to the main actor for view updates, debounced to ~15fps. Anything more was wasted work; the eye can’t read the grid faster than that.

Haptics as feedback, not gimmick

UIImpactFeedbackGenerator fires a soft tick when the horizon levels out and a crisper one when the subject crosses a thirds intersection. It sounds minor, but haptics turned out to be the feature people mention first. The lesson: a tiny amount of well-timed tactile feedback does more for “feel” than any animation.

AI scoring with OpenAI Vision

After capture, the photo gets sent to OpenAI Vision for a composition score and short critique. The interesting design problem wasn’t the API call — it was making the latency feel acceptable. Two things helped:

  • Stream the critique so text appears word by word instead of all at once after a long pause.
  • Score locally in parallel using a lightweight on-device heuristic (edge density + center bias) so there’s something on screen within 200ms, and the network score refines it when it arrives.

StoreKit 2 and the curriculum

The 45-lesson curriculum is gated behind a single subscription, configured with StoreKit 2’s async/await API. Transaction verification is dramatically nicer than the old StoreKit 1 delegate soup — Transaction.updates as an async sequence means handling renewals and family-sharing is just a for await loop.

What I’d do differently

The capture/overlay split was right, but I underestimated how much edge-case work permissioning and lifecycle (backgrounding mid-capture, interrupted sessions) would eat. Next time I’d build the session-management state machine before any UI.

FotoCraft is live on the App Store. I’m still adding lessons — and still learning to see frames myself.