# Why everything runs on your phone > Why parking, sleep audio, and noise meters must compute on your phone — latency, privacy, and offline garages explained step by step. 2026-06-15 · 19 min read · privacy · by ntan (ntan) for uranashel Canonical HTML: https://uranashel.com/blog/on-device-first.html --- Most consumer software assumes a server in the middle: you sign in, telemetry goes up, machine learning runs in a data center, and state flows back through REST endpoints. For social feeds and collaborative documents that architecture is the right call. For parking dead reckoning, 48 kHz audio synthesis, and calibrated noise measurement it fits badly, and those are the three problems Wheria, Estua, and Sonarish work on every day. The phone in your pocket is not a thin client displaying someone else's computation; for our sensor apps, it is the computer. On-device-first means the entire pipeline executes locally. Sensors get sampled at hardware rates, estimates fused in real time, the interface rendered, history persisted inside the app sandbox. Phyzix follows the same rule: lab sessions and CSV exports stay on the device until you explicitly share them. Stashio is the deliberate exception, with optional cloud sync for anyone who wants bookmarks on a second phone while capture, indexing, and search keep working in airplane mode. Nobody here treats the rule as ideology. Three things force it: the physics of latency, the economics of privacy for a 3-person studio, and the places our users actually stand. ## The deadline arithmetic Wheria redraws your walked path after every detected step. At a normal pace footfalls land 0.5–0.7 s apart, and beneath them the IMU streams accelerometer and gyroscope samples at 50–200 Hz. The fusion filter has to ingest each measurement, propagate uncertainty, and redraw the polyline within a few milliseconds. A round trip from Saigon to a Singapore data center costs about 80 ms on a good day; the physical distance is roughly 1,100 km, fiber covers that in about 11 ms both ways, and the remaining 70 ms is queueing and radio scheduling. Compass heading arrives at 50 Hz, which leaves 20 ms between updates. Wi-Fi round-trip time alone consumes that entire allowance before any server-side Kalman filter gets a turn. Estua lives under a harder deadline. The render callback fires every 512 samples at 48 kHz, so each buffer must be filled within `512 / 48000 s ≈ 10.7 ms`, every callback, for hours. Miss one and the output carries a discontinuity the ear reports as a click. At 2 AM, with a listener finally asleep, a single click undoes the whole product. No practical path exists that POSTs PCM to a remote server and receives synthesized noise back inside 10.7 ms, which is why the full synthesis graph runs inside the callback under the no-malloc, no-locks discipline we wrote up in [life on the audio thread](https://uranashel.com/blog/dsp-audio-thread.html). Sonarish carries the same constraint on the capture side. Its FFT windows span 2048–4096 samples at 48 kHz, which is 43–85 ms of sound per transform, and a real-time spectrogram needs that transform running on the same device that owns the microphone HAL. Pushing raw audio upstream would insert a network hop into every column of pixels. The A-weighting filter that turns raw spectra into dB(A) is a fixed cascade and runs locally too. ## What a garage does to your radio The latency argument still assumes a link exists. Underground it usually does not. In June we logged connectivity across 40 garage descents on 6 phones (3 iPhone, 3 Android), pinging a Singapore endpoint every 2 s. Median LTE round trip at street level was 42 ms. At B1 it stretched to 310 ms with 38% packet loss. At B2 no usable link existed on 31 of the 40 descents. B2 is also where the cars are. An early Wheria prototype learned this the slow way. It streamed raw IMU frames over a WebSocket to a laptop so we could tune the step filter in Python, and at a desk the setup ran beautifully. One ramp below street level, the stream stalled every few seconds and the plotted path froze mid-turn. That afternoon the no-network rule went into the engineering notes. The pattern repeats far from garages. Sonarish users run noise surveys inside shielded factory halls where the cellular radio gives up before the machines do. Estua has to keep synthesizing through a 13-hour flight in airplane mode. Treating connectivity as optional keeps the apps working in the exact places people open them: underground, inside metal structures, at 3 AM when the household Wi-Fi is off. ktuyen's release checklist therefore includes a full offline garage walk before every release; if indoor navigation required a network handshake, it would fail the moment you descend the ramp. The sensors never notice any of this. Atmospheric pressure falls by about 12 Pa per metre of altitude near sea level, so one 3.2 m garage floor is worth roughly 38 Pa against a phone barometer noise floor of 0.3–1 Pa RMS, and the floor hint follows from `Δh = ΔP/(ρg)` with no server in the loop. The full derivation lives in [barometer floor math](https://uranashel.com/blog/barometer-parking-math.html). ## The phone is fast enough The classic argument for cloud offload was compute, and that argument quietly expired years ago. From our July bench notes: a 4096-point real FFT through Accelerate averages about 70 µs on an iPhone 12, and the same transform through KissFFT on a mid-range Snapdragon lands near 350 µs (each figure averaged over 10,000 transforms in release builds). Both sit 2–3 orders of magnitude below the 43–85 ms of audio the window represents. One Wheria EKF update over a handful of states is microseconds of matrix arithmetic. Steps arrive at walking cadence, under 3 Hz. Estua's per-sample work (a pink filter, a few biquads, some slow LFOs) occupies a low single-digit percentage of one core at 48 kHz. Power is the honest cost, and it stays modest. With the screen at half brightness and the IMU at 100 Hz, a find-my-car walk costs about 1% of battery over 4 minutes on the same 6 bench phones. The radio runs the other direction: a phone hunting for signal in a basement draws more power than one that has stopped trying, so staying offline underground actually saves battery. ## Privacy as a byproduct of the wiring The privacy story is mostly an absence. We never built the server-side infrastructure that could violate it, so there is no policy to audit and nothing to police. Wheria keeps parking coordinates, walked-path polylines, floor hints, and optional photos entirely inside the app sandbox, with no account and no upload queue behind the UI. The record that says floor B2, pillar E9 exists in one database file on one phone. Sonarish stores noise sessions, machine baselines, and exported spectrogram images locally by default. Estua remembers exactly two things about you: a scene preference and a random seed. The audio stream itself is never recorded unless you export it yourself. No third-party analytics SDKs ship in these applications, and crash reports flow through Apple's and Google's standard channels only. Model training on our servers does not happen, for the airtight reason that no servers collect accelerometer traces in the first place. Data that was never centralized cannot leak, and cannot be quietly repurposed when a company changes hands. ## The economics of not running servers There are three of us. A server-side sensor pipeline would mean an on-call rotation, database backups, API versioning, and a bill that arrives every month whether or not anyone parks a car. On-device compute is hardware the user already bought, so our marginal infrastructure cost per Wheria user rounds to zero. The Wheria server bill has never had an outage. Longevity is the quieter half of the argument. A sensor app whose processing lives on a startup's backend tends to die with the startup. An app whose entire pipeline is local keeps working years after release, even through a quarter where we ship nothing. atuan saves his backend effort for the one product where it earns its keep. ## The Stashio exception Stashio breaks the rule on purpose. A save-for-later tool earns trust when a link captured on the phone shows up on the tablet, so an optional account exists and atuan runs a small sync service behind it. The local-first spine stays intact: capture, indexing, and search all work in airplane mode, and the search index is built on the device before anything syncs. My own backlog holds about 2,400 links collected over four years; after three months of daily use, roughly 94% of retrieval attempts succeed in under 10 s, offline included. When sync is on, data travels as encrypted blobs. The sensor apps and Stashio sit at opposite ends of one decision, which makes [the Stashio post](https://uranashel.com/blog/stashio-second-brain.html) a useful mirror of this one. ## What we give up, in writing On-device-first has costs and we keep a written list of them. Cross-device sync for Wheria parking pins (carrying a garage walk from an iPhone to a Pixel without a manual export) remains unbuilt, because the encrypted sync layer has never reached the top of the queue. A community heatmap of parking availability would need everyone's positions on a server. Models that improve from pooled user data would need the pool. Competitors ship these features and they are genuinely useful; they also dismantle the latency and privacy properties that make a sensor app worth trusting. The standing trade is slower feature velocity in exchange for millisecond feedback, offline reliability, and data that stays on the phone until you choose to export it. For a 4-minute walk back to your car, that trade is correct. To see what the local computation actually does underground, continue with [indoor navigation when GPS dies](https://uranashel.com/blog/building-wheria-indoor.html); for the render-deadline discipline Estua shares with Sonarish, read [life on the audio thread](https://uranashel.com/blog/dsp-audio-thread.html). --- uranashel · [Home](https://uranashel.com/) · [Apps](https://uranashel.com/apps.html) · [Lab](https://uranashel.com/lab.html) · [About](https://uranashel.com/about.html) · [Blog](https://uranashel.com/blog/) · [Developers](https://uranashel.com/developers/) · [API docs](https://uranashel.com/docs/) · [Privacy](https://uranashel.com/privacy.html) Machine-readable: [llms.txt](https://uranashel.com/llms.txt) · [sitemap.xml](https://uranashel.com/sitemap.xml) · [openapi.json](https://uranashel.com/openapi.json) · [API](https://uranashel.com/api/v1/)