This is a submission for the Hacktoberfest Open-Source AI Challenge Week 1: Touch Grass
What I Built
We all know the four "happy chemicals": Dopamine, Oxytocin, Serotonin and Endorphins. The phone has figured out how to hand out cheap dopamine on demand, so we keep coming back to it. DOSE turns that around: you tell it which feeling you're short on, and it sends you outside to get it the real way.
How it works:
- Pick a chemical. Dopamine (achievement, novelty), Oxytocin (connection), Serotonin (calm, sunlight) or Endorphins (movement). There's also Surprise me.
- Get a challenge. Choose one from a library of 48 hand-written outdoor challenges, or ask the AI coach. You tell it where you are, who you're with, how much energy you have and how many minutes you've got (it can also take the current weather), and Gemma 3, running locally in your browser, writes a 15–45 minute challenge for that exact moment.
- Put the phone away. A timer runs with a chime and vibration at the end. DOSE also counts "screen peeks", meaning how often you opened the app during the challenge.
- Reflect. You get a fun fact about the chemical, a short journal questionnaire, and an optional reflection that Gemma writes from your answers.
- Watch the ratio. The journal tracks your grass vs. screen ratio over time.
Who it's for: anyone who has caught themselves scrolling and thought "I should really go outside" without knowing what to actually do once they got there. DOSE gives you one small, specific thing to do, and then it gets out of your way.
The app is built so that the screen is the shortest part of the experience: about 30 seconds to get a challenge, then 15–45 minutes outside.
I took it outside 🌱
To test it, I picked Serotonin, chose a short session, and asked the coach for a challenge. Gemma came back with this:
Go out onto the grass and pick up a stone. Hold it, notice every sensation it gives you: its weight, temperature, texture. Let your thoughts go and focus only on its structure and beauty for 15 minutes.
It sounded almost too simple. It turned out to be one of the most satisfying 15 minutes of my week.
The stone was smooth on one side and rough on the other, with tiny ridges I'd never have noticed if I'd been looking at a screen. It's strange that an object with no life in it, which has been lying in the same spot for who knows how long, can pass some kind of energy on to your mind and body. Focusing on its texture and smoothness slowly crowded out everything else I'd been thinking about. When the chime went off, I felt calm and honestly a little joyful.
Back inside, I filled in the journal questionnaire and asked Gemma for a reflection. It picked up on what I'd written and gave me useful feedback about why the challenge worked for me. What stayed with me most is that this whole loop ran on my own laptop, offline, with an open model. None of my thoughts about the stone, my mood or my journal went to anyone's server.
Demo
🔗 Live app: https://dose-touch-grass.vercel.app/
To try the AI coach you need a WebGPU browser: desktop Chrome/Edge 113+ or Android Chrome 121+. The first time, it downloads the model (about 700 MB). After that it loads from the cache in a few seconds and works offline. In browsers without WebGPU, the full challenge library, timer and journal still work.
Code
🌱 DOSE: Touch Grass
An on-device AI coach that gets you off your phone and outside.
Pick the feel-good chemical you're craving (Dopamine, Oxytocin, Serotonin or Endorphins), and DOSE gives you a short screen-free challenge to do outdoors. A timer runs while you're out, and a private journal keeps track of how it went.
The coach is Gemma 3 1B running entirely in your browser through WebGPU. There are no API keys, no server and no account, and your journal never leaves your device.
Built for the DEV Hacktoberfest Open-Source AI Challenge, Week 1: Touch Grass ·
#hf26challenge
Live demo: add your Vercel URL here · Write-up: add your DEV post here
Why open-source AI?
An app that wants you to put your phone down shouldn't send your mood journal to a cloud API.
- Private: inference runs locally, so your mood, energy and journal…
How I Built It
The open-source AI stack:
-
Gemma 3 1B Instruct (
gemma3-1b-it-q4f16_1-MLC), quantized to 4 bits, about 700 MB. - WebLLM from MLC runs the model in the browser on WebGPU, inside a Web Worker so the UI never freezes.
-
Next.js 16, Tailwind v4, shadcn/ui and zustand. There's no backend at all: the journal lives in
localStorage, and a service worker caches the app shell for offline use. - Open-Meteo (also open source) adds optional weather context, with coordinates rounded before the request.
pick chemical ─► CoachPanel ─► engine.ts ──postMessage──► llm.worker.ts
▲ │ WebLLM + Gemma 3 1B
│ ▼ (WebGPU)
parse + validate (prompts.ts) ◄── streamed tokens
Making a 1B model behave in a browser
Getting Gemma to load was the easy part. Getting it to behave was the real work. Some of what I learned:
1. One config flag made all the difference. WebLLM's prebuilt Gemma 3 record sets a 4096-token context window, but the model uses a 512-token sliding window, and WebLLM rejects having both. My first fix was to disable the sliding window. The model loaded, but it rambled endlessly, never emitted end-of-turn, and wrote several JSON objects in a row. The right fix is to keep the sliding window Gemma 3 was trained with and drop the fixed context:
{ context_window_size: -1, sliding_window_size: 512, attention_sink_size: 0 }
That one change took the output from garbage to coherent.
2. JSON mode works against small models. Under WebLLM's JSON-schema grammar, Gemma 1B padded whitespace until it hit max_tokens and never closed the object. It also kept leaving out the steps array. So I dropped JSON and asked for plain lines instead:
Title: ...
Description: ...
1. ...
2. ...
3. ...
A tolerant parser accepts **Title:**, Step 1:, inline Steps: 1. … 2. … and other variations, and keeps a JSON salvage path as a fallback. As soon as step 3 is complete, generation is interrupted, so there's no rambling afterward.
3. A validator rejects off-theme output. Any challenge that mentions screens, phones or apps is rejected, and the coach retries automatically. A coach that tells you to "open a meditation app" would defeat the whole point.
4. The UI must never spin forever. On my Intel Iris Xe laptop I hit DXGI_ERROR_DEVICE_HUNG. WebLLM then unloads the model, and any pending generation waits forever. So:
- each attempt has a 90 s timeout, then
interruptGenerate(), then a hard reset that terminates the worker and reloads from the cache; - the worker wraps
GPUAdapter.prototype.requestDeviceto watchdevice.lostand broadcasts it on aBroadcastChannel, so the UI can show a clear error right away instead of hanging.
5. Shader warm-up. A 4-token generation followed by resetChat() after load makes the first real request noticeably faster.
On an integrated Iris Xe GPU this runs at about 5 tokens/s, so a full challenge takes 20–35 seconds. The live preview of the title as it streams in makes that wait feel short.
What's next
The README has an honest roadmap. Gemma 1B sometimes writes a challenge that fits its chemical only loosely, occasionally names the wrong chemical in the text, and my length caps can cut a sentence off mid-thought. Next up: few-shot examples per chemical, trimming at sentence boundaries instead of character limits, a validator that catches the wrong chemical, and an opt-in "quality mode" with a bigger Gemma on capable GPUs.
Why Does Open Innovation Matter?
For this app, a closed API would have been the wrong tool:
- Privacy is the product. DOSE asks how you feel, where you are, who you're with, and has you write a journal about it. That's some of the most personal data there is. With an open-weight model running in the browser, none of it leaves your device. There's no account, no server and no logs.
- It works where it's needed. The point is to go outside, often to places with bad or no signal. Once Gemma is cached, the coach works completely offline. A cloud API would fail at exactly the moment you need it.
- It costs nothing to run. There are no per-token costs and no API keys to protect. I host static files on Vercel's free tier, and anyone can fork it and run their own copy for $0. A wellbeing tool shouldn't need a subscription to pay for someone else's GPUs.
- I could fix what was broken. Every bug in the "making it behave" section above I could only fix because the whole stack is open. I read WebLLM's source to find the sliding-window conflict, changed the model's runtime config, and changed how decoding stops. With a closed API, "the model rambles" would have stayed a support ticket.
- The model is swappable. It's a single constant. When a better small open model comes out, DOSE gets better without any change to its architecture.
The irony isn't lost on me: an AI model running on your laptop GPU, whose only job is to get you away from the laptop. Open models make that possible without a cost, either to your wallet or to your privacy.
Prize Categories
- Best Use of Gemma. Gemma 3 1B is the core of the app: it writes every personalized challenge and every journal reflection, entirely on-device, through WebLLM and WebGPU.
Top comments (1)
Official Platform Update
Security protocols have been updated for all developer accounts.