DEV Community

Jayant Jeet Tomar
Jayant Jeet Tomar

Posted on Edited on AI-assisted

4,271 plants, zero bars: BioDex, an offline Pokédex for the plants around you

Hacktoberfest Open-Source AI Challenge Week 1: Touch Grass Submission 🌿

This is a submission for the Hacktoberfest Open-Source AI Challenge Week 1: Touch Grass

What I Built

Hacktoberfest said “touch grass"... so I built an app that literally makes you do it.

Meet BioDex — an Android game where plants are your Pokémon cards. Snap a pic 🌿📸, wait a few seconds, and boom: you’ve got a collectible card with the plant’s name, rarity, and a fun little field note. XP, a daily streak, and a daily field mission push you to go find the next one. The only way to fill the Dex is to leave the house.

The screen is meant to be the shortest part of the walk: one photo, five seconds of waiting, then the phone goes back in your pocket. This Saturday morning I tried it for 30 minutes in my society’s park and collected 8 cards. It took me back to my biology classes, where we learned the scientific and common names of plants and animals. I used to remember so many of them, like Mangifera indica for mango. It was a nice flashback to my school days.

🌱 Features:

• Camera-based plant capture for collectible cards
• Learn scientific names and common names of flora
• Rarity system (S‑rank, rare, common) for added challenge
• Offline gameplay — no internet required (apart from downloading the model on first run)
• Educational yet fun: explore, collect, and build your own flora deck
• Safe and private: no personal data collected or shared

Demo

A short screen recording shows BioDex in action:

🎮Try it

Code

Everything lives in one repo: the Android app, the model export script, and the Gemma note generator.

BioDex

BioDex is an Android-first, offline plant-collector MVP built with Kotlin, Jetpack Compose, CameraX, and the official Imageomics BioCLIP 2.5 ViT-H/14 image encoder. Capture a plant photo, find its closest match in a 4,271-species field guide, generate a field card, save it locally, and share the PNG.

Run

Prepare the official model

The app uses the official checkpoint, not the smaller distilled student. The upstream OpenCLIP/PyTorch checkpoint is about 3.94 GB. Before building the app:

  1. Install Python 3.13 and create the project environment with py -3.13 -m venv .venv.
  2. Install the model-export dependencies: .venv\Scripts\python.exe -m pip install -r scripts\requirements-bioclip-export.txt.
  3. Run .venv\Scripts\python.exe scripts\export-bioclip-25-onnx.py.

The exporter verifies the existing 4,271-label embedding table against its published SHA-256 (the model author identifies it as the teacher's text-embedding space), downloads the checkpoint at a pinned Hugging Face revision, exports an FP16 ONNX image encoder, and verifies its output against OpenCLIP and…

How I Built It

BioDex is a Kotlin app: Jetpack Compose for the UI, CameraX for the camera, ONNX Runtime for the model. The interesting part is what the model is and where each half of it runs.

BioCLIP, split in half. Only the image encoder runs on the phone. The 4,271 plant names were turned into embeddings ahead of time and ship as a table. At runtime, a photo becomes a vector, which is compared against that table with cosine similarity. The closest match becomes your card.

Gemma at build time. Gemma 4 E4B, running locally through Ollama, wrote a common name and a short field note for all 4,271 plants, once, with a resumable script. No language model runs on the phone. The notes describe the species, not your photo, and they can be wrong.

Shipping releases. I run a GitHub Actions workflow manually and choose whether the change is a patch, a minor or a major release. It bumps the version, then builds a signed AAB for the Play Store and a signed APK for sharing locally, such as the v1.1.3 link above.

🤦Things that went wrong (lol)

Testing on my own phone turned up two problems:

1. Random objects came back as plants. I photographed things that weren’t plants at all, and BioDex still returned the closest plant in the guide. Similarity always finds a nearest neighbour. I fixed it with a minimum cosine-similarity threshold of 0.45, so below that BioDex says it doesn’t recognise the photo.

2. Plain-looking plants give false matches. If the plant shows no distinguishing features, such as leaves and small buds but no recognisable flower, the model can still return a confident-looking wrong species. The threshold doesn’t catch this, because the photo is plant-like enough to pass. The similarity score isn’t a confidence level, so BioDex treats it as a suggestion, never a verdict.

Other rough edges:

  • Specimen #0001: the note said small pale flowers, and my photo was full of pink ones.
  • Plants only. Animals and fungi aren’t in the guide, and a plant that isn’t listed can only come back as its closest cousin.
  • Never use BioDex to decide whether a plant is edible, poisonous or medicinal.

Why Does Open Innovation Matter?

On the trail Open (BioCLIP, ONNX Runtime) Hosted vision API
No signal Works after one model download A spinner
Photos of your garden or kids Stay on the phone Uploaded
Cost No per-photo fee or API key Per call
Reproducibility Pinned revision, verified checksums, swappable encoder Can change underneath you

Where closed would have won. A hosted model would probably know far more than 4,271 plants, handle animals and fungi too, and wouldn't need 1.26 GB of my phone. Open cost me storage, RAM and one very long export script instead of money and privacy. For a game whose whole point is walking somewhere without signal, I'd make that trade again.

I also didn't have to invent any of the hard parts. The Imageomics Institute trained and open-sourced the model, Nate Hamilton published a plant list and embeddings I could build on, Google's Gemma wrote the notes, and ONNX Runtime ran the whole thing on a phone. I wired them together and put a card game on top. That's open innovation at hobby scale.

Prize Categories

Best Use of Gemma. Gemma 4 (E4B), running locally through Ollama, wrote the common name and field note for all 4,271 plants. It runs at build time, not on the phone, and the generator is a resumable script in the repo.

Best Use of GitHub Copilot. I used Copilot to generate the GitHub Actions workflow that prepares releases. I choose patch, minor or major, and it versions the app and builds a signed AAB and APK, so each release is one click to publish to the Play Store or share locally.

Top comments (3)

Collapse
 
ssapable profile image
ssapable •

Shipping only the image half of BioCLIP and letting 4,271 precomputed name embeddings do the "reading" is the cleverest on-device trick I've seen this week, and "the note says small pale flowers, my photo is full of pink ones" plus a README that says the notes can be wrong is the honesty that makes me trust the rest. I turned the post into a 90-second hand-drawn cartoon: the card, the 3.94 GB to 1.26 GB export, the 0.45 "says so instead of inventing a plant" line, and the pink-flower trade-off. No strings, yours to use or ignore, on a plain page with no sign-up:

ssap-pa.github.io/scripttoon-samples/

If any detail is off, say which shot and I'll re-render it. One question: on your phone, how long does the single forward pass of the 1.26 GB encoder take per photo?

Collapse
 
halfbloodcoder profile image
Jayant Jeet Tomar •

Thanks for taking the time to render that animated explanation — it really brings the write‑up to life.

And yes, your summary is accurate. In my own testing, the forward pass on the 1.26 GB encoder averages about 4–5 seconds per photo on a Galaxy S24 Ultra, while other Android devices used by members of closed testers tend to be in the 7–8 second range.

I’m glad the on‑device performance is holding up well; it’s encouraging to see the community validating these results.

Collapse
 
ssapable profile image
ssapable •

Thank you for the numbers: 4 to 5 seconds on an S24 Ultra and 7 to 8 on the other testers' phones is a real answer, and honestly better than I'd have guessed for 632 million weights per photo. Glad the shots held up.