Skip to content
IgfrayPublic

About

Accurate positional astronomy with no dependencies: Sun, Moon, planets, precession, meteor showers, and a stereographic sky projection.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Latest commit

 

History

6 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

skymaths

test npm

Accurate positional astronomy in JavaScript, with no dependencies and no platform.

Where the Sun, Moon and planets are; where the stars are once precession is applied; how to get any of it onto a screen; and how much the atmosphere dims it on the way. Runs in Node, in a browser, and in GJS — it imports nothing, so there is nothing to be incompatible with.

npm install skymaths
import {bodies, basis, vec, projectPoints, scale} from 'skymaths';

const now = Math.floor(Date.now() / 1000);
const {moon, planets} = bodies(now);
console.log(`Moon is ${(moon.illum * 100).toFixed(0)}% lit`);

// Where does Jupiter land on a 1920-wide view, 150° across, looking south?
const R = basis(now, {latitude: 51.48, longitude: 0, skyAzimuth: 180, skyAltitude: 42, skyFov: 150});
const jupiter = planets.find(p => p.name === 'Jupiter');
const pts = [vec(jupiter.ra, jupiter.dec)];
projectPoints(pts, R.ofDate, 960, 540, scale(1920, 150), true, true);
console.log(pts[0].behind ? 'below/behind you' : `${pts[0].x | 0}, ${pts[0].y | 0}`);

What it gives you

ephemeris — Sun and Moon (phase, illuminated fraction, angular diameter, elongation), the seven planets (RA/Dec, magnitude with the phase-angle term, apparent size, illuminated fraction, Saturn's ring opening, Jupiter's Galilean moons), precession matrices, obliquity, and a meteor-shower table whose peaks are stored in solar longitude — so the Perseids arrive in August because the Earth gets there, not because a date is hard-coded.

projection — a stereographic sky projection with three coordinate frames, plus Kasten–Young airmass, real extinction and scintillation.

The three frames, which is the load-bearing idea

basis() returns three row-sets, and using the wrong one is the bug this design exists to prevent:

Row-set For Because
j2000 star catalogues precession is baked into the rows, so it is never applied per star
ofDate Sun, Moon, planets the ephemeris already returns these of date
enu horizon, compass, anything at an azimuth it must stand still while the sky turns past it

Mixing the first two puts the Moon about a third of its own width off — small enough to look fine and be wrong, which is the worst kind of bug.

Accuracy, honestly

Error Validated against
Sun ~0.01′ Meeus example 25.a — 0.03″
Moon ~10″ Meeus example 47.a — 0.00″
Planets ~1″ Meeus example 33.a (Venus) — 0.48″
Nutation ~0.5″ Meeus example 22.a — 0.075″
Aberration ~0.13″ two independent forms agree
Precession exact to IAU 1976 —

Every figure is checked against Meeus's own published worked examples rather than against another part of this library — agreeing with the author of the method is a much stronger claim than two of your own components agreeing with each other.

This was a naked-eye library until it was used for sight reduction, where one arcminute of angle is one nautical mile of position and the distinctions above stop being academic. Three things were wrong, and none of them was visible at 2 arcmin/px:

  • The planets carried the whole of precession since J2000. The JPL elements are referred to the J2000 ecliptic while the Sun and Moon come out already of date, so the planets were handed an of-date obliquity as though they were of-date themselves. 50″/year — 22 arcminutes by 2026, growing forever. It was never an orbital-elements problem.
  • The Moon was on an abridged term list, 0.1° — a fifth of its own disc.
  • ΔT was absent entirely. julianDate() gives UT; every formula here wants TT. They differ by ~69 seconds, which is 38″ of lunar motion.

Two Julian Dates, and they are not interchangeable

bodies() returns both, named, because the caller must choose deliberately:

const b = bodies(unixSeconds);
b.jd      // UT — the rotation of the Earth: sidereal time, hour angles, azimuth
b.jdTT    // TT — the ephemeris. Every position was computed at this.
b.deltaT  // seconds between them

Using one for both is a silent systematic error that drifts with the season.

Still limited

Planets rest on JPL approximate elements (valid 1800–2050), not VSOP87 — accurate now because the frame, light time and aberration are handled, but that is the ceiling. Star proper motion is not applied: properMotion() exists, a catalogue carrying the columns does not, and over 26 years the fastest navigational stars have moved ~1.6′. Aberration is opt-in in the projection ({aberration: true}) — 20.5″ is 0.34 nautical miles to a navigator and 0.17 pixels to a sky chart, so paying for it every frame would be the same unmeasured-negligibility mistake reversed.

Where it is deliberately exact: precession, sidereal time (15.0411°/hour — the sidereal day, not the solar one), the phase-angle magnitude terms, and airmass.

Tests

npm test

40 checks, and every one is an invariant rather than a number copied from an almanac: the June solstice declination must equal the obliquity; a full moon must be opposite the Sun; Venus's greatest elongation must fall between 45° and 47°; Perseid ZHR must peak at its tabulated value and fall away either side; Polaris must sit at the observer's latitude. They need no network and no reference data, so they cannot rot.

Provenance

Extracted from TerraFirma, a GNOME Shell extension that draws the real sky over the desktop wallpaper, where this code ran for months before being lifted out. It contains no catalogue data — only maths. If you need a star catalogue, d3-celestial is a good source and is what TerraFirma bakes its own from.

MIT licensed.

About

Accurate positional astronomy with no dependencies: Sun, Moon, planets, precession, meteor showers, and a stereographic sky projection.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages