DOSE-touch-grass: an offline Gemma coach that hands you a stone and tells you to put your phone down A developer built DOSE-touch-grass, an open-source web app that runs Gemma 3 1B entirely in the browser via WebGPU to coach users through short outdoor, screen-free challenges tied to dopamine, oxytocin, serotonin and endorphins. The app requires no API keys, server or account, keeps journal entries in localStorage, and caches the roughly 700 MB quantized model for offline use after the first load. The developer reports the on-device loop worked end to end, with the model generating a 15-minute stone-focusing challenge and a follow-up reflection from journal answers. This is a submission for the Hacktoberfest Open-Source AI Challenge Week 1: Touch Grass https://dev.to/challenges/hacktoberfest-week1-2026-10-05 We all know the four "happy chemicals": D opamine, O xytocin, S erotonin and E ndorphins. 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: 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. 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. 🔗 Live app: https://dose-touch-grass.vercel.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. An on-device AI coach that gets you off your phone and outside. Pick the feel-good chemical you're craving D opamine, O xytocin, S erotonin or E ndorphins , 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 https://dev.to/challenges , Week 1: Touch Grass · hf26challenge Live demo: add your Vercel URL here · Write-up: add your DEV post here An app that wants you to put your phone down shouldn't send your mood journal to a cloud API. The open-source AI stack: gemma3-1b-it-q4f16 1-MLC , quantized to 4 bits, about 700 MB. localStorage , and a service worker caches the app shell for offline use. pick chemical ─► CoachPanel ─► engine.ts ──postMessage──► llm.worker.ts ▲ │ WebLLM + Gemma 3 1B │ ▼ WebGPU parse + validate prompts.ts ◄── streamed tokens 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: interruptGenerate , then a hard reset that terminates the worker and reloads from the cache; GPUAdapter.prototype.requestDevice to watch device.lost and broadcasts it on a BroadcastChannel , 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. 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. For this app, a closed API would have been the wrong tool: 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.