RORK LABJP
TOOLING — Rork's developer repos keep moving: rork-xcode was updated on July 16, rork-device on July 15, and rork-plist on July 13OPUS46 — Claude Opus 4.6 is live in Rork, and Rork Max is built to assemble apps on top of Claude CodeSIM — A cloud iOS simulator runs in the browser, with one click to install on a device and two clicks to publish to the App StoreMAX — Rork Max emits pure Swift rather than React Native, reaching iPhone, iPad, Apple Watch, Apple TV, Vision Pro, and even iMessageNATIVE — That opens up HealthKit, ARKit and LiDAR, NFC, Dynamic Island, Live Activities, 3D through Metal, and on-device inference with Core MLSEED — Rork raised a $15M seed led by Left Lane Capital, with Peak XV and a16z Speedrun joining the roundTOOLING — Rork's developer repos keep moving: rork-xcode was updated on July 16, rork-device on July 15, and rork-plist on July 13OPUS46 — Claude Opus 4.6 is live in Rork, and Rork Max is built to assemble apps on top of Claude CodeSIM — A cloud iOS simulator runs in the browser, with one click to install on a device and two clicks to publish to the App StoreMAX — Rork Max emits pure Swift rather than React Native, reaching iPhone, iPad, Apple Watch, Apple TV, Vision Pro, and even iMessageNATIVE — That opens up HealthKit, ARKit and LiDAR, NFC, Dynamic Island, Live Activities, 3D through Metal, and on-device inference with Core MLSEED — Rork raised a $15M seed led by Left Lane Capital, with Peak XV and a16z Speedrun joining the round
Articles/AI Models
AI Models/2026-06-15Advanced

Building a Room-Measuring App with Rork Max and RoomPlan — Absorbing Scan Variance by Design

Now that Rork Max generates native Swift, a LiDAR-based RoomPlan scanning app is a realistic project for an indie developer. Scan results drift depending on device and how you hold it. This walks through how to absorb that drift in your app design and export stable dimensions.

Rork Max230RoomPlanLiDAR2Swift48Architecture17

Premium Article

The first time I used RoomPlan, I scanned the same small room three times and got three different wall lengths: 3.62m, 3.57m, 3.64m. A few centimeters of difference, but if you are building an app that draws a floor plan, you cannot expose that drift to the user. People do not trust a tool whose numbers change every time they measure.

Now that Rork Max can generate native Swift, a LiDAR-based measuring app suddenly came within reach for indie developers. But ship the generated code as-is and that drift lands directly in the user's hands. Here I share how I learned to absorb scan variance by design, working through a small measuring app of my own.

Why RoomPlan numbers drift

RoomPlan sits on top of ARKit. It combines the LiDAR point cloud with planes estimated from the camera image to reconstruct the room's structure. In other words, the final dimensions are not a measurement but an estimate. Because it is an estimate, the result moves with the input conditions.

There are three main sources of drift. Lighting: against backlight or in the dark, feature points are scarce and plane estimation gets loose. Motion speed: sweep too fast and the point cloud thins out, delaying how edges are resolved. And the device itself: iPhone and iPad Pro differ in LiDAR resolution and field of view, so the same room reconstructs slightly differently.

The important thing is to not try to crush these as bugs. Estimation drift is the spec, and designing your app to absorb it produces a more stable result in the end.

A three-layer design that absorbs drift

I treat measurement data in three layers: raw, confirmed, and display.

The raw layer keeps the CapturedRoom that RoomPlan returns, untouched. Nothing is rounded here. The confirmed layer applies rounding and snapping to turn raw data into "dimensions the app takes responsibility for." The display layer shows the user only the confirmed values.

With this separation, when you later want to change the rounding rules, you can redo it without throwing away the raw data. Scanning is an effort for the user, so a design that reduces re-scans directly improves the experience.

Rounding and snapping in the confirmed layer

The confirmed layer has two core operations. One is rounding to 5cm units. The other is snapping toward right angles and parallels. Real room walls are made almost entirely of right angles and parallels, so if the estimate returns 88 or 92 degrees, nudging it to 90 produces a more natural drawing.

import RoomPlan
import simd
 
struct ConfirmedDimension {
    let widthMeters: Double
    let lengthMeters: Double
    let cornerAngles: [Double]   // each corner angle, in degrees
}
 
enum DimensionResolver {
    // Round to 5cm so users see a granularity they can trust
    static func snapLength(_ raw: Double) -> Double {
        let grid = 0.05
        return (raw / grid).rounded() * grid
    }
 
    // Snap toward right angles. Within +/-4 degrees, pull to a multiple of 90
    static func snapAngle(_ rawDeg: Double) -> Double {
        let nearest = (rawDeg / 90.0).rounded() * 90.0
        return abs(rawDeg - nearest) <= 4.0 ? nearest : rawDeg
    }
 
    static func resolve(from room: CapturedRoom) -> ConfirmedDimension {
        let walls = room.walls
        let lengths = walls.map { Double($0.dimensions.x) }.sorted(by: >)
        let width = snapLength(lengths.first ?? 0)
        let length = snapLength(lengths.dropFirst().first ?? 0)
 
        let angles = walls.map { wall -> Double in
            let yaw = atan2(wall.transform.columns.0.z, wall.transform.columns.0.x)
            return snapAngle(yaw * 180 / .pi)
        }
        return ConfirmedDimension(widthMeters: width, lengthMeters: length, cornerAngles: angles)
    }
}

The +/-4 degrees threshold is a value I settled on after scanning a few times on my own devices. Snap across too wide an angle and rooms with genuinely diagonal walls break. Too narrow and you fail to absorb the drift. Carry this as a number you will tune for the kinds of rooms your app handles.

Carry a confidence value alongside

If you hand over only the rounded numbers, the display layer cannot judge how much to trust them. I attach a confidence score to the confirmed value. Even a rough calculation from point-cloud density and scan time is enough to drive what the display shows.

struct DimensionWithConfidence {
    let dimension: ConfirmedDimension
    let confidence: Double   // 0.0 to 1.0
 
    var needsRescanHint: Bool { confidence < 0.6 }
}

When needsRescanHint is set, the display layer adds "scanning again slowly will improve accuracy." Rather than hiding the numbers, honestly conveying their certainty is what earns the user's trust in the tool.

Thank you for reading this far.

Continue Reading

What follows includes implementation code, benchmarks, and practical content we hope you'll find useful. This site runs without ads — server and development costs are supported entirely by members like you. If it's been helpful, we'd be truly grateful for your support.

WHAT YOU'LL LEARN
A rounding and snapping design that assumes RoomPlan results drift 5-10cm by device, lighting, and hand motion, so you can lock in trustworthy dimensions
How to add a minimal shared-contract layer that exports dimensions to JSON on top of the Swift code Rork Max generates
Judgment criteria for a LiDAR-absent fallback that survives App Store review instead of getting rejected
Secure payment via Stripe · Cancel anytime

Unlock This Article

Get full access to the rest of this article. Buy once, read anytime. This site is ad-free — your support goes directly toward keeping it running.

or
Unlock all articles with Membership →
Share

Thank You for Reading

Rork Lab is ad-free, supported entirely by members like you. We publish practical guides daily with implementation code, benchmarks, and production-ready patterns. If you've found it useful, we'd love to have you on board.

  • Copy-paste ready implementation code
  • New advanced guides published daily
  • $5/mo or $10 for lifetime access
View Membership →

Related Articles

AI Models2026-06-23
On-Device Translation in a Rork Max App with iOS 18 — Free, Offline, Multilingual
Add free, offline, real-time translation to a Rork Max Swift app using the iOS 18 Translation framework. Covers checking language availability, batch translation, and avoiding empty results — all with working Swift code.
AI Models2026-03-10
How Claude Opus 4.6 Powers Rork Max's Development Engine
Discover how Claude Opus 4.6 and Anthropic's AI engine power Rork Max to generate native Swift apps in minutes.
Dev Tools2026-07-16
Regenerable Zones in Rork Max Code: Keeping the Freedom to Rebuild
Generated code carries an invisible asset: the option to throw it away and rebuild it. Every hand edit quietly expires that option. Here is how I track it with a ledger and CI checks across six live apps.
📚RECOMMENDED BOOKS
Build a Large Language Model (From Scratch)
Sebastian Raschka
LLM Dev
Prompt Engineering for LLMs
Berryman & Ziegler
Prompting
AI Engineering
Chip Huyen
AI Eng
* Contains affiliate links
See all →