A Speed Gun That Would Rather Say Nothing: What Building Paceball Taught Me About False Precision
I'm Abdulbasit, 19, from Rawalpindi. For the last month, I've been building Paceball, an Android app 2026-10-1 20:57:19 Author: hackernoon.com(查看原文) 阅读量:6 收藏

I'm Abdulbasit, 19, from Rawalpindi. For the last month, I've been building Paceball, an Android app that measures how fast a cricket ball is bowled using nothing but a phone video. No radar, no sensors, no hardware. You film a delivery side-on, mark a known length in the frame (usually the two sets of stumps, 20.12 m apart), mark where the ball left the hand and where it bounced, and the app works out the speed from the distance and the frame count.

It's my first mobile app. I'm building it with my partner Mustafa, the lead developer after me, for RevenueCat's Shipaton 2026, and this is the story of the second half, the part where the maths was mostly done and everything else tried to break.

The rule that shaped the whole app

Early on, a real test at the nets went wrong in a quiet way. The ball was invisible at the bounce; I guessed where it landed, and the app happily gave me a clean, believable number.

That number was fiction. And the worst part was that it looked exactly like a real one.

So Paceball got a rule that everything else now bends around: if the bounce wasn't actually seen, there is no speed. Not a zero, not a dash in a big font, not a greyed-out guess. The app says "No speed measured", keeps the video and the marks, and moves on.

The second rule came from the same place. A speed is never shown without its error range. Every reading carries a range built from the frame timing, the length of the reference, and how precisely each point was tapped. A delivery isn't "128.4 km/h". It's 128.4 km/h plus or minus whatever the footage can actually support. If you can't show the range, you can't show the number.

Those two rules sound small. They ended up deciding the design, the paywall, the share card and even the animations.

Money: RevenueCat, and a Play Store lesson I paid for

Shipaton is a RevenueCat hackathon, so purchases had to be real. The setup itself was straightforward: one entitlement called pro, one offering, a monthly plan at $3.99 and an annual plan at $24.99 with a 7-day free trial on the annual only. Free users get 3 analyses a week, anchored to the day of their first ever analysis, shared across every player profile on the phone.

The paywall was more interesting than the plumbing. I watched a RevenueCat livestream with their paywall designer, and a few of her rules went straight into the app:

  • Never "Upgrade to Pro" or "Subscribe". The button says what happens: "Start my 7 days free".
  • If there's a trial, it should be loud, not grey small print.
  • The dismiss button names what you give up: "Continue with the watermark", not "Not now".
  • Prices readable, but not the hero, and never shown twice.

Then came the lesson I didn't expect. Purchases kept failing with ITEM_UNAVAILABLE. The code was fine. The problem was that I was testing on an APK I'd installed by hand. Google Play billing only works properly when the app was installed from Play itself. Once I tested on a build from the internal track, buy, restore, cancel, expire and re-buy all worked.

The same mistake cost me more elsewhere. I'd sent our closed testers a direct APK link instead of the Play opt-in link. Their usage never counted, so when I applied for production access, Google declined it and asked for another 14 days of closed testing. That pushed the public release past the Shipaton deadline and narrowed us down to one category, the Next Gen award for student builders. If you're doing closed testing for the first time: testers have to install from Play, through the opt-in link, or it doesn't count.

The bug that lived in the audio track

For a while, speeds on some clips were slightly off, in a way that was hard to pin down. The cause turned out to be almost funny.

To get the frame rate, the app was dividing the number of frames by the duration of the video file. But the file's duration includes every track, and the audio track often runs a little longer than the video. So the "duration" was too long, the frame rate came out too low, and every speed calculated from it drifted.

The fix was to read the duration of the video track alone, in the native Kotlin frame extractor, instead of the container. It's a one-line idea that took a lot longer to find than to fix, and it's the kind of error that would never show up in a demo but would quietly make every reading a bit wrong.

Auditing my own app

Before the design phase, I ran a full audit of the codebase with Claude Code, which has been doing most of the actual typing on this project while I review, decide and test. It came back with 21 commits of fixes and the test suite at 245 passing tests. A few of the findings were genuinely scary in hindsight:

  • A build with a real store key could show sample prices next to a live buy button.
  • The weekly free allowance was counted per player, so adding a second profile quietly doubled it.
  • A debug screen was reachable in release builds.

None of these would have shown up in normal testing. All of them would have shown up to a judge.

Designing around honesty

The design phase started with a brief from ChatGPT and a mockup sheet, which I then checked line by line against the actual repo. About a third of it had to go. It rewrote the measurement maths, changed how the free allowance worked, and invented features I'd explicitly ruled out. Good design ideas, wrong app.

What survived is a calm, flat, black-and-lime look where numbers are the hero and lime only appears when it means something. The part I care about most is the reveal on the Result screen. The number counts up from zero to the measured speed and never overshoots, not even for a single frame, because an overshoot would briefly show a speed faster than what was measured. The range is on screen from the first frame, so the number is never alone. When the count lands, a small set of stumps locks into place with a bail dropping, and that's the moment the reading turns lime.

The line drawn between release and bounce is straight on purpose, labelled "Marked, not tracked". A curve would look nicer. It would also draw a flight path nobody measured.

Even here the honesty rule found bugs. On my phone the counter reached the speed and then, a second later, dropped back to zero. A number that shows up and disappears is its own kind of dishonest, so that's the first fix on the list, along with turning the reveal into a proper speedometer.

When the builds ran out

With four days to go, I hit the free monthly build limit on Expo's cloud service. The reset date was after the deadline.

Instead of paying, I moved the builds to Codemagic, running Expo's local build command on their free machines. It still pulls the signing key and settings from Expo, so the app is signed exactly like before and Play accepts it as an update. It took a few tries:

  • My RevenueCat key was stored as a "Secret" on Expo, which only Expo's own servers can read. A local build on another machine never saw it, which would have shipped a paywall that can't sell anything. It had to be added to Codemagic separately.
  • The first builds failed at the very last step, when the Sentry plugin tried to upload source maps without an auth token. Adding the token fixed it.

Small things, but each one would have been a disaster the night before submission instead of four days out.

What I'd tell someone starting their first app

  1. Decide what your app refuses to do. Paceball's best feature is the number it won't show.
  2. Install from the store early. Billing and closed testing both assume it.
  3. Test on the real device, constantly. Every screen in this redesign was written without anyone seeing it run. The phone found the counter bug in thirty seconds.
  4. Audit before you polish. Design makes bugs prettier, not rarer.
  5. Plan your build pipeline before you need it. Running out of builds four days before a deadline is a bad time to learn a new CI tool.

Paceball is in closed testing on Google Play right now, and the code is public under the MIT licence here.

If you bowl, or coach someone who does, I'd love for you to try it and tell me where the numbers feel wrong.


文章来源: https://hackernoon.com/a-speed-gun-that-would-rather-say-nothing-what-building-paceball-taught-me-about-false-precision?source=rss
如有侵权请联系:admin#unsafe.sh