A fully featured, fully open 3D scanning app for LiDAR iPhones and iPads.
Scan the world, view it in 3D, export to standard formats, and share to Photos and AR.
- LiDAR mesh scanning — ARKit scene reconstruction with a live mesh overlay, tracking-quality hints, coaching overlay, torch toggle, and live triangle/color statistics while you scan.
- True color capture — while scanning, every LiDAR depth frame is unprojected into world space and paired with the camera image, accumulating a quality-weighted sparse voxel color field. After the scan, each mesh vertex is painted from that field, so scans come out in color without any cloud processing.
- Surface classification — optionally labels faces as wall / floor / ceiling / table / seat / window / door, with a dedicated color-coded view mode.
- Post-processing pipeline — mesh chunk merging, vertex welding across ARKit anchor borders, color hole-filling, floater (disconnected island) removal, smooth normal recomputation, and optional vertex-clustering decimation (Maximum / Balanced / Compact detail settings).
- Scan library — thumbnails rendered offscreen, rename/delete, scan info (dimensions, surface area, triangle counts, color coverage, file size).
- In-app 3D viewer — SceneKit orbit/zoom viewer with Shaded, Unlit, Wireframe, Points, and Classes display modes, in light and dark themes.
- Standard-format export — OBJ, PLY, STL, glTF binary (GLB), and USDZ, shared via the system share sheet (AirDrop, Files, Messages, …). GLB and USDZ writers are implemented from scratch.
- Photos integration — save viewer snapshots and rendered 360° turntable videos straight to your photo library (Photos can't store 3D models, so CatScan renders them for you).
- AR Quick Look — view any scan in AR, placed in your room, via the built-in USDZ pipeline.
- Works without LiDAR too — devices without LiDAR (and the simulator) can't scan, but get a procedural sample scan to exercise the viewer, exports, and Photos features.
- Xcode 16 or newer (project uses the folder-synchronized project format).
- iOS 17.0+ deployment target.
- Scanning requires a LiDAR device: iPhone 12 Pro or later Pro/Pro Max models, or iPad Pro (2020 and later). Everything else runs anywhere, including the simulator.
- Open
CatScan.xcodeprojin Xcode. - Select the CatScan target → Signing & Capabilities → choose your development team.
- Build and run on your iPhone (or the simulator for the non-scanning features — use ⋯ → Add Sample Scan to get a model to play with).
CLI build:
xcodebuild -project CatScan.xcodeproj -scheme CatScan \
-destination 'platform=iOS Simulator,name=iPhone 17 Pro' buildCatScan/
├── App/ Library home screen, app entry, unsupported-device sheet
├── Models/ MeshData (+ compact binary serialization), ScanDocument,
│ ScanStore (Documents/Scans/<uuid>/), sample mesh factory
├── Scanning/ ScanSessionController (ARSession lifecycle & delegates)
│ DepthColorSampler (depth-map → colored world points)
│ SpatialColorStore (sparse voxel color field)
│ MeshBuilder (merge → weld → color → clean → normals → simplify)
│ ScannerView + ARViewContainer (RealityKit mesh overlay UI)
├── Viewer/ SceneKit viewer + display modes, turntable video renderer,
│ AR Quick Look presentation, scan info
├── Export/ OBJ / PLY / STL / GLB / USDZ writers, export UI, share sheet
└── Support/ Photos saving, toasts, haptics, formatting helpers
Capture design notes:
- ARKit continuously re-tessellates its mesh anchors, so per-anchor color buffers don't survive a scan. CatScan instead keys color samples by quantized world position (8 mm voxels): each depth frame contributes ~49k colored points with a quality score (depth-confidence × closeness), and the best sample per voxel wins. At finish, each welded vertex looks up a quality-weighted blend of its 3×3×3 voxel neighborhood, and remaining gaps are filled from mesh-neighbor colors.
- The USDZ exporter writes a USDA layer with per-vertex
displayColorprimvars inside a spec-compliant stored-zip container (64-byte aligned payloads). SceneKit's built-in USDZ writer was dropped because it silently discards vertex colors. - The GLB exporter emits glTF 2.0 with
POSITION/NORMAL/COLOR_0accessors and a double-sided material, so vertex-colored scans open correctly in Blender, three.js, MeshLab, and Windows 3D Viewer.
| Format | Colors | Best for |
|---|---|---|
| USDZ | ✓ (displayColor) | AR Quick Look, Messages, Apple ecosystem |
| GLB | ✓ (COLOR_0) | Blender, three.js, game engines, web |
| PLY | ✓ (binary) | MeshLab, CloudCompare, scan processing |
| OBJ | ✓ (MeshLab convention) | Maximum compatibility, text-based |
| STL | — | 3D printing, CAD |
Debug builds understand two launch arguments (see Support/DebugAutomation.swift, compiled out of Release):
-catscanAutoTest— builds the sample scan, runs every exporter, renders a turntable, saves to Photos, and writesDocuments/autotest-report.txt.-catscanOpenFirst— navigates straight to the first scan on launch (handy for screenshots).
Everything happens on-device. CatScan uses the camera/LiDAR only while you scan, saves scans to its own Documents folder, and only touches your photo library when you explicitly save a snapshot or video (add-only access).
MIT — see LICENSE.


