Native SwiftUI app: ARKit multi-point measuring (distance / area / volume / angle, LiDAR + visual fallback), RoomPlan room scanning → parametric floor plans, exports (PDF / PNG / SVG / DXF / CSV / USDZ / glTF), optional Supabase accounts with offline-first sync, StoreKit 2 Pro subscription.
Bundle: com.faisalnurarif.tapescan · iOS 17+ · iPhone (room scan needs LiDAR).
Legal/support pages: https://faisalarip.github.io/tapescan-legal/
Five enhancements from the "TapeMeasure v2 Feature Spec", each behind a flag in
Sources/App/FeatureFlags.swift and instrumented for its success metric:
| # | Feature | Tier | Where |
|---|---|---|---|
| 01 | Snap-to-Edge | Free | Services/EdgeSnapping.swift (pure crease/corner geometry) + ARKitMeasureService reticle sampling; HUD SNAP chip, SNAPPED · WALL EDGE/CORNER pill, acquisition haptic, press-and-hold for a free point. Corner snap is LiDAR-only; snapping suspends on weak tracking. |
| 02 | Photo Receipt | Free (Pro removes watermark) | Services/ReceiptComposer.swift composites the captured frame + overlay at capture resolution (not a screen grab); ReceiptArchive sidecars; Screens/Measure/PhotoReceiptView.swift. Opens on measure completion and from a History row. JPEG 0.9 → share sheet / "TapeScan" album. Composited images carry no EXIF GPS by construction. |
| 03 | Furniture Layout | Pro | Domain/FurnitureLayout.swift (pure fit math: fits / tight / over / unchecked, door-swing zones, 90° snap) + Screens/Rooms/FurnitureLayoutView.swift (drag / rotate / place). Persists per room (FurnitureArchive), exports as the SVG furniture layer via the Export "Furniture & openings" toggle. |
| 04 | Report PDF | Pro | Services/Export/ReportPDFExporter.swift — multi-page vector PDF (cover → plan + dimension table → photo/notes pages), selectable text, Pro branding vs free footer, silent-collapse of empty sections. Options + generate in Screens/Rooms/ReportView.swift. |
| 05 | Guided Scan Flow | Free | Screens/Rooms/ScanGuideOverlay.swift — 4 coach steps auto-advancing on real RoomScanService events (floor lock → first wall → coverage ≥ 90%), debounced 1 s, Reduce-Motion + VoiceOver aware. First-scan-only (hasCompletedFirstScan), replayable from the scan HUD's "?". |
| 06 | Photo Mode | Free · no quota | Services/PhotoModeService.swift — guided object capture (RealityKit ObjectCaptureSession + its coached ObjectCaptureView) → on-device photogrammetry (PhotogrammetrySession) → USDZ under Application Support/Captures; up to 300 photos per capture (the OS input cap). Screens/Rooms/PhotoModeView.swift HUD + ObjectCaptureRecord (SwiftData) + Quick Look viewing from the Rooms tab. LiDAR + A14 or newer; the Simulator runs a scripted capture. |
Report PDF and Furniture Layout entries live on the Export screen (Pro-gated → paywall); Snap, the Scan Guide, and Photo Mode are always on for free.
brew install xcodegen # once
xcodegen generate # after adding/removing files
open TapeMeasureARPro.xcodeproj # scheme: TapeScan → iPhone 17 Pro simulatorCommand line:
xcodebuild -project TapeMeasureARPro.xcodeproj -scheme TapeScan \
-destination 'platform=iOS Simulator,name=iPhone 17 Pro' \
CODE_SIGNING_ALLOWED=NO testThe Simulator runs end-to-end with a simulated AR backend, a scripted room
scan, and the local TapeScan.storekit configuration (purchases testable
without App Store Connect). Real ARKit/RoomPlan run on device only.
| Layer | Where | Notes |
|---|---|---|
| Domain math & models | Sources/Domain/ |
Pure, fully unit-tested (MeasureMath, FloorPlanModel + quantities, CapturedRoomConverter) |
| Services | Sources/Services/ |
AR seam (ARMeasureService protocol → simulated/ARKit), RoomPlan scan, StoreKit 2, Supabase auth, SyncEngine, exporters |
| Persistence | Sources/Persistence/ |
SwiftData records w/ sync bookkeeping, crash-recovery session drafts |
| UI | Sources/Screens/, Components/, Theme/ |
Design-system theming, Dynamic Type via UIFontMetrics, Reduce Motion gates |
Key invariants:
- isPro is never stored — derived from
Transaction.currentEntitlements(launch +Transaction.updateslistener inTapeMeasureARProApp). - Accounts never gate the app — sign-in is an optional, dismissible sheet; sync failures are silent; deleting the account keeps local data.
- No silent wrong numbers — raycasts >15 m are rejected; tracking degradation surfaces guidance strings in the HUD.
- Crash-safe capture — measure sessions autosave per change
(
SessionDraftStore); scans persist immediately on completion.
DEVELOPMENT_TEAMinproject.yml(+ flipCODE_SIGNING_ALLOWED).- Supabase project: apply
supabase/migrations/0001_init.sql, fillSources/Services/SupabaseConfig.swift. - App Store Connect app record + the 3 IAPs (
tapescan.pro.monthly,tapescan.pro.annual,tapescan.pro.lifetime) — seedocs/ASC-SETUP.md(M9).
TapeScanTests (unit: math, formatters, converters, exporters, sync merge,
product mapping, persistence) and TapeScanUITests (launch smoke). All
DEBUG-only launch args (-uiPhase, -uiTab, -uiPro, -uiPaywall,
-uiFreeExports, -uiMeasureDir) are compiled out of Release.
Design history & specs live in docs/superpowers/.