Docs
Set up your darkroom.
Touch Grass, Not Glass has two halves. The camera runs in any browser, including your phone, and works offline. The darkroom is an open-weight AI model on your own computer, run with Ollama. It writes your quests and develops your photos. No cloud is involved.
Quick start
About five minutes, most of it the model download.
1. Install Ollama and pull Gemma 3
ollama pull gemma3:4b
2. Get the app and run it
git clone https://github.com/angelraph/touch-grass-not-glass
cd touch-grass-not-glass
npm start
3. Open the camera
Go to http://localhost:5173/app.html. The pill in the top-right corner shows gemma3:4b when the model is ready. If it says pocket mode, the app can't reach Ollama; see Troubleshooting.
There are no npm dependencies. npm start runs a tiny built-in static server, so any static server works too.
Requirements
| Minimum | Notes | |
|---|---|---|
| Computer | Any 64-bit laptop, 8 GB RAM | No GPU needed. On a CPU, expect about 30s to write quests and about 2 min per photo. |
| Disk | ~3.3 GB | For gemma3:4b. |
| Phone | Any modern browser | Install it to the home screen for the best offline experience. |
| Node.js | 18+ | Only for npm start. |
Using the camera
Today
The large number is your total minutes away from the screen across all walks. Choose where you're heading and tap Load film. Gemma writes six quests for the season, the time of day and the place.
Field mode
Tap Start walking and the screen goes dark. You see one quest at a time, and it's read aloud. When you find it, tap I found it: your camera opens, you take one photo and the next quest appears. Nothing is shown back to you. The dots at the top count your frames, and end walk finishes early.
Develop
Open the Journal on the computer running Ollama and tap Develop. Each photo shows a "developing" animation while Gemma writes it up. Developed frames get a title, a ✓ Found or Not quite stamp, a field note, and a line describing what the model actually saw.
Glass-free %
The share of your walk when the field screen was not showing, measured with the browser's Page Visibility API. This is the only metric the app keeps.
The online darkroom
Not everyone has Gemma on a computer, so the hosted site has a second darkroom. When the app can't find Gemma on your computer, it uses Gemma 4 hosted by Google instead: the newest open Gemma (Google only hosts Gemma 4 now), with exactly the same prompts (they live in prompts.js and both darkrooms import them).
- The camera's top right pill tells you which darkroom you're using: your model name (local), online darkroom, or pocket mode (no AI reachable).
- Each developed frame says where it was developed.
- Photos sent to the online darkroom go to Google's Gemini API for developing. This app's server passes them straight through and stores nothing.
- You can turn it off in Settings → Use the online darkroom. Then only your own computer develops photos.
Running your own online darkroom
The darkroom is one serverless function, api/gemma.js. Deploy the repo to Vercel and set an environment variable GEMMA_API_KEY with a free key from Google AI Studio. Optionally set GEMMA_MODEL (default gemma-4-26b-a4b-it, a mixture of experts model with about 4B parameters active, so it answers in seconds).
Phone outside, computer at home
The most natural setup: walk with your phone, develop on your laptop.
- On your phone, open the hosted camera at touch-grass-not-glass.vercel.app and add it to your home screen.
- Load film. With no model nearby, quests come from the built-in pocket deck. To use Gemma's quests instead, load film on the computer before you leave.
- After your walk, open Journal → Export on the phone. This saves a single
.jsonfile containing the roll and its photos. - Send that file to your computer (AirDrop, cable, USB stick) and use Journal → Import a roll, then Develop.
Using the hosted site with your local model
Browsers only let a website talk to your local Ollama if Ollama allows that website's address. To develop from the hosted site instead of npm start, start Ollama with:
# macOS / Linux
OLLAMA_ORIGINS=https://touch-grass-not-glass.vercel.app ollama serve
# Windows (PowerShell)
$env:OLLAMA_ORIGINS="https://touch-grass-not-glass.vercel.app"; ollama serve
Choosing a model
Any Ollama model that accepts images works. Change it in Settings → Model.
| Model | Good for |
|---|---|
gemma3:4b | The default. Runs on almost anything. |
gemma3:12b | Sharper identification. Wants 16 GB RAM or a GPU. |
gemma3n | Lighter on-device variant. |
llava, qwen2.5vl | Alternative open vision models. |
Small models make mistakes. In our sample roll, gemma3:4b titled a photo "Black Slug on Stone" but still counted it as the snail the quest asked for, and it called a black-coated red squirrel an Eastern Gray. The prompt tells the model to say "uncertain" rather than invent a species, and you can always swap in a bigger model or fine-tune one on your local flora.
Privacy & data
- Rolls, including photos, are stored in your browser's IndexedDB on your device.
- Photos are resized to 768px on the device before they're stored.
- With Gemma on your computer, photos are sent only to the Ollama address in Settings, which is
localhostby default. - Without it, the online darkroom sends photos to Gemma 4 hosted by Google for developing. Nothing is stored by this app. Switch it off in Settings if you prefer.
- There are no accounts, analytics or cookies. Your rolls live only on your device; clearing the site's data deletes everything.
- Location is never requested. Quests use only the month and time of day.
How the AI is used
Both prompts are in ollama.js, and both use Ollama's structured output (format with a JSON schema), so the model always returns data the app can read.
Quest writer
Input: month, time of day and destination. Output: exactly six one-sentence quests, each findable in under 10 minutes, safe, and leaving nature undisturbed. The six mix plants, animal signs, light and season.
Darkroom verifier
Input: one photo plus its quest. Output, in this order: observation, matches_quest, confidence, title, field_note, species_guess.
The order matters. Making the model describe what it sees before it decides keeps the verdict grounded. When we asked for the verdict first, the model would sometimes say "found" and then argue against itself in its own note.
Troubleshooting
The pill says "pocket mode"
The app can't reach Ollama. Check that it's running (ollama list) and that Settings → Local AI address is http://localhost:11434. On the hosted site, see OLLAMA_ORIGINS.
The pill says "model missing"
Ollama is running, but the model isn't installed. Run ollama pull gemma3:4b, or set Settings to a model you already have.
Developing is slow
That's expected on a CPU: about 2 minutes per photo with gemma3:4b. Leave the tab open. A GPU makes it a few seconds per photo.
Quests aren't read aloud
Speech uses your device's built-in voices. Some browsers only allow speech after you've tapped the page once, which tapping Start walking does.
Project structure
| File | What it does |
|---|---|
index.html | This website's landing page. |
app.html, app.js | The camera: Today, field mode, journal, settings. |
ollama.js | Quest writer and darkroom verifier prompts. |
store.js | IndexedDB storage for rolls. |
sw.js | Service worker that makes the app work offline. |
serve.mjs | Zero-dependency local server. |
MIT licensed. Issues and pull requests are welcome on GitHub.