Skip to content

feat(app): draw earlier rides as coverage and outlines, pulse the newest reception, and name the nodes in a hex cell - #579

Open
khagele wants to merge 1 commit into
efiten:masterfrom
khagele:feat/556-new-vs-old
Open

feat(app): draw earlier rides as coverage and outlines, pulse the newest reception, and name the nodes in a hex cell#579
khagele wants to merge 1 commit into
efiten:masterfrom
khagele:feat/556-new-vs-old

Conversation

@khagele

@khagele khagele commented Sep 4, 2026

Copy link
Copy Markdown
Contributor

Closes #556

The problem

The map drew a live reception and the stored backlog the same way. Open the app mid-hunt and the screen filled with everything in the time window; what landed right now, the thing you steer on, was indistinguishable from what already stood there. Age fade encodes age, not arrival: a 20-minute-old point looked the same whether it was on screen all along or loaded a second ago.

The refinement pass in the issue thread settled the form against a rendered design (four drawings of one drive).

My changes in this PR

All in 2D; the 3D views keep their drawing.

  • "Old" is everything before the current ride (app/src/rides.js). A gap of more than 10 minutes between consecutive receptions ends a ride. Not the app-open moment: a restart mid-hunt keeps one ride, and yesterday's drive is old however wide the window is.
  • Below zoom 15, the backlog is coverage only. A backlog reception has no point, only its hex cell. What lands now is a point on top of that coverage.
  • From zoom 15, the backlog comes back as outlines. An outline circle in its tier colour, no fill, a heavier stroke; this ride is drawn filled as before. Colour and place stay, so the backlog is still a measurement; the fill says "this ride". Age fade rides on top of both.
  • The newest reception pulses. One ring in its tier colour, 1.6 s, whatever the zoom, and only when the filter would draw it. A timer drives it rather than requestAnimationFrame, so it runs while the page is not painting.
  • From zoom 16 a hex cell names the nodes heard in it (app/src/hexlabels.js): 4-character id prefixes, newest first, three at most, then +N. A prefix comes only from a record with a node id; direct_hash and path_hash never contribute one, and a refused identity has none (app: traffic from a node whose adverts fail verification cannot be found or grouped #558). Drawn as HTML markers like the node layer, since the bare fallback style has no glyphs for a symbol layer. layerVisibility carries the labels with the flat hex layer, in 2D only.
  • Decision log: docs/2026-09-04-new-versus-old-on-the-map.md. Changelog entry in both copies.

Verification

Suite Result
app vitest 911 passed, build and eslint clean
web vitest 509 passed
web e2e whatsnew.spec.js, --fail-on-flaky-tests 13 passed (the changelog copies)

Unit tests cover the ride split (a gap exactly on the threshold stays one ride, unsorted input, unparseable rows, one ride, none), backlog membership with no ride known, both zoom thresholds, the label rules (newest first, one prefix per node across id variants, hash kinds and missing ids excluded, the +N cap) and the visibility rule for the labels in 2D and 3D.

Browser at 360x780 with seeded receptions, an earlier ride 25 minutes back and this ride now, both inside the 30-minute window: zoom 14 draws the 4 ride points and no backlog point; zoom 15 draws 5 backlog outlines beside them (circle-opacity 0, stroke 1.5); zoom 16 labels the cells 7e76 and 7e76 4ac3, the 1-byte hash contributing nothing; a new reception pulses from 8 to 24 px and clears; a reception the target filter hides does not pulse.

Decisions worth a look

  • The ride split runs on the rows the map already holds, cached on the records like the pillar collapse, so a 1 Hz tick that changes nothing does not sort again.
  • Labels are rebuilt only when the set of cells and their text changes (signature guard), and only for cells in the viewport.
  • Prefixes rather than a count per cell was Kasper's call; app,web: the map shows every place you heard a repeater, but never the edge of its reach #549's reach outline will share the label spot.

🤖 Generated with Claude Code

…est reception, and name the nodes in a hex cell

The map drew a live reception and the stored backlog the same way
(efiten#556): open the app mid-hunt and what lands right now, the thing you
steer on, was indistinguishable from what already stood there. Age
fade encodes age, not arrival.

Decided against a rendered design (Kasper, 2026-09-04), in 2D:

- "Old" is everything before the current ride (rides.js): a gap of
  more than 10 minutes between consecutive receptions ends a ride.
  Not the app-open moment, so a restart mid-hunt keeps one ride.
- Below zoom 15 a backlog reception is coverage only, its hex cell.
  From zoom 15 it comes back as an outline circle in its tier colour,
  no fill, heavier stroke; this ride is drawn filled as before. Age
  fade rides on top of both.
- The newest reception pulses once, 1.6 s, in its tier colour, and
  only when the filter would draw it. A timer, not
  requestAnimationFrame, so it runs while the page is not painting.
- From zoom 16 a hex cell names the nodes heard in it (hexlabels.js):
  4-character id prefixes, newest first, three at most, then +N. Never
  from a hash kind or a record without an id (efiten#558). HTML markers like
  the node layer, since the bare fallback style has no glyphs.

The 3D views keep their drawing; layerVisibility says so for the
labels. docs/2026-09-04-new-versus-old-on-the-map.md records the
decisions and the alternatives.

Verified: app 911 unit tests, build and eslint clean; web 509 and the
whatsnew e2e. Browser at 360 with seeded receptions, an earlier ride
25 minutes back and this ride now, both inside the window: zoom 14
draws the 4 ride points and no backlog point; zoom 15 draws 5 backlog
outlines beside them; zoom 16 labels the cells "7e76" and "7e76 4ac3"
with the 1-byte hash contributing nothing; a new reception pulses
from 8 to 24 px and clears; a reception the target filter hides does
not pulse.

Closes efiten#556

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

app: a reception that just arrived looks identical to what already stood there

1 participant