DEV Community

Cover image for Nature Quest (pocket edition): Bring Mindfulness Outdoor.
Beon Cloud
Beon Cloud

Posted on

Nature Quest (pocket edition): Bring Mindfulness Outdoor.

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.

Nature Quest (pocket edition) is taking Gemma 4 E2B outside into the outdoor environment with no internet connection, fully Offline.

What I Built

Pocket Nature Quest is a fully offline Android field companion that turns one outdoor photo into a short Look · Listen · Move quest.

The idea is deliberately a little paradoxical: use AI on a phone to encourage someone to stop looking at their phone. Help user achieve wellness by observing their natural environment. The screen is only the starting point. A user takes a photo, optionally adds GPS context, chooses a time and energy level, and receives three simple actions to complete outside.

The app is designed for walkers, families, travelers, nature beginners, or anyone who wants a small push to notice their surroundings more carefully. It does not need Wi-Fi, an API key, web search, or online geocoding. The photo, coordinates, prompt, and generated quest stay on the device.

An accidental by design

This project began with a misunderstanding. My first prompt did not clearly explain the mobile, fully local application I had in mind, and my AI coding assistant moved too quickly into implementing a polished web prototype without first discussing the architecture with me.

I share responsibility for that. I had a design in mind, but I had not communicated it clearly. The assistant also should have paused for requirements plan and involved me before implementation. We effectively built the project twice.

That mistake became useful. It gave me two versions of the same product idea:

  • a fast web prototype using Gemini 3.6 Flash through an API; and
  • the actual challenge entry: a Flutter Android application running the open-weight Gemma 4 E2B model locally through LiteRT-LM.

The web version is not my challenge submission. I used it only as a comparison point while evaluating the local Android experience.

More importantly, the reset changed how I worked. I defined the requirements, selected the target device and local model, rejected web search and reverse geocoding, tested the application outdoors, evaluated its output, and reported the failures. The coding assistant acted as an implementation partner and mentor under those decisions. That process taught me as much as the final code.

Demo

Short Android demo

Pocket Nature Quest running on the Samsung Galaxy A25 with local, on-device Gemma inference.

Deck at Sunset Pier Boulevard PIK

Sunset Pier test scene 1: calm waterfront, shoreline plants, skyline, terraces, and white paper-boat sculptures.

Floral at Sunset Pier Boulevard PIK

Sunset Pier test scene 2: large floral cone sculptures on a wooden deck beside the water.

I took the app to Sunset Pier, a waterfront area beside a mangrove forest with space to walk, take photos, sit, dine, and drink coffee. This was the right kind of test: not a desk demo, but an actual walk where the generated quest had to match a real place.

Field results

I tested two photos with both versions. These are informal observations from one phone and two scenes, not a scientific benchmark.

Scene Settings Local Gemma 4 E2B Gemini 3.6 Flash web prototype
Waterfront and paper boats 15 minutes · Curious 1.5–2 minutes 2–3 seconds
Floral sculptures and deck 10 minutes · Gentle 1–1.5 minutes 2–3 seconds

For the first photo, local Gemma produced:

  1. Look — Observe the surface of the water. Notice that the water appears relatively calm with some ripples.
  2. Listen — Ambient sounds. Listen for sounds from the water or the surroundings.
  3. Move — Walk along the edge. Walk beside the landscaped foreground area.

For the second photo, local Gemma asked me to examine the colors and shapes of the floral arrangements, listen for water sounds, and walk slowly along the wooden deck.

The cloud model was much faster and its language was more specific. It noticed the paper-boat sculptures, shoreline plants, terraced sections, floral textures, railing, skyline, and changing perspective. Gemma's wording was stiffer and more general.

From the first photo, the cloud model produced

  1. Look - Compare Boat Sculptures and Shoreline Plants. Scan the calm water to locate the white paper-boat sculptures floating offshore. Then observe the green groundcover spreading across the shoreline rocks below the walkway wall.
  2. Listen - Tune In to Waterfront Sounds. Pause near the edge of the promenade and close your eyes for 30 seconds. Listen for the gentle lap of water against the embankment or birds along the shoreline foliage.
  3. Move - Trace the Terraced Pathway. Walk slowly along the upper paved deck toward the viewing area overlooking the floating boats, staying safely behind all railings and walls.

