Mobile

Whiteboard photo to round timer for iPhone

Native SwiftUI iPhone app that reads gym whiteboard photos with Vision OCR into workout rounds and runs an interval timer offline.

swiftswiftuivisionavfoundationswiftdataios

Built 1 time, downloaded 0 times.

Install from your terminal

Run this in your project folder. It signs you in, shows what changes and asks before it overwrites a file.

npx claude-lab add whiteboard-photo-to-round-timer-for-iphone-7cd746
CLAUDE.md
# the app

Native iPhone app. The user photographs a gym whiteboard. The app reads the text with Vision OCR, parses it into workout rounds (exercises, work seconds or reps, rest), lets the user review and edit the text, and runs an interval timer over the parsed plan. Everything runs on device with no network calls.

Scope and acceptance criteria are in @SPEC.md. The current phase and its /goal block are in @PLAN.md. Review rules are in @REVIEW.md.

## Stack

- Swift 5.10 or newer, SwiftUI, iOS 17 minimum.
- Vision (VNRecognizeTextRequest) for OCR, AVFoundation for camera capture.
- No third-party dependencies unless approved and listed in SPEC.md.
- Saved plans use SwiftData or Codable JSON, as decided in SPEC.md.

## Commands

Run from the project root.

- Build: `xcodebuild -scheme the app -destination 'platform=iOS Simulator,name=iPhone 16' build`
- Test: `xcodebuild test -scheme the app -destination 'platform=iOS Simulator,name=iPhone 16'`
- Lint (if installed): `swift-format lint -r Sources Tests`
- After any Swift change, run the `verify` skill.
- For test results, use the `test-runner` agent so raw logs stay out of the main context.

## Architecture

- `Parsing/`: pure Swift. Takes `[String]` of recognized lines and returns a `WorkoutPlan`. No UIKit or SwiftUI imports. Unit tested with text fixtures.
- `Timer/`: timer state machine. No UI imports. Driven by a clock protocol so tests advance time without sleeping.
- `Views/`: SwiftUI only.
- `Camera/`: capture, photo picker, and the VNRecognizeTextRequest wrapper.
- `Tests/Fixtures/images/`: sample whiteboard photos.
- `Tests/Fixtures/ocr/`: raw OCR text, same basename as the image.
- Expected plan JSON sits next to each OCR file.

## Rules

- Parser tests never call Vision. They feed `[String]` fixtures.
- Timer code never reads the system clock directly. Inject the clock protocol.
- Sort Vision observations by bounding box y, then x, before joining text. Vision's order is not reliable.
- The parser must tolerate misspellings and missing rest lines. Return warnings. Never crash.
- AMRAP and EMOM are text labels only in v1. Do not add timing behavior for them.
- No force unwraps and no `try!` outside tests.
- User-visible strings go in the String Catalog.
- No network code. v1 is offline.

## Gotchas

- The simulator has no camera. Photo flow tests use bundled sample images and the Photos picker path.
- Whiteboard handwriting is noisy. Expect misspellings and dropped lines.
- Do not edit an expected JSON fixture to make a test pass without stating the reason in your reply. The parse-whiteboard skill has the full steps.
- Keep sample photos free of gym members and faces.
- Info.plist needs NSCameraUsageDescription and NSPhotoLibraryUsageDescription before camera or photo code ships.

## Signing and secrets

- Use `TEAM_ID_PLACEHOLDER` in every committed file. Put the real team id only in local Xcode signing settings.
- Never commit signing certificates, provisioning profiles, or App Store Connect keys.
- Do not run fastlane match from a Claude session.

## Working style

- Start each phase in a fresh session with `/clear`. Use `/compact` at natural breaks.
- Work in this order: explore, plan, code, verify. The verify skill is the check.
- Default model is Opus 5.5 at medium effort. Switch to Sonnet 5.5 with `/model` for routine edits.
Use for my project