npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

skymaths

v0.1.1

Published

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

Readme

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.