Commit Graph
5 Commits
Author SHA1 Message Date
SenrokaiandClaude Opus 5 86e143131e Answer the review: pin by the index the neighbourhood holds, and choose again only when it can matter
The adversarial review confirmed three costs this PR added, all reproduced in
the browser.

- The first pinned refocus stalled the first flight of a session. The
  renderer built its own id-to-index Map of 423 651 entries the first time a
  star was pinned, which is at the first selection, inside the approach
  flight. The worst frame was 47-103 ms, and the Map stayed as a second copy
  of a lookup the scene already had. The scene now pins by catalogue index,
  through the StarNeighbourhood it builds at load (new `indexOf`), and the
  renderer takes indices. First selection, measured in the browser: worst
  frame 18 ms.

- At galactic scale every label pass rewrote the drawn set. The view centre
  sweeps hundreds of parsecs a pass there, far past any star, so each pass
  chose the same 70 000 stars again and uploaded 2 MB to the GPU: 11 times
  on the flight out to the Galaxy. The scene no longer refocuses at galactic
  scale, where the whole catalogue is a few pixels, and the renderer leaves
  its buffers alone when the drawn set is unchanged. Flight to the Galaxy:
  2 refocuses, no frame over 50 ms.

- At load the same set was chosen twice: once by the renderer's constructor
  around the Sun, and again by the first label pass, centred on the Sun. The
  scene now records the constructor's choice as the current focus.

Tests: the buffers keep their version for an unchanged set, no refocus at
load, none at galactic scale, and pins arrive as indices. Proxima's id in the
scene spec now differs from its index, so a lookup by id cannot pass for one
by index. Negative controls, each caught: an unchanged set rewritten anyway, a
refocus at galactic scale, the boot choice not recorded, and pins passed as
ids.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016jxMkwA2rbicdGxHosecYi
2026-09-16 15:12:46 +02:00
SenrokaiandClaude Opus 5 efe6667b00 Route with A* over numeric cell keys, so a route can reach past the Sun's crowd
The route search widened evenly from the departure, Dijkstra-style, with a
budget of 20 000 stars. On the Gaia catalogue those are all within about
40 pc of the Sun, so it found no route to anything farther at any range:
Sol to Mirfak (155 pc) failed at 3, 8, 15 and 30 pc alike. Every failure
then asked minimumRangeBetween what range would work. That search widened
the same way with a 30 pc ceiling, and it ran for up to a minute on the
main thread before giving up with nothing.

routeBetween is now an A* search. Each star is queued by the distance
travelled to it plus the straight line on to the destination, on a binary
heap rather than a linear scan of the frontier. It heads for the
destination instead of flooding the core around the departure.

minimumRangeBetween bisects the range, one routeBetween per step, because
whether a chain exists can only become truer as the range grows. Its
answer is always the longest hop of a route actually found, so a range it
names always opens one. Its ceiling is now the Routes panel's own
maximum, MAX_JUMP_RANGE_PC: a range the control cannot be set to is no
answer, and raiseTo already clamped any figure above it.

The spatial index keys its cells by one number packed from their three
indices instead of an "ix,iy,iz" string. A search visits up to 125 cells
for every star it expands, and building those strings was half of what a
route cost. forEachWithin hands neighbours over unsorted and uncollected,
which was most of the other half; within is now that, gathered and sorted.

The no-route line said nothing in the catalogue bridged the gap; it now
says no chain of jumps up to the panel's maximum reaches the star, which
is what was searched.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016jxMkwA2rbicdGxHosecYi
2026-09-11 19:42:57 +02:00
SenrokaiandClaude Opus 5 f14e252b19 Name the neighbours that have a name, before the ones that only have a number
The neighbour ring exists to say where you are. Since the catalogue refresh it
has been spending one of its four places in Sol on "Gaia DR3 5853498713190525696"
-- a nineteen-digit survey id for the star printed beside it as Proxima
Centauri, the same star twice -- and that duplicate row pushed Barnard's Star
off the ring altogether. 91.9% of the refreshed catalogue is named that way.

Named stars now come first, and survey designations fill in only where fewer
than four named ones are in reach. The line between the two is the one the
catalogue format already draws: a name is a designation when it is what the
star's source would generate for it. Judged by the prefix rather than by
rebuilding "prefix id" from the row, because the number after "Gaia DR3" is the
survey's own id, which the 32-bit row id cannot hold -- a round trip through
the id would have called every one of those stars named.

The preference lives on the index as `nearestPreferring`: the preferred pass
exhausts the search before the fill runs, so a named star is never outranked by
a nearer unnamed one. That is the whole point of asking.

The end-to-end spec names Barnard's Star again, on purpose. The four nearest
named stars to the Sun are a fact about space, not about which catalogue was
refreshed last, and without this change that is exactly the label that
vanished -- checked by running the spec with the preference stashed: it fails
on that line, and passes with it back.

npm test 609/609, npx playwright test 16/16 under CI=true --workers=2.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014fcUfL82nvyh9VebX1Fz6w
2026-08-27 20:06:04 +02:00
SenrokaiandClaude Fable 5 68a919bd84 Route between stars, through the crossings a chosen range allows
The map could say where a star is and what is near it, and nothing about
getting from one to another. This adds the question and the answer: pick a
departure and a destination, choose how far a single crossing may be, and get
the chain — how many jumps, how far in total, and every star on the way, each
one a step you can fly to.

A jump link is not a feature of space. There are no corridors out there; a
link is a question asked of the catalogue, which is why the range is the
user's control rather than a constant. Two facts about that catalogue decide
what the answers look like, and both are stated in the code because they read
as defects otherwise. It is magnitude-limited, so it is dense around the Sun
and thins with distance — within 50 pc a 3 pc range links 99% of it into one
piece, while over the whole 250 pc reach the same range leaves most stars
alone. And a gap in it is a gap in what has been catalogued, not in what is
there.

That is why "no route" is not the end of the answer. Where no chain exists at
the range asked for, the panel says which range would open one — the chain
whose longest hop is as short as possible, found by the same search with the
cost of arriving somewhere being the worst hop taken rather than the sum — and
offers that number as a control to accept.

Departure defaults to wherever the view already is, so one field is usually
enough. Sol to Vega at 3 pc: four jumps, 10 pc, by way of Barnard's Star,
Struve 2398 B and HD 155876. Narrow it to 0.8 pc and it says 2.26 would reach.

The graph is drawn as one buffer of line segments and the route as a second,
brighter one over it, with the graph stepping back while a route is up: near
the Sun the links are a haze, and a thread through a bright cloud is not a
thread. Both fade out with the local layer, since from outside the Galaxy the
graph is a smear.

Two measurements shaped this. Asking the index for each star's neighbours in
turn — sixty-eight thousand sorted lists, thrown away — took eight seconds; the
grid now walks its own cells once and pairs them, which takes a quarter of one.
And the range control emits per pixel dragged, so the rebuild waits for the
hand to settle.

Three defects fixed on the way, all older than the routing:

hud-acquire animated with fill-mode `both`, which leaves its closing keyframe
applied for good — and that keyframe carries a clip-path. Every panel wearing
it has been clipping its own box ever since, so anything that had to escape
one was cut away and could not even be clicked. Nothing had needed to escape
until this panel's dropdown opened upward.

The routing fields returned nothing when typed into before the catalogue
finished loading, and stayed nothing until the next keystroke. The options are
derived from the query and the index together now, so they appear when the
second of the two arrives, whichever that is.

And a link was `3-7` walking one way and `7-3` walking the other, which is two
links to anything comparing them.

Verified: build clean, 571/571 unit, 9/9 end-to-end including two new specs —
one plotting Sol to Sirius, one narrowing the range until there is no route and
accepting the one it names — design detector clean, screenshots at 1440x900
and 390x844.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016jxMkwA2rbicdGxHosecYi
2026-08-20 18:39:22 +02:00
SenrokaiandClaude Fable 5 44c6a1f15e Name the neighbours, from inside the system
A system view could say everything about the star it was inside and nothing
about where that star was. The four nearest catalogue stars are now named
around the edge of it, each with its distance, each a button that flies there
— so a chain of neighbours can be walked without pulling back out to the field
between hops.

These are bearings, not sky positions, and that is the one deliberate
compromise here. A true direction was tried first and does not work: at this
field of view the visible cone is about 30 degrees, so on average one
neighbour in fifteen falls inside the frame — measured, not guessed, at one
label of four in Sol and none at all after a small orbit. What survives the
ring is the half of the direction a viewer can act on, which way to turn to
face it, and the ring reads as instrument rather than as scene because it sits
at a fixed radius. Real distance was never an option: Proxima is 268 000 AU
from Sol, thirteen far planes out, so the distance goes on the type line.

Proximity is answered by a new pure module rather than by a scan. A uniform
grid over the catalogue answers both "the k nearest to this star" and "every
star within n parsecs", the second being what the jump-link graph in the next
PR is built from — one scan per node, and the quadratic would show. Its spec
pins the grid against a brute-force sweep of a pseudo-random cloud, because a
spatial index is an optimisation and never a different answer.

Where the ring meets the HUD, the HUD wins: placement is given the boxes the
readout, the strip and the object card occupy, and slides a name along the
ring until it clears them, or drops it rather than print it half hidden. That
rule is a pure function with its own spec.

Four defects found while verifying this, three of them older than it:

The dock's flex column was pointer-events-auto and as wide as its strip, so
an invisible band above the strip swallowed every click in it — including,
but not only, a neighbour's. The column is transparent now and each surface
opts back in.

The ring was sized against the frame's height alone, which on a phone held
upright put it a viewport and a half wide: no neighbour was reachable on any
portrait screen. It is sized against the shorter side.

Picking a search result reopened the readout, which on a narrow viewport is a
sheet over most of the scene — reopening it onto whatever was just flown to.
Below sm it now folds away.

A selectable label's two lines are adjacent spans, so it announced as
"Sirius2.64 pc"; it carries an explicit label saying what it does.

Verified: build clean, 558/558 unit, 7/7 end-to-end including a new spec that
flies Sol to Barnard's Star by its label, design detector clean, screenshots
at 1440x900 and 390x844 in Sol and Proxima Centauri, and the keyboard path
walked: both names are in the tab order, focusable, with the accent ring.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016jxMkwA2rbicdGxHosecYi
2026-08-20 17:06:25 +02:00