Eyespie (formerly Scouter) is a mobile version of the game “I Spy.” It started as a prototype, went through multiple rewrites, and is now evolving through an open source project.
The project management page tracks the current sprint and roadmap.
The Use Case
The core loop is supposed to be simple: one player captures an image, the app generates clues, and another player tries to find the matching object or scene. It is a social, low‑friction game that can run in a park, on a road trip, or on a hike with no reliable connection.
At a high level:
- Player 1 takes a picture of “the thing”
- The device generates clues via on‑device ML
- Player 2 takes a picture to guess based on the clues
- The app scores the match
The Current MVP (Re‑Scoped)
After multiple false starts, the MVP now focuses on the essential loop and removes anything that does not move the game forward. The flow looks like this:
Player 1:
- Select “new thing” from the dashboard
- Capture or upload an image
Device 1:
- Generate clues and embeddings
- Generate a mask image
- Make it available online
Player 2:
- Select the thing from the dashboard
- Capture or upload a guess
Device 2:
- Generate clues and embeddings
- Compare against the original
- Score the match
Dashboard:
- Action buttons
- A list of things and players
AI and Offline Play
The current version uses embeddings to match images, which makes clue quality less fragile. Text‑to‑image models can generate a mask image from clues.
All ML is on‑device and offline‑first for remote play. That decision is non‑negotiable for the use case, but it is also one of the hardest parts to get right.
Backend Direction
The backend is mostly offloaded to Supabase (PostgreSQL):
- PGVector for embedding search
- Realtime table sync across devices
- Object storage for user images
- Edge functions for background processing
- Authentication bundled
Kotlin Compose Multiplatform is the current target so the app can ship on Android, iOS, and web from one codebase.
What I Learned (The Hard Way)
1) Too much MVP
The initial MVP was too large in scope. I tried to include too many modes, features, and automation in the first release. That created a long runway, complicated testing, and a lot of rework.
2) Framework churn is expensive
This project has gone through multiple prototypes and frameworks:
- Native Android (first build)
- React Native (rewrite)
- Kotlin Multiplatform (current)
Each rewrite cost significant time and momentum. The product vision kept changing while the foundation kept moving.
3) Business use cases exploded
Even when the core game loop was stable, the business use cases expanded fast: classroom modes, events, team play, and monetization paths. That created fragmentation and analysis paralysis.
4) Backend costs and privacy mattered
I avoided Firebase because of long‑term cost and data privacy concerns. Sharing private images raised real questions about storage, retention, and consent. That pushed me into self‑hosting and infrastructure work, which slowed everything and delayed releases.
5) Offline support was the killer
The app needed to work in places with no internet connection. That meant relying on on‑device ML and offline‑first workflows. Device‑side models were too slow and too inaccurate for consistent gameplay, and syncing later introduced new edge cases.
Conclusion
I Spy is a simple human game with a deceptively complex implementation. The main lesson is to shrink scope, pick a platform early, and design around the hard constraints (offline, privacy, cost) from day one.
The concept still has promise. But it only works if the technical choices match how and where people actually play.