@johnmorrisdotca/wakusei-planets
v0.52.0
Published
Wakusei Planets 惑星 — The Sun, planets and moons for the web: each as a clean line drawing, a shaded realistic drawing or a painted surface map, with real sizes, axial tilt and rotation as data, and positions of the moons for any date and time. SVG for the
Downloads
8,797
Maintainers
Keywords
Readme
Wakusei Planets runs in the browser of a phone, a tablet or a computer: nothing to install, no account, and it is free.
Who it is for
- Teachers and students: the size line-up puts the Sun and the largest stars side by side at true relative size, each with its radius, its error and its paper, and colouring sheets of the Sun, the planets and the big moons print on A4 or US Letter in English and Japanese, with the real colours and three facts each.
- Space enthusiasts: the space view puts the Earth, the Moon, the Sun and the planets where they are now, or on any date you set, and zooms out to the whole solar system; Jupiter and its moons as the Earth sees them now is one click. The ten famous spacecraft (Voyager 1 and 2, New Horizons, Cassini, Juno, the Webb telescope and the rest) and where each is on any date are in the spacecraft guide: that is code and a table, and there is no demo page for it yet.
- Researchers and outreach staff: every planet and the Moon is held within 6 arc-seconds of NASA's JPL Horizons on 60 dates from 1800 to 2200, and Jupiter's four big moons within 0.15 degree; the accuracy guide gives each body's number and NOTICE.md names every source. The tables download as CSV and Parquet (data files). Read Limits first, and see How to cite.
- Writers, museums and site owners: the code builder and the portrait builder write the code that puts a body, or a picture of several, in your page as an
<iframe>or a tag, with no build step. - Developers: one
<wakusei-body>tag, an SVG string with no browser at all, and typed data for the sizes, tilts, poles and places, and the bodies as objects for a three.js scene of your own; One minute and the API are below.
Try it now, nothing to install
Learn: Colouring sheets to print · Saturn's sheet · The size line-up, the Sun to the largest stars
Look: Saturn, painted · Jupiter and its moons now · The space view · A star from its numbers: Vega
Make: The portrait builder · The code builder
For teachers and families
Wakusei Planets works on a phone or a tablet as well as on a computer, in the browser, and it is free: the code is MIT-licensed, and nothing is installed or signed up for. The colouring-sheets guide says what each sheet is and how to print it, and the size line-up guide says where each star's radius comes from. Every source is credited in NOTICE.md and at the foot of each demo page.
One minute
npm install @johnmorrisdotca/wakusei-planetsA page with no build step needs one tag. look="line" is an SVG and needs nothing else:
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>Wakusei Planets from jsDelivr</title>
<script type="module" src="https://cdn.jsdelivr.net/npm/@johnmorrisdotca/wakusei-planets/element/+esm"></script>
</head>
<body>
<wakusei-body body="saturn" look="line" size="320"></wakusei-body>
</body>
</html>Every view already turns, zooms and pans with a drag, a pinch, Ctrl and the wheel and the keys (the plain wheel still scrolls the page). To add the shared kazoku-ui bar, with buttons and sliders, point it at the tag:
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>Wakusei Planets with the shared controls</title>
<script type="module">
import "https://cdn.jsdelivr.net/npm/@johnmorrisdotca/kazoku-ui/view-controls/define/+esm";
import "https://cdn.jsdelivr.net/npm/@johnmorrisdotca/wakusei-planets/element/+esm";
const body = document.querySelector("wakusei-body");
document.querySelector("kazoku-view-controls").addEventListener("kazoku-viewchange", (event) => {
body.setView(event.detail);
});
</script>
</head>
<body>
<wakusei-body id="planet" body="saturn" look="line" size="420" tabindex="0"></wakusei-body>
<kazoku-view-controls for="planet" address controls="advanced" speed="0"></kazoku-view-controls>
</body>
</html>A bundled app imports it: import "@johnmorrisdotca/wakusei-planets/element" (and import { lineSvg } from "@johnmorrisdotca/wakusei-planets" for the SVG string, which needs no browser). For the shaded look add the body's own entry point, import "@johnmorrisdotca/wakusei-planets/jupiter", and three (an optional peer).
Features
- The asteroid belts and the Kuiper belt: 3,340 real numbered small bodies from NASA/JPL's Small-Body Database in seven belts, drawn in the space view (one draw each) with a flight into the main belt, and as data (
/belts). - The Sun, the eight planets, Pluto, eight more dwarf planets, five minor bodies (the asteroids Vesta and Pallas, the centaurs Chiron and Pholus and Halley's comet) and 29 moons, each with its real size, flattening, axial tilt, pole and rotation as data.
- Three looks: a clean
linedrawing (an SVG string), a shadedrealisticsphere worked out in a shader, and apaintedsurface map from public-domain imagery. - The sky for any date and time: a body's pole, rotation, phase and ring opening as the Earth sees it, and a planet's moons where they are then.
- One WebGL context for the page, nothing drawn at rest, at most thirty frames a second, and everything freed when an element leaves.
- A pure side that runs on a server:
BODIES,apparent,system,orbitPath,portraitandlineSvg. embedCodewrites the code that puts a body in a page for HTML, a module, React, Vue, Angular, Svelte or an iframe.painter.makehands a body to a three.js scene of your own.- Every guide in English and Japanese; the demo's words too.
Use it in your project
npm install @johnmorrisdotca/wakusei-planets threeimport "@johnmorrisdotca/wakusei-planets/element";
import "@johnmorrisdotca/wakusei-planets/saturn";Import the element once in client code, and the entry point of each body you draw in a shaded look (or /all). A line drawing needs neither three nor an entry point. Bundlers and Frameworks go through it.
Three looks
| Look | What it is | Needs |
|---|---|---|
| line | A clean outline drawing with the body's key features: bands, craters, rings and their gaps, caps, the dark side dashed off. An SVG. | nothing |
| realistic | A shaded sphere drawn from the body's real colours and features, lit from the Sun's side, with the rings casting shadows. No pictures: the surface is worked out in a shader. | three, the body's entry point |
| painted | A real surface map: public-domain NASA, USGS and JPL imagery, or for Mercury, Venus, Jupiter, Saturn, Uranus, Neptune and the Sun a CC BY 4.0 map (picturesCredit writes each body's credit). Small pictures first (1.31 MB for all of them in the package), a sharper one fetched when you zoom in, and finer map tiles for the part in view when you zoom right up, in a body, a portrait or the space view (Mars, the Moon, the Earth and ten moons: close zoom). | three, the body's entry point |
Every body has its real size relative to the others (scale-to="jupiter"), its axial tilt and its rotation. The Sun, Mercury, Venus, Mars, Jupiter, Saturn, Uranus, Neptune and Pluto are drawn, and so are the eight other dwarf planets (Ceres, Orcus, Haumea, Quaoar, Makemake, Gonggong, Eris and Sedna; Haumea and Quaoar as the long shapes they are, and Ceres with a painted map from Dawn) five minor bodies (Vesta, with Dawn's own map, Pallas, Chiron, Pholus and Halley's comet, each its own shape, size and spin as the Small-Body Database has them) and 29 moons (the Moon, Phobos and Deimos, the four Galilean moons, Saturn's seven larger moons, Uranus's five, Proteus, Triton and Nereid, Charon, Nix and Hydra, and Vanth, Hiʻiaka, Namaka and Dysnomia, the moons of the dwarf planets whose orbits are published with a date). The Earth is drawn like the rest in the realistic and painted looks (NASA's Blue Marble), and its line look is chikyu-earth's own globe: import "@johnmorrisdotca/wakusei-planets/earth" (it needs @johnmorrisdotca/chikyu-earth 0.10.0 or later installed). The painted looks cover the Sun, the planets from Mercury to Earth and Pluto, Ceres, the Moon, the four Galilean moons, Saturn's Mimas, Enceladus, Tethys, Dione, Rhea, Titan and Iapetus, Triton and Charon, and Saturn's rings are Cassini's own picture of them.
A star from its numbers
<wakusei-body star="Betelgeuse" temperature-k="3650" radius-sun="1057" luminosity-class="Iab"> draws any star in 3D or as a line drawing, from a few numbers and with no catalogue: the temperature gives the colour, the radius the size beside the Sun, the luminosity class the grain of the surface, the rotation how it turns, and a flattened star such as Vega or Altair is squashed with hotter poles. Granulation boils, an active star has spots, prominences and flares, and a soft corona glows round it, all through the same shared renderer, with a cheaper quality="low" for weak devices. Every star says which parts are measured and which are drawn for looks: drawn from its numbers, not a photo. The Sun keeps its own look. See A star from its numbers and the star page.
import { starLook } from "@johnmorrisdotca/wakusei-planets";
const vega = starLook({ name: "Vega", temperatureK: 9660, radiusSun: 2.726, oblateness: 0.113, rotationDays: 0.71 });
console.log(vega.colour, vega.parts.map((part) => part.status).join(", "));The size line-up
<wakusei-lineup stars="bright" planets at="betelgeuse"> shows the Sun, Sirius A, Vega, Arcturus, Aldebaran, Rigel, Antares, Betelgeuse and the largest stars known (VY Canis Majoris, WOH G64, UY Scuti, Stephenson 2-18) side by side or one above the next at true relative size, each drawn with the star look and labelled with its radius in Suns and kilometres, its error and its paper. A slider zooms smoothly from the Sun (or the Earth, with planets) up to the largest star; each star turns slowly and a drag turns the one it takes hold of. Every radius is from a refereed paper that measured the star's angular diameter, or says it did not (WOH G64 and Stephenson 2-18 are estimated from brightness, UY Scuti's distance is not a parallax); where the papers disagree, the label and the guide say so. The demo's size line-up page saves the picture as a PNG or SVG, prints it as a poster on A4 or US Letter, and writes the code for every way of putting it in a page. The table needs no browser:
import { lineupBodies, lineupText } from "@johnmorrisdotca/wakusei-planets";
const largest = lineupBodies({ set: "largest" }).at(-1)!;
const text = lineupText(largest, "en");
console.log(`${text.name}: ${text.radius}, ${text.km}, ${text.source}`);The top-down plan
<wakusei-plan mark="mars"> is a small map of the solar system from above, or (system="jupiter" mark="io") of one planet's moons from above its pole, with the body you are looking at marked. It is SVG with no WebGL, made to be read at 200 to 280 pixels, so it fits an inset beside a 3D view. Distances are squeezed with a logarithm so Mercury and Neptune both show, or to scale with spacing="true". It draws only when its time, mark or another attribute changes, never on a timer. The pure side needs no browser; the guide has the attributes and both spacings:
import { planAt } from "@johnmorrisdotca/wakusei-planets/plan";
const io = planAt(Date.UTC(2026, 10, 11), { system: "jupiter", mark: "io", spacing: "true" }).dots.find((dot) => dot.id === "io");
console.log(io?.distance.toFixed(1), "Jupiter radii from Jupiter");A name on the body
body-label="painted" writes the body's name on its own globe, large and in capitals, lying on the surface and turning with it, as a film lays a title over the thing it names: on <wakusei-body> and on every body of <wakusei-space>, in the page's language, in Michroma by default or a font of yours. Four looks (painted, etched, outline, burned), once or on both sides, at the equator or near a pole, turning with the body or always facing you; nothing on a body too small on the screen. A name on the body has the attributes.
Two packages: this one and chikyu-earth
This package is the Sun, the planets, the dwarf planets and the moons, and where they are. chikyu-earth is the Earth in detail: its countries, day and night, places and satellites. Each works alone; install both and the Earth's line look becomes chikyu-earth's globe with the countries. The dependency runs one way: this package may use chikyu-earth, never the reverse. Why two packages has the rule, a table of what lives where and how to use them together.
As the Earth sees it
Give a body a time and it is drawn as the sky shows it then: its pole and rotation, how far the rings are open (Saturn's rings are edge-on in March 2025), the phase of the Moon or Venus, the Sun's direction.
<wakusei-body body="saturn" look="realistic" time="2026-11-02T12:00:00Z"></wakusei-body>Every way to use it
| How | Where |
|---|---|
| A script tag from jsDelivr or unpkg, a shaded body from a CDN | CDN guide |
| An ES module in Vite or webpack, only the bodies you need | bundlers guide |
| React, Vue, Svelte, Angular; Next.js, Nuxt, SvelteKit | frameworks guide |
| An <iframe> of the embed page, no script of your own | iframe guide |
| Set up a body in the demo and copy the code for HTML, React, Vue, Angular, Svelte or an iframe | Put it in your page, or embedCode() |
| TypeScript types, an SVG string on a server, Node | TypeScript and Node guide |
| The looks, the entry points, one WebGL context | looks and bodies |
| Moons where they are on a date, time that runs fast | moons and time |
| Something does not appear | troubleshooting |
The guides are also in Japanese (日本語), one language to a page: docs/guides/ja/.
In React, with the browser-only import where a server render never reaches it:
import { useEffect } from "react";
export function WakuseiBody({ body = "saturn", look = "line" }: { body?: string; look?: "line" | "realistic" }) {
useEffect(() => {
// The element needs a browser, so it is imported here, never at the top of the file: a server render never reaches an effect.
void import("@johnmorrisdotca/wakusei-planets/element");
void import("@johnmorrisdotca/wakusei-planets/all");
}, []);
return <wakusei-body body={body} look={look} />;
}Vue, Svelte and Angular components, the Vite and webpack setups and an <iframe> are in the guides, each one built and opened in a browser by pnpm test:usage.
Light by design
A page full of bodies stays light: one WebGL context for the page through kazoku-ui's shared renderer (the body in focus is live, the others are pictures), nothing drawn while nothing changes, at most thirty frames a second while it moves, a canvas held to 4096 pixels a side and six million pixels, everything freed when an element leaves, no drawing out of sight or in a hidden tab, a slower turn for a reader who prefers reduced motion (turn="0" is the only stop), and a lost WebGL context coming back by itself. The tests count draws, animation frames, contexts and GPU objects at rest and over many changes (pnpm test:freeze, and a soak with pnpm test:soak).
The element
| Attribute | What it does | Default |
| --- | --- | --- |
| body | The body's name. | earth |
| look | line, realistic or painted. | line |
| size | The width in pixels. | 320 |
| time | now or an ISO date: the body as the Earth sees it then. Left out, a portrait. | portrait |
| moons | A planet with its moons on their orbits (with a date). | off |
| rate | Simulated seconds for each real second; 0 holds the clock and draws nothing. A dated picture sends wakusei-timechange ({ time, running }) while the clock runs and once when it holds. | 1 |
| turn | A portrait turns this many degrees a second. | 0 |
| tilt, pitch, phase, meridian | A portrait's pose in degrees. | the body's own |
| scale-to | Draw to scale with another body. | fills its box |
| live | always, hover or off: when a shaded body takes the page's one WebGL context. | always |
| lang | en or ja for names and labels. | en |
The pure side has no DOM: BODIES, apparent(id, time), system(planet, time), orbitPath, portrait and lineSvg(id, options).
The data
Sizes, flattening, poles and rotation are the IAU's and NASA's; Mercury to Neptune are VSOP87B, cut down, and Pluto is a table fitted to Horizons; the Moon's are the lunar solution ELP2000-82B cut down; Jupiter's four big moons are the theory L1.2 and Saturn's seven inner ones TASS1.7, and the others are fitted to JPL Horizons' positions, and every body is tested against Horizons (accuracy). Nothing is fetched at run time by the line and shaded looks, which use no pictures. See NOTICE.md.
The same data comes as files for other languages: every release attaches CSV and Parquet tables of the bodies, their orbital elements, the spacecraft and their events, each with a schema, the data licence and checksums, for pandas, polars, R or Rust (data files). Serve it yourself is a small Node server that answers a body's facts, its position on a date and the distance between two bodies; we host nothing, you run it.
Examples
Every ts block in this README is type-checked and run against the package as npm packs it (pnpm test:readme).
import { BODIES, MOONS_OF, PLANET_IDS } from "@johnmorrisdotca/wakusei-planets";
BODIES.saturn.radiusKm; // 60268
PLANET_IDS.length; // 9
Object.values(MOONS_OF).flat().length; // 25The planets' state as the Earth sees them on a date:
import { apparent } from "@johnmorrisdotca/wakusei-planets";
const saturn = apparent("saturn", Date.UTC(2026, 10, 2));
console.log(saturn.subObserverLat.toFixed(1), saturn.illumination.toFixed(2));A planet's moons where they are on a date, as offsets from it in the planet's radii:
import { system } from "@johnmorrisdotca/wakusei-planets";
const { moons } = system("jupiter", Date.UTC(2026, 10, 2));
console.log(moons.map((moon) => `${moon.id} ${moon.x.toFixed(1)}`).join(", "));A line drawing as an SVG string, with no browser:
import { lineSvg } from "@johnmorrisdotca/wakusei-planets";
const svg = lineSvg("mars", { size: 200, tilt: 15, lang: "ja" });
if (!svg.startsWith("<svg") || !svg.includes("火星")) throw new Error("not a Mars drawing");The code that puts a body in a page, for any of the ways a page is made:
import { EMBED_KINDS, embedCode } from "@johnmorrisdotca/wakusei-planets";
for (const kind of EMBED_KINDS) console.log(kind, embedCode({ body: "mars", look: "line", size: 240 }, kind).split("\n")[0]);A body for your own three.js scene, in the browser:
The moons' places on an orbit, as points for a line you draw yourself:
import { orbitPath } from "@johnmorrisdotca/wakusei-planets";
const path = orbitPath("io", Date.UTC(2026, 10, 2), 8);
console.log(path.length / 3, "points");How much of the Moon is lit on a date:
import { apparent } from "@johnmorrisdotca/wakusei-planets";
const moon = apparent("moon", Date.UTC(2026, 10, 24, 14));
if (moon.illumination < 0.9) throw new Error("the Moon is nearly full on 24 November 2026");A page that cannot run script uses an iframe of the embed page:
<iframe src="https://johnmorrisdotca.github.io/wakusei-planets/embed.html?body=mars&look=line" title="Mars" width="320" height="320" style="border:0"></iframe>import * as THREE from "three";
import { painter } from "@johnmorrisdotca/wakusei-planets/painter";
const scene = new THREE.Scene();
const jupiter = painter.make(THREE, "Jupiter", { look: "realistic", invalidate: () => {}, ratio: 1 });
scene.add(jupiter.object);A body that turns by itself and a moving sky, in HTML:
<wakusei-body body="jupiter" look="line" moons time="now" rate="600" size="360"></wakusei-body>
<wakusei-body body="venus" look="realistic" time="2026-11-02T12:00:00Z" turn="12" live="hover"></wakusei-body>Outside data
The package draws; you bring the data. @johnmorrisdotca/wakusei-planets/door takes a finer map of a body, or a list of small bodies, as a source: a small object that carries its own licence and credit, so the page can always say whose data is on the screen. Without a source the package draws exactly what it did before, from its own pictures, tiles and series. A source of yours may be non-commercial or share-alike; the credit line says so beside the licence, and the package never bundles one.
import { createSourceBook, creditLine, smallBodyAt } from "@johnmorrisdotca/wakusei-planets/door";
// A source of your own: here two small bodies held in memory (the second has a number that is not one, so it is left out). A real one would read a catalogue, and says whose it is and under what licence.
const mine = {
kind: "records",
info: {
id: "my-rocks",
name: { en: "My rocks", ja: "私の小天体" },
credit: { en: "My rocks, A. Person (2026)", ja: "私の小天体(A. Person、2026年)" },
licence: { name: "CC BY-NC 4.0", url: "https://creativecommons.org/licenses/by-nc/4.0/", nonCommercial: true },
url: "https://example.org/my-rocks",
retrieved: "2026-11-10",
},
records: () => [
{ name: "Ceres", a: 2.7656, e: 0.0795, i: 10.588, node: 80.25, peri: 73.3, M0: 291.4, epoch: 2461000.5, H: 3.34 },
{ name: "Broken", a: Number.NaN, e: 0.1, i: 5, node: 0, peri: 0, M0: 0, epoch: 2461000.5, H: 12 },
],
};
// An element keeps a book like this one: `space.addSource(mine)` is `book.addSource(mine)`.
const book = createSourceBook();
book.addSource(mine);
await book.ready();
const [ceres] = book.smallBodies();
const [x, y, z] = smallBodyAt(ceres, 2461000.5);
console.log(`${book.smallBodies().length} small body, ${book.stats().records["my-rocks"].skipped} left out: ${ceres.name} is ${Math.hypot(x, y, z).toFixed(2)} au from the Sun`);
const credits = [{ source: mine.info, own: false, used: book.smallBodies().length }];
console.log(creditLine(credits, "en"));
console.log(creditLine(credits, "ja"));
book.enableSource("my-rocks", false);
console.log(`${book.smallBodies().length} small bodies with the source off`);<wakusei-space> draws small bodies as points in one instanced draw, and <wakusei-body> and <wakusei-space> both take a map of a body to lay over its own picture. Both have sources and addSource(source), which checks the source at once and returns the way to remove it, removeSource(id), enableSource(id, false) and the attribute data="own" to switch outside sources off (their loads abort and their tiles are freed), and credits() with the event wakusei-creditschange for the credit line.
import { creditLine, tilesSource } from "@johnmorrisdotca/wakusei-planets/door";
import "@johnmorrisdotca/wakusei-planets/space/element";
const space = document.querySelector("wakusei-space");
space.addSource(mine); // the source above: its points are in the next frame
space.addSource(tilesSource("/my-tiles/")); // what tiles="/my-tiles/" means
space.addEventListener("wakusei-creditschange", () => console.log(creditLine(space.credits(), "en")));The tiles of every body share one 48 MB budget, six loads at a time for a source, and nothing is sent at rest. OWN_SOURCES and ownCredit give the package's own credits, mapKeys helps a source of your own name the tiles of a place, and readSmallBodies and smallBodyAt read a list of small bodies and say where one is on a date. The guide has the shapes and the rules.
The code builder
The code builder is one screen: choose which planet's system, the body, the look, the size, the sky and the turning, then pick how your page is made and copy the code. It is the family's embed panel with those choices inside it, built from embedCode, so it writes what the package writes. Put it in your page is its guide.
The portrait builder
The portrait builder puts any bodies in one picture: drag them, size them, turn them, order them front to back, arrange them in a row, an arc, a grid or at true orbit distance (true or readable sizes, a planet's moons round it in orbit order), light them from one direction, and take the code, a PNG or an SVG. The scene is kept in the address, and every body is drawn in one WebGL scene, so the page holds one WebGL context. The portrait builder is its guide.
<script type="module" src="https://cdn.jsdelivr.net/npm/@johnmorrisdotca/wakusei-planets/portrait/+esm"></script>
<script type="module" src="https://cdn.jsdelivr.net/npm/@johnmorrisdotca/wakusei-planets/all/+esm"></script>
<wakusei-portrait scene="look:painted~jupiter_0_0_0.3_0~io_0_0_0.1_0"></wakusei-portrait>What is nearby, and when bodies come close
/nearest answers "what is next to this?" for the Sun, the planets, the dwarf planets and the moons. nearest and within list the bodies closest to one on a date, by the angle between them in the sky (of the Earth, a place on it or another body) or by the distance between them in space. closestApproach and conjunctions search a span of time: coarse steps, then each minimum narrowed to about a second. distance and distanceRange give two bodies' distance on a date and how near and far they get over a span (Earth and Mars: 0.373 to 2.676 au from 1900 to 2100, the guide has every planet pair). Every result carries the accuracy the theories are held to; against JPL Horizons the great conjunction of 2020 is within 270 s and 0.3 arc-seconds, and the Moon's approaches to the planets within 8 s and 1.5 arc-seconds. The guide has the options and the numbers.
import { closestApproach, distanceRange, nearest } from "@johnmorrisdotca/wakusei-planets/nearest";
const planets = nearest("moon", { kind: "planet", count: 2, date: Date.UTC(2026, 11, 27, 16) });
console.log(planets.map((row) => `${row.id} ${row.angle.toFixed(2)} degrees`).join(", "));
const great = closestApproach("jupiter", "saturn", { from: Date.UTC(2020, 11, 1), to: Date.UTC(2021, 0, 1) });
console.log(great.time.toISOString(), great.angle?.toFixed(2), "degrees");
const mars = distanceRange("earth", "mars", { from: Date.UTC(1900, 0, 1), to: Date.UTC(2100, 0, 1) });
console.log(mars.min.distanceAu.toFixed(2), "to", mars.max.distanceAu.toFixed(2), "au");The space view
The space view puts the Earth, the Moon, the Sun and the planets in their places for any date and time, in one WebGL context: the Moon's phase and the Earth's day side come out of the real Sun's light. Zoom from the Earth out to the whole solar system, in a compressed scale (every direction real, the distances squeezed) or the true one, and run time forwards or backwards. Positions come from this package's own models.
<script type="module" src="https://cdn.jsdelivr.net/npm/@johnmorrisdotca/wakusei-planets/space/element/+esm"></script>
<wakusei-space time="2026-11-02T14:00Z" speed="0"></wakusei-space>import { frameAt } from "@johnmorrisdotca/wakusei-planets/space";
const frame = frameAt(Date.UTC(2026, 10, 2, 14));
console.log(Math.hypot(...frame.sun).toFixed(3), "au to the Sun");API
The reference is a site, made from the source's own doc comments: every export has a summary, its parameters, what it returns and an example that runs when the site is built. Open the reference.
| Entry point | What it gives |
| --- | --- |
| @johnmorrisdotca/wakusei-planets | The pure side: BODIES, apparent, system, orbitPath, portrait, lineSvg, embedCode, lineupCode, lineupBodies, starLook, starLineSvg. No browser. |
| .../element | <wakusei-body>; three.js is loaded only for a shaded look. |
| .../portrait | <wakusei-portrait>: many bodies in one scene. The scene model (addBody, layoutPortrait, encodeScene, decodeScene) is in the main entry. |
| .../space | Where the Sun, the Moon and the planets are for a date, in two scales, and where a camera riding along looks: frameAt, createTrack, placeSun, placeAround, ridePose. No browser. |
| .../space/element | <wakusei-space>: the Earth, the Moon, the Sun and the planets in their places. |
| .../plan | The top-down plan: planAt, planSvg, planText. .../plan/element is <wakusei-plan>, in SVG with no WebGL. |
| .../nearest | The bodies nearest to a body on a date (nearest, within), when two bodies come closest (closestApproach, conjunctions) and how far apart they are (distance, distanceRange). No browser. |
| .../sheets | Printable colouring sheets for children: the Sun, the planets and the big moons in thick lines with the real colours and three facts, and all the planets at one scale, in English and Japanese (kidsSvg, kidsSheet, kidsFacts). |
| .../look | What a body needs to be drawn with three.js. |
| .../painter | The bodies as objects for a scene of your own. |
| .../all | Every body's shaded look, at once. |
| .../saturn, .../jupiter and the rest | One body's shaded look. .../moons-jupiter and its siblings: a planet's moons. |
import * as pure from "@johnmorrisdotca/wakusei-planets";
console.log(Object.keys(pure).sort().join(", "));Guides
Each guide has a Japanese twin in docs/guides/ja.
| Guide | What it is for |
| --- | --- |
| Getting started | A body on a page |
| HTML and CDN | A script tag from jsDelivr or unpkg |
| Bundlers | Vite and webpack, only the bodies you need |
| Frameworks | React, Vue, Svelte, Angular |
| Embed in an iframe | No script of your own |
| Put it in your page | Set up a body and copy the code |
| The portrait builder | Many bodies in one picture |
| Looks and bodies | The looks and each body's entry point |
| A name on the body | The body's name written on its globe: looks, how many, where, facing you, the font |
| Why two packages | This package and chikyu-earth: which to install, alone or together |
| Moons and time | The sky on a date, time that runs fast |
| The space view | The Earth, Moon, Sun and planets in their places; two scales; time both ways |
| A star from its numbers | Any star in 3D or as lines, what is measured and what is drawn, every way to put it in a page |
| The size line-up | The Sun and the largest stars at true relative size, with each radius, its error and its paper, where the papers disagree, every way to put it in a page |
| The top-down plan | The solar system or one planet's moons from above, with one body marked: squeezed or to-scale distances, drawing only on change |
| Zoom and pan | Every view zooms and moves by itself: the range of each and why it ends there, the bar, the embed page |
| Close zoom and map tiles | How far each body zooms and why, the finer map tiles for a close zoom (made from public-domain maps, served beside the demo, never in the package), the generic detail, what it costs |
| Outside data, the data door | Hand the package your own maps of a body or small bodies with their licence and credit, switch them off, and show whose data is on the screen |
| Riding along | The camera on a moon, a planet or any moving point, looking at what it goes round |
| Standing on the Moon | A person at the Apollo 17 landing site: the measured ground, the Sun and the Earth where they are, hard shadows, and detail that is made and says so |
| Accuracy | How far each body is from JPL Horizons |
| In your own three.js scene | painter.make |
| Time | Julian dates, calendars, time scales, sidereal time, Mars time |
| The stars you can see without a telescope | 5,080 stars with names, positions, proper motion, distance and colour |
| What is nearby, and when bodies come close | The nearest bodies to a body on a date, closest approaches and conjunctions, and how close they are to Horizons |
| Colouring sheets for children | Printable sheets of the Sun, planets and big moons, A4 and US Letter, English and Japanese, and the ready-made PDFs |
| Famous spacecraft | Voyager, New Horizons, Pioneer, Cassini, Galileo, Juno, Parker and Webb: where they are and their whole voyage |
| Starman and the Tesla Roadster | where the car launched on the first Falcon Heavy is on any date from 2018 to the start of 2036, its distances, speeds, orbit and key moments |
| Comets | 34 well-known comets with orbits from JPL: where each is on any date, its distances, orbit line, last and next perihelion, meteor showers, and a door to add a new comet |
| Places on the Moon, Mars and 31 more bodies | every landing, rover, crash, impact and atmospheric-entry site and the named features of 33 bodies, with positions, dates and sources, the famous ones marked, and the Sun's point, the terminator and the local solar time on any body |
| Which face of a body the view looks at | subCameraPoint() and faceTo() on the space view and on a body's picture: the longitude and latitude under the camera, and a turn to a point, for a card picture that follows the view |
| Data files | CSV and Parquet tables of the bodies, orbits and spacecraft, for Python, R and Rust |
| Serve it yourself | A small Node server over the package, that you host |
| The Sun and Moon from a place | Position, sunrise and sunset, Moon rise, set and phase; a drop-in for suncalc |
| Where the planets are in the sky | The Sun, the Moon and the planets for a moment and a place: right ascension and declination of date and J2000, magnitude, size, phase, elongation, azimuth and altitude, as plain data |
| Coordinate conversions | Pure spherical, ecliptic, equatorial and horizontal coordinate conversions |
| TypeScript and Node | Types and the pure side |
| How it works | Where the numbers come from |
| Asteroids and distant small bodies | 104 asteroids, trojans, centaurs and trans-Neptunian objects: orbits, sizes, the spacecraft that visited them, and where each is on any date |
| Every known moon | every known moon of the planets and dwarf planets as JPL lists them: names, discovery, mean orbit, size, group, and where each is, with its measured accuracy; dots round the planets in the space view (each moon's orbit and rough place: many small outer moons are tens of degrees off within a year) |
| You are here, and places on the Earth | the reader's own place and places they keep on the space view's Earth: a beam, a pin or a ring standing out of the ground, hidden on the far side, dimmer at night, with names that never overlap; the layout is chikyu-earth's through an optional peer |
| Close approaches to the Earth | 4,183 approaches of near-Earth objects: every one within 0.05 au from 2026 to 2036 and the close ones since 1900, with dates, distances, speeds and sizes |
| Architecture | How the layers fit |
| Troubleshooting | Something does not appear |
| Upgrading | What to act on between versions |
Limits
import { BODIES } from "@johnmorrisdotca/wakusei-planets";
BODIES.pluto.kind; // "dwarf-planet"- What it is for. Pictures, charts, teaching and stories about the sky. It is not an ephemeris for pointing a telescope or planning a flight: for that use JPL Horizons itself, which every position here is checked against.
- The planets (Mercury to Neptune, VSOP87B cut to 995 of its 35,080 terms) are within 5 arc-seconds of Horizons on 60 dates from 1800 to 2200, Mars the worst at 4.8, and the tests hold each to 6 or less; the series is good for the years 1750 to 2250 and slowly worse beyond. Pluto's table is within 0.2.
- The Moon (ELP2000-82B cut to its 540 largest terms) is within 4.7 arc-seconds on the same 60 dates, held to 5.8.
- The moons are less exact: Jupiter's four big moons are within 0.15 degree and Saturn's seven inner ones within 2.1, Uranus's Miranda within 3 and Neptune's Nereid within 6.3; one degree on a moon's orbit is about the width of the moon on a screen. Accuracy has each moon's number.
- The minor bodies (Vesta, Pallas, Chiron, Pholus, Halley) are within an arc-second of Horizons in the years their tables cover (Vesta and Pallas 1900 to 2100, the others 1800 to 2200; 0.5 at the worst on the dates checked); outside them they are plain ellipses from Horizons' elements of one epoch, a few degrees off a century away (and Halley's 31 degrees off in 2026 without its table: the space view loads it).
- The dwarf planets are within 0.2 arc-seconds of Horizons in the years their tables cover (1800 to 2200, Ceres 1900 to 2100); outside them the positions are plain ellipses, good for a few years either side of June 2026. Their moons other than Pluto's are not checked against Horizons, and a dwarf planet's pole is estimated where it is not measured (NOTICE.md says which).
- The spacecraft follow Horizons' own record, within 1,000 km near a planet and elsewhere a millionth of the distance from the Sun; a path after today is Horizons' prediction, not a fact.
- Star sizes in the line-up are each from a refereed paper, with the paper's error; WOH G64's and Stephenson 2-18's are estimated (from the spectrum and the brightness, and from a dust-shell fit) and not measured, and UY Scuti's distance is not a parallax. A star's surface (cells, spots, glow) is drawn for looks and says so.
- Nothing is guessed. A fact with no source is left out. Accuracy has each body's number and how to run the check yourself.
realisticandpaintedare the photo maps (paintedis the same maps, so an older page still works).illustratedis the shaded drawing from the numbers, and it is not a default. Venus, Saturn, Neptune and the Sun use Solar System Scope's maps (CC BY 4.0). Mercury uses the natural grey 8K map (Shady Tex and Solar System Scope, CC BY 4.0). Mars stays on the Viking mosaic, graded toward a butterscotch ochre, with the frost in Hellas toned to the basin and the polar ice left. Jupiter and Uranus use Nestaeric's maps (CC BY 4.0), and Saturn's poles use Nestaeric's caps (CC BY 4.0). The Earth and the Moon stay on their NASA maps until those have been compared. The rest are the public-domain maps inNOTICE.md.- A shaded look needs WebGL. Without it the line drawing is drawn.
- Jupiter, Saturn, Uranus and Neptune have their rings drawn.
- A portrait with no
turnturns at 12 degrees a second, backwards when the body turns backwards. A picture with a date keeps that orientation and adds the same turn.turn="0"stays still. - Pictures for the painted look are 1.31 MB in the package at 512 and 1024 pixels; a sharper picture is fetched when you zoom in.
How to cite
If this package helps a paper, a talk or a class, please cite it as software. GitHub's "Cite this repository" button reads CITATION.cff and gives BibTeX and APA; in plain text:
Morris, J. (2026). Wakusei Planets (version 0.52.0) [Computer software]. https://github.com/johnmorrisdotca/wakusei-planets
Cite the version you used (npm ls @johnmorrisdotca/wakusei-planets), and cite the sources of the numbers you use as well: NOTICE.md names each one, with the paper or the page it was read from (the IAU working group's report for sizes and poles, VSOP87B, ELP2000-82B, L1.2 and TASS1.7 for positions, and NASA's JPL Horizons for the fits and the spacecraft).
Accessibility
- Every
<wakusei-body>is an image with an accessible name from its body and look, such as "Saturn, line drawing", or the Japanese name withlang="ja". - A reader who prefers reduced motion gets a quarter of the turn.
turn="0"is the only stop. - A body can be turned, tipped, zoomed and panned with the keyboard, and the view controls are at least 48 pixels.
- Names and labels are in English and Japanese (
lang="ja").
<wakusei-body body="saturn" look="line" lang="ja" size="320"></wakusei-body>Browser and runtime support
- The package needs Node 24 or later. The pure side runs in Node and in any current browser; the element needs a current browser.
- The shaded looks need WebGL and
three>=0.160.0(an optional peer). - The tests run the demo in Chromium and WebKit, at a phone's width and a desk's, and draw WebGL in software.
Languages
The names and labels in the element are in English and Japanese (lang), and so are the demo's words and every guide: each guide in docs/guides has a twin in docs/guides/ja, one language to a page.
import { lineSvg } from "@johnmorrisdotca/wakusei-planets";
console.log(lineSvg("saturn", { size: 160, lang: "ja" }).includes("土星"));Japanese names and labels need only the lang attribute; the SVG string takes the same option.
Architecture
The lowest layers are pure and import with no browser: the facts, the positions, the pose and the line drawing. The shaded looks are one entry point for each body, registered by name, and every <wakusei-body> shares one WebGL context through kazoku-ui. Architecture has the layers.
import { portrait } from "@johnmorrisdotca/wakusei-planets";
const pose = portrait("uranus");
console.log(pose.pole.length);Development
pnpm install
pnpm check # lint, types, unit tests, the build and the packed package
pnpm test:readme # every ts block of the README, type-checked and run against the packed package
pnpm test:usage # every way of using it in the README and the guides, built and opened
pnpm docs:check # the reference site's checks
pnpm test:demo # the demo and the docs site in a real browser
pnpm dev # the demo on http://127.0.0.1:8225/wakusei-planets/The pictures in docs/images are made by the package's own script:
ONLY=hero-saturn-painted,builder-desk pnpm screenshotsContributing
Work in a git worktree from origin/main, one branch per change:
git worktree add ../wakusei-work -b my-change origin/mainSee CONTRIBUTING.md. The rules that matter most: draw from public facts and cite them, pictures only from public-domain sources, a fact with no source is left out, and performance is not optional.
Changes
CHANGELOG.md lists every release with its date.
Licence
MIT: see LICENSE. The code is MIT. Some pictures are CC BY 4.0 (Solar System Scope, and Nestaeric for Jupiter, Uranus and Saturn's poles) and the rest are public-domain NASA, USGS and JPL imagery. Each file is credited in NOTICE.md.
The name
Wakusei (惑星, わくせい) is Japanese for a planet.
The family
Wakusei Planets is one of forty-one packages, each made for the same site, each at github.com/johnmorrisdotca or github.com/spxis. The code of every one is MIT.
Games — board
- Domino (ドミノ): dominoes and Mexican Train. Demo.
- Gunjin (軍人): five hidden-rank strategy games with pass-the-device play. Demo.
- Narabe (並べ): one rules engine for abstract board games, from gomoku and Reversi to Go and checkers. Demo.
- Sugoroku (双六): backgammon and its variants, with the doubling cube and match play. Demo.
- Tenka (天下): world conquest for two to six, on a map of the real world. Demo.
Games — cards & tiles
- Fuda Cards (札): collectible card frames with a true thickness, foil, stacks, wear and a binder, as two web components. Demo.
- Hitotsu (一つ): a colour-card shedding game for two to eight, with the house rules people play. Demo.
- Jarajara (ジャラジャラ): mahjong tiles drawn as SVG, stacked layouts, and the matching solitaire Awase. Demo.
- Kumimoji (組み文字): a crossword tile race, in English and Japanese kana. Demo.
- Toranpu (トランプ): a deck of playing cards, card games with computer players, and solitaires. Demo.
Games — puzzles
- Houseki (宝石): gem and stone matching puzzles: falling triplets, stone collapse, colour chains and gem swap. Demo.
- Jirai (地雷): minesweeper on shaped grids with verified no-guess boards. Demo.
- Karakuri (からくり): eight hyper-casual puzzle games, some of them physics: draw a shield, pull pins, cut ropes, slide blocks, pour tubes. Demo.
- Kazu (数): grid number puzzles: Sudoku and its variants, Futoshiki and Skyscrapers. Demo.
- Kyuubu (キューブ): a turning cube for the browser, 2×2 to 7×7, with record solves to replay. Demo.
- Meikyuu (迷宮): mazes on squares, hexagons, triangles and circles, made from a seed and drawn through with a finger or the mouse. Demo.
- Suido (水道): a pipe puzzle: turn the pieces until the water reaches every drain. Demo.
- Tobiishi (飛び石): peg solitaire with nine boards and seeded solvable challenges. Demo.
- Tsunagi (繋ぎ): a line-joining logic puzzle whose every level has exactly one answer. Demo.
Games — dice & random
- Korokoro (コロコロ): dice, with notation, exact odds, real sounds and the dice of many games. Demo.
- Tane (種): seeded random numbers and daily seeds, the same in every browser and on every server. Demo.
Language
- Bushu (部首): find a kanji by the parts it is made of. Demo.
- Hikidashi (引き出し): a drawer of small Japanese text tools: era dates, kanji numerals, readings and sentence difficulty. Demo.
- Jisho (辞書): words of Japanese looked up by reading or written form, and the grades, JLPT levels, readings and look-alike pairs of 2,999 kanji. Demo.
- Kotoba (言葉): word lists and word-game rules in English, French, German and Japanese. Demo.
Space Program X
- Chikyu Earth (地球): a line-drawn globe that turns at the Earth's own rate, with an optional realistic Earth from space and markers for any place. Demo.
- Hoshi Stars (星): the stars you can see without a telescope, with names, colours and distances, the constellations with their lines and boundaries, and the Messier objects, drawn on any of seven sky maps. Demo.
- Uchusen Rockets (宇宙船): rockets drawn from sourced sizes, as line drawings and 3D views you can take apart and turn, with a check that a rocket really goes together. Demo.
- Wakusei Planets (惑星): the Sun, the planets and their moons, as line drawings, shaded drawings and painted surface maps, with their real sizes, tilt and rotation. Demo.
Geography & data
- address-plus (アドレスプラス): parse and format addresses in the United States, Canada, Japan, Australia, France, Germany and the United Kingdom. Demo.
- Chizu (地図): maps of the world and of countries' regions, in English and Japanese, with a quiz and callouts. Demo.
- Hako Devices (箱): line drawings and 3D views of computers, phones, consoles and NAS boxes, from published sizes. Demo.
- Hata (旗): country and regional flags as SVG, at their true proportions and keyed by ISO code. Demo.
- Koyomi Calendars (暦): calendar-page icons and whole months as SVG, in light and dark, with page-turning from one day to the next. Demo.
- Kuni (国): countries and their regions, with ISO codes and names in English and Japanese. Demo.
Sports
- Dougu Sports (道具): sports emblems as SVG: trophies, medals, crests, and the ball and gear of every sport, with optional 3D turning. Demo.
- Kyogijo Stadiums (競技場): sports fields, rinks, courts and ballparks drawn to scale as SVG, with each team and the score on them. Demo.
- Meigen Sports (名言): sports quotations and on-this-day history. Demo.
- Senshu Jerseys (選手): sports jerseys, sweaters, kits, caps, helmets and retired-number banners as SVG, front and back, with optional 2.5D turning. Demo.
- Taisen Brackets (対戦): a sport-agnostic tournament bracket, drawn as SVG, from a list of ties. Demo.
Developer tools
- REST in Pieces (レスト・イン・ピーシーズ): seeded test data and REST APIs for frontend development, with latency and error drills. Demo.
This package is Wakusei Planets. The demos of all forty-one share one header and footer, so each links the rest.
