fc7677e715923bb0d7430bf7b06c4eb341849190
28
Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
fc7677e715 |
Turn Nereid in the 11.594 hours Kepler measured, where it was drawn still
Nereid's Horizons page states no spin, and the ETL, finding none, left it still; the validator's
comment read that as "Nereid has no spin". Its rotation is measured: Kepler's K2 light curve gives
11.594 +/- 0.017 hours, confirming earlier ground-based periods (Kiss et al. 2016, MNRAS 457, 2908;
arXiv:1601.02395). Its spec now carries that day, as Eris's carries Bernstein et al.'s, and with no
known pole it turns about its orbit normal, as Eris, Haumea and Makemake do. The free-spinner check
accepts it (11.594 hours against a 360-day orbit).
A new validator: a moon without a lock must have a day unless it tumbles, and only Hyperion
("Rotational period = Chaotic") does. Nereid, left without one, fails it: "Moon nereid is drawn not
turning, and is not known to tumble". The renderer spec's example of a body left still was Titan,
said to have no period on Horizons, though it carries its orbit's; it is Hyperion now, and
BodyRecord.rotationPeriodHours says where each kind of period comes from.
Measured: the solar ETL passes; in bodies.json only Hyperion has no rotationPeriodHours; live on
:4301 Nereid's marker turns 60.000 degrees in a sixth of its day. Test: Nereid, as shipped, turns 60
degrees in 1.93 hours. Guarded mutant, the day removed from its spec and run through the solar
ETL: the validator fails, and the suite on the data it wrote fails that test and only it.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
|
||
|
|
3b4fd1af6c |
Turn each locked moon at its orbit's rate and Iapetus's pole round its orbit, so they face their planets at every date the clock reaches
The IAU gives a locked moon's W the mean motion of whichever orbit its authors had, and JPL's table has another. Near the present the difference is nothing; over the clock's AD 1 to 3000 it turned Proteus's far side to Neptune at AD 1 (146 degrees), Mimas 52 degrees from Saturn and Miranda 23. Iapetus was worse for another reason: its IAU pole is a straight line, 3.9 degrees a century in right ascension, through its orbit normal's 3 439-year circle round the Laplace pole, which by AD 1 has run past the celestial pole (Dec 97.9), 11 degrees off the orbit, with the face 87 degrees from Saturn. Mimas and Iapetus carry mission maps, so a wrong hemisphere was drawn facing Saturn. The ETL's lock check sampled only 1950-2100, so none of it failed. tools/etl/lib/locked-spin.ts, lockedToOrbit, called for every locked moon: - W's rate becomes the orbit's own mean motion, its constant moved so W is unchanged on 2025-01-01; the pole and every periodic term stay the IAU's. A W with a quadratic is left (Phobos's orbit already takes it; the Moon's is its tidal slowing, 0.75 degrees at AD 1). The kernel's rate must be within 1e-5 of the orbit's first (at most 3.4e-6, Iapetus). - Iapetus (poleFollowsOrbit): the pole follows its orbit normal, as a moon in a Cassini state does, in the IAU's own form: sines of the node's angle and four harmonics on right ascension, cosines on declination, fitted to the normal's circle and pinned to the IAU pole at the present; W takes sines of the same angles, fitted to hold the face where it is today. build.ts samples the lock over AD 1 to 3000 (8 114 dates, every 135 days) instead of 1950-2100, and subPlanetLongitudeDeg moved to the lib, shared by both. Measured on the real catalogue: at most 5.36 degrees (Titan) but the Moon 7.62 (its eccentricity, and W's quadratic at AD 1: a new named ceiling of 8), Mimas 8.94 (ceiling 11 -> 9.5) and Iapetus 15.95 (19 -> 16.5, 9.4 of it its row's lag); Proteus's own ceiling of 9 is gone, at 2.66. Iapetus's axis stays within 0.74 degrees of its orbit normal (11.06 before) and its pole is the IAU's at the present to 1e-4 degrees. Live on :4301, the longitude facing the planet at AD 1 / 1000 / 2025 / 2999: Proteus 2.6 / 2.6 / 2.6 / 2.6 (was -146.5 / -72.9 / 2.6 / 74.5), Iapetus -15.9 / -15.4 / -15.3 / -9.3 (-87.0 / -50.9 / -15.3 / 22.8), Mimas 4.1 / 6.8 / 5.7 / 8.4 (48.6 / 29.3 / 5.7 / -13.0), Miranda -0.1 / 2.2 / 0.0 / 1.4 (-23.4 / -9.6 / 0.0 / 12.6); the present is unchanged. The renderer spec now takes the rotational elements from bodies.json too, so no hand copy is left, and a new test turns Proteus, Miranda, Mimas and Iapetus to their planets at AD 1 and AD 3000. Guarded mutants, each run through the solar ETL and then the full suite on what it wrote: lockedToOrbit bypassed (validator: Mimas 52.30, ceiling 9.5; the new test fails), Iapetus on the IAU's straight pole (98.48), and its pole round the orbit without W's terms (73.13); each fails the new test and only it. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> |
||
|
|
28fa79e1e0 |
Check the Horizons vectors against the bodies.json the app ships, and every rate Standish's rows give
The frozen Horizons tests ran on a hand copy of seventeen records, so an ETL that lost Standish's a, e and i rates, or Io's and Europa's backward periapses, wrote a bodies.json that passed both its own validators and the whole unit suite: the data-refresh job's "Unit tests against the new data" read none of it. record() now takes kind, orbit, rates, laplacePole, parentBodyId and massRatio from src/assets/data/bodies.json, read with node:fs as texture-catalog.spec.ts reads its JPEG, and the copy is gone. Today's data passes as the copy did (all seventeen were identical). The parser test checked only the mean motion and the periapsis rate on Earth's row. It now checks the node, a, e and i rates too, against Standish's Table 2a (-0.24123856, -0.00000003, -0.00003661, -0.01337178 a century). Dropped, those rates move Saturn 0.66 degrees at AD 1 (node) and 0.36 at AD 3000 (a, e, i), where no date from 1950 to 2100 shows more than 0.036. Guarded mutants, each run on the full suite: - bodies.json without the a, e and i rates, as that ETL writes it: 'puts saturn within 0.1 degrees of Horizons on JD 2816787.5' and Earth's fail (and the new orbit-line test, on the same data). - bodies.json with Io's and Europa's periapsis rates turned positive: Io's and Europa's 1950 tests fail. - the parser without its a, e and i rates, and with a node rate of 0: 'gives the rates per day' fails, and only it. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> |
||
|
|
3e1bd33b6c |
Draw every body in a system on one shared sphere, so returning to the Sun's system is no long task
Each marker built its own 64 by 32 SphereGeometry, and the Sun's system now has 38 of them: the
renderer's constructor took 15 ms, 12 of them building spheres, and with their first upload a
return to the system made a long task of 52 to 70 ms that the base's 18 bodies never did.
Every marker is now the one unit sphere, scaled to its radius, which it keeps in
userData.radiusAu. The shared sphere is never disposed; Saturn's ring is built in the sphere's
own units, since it is the marker's child; keepMarkersLegible reads the stored radius and scales
against the sphere's.
Measured on :4301, eight returns to the Sun's system each (select null, then 0, at 1600x1000):
before, a long task on 3 of 8 (52-57 ms), swapToSystemSpace 13-17 ms and the first render 30-40;
after, no long task on 8 of 8, the swap 2.7-4.4 ms and the first render 20-38. Earth is drawn at
the same 0.656 AU at arrival, and every member shares one geometry.
Tests: one sphere for every marker, each at bodyMarkerRadiusAu of its radius, and not disposed
with its system; Earth held to its 3-pixel floor at the arrival framing, which no test covered.
Guarded mutants, each failing only its named test: a sphere per marker, the shared sphere
disposed, the ring built in AU inside the scaled marker ('picks Saturn through its rings'), and
the legibility scale divided by the body's radius.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
|
||
|
|
c2683da37b |
Redraw a planet's orbit line as its axis and eccentricity drift, so Saturn stays on it at AD 1
The orbit lines kept the shape of the J2000 elements and only turned with the node, while the markers moved on Standish's drifting a and e. Saturn's eccentricity falls 0.00032 a century, so at AD 1 its line passed 0.056 AU (8.4 million km) from Saturn, Jupiter's 0.016 AU from Jupiter, and Pluto's 0.021 AU from Pluto at AD 3000. The comment that said no drawn line shows the drift weighed one century of Pluto's axis, not twenty of Saturn's eccentricity. update() now writes the line's 129 points again once |da| + a |de| since they were drawn passes 1e-4 AU, well under the 128 chords' own sag. Measured in the app on :4301, marker to its own polyline: Saturn 0.0016 AU at AD 1 and 0.0028 at AD 2999, Jupiter 0.0014 at AD 1, Pluto 0.0078 at AD 2999 and 0.0082 today, all the chord sag. The existing Mars test checked only that Mars stays in its line's plane. A new test measures the distance to the drawn chords: Saturn 0.0017 AU and Mars 0.0005 at AD 1 (0.054 and 0.0022 without the redraw). Guarded mutants: the call removed, and the threshold raised to 1 AU, each fail it and only it. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> |
||
|
|
83dc46416b |
Test an exoplanet's aphelion in the framing radius and a derived surface's white, and give Earth's old TDB error as 8.6 degrees
Two lines the review found unguarded, each now held by a test that fails without it:
- outermostRadiusAu takes an exoplanet's eccentricity as well as a solar-system body's.
|
||
|
|
c45d9160e3 |
Frame the Sun's system on Eris's aphelion, the furthest it draws, not on the grid ring inside it
The scene framed the grid's outer ring, sized from the largest semi-major axis, and two comments said the ring was "always the wider of the two, by construction". That held until Eris came in: its a = 67.93 AU gives an 80 AU ring, but with e = 0.438 its orbit reaches 97.7 AU, and Eris is 95.5 AU out now. The 12 per cent margin protected the ring, not Eris. The review measured Eris's orbit at 0.982 of the half-width on a 390x844 phone (3.5 px from the edge), 0.987 on 1000x1400, and on a 1000x1000 window Eris's marker at NDC 1.002, off screen on arrival. SystemOrbitsRenderer.gridOuterRadiusAu becomes outermostRadiusAu: the ring, or the largest top-level aphelion a(1 + e) where that runs past it. The scene frames that. Some orbit runs past its ring in 303 of the 1 190 exoplanet systems too (counted on exoplanets.json), and they are framed the same way. The 500 AU ceiling rises to 600: the aphelion needs 508 AU on a 390x844 phone, and 600 holds it with its whole margin down to an aspect of 0.39. The comments are corrected. Measured in the app on :4301 after entering the Sun, Eris's drawn orbit, largest |NDC x| over its 129 vertices (review's figures before): 390x844 camera 507.9 AU 0.804 (0.982) 1000x1400 camera 328.5 AU 0.805 (0.987) 1000x1000 camera 234.7 AU 0.812 (1.004, marker off screen) 950x1000 camera 247.0 AU 0.810 1600x1000 camera 234.7 AU 0.508 (0.627) No orbit vertex of Neptune, Pluto, Eris, Haumea or Makemake is off screen at any of them. The cost: inner bodies arrive smaller, the landscape camera 235 AU out instead of 192. Tests: renderer 'reaches as far as an eccentric orbit goes past the grid: Eris's aphelion, 97.7 AU, not the 80 AU ring' (and the ring where every orbit stays inside it), and framing 'leaves Eris's aphelion its whole margin in every window shape'. Controls, each failing its named test only (1 failed, 839 passed): framing on the ring alone; the ceiling back at 500 AU. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> |
||
|
|
85cb66e63c |
Test that a photograph shows in its own colours once it reaches its body
Since
|
||
|
|
cbe4908219 |
Turn Earth by the Earth Rotation Angle, so its lit face stays Horizons' at AD 1 as it is today
Earth was turned by its IAU W, taken at the clock's UT plus today's 69.184 s. That W is a straight
line fitted to the present: 360.9856235 degrees a day, which, once its pole's -0.641 degrees a
century in right ascension is counted, runs 6.3e-6 degrees a day slow of Earth's real turning. The
followsUt comment said the clock's date "already says how far it has turned"; it did not. Against
Horizons (observer quantity 14 from the Sun, TIME_TYPE=UT, Earth one light-time back) the drawn
sub-solar point was 2.3 degrees off at AD 1000 and 4.5 at AD 1.
Earth is now turned by the IERS Earth Rotation Angle (IERS Conventions 2010, eq. 5.15) at the
clock's date, counted from the node the IAU's W starts at, 90 degrees past the pole's right
ascension. The pole is unchanged. Drawn minus Horizons, in degrees:
date before after
2025-06-01 12:00 (unit) +0.06 -0.003
AD 1000, JD 2086455 (unit) -2.3 -0.001
AD 1, JD 1721600 (unit) -4.5 +0.051
live app, :4301, same probe as the review's
JD 2460900.25 +0.089 +0.005
JD 2086300.5 -2.281 +0.010
JD 1800000 -4.049 +0.056
JD 1721450.75 -4.530 +0.072
At noon UTC on 1 June 2025 the Sun now stands over 0.52 W on the drawn sphere, where the equation
of time puts it at 0.53 W (0.43 W before).
TT_MINUS_UTC_DAYS had no other use and is removed; its comment also counted 37 leap seconds where
UTC has taken 27 on top of the 10 s it started from in 1972.
Tests: body-orientation.spec 'lights Earth's face where Horizons does at the far end of the clock
too: AD 1000 and AD 1' (within 0.15 degrees), and the renderer's AD 1000 Earth test now checks the
drawn face against Horizons instead of against the IAU W the old code used. Control: turning Earth
by its IAU W at UT + 69.184 s again fails both named tests (2 failed, 834 passed). The README says
which model turns Earth.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
|
||
|
|
d93bb1ee2c |
Say that Pluto's tilt is checked against its own IAU pole, not against Horizons
The ETL's obliquity check, its failure message and the renderer spec's test name all compared Pluto's drawn tilt with "the obliquity Horizons gives", as |
||
|
|
2d4b8a98d5 |
Put each body's photograph on it one frame at a time, so entering the Sun's system no longer stalls
buildMarker gave every photographed body its map at once. A texture is copied to the GPU in the first frame that draws it, and the 28 maps arrive within about 40 ms of each other, so that frame copied some 20 megapixels of JPEG (seven maps at 2048x1024) through copyExternalImageToTexture: a second long task of 135-162 ms about 1.25 s after entering, measured here four times on the committed renderer (reviewers measured 160-210 against 85-100 without the 18 new maps). de34fff's "adds no long task" was measured before those maps landed. A photographed body now starts in its kind's flat colour, as a derived one does, and its texture waits in a queue; each update() puts the first one that has loaded on its body. The copies are spread one a frame, and all 38 bodies have their maps within half a second of the first. In the running app, five fresh entries into the Sun's system at 1600x1000 left one long task of 52-66 ms or none at all ([66], [52], [62], [], [56] ms, where the committed renderer gave [62, 149], [56, 135], [74, 162], [78, 162]). Control: putting every loaded photograph on in one frame fails "puts them on their bodies once loaded, one a frame". Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> |
||
|
|
8c4f1c11c9 |
Build a body still waiting for its surface with a null map, so three stops warning on each one
Since
|
||
|
|
036af5f02d |
Test what the drawn solar system claims at far dates and on Saturn's ring
Three claims had no test that fails without them: - Standish's rates for a, e and i. The frozen Horizons vectors run from 1950 to 2100, where dropping them moves a planet at most 0.036 degrees (Saturn in 2100), inside every ceiling; the clock runs to AD 3000, and the long span is what those rates are for. Two vectors from Horizons (DE441) for 3000-01-01 now join the table: the Earth-Moon barycentre, 0.005 degrees out (0.129 without the rates), and Saturn's, 0.065 (0.412). - A planet's orbit line turned each tick with its node and periapsis: only the Moon's and Pluto's were tested. Mars must stay on its own line 730 000 days before J2000; on a line left at J2000 it is 3.3 million km from it at AD 1. - Saturn's ring lit and drawn from both faces, which dc20acc's title claims and the tests, reading only its geometry and picking through its front face, never checked. Controls: the three rates dropped fails "puts earth within 0.02 degrees of Horizons on JD 2816787.5" (and Saturn's); the top-level line left unturned fails "turns a planet's drawn orbit with its node"; an unlit front-face-only material fails "is lit, and seen from either face". Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> |
||
|
|
34ae803c06 |
Take TT - UT from the historical record before 1972, so the far dates the clock reaches turn every body by the right amount
The clock reaches AD 1, but TT - UT was held at today's 69.184 s. At AD 1000 it was 1 574 s and at AD 1 about 10 570 (Espenak and Meeus, NASA's Five Millennium Canon; Horizons' TDB - UT gives 1 658 and 10 466 on JD 2086455 and 1721600). So every spin but Earth's was (ΔT - 69 s) times its rate out, Jupiter 15.2 degrees at AD 1000 and 106 at AD 1, Mars 6 and 43, and every orbit that much behind: the Moon about 0.2 and 1.4 degrees. ttMinusUtSeconds gives TT - UT for a date on the clock: the Espenak-Meeus polynomials before 1972, 32.184 s plus UTC's leap seconds from 1972 to the last one, at the start of 2017, and 69.184 s held after it, as Horizons holds it. Its pieces join within 0.1 s. tdbFromUtc, which positions and spins already share, now adds it. Within 0.2 s of Horizons in 1950, 105 s at AD 1 and 86 s at AD 1000, where the historical record itself is that uncertain. Earth is the exception: its turning is what UT counts, so the clock's date already says how far it has turned, and ΔT would turn it again, 44 degrees at AD 1. Its W, fitted to today, keeps today's 69.184 s (bodyOrientation's followsUt, set for Earth in the system view and on its page). In the running app at 1000-01-01 00:00 UT, Jupiter's drawn prime meridian sits 0.000 degrees from its IAU W at TT and 15.164 from where the held offset put it; Earth's sits on its W at UT + 69.184 s, 6.288 degrees short of what TT would have turned it to. The renderer spec now hands its frozen Horizons vectors over as the UT dates that name them through the same TT - UT, and checks Jupiter's and Earth's prime meridians at AD 1000. Controls: the leap-second rule used before 1972 fails "follows the historical record before 1972"; TT - UT held at 69 s fails "turns Jupiter at AD 1000 by its W"; Earth turned at TDB, or the renderer or the page not keeping it on UT, fails the Earth tests. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> |
||
|
|
d4808788ec |
Take the orbits at TDB as the spins already were, so a locked moon faces the planet it is drawn round
Every element set here runs on TDB: Standish's T_eph, the SSD satellite and SBDB epochs, the IAU's d and T. bodyOrientation already took the clock's UTC to TDB, but SystemOrbitsRenderer.update and the body page's heliocentricPosition fed the UTC date straight to meanElementsAt, so in one frame each body's place was 69.184 s behind its spin. That is n x 69 s of orbit: Phobos 0.90 degrees, Mimas 0.31, Deimos 0.23, Enceladus 0.21, Miranda 0.20, Io 0.16, Tethys 0.15, Europa 0.08, the Moon 0.011. 48319c3's table measured the app at a UTC date against Horizons at the same number read as TDB, which hid it, and its "nothing for anything else" was wrong: Io's 0.16 is four to five times Io's worst model error there (0.035). tdbFromUtc, in constants.ts, is now the one conversion, and positions and spins both go through it. In the running app, clock pinned to 2025-06-01 12:00 UTC, Io's face towards Jupiter is at 0.024 E, latitude -0.009, where Horizons (observer quantity 14 from Jupiter's centre) has 0.036 E and -0.003: 0.012 degrees apart, where it was 0.175. The renderer spec checks that point, and now hands its frozen Horizons vectors, which are TDB, to update() as the UTC dates that name them, 69.184 s earlier; the same frozen rows fed at the UTC date fail for Io and Europa. A body-page test checks that the Sun lights the point it stands over at the same TDB instant the body is turned for. Controls: taking the renderer's orbits at the clock's UTC fails "faces jupiter and the Sun with the points Horizons gives on io"; taking the page's Sun there fails "takes the Sun where it stands at the same TDB instant". Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> |
||
|
|
f8ee3ac3ab |
Move Mimas, Tethys and Phobos along their orbits by the terms their IAU W already carried
The IAU W of a locked moon follows its mean longitude, so a term of W that is the moon running
ahead of and behind its mean motion is its orbit's too. Two were in bodies.json's W and in no
orbit: the 71-year libration of the Mimas-Tethys 4:2 resonance, -44.85 degrees on Mimas and
+2.23 on Tethys on the angle S5 = 316.45 + 506.2 T of pck00011.tpc, and Phobos's tidal
quadratic, 9.536e-9 degrees a day squared about J2000. JPL's satellite table has a column for
neither. orbitalTermsOfPrimeMeridian now turns each into the row's meanAnomalyTerms about the
row's own epoch (Phobos's 1950 row gets the quadratic re-centred, which adds to its mean motion
and mean anomaly at the epoch), and the ETL takes them for the three moons named in their specs.
Against Horizons: Mimas on 2026 May 27, near the libration's extreme, 2.24 degrees instead of
43.3; Tethys the same day 0.18 instead of 2.05; Phobos in 2100 1.25 instead of 11.1. On the
ETL's 2025-01-01 check Mimas is 1.56 degrees, so its named 46-degree ceiling is gone. The renderer
spec freezes the Mimas and Phobos vectors.
The day-equals-orbit check checked a number that turns no locked moon: since
|
||
|
|
dc20accfdf |
Draw Saturn's rings in the system view, lit, at the radii their texture draws
Audit #47. The body page's rings already lie in Saturn's equator (
|
||
|
|
cdf474bcd5 |
Turn every body in the system view by its IAU pole and prime meridian, so the lit face is the real one
Until now each body's axis was its orbit normal, tipped by the obliquity about the orbit's node, an azimuth the data never gave. Its phase started at an arbitrary point at the elements' epoch. The rate and the sense were real; the face towards the Sun was not. Now each of the 33 bodies with IAU elements is set, every tick, from its pole and its W at the clock's date. Eris, Haumea and Makemake keep the old fallback: their published period, about their orbit normal. None of them has an obliquity, so the tilt code that only served bodies now turned by the IAU is gone. Exoplanets have no rotation published and stay still, as before. The texture convention is settled once, in src/app/shared/rendering/body-orientation.ts (MAP_TO_BODY): - SphereGeometry runs u eastward about +Y from a seam on -X, so u = 0.5 faces +X. - Every photograph in the catalogue is centred on longitude 0 with east to the right. Checked on the maps: Greenwich; Olympus Mons 134 degrees left of centre; Mare Crisium right and Mare Orientale left; Kuiper just left. - A map labelled in west longitude is still drawn east-right, so where longitude 0 sits is the only question, and for all of them it is the centre. - So a quarter turn about X puts the map on the IAU body frame: pole +Z, prime meridian +X. The scene is already ICRF equatorial (the ecliptic is turned into it by the J2000 obliquity), so the pole goes in as it is. The equator frame is built through laplacePlaneToEquatorial, the same conversion the moons' Laplace planes use; moonFrame now calls it too. The clock is UTC and the elements TDB, so TT - UTC (69.184 s) is added: Earth turns 0.29 degrees in that time, Jupiter 0.70 and Phobos 0.90. Measured on the live app (port 4311), clock pinned to 2025-06-01 12:00 UTC: - The Sun stands over 0.433 W, 22.125 N on Earth's drawn sphere. The equation of time puts it at 0.53 W. - Each body was drawn one light-time earlier and compared with Horizons' observer quantities 14 and 15: - Earth (from the Sun): longitude 0.095 off. - Mars: sub-Earth 0.001, sub-solar 0.004. - Jupiter: sub-Earth 0.005, sub-solar 0.002. - The Moon: sub-solar 0.004; sub-Earth 0.699, which is the error of its mean orbit. - Horizons' latitudes are planetodetic. Raw, they differ by the flattening: Earth 0.14, Mars 0.23-0.27, Jupiter 0.33, the Moon (a sphere) 0.000. The unit tests put the same comparison through real raycasts on the drawn spheres' texture coordinates, with the latitudes put on each body's flattened figure. Every residual is within 0.09 degrees, but for the Moon's sub-Earth point (0.70 and 0.09). The retrograde tests of #33 are rewritten for the IAU's convention: a planet's named pole is the one on the north side, so W runs backwards for Venus and Uranus, while Pluto follows the right-hand rule. The spin read off the drawn sphere, against the drawn orbit's normal, is 177.36 for Venus, 97.77 for Uranus and 119.61 for Pluto, all past 90, and 23.44 for Earth. Each is within 0.5 of Horizons. Six mutants, each failing its named test: the map upside down; UTC taken for TDB (Jupiter's test); W turned the wrong way (the retrograde test, and again Earth's noon test); moons, or planets, not turned by the IAU; and the fallback ignoring a negative period. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> |
||
|
|
de34ffff43 |
Paint a system's derived surfaces after entering it, not while building it
Every body with no photograph gets a surface derived from its measurements, a 128 by 64 texture painted on the main thread as its marker was built, inside the task that enters the system. At about 4.4 ms each (measured in node for the twenty the next commit adds, 88 ms together), that is the cost that grows with the number of bodies: with the solar system at 38 bodies, the long tasks after selectStar(0) were [219, 72], [228, 79] and [177, 72] ms over three runs, against [85, 72], [94, 75] and [78, 67] at 18. buildMarker now gives such a body its kind's flat colour and hands the painting to the renderer, which paints one surface per task (setTimeout 0) once the constructor has returned, and drops the rest if the system is left first. Measured in the running app (port 4311, three runs each, long tasks over 50 ms in the 9 s after entering the Sun's system): - 18 bodies: [79], [73], [77] ms. The task that entered the system is under 50 ms. - 38 bodies: [55, 72], [69, 78], [60, 83], and [52, 78] on a fourth run. The entering task is 52-69 ms, down from 78-94 before this change with 18 bodies, so the twenty new bodies add no long task over what the branch had. What they still add to it is not measured apart. The flat colour shows for a moment: the Sun's 29 derived surfaces were all painted 436, 689 and 399 ms after its renderer was built (three runs), and a surface once painted is cached, so a return visit paints them at once. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> |
||
|
|
7b65ab4812 |
Draw a planet and a heavy moon going round their barycentre, as Pluto and Charon do
Standish's "Pluto" is the Pluto-Charon barycentre, and Charon is an eighth of Pluto's mass, so that point lies 2 131 km from Pluto's centre, 943 km above its surface. Drawn the usual way, with Pluto at its row's position and Charon going round it, Pluto sits where nothing is and Charon's orbit is 2 131 km too wide on one side. A moon record can now carry massRatio, its mass over its planet's. For such a moon the renderer keeps the pivot at the planet's elements, which is the barycentre, and each tick puts the planet massRatio / (1 + massRatio) of the relative separation back from it and the moon the rest out. Both orbits are the relative ellipse scaled, the moon's by 1 / (1 + q) and the planet's by -q / (1 + q), turned with the moon's node every tick: Charon's spans 17 460 km of radius and Pluto's 2 131, round the same point, and neither passes through Pluto. Only Charon will carry it; every other moon's barycentre is inside its planet. Checked against Horizons in the unit suite, on JPL's records for the two: Pluto (999) from the Pluto-system barycentre (9) in 2100 is 2 131.24 km out, and the renderer puts it within 5 km of that length and 0.5 degrees of that direction, exactly opposite Charon at the inverse of their mass ratio; Charon from Pluto is within 0.5 degrees of Horizons in 2100 (measured 0.37). The same table adds Titania, against Uranus's equator 120 years from its 1980 epoch, within 0.75 (measured 0.62). Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> |
||
|
|
48319c3fe2 |
Move the solar system on JPL's mean elements, so it stays right as the clock runs
Every body carried one set of osculating elements from Horizons at 2025-01-01, run forward by
Kepler with a GM from a table of mass ratios. That set is exact at its instant and drifts from
then on, and the clock now runs a month a second: the Moon, with Earth's mass ratio lacking its
own and the osculating axis, went round in 27.70 days instead of 27.32, 66 degrees out after a
year, and its locked face was spun at the same wrong rate.
Planets and Pluto now take Standish's Table 2a/2b ("Keplerian Elements for Approximate
Positions of the Major Planets"): elements against the J2000 ecliptic, their rates per century,
and the b, c, s, f terms of Jupiter to Pluto, fit for 3000 BC to AD 3000. Table 1 is closer near
the present (Saturn 0.23 degrees at worst 1950-2100, against 0.32 here) but is only fit for
1800-2050, and by AD 3000 has Saturn 4.3 degrees out where Table 2 holds every planet within 0.3.
The moons take JPL SSD's satellite mean elements: sidereal mean motion n to ten figures, the
periods of their node and periapsis, and each one's local Laplace plane by its pole. They
propagate with n itself, never a GM: gmForParent and its mass table are gone. Horizons still
gives size, spin and obliquity.
Both tables are read from the Internet Archive's copy of JPL's pages, pinned to one capture: the
live approx_pos page has dropped Pluto, and the live sats/elem page has dropped n and rounds the
period to four or five figures (Phobos 0.3187 d, a revolution out within a decade).
What the tables leave implicit, measured against Horizons before it was accepted:
- The precession periods are magnitudes. A node regresses on a prograde orbit and advances on a
retrograde one; a periapsis advances except where a resonance forces the eccentricity. Io's
and Europa's follow their conjunction line backwards at 2 n(Europa) - n(Io) = 0.74 degrees a
day, which is exactly the 1.625- and 1.394-year periods in the table. Read as advancing, Io
was 0.9 degrees out and Europa 2.1.
- On a retrograde orbit the node's turning is added back to the mean anomaly. Taken off, Triton
drifted a degree a year, 105 degrees by 2100.
- The Laplace frame's x axis is where the plane rises through the ICRF equator, RA of the pole
plus 90. Read against the ecliptic, Io was 2.8 degrees out, Phobos 54 and Titan 127.
Orbit lines are now drawn in their own plane and turned by a quaternion each tick, so a turning
node carries the line with the body: fixed at one date, the Moon's line would be up to 69 000 km
off it nine years on. The Earth row is the Earth-Moon barycentre, 4 700 km from Earth, 0.002
degrees from the Sun. A tidally locked moon's day is now 360 / n, its sidereal period (the Moon
27.321662 d), so it stays locked to the orbit it is drawn on.
Angular error against Horizons VECTORS (ICRF, TDB; heliocentric for planets, planet-centred for
moons), degrees, read from the live renderer's markers in the running app:
body 1950-01-01 1975-01-01 1987-07-23 2000-01-01 2025-01-01 2037-03-06 2050-01-01 2075-01-01 2100-01-01 max
mercury 0.004 0.002 0.003 0.002 0.002 0.001 0.000 0.002 0.000 0.004
venus 0.003 0.007 0.003 0.004 0.004 0.004 0.003 0.004 0.004 0.007
earth 0.003 0.008 0.002 0.005 0.004 0.009 0.003 0.002 0.003 0.009
mars 0.009 0.010 0.008 0.024 0.009 0.012 0.009 0.011 0.028 0.028
jupiter 0.063 0.030 0.171 0.135 0.013 0.020 0.056 0.041 0.075 0.171
saturn 0.080 0.064 0.018 0.320 0.066 0.114 0.044 0.164 0.177 0.320
uranus 0.018 0.169 0.068 0.050 0.101 0.015 0.141 0.017 0.114 0.169
neptune 0.070 0.028 0.004 0.021 0.036 0.037 0.013 0.029 0.072 0.072
pluto 0.045 0.054 0.041 0.033 0.019 0.020 0.023 0.027 0.026 0.054
moon 0.486 1.928 0.127 0.631 1.407 1.086 0.720 0.339 1.180 1.928
phobos 2.068 0.294 0.881 1.113 0.313 0.636 2.089 5.862 11.099 11.099
deimos 0.077 0.043 0.310 0.066 0.164 0.068 0.034 0.468 0.044 0.468
io 0.021 0.015 0.010 0.019 0.009 0.035 0.006 0.011 0.022 0.035
europa 0.036 0.039 0.053 0.064 0.078 0.032 0.006 0.034 0.044 0.078
ganymede 0.132 0.103 0.018 0.007 0.023 0.054 0.091 0.118 0.044 0.132
callisto 0.040 0.019 0.023 0.019 0.038 0.008 0.060 0.119 0.056 0.119
titan 0.003 0.019 0.023 0.023 0.027 0.028 0.048 0.008 0.014 0.048
triton 0.051 0.029 0.009 0.021 0.052 0.048 0.063 0.089 0.137 0.137
Three miss what was hoped for, and why:
- Jupiter 0.17, Saturn 0.32, Uranus 0.17 against the 0.1 hoped for: short-period perturbations
of the giants by one another, which no Keplerian fit carries. Standish states his own Table 2
errors as 600, 1 000 and 2 000 arcseconds (0.17, 0.28, 0.56 degrees). Out to AD 3000, measured
at 1800, 2200, 2400, 2600 and 3000, every planet stays within 0.3.
- The Moon, 1.9: evection (1.27) and variation (0.66), which a mean ellipse leaves out.
- Phobos, 2.1 until 2050, then 5.9 in 2075 and 11.1 in 2100, growing as the square of the time:
its tidal acceleration, which the table has no column for. Its elements are MAR080's, epoch
1950. The map's dates are also UTC where the elements are TDB, 69 s today,
which is 0.9 degrees of Phobos and nothing for anything else.
Held in place by:
- build.ts: each body's mean elements against Horizons' own osculating elements on the ETL's
2025-01-01, at most 0.25 degrees for a planet and 2.5 for a moon (measured: Uranus 0.101, the
Moon 1.407; a regressing Triton node reads 10.24 and fails), and every moon's day equal to its
sidereal period (a 1% error fails).
- Unit tests freezing nine Horizons vectors (Earth 2100, Jupiter 1950, Saturn 2075, Pluto 1975,
the Moon 2050, Io and Europa 1950, Titan and Triton 2100) through SystemOrbitsRenderer, the
Moon kept on its own turning line, the retrograde rule, the Standish terms, the Laplace frame,
and both table parsers. Nine mutants each fail the test named for them, and the two
validators each refuse a mutated build of the real catalogue.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
|
||
|
|
c38a42cbcb |
Fix what the review of this branch found, starting with the pick rule it only claimed
The off-screen rule for clicks was described in
|
||
|
|
225d676ab0 |
Turn each body at its own rate, from Horizons' own figures
The view had one rotation in it — the planet on the detail page, at 0.08 rad/s, a number with no source. Nothing in the system view turned at all. The data was already on disk: every cached Horizons page carries how its body spins, in one of five forms. The rate in radians per second is preferred where it appears, because it is signed — that is how Venus and Uranus are known to turn backwards — then a period in hours or days, then the `9h 55m 29.711 s` the giant planets use, and finally the word every major moon here carries instead of a number: Synchronous. A tidally locked moon's day is its orbit, so Kepler supplies it from the elements already parsed and the parent it goes round. Seventeen of the eighteen bodies come out within 1% of their published period — Earth 23.934 h, Jupiter 9.925 h, Venus -5832.5 h, Io 42.5 h, Callisto 400.5 h. Titan is the exception: its page states no period at all, so it is left still rather than turned at an invented rate. The axis is the orbit normal tilted by the obliquity about the orbit's ascending node, which is where an obliquity is measured from and the only line in the orbit the elements name. The phase at the epoch is published for none of these bodies, so the face turned toward the camera is not a claim; the rate and the direction are. At true rates nothing is visible moving — Earth turns 15 degrees an hour. A clock the reader can run faster is the next piece, and the audit asks for it anyway. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016jxMkwA2rbicdGxHosecYi |
||
|
|
a84e2d3a69 |
Put a reference grid under the system view
A system was a handful of ellipses floating in the dark. You could see that one orbit was bigger than another, but not how big, and not that a planet sat above or below the plane the others share. Adds the same plane-and-tether reading aid the outer scales got: a polar grid in the system's own reference plane, with a drop line from each body onto it. Ring radii snap to a 1-2-5 ladder rather than dividing the system evenly, because the point is to put a number on a distance — 5, 10, 15 AU can be read at a glance and 4.34, 8.68, 13.02 cannot. That holds across the four orders of magnitude real systems span: the solar system gets 5 AU rings, TRAPPIST-1 gets 0.01 AU ones. The outermost ring encloses the outermost orbit rather than falling just inside it. The rings are dashed. Solid ones would sit in the same plane as the orbit ellipses, which are themselves rings, and at a glance a reference circle and a circular orbit are the same picture. Dashes are cut by dropping whole segments rather than by a dashed material: the ring is already built from independent segment pairs, so a material's dash pattern would restart at every one. Drawing the grid exposed a framing bug it made unmissable. The camera settled along one fixed direction derived from the ecliptic, which is face-on only for the one system whose elements are ecliptic. Every exoplanet system — measured against the plane of the sky, perpendicular to the line of sight to its own host star — was being presented nearly edge-on, a smear of overlapping ellipses. The settle direction is now taken relative to whichever plane the system was measured in, so all of them read as discs. The solar system is unmoved, which a test pins. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01WaySiNst4HhDXBHnMy8p5G |
||
|
|
2f45fa7fef |
Measure exoplanet inclination from the plane of the sky
The Exoplanet Archive measures orbital inclination from the plane of the sky — the plane perpendicular to our line of sight to the host star. Ninety degrees means edge-on as seen from Earth, which is why transiting planets pile up there: 1643 of the 2061 published inclinations are within five degrees of 90. The renderer fed that straight into a propagator that reads inclination as an angle from the reference plane, so every transiting system was tilted against a plane its inclination was never measured against. Each body's elements are now rotated out of their own reference plane into the scene by a per-body quaternion. Solar-system elements keep the ecliptic rotation from the previous commit. Exoplanets get a rotation carrying the elements' +Z onto the line of sight to their host, which is exactly the star's own position — so an inclination of i means the orbit's normal sits i from our line of sight, which is the definition. The rotation about that axis is the node's position angle on the sky. The archive does not publish it and the ETL does not request it, so the shortest arc is used: deterministic, and no less arbitrary than anything else given no data. Planets with no published inclination default to face-on, which is the honest reading of an unconstrained orbit rather than a guess at a tilt. Unifying this replaced the direct eclipticToEquatorial call in the renderer, so solar-system bodies and moons come out exactly where they did before — verified against Sol side by side. Tests: 253 passing, up from 247. The strongest one is the definition itself: a 90-degree planet must pass through our line of sight to the star, which is what a transit is. One test of mine had to be corrected rather than the code — it asserted that two systems at the same inclination must occupy different planes, which is not guaranteed once the node angle is arbitrary, while each still sits at the correct angle to its own host. Note the e2e camera-flight test flaked once under parallel load during this work, then passed in isolation and on two further full runs. Its click-until- entered poll has a fixed 15s budget that a loaded machine can exceed; that is pre-existing and unrelated to this change. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01WaySiNst4HhDXBHnMy8p5G |
||
|
|
2293585940 |
Put orbits and stars in the same reference frame
The app's two sources disagree about which frame they are in, and nothing reconciled them. HYG star positions are equatorial J2000 — that is what raDecDistanceToXyz produces and what the galaxy view renders directly. Orbital elements come from JPL Horizons, whose default reference plane for element output is the ecliptic, and the ETL never overrides it. The two are tilted 23.4 degrees apart, so the orbits sat that far off the sky they are drawn against. Confirmed rather than assumed, from both ends: the Horizons request in lib/horizons.ts sets no REF_PLANE, and the resulting solar-system inclinations are 0 to 17 degrees with Earth exactly 0.00 — which is only true of the ecliptic, since Earth's orbit defines it. eclipticToEquatorial now rotates orbit positions into the scene frame, so a direction means the same thing in the galaxy view and the system view. The rotation is about the vernal-equinox axis, which both frames share. That exposed a presentation problem the old code had been hiding. The renderer mapped the propagator's z straight onto the scene's vertical, which silently redefined the frame but did make systems render flat. In a properly equatorial scene, orbital planes lie 23.4 degrees off the scene's own axes, so a system would be presented edge-on. Rather than rotate the world back into a comfortable pose — which would only put the orbits at odds with the sky again — the camera now settles relative to the orbital plane: a three-quarter view about 37 degrees off the ecliptic normal. The arrival still begins along the approach direction and swings round as it settles, so the transition stays continuous, and the framing is now the same every time rather than inherited from wherever the camera happened to be. Tests: 247 passing, up from 237. The frame tests are the discriminating kind — Earth's orbit must lie perpendicular to the ecliptic pole rather than to the scene's vertical, and must reach 23.4 degrees of declination a quarter orbit on, where it used to read zero. Verified in a browser against Sol and Gl 357. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01WaySiNst4HhDXBHnMy8p5G |
||
|
|
f241b093eb |
Draw the 1509 exoplanets that were being silently dropped
The system renderer required both a semi-major axis and an eccentricity before it would place an exoplanet, even though resolveOrbitalElements already defaults every other missing element. The archive publishes an axis far more often than an eccentricity: 3895 records have one and only 2386 have both, so 1509 planets were dropped for want of a value that can simply be assumed. A missing eccentricity now defaults to 0, a circle. That is the conventional assumption for an orbit whose shape has not been constrained, and it is the only honest option available, since the axis alone says nothing about elongation. The effect is not subtle. 18 systems gain planets, and seven of them previously rendered as a bare star with nothing around it at all: Gl 357 goes from zero planets to three, HD 176986 likewise. Beyond the effect today, a user could already reach one of these planets through search and its detail page, then jump to its system and find it missing from the very system it belongs to. isPropagatableOrbit replaces the old inline guard and also rejects what the old one never checked: a non-positive axis, and an eccentricity of 1 or more. Those are escape trajectories that no ellipse describes, and propagating them anyway does not throw — it yields NaN, which reaches the vertex buffer and poisons the geometry's bounding sphere, disabling culling for the whole object rather than just the bad orbit. Being a type guard, it also lets the caller drop a seven-line field-by-field copy of the orbit. Fixes a label leak found while verifying this in the browser. Galaxy star labels were being cleared on entering system space but immediately recomputed, because the tick gated them on `currentStarId`, which is not assigned until the arrival flight finishes a second later — so parsec-scale names sat pinned over the system. Both label and orbit updates now gate on which group is actually visible, which is true throughout the transition rather than only at the end of it. Tests: 185 passing, up from 171. Verified in a real browser: GJ 1151 draws the orbit and marker it gained, and no labels survive into the system view. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01WaySiNst4HhDXBHnMy8p5G |
||
|
|
8d8c65bdb2 |
Propagate exoplanets with their real orbital period
Every exoplanet was propagated with gmForParent(undefined) — the Sun's gravitational parameter — so the whole catalogue orbited as though each host were exactly one solar mass. Most hosts are red dwarfs far lighter than that, and a heavier central mass pulls harder and shortens the period, so their planets were whirling round much too fast: TRAPPIST-1 is 0.09 solar masses, and its planets were completing an orbit in roughly a third of the true time. pl_orbper was already in the TAP query and was being discarded on the way into the record. It is now kept, along with st_mass. A period and a semi-major axis together pin the host's gravitational parameter exactly, via GM = n^2 a^3 — no stellar model, no assumption, just the inverse of the orbitalPeriodDays helper that was already there. resolveGravitationalParameter picks the best available source: the measured period, else the published host mass, else one solar mass as before. A derived value implying something outside 0.01-150 solar masses is rejected and falls through, since a period and axis taken from disagreeing solutions would otherwise send a planet spinning at a visibly absurd rate. Note the direction of the error, which is the opposite of what it looks like: assuming a *heavier* host than reality makes a planet orbit *faster*. A test pins it, and caught me stating it backwards first. The NASA Exoplanet Archive is unreachable from this environment (egress policy returns 403 on CONNECT), so exoplanets.json cannot be regenerated here and still carries no periods. Behaviour is therefore unchanged until `npm run etl` is run somewhere with archive access, at which point every planet with a published period starts moving correctly with no further code changes. build.ts reports how many records gained a period, and rejects non-positive ones. Tests: 171 passing, up from 151, including a new end-to-end check that TRAPPIST-1 b with its real period completes exactly one orbit in 1.51088 days and sits a full diameter away at half that. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01WaySiNst4HhDXBHnMy8p5G |