@johnmorrisdotca/chikyu-earth
v0.51.1
Published
Chikyu Earth 地球 — A line-drawn globe for the web: country outlines that turn at the Earth's own rate, centred on the place you give it, with an optional realistic Earth from space (three.js), the Sun, Moon and planets, satellites on their orbits, and mark
Maintainers
Keywords
Readme
It runs in the browser of a phone, a tablet or a computer: nothing to install, no account, and it is free. Turn the Earth, see where the Sun is shining on it, and find out when the International Space Station (ISS) crosses the sky over your place.
Who it is for
- Teachers and students: the Earth lit by the real Sun, so day and night can be seen for any date and time, and sheets to print in English and Japanese: the globe to colour, a world map, my country, day and night and the seasons.
- Satellite spotters and space enthusiasts: when the ISS passes over your place, with the direction, the height and how bright, and all 135 Space Shuttle flights put on the globe.
- Researchers and outreach staff: the orbit model (SGP4) and how far it can be trusted, every source with its terms in NOTICE.md, the passes checked against Skyfield. Read Limits first, and see How to cite.
- Developers and sites with a place on them: one tag, no build step, no canvas, an SVG that prints sharply, markers that move with the globe, and countries as data (outlines, English and Japanese names and two-letter codes, no network). The install and the API are below.
Try it now, nothing to install
Learn: Day and night now · Sheets to print · The day and night sheet
Look up: When can I see the ISS? (pick a place, search, or press My location) · The Earth, the Moon and the planets · Space Shuttle STS-31, which put the Hubble telescope up
Make: The code builder · The embed page · The demo in Japanese · in English
For teachers and families
Chikyu Earth 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 sheets guide says what each printable sheet is, and the ISS guide says how a pass is worked out and how to read one. Every source is credited in NOTICE.md and at the foot of each demo page.
Features
- A line-drawn globe as one SVG: country outlines on an orthographic disc, in two looks (
line,thick), with an optional graticule. - It opens centred where you say, or on 0,0 when you say nothing; it never asks the browser where the reader is. Auto-turn runs at the Earth's own rate: one sidereal day a turn, and the family's speed buttons (0.5×, 1×, 2×) are multiples of it.
- The Earth from space (
/realistic): day and night by the real Sun, city lights, sun glint, clouds and the atmosphere, drawn with three.js through one shared WebGL context. - The Sun, the Moon and the planets where they are on a date and time (
/space), and satellites at the places SGP4 puts them (/satellites), with a camera that rides along. - When you can see the ISS (
/passes): the next passes of the ISS, Tiangong and Hubble over any place, with direction, height, brightness and whether the satellite is lit while the sky is dark, a sky dome that draws each, and<chikyu-passes>. - Markers with labels, groups, clusters and events (
/markers), on either globe. - Pure parts that run on a server:
globe(), the rotation and view maths,COUNTRIESandcountryList(). - Every live view zooms, pans and turns by itself, with no bar: drag, two-finger pinch, Ctrl and the wheel (a plain wheel at Fit scrolls the page) and the keys, through kazoku-ui's controls, from a tenth of Fit to 20 times on the line globe (each range and why). Add
<kazoku-view-controls>for buttons and the address. - Names in English and Japanese, and a strict content security policy is enough.
Install and use
npm install @johnmorrisdotca/chikyu-earthOr use no install at all: every example below was run in a browser, built or type-checked by pnpm test:usage against the package as npm packs it, and the guides hold the same text.
In a plain HTML page
One script tag from jsDelivr and the tag. (From unpkg, with the realistic Earth, and pinning a version: the CDN guide.)
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>Chikyu Earth from jsDelivr</title>
<script type="module" src="https://cdn.jsdelivr.net/npm/@johnmorrisdotca/chikyu-earth/element/+esm"></script>
</head>
<body>
<chikyu-earth center="139.7,35.7" look="thick" graticule size="320"></chikyu-earth>
</body>
</html>The globe appears centred where you say; with no center it opens on 0,0, the Greenwich meridian on the equator. The globe never asks the browser where the reader is: a page that wants the reader's place asks for it itself, on a press, and sets center. look is line or thick. It also zooms and turns: drag, pinch, Ctrl and the wheel, the arrow keys (controls="none" takes that off).
With the shared controls
The kazoku-ui view controls bar adds buttons and a slider and keeps the view in the address. One listener passes its camera on:
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>Chikyu Earth 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/chikyu-earth/element/+esm";
const earth = document.querySelector("chikyu-earth");
document.querySelector("kazoku-view-controls").addEventListener("kazoku-viewchange", (event) => {
earth.setView(event.detail, event.detail.final, event.detail.reason !== "auto");
});
</script>
</head>
<body>
<chikyu-earth id="earth" size="420" look="thick" center="139.7,35.7" tabindex="0"></chikyu-earth>
<kazoku-view-controls for="earth" address grab-radius="fit" controls="advanced" tilt-max="90" speed="0.004178"></kazoku-view-controls>
</body>
</html>Auto-turn (add autoplay) moves at the Earth's own rate: 0.004178 degrees a second, one sidereal day — 23 h 56 min 4.0905 s — per revolution.
In React
The element needs a browser, so it is imported inside the effect, never at the top of the file; that keeps a server render working. (Vue, Svelte and Angular do the same: the frameworks guide.)
import { useEffect, useRef } from "react";
export function ChikyuEarth({ center = "139.7,35.7", look = "thick" }: { center?: string; look?: "line" | "thick" }) {
const host = useRef<HTMLDivElement>(null);
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/chikyu-earth/element");
}, []);
return (
<div ref={host}>
<chikyu-earth center={center} look={look} graticule />
</div>
);
}Every other way
| How | Where |
|---|---|
| A script tag from jsDelivr or unpkg, the realistic Earth from a CDN | CDN guide |
| An ES module in Vite or webpack | 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 |
| TypeScript types, an SVG string on a server, Node | TypeScript and Node guide |
| The web component (<chikyu-earth>, <chikyu-earth-realistic>) | every one of the above; its attributes are in The element |
| Something does not appear | troubleshooting |
The guides are also in Japanese (日本語), one language to a page: docs/guides/ja/.
Two packages: the Earth here, the rest in wakusei-planets
Chikyu Earth is for someone who cares about the Earth only: the countries, day and night, city lights, clouds, markers and the satellites round it. The Sun, the other planets and the moons, where each one is on a date, and the solar system as a scene are wakusei-planets. The dependency runs one way: wakusei-planets may use chikyu-earth, and chikyu-earth never needs wakusei-planets. A page about a city or a flight installs only this one, a page about Saturn only the other, and a page about the Earth in the solar system both; with both, wakusei-planets' line Earth is this package's globe with the countries:
npm install @johnmorrisdotca/chikyu-earth @johnmorrisdotca/wakusei-planetsimport "@johnmorrisdotca/chikyu-earth/element";
import "@johnmorrisdotca/wakusei-planets/element";
import "@johnmorrisdotca/wakusei-planets/earth";The full page, the rule and what lives where, each example run by pnpm test:usage: Why two packages.
The Earth from space
An optional second look, for a page with room for a real picture: day and night by the real Sun, cities' lights, a sun glint on the sea, a cloud layer and the atmosphere at the rim, drawn with three.js through kazoku-ui's shared renderer. It is its own entry point, so the line globe above costs nothing extra.
<script type="module">
import "@johnmorrisdotca/chikyu-earth/realistic/element";
</script>
<chikyu-earth-realistic center="139.7,35.7" time="2026-06-21T03:00Z" texture-base="/textures/"></chikyu-earth-realistic>Needs three and @johnmorrisdotca/kazoku-ui (both optional peers) and the pictures (1.6 MB, from NASA, in dist/textures/). It draws nothing while nothing changes,
at most 30 times a second while it does, in one WebGL context, with textures that grow as you zoom and are freed after. With tiles="/tiles/" (a folder of NASA map
tiles, how) it loads only the finer tiles in view, so you can zoom in to 40 times and stay sharp. tiles-finer="gibs" (off unless set) also asks NASA's imagery service for a daily picture, only closer than those tiles, and the credit line names it while it is on screen. With speed="86400" (a day a second; the name <chikyu-space> uses) its clock runs on from the date shown and the Sun, the night side and the clouds follow it (guide). immersive fills the window, camera="space" holds the camera in the stars so the Earth turns beneath it, and it draws every satellite group at once (guide). All of it, the budget and the tests:
docs/realistic.md.
The Sun, the Moon and the planets
<chikyu-space> (@johnmorrisdotca/chikyu-earth/space/element) places the Earth, the Moon, the Sun, the planets and Pluto (the real ones, with their moons, when wakusei-planets is installed: guide) where they are at a date and time, with the Moon's phase and the Earth's day side
from the light, a compressed scale you can read (and a true one that shows how empty it is), time that runs forwards or backwards (Play, Pause and Back in the demo, and a chikyu-timechange event for a date box to follow: guide), and a zoom from the Earth to the solar system. Positions are
computed in the browser by astronomy-engine (MIT), nothing is fetched. docs/space.md. The solar system is wakusei-planets' to own, so this view is moving there; this package keeps the Earth and its satellites (why two packages).
Meteors
<chikyu-earth-realistic meteors> and <chikyu-space meteors> draw meteors as they look from space: short streaks 80 to 120 km up, only on the dark side and in twilight, more of them under an active shower's radiant, and only while the clock runs. Each streak's place and moment are drawn at random, and the element says so under the picture; how many there are, where they fall, their height and the showers' dates are real. meteors-strength (0 to 1, the property meteorsStrength; 1 when you say nothing) makes them subtler: fewer streaks and fainter ones, none at 0, with every real figure unchanged. The showers are the International Meteor Organization's working list for 2026 (37 of them), each linked by IAU code to its parent body and checked against the IAU Meteor Data Center's lists, in an entry point of its own with the rate functions, which needs no browser: guide.
import { activeShowers } from "@johnmorrisdotca/chikyu-earth/meteors";
// The showers active on the night of the Geminids' maximum, strongest first.
for (const { shower, zhr } of activeShowers(Date.UTC(2026, 11, 14, 8))) console.log(`${shower.name}: ${zhr.toFixed(1)} an hour`);A name on the Earth
body-label on <chikyu-earth-realistic> and <chikyu-space> writes the Earth's name (EARTH, 地球 on a Japanese page) on the globe so it turns with it and the surface shows through the letters: the family's shared label (kazoku-ui's body-label), in the family's plain attributes (body-label = painted, etched, outline or burned, then body-label-strength, -repeat, -latitude, -facing, -font, -fallback-font) and the property bodyLabel. The default is Michroma, painted, half strength, once, turning with the Earth. Off unless set; nothing is fetched until it is; nothing is drawn at rest: guide.
import { BODY_LABEL_ATTRIBUTES, bodyLabelText, readBodyLabel } from "@johnmorrisdotca/chikyu-earth/realistic";
// The family's plain attributes: absent, no name; present, the family's own default (painted, half strength, once, on the equator).
const none = readBodyLabel(() => null);
const plain = readBodyLabel((name) => (name === "body-label" ? "" : null));
console.log(none, JSON.stringify(plain));
// A page's own choices, and the name in its language.
const mine = { "body-label": "etched", "body-label-strength": "0.8", "body-label-repeat": "both", "body-label-latitude": "55" };
console.log(JSON.stringify(readBodyLabel((name) => mine[name] ?? null)));
console.log(bodyLabelText("en"), bodyLabelText("ja"), BODY_LABEL_ATTRIBUTES.length);Names on the stars and faint constellation lines
star-names, star-names-magnitude and constellation-lines on <chikyu-space> and <chikyu-earth-realistic> lay the names of the brightest stars, and the 88 constellations as very faint lines (the figure under the pointer at full strength, with its name), over the sky the page draws: hoshi-stars' sky labels, an optional peer loaded only when one is set, in hoshi's own attribute names. Names never overlap, are in the page's language and are left out behind the Earth, the Moon and the Sun; nothing is drawn at rest: guide.
<chikyu-space star-names="12" constellation-lines="0.16"></chikyu-space>City names
city-names on <chikyu-earth-realistic> and <chikyu-space> names cities on the Earth from kuni's list: the capitals first, then the cities of a million and the large ones as the Earth grows on the screen, the most populous first, in the page's language (Japanese where kuni has the name), never overlapping and none on the far side. kuni is an optional peer loaded only when it is set, a tier at a time; the look is the property cityNamesStyle; nothing is drawn at rest: guide.
<chikyu-earth-realistic city-names="24"></chikyu-earth-realistic>Borders
borders on <chikyu-earth-realistic> and <chikyu-space> draws the borders between countries on the land, as thin lines that turn with the Earth, by day and by night, from chizu's world-geo (Natural Earth 1:110m, public domain), loaded only when it is set (44 kB gzipped). borders="regions" adds a page's own provinces and states (borderData.regions) once the Earth is large enough to tell them apart. Each set is one batch of lines; nothing is drawn at rest: guide.
<chikyu-earth-realistic borders="countries"></chikyu-earth-realistic>The grid and country names
grid on <chikyu-earth-realistic> and <chikyu-space> draws the meridians and parallels on the Earth (every 30 degrees while it is small on the screen, every 15 once it is large), with the equator, the tropics, the polar circles and the prime meridian picked out, light by day and dim by night. country-names names the countries in sight at the middle of the part of each you can see, in the page's language (chizu's English and Japanese names), never over another name and never on the far side. Both are off unless set; the grid is one batch of lines and nothing is drawn at rest: guide.
<chikyu-earth-realistic grid country-names></chikyu-earth-realistic>You are here, and places on the Earth
route on <chikyu-earth>, <chikyu-earth-realistic> and <chikyu-space> draws the line between two places (lon,lat,lon,lat). routeInfo gives the accurate distance on the Earth's real shape, the great-circle distance, the bearings and a flight time at 900 km/h. The line is off until it is set, and nothing is drawn at rest: guide.
places on <chikyu-space> and <chikyu-earth-realistic> marks places on the Earth, each a beam, a pin or a ring (places-look) standing out of the ground, turning with the Earth, hidden on its far side and dimmer at night: kind: "here" for the reader's own place (brighter, with a quiet pulse) and favourites, quieter, each with an optional color. Up to 5,000: the first 32 in sight stand up with their names, the rest are rings in one draw call, crowds are gathered with their count, and goToPlace(id) turns the view to one. Names never overlap; nothing is drawn at rest. here-city (off by default) names a here place with the nearest city within 100 km, in the page's language; kuni is loaded only then. The package never asks for the reader's place and stores or sends nothing: the page asks on a press and rounds the place with nearby first: guide.
<chikyu-space places='[{"id":"me","lon":-79.4,"lat":43.7,"label":"You are here","kind":"here"}]'></chikyu-space>Outside data: the data door
The package draws; you bring the data. @johnmorrisdotca/chikyu-earth/door takes a finer map of the Earth, or a list of satellites' orbit data, as a source: a small object that carries its own licence and credit, so the screen can always say whose data it shows. With no source nothing changes: the Earth is drawn from the package's own pictures and tiles (OWN_SOURCES, written from NOTICE.md, never non-commercial or share-alike). A source of yours may be either, and the credit line prints that beside the licence.
import { createSourceBook, creditLine, mapKeys, mergeElementSets, ownCredit } from "@johnmorrisdotca/chikyu-earth/door";
// A map of your own: here a day picture with no pictures behind it, only the keys it would answer. A real one fetches tiles, and says whose they are and under what licence.
const info = (id, name) => ({
id,
name: { en: name, ja: "私のデータ" },
credit: { en: `${name}, 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/mine",
retrieved: "2026-11-11",
});
const myMap = {
kind: "tiles",
layer: "day",
info: info("my-map", "My map"),
need: (place, detail) => mapKeys(place, detail, undefined, "mine/"),
load: async () => ({ width: 512, height: 512, image: { width: 512, height: 512 } }),
bytes: (tile) => tile.width * tile.height * 4,
};
// An element keeps a book like this one: `earth.addSource(myMap)` is `book.addSource(myMap)`, and `passes.addSource(mine)` is the same for orbit data.
const book = createSourceBook();
book.addSource(myMap);
const mine = {
kind: "records",
info: info("my-orbits", "My orbits"),
records: () => [
{ OBJECT_NAME: "ISS (ZARYA)", EPOCH: "2026-11-10T00:00:00", MEAN_MOTION: 15.49, ECCENTRICITY: 0.0007, INCLINATION: 51.6, RA_OF_ASC_NODE: 335.9, ARG_OF_PERICENTER: 339.3, MEAN_ANOMALY: 20.6, NORAD_CAT_ID: 25544, BSTAR: 0.0001, MEAN_MOTION_DOT: 0.0001, MEAN_MOTION_DDOT: 0 },
{ OBJECT_NAME: "Broken", EPOCH: "2026-11-10T00:00:00", MEAN_MOTION: Number.NaN, ECCENTRICITY: 0, INCLINATION: 0, RA_OF_ASC_NODE: 0, ARG_OF_PERICENTER: 0, MEAN_ANOMALY: 0, NORAD_CAT_ID: 1, BSTAR: 0, MEAN_MOTION_DOT: 0, MEAN_MOTION_DDOT: 0 },
],
};
book.addSource(mine);
await book.ready();
const sets = mergeElementSets(book.elementLists());
console.log(`${sets.length} element set kept, ${book.stats().records["my-orbits"].skipped} left out: ${sets[0].set.OBJECT_NAME}`);
console.log(`the day map answers ${book.mapSources("day")[0].need({ lonMin: -10, lonMax: 10, latMin: -5, latMax: 5 }, 8192).join(", ")}`);
const credits = [ownCredit("chikyu-pictures", 1), { source: myMap.info, own: false, used: 6 }];
console.log(creditLine(credits, "en"));
console.log(creditLine(credits, "ja"));
book.enableSource("my-map", false);
console.log(`${book.mapSources("day").length} day maps with the source off`);<chikyu-earth-realistic> takes map sources and <chikyu-passes> takes orbit data: sources, addSource(source) (checked at once, returns the way to take it away), removeSource(id), enableSource(id, on), data="own" to ignore every outside source, and credits() with chikyu-creditschange to say whose data was in the last drawn frame. earthTiles(base) is the package's own folder of tiles as a source (what tiles="..." means), and elementsFrom(url, info) makes a source of an address you chose, read politely. The tiles of a view share one 72 MB budget, six loads at a time, and nothing is sent at rest. Every old attribute and function stays: guide.
Satellites
The ISS, a space station or thousands of Starlink satellites at the places SGP4 puts them for the date and time shown, on <chikyu-space>: a group is one draw call however many it holds, press one to get its name, height and speed, and its orbit is drawn. Chikyu fetches nothing: your page passes in orbital elements (CelesTrak's JSON, within its usage policy), and satellite.js (MIT, an optional peer) does the maths about once a second, with every frame between interpolated. fetchElements(url) reads OMM JSON, CSV or TLE from an address you choose, politely (https, not again within two hours, stop on any answer that is not 200). A satellite whose elements are more than 14 days from the time shown is drawn dimmer, and one more than 30 days away is left out. A group is hidden while the clock runs faster than 60 times real time. nearest and within say which satellites are closest to a place, a direction in the sky or another satellite, and closeApproach the next time two of them pass; each call places every satellite once and does not run again by itself. ringSatellites rings the ones you name. A small catalogue (SATELLITE_GROUPS, CATALOGUE, findInCatalogue) names fourteen groups (stations, weather, GPS, Galileo, OneWeb and more) and about forty satellites worth following, with no elements in it. The guide has the rules for getting elements and the budget, each line tested: satellites guide, docs/satellites.md.
import "@johnmorrisdotca/chikyu-earth/space/element";
import { createSatellites, type ElementSet } from "@johnmorrisdotca/chikyu-earth/satellites";
const elements: ElementSet[] = await (await fetch("/my-celestrak-copy.json")).json();
document.querySelector("chikyu-space")!.setSatellites("stations", createSatellites(elements), { orbits: true });Passes: when can I see the ISS?
findPasses(elements, place, { from, to }) gives the next passes of a satellite over a place: when it comes up, is highest and goes down (UTC, with the compass word and degrees at each, and the height), how bright it looks, and whether it can be seen, which needs the satellite in sunlight while the watcher's sky is in civil twilight or darker (each pass says which). It is a pure function over the same SGP4 as the rest, with no DOM and no clock. skySvg draws a pass across the sky as an SVG string, groundTrack gives the path under the satellite for a globe, and <chikyu-passes> lists the passes and draws the dome, in English and Japanese. The ISS, Tianhe and Hubble have estimated standard magnitudes (from their size and an assumed albedo); give better ones with magnitudes.
import { findPasses } from "@johnmorrisdotca/chikyu-earth/passes";
const iss = {
OBJECT_NAME: "ISS (ZARYA)",
EPOCH: "2026-11-09T04:58:46.240896",
MEAN_MOTION: 15.49270212,
ECCENTRICITY: 0.00072974,
INCLINATION: 51.6321,
RA_OF_ASC_NODE: 302.4538,
ARG_OF_PERICENTER: 5.2479,
MEAN_ANOMALY: 354.8585,
NORAD_CAT_ID: 25544,
BSTAR: 0.0001553356,
MEAN_MOTION_DOT: 8.201e-5,
MEAN_MOTION_DDOT: 0,
};
const from = Date.UTC(2026, 10, 10);
const tokyo = { latitude: 35.69, longitude: 139.69 };
const [next] = findPasses(iss, tokyo, { from, to: from + 5 * 86_400_000 });
console.log(next ? `${new Date(next.highest.ms).toISOString()}: ${next.highest.compass}, ${Math.round(next.highest.altitude)} degrees, ${next.sky}` : "none");Passes are only as good as the orbit data are new: each pass says how old its elements are, and the ISS's change with every reboost. Checked against Skyfield (249 passes: every time within a second, directions within 0.06 degree), and by hand against a sky-watching site's published predictions (all found, times within two seconds). Brightness is a model from the satellite's size, good to a magnitude or two. The guide has the numbers and the rules: passes guide. The demo's page Passes over me has a map, a search, "My location" (asked for only when pressed) and the code for every way a page is made.
Riding along
space.ride({ group: "stations", index: 0 }, { look: "horizon" }) puts the camera on the ISS (or a Starlink satellite, the Moon, a planet) at its real place for the moment shown and looks at the Earth, which goes by beneath
as the body moves along its orbit; switch to another body and the camera glides there. Straight down or toward the horizon, from the body or following it at a distance, time faster or slower. A ridden satellite is in the picture by default (the camera a little behind and above it, a small drawing of it where the page has no model, not to scale); ride-viewpoint="inside" (property rideViewpoint, option viewpoint) puts the camera at the satellite instead. Seen from above, the model shrinks as the ride rises and hands over to the ordinary mark by 2,000 km; ride-model-size="fixed" (property rideModelSize, option modelSize) keeps one size at every height. ride-model-share, ride-model-seat and ride-zoom frame and zoom the ridden satellite (properties rideModelShare, rideModelSeat, rideZoom). It animates continuously, so it keeps to the
same budget: at most 30 frames a second (one a second for reduced motion), nothing drawn while paused, out of sight or hidden. Ride along guide, docs/ride-along.md.
Printable sheets
@johnmorrisdotca/chikyu-earth/sheets draws five printable sheets for children and everyone as SVG strings measured in millimetres, with no browser and no dependency: the globe to colour (the continents in thick outlines, the continents and oceans named; three sides), a world map, a "my country" sheet (the outline, the capital as a star, a box to draw the flag), day and night for a date and time (the line between them from the package's own sun position, the night hatched so black and white prints well) and the seasons (the Earth at four points round the Sun, tilted 23.4 degrees). A4, US Letter, A3 or Tabloid, English or Japanese, thick lines and big type (kid) or thin and small (normal). The demo's sheets page puts kazoku-ui's header (the brand, the title, a Name box) and footer (credits, version, a QR code) round them and has Print / save PDF, and the Pages build makes ready-made PDFs. Guide.
import { dayNightSvg, globeSheetSvg, terminator } from "@johnmorrisdotca/chikyu-earth/sheets";
const room = { widthMm: 184.6, heightMm: 180 };
console.log(globeSheetSvg("americas", { ...room, lang: "en" }).includes("North"));
console.log(dayNightSvg(Date.UTC(2026, 5, 21, 12), room).includes('data-sun="0.'), terminator(Date.UTC(2026, 5, 21, 12), 12).length);Markers
Mark any place at [lon, lat] with a label, colour or icon, in groups you can show or hide, on either look. Chikyu ships no places; yours move with the globe, fade on the far side, make room
for their labels, gather into clusters when crowded, and fire hover, click and keyboard events with your own data. One canvas pass for thousands, a pool of 24 buttons for the labels. docs/markers.md.
import "@johnmorrisdotca/chikyu-earth/element";
import { attachMarkers } from "@johnmorrisdotca/chikyu-earth/markers";
const markers = attachMarkers(document.querySelector("chikyu-earth")!);
markers.add({ id: "tokyo", lon: 139.69, lat: 35.69, label: "Tokyo", group: "Cities" });Controls
The elements carry the shared kazoku-ui view controls themselves, so
every live view zooms, pans and turns with no bar: drag to turn (and move, once zoomed), touch pinch, Ctrl and the
wheel to zoom (a plain wheel at Fit scrolls the page), the arrow keys, +, - and 0 once the element is focused.
controls="none" takes the hands off; zoom-min and zoom-max change the range. Chikyu does not draw its own zoom,
rotate or drag controls.
| Element | Zoom range | Why it stops there |
| --- | --- | --- |
| <chikyu-earth> | 0.1 to 20 times | Natural Earth 1:110m outlines, redrawn at each zoom; at 20 times the view is about 640 km across and a coast is a few straight segments |
| <chikyu-earth-realistic> | 0.1 to 5 times; 40 with tiles found (20 for a set that stops at level 4) | the package's pictures are 4096 pixels across at most; the finest tile level is up to 8 times that |
| <chikyu-space> | a millionth to 2.5 times; 0.5 to 40 riding from a body | the zoom is the camera's distance (the whole solar system needs a millionth); close in, the Earth's picture and the textures stay sharp to 2.5 |
Zoom, pan and turn says more. For buttons, a slider, Auto-turn and the address, add the
bar for the element (give it an id and a tabindex); it takes the hands over and the page applies its events:
<chikyu-earth id="earth" size="420" tabindex="0"></chikyu-earth>
<kazoku-view-controls id="controls" for="earth" address grab-radius="fit" controls="advanced" tilt-max="90" speed="0.004178" autoplay></kazoku-view-controls>import "@johnmorrisdotca/chikyu-earth/element";
import "@johnmorrisdotca/kazoku-ui/view-controls/define";
import type { ViewChangeDetail } from "@johnmorrisdotca/kazoku-ui/view-controls/element";
const earth = document.querySelector("chikyu-earth")!;
document.getElementById("controls")!.addEventListener("kazoku-viewchange", (event) => {
const { yaw, tilt, zoom, panX, panY, final } = (event as CustomEvent<ViewChangeDetail>).detail;
earth.setView({ yaw, tilt, zoom, panX, panY }, final);
});The mapping is rotate([lambda0 + yaw, phi0 + tilt]), scale(baseScale * zoom) and
translate([cx + panX, cy + panY]), where lambda0 and phi0 are the home centre. Front returns to that home
view. Auto-turn's 0.004178 degrees a second is 360° per sidereal day; kazoku-ui leaves it still for a reader who
prefers reduced motion, and a drag or zoom never stops or resets it.
Draw one as a string
globe() returns the SVG markup, so a server, a build step or a test can draw the same globe with no DOM:
import { globe } from "@johnmorrisdotca/chikyu-earth";
const svg = globe({ size: 320, rotation: [-139.7, -35.7], style: "line" });The rotation is the pair d3-geo's rotate takes: [-longitude, -latitude] centres that place. The helpers in
rotate.ts do the time maths — SIDEREAL_DAY_MS, spinAt(ms), centreRotation(point) and
rotationAt(centre, now, start).
The element
| Attribute | What it does | Default |
| --- | --- | --- |
| size | Width and height of the square SVG, in pixels. | 320 |
| center | "longitude,latitude" to centre on. The element never asks the browser where the reader is: a page that wants that asks on a press and sets center. | 0,0 |
| look | line or thick. (style is the older name for it: a framework reads style as CSS, so use look there.) | line |
| graticule | Draw a light graticule under the countries. | off |
| controls | none takes off the drag, pinch, wheel and keys the element carries. | on |
| zoom-min, zoom-max | The zoom range, over the element's own (0.1 to 20). | 0.1, 20 |
setView(view, final = true) applies a shared controller's { yaw, tilt, zoom, panX, panY }. Every call updates
the state; pass final: false for the cheap relative transform during a gesture and final: true for the full
projection redraw. projectionView(centre, size, view) is the same mapping as a pure function: yaw is added to the
home longitude, tilt is subtracted from its latitude, zoom multiplies the scale, and pan offsets the translation.
Front is therefore the home centre; Fit is 1x with no pan.
The data
Every country the globe draws comes from chizu's world-geo entry
(@johnmorrisdotca/chizu/world-geo): Natural Earth 1:110m (public domain) as longitude and latitude, with
chizu's English and Japanese names. Nothing is fetched at runtime. COUNTRIES is that GeoJSON (177 features,
Antarctica included); countryList() is just the names and codes. alpha2 is the two-letter code, XK for Kosovo,
and null for Northern Cyprus and Somaliland, which have none:
import { countryList } from "@johnmorrisdotca/chikyu-earth";
countryList().find((c) => c.alpha2 === "JP"); // { name: "Japan", ja: "日本", alpha2: "JP" }To take newer outlines, update @johnmorrisdotca/chizu; there is no data file in this repository.
Examples
Every ts block in this README that is not marked no-run is type-checked and run against the package as npm packs it (pnpm test:readme).
import { COUNTRIES, countryList } from "@johnmorrisdotca/chikyu-earth";
COUNTRIES.features.length; // 177
countryList().find((country) => country.alpha2 === "CA")?.ja; // "カナダ"A globe with a graticule, centred on Tokyo, as a string:
import { globe } from "@johnmorrisdotca/chikyu-earth";
const svg = globe({ size: 240, style: "thick", centre: { lon: 139.7, lat: 35.7 }, graticule: true });
if (!svg.startsWith("<svg")) throw new Error("not an SVG");The turn of the Earth, from the time:
import { centreRotation, rotationAt, SIDEREAL_DAY_MS, spinAt } from "@johnmorrisdotca/chikyu-earth";
const tokyo = { lon: 139.7, lat: 35.7 };
console.log(centreRotation(tokyo), rotationAt(tokyo, SIDEREAL_DAY_MS / 2, 0), spinAt(SIDEREAL_DAY_MS / 4));What a shared controller's camera means for the projection:
import { HOME_VIEW, projectionView } from "@johnmorrisdotca/chikyu-earth";
const view = projectionView({ lon: 0, lat: 0 }, 400, { ...HOME_VIEW, zoom: 2 });
console.log(view.scale, view.translate);A look that does not exist falls back to the default instead of failing:
import { cleanStyle, STYLE_NAMES } from "@johnmorrisdotca/chikyu-earth";
console.log(STYLE_NAMES, cleanStyle("neon"));The globe with a graticule and the realistic Earth, side by side in HTML:
<chikyu-earth center="-79.38,43.65" look="line" graticule size="240"></chikyu-earth>
<chikyu-earth-realistic center="-79.38,43.65" time="2026-06-21T12:00Z" style="display: block; width: 240px"></chikyu-earth-realistic>A page that cannot run script uses an iframe of the embed page:
<iframe src="https://johnmorrisdotca.github.io/chikyu-earth/embed.html?look=thick¢er=10,30&graticule=1" title="The Earth" width="320" height="320" style="border:0"></iframe>The code builder
The code builder is one screen, and the demo's "Put it in your page" is the same panel (the family's <kazoku-embed-panel>): choose the place to centre on, the look, the graticule and the size, then pick how your page is made (HTML from a CDN, a module, React, Vue, Angular, Svelte or an iframe) and copy the code. The picture beside the code is made from the same choices; Open the embed page, Read the docs and the credit line are under it. It writes the same text the guides show.
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/chikyu-earth | The pure side: globe, COUNTRIES, countryList, the looks, the rotation and view maths. No browser. |
| .../element | <chikyu-earth>. |
| .../realistic, .../realistic/element | The Earth from space; three for the element. |
| .../markers | attachMarkers and the pure projection, clusters and labels. |
| .../space, .../space/element | The Sun, the Moon and the planets; astronomy-engine and three. |
| .../space/no-cultures, .../realistic/no-cultures | The same two elements with no sky culture but the IAU's: nothing under hoshi-stars/cultures is in the build (guide). |
| .../satellites | SGP4 for a group of satellites; satellite.js. |
| .../meteors | The year's meteor showers, and when and where their meteors fall. No DOM, no dependency. |
| .../door | The data door: sources of your own maps and orbit data with their licence and credit, creditLine, the package's own sources. No DOM, no dependency. |
| .../passes, .../passes/element | Passes of a satellite over a place, the sky dome, <chikyu-passes>; satellite.js. |
| .../catalogue | The Earth-orbit catalogue's pure parts: the class of an orbit from its elements, the kind of an object, colours, legend, fleets, and the packed file of up to 200,000 objects. No data, no DOM, no dependency. |
Guides
Each guide has a Japanese twin in docs/guides/ja.
| Guide | What it is for |
| --- | --- |
| Getting started | A globe on a page |
| HTML and CDN | A script tag from jsDelivr or unpkg |
| Bundlers | Vite and webpack |
| Frameworks | React, Vue, Svelte, Angular |
| Embed in an iframe | No script of your own |
| TypeScript and Node | Types and the pure side |
| The realistic Earth and markers | The Earth from space, markers |
| Satellites | SGP4 and the space view |
| Full screen, the camera in the stars and every satellite | immersive, camera="space", the Earth's look, and every satellite group on the realistic Earth |
| When can I see the ISS? | Passes over a place, the sky dome, how it was checked |
| Ride along | A camera on a moving body |
| The date follows the clock, and Play | The chikyu-timechange event, a speed for the space view and the realistic Earth, Play, Pause and Back |
| Names on the stars and faint constellation lines | The brightest stars named and the constellations as faint lines over the sky, in hoshi-stars' attribute names |
| City names on the Earth | Cities named from kuni's list, more as the Earth grows on the screen, in the page's language |
| Borders on the Earth | The borders between countries, and a page's own regions once the Earth is large enough |
| The grid and country names on the Earth | Meridians and parallels with the special lines picked out, and the countries in sight named in the page's language |
| A beam from a satellite to the ground | A soft cone of light from the chosen satellite to a lit footprint, true to its height, with optional spot cells, in a ride too |
| A name on the Earth | The Earth's name written on the globe, in the family's plain attribute names |
| You are here, and places on the Earth | The reader's place and favourite places as markers standing out of the Earth, asked for only on a press, kept on the device |
| Meteors seen from space | Streaks over the night side, the shower table, what is real and what is illustration |
| Outside data, the data door | Hand the package your own maps of the Earth or orbit data with their licence and credit, switch them off, and show whose data is on the screen |
| Zoom, pan and turn | The hands every view carries, each zoom range and why |
| Printable sheets | The globe, a world map, my country, day and night and the seasons to print and colour |
| Why two packages | This package and wakusei-planets: which to install, alone and together |
| How it stays light | The budget |
| Architecture | How the layers fit |
| Troubleshooting | Something does not appear |
| Upgrading | What to act on between versions |
| The catalogue of objects in Earth orbit | The orbit class and kind of any object, colours, fleets, and the packed file a site hosts for up to 200,000 objects |
Limits
Chikyu Earth is made for learning, teaching, drawing and finding a satellite in the sky with your own eyes. It is not made for pointing an antenna or a telescope, for navigation, or for any work that needs a satellite's place to better than a few kilometres. It says where each number stops:
- Outlines. Natural Earth 1:110m: good for a globe, not for a street map.
COUNTRIEShas 177 features, Antarctica included. Three places have no two-letter code (alpha2isnull), and Kosovo isXK. - The pictures of the Earth. The land, the oceans and the clouds of the realistic look are fixed NASA pictures (Blue Marble of September 2004 and its clouds, the city lights of 2016), not today's weather or today's coast. What follows the date is the light: the Sun's place comes from NOAA's low-precision formulas, tested against the almanac to 0.05 degree, so the direction of the light is right to about 0.05 degree, and the dusk is drawn as a soft band; it is not a table of sunrise or twilight times.
- Satellite places. They are SGP4's, from orbital elements you supply, which are only a snapshot: the error grows by a few kilometres a day, the ISS is moved by a reboost every month or two, and elements more than 14 days from the date shown are drawn dimmer and past 30 days left out. Good for a picture.
- Passes. Times, directions and heights matched Skyfield on 249 passes, every time within a second and every direction within 0.06 degree away from straight overhead (the passes guide has the numbers), but a pass is only as good as the elements are new, and the brightness is a model good to a magnitude or two, not a measurement.
- The Sun, the Moon and the planets come from astronomy-engine and are drawn for a picture: on the compressed scale the distances are squeezed and the bodies drawn larger than life, and between two lookups the Moon is placed by interpolation within 0.1 degree. A table of measured accuracy for the realistic look and the satellites is not published yet.
- WebGL. The Earth from space and the space view need it; without it the line globe is drawn.
- Data terms. NOTICE.md gives the terms of every source. CelesTrak states no licence or credit rule for its element sets: the demo uses them as a snapshot, within its usage policy and with credit, and never fetches them for a visitor; NOTICE.md says so.
import { countryList } from "@johnmorrisdotca/chikyu-earth";
console.log(countryList().filter((country) => country.alpha2 === null).map((country) => country.name));How to cite
Morris, J. (2026). Chikyu Earth (version 0.51.1) [Computer software]. https://github.com/johnmorrisdotca/chikyu-earth
GitHub's "Cite this repository" button reads CITATION.cff and gives BibTeX and APA. Cite the version you used (npm ls @johnmorrisdotca/chikyu-earth), and credit the sources behind the numbers and pictures: NOTICE.md says who made each one and under what terms.
Accessibility
- A reader who prefers reduced motion gets a still globe, and the riding-along camera draws at most one frame a second.
- The view takes the keyboard through the shared controls, and the markers' labels are real buttons.
- Names are available in English and Japanese.
<div id="globe" tabindex="0" role="group" aria-label="The Earth"><chikyu-earth size="420"></chikyu-earth></div>Browser and runtime support
- The package needs Node 24 or later. The pure side runs in Node and in any current browser; the elements need a current browser.
- The Earth from space and the space view need WebGL and
three>=0.160.0(an optional peer); the space view also needsastronomy-engine, and satellitessatellite.js:
npm install three astronomy-engine satellite.js- The tests run the demo in Chromium and WebKit at a phone's width and a desk's, with WebGL drawn in software.
Languages
The countries have English and Japanese names (countryList() gives name and ja), the demo is in both, and every guide in docs/guides has a Japanese twin in docs/guides/ja, one language to a page.
import { countryList } from "@johnmorrisdotca/chikyu-earth";
console.log(countryList().find((country) => country.alpha2 === "JP"));Architecture
One small core and four optional layers, each its own entry point. The core is a pure function that returns an SVG string; the layers add the Earth from space, markers, the space view and satellites. Architecture has the layers.
import { DEGREES_PER_MS } from "@johnmorrisdotca/chikyu-earth";
console.log((DEGREES_PER_MS * 1000).toFixed(6), "degrees a second");Development
pnpm install
pnpm check # lint, types, unit tests, the build and the packed package
pnpm test:readme # the README's ts blocks, type-checked and run against the packed package
pnpm test:usage # every way of using it, built or run
pnpm docs:check # the reference site's checks
pnpm test:demo # the demo, the embed page and the docs site in a real browser
pnpm dev # the demo on http://127.0.0.1:8200/chikyu-earth/Contributing
See CONTRIBUTING.md. Work in a git worktree from origin/main, one branch per change:
git worktree add ../chikyu-work -b my-change origin/mainThe rules that matter most: draw from public facts and cite them, no data of our own, a look changes lines and fills and never the geometry, and a fact with no source is left out.
Changes
CHANGELOG.md lists every release with its date.
Licence
MIT: see LICENSE. The outlines are Natural Earth's (public domain), and the realistic Earth's pictures are made from NASA Earth Observatory images: NOTICE.md says what each rests on.
The name
Chikyu (地球, ちきゅう) is Japanese for the Earth.
The family
Chikyu Earth 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 Chikyu Earth. The demos of all forty-one share one header and footer, so each links the rest.
The rest
CONTRIBUTING.md · docs/ · NOTICE.md · CHANGELOG.md · MIT licence. Dependencies: d3-geo and chizu (MIT); shared view controls are John Morris's kazoku-ui (MIT).
