SCENE DEPTH · ARKIT · ON-DEVICE

VisiPallet.Spatial Intelligencefor Industrial Warehousing.

An on-device iOS system that counts and identifies every carton on a pallet with a hand-held iPhone — each label raycast into 3D world space, deduplicated by position and surface normal, and committed before the next camera frame. No network dependency anywhere in the scan path.

A hand holding an iPhone running the VisiPallet app, with an ARKit raycast overlay locking green and orange numbered targets onto cartons on a shrink-wrapped warehouse pallet
01The Problem

Built for the loading dock,not a demo table.

Standard barcode pipelines are tuned for retail: clean labels, fixed distance, controlled light. None of that exists on a warehouse floor. Specular glare compounds into a zero-observation failure  Vision's own DetectBarcodesRequest returns no observations at all, not a low-confidence one  and that's before gloves, thin cartons, and forced restarts enter the picture. 

01
Glare & Shrink-Wrap

Specular highlights clip the sensor to white, and Vision's own barcode and text requests return zero observations, not low-confidence ones. VisiPallet measures clipping directly in the sensor's luma plane and biases exposure at the hardware level before any software fallback runs.

02
Gloves

Every interactive control is at least 60 pt. There is no text entry anywhere in the scanning flow — text-only labels are taught by photographing one and tapping the value, never typing it.

03
Thin Cartons & Walk-Arounds

Identity is the 3D hit point and its surface normal, so the back label of a 6cm-thick carton is never swallowed by the front one as the operator circles the pallet.

04
Restarts

The ARKit world map is serialized on backgrounding, so a half-counted pallet relocalizes — exclusion zones intact — after the app is killed and relaunched.

05
Interoperability

A Scanner Gun mode streams codes over a custom Bluetooth LE service to a Mac or Windows receiver that types them into any spreadsheet, because iOS forbids third-party apps from presenting as HID keyboards.

Macro photo of a QR-coded shipping label under wrinkled stretch film — the specular streaks across the wrap are exactly what clips the sensor to white
OBSERVATIONS: 0
DetectBarcodesRequest
clipped_fraction: 0.94exposure_bias: -1.50 EV
Per-frame failure signature
Clipped luma fraction (glare)94%
Exposure bias applied (of -1.5 EV floor)87%
OCR crop vs. full frame area46%
02Vision Pipeline

Fix glare at the sensor never on the whole frame.

A clipped pixel carries no recoverable signal, so cloud OCR’s retry-until-it-works model doesn’t apply here. VisiPallet attacks specular glare in layers — measuring clipping in the sensor’s luma plane, biasing exposure at the hardware level, and only when that isn’t enough, filtering just the label region on the GPU before OCR runs.

visipallet@edge — glare.log
01GlareMeter.clippedFraction(roi: targetingRegion)
0232×32 luma sample → 0.61 clipped (≥ 250 full-range)
03GlareExposurePolicy.step() → bias -0.25 EV / 0.6s
04clipping still ≥ 4% → bias -1.50 EV (floor reached)
05CameraExposureController.setExposureBias(-1.50)
06DetectBarcodesRequest / RecognizeTextRequest → 0 observations
07isShrinkWrapMode = true → enhancedCrop(labelRect)
08CIContext(MTLCreateSystemDefaultDevice()) → ≤1600px, ≤50% frame
09RecognizeTextRequest(.accurate) on crop → 1 block, SKU recovered
//filtered pre-emptively under glare — never the full 4K frame.
Why the crop, not the frame

Filter pre-emptively, filter small

Sensor-level exposure bias buys back dynamic range for free, but on shrink-wrap under sodium overheads it isn’t always enough. Rather than filter the entire 4K sensor frame, VisiPallet crops the label rectangle out of a lazy CIImage before the exposure/contrast chain is attached, downscales it to 1600px, and renders on a Metal-backed CIContext with the software renderer disabled.

Research direction, not shipped — Appendix D of the architecture spec tracks treating clipped QR modules as Reed–Solomon erasures rather than hard errors — which would roughly double the recoverable error-correction budget. It requires a custom module sampler Vision doesn’t expose; production removes glare at the sensor and on the GPU instead.

Metal CIContext0 network calls
03Core Architecture

One coordinator.Zero shared state.

The scan pipeline is single-purpose services that never reference one another — a single coordinator is the only object permitted to call more than one.

Spatial Anti-Duplication

ARKit raycast · distance + surface normal

Every detected label is raycast from a 2D image point into a 3D world hit. A candidate is a duplicate only when it falls within 0.12m of a registered point and its surface normal agrees within cos 60° — so the back label of a thin carton, facing the opposite way, is never swallowed by the front one.

CAMERA0.12m radius · normal ≥ cos 60°frontbackdup rejectedopposite faces never merge
0.12m
default radius, 0.05–0.30 tunable
cos 60°
surface-normal agreement
O(n)
n ≤ ~500 per pallet

Teach-by-Tapping Calibration

Zero typing · 4-signal re-identification

Text-only cartons are taught, not typed: photograph one label, tap the SKU once. Every later carton is re-identified by four independent signals — shape, position, anchor caption, and a folded, confusable-aware signature match.

raw_ocr →
"PLT-OO482O"
fold() + confusables (O→0, I/L→1, S→5) →
"PLT-004820"shape 3.0 + sig 3.0 = 6.0 ✓
4
signals scored per match
≥ 4.0
acceptance threshold
0
characters ever typed

Custom BLE Scanner Gun

Custom GATT service · no HID available

iOS forbids third-party apps from presenting as a Bluetooth HID keyboard, so VisiPallet ships its own GATT service. A receiver on a Mac, Windows, or Linux box subscribes, reassembles records on the terminating \r, and types each one into any spreadsheet like a hardware gun would.

off → starting → advertising ⇄ connected(name)
MTU
chunked custom GATT service
⌘V
Universal Clipboard fallback

ARWorldMap Persistence

30s autosave · actor-backed store

ARKit assigns a new world origin at every launch, so the world map is serialized every 30 seconds, on backgrounding, and before Scanner Gun mode takes the camera. On relaunch, dedup points and their normals rehydrate immediately, then ARKit’s coordinate system is restored so already-placed billboards land correctly.

30s
autosave, excluded from iCloud
Restored
normals rehydrate on relaunch

Pallet Volume & CSV Export

EMA-smoothed CBM · RFC 4180

A bounding box grown from accepted scan positions and refined by nearby plane geometry estimates cubic volume, smoothed with an exponential moving average so the HUD settles instead of jittering. Sealed pallets export as CSV — SKU, quantity, GTIN, lot, world position, volume — via ShareLink.

α 0.2
EMA smoothing constant
Lockable
operator can freeze the estimate