M2-10: Heat map — every route on one map, to find the ones not taken #39
Labels
No labels
area/agent
area/capture
area/editor
area/geo
area/security
area/sync
area/transcription
area/ui
area/vault
area/voice-memos
blocked
milestone/M1
milestone/M2
milestone/M3
milestone/M4
needs-decision
needs-hardware
p0
p1
p2
type/bug
type/enhancement
type/feature
type/idea
type/infrastructure
No milestone
No project
No assignees
2 participants
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
Stash/stash-ios#39
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Every memo's route on one map, with a heat map of where I actually go — so I can see where I
don't.
Wes: "This way i can find new paths to take."
The inversion worth building for
A heat map's obvious reading is the bright parts. This feature is for the dark parts. The stated
use is finding a new route, which means the value is in the streets near the hot ones that have
no colour at all. That should shape the rendering: a hot path on a black background is pretty and
useless; a hot path against legible surrounding streets is the feature.
This has been sitting in Wes's notes since 2026-07-27, framed the same way then: "I walk roughly
the same path to the library nearly every day, so that path would be a bright red hotspot", and
two uses fall out — choose a different path, and see where the best ideas come from.
Entry point and layout
detail page; this one aggregates every route there is.
app. Stock
Mapgestures, not a custom gesture recogniser.The open question: what "current location" means here
The initial zoom is specified as neighbourhood-level based on current location. That conflicts
with a rule M2-06 states outright:
Opening a map view is not recording. Two ways out, and this needs Wes's call at the planning
checkpoint:
Decided 2026-08-09: this view takes a location fix, and M2-06's rule gets an explicit
exception. Wes: "yes, this opens up a new view that would require location."
Centring on the last track's endpoint was the alternative and it was rejected — it only works when
you are already at home, and the case that matters most is standing somewhere unfamiliar wanting to
know what is unexplored here.
The exception is narrow, and it gets written down rather than absorbed quietly, because M2-06
states its rule flatly and a reader of that file must not be able to conclude the code contradicts
it:
centring aid, not tracking.
library's extent. A denied permission never blocks the feature, it only costs the centring.
AGENTS.mdand M2-06's documentation are amended in this PR to state the exception and itsbounds. Two rules that disagree is worse than the looser rule stated honestly.
When the feature has never been turned on
Location is opt-in and off by default (M2-04), so the ordinary first visit here has no data and no
permission. That is the moment to explain the feature, and this is the only place a user naturally
arrives already wanting it.
Wes: "there should be a notification and an option to enable it here. The notification should tell
the user what the feature does and that the data doesn't get sent anywhere."
So the empty state is an explainer with an enable action, not a shrug:
drawn on one map and the places you never go become visible.
.gpxfile beside the memo, on this phone. It is not sent anywhere.There is no server in M2 at all, and when sync arrives the relay is blind by design and cannot
read it.
so nobody has to go find Settings to act on what they just read.
This copy and M2-04's Settings copy say the same thing and must not drift. One string source, used
in both places.
A memo recorded before the feature was enabled has no track and never will. Say so, so an empty
map straight after enabling reads as "go for a walk" rather than as broken.
The tension with "no index"
Reading every track file on every open is the honest implementation and it matches the principle
the app is built on — the files are the record, there is no database. It is also the first feature
that genuinely wants an index, and it degrades with the number of memos.
Do the honest thing first and measure it. Read them all, on a real library, and write the
number down. Add caching when there is a measurement saying it is needed, not in anticipation — and
if caching arrives, it is a derived cache that can be deleted and rebuilt from the files, never a
second source of truth.
The heat map itself is custom, and that needs saying out loud
AGENTS.mdsays reach for the stock component first and say why when you do not. MapKit has noheat map, so this is a hand-drawn overlay: bin the points into a grid, weight by how many distinct
recordings crossed each cell rather than by raw point count — otherwise standing still for five
minutes outranks walking a street a hundred times — and render density.
Keep it small and say in a comment why it exists. Weighting by distinct visits rather than samples
is the substance of this issue and it is what makes the map answer the question being asked.
⚠️ This is a map of where Wes lives
No screenshots of this view in issues, PRs, commit messages or review artifacts. This
repository is public, and a heat map of daily walks is a home address with extra steps. Test
fixtures are synthetic coordinates, as everywhere else — and here that rule has teeth rather than
being a formality.
Depends on
M2-07 (there is nothing to map until tracks are being written) and M2-08 (the map component and its
conventions). Sequenced after M2-09, as the last thing in the milestone.
Deliberately not in this
The dashboard from the 7/27 note — distance week over week, memo statistics, correlating good ideas
with places — is a real idea and a separate one. So is filtering the map by anything other than
date. This issue is the map, the heat, and the date filter.
Done when
Milestone 2 of the Stash v3 rebuild. M2 is still app-side — no sync, no account, no server.
Sync arrives in M3.
Origin: the 2026-07-27 walk memo, captured in the vault as "Stash - Walk Path Mapping and
Heatmap" and restated on 2026-08-09.
Working agreement for every issue in this repo: feature branch, tested before the PR opens
(on-device where the label says so), then Wes reviews the PR and we walk the code together. Docs
update in the same commit. A PR that takes more than 20 minutes to review is too big — say so and
split it.
This is solid