This is a submission for the Hacktoberfest Open-Source AI Challenge Week 1: Touch Grass
What I Built
TerraTale is a treasure map of your neighbourhood that is blank until you walk it.
You start with a sheet of parchment and exactly one hex inked in: wherever you live. Every real walk inks in the ground you actually covered. A local Gemma writes the legend for what is there. Print it weekly.
It is for anyone who already walks and wants the walking itself to be the point — not a step count, not a leaderboard, not another number going up. The reward for a walk is a map that got bigger, and a sheet you can pin to a wall.
The only way to unlock content is to go there. Uncharted hexes sit on the frontier as dashed ghosts, so you can always see which direction you have not walked yet. terratale quest picks the nearest unknown hex and prints a card with a bearing and a distance:
A QUEST — Chart the hex 0.36 km west
Walk to roughly -17.82550, 31.04880 — about 0.36 km west of your anchor. Stay a few minutes and move around so the trace records a real visit, then bring the map home.
That is the whole design. The screen is the shortest part of the experience: you open it for four seconds after a walk, and the other fifty-nine minutes you are outside.
The sheet you start with
The card that sends you out
The map after a fortnight
Code
https://github.com/sehmaluva/terratale
How I Built It
Two open models do the work, and neither is decoration:
| Job | Model | Why it has to be this one |
|---|---|---|
| Decide what kind of place each hex is | TabPFN | The dataset is a few dozen rows that belong to one person. TabPFN is a prior-fitted tabular classifier that predicts from a support set with no training run, so the primer ships in the box and your own labels bend it immediately. |
| Write the name and the legend | Gemma, locally via Ollama | A map of everywhere you walk is a map of where you live. It stays on your disk. |
GPX traces ──▶ hex grid ──▶ 16-feature table ──▶ TabPFN ──▶ archetype
│
printed map (SVG/PNG/PDF) ◀── Gemma (Ollama)
│
name + legend
Each hex becomes a row of 16 measured quantities: visits, distinct days, dwell, median speed, path length, straightness, turn rate, distance from home, hour-of-day circular mean and spread, weekend and after-dark fractions, climb, revisit span. An evidence gate means a hex is only charted once real walking happened inside it.
The four things that were measurably wrong. None of these were caught by reading code. They were caught by looking at numbers the program printed and thinking that cannot be right.
1. Raw GPS distance is fiction. Summing a 1 Hz trace measures the receiver's wander as much as your legs. On a synthetic 2.0 km walk with 3.2 m of noise per fix, the raw sum reads 8.1 km — four times the truth. Averaging position over a short window and resampling on distance brings the same trace to 2.04 km. That is the 360.7 km versus 63.7 km above.
2. Standing at a hex boundary counted as eighty visits. GPS noise alone flips the hex assignment every few fixes when you are standing still. One bench, eighty arrivals. The fix is an excursion collapse: any excursion shorter than 25 seconds that returns to where it came from is merged back into the stay it interrupted.
3. Every hex on the map came back as an overlook. The portable primer was half-specified — elevation was only filled in for 2 of its 16 rows, so imputation pushed every unknown row to the mean of those two and every cell looked like high ground. The primer is now complete, with an assertion that its column order matches the feature list. A silent misalignment here would misclassify the entire map and look like a modelling problem instead of a typo.
4. Labels were not reaching the classifier at all. Labelling a hex appeared to work, wrote to disk, and did nothing: labels were stored under string keys while the feature table was keyed by Hex objects, so every lookup returned None. It failed silently, in the one place the user is invited to teach the system something. That is the interaction I care about most — the model is a starting point, not an oracle you argue with:
terratale label 2:-1 gathering_place # that hex is my bench
terratale reveal # re-classify with your label in the support set
Two seams in Ollama that cost me real time, both of which I only understood after reading what other developers had already hit. Its native chat path re-sorts your JSON schema keys alphabetically, so I named the fields a_name, b_legend, c_inscription to make alphabetical order the order I actually want. And it can skip the schema entirely on a thinking model that answers without thinking, so TerraTale sends think: false, validates on the client, and retries. The lesson: do not trust the transport to enforce your schema.
Why Does Open Innovation Matter?
I want to be specific here, because it would be easy to bolt a model onto the end of a mapping app and call it AI.
Your location history never leaves the machine. Not as a promise — as an architecture. There is no account, no sync, no telemetry, and no network call anywhere in the map pipeline. For a project whose entire input is the shape of your daily life, a hosted API would mean handing a third party a movement record that is trivially de-anonymisable. Home is the one place you return to most often; a fortnight of traces guesses your address without much work. This is the case where local inference is not a cost optimisation, it is the only defensible design. A closed API could not have built this product at all — not because it is worse, but because the data cannot leave.
The whole pipeline runs offline. GPX parsing, hex grid, feature extraction, classification, map rendering, PDF output: all of it, with the network off. Even the PDF writer is hand-rolled so printing a map needs no extra dependency. The map is a file on disk that you own.
The taxonomy is yours to change. Place archetypes are not baked into weights. You label a hex, that label joins the support set, and every other prediction on the map shifts. Against a closed model, changing what counts as a gathering place is a fine-tuning run. Here it is a label.
It costs nothing to run. No tokens, no API key, no per-walk bill. A weekly print ritual should not have a meter running on it.
The open pieces are not a nice-to-have bolted onto a closed core. Delete Gemma and the map has no legends; delete TabPFN and it has no idea what any hex is. The project is the two open models plus a hex grid.
My Agent Session
The full session is below — it includes the four bugs above in the order they were actually found, including the moment each one surfaced.
Prize Categories
Best Use of TabPFN - TabPFN is the classifier, not a garnish. The whole point is few-shot tabular prediction on a few dozen rows of one person's movement data: the primer ships as a table, the walker's labels join the same support set, and every prediction on the map re-bends when you teach it something. I also added explicit missing-indicators to the feature vector, because a hex you have never revisited genuinely lacks a value and imputing zero would be a lie the model then reasons from.
Best Use of Gemma - Gemma writes every place name, legend and inscription, and it only ever sees measurements taken in that one hex. It is never asked to imagine a place; it is given the visit count, the dwell, the distance from home and the hour-of-day distribution, and asked to describe what those numbers imply. It runs locally through Ollama, which is the only reason a tool built on the shape of your daily life can exist at all.



Top comments (1)
tr.ee/dev-to