We can see that the cloud model produce more articulate output, but the local model succeeded at the part that mattered most to this experiment: it looked at a real photo, created a safe three-part activity, and did so without sending my photo or precise location anywhere.

That trade-off became my main lesson. “Better” does not mean only richer prose or lower latency. For a tool intended for trails, waterfronts, rural areas, or private family outings, offline availability and data ownership are also product features.

Code

GitHub logo beoncloud8 / week-1-touch-grass-android

Fully offline Flutter field companion powered by on-device Gemma 4 E2B

Pocket Nature Quest — Android

Pocket Nature Quest is a fully offline Flutter field companion for the Hacktoberfest 2026 Week 1 Touch Grass challenge. Take one outdoor photo and Gemma 4 E2B creates a short mission for your eyes, ears, and feet—without sending the photo or location to a server.

This repository is the Android application. The earlier web prototype remains a separate project and is not a runtime dependency.

Product flow

  1. Import a local gemma-4-E2B-it.litertlm model once.
  2. Take or choose an outdoor photo.
  3. Optionally add a place description and device GPS coordinates.
  4. Choose the available time and energy level.
  5. Generate a validated Look · Listen · Move field card locally.
  6. Start low-distraction field mode and put the phone down.

Why the model is not in Git or the APK

The E2B model is several gigabytes. Committing it would make the repository and APK impractical and would blur the model's…

The application source is MIT licensed. The Gemma model weights are not committed to Git or bundled in the APK; users select their separately downloaded .litertlm model on the phone.

The central inference flow lives behind LocalGemmaService, keeping model management out of the UI. The response must parse into exactly three distinct steps—Look, Listen, and Move—before the application displays it.

final model = await FlutterEdgeAi.getActiveModel(
  maxTokens: 2048,
  preferredBackend: PreferredBackend.gpu,
  preferredVisionBackend: PreferredBackend.gpu,
  supportImage: true,
  maxNumImages: 1,
);

final chat = await model.createChat(
  supportImage: true,
  systemInstruction: _systemInstruction,
  temperature: .35,
  topK: 32,
  maxOutputTokens: 700,
);
Enter fullscreen mode Exit fullscreen mode

How I Built It

The stack is intentionally small:

  • Flutter and Dart for the Android interface
  • Gemma 4 E2B, an open-weight multimodal model
  • LiteRT-LM through flutter_edge_ai and flutter_edge_ai_litertlm
  • image_picker for the camera and gallery
  • image for orientation correction and memory-conscious resizing
  • geolocator for optional raw coordinates
  • file_picker and path_provider for importing and preserving the local model

The flow is:

camera or gallery
      ↓
resize image to 768 px
      ↓
optional GPS coordinates + time + energy
      ↓
safety-first structured prompt
      ↓
Gemma 4 E2B via LiteRT-LM
      ↓
validate JSON as Look · Listen · Move
      ↓
low-distraction field card and timer
Enter fullscreen mode Exit fullscreen mode

The model prompt prohibits claims about uncertain species, edibility or medical advice, touching wildlife, trespassing, climbing, entering water, and leaving a safe path. Coordinates are treated only as context; the app performs no reverse geocoding.

A bug that only appeared on the second run

The first outdoor test worked, but reopening the application later produced:

Bad state: No active inference model set.
Use FlutterEdgeAi.installModel() first.
Enter fullscreen mode Exit fullscreen mode

The model file still existed. The problem was lifecycle and storage: the UI treated “a model file is listed” as equivalent to “the model is active,” and the imported 2.4 GB model was referenced through a temporary file-picker cache path.

I changed the app to copy the selected model into durable application storage, verify actual activation on startup, restore it when necessary, and block generation while preparation is still running. Then I installed the new APK over the old one, migrated the model, force-closed the app, reopened it, and verified that the active model pointed to the permanent path.

That failure was a useful reminder: a successful first inference is not the same as a reliable mobile application. Restart testing matters.

Why Does Open Innovation Matter?

The open model is not decoration in this project. It is the reason the Android version can exist as designed.

With Gemma 4 E2B running locally:

  • a walk can start somewhere with no mobile signal;
  • private photos never need to leave the phone;
  • raw GPS coordinates stay under the user's control;
  • there is no API key to expose and no per-request inference bill;
  • the inference layer and prompt can be inspected, changed, or replaced; and
  • the experience remains available even if a hosted service is unreachable.

The comparison also kept me honest about the costs. On my mid-range Galaxy A25, local inference took roughly one to two minutes, while Gemini returned more detailed writing in seconds. A compact edge model requires tighter prompts, patient UX, and realistic expectations.

For Pocket Nature Quest, I accept that cost because the application is meant to work outside—and because a photo of where someone is standing, combined with GPS coordinates, is exactly the kind of data that deserves a local-first option.

My Agent Session

I used Codex as a coding assistant and mentor during planning, implementation, debugging, and testing. I made the product decisions and evaluated the app on a physical phone outdoors; the assistant generated and revised significant parts of the code and helped diagnose the model lifecycle bug.

Building and Field-Testing Pocket Nature Quest with Local Gemma 4 E2B
You

I want to enter the Touch Grass challenge in the Best Use of Gemma category. Please involve me in the development and teach me as we work.

Agent

We began with a web prototype too quickly, before settling the requirements together.

You

I want an Android application that runs locally on my Samsung Galaxy A25, uses Flutter and Gemma 4 E2B, and works fully offline without web search or online geocoding. Let us plan before implementation.

Agent

We agreed on an offline architecture: camera or gallery input, optional raw GPS, a safety-first prompt, Gemma inference through LiteRT-LM, strict Look/Listen/Move JSON validation, and a low-distraction field mode.

You

The application works on my phone. The photo and GPS work, and Gemma creates quests, although its language is stiffer than the cloud prototype.

Agent

We treated that as a meaningful edge-versus-cloud trade-off: slower, less polished language in exchange for offline operation, privacy, and no API dependency.

You

On a later launch I received: Bad state: No active inference model set. Use FlutterEdgeAi.installModel() first.

Agent

I inspected the phone and found that the 2.4 GB model still existed and its metadata was present, but it was referenced through a temporary file-picker cache path. The UI checked only whether a model was listed, not whether it was active.

Agent

After the user approved the plan, I added durable application storage, startup reactivation, readiness checks, and progress UI. Analysis and tests passed; the APK was installed over the existing app; the model migrated; and a force-close/reopen test confirmed that the active identity pointed to permanent storage.

You

I tested two outdoor scenes at Sunset Pier. Local Gemma took roughly one to two minutes, while the Gemini web prototype took two to three seconds and used more specific language. The local app still succeeded privately and offline.

Agent

We turned those real-world observations into an honest challenge report that distinguishes the Gemini comparison prototype from the submitted, fully local Gemma Android application and discloses meaningful AI assistance.

Open the curated Agent Session on DEV

This article was drafted with meaningful AI assistance and reviewed against my own test notes and observations.

What I Learned

My biggest lesson was not a Flutter API. It was that requirements are part of programming.

When I did not explain the intended platform, constraints, and role of the local model, we produced the wrong thing—even though it was beautiful and functional. Once I wrote down those decisions and asked for a plan before implementation, I became more involved and learned more from the work.

I also learned that evaluating software in its real setting changes the conversation. At Sunset Pier I could see both the limitations of a small local model and the value of an application that continued to work privately, with no network dependency.

Next I would improve the prompt with a few examples to make Gemma's language warmer and less repetitive, add structured latency measurements over more scenes, and continue testing memory use on mid-range Android hardware.

Prize Categories

  • Best Use of Gemma

References

Top comments (1)

Collapse
 
suppdevbot profile image
Info Comment hidden by post author - thread only accessible via permalink
DEV SUPPORTS •
You need to verify your account.
Enter fullscreen mode Exit fullscreen mode

tr.ee/dev-to

Some comments have been hidden by the post's author - find out more