neighborhood steps actually mean something now
so way back, I wrote step_neighborhood as a function that… just called step(). full graph. every time. with a little // Note: functionally equivalent to step() comment that was basically an “it’s fineeee” for now.
it’s been sitting there mocking me… for months
(no joke i had it at #1 on the mental todo after deleting Dioxus)
not anymore! it does the real thing now. when you nudge one note, only the notes within ~400px of it recompute. everything past that radius stays frozen and acts as an anchor so the local cluster settles against the rest of the map instead of the whole universe re-jiggling every frame. this is the “atomic graph updates” idea from the original plan thing, finally real: touch one note, its neighborhood adjusts, the far-off constellations don’t even notice.
Efficiency
to make that not-slow I built a spatial hash. uniform grid, bucket nodes by cell, “give me everything within radius R” only checks the overlapping cells instead of all N nodes. the CPU layout uses it for the localized force pass (repulsion from local neighbors, springs to actual link partners even if they’re outside the neighborhood, gravity), and I also went back and ripped the O(n²) all-pairs loop out of the regular collision resolver and put it on the spatial hash too. that one was quietly quadratic this whole time and would’ve melted at a couple thousand notes. rebuild the hash each pass so pushed nodes land in their new cells. much better.
Collisions?
the collision resolver got a neighborhood-scoped twin as well, so a local step also only de-overlaps locally. nodes inside the neighborhood push each other apart normally; a node that’s an anchor outside it doesn’t move, so the inside node just gets shoved twice as hard away from it. felt like the right call.
PERSISTENCE?!
also taught storage about pins, separate workspace.pins.json file (refactored the workspace/pins file openers to share a state_file helper), and note cards carry a pinned flag now.
Oh lines
and there’s a whole new map module in the UI crate that generates the actual SVG-ish path strings: bezier edges between linked cards in screen coordinates, viewport culling so off-screen edges don’t get drawn, selected-neighborhood highlighting (the selected note’s edges render in the “selected” layer, everything else in “base”), and a grid path that anchors to the camera and clamps its own density so zooming way out doesn’t try to draw ten thousand grid lines.
the map handling a lot of notes without choking was the thing I was VERY, VERY worried about.
Not as much of a problem as I thought! :D
Comments 0
No comments yet. Be the first!
Sign in to join the conversation.