This is a submission for the Hacktoberfest 2026 Open-Source AI Challenge, Week 1: "Touch Grass".
What I Built
In most of Brazil, "I'll go for a run later" isn't about frost or snow. It's about dodging a UV index of 11 at noon, a feels-like of 38 °C at 2 PM, and the thunderstorm that shows up at 5 PM almost every summer afternoon. The weather app has all of that data. It just doesn't tell you when to go.
Hina from Weathering With You could pray for a sunny window. The rest of us have to read the forecast.
Janela (Portuguese for window) does that for you. You give it a city, an activity (run, walk, bike, picnic, gardening, or an outdoor workout at the square's gym), how long you want to be out, and how many days ahead to look. It answers with:
- the best time window, plus two alternatives, each scored 0–100 with its feels-like temperature, UV, rain chance and wind;
- each day's comfort drawn as a tide, so you see at a glance when the day opens up and when it closes;
- a short explanation written by Gemma running on my own laptop, saying why that window wins, plus a tiny "touch grass" challenge for when you're out there.
It works in Portuguese and English (°F and mph in English), and searches are shareable links.
Every activity, in anime terms
| 🏃 Run | 🚶 Walk | 🚴 Bike |
|---|---|---|
![]() |
![]() |
![]() |
| 10–22 °C feels-like. Form not included. | Janela finds the window. Finding the park is on you. | Pick the cool hour, then draft behind your friends. |
| 🧺 Picnic | 🌱 Gardening | 💪 Square gym |
|---|---|---|
![]() |
![]() |
![]() |
| 18–28 °C feels-like. Bring enough for Goku. | Domain Expansion: Vegetable Garden. | The springtime of youth starts at 06:00. |
Lain lived in the Wired. Janela is for the rest of us, who occasionally need to log off.
Demo
How I Built It
city + activity ──▶ Spring Boot API ──▶ Open-Meteo (geocoding + hourly forecast)
│
▼
WindowScorer (plain Java, unit-tested)
│ top 3 windows, already ranked
▼
Ollama up? ── yes ──▶ Gemma writes the explanation
└── no ───▶ template writes it instead
Java computes, Gemma explains
This was the one rule I set before writing any code: the model never picks a time and never does math. Java is Senku here: it does the science. Gemma just presents the results.
Small models (I'm using gemma3:4b) are great at turning data into friendly sentences and bad at arithmetic. If I asked Gemma "when should I run in Recife tomorrow?" with a raw forecast, it would answer confidently, and sometimes wrongly.

A 4B model doing arithmetic: full confidence, questionable results.
So all the deciding happens in a deterministic domain:
- every daylight hour starts at 100 and loses points for rain chance, feels-like temperature outside the activity's range, and UV or wind above its limits (a run wants 10–22 °C feels-like, a picnic 18–28 °C);
- a window is the best run of consecutive hours covering your duration, and any hour below 40 rules the whole window out;
- the best window of each day is picked before repeating a day, and once the sun has set, "3 days" starts tomorrow instead of wasting today.
All of that is covered by JUnit tests (118 on the backend), with an injected Clock so "drop the hours that already passed" is testable too.
Pre-digesting the payload for a 4B model
The interesting part was learning what a small model needs to not make things up. My first prompts sent ISO timestamps and raw numbers, and Gemma would echo 2026-10-07T17:00, call UV 0.6 "high", and praise window #2.

gemma3:4b looking at UV 0.6, before I pre-digested the payload.
What fixed it was doing the interpreting in Java and letting the model only reword:
{
"best": {
"rating": "great",
"day": "Thursday, Oct 8",
"start": "06:00",
"end": "07:00",
"temperature": 83,
"comfort": "hot",
"uvIndex": 0,
"uvLevel": "low",
"rainChancePercent": 6,
"rainLevel": "low",
"wind": 5,
"reasons": ["before the day's heat peaks at 13:00"]
},
"alternative": { "rating": "fair", "day": "Friday, Oct 9", "start": "17:00", "end": "18:00", "…": "…" }
}
- day names and times are already formatted in the reader's language;
- numbers are rounded and converted (°F/mph in English) the way the UI shows them;
- the window's quality, temperature, UV and rain come with words (
ratingis the same word the screen shows next to the score, pluscomfort, the WHO UV category andrainLevel), so Gemma never decides what "hot", "low chance" or "ideal" means; -
reasonsare the window's advantages already worked out in Java from the day's outlook; the prompt tells Gemma to reword those and draw no conclusions of its own; - the score is left out on purpose, because the model kept quoting it;
- there are no ranks: the best window and one alternative go by name, because with a ranked list of three, Gemma mixed up the order, praised the wrong one and wrote "Rank 2" into the text.
The prompt then forbids the specific failures I saw in testing: inventing a beach or a park, saying "today" about a window two days out, writing JSON field names into the text, or describing a 33 °C afternoon as "pleasant".
A prompt is a request, not a guarantee, so Java also reads the reply before showing it. Any time it wasn't given, a 12-hour clock, a field name, an invented beach, "pleasant" for a hot hour, "ideal" for a fair window or a missing 🌿 line gets the reply rejected, and Gemma gets one more try with the mistake named. It usually fixes it, and on my laptop the retry costs 2–4 seconds.
If the second try still breaks a rule, or Ollama is off or slow (30 s timeout), a template writes the text and the UI labels it as such instead of pretending.
Stack
- Backend: Java 21, Spring Boot 4, Spring AI 2.0 with the Ollama starter, Clean Architecture (the use case is framework-free), API versioning with Spring Framework 7, Caffeine caches, OpenAPI docs
-
Model:
gemma3:4bvia Ollama, swappable with one env var - Weather: Open-Meteo forecast and geocoding (open data, no key)
- Frontend: React 19, TypeScript, Vite, TanStack Query, Tailwind 4, shadcn/ui on Base UI, a hand-drawn SVG tide chart
Why open innovation matters here
- It runs on a laptop. No API key, no account, no cost per question. Anyone can clone it and have it working in three commands.
- Your routine stays with you. Where you live and when you go out are exactly the kind of data I don't want to send to an AI cloud. With Gemma local, they don't leave the machine. To be honest about it: the forecast comes from Open-Meteo's open API, so that request does go out (just coordinates, no profile).
-
Swap the model with one variable.
OLLAMA_MODEL=gemma3:12band you're done. Open weights mean the app isn't tied to one vendor's pricing or deprecation schedule. - It works without AI. Because the AI only explains and never decides, turning it off loses the nice sentences, not the answer.
Prize Categories
Best Use of Gemma. Gemma 3 (4B) runs locally through Ollama and writes every recommendation, in Portuguese or English. The project is built around what a small open model is good at (language) and keeps it away from what it isn't (math and decisions).
Code
mauricioandrade
/
janela
🌿 Find your window to touch grass. Picks the best outdoor time for running, walking or cycling based on heat, UV and rain — explained by a local open-weight model (Gemma via Ollama). Java 21 + Spring AI. Built for Hacktoberfest 2026.
🌿 Janela
Find your window to touch grass.
Janela (Portuguese for window) finds the best time windows in the next few days for an outdoor activity — running, walking, cycling, a picnic, some gardening, a workout at the square's outdoor gym — based on what actually matters in a tropical climate heat, UV index, afternoon storms and wind.
Then a local open-weight model (Gemma, via Ollama) turns those numbers into a short, human recommendation and a tiny "touch grass" challenge. No API keys, no per-query costs, and it still works if the model is offline.
Built for the Hacktoberfest 2026 Open-Source AI Challenge: Week 1 — "Touch Grass".
Why
In much of Brazil, "go for a run" isn't about frost. It's about dodging a UV index of 11 at noon and the thunderstorm that shows up at 5 PM. Weather apps give you the data; Janela tells you…
Credits
Weather data by Open-Meteo (CC BY 4.0) · Gemma by Google · Spring AI and Ollama · Archivo typeface by Omnibus-Type · country flags from country-flag-icons, Brazilian state flags from Wikimedia Commons. Anime GIFs belong to their respective creators and studios.










Top comments (0)