This is the sixth post in the LocalPapa Notes dev-log series. The last few were about files, architecture and monetisation; this one returns to a tool itself — and one that best shows off "what a website can do that an AI chat can't": the Phone Sensor Dashboard.
Why this tool is special
You can ask an AI all sorts of questions, but you can't tell a chat conversation to read your phone's current tilt angle, the direction it's facing, or how hard you just shook it. That requires direct access to device hardware.
A browser can. Through the native DeviceMotion and DeviceOrientation APIs, a single web page can read live data from the accelerometer and gyroscope. We used them to build seven live panels: a level, a 3D device pose, a compass, a G-meter, shake detection, raw readouts and CSV recording.
And — as is the LocalPapa way — not one byte of this data leaves your phone.
The hard part isn't the physics — it's getting permission
The sensor maths isn't actually complicated. The real headache is the iOS permission flow.
Since iOS 13, for privacy reasons a web page can't silently read motion sensors — it must call DeviceMotionEvent.requestPermission() within a user gesture (a tap) to get authorisation. You can't request automatically on page load, or you're rejected outright.
So in the UI we deliberately built a "Start" button banner rather than demanding data the moment you arrive:
- Detect that
requestPermission is a function → it's iOS, show the start button, and only request permission and attach listeners at the moment the user taps.
- On Android / desktop we just try listening; if no
devicemotion event arrives within 1.5 seconds, we mark it unsupported and show a hint — so users don't stare at a blank page that will never move.
This is a classic case of "platform differences eat most of the hours": the core feature is a day's work; handling three platforms' permissions and fallbacks is the real job.
Turning raw data into readable gauges
Once you have beta / gamma / alpha and the three acceleration axes, each panel is a small conversion:
Level (bubble): map beta (front/back tilt, −90~90) to the bubble's Y offset and gamma (left/right tilt) to X, clamped within the circular container's radius. When the bubble is close enough to centre (< 0.08× radius), a green "level" lights up.
3D device pose: apply the CSS 3D transform rotateX(-beta) rotateY(gamma) directly to a phone-model div, so the on-screen model turns in real time with the phone in your hand.
Compass: use DeviceOrientation.alpha (north-referenced heading, 0~360) to rotate(-alpha) an SVG needle so it always points north.
G-meter: from the gravity-inclusive acceleration axes, compute the vector length √(x²+y²+z²) and divide by 9.81 to get G — about 1G at rest, over 2G when you swing it.
Shake detection: compare the gravity-vector length difference (delta) between consecutive events; if it exceeds 18 m/s² and more than 600ms has passed since the last detection, count one shake. Using both thresholds (magnitude and time gap) together avoids counting one continuous wobble as dozens.
A deliberate technical choice: no external libraries
The whole dashboard is built with pure CSS + SVG, with no external JS dependency beyond the shared tools-common.js.
Why? Because a sensor tool is most often used on a phone, sometimes with poor signal. No external dependencies means fast first load and offline operation — in a basement, up a mountain, it still works. This is the same consideration as the PDF tools' deliberate CDN lazy-loading, in a different context: always design for the real environment of use.
Later, it learned to "stream"
This dashboard kept growing: it gained the ability to stream sensor data live to a computer — over WebSocket, HTTP POST, even Web Serial (USB) wired transfer — sending JSON packets at a fixed rate (10/30/60Hz) to your own receiver, complete with a one-click-copy Python receiving script. GPS and a magnetometer came later too. But that's another story for another day.
What we learned
- Differentiation comes from "what only this platform can do." A browser can touch hardware directly — a structural advantage over AI chat. Doing it well is one of LocalPapa's moats.
- Platform permission differences are an invisible big project. iOS must request within a gesture; Android uses a timeout to detect non-support — these "edges" are what separate a good experience from a bad one.
- Zero dependencies is an offline promise. The more field- and mobile-oriented a tool, the more you should cut external dependencies.
- Local processing matters even more for sensors. Your motion, orientation and location are deeply personal data — they belong on your own device.
The same question, pushed further
This tool pushes the series' core question to a new edge: not just "can this be done in the browser," but "is there something only the browser can do?"
Reading your phone's senses, right now — the answer is yes, and that's exactly where a website beats a chat box.
In the next dev log, we step into that "streaming" story: how to turn a phone into a live sensor data source. Want to follow the series? Bookmark LocalPapa Notes.