A game at a shooting gallery costs about $5. The lane counts it, and that is the whole record. Nobody knows who played, so nobody comes back for a rank, and the operator cannot tell a regular from a walk-in.
What It Is
NeatoFX builds the hardware inside those galleries: IR hit detection with an onboard prop controller, event-triggered audio, touchscreen scoring displays, and a motor controller built for animatronics and moving props. Its founder is a friend of mine, and his lanes already count the games. NeatoFX Play is the identity layer that sits next to that count.
A player scans a printed QR code at the stall and signs up with a passkey. Email is optional. They get a dashboard of their points, offers and scores across every location they have played. At the counter they show a code. The attendant, signed in on the admin side, scans it to confirm who they are and that they paid. The lane does not know who is shooting. The scan is what attaches a name.
Who Sees What
The sale credits that store’s account, down to the individual stall. A store owner sees their own takings and games broken down the same way. A super admin sees every store. The public site shows leaderboards.
Payments are Stripe Connect destination charges through Stripe-hosted Checkout, so the money lands in each store’s own Stripe account and Play never touches a card. Sign-in is WebAuthn passkeys. A passkey is bound to one domain, so attaching a custom domain later means every player and every staff member registers again. That is a product constraint, and it decides the order the launch happens in. A player who may be under 13 gets a stable public alias instead of the name they typed, and cannot give an email.
Four Demos, Because the Hardware Is Not in the Room
The founder had to be able to see this without shipping a lane anywhere. So: a 56-second self-running tour on one screen, a fleet view across five fictional venues, a live in-browser sandbox running the real matching code, and a hardware lane driven by a USB arcade button through the Gamepad API. An ESP32 sketch and a Home Assistant package are the two integration paths. His installs report to his own server, and the bridge from that server to Play is specified rather than built.
One Seam, Three Backends
The domain logic runs behind a single storage interface with three implementations: Firestore, D1, and in-memory. That is why the backend could move from Firebase to Cloudflare without rewriting the product, and why the tests and the in-browser demo run the real matching code instead of a stub.
Verification: 203 unit tests pass. Seven Firestore rules tests have never run at all, because they need Java and I do not have it installed. Plus a six-role walk that passes 27 of 27 against the deployed backend rather than a mock. Passkey signup, attendant scan and cash payment, hardware ingest through Play’s own Node client, all three dashboards, leaderboards, and the negative cases.
Honest Constraints
Real Stripe has never run. There are no keys yet, so a purchase answers 503 by design. The camera scan has been proven against a fake video feed, not a real phone camera in a real hand. The ESP32 sketch has not been compiled. The bridge from the founder’s server to Play is still unbuilt, so nothing on his hardware makes Play’s request today.
And nothing is signed. This is a pitch with a working product behind it, and still not a partnership.
Stack
| Layer | Tool | Role |
|---|---|---|
| Frontend | Vite + React + TypeScript | One app, player and staff surfaces behind role checks |
| API | Cloudflare Pages Functions | Route contract written first, so five workstreams could build against it at once |
| Data | Cloudflare D1 | Ledger rows for every sale and every game: store, stall, lane, staff, player, offer |
| Auth | WebAuthn passkeys | Domain-bound, fails closed if the origin is unset |
| Payments | Stripe Connect | Destination charges, Stripe-hosted Checkout, no card data here |
| Testing | Vitest + Playwright | 203 passing unit tests (7 more need Java and have never run), and role walks driven against the deployed backend |





