This is a submission for the Hacktoberfest Open-Source AI Challenge Week 1: Touch Grass
What I Built
Sprout is a creature that lives on your phone and starves indoors.
It's a Tamagotchi with one rule: it only eats things that exist outside. Hold your phone up to real sunlight and it drinks. Point the camera at actual grass and it eats. Carry it on a walk and it perks up. Shake it awake and it tells you — groggily — about the dream it just lost. Every word it speaks is generated on-device by Gemma 4, an open-weight model running inside the app. There is no server. In a forest with zero bars of signal, the creature still talks back.
It also refuses to let you cheat the theme:
- Indoor lamps and bright windowsills don't count as sun — the ambient light sensor only banks "drinks" above outdoor-class lux.
- A photo of a green wall gets rejected by a pixel classifier before the AI ever sees it.
- Leave the phone in a sunny window and walk away? Nothing happens. Sunlight only counts toward growth while you're actually engaged with the creature — it can't evolve alone.
Who is it for? Anyone whose screen time is beating their outside time. The shortest path to keeping Sprout alive is to put on shoes.
Demo
▶ Video demo: https://drive.google.com/file/d/1c7aG0o_WBRdop3rcMKDgyWcqQPEbmjhC
Code
GitHub repo:
Sprout
A creature that needs you to go outside. On-device AI, sunlight detection, grass verification.
Built for Hacktoberfest 2026 — Week 1: Touch Grass.
What it is
Sprout is a small creature that lives on your phone. It hatches from an egg, then survives on two things:
-
Sunlight — detected by the Android ambient light sensor (
TYPE_LIGHT), no camera needed - Grass — confirmed by a green-pixel HSV classifier, with Gemma vision as a borderline arbiter
Every line the creature speaks — its greeting, its gratitude, its confusion when you show it something that isn't grass — is generated on-device by Gemma 4 E2B running locally through LiteRT-LM. No network call, no API key, no data leaves the device.
Why open-source AI
- Private by design: photos of your environment, your outdoor habits, your streak — nothing leaves the device
- Offline: the creature works in a forest…
MIT licensed. Requires Android API 30+ (arm64).
How I Built It
Sprout is a Flutter app, but the interesting parts are three systems that never touch the network.
The body: physical detection
Everything the creature senses comes straight from the phone's hardware — I wrote my own Kotlin EventChannels instead of pulling sensor plugins:
-
Sunlight — Android
TYPE_LIGHTambient sensor. The feed threshold is 5,000 lux, deliberately above indoor bulbs (~200–800) and bright windows (~1–3k); only genuinely outdoor light counts. Charge builds in 3-second "drinks" at a 10 Hz tick, and a passing shadow drains the bar at 40% speed instead of wiping it — sustained darkness still does. - Shake — accelerometer magnitude over 2.5 g, with a 900 ms cooldown so one physical shake doesn't fire fifty events. A rough wake: the creature stirs, but the dream it was having is gone.
- Tilt — a low-pass filter over the same accelerometer broadcast pulls gravity out of the noise and emits lateral lean (-1..1). Tilt it sideways and the creature complains.
-
Walking —
TYPE_STEP_DETECTORemits one event per step; carrying it outside counts as care. - Grass — camera photos are downscaled to 64×64 and scored by a pure-statistics HSV classifier: hue 60–160°, saturation > 0.25, value > 0.20. ≥40% green pixels passes, <20% fails, and the grey zone in between goes to the model. An md5 of the photo blocks re-feeding the same patch twice.
The mind: a local, open-weight model
Every line of dialogue — the hatch moment, the morning greeting keyed to its energy/hunger/stage/streak/mood, gratitude after a drink of sun, confusion at a rejected photo, dreams, dizziness, songs — comes from Gemma 4 E2B running locally through LiteRT-LM (flutter_edge_ai). No API key, no network call, ~40–80 tokens per line under a character system prompt, a fresh session per call so prompts never accumulate.
Two places go beyond text:
-
Function calling. Periodically the creature is asked what it wants — Gemma picks a native tool call:
demand_sunlight,request_grass,request_walk,sing,nap,ask, orinvent_quest, which lets it author a small real-world quest ("find something round and alive") that it later verifies itself. -
Vision. The borderline grass verdict and
judgePhoto— a yes/no check of a photo against a verification prompt the creature invented — run the model's vision modality with an 8-token cap.
The model is downloadable, not hardcoded
A first-run Model Manager screen pulls the ~2.4 GB gemma-4-E2B-it.litertlm from the ungated Hugging Face litert-community mirror — resumable progress, cancel, and a foreground service so Android's background limit can't kill the download. You can also sideload any .litertlm file through a file picker, which means a fine-tuned creature personality is a file swap away. Until the model lands, a deterministic FakeGemmaClient keeps the whole game playable — and keeps the test suite model-free.
State, care logs, quest progress, and stage history persist in sqflite. Evolution runs on trials: a couple of feeds plus a completed real-world quest, or roughly nine seconds of honest sunlight.
| Layer | Tech |
|---|---|
| App | Flutter 3.44.5 / Dart 3.12.2 |
| AI | Gemma 4 E2B .litertlm via flutter_edge_ai (LiteRT-LM) |
| Lux sensor | Custom Kotlin EventChannel → TYPE_LIGHT
|
| Grass gate | Custom HSV classifier, ~0 ms, no ML |
| Storage | sqflite |
| Camera |
camera + image_picker + image
|
Why Does Open Innovation Matter?
A creature whose whole job is sending you outside cannot depend on a network — that's the premise. Open weights make the premise real:
- Offline where it matters. The app works in a forest, on a mountain, in a dead zone — exactly the places it sends you. A closed API would brick its voice the moment you left coverage.
- Private by design. Photos of your yard, your walking habits, your streak — none of it leaves the device, because there is nowhere to send it.
-
Inspectable and swappable. The brain is a
.litertlmfile you can audit, swap, or fine-tune into a different personality — the file-picker import exists precisely so someone can ship their own. - Zero marginal cost. It can nag you to go outside forever, for free. No API bill scaling with how needy the creature gets.
Prize Categories
- Best Use of Gemma — Gemma 4 E2B is the creature's entire voice, decision-maker, and vision arbiter, running fully on-device via LiteRT-LM.
Built with ❤️ by Musaddiq625
Top comments (2)
Some comments may only be visible to logged-in visitors. Sign in to view all comments. Some comments have been hidden by the post's author - find out more