Commit Graph
4 Commits
Author SHA1 Message Date
SenrokaiandClaude Fable 5 b2cb307b60 Merge the review fixes, and take Junie's on the hit radius with them
Carries the shared reference-viewport module and the cached card lookup up from
the branch they were reviewed on, and answers the one comment left against this
one.

The orthographic branch of the star field's hit test multiplied the angular size
by the frustum's half-height and then divided the result by that same
half-height. The two cancel: `setProjection` had already sized the sprite as
`angular * halfHeight / tan(REFERENCE_FOV/2)`, so dividing back out by the
half-height leaves the reference field of view and nothing else. Both
projections are one formula over a different angle now — which is also one
fewer division by a number that is zero if the frustum ever degenerates.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016jxMkwA2rbicdGxHosecYi
2026-08-21 14:55:59 +02:00
SenrokaiandClaude Fable 5 e853fe312e Answer the review: one reference viewport, one lookup for the card
Two of the three comments were worth taking.

The star field and the rings drawn over it each carried their own copy of the
reference viewport and field of view the angular sizes are figured against.
They agree today, and nothing would have told anyone when they stopped: a ring
would just sit a little wide of its star at some window sizes. One module now
holds the three constants and says what they are for.

The leader line to the object card looked the card's panel up by selector on
every frame it was drawn. The host element is stable and the panel inside it
only changes when a different body is selected, so the lookup is derived once
per change instead of sixty times a second.

Left alone: replacing `positions.set([x, y, z], i * 3)` with an index-by-index
loop to avoid a temporary array per host. It runs once, over six hundred and
thirty-four stars, at bootstrap, and the version with the temporary reads
better than the version without.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016jxMkwA2rbicdGxHosecYi
2026-08-21 14:50:19 +02:00
SenrokaiandClaude Fable 5 d9bd913458 Draw it flat: an orthographic plan view
A perspective camera leans everything away from the centre of the frame. In a
system that means the orbits are ellipses whose shape depends on where they
happen to sit on screen, so two planets on the same circular orbit do not look
like they are on the same circle. Plan view, in the Display panel, swaps the
projection for a parallel one and swings to look down the plane the current
scale is read against — the galactic plane out in the field, this system's own
orbital plane inside one. Circles are circles again, wherever they are.

Both halves are the feature and neither alone is it. The projection is what
makes the shape honest; the swing is what makes it worth looking at. Orbiting
still works afterwards, so a plan is where the view starts rather than a cage.

The engine now holds both cameras and keeps them in step, rather than making
one on demand: a camera that exists only while it is being looked through is a
camera whose pose is always one swap out of date. The orthographic frustum is
derived, never stored — it is the perspective camera's own frustum at the
current orbit distance, made parallel — which is why the camera flights work
through it untouched. They move the camera; the frame follows.

Three things had to be taught that a projection had changed.

Sprites. three.js turns an angular size into a world size only when it is
compiling against a perspective camera (SpriteNodeMaterial: `camera
.isPerspectiveCamera && sizeAttenuation === false`). Under a parallel one that
step is silently skipped and every star in the field collapses to a thousandth
of a parsec. The same arithmetic is now done in the node graph behind a
uniform, so one material serves both cameras without being recompiled — and
picking follows it exactly, since a star has to be clickable where it is drawn.

Depth. A parallel camera does not back away as its frame grows, so at galactic
framing the backdrop shell and half the Milky Way sit behind its own plane. Its
depth range is symmetric about it instead, which a linear depth buffer can
afford and a perspective one could not.

And distance. Half the map was keyed on how far back the camera was pulled —
the scale ladder, the crossfade, the label radius, the range readout — which
under a parallel projection says nothing at all, because the frustum sets the
extent. They all read one honest equivalent now: the distance a perspective
camera would need to frame the same thing.

Two defects found while verifying, both mine, both from this change:

The per-frame work was computed against the camera captured at bootstrap while
the renderer drew through the other one, so after a swap every label was
projected by a camera nobody was looking through.

And the zoom limits were derived from the orbit limits, which are in whichever
unit space the view is in. Reading them on the frame the scene swaps parsecs
for astronomical units pinned the zoom at the ratio between the two, and
leaving a system landed the view three kiloparsecs out. Zoom is a plain
multiplier on a frame the distance already sets, so it is bounded by a factor.

Verified: build clean, 595/595 unit including a new spec for the projection
arithmetic, 13/13 end-to-end including two that flatten a system and check the
ladder still knows how far out it is, design detector clean, screenshots of
both scales in both projections.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016jxMkwA2rbicdGxHosecYi
2026-08-20 20:11:31 +02:00
SenrokaiandClaude Fable 5 7591bcc0ea Point at what is selected: arcs, a leader to the card, rings on the systems
Four things the scene did not yet say, all about where to look.

Selection. Hovering or pinning a body raised its card in the corner, but
nothing in the scene said which point the card was about. Two hairline arcs
now bracket the body — the one mark borrowed from the ARK's control disc — and
a leader runs from their rim to the card's near edge, in screen space, once
per frame, because the body moves and the card's height depends on its
content. The selected body's own label swaps to the left of its point, since
the leader leaves the right and would otherwise cross the text.

Labels choose a side. Right by default; left when the text would run off the
right of the view, or into the reach of a label already placed to the right,
and never left when that would run off the left. The overlay hangs the label's
near edge on the point either way, so the hairline still meets the star.

Rings on the systems. A faint accent ring on every star known to host
planets — the one binary fact about a point of light worth reading at a
glance from the neighbourhood, since it is the one thing that says "there is
somewhere to go here". Drawn the way the star field draws stars, as
unattenuated instanced sprites with the ring a band of the quad's own uv, so
they sit on the field's points at any zoom; a first cut as three.js Points
rendered nothing at all under the WebGPU renderer. 634 of them are a lot at
the overview, so they are faint, small, fade with the local layer, and have
their own toggle — Systems — in the dock's Display tab.

Verified: build clean, 537/537 unit, 6/6 end-to-end, design detector clean,
screenshots at the overview, at 90 pc, and in Sol and Proxima with a body
hovered and pinned.

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