This is a submission for the Hacktoberfest Open-Source AI Challenge Week 1: Touch Grass.
What I Built
The most useful button in GroundLens is “Take this mission outside.” It gives the screen a stopping point.
GroundLens learns a small color palette from an outdoor photo, lets you choose one color, and asks you to find it in two different places. A leaf and a stone. Bark in sunlight and bark in shadow. The task is to notice what a label would miss: light, texture, distance.
The intended audience is anyone who would enjoy a five-minute observation pause, including people who do not know the names of the plants around them. A garden, a courtyard or a nearby accessible outdoor spot is enough. The app does not require a long hike, species expertise, a camera permission or a GPS fix.
The interaction has three parts:
- Notice: choose a photo and inspect its locally learned colors.
- Leave: take one observation prompt outside and put the screen away.
- Keep: return with a sentence, optionally saved only on your device.
There are no streaks, points or notifications. Five minutes is a suggestion, not an achievement threshold. That is a design decision; I have not measured whether it reduces screen time.
Demo
For a quick walkthrough, use the clearly labeled synthetic garden already in the app. Choose a palette swatch, select Show learned regions, then Take this mission outside. Return with I'm back — capture one detail to try the local notebook. The initial illustration is a reproducible demo, not a photograph or a claimed field trial.
For your own scene, choose a JPG, PNG, WebP or AVIF image under 12 MB. The browser decodes it locally. The application does not upload the image or request your location.
The method panel includes Download the complete offline app + source. Extract it and open dist/index.html; there is no installation or inference service to configure. Local-storage behavior for files varies between browsers, so the notebook also offers JSON export.
Code
Apache-2.0. The project and repository were started on October 6, 2026 for this challenge. The learning engine is dist/model.js, the interface is dist/app.js, and numerical checks live in tests/model.test.cjs. There are no runtime packages or pretrained weights to download.
How I Built It
A model small enough to inspect
The core is classical unsupervised machine learning: k-means++ color clustering, implemented in open JavaScript. It is not a foundation model or a species recognizer. The model learns anew from each photograph; the learned centers determine both the palette and the optional segmented view.
The pipeline resizes the image to at most 720 pixels on its longest side and samples at most 6,500 pixels. RGB values are converted to CIELAB, where Euclidean distance is more useful for this color-reconstruction task than raw RGB distance.
Every fifth sampled pixel is held out. Three deterministic initializations—seeds 26, 91 and 2026—fit up to five clusters to the remaining pixels. The selected restart has the smallest training objective. Each restart has a maximum of 35 Lloyd iterations.
The app then predicts the held-out pixels by nearest center. It displays their mean ΔE76 error beside a simple baseline: reconstructing every pixel with the training mean color. This exposes what the model actually accomplished rather than attaching an unexplained confidence percentage to a photograph.
The observation sentence is a fixed template populated with the selected learned color. A small hand-written vocabulary supplies an approximate color name alongside its hex value. No language model invents a description of the scene.
What the tests establish
The same JavaScript model runs in the browser and in Node. Reproduce the numerical checks with:
node tests/model.test.cjs
Seven tests passed on Node v24.19.0. They cover RGB/Lab round trips, a known two-color mixture, a constant image, invalid inputs, deterministic optimization, exact split/proportion accounting and 30 seeded synthetic color mixtures.
Across those 30 mixtures, mean held-out reconstruction error was 3.97 ΔE76, compared with 41.88 for the single-mean baseline. All 30 cases improved on that deliberately simple baseline. Per-case results are included in tests/results.json.
That result has a narrow meaning: the implementation can recover clustered synthetic colors. It is not evidence of species accuracy, ecological insight, generalization to future photos or improved wellbeing. Nearby pixels are correlated, so even the within-image holdout shown in the app is a diagnostic, not an independent field-validation set.
Boundaries I kept visible
A nearly uniform picture triggers a low-variation message rather than a richer invented interpretation. Five clusters can miss small details. Lighting, exposure and camera processing change the palette. The segmented image has color regions, not identified objects.
No outdoor trial or user study has been performed. Browser interaction and WebMCP validation were unavailable in the static preview environment; model tests and JavaScript syntax checks passed. Those are remaining validation gaps, not tests silently counted as successful.
Why Does Open Innovation Matter?
For this project, openness is practical: the complete learning algorithm is short enough to read, change and run without asking a provider for access.
A teacher could replace the mission wording. A developer could compare sampling strategies or change the number of clusters. A privacy-conscious user can inspect the application and run the downloaded folder offline. The model has no credentials, quota or remote inference dependency.
Photos remain in memory. Only an explicitly saved text note, selected color and timing information enter device storage. The application has no analytics or network requests of its own; the hosted page still requires ordinary requests to its hosting provider. Downloading the bundle removes that hosting dependency for subsequent offline use.
The open implementation matters because learning colors locally is the whole interaction. If it disappears behind a paid inference endpoint, the app becomes less useful precisely where it is supposed to work: away from a desk, without having to send a private photograph anywhere.
Development Disclosure
An autonomous AI coding agent generated the implementation, tests, documentation and this write-up at my request. This is disclosed as Fully Autonomous. No human editing or human-run field experiment is claimed.
The algorithm follows k-means/Lloyd's iterative quantization and Arthur–Vassilvitskii k-means++ initialization, with sRGB/D65 CIELAB conversion. The implementation is newly written; no third-party source code or pretrained weights are bundled.
The entry is for the overall challenge. No partner-technology prize is claimed.
Top comments (0)