celestial-chart 0.9.0

Interactive celestial map for the browser: stars, constellations, deep-sky objects, the Milky Way and planets, in 67 map projections — drawn to canvas, exportable to SVG.

npm install celestial-chart GitHub upstream: d3-celestial

Live

loading the star catalogue…

What changed

D3 v7

The upstream library is pinned to D3 v3, last released in 2022. The whole rendering path was migrated, and D3 now ships inside the bundle — no global d3, no separate plugin script.

Several maps per page

The map is a class now, so independent instances can live side by side, each with its own settings form. The old global Celestial.display() still works unchanged.

ES modules + types

ESM, CJS and a browser IIFE build, tree-shakeable, with hand-written TypeScript declarations for the public surface.

Bugs fixed

The Milky Way no longer inverts near the edge of the globe, star colours are right again, and a set of silent v3→v7 breakages — SVG export, resize, hour angle — were caught and repaired.

Same output, verified

A migration is only worth anything if the picture does not move. Every (right ascension, declination, projection, rotation) is deterministic, so the old library's output was pinned and compared against the new one.

measurementresult
projections × rotations × sky points67 × 4 × 413 = 110 684
maximum difference from the D3 v3 original0.000 px
rendered images, old vs newdiffer only at anti-aliasing level
unit tests · browser assertions66 · 27
files to load (was 3: d3 + plugin + celestial)1 — 295 KB

Time zones without an API key

To show the sky above you, the library needs the UTC offset of your position. A browser cannot work that out for an arbitrary point on Earth — only for its own zone — so it takes an outside source.

Upstream baked the author's TimeZoneDB account id into the library, so every page embedding it sent its visitors' coordinates to a third party, unasked, on a shared quota. This fork ships no key: you hand it a timezoneResolver and it calls that instead. “My sky now” above uses one — it resolves against a small service that keeps the timezone polygons inside its own binary, so nothing is asked of anyone else at runtime.

Celestial.display({
  timezoneResolver: (lat, lon, when) =>
    fetch(`https://api.blackit.hu/timezone?lat=${lat}&lon=${lon}&t=${when}`)
      .then(r => r.json())
      .then(j => j.offsetMinutes)
});

With neither a resolver nor a key of your own, no request is made at all and the offset is estimated from longitude — right to within an hour or so, except where zones follow politics rather than meridians.

Usage

import Celestial from "celestial-chart";

Celestial.display({
  container: "celestial-map",
  projection: "aitoff",
  stars: { limit: 6, colors: true },
  constellations: { names: true, lines: true }
});

// or, for several independent maps on one page:
import { SkyMap } from "celestial-chart";
const north = new SkyMap({ container: "map-a", center: [0, 90, 0] });
const south = new SkyMap({ container: "map-b", center: [0, -90, 0] });