822c69944cfaac5a885f43386d2690503291de70
13
Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
bd37bb8b96 |
Say what is written about a world, when asked
Every figure this map shows is a measurement or something derived from one, and it says which. What it could not do was tell you what a place is — a radius and an eccentricity do not say that Titan is the only moon with a dense atmosphere. An About control on a body's panel now fetches the Wikipedia lead, and it is labelled as what it is: prose from another site, credited and linked back, below the line where this map's own figures end. Only on the press. Nothing is fetched while a body loads, and nothing is fetched twice. Three things the encyclopedia does that had to be handled, all found by asking it rather than by guessing: It redirects, generously — "Proxima Cen b" lands on "Proxima Centauri b" and "Kepler-22 b" on "Kepler-22b" — so the catalogue's own names can be sent as they are, with no mapping table to maintain. It disambiguates. "Titan" is a list of everything called Titan, and so are "Mercury" and "Io". Wikipedia says so in the response, and this app happens to know the kind, so a disambiguation is retried as "Titan (moon)". Only in English: every wiki words its own qualifiers, and inventing a translation of one would be inventing an article title. And it rate-limits, which it did to me while I was checking the above. A refusal to answer is not an empty answer, so the two are separate outcomes: "Wikipedia has no article on this" is about the world, "Wikipedia could not be reached" is about this minute — and only the first is remembered, so a second press is allowed to try again. The extract is capped and scrollable. A lead can run a dozen lines, and this panel is anchored to the top of a viewport that may be shorter than the prose. Verified: build clean, 606/606 unit including twelve for the lookup chain, 16/16 end-to-end including three that stub the encyclopedia — this suite tests the panel, not Wikipedia — design detector clean, and the real thing exercised by hand against Earth, Titan and Proxima Cen b at three viewport sizes. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016jxMkwA2rbicdGxHosecYi |
||
|
|
307fd41be8 |
Keep a place, and come back to it
Restores the commit reverted off the routing branch, which is where it was committed by mistake. The change is unmodified; only its branch is. The map had no memory. Every visit started at the same overview, and a system worth returning to had to be found again by name each time. A mark on the readout and on a body's panel now keeps it, a Bookmarks tab lists what has been kept, and choosing one goes there — a star by flying into its system, a body by opening its page. Local storage, not an account. This map asks nobody to sign in, and a list of stars somebody liked is not worth a server. Every read of that store is defensive, because it is a string a person can edit, another tab can write, and a browser can refuse to hand over at all: a bad entry is skipped rather than losing the rest, duplicates are collapsed since two entries for one place would each toggle the other's control, the list is bounded so a hand-edited store cannot decide how much this renders, and where storage is denied outright the bookmarks still work for the visit — they just do not outlive it. The name is stored alongside the id rather than looked up, so the list reads before the catalogues have loaded, and a bookmark to something a later catalogue no longer holds still says what it was instead of decaying into a bare number. The tab is offered even when it is empty, and says what the mark does: a tab that appears only once you have already found the feature is a tab that never taught anyone anything. Choosing a kept place hands the panel back to the readout, the same move as choosing a search result and for the same reason. That behaviour is what the end-to-end spec caught missing — the readout it asserted on did not exist, because the panel just used was still covering it. Verified: build clean, 587/587 unit, 11/11 end-to-end, 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 |
||
|
|
9cdd8f9388 |
Revert "Keep a place, and come back to it"
This reverts commit
|
||
|
|
bd3a5a48c9 |
Keep a place, and come back to it
The map had no memory. Every visit started at the same overview, and a system worth returning to had to be found again by name each time. A mark on the readout and on a body's panel now keeps it, a Bookmarks tab lists what has been kept, and choosing one goes there — a star by flying into its system, a body by opening its page. Local storage, not an account. This map asks nobody to sign in, and a list of stars somebody liked is not worth a server. Every read of that store is defensive, because it is a string a person can edit, another tab can write, and a browser can refuse to hand over at all: a bad entry is skipped rather than losing the rest, duplicates are collapsed since two entries for one place would each toggle the other's control, the list is bounded so a hand-edited store cannot decide how much this renders, and where storage is denied outright the bookmarks still work for the visit — they just do not outlive it. The name is stored alongside the id rather than looked up. That way the list reads before the catalogues have loaded, and a bookmark to something a later catalogue no longer holds still says what it was instead of decaying into a bare number. The tab is offered even when it is empty, and says what the mark does. A tab that appears only once you have already found the feature is a tab that never taught anyone anything. Choosing a kept place hands the panel back to the readout, which is the same move as choosing a search result and for the same reason: the panel has done its job and the thing to look at is now the scene. That behaviour is what the end-to-end spec caught missing — the readout it asserted on did not exist, because the panel that had just been used was still covering it. Verified: build clean, 587/587 unit, 11/11 end-to-end including a spec that keeps Earth, leaves the page, comes back to it from the list and forgets it, and one that keeps Proxima Centauri, flies out to the field and flies back in by what was kept. 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 |
||
|
|
4a1cc5240a |
Dock the HUD: every tool and readout on one rail along the bottom
The overlay had grown by accretion: a search box floating top-centre, a readout panel bottom-left, a range readout bottom-right, and nothing that said these were parts of one instrument. This puts them on one rail across the bottom of the viewport — the dock — with a tab strip pinned to the bottom edge and whichever panel is open growing upward from it. The top of the screen keeps only the scale ladder and the nameplate, so the map itself is what fills the frame. Three tabs. SEARCH is the old search, with its field pinned to the bottom of the panel and the results growing upward above it, so the thing being typed into never moves while the list grows. READOUT is the old bottom-left panel. DISPLAY is new: five layer toggles — labels, orbits, grid, deep sky, sky — each a real scene object switched by visibility, except the ones the galaxy crossfade already rewrites every frame, whose toggles fold into that crossfade instead of fighting it. The range readout sits on the strip itself, so it is readable whatever is open. Behaviour worth stating: choosing a search result hands the panel straight back to the readout, since the thing to look at is now the scene. `/` opens the search from anywhere. Below `sm` the dock is the strip alone; a tap opens a panel as a sheet, a tap on the scene folds it away. The body-detail page gets the same dock with only the search — the info panel is its reading. Two things found on the way. CSS2DRenderer gives every label its own z-index for depth order, and the label host created no stacking context, so labels painted over every HUD panel; `isolate` on the host keeps them under. And starmap-hud's readout tests were really tests of the panel that moved, so they moved with it. Verified: build clean, 535/535 unit, 6/6 end-to-end, design detector clean, screenshots at 1440×900 and 390×844 across galaxy, galactic, system, body-detail, all three tabs and the layers-off state. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016jxMkwA2rbicdGxHosecYi |
||
|
|
650b3b37a0 |
Fix what the review confirmed: anchoring, overlap, honesty, one voice
Fourteen findings from an adversarial review pass, applied together because most share two roots — geometry written against assumptions the renderer does not hold, and a design language spelled out longhand until it drifted. Correctness. The leader line pointed at empty space: CSS2DObject centres a label on its anchor by default, and margin only nudges the centred box — the overlay now anchors the left edge (center 0, 0.5) so the hairline meets the star. The info panel and not-found panel returned to top-4 at sm, under a search field that is 26rem wide and centred, covering the back button on every viewport from 640 to 1088px; they now wait for xl. The search empty state asserted "nothing matches" while the catalogues were still loading — and forever if they failed — so it now waits for the index. "Matches 8" was the page size wearing the costume of a count; the header now reports the real total, with the cap stated when it bites. The nameplate un-hides at lg instead of sm, clear of the rail and the object card. theme-color matches the void again. Accessibility. Tabbing to search changed one hairline's hue; the wrapper now carries the old ring as a visible focus indicator. Structure. hud-surface names the panel recipe that had been inlined at seven sites and had already forked into /85 and /92; the backdrop blur it carried is gone from every near-opaque panel — the canvas beneath redraws every frame, so each blur was re-sampled continuously for an effect the fill hid — and survives only as blur-sm on the genuinely translucent search shell. type-label and type-eyebrow name the two label voices, retiring 0.14em and the stray hover:bg-accent/10. The Measured/Derived rows both cards pasted twice each live once in ReadoutSectionsComponent; the reticle and chevron each draw from a single geometry, the reticle's stroke held in screen pixels so one mark serves every size. The acquire wipe plays once per search, not once per keystroke, because both outcomes now share one panel. hud-banner, which styled nothing since the rule was deleted, is a data-testid — the convention its own file already used. 527 unit tests, 6/6 end-to-end, production build, and a driven screenshot: every label now hangs off its star with the hairline touching the point. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01WaySiNst4HhDXBHnMy8p5G |
||
|
|
0dcd49c777 |
Merge main again: readouts built once, said in the instrument's voice
Main moved while the previous merge was being verified. It brought the shared bodyReadouts builder — one source for a body's measured and derived rows, used by the detail page and the system view's new object card — plus the derived-value asterisk in the HUD readout panel. All of that data flow is kept. The templates it arrived in are restyled to this branch's idiom: the info panel and the object card share the same organism (header, full-bleed readout rows, provenance line, route rail), the object card's route rail sits at the bottom because there the route is the next step rather than the way back, and the derived asterisk and its footnote keep their meaning in sentence case. The card also needed the restyle to render at all — it arrived wearing hud-panel, a class the observatory system no longer defines. Verified: build clean, 527/527 unit, 6/6 e2e, design detector clean. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016jxMkwA2rbicdGxHosecYi |
||
|
|
a965aed1db |
Merge main, carrying the observatory instrument onto its rebuilt chrome
Two HUD redesigns happened in parallel: this branch restyled the old chrome as a precision observatory instrument, while main rebuilt the chrome against screenshots of the Star Citizen starmap — a scale ladder, a nameplate, a readout panel, and two-line labels that say what a thing is, not just what it is called. This merge keeps everything main's rebuild learned and says it in this branch's voice. Kept: the ladder's reachability semantics and test hooks, the two-line name/kind labels and their shared declutter logic, system-view body labels, every readout. Restyled: chamfered clip-path panels become hairline frames with corner-tick brackets; Orbitron is gone and one readout face carries the hierarchy; the hexagon reticle becomes the same circle-and-ticks mark the search field wears; focus states move to real focus-visible outlines; the long uppercase caveat notes drop to sentence case so they read as sentences. Two merge-borne fixes along the way: the labels' translate offset moved into .map-label as a margin (CSS2DRenderer rewrites the inline transform every frame, the margin is the offset it cannot touch), and the info panel's new Derived section picked up the horizontal padding it lost when the panel moved to per-block padding. Verified: build clean, 496/496 unit, 6/6 e2e (on a free port — 4300 is occupied on this machine), design detector clean, screenshots reviewed at 1440x900 and 390x844 across all four views plus search states. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016jxMkwA2rbicdGxHosecYi |
||
|
|
836816ffbd |
Restyle the HUD as an observatory instrument
Replaces the generic rounded dark cards floating over the scene with a single instrument language: hairline frames cut by accent corner ticks, a viewport frame that reads the whole screen as one panel, and readouts whose figures are what the eye lands on. - styles.css: retune the tokens (deeper void/panel, brighter text/muted so every label clears 4.5:1 even over the brightest part of the skybox) and add two utilities — `hud-brackets` draws the four corner ticks from eight background gradients so no panel pays for them in DOM, `hud-acquire` wipes a panel down on mount as its one authored moment (reduced-motion aware). - Drop Orbitron: every string in this UI is a measurement, an identifier, or a catalog label, so one readout face carries the hierarchy through weight, size, and tracking — and the HUD paints one font request sooner. - Search: reticle mark instead of a magnifier, transparent field inside a framed shell, results as a dense two-column list with a match count, and the previously missing empty state. - Info panel: return rail, name/class header, and a readout table with tabular figures and the unit tinted back off the number. - Star labels: a hairline leader back to the star they name. The offset moved from `translate-*` to a margin because CSS2DRenderer overwrites the inline transform every frame, which silently beat the old classes. - Both top-anchored overlays drop below the search field under `sm` so they no longer stack on top of it on a phone, and focus moved from a removed outline plus ring to real `focus-visible` outlines. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016jxMkwA2rbicdGxHosecYi |
||
|
|
7b0f32f71a |
Assemble a body's readouts once, not once per panel
Follow-up to review on #3. The card and the detail page each built their own Measured/Derived split, kind label and provenance sentence — the drift buildBodyViewModel exists to prevent, re-forked one layer up, and the drift would have been in which side of the measured/derived line a quantity falls on, which is the distinction those panels exist to draw. One bodyReadouts(body) now returns both blocks and the sentence, and both templates iterate it. The two surfaces render identical rows as a result, and the card gains the inclination the detail page already showed. Also from that review: - KIND_LABELS was duplicated between the two panels; it now lives beside bodyReadouts. The third copy the review pointed at is a different union (search results are star/body/exoplanet, and label a body "Body"), so it stays where it is. - CardRow was HudReadout renamed. Both are now Readout, which HudReadout extends with its derived flag. - The enterable-systems count was a 21-line lazy memo over arrays that are already in hand; it is one expression where those arrays are assigned. - buildBodyViewModel now carries hostStarId, so the detail scene stops rescanning both catalogues for something the builder had already resolved. - heliocentricPeriodDays was called twice for the same body. - The superscript helper was a split/map/join; it is a replace. - info-panel had five computed() each wrapping one pure call with a non-null assertion, beside a template that inlined the same kind of call directly. They are gone with the shared readouts. - Dropped a tautological test that compared a pure function to itself. Replaced with one that asserts the host star id the builder now carries. - Removed the orphaned doc comment left behind when formatParsecs/formatAu moved out. And one the review raised as out of scope but is worth taking: formatRadiusKm grouped thousands above its decimal threshold and not below it, so 69,911 km sat beside a bare 6371 km. Both are grouped now. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01WaySiNst4HhDXBHnMy8p5G |
||
|
|
1019727a39 |
Say what is known about a world, and how it is known
Four changes to the readout panel and the body cards, which between them were showing less than the catalogues hold and not always distinguishing a measurement from an inference. Picking a planet used to navigate straight to /body/:id. That tore down the system scene and the camera with it, so comparing two planets meant flying back into the system between each. Hovering a body now raises a card over the live view and clicking pins it; Full view still opens the route for the full 3D inspection. Clicking empty space unpins, and leaving the system clears it. The card and the detail page were assembling "what do we know about this world" independently, which is the shape of bug where a planet reads 255 K in one panel and 254 K in the other. Both now build from one shared view model. Orbital period was absent everywhere. For a heliocentric orbit it follows exactly from the semi-major axis, because in these units the Sun's mass is the unit of mass — Mars comes back 687.0 d against a published 686.98. It is deliberately not computed for moons, whose elements are relative to a parent planet the catalogue has no mass for, nor for exoplanets: periodDays is populated for none of the 6319 shipped records and hostStarMassSolar for none either, so any figure would assume a solar-mass host and mis-state every planet around an M dwarf. Where a period does exist it is filed under Measured or Derived according to which it is, not by its field name. The system readout showed a flat 0.00 pc for the Sun's distance, which is arithmetically right and reads as a bug — the distance from here to here is not a measurement, so it is suppressed. It gains the host star's luminosity, marked as derived, and counts moons separately from planets. The neighbourhood readout gains the one thing the star field cannot show: how many of those points can actually be entered. Derived readouts carry a marker and a footnote saying so. Every quantity now formats through one module whose precision follows magnitude, rather than a fixed decimal count per call site that read as false precision at one end and lost real information at the other: 0.0026 AU stays legible instead of rounding to 0.00, and Pluto's period reads 248 yr rather than 90560 d. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01WaySiNst4HhDXBHnMy8p5G |
||
|
|
ac296f5133 |
Derive a surface for every body that was never photographed
Fifteen bodies here have a real photograph. Every exoplanet does not, and never will on current instruments — none has ever been imaged — and nor do several of the solar system's own moons. Those all shared one crude stand-in: a few noisy bands tinted by category, cached per colour, so every exoplanet in the app was literally the same picture. They now get a surface reasoned from what has actually been measured. The chain is standard at every link. A host star's luminosity comes from its catalogued apparent magnitude and its parallax distance — that pair is exactly an absolute magnitude — plus a bolometric correction for its spectral class. The correction is not optional: an M dwarf radiates most of its light in the infrared, so its visual magnitude understates it more than tenfold, and M dwarfs are what most nearby planet hosts are. Luminosity and the semi-major axis then give an equilibrium temperature, mass and radius give a bulk density, and size, temperature and density together give a class of world. Checked against the solar system the temperatures land on Earth 255 K, Jupiter 112 K, Neptune 46 K, all within a kelvin or two of published values, and 51 Pegasi b comes out at 1227 K against a published 1200. Each class carries a palette reasoned from its chemistry — methane absorbs red light, which is why the ice giants are blue — and a structure: zonal bands for a body with a fluid envelope, because a rapidly rotating atmosphere organises into them, and fractal terrain for one with a solid surface. Polar caps grow and shrink with the derived temperature, which is the clearest visible consequence of the whole chain. The generator samples three-dimensional noise along the sphere rather than a flat field, so there is no seam to stitch at the antimeridian and no pinching at the poles, and it writes into a byte array rather than a canvas — a pure function, testable, with no 2D context to be unavailable. Two things the derivation cannot do, both stated on screen next to the measurements it rests on. Equilibrium temperature ignores greenhouse warming and internal heat, so Venus comes out at 300 K against a real surface of 737 K and Io, kept molten by tides, classifies as ice. And these are illustrations: reasoned, but not observations. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01WaySiNst4HhDXBHnMy8p5G |
||
|
|
d7e8ea1d4d |
@
Add star-map Angular app, ETL pipeline, and caveman plugin Angular 3D star map (galaxy/system/body views, Three.js rendering, navigation store) plus the NASA ETL tooling that builds the star, exoplanet and solar-system datasets, Playwright e2e suite, and the cs:caveman Claude Code plugin (command, agent, skill). Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> @ |