@johnmorrisdotca/chikyu-earth 0.4.0 → 0.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (70) hide show
  1. package/CHANGELOG.md +78 -0
  2. package/NOTICE.md +39 -1
  3. package/README.md +199 -24
  4. package/dist/countries.d.ts +11 -0
  5. package/dist/countries.js +11 -0
  6. package/dist/element.d.ts +24 -1
  7. package/dist/element.js +70 -5
  8. package/dist/globe.d.ts +15 -1
  9. package/dist/globe.js +15 -1
  10. package/dist/index.d.ts +12 -1
  11. package/dist/index.js +12 -1
  12. package/dist/markers/cluster.d.ts +38 -0
  13. package/dist/markers/cluster.js +42 -0
  14. package/dist/markers/index.d.ts +5 -0
  15. package/dist/markers/index.js +6 -0
  16. package/dist/markers/labels.d.ts +64 -0
  17. package/dist/markers/labels.js +70 -0
  18. package/dist/markers/layer.d.ts +129 -0
  19. package/dist/markers/layer.js +455 -0
  20. package/dist/markers/project.d.ts +82 -0
  21. package/dist/markers/project.js +93 -0
  22. package/dist/markers/types.d.ts +83 -0
  23. package/dist/markers/types.js +1 -0
  24. package/dist/realistic/earth.d.ts +81 -0
  25. package/dist/realistic/earth.js +163 -0
  26. package/dist/realistic/element.d.ts +93 -0
  27. package/dist/realistic/element.js +284 -0
  28. package/dist/realistic/gate.d.ts +64 -0
  29. package/dist/realistic/gate.js +72 -0
  30. package/dist/realistic/index.d.ts +5 -0
  31. package/dist/realistic/index.js +6 -0
  32. package/dist/realistic/shaders.d.ts +10 -0
  33. package/dist/realistic/shaders.js +124 -0
  34. package/dist/realistic/shared.d.ts +23 -0
  35. package/dist/realistic/shared.js +51 -0
  36. package/dist/realistic/sun.d.ts +44 -0
  37. package/dist/realistic/sun.js +65 -0
  38. package/dist/realistic/textures.d.ts +40 -0
  39. package/dist/realistic/textures.js +141 -0
  40. package/dist/realistic/tiers.d.ts +94 -0
  41. package/dist/realistic/tiers.js +94 -0
  42. package/dist/rotate.d.ts +59 -4
  43. package/dist/rotate.js +59 -4
  44. package/dist/space/element.d.ts +134 -0
  45. package/dist/space/element.js +394 -0
  46. package/dist/space/ephemeris.d.ts +151 -0
  47. package/dist/space/ephemeris.js +162 -0
  48. package/dist/space/index.d.ts +3 -0
  49. package/dist/space/index.js +5 -0
  50. package/dist/space/scale.d.ts +124 -0
  51. package/dist/space/scale.js +141 -0
  52. package/dist/space/scene.d.ts +131 -0
  53. package/dist/space/scene.js +295 -0
  54. package/dist/styles.d.ts +65 -2
  55. package/dist/styles.js +43 -2
  56. package/dist/textures/clouds-1024.webp +0 -0
  57. package/dist/textures/clouds-2048.webp +0 -0
  58. package/dist/textures/day-1024.webp +0 -0
  59. package/dist/textures/day-2048.webp +0 -0
  60. package/dist/textures/day-4096.webp +0 -0
  61. package/dist/textures/moon-1024.webp +0 -0
  62. package/dist/textures/moon-2048.webp +0 -0
  63. package/dist/textures/night-1024.webp +0 -0
  64. package/dist/textures/night-2048.webp +0 -0
  65. package/dist/textures/water-1024.webp +0 -0
  66. package/dist/textures/water-2048.webp +0 -0
  67. package/dist/types.d.ts +55 -5
  68. package/dist/view.d.ts +64 -3
  69. package/dist/view.js +56 -3
  70. package/package.json +93 -8
package/CHANGELOG.md CHANGED
@@ -1,5 +1,83 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.7.0
4
+
5
+ The space view can look at any body, bodies can be chosen, and how the Sun and the planets are drawn is a seam another package can fill.
6
+
7
+ - **Look at a body**: `element.body = "Mars"` (any of Earth, Moon, Sun and the seven planets) points the camera at it; at zoom 1 it fills the view, and the shared controls turn the camera round it and zoom in and out from it. The demo's "Look at" row does it.
8
+ - **Bodies can be chosen**: each name beside a body is a real button (Tab and Enter), and a press on a body (not a drag) fires `chikyu-body-click`; `chikyu-body-focus` for the keyboard. The event carries `name`, `radiusKm` and `distanceKm` (`element.bodyInfo(name)` gives the same for a caption); the demo prints "Jupiter: radius 69,911 km, 666,000,000 km from the Earth".
9
+ - **A seam for drawing the bodies** (`BodyPainter`, `setBodyPainter`, `plainPainter` from `@johnmorrisdotca/chikyu-earth/space`): the space view keeps each body's place, size, light direction, name and orbit, and asks a painter only for what to draw there (an object of radius 1; `light(toSun)` each draw; the Sun's turns to face the camera). The default is what 0.6.0 drew: spheres in the planets' colours and a glow for the Sun. John chose a separate package (wakusei-planets) for the bodies' own looks, so chikyu ships no planet pictures and no rings; the Earth and the Moon keep theirs.
10
+ - Tests: e2e (a body looked at, its name chosen by keyboard, a press on it chooses it, a drag that turns the view does not) and a unit test of the default painter.
11
+
12
+ ## 0.6.0 (never published on its own: it ships in 0.7.0)
13
+
14
+ The Sun, the Moon and the planets: `<chikyu-space>`, an optional entry point, under the same performance budget as the Earth from space.
15
+
16
+ - **`<chikyu-space>`** (`@johnmorrisdotca/chikyu-earth/space/element`) places the Earth, the Moon, the Sun and the planets (Mercury to Neptune) in their positions for a date and time, with the Moon's
17
+ phase and the Earth's sunlit side coming out of the light (the Moon is half lit on 2 November 2026, last quarter). Positions are computed in the browser by **astronomy-engine** (MIT, a new optional peer dependency;
18
+ nothing is fetched). Time controls: `time` (an ISO date or `now`), `speed` (1 real time, 0 held, 3600 an hour a second, 86400 a day a second, negative backwards). Zoom from the Earth out to the solar system and back with
19
+ the shared controls (`zoom-min`, `zoom-max`), and `zoomFor("moon" | "sun" | "inner" | "solar-system" | "earth")` for the jumps. Names beside the bodies and the planets' orbits can be switched off.
20
+ - **Two scales, and it says which**: `compressed` (default; every direction real, the Moon 10 Earth radii away instead of 60, the Sun 44, the planets round the Sun at 44 radii times their distance in astronomical
21
+ units to the power 0.45, sizes enlarged) and `true` (real distances and sizes, where the planets are specks). The demo says "Compressed scale: ..." whenever it is on. [docs/space.md](docs/space.md).
22
+ - **Budget, each line tested** (`e2e/space.gl.ts`): paused, 0 draw calls and 0 frame requests in 4 s; real time, 0 draw calls in 6 s (a draw a minute); a day a second: 1.00 days a second of game time, 29.4 draws a second,
23
+ and 2.0 ephemeris lookups a second (the ephemeris is looked up once a game-second span and interpolated, within 0.1 degree of the Moon's true place); nothing drawn out of sight at a day a second; the textures follow the zoom and
24
+ are freed after it; removal frees what it held; a lost context is recovered. The space soak (10 minutes, 945 steps from the Earth to the solar system and back, at every speed, both scales, orbits and names toggled): JS heap 8.05 to 8.45 MB after garbage collection (flat from the fifth minute), GPU objects 46 to 46, textures, buffers and programs equal to the start, the average 76 GL draw calls a second (about 25 a frame, so 3 frames a second), one WebGL context, no error.
25
+ - **Pictures**: the Moon (NASA SVS 4720, LROC colour mosaic, 1024 and 2048 wide, 306 KB) joins the Earth's; the package's textures are 1.85 MB. The planets are plain colours.
26
+ - **Shared parts**: the texture loader (`src/realistic/textures.ts`) and the page's one renderer (`src/realistic/shared.ts`) now serve both the Earth from space and the space view, so a page keeps one WebGL context between them. The
27
+ Earth's shaders look at the camera instead of assuming one, so they work from any angle.
28
+ - **Research, no code** ([docs/satellite-sources.md](docs/satellite-sources.md), MODULES-85): CelesTrak (grey), Space-Track (red for a package), the r/SpaceX API (archived, offline), Launch Library 2 (grey), Wikipedia and Wikidata
29
+ (green) for launches; the recommendation is a satellite view that takes elements the page supplies. John chooses before MODULES-86 and MODULES-87 start.
30
+
31
+ ### The family's published parts: demo, embed, docs and usage
32
+
33
+ Chikyu Earth now has what every package of the family has, and it was missing from 0.3.0 to 0.5.0.
34
+
35
+ - **Demo on GitHub Pages**, set as the repository's and the package's homepage: <https://johnmorrisdotca.github.io/chikyu-earth/>, with the family header (the kazoku-ui language picker, English and Japanese, and theme switch, the table cloths and the Help switch), light and dark, and the family footer. `pnpm site` builds it, and the Pages workflow publishes it on every push to `main`.
36
+ - **An embed page**, `embed.html`, for an `<iframe>` with no script of your own: `?look=line|thick|realistic`, `center`, `graticule`, `turn=0|1|auto`, `time`, `clouds`, `lights`. Still by default, no controls, no location prompt; it draws only when something changes and nothing while hidden. Tested in Chromium and WebKit, and on the realistic look: one WebGL context, canvas inside its budget, nothing drawn at rest.
37
+ - **A documentation site** at `/docs/`: a page for every export (from its TSDoc, with an example that is run when the site is built), ten guides in English and in Japanese, one language to a page, search, `llms.txt` and the family's header. Every export of every entry point has a summary, `@param`, `@returns` and an `@example` that imports the package by its name; `pnpm check` fails when one does not.
38
+ - **Every way to use it, written down and tested** (`pnpm test:usage`): a script tag from jsDelivr and from unpkg, the realistic Earth from a CDN, the shared controls, Vite, webpack, React (and a server render of it), Vue, Svelte, Angular, an iframe, TypeScript types and Node. Each example is built or run against the package as npm packs it, opened in a browser and made to show a globe; the guides and the README must hold the same text word for word.
39
+ - **`look` attribute**: `<chikyu-earth look="thick">` is the new name of `style`, which frameworks read as CSS (React refuses a string `style`). `style` still works.
40
+ - **Types for the tags**: `document.querySelector("chikyu-earth")` is a `ChikyuEarth` (and `"chikyu-earth-realistic"`, `"chikyu-space"`) once the element's entry is imported.
41
+ - **A freeze test in the release** (`e2e/freeze.demo.ts`, `pnpm test:freeze`): at rest nothing is drawn and no frame asked for, turning draws at most once for each frame of the page and asks for one frame at a time, out of sight or in a hidden tab nothing is drawn, the canvas stays inside 6 million pixels and 4096 a side on a 5K screen at a pixel ratio of 2 in the Earth from space and the space view, and six rounds of changing the look leave the GPU objects flat in one WebGL context and let the context go at the end. Every Chromium project draws WebGL in software, never on the machine's graphics card. The release workflow runs it (`freeze-command`, kazoku-ui 0.9.1).
42
+ - **The family's must-have list**, checked: `scripts/check-standard.mjs` (kazoku-ui's, unchanged) fails `pnpm check` when a package lacks its demo, embed page, docs site with Japanese twins, family files or tested usage.
43
+ - **Family files**: `family-template.mjs` and `family-readme.mjs` of 2026-11-02 with Chikyu Earth added to the family's list (33 packages), `family.css`, and the README's "The family" block. Added to the list here only; the other packages take the new files when they are next touched.
44
+
45
+ ## 0.5.0
46
+
47
+ The Earth from space, and markers for any place on either globe, both under a hard performance budget.
48
+
49
+ ### Markers
50
+
51
+ - **`attachMarkers(element)`** (`@johnmorrisdotca/chikyu-earth/markers`) puts your places on `<chikyu-earth>` or `<chikyu-earth-realistic>`: add, update and remove markers at `[lon, lat]` with a label, colour, icon and size; groups (cities, stadiums) shown or hidden together; markers that turn, zoom and pan with the globe and fade on the far side; crowded places gathered into clusters; labels that make room for each other; `chikyu-marker-hover`, `-click` and `-focus` events carrying your own `data`; a button for each shown label (Tab and Enter work) and a hidden list of every place for a screen reader. Chikyu ships no places; the demo shows 22 cities and 10 stadiums (Wikidata coordinates, CC0). [docs/markers.md](docs/markers.md).
52
+ - **Budget**, each line tested: all dots in one 2D canvas pass, and a pool of 24 label buttons, never an element per place; 5,000 markers cost 0.36 ms a view change on the flat globe; a 5,000-marker drag on the Earth from space made 117 draws in 4 s (29 a second), the markers drawn with them one for one and not at all at rest or out of sight; the overlay canvas holds the same 4096-a-side, 6 MP limit.
53
+ - The flat element's picture now sits in a holder beside the markers' overlay (a redraw replaces only the picture), and `lookAt` moves to `view.ts`.
54
+
55
+ ### The Earth from space
56
+
57
+ An optional realistic look, drawn with three.js through kazoku-ui's shared renderer.
58
+
59
+ - **`<chikyu-earth-realistic>`** (`@johnmorrisdotca/chikyu-earth/realistic/element`): day side from NASA's Blue Marble, the cities' lights on the night side, a cloud
60
+ layer that drifts with the date, a sun glint on the sea, an atmosphere at the rim, and the day and night line placed by the real Sun for a date and time (now by
61
+ default). The same shared controls (turn, tilt, zoom, pan) and the same `setView(view, final)` as the flat globe. `time`, `clouds`, `lights`, `center`,
62
+ `texture-base`, `max-texture` and `live-seconds` attributes; `chikyu-ready`, `chikyu-unavailable` and `chikyu-tier` events. [docs/realistic.md](docs/realistic.md).
63
+ - **The flat look stays**: `<chikyu-earth>` is unchanged (and gains a `centre` getter); the demo's Line, Thick and Realistic buttons choose between them, keep the
64
+ camera, and keep the choice, the graticule, the clouds, the lights and the time in the address (kazoku-ui's address state). Without WebGL the demo says so and
65
+ shows the line globe.
66
+ - **Optional, so the base install stays small**: `three` and `@johnmorrisdotca/kazoku-ui` are optional peer dependencies; the base entry and `<chikyu-earth>` need neither.
67
+ The realistic element, its Sun, its scene and its shaders, with kazoku-ui's renderer, are 22.6 KB minified (9.2 KB gzipped); three.js is the page's, and the demo's
68
+ subset of it (`demo/three-subset.ts`) is 188 KB gzipped. Sun position: `subsolarPoint(ms)` in `@johnmorrisdotca/chikyu-earth/realistic`, tested against the almanac
69
+ (declination within 0.05 degree, the equation of time in the longitude).
70
+ - **Pictures** (1.55 MB in `dist/textures/`, WebP, all NASA public domain, credited in NOTICE.md): day at 1024, 2048 and 4096; night, clouds and a water mask at 1024 and 2048.
71
+ The 1024 ones load first; a larger one loads when the zoom needs it (about 3 texels per pixel of the disc's radius), replaces the smaller, and is freed 4 s after the
72
+ zoom drops. No texture is wider than 4096 (2048 on a device with 2 GB or less); `pnpm textures` rebuilds them.
73
+ - **Performance, each proved by `e2e/realistic.gl.ts` (Chromium, software WebGL)**: 0 draw calls and 0 animation frames in 4 s at rest; a drag at 125 moves a second
74
+ draws 29.3 times a second, and 2,700 `setView` calls in 2 s make 59 draws; an Auto-turn at the Earth's rate draws 0 times in 6 s; one WebGL context; the canvas on a
75
+ 5K screen at ratio 2 is 3264 x 1835 = 5.99 MP; the textures alive grow one a layer with the zoom and return to the start after it; 0 draws and 0 frames while out of
76
+ sight or in a hidden tab; after removal 0 buffers, 0 programs and none of our textures remain, and the element can come back; a lost context draws nothing and then
77
+ recovers, not black; no WebGL gives `chikyu-unavailable`. The soak (10 minutes, 976 moves, 2,000 markers on): JS heap 7.29 to 7.80 MB after garbage collection, GPU objects 20 to 20, textures, buffers and programs the same as at the start, the draw rate 5.4 a second on average, one WebGL context, no error.
78
+ - `pnpm test:soak` (`SOAK_MINUTES`, 10 by default; CI runs 1) turns, zooms, re-times and toggles for that long and compares the heap, the GPU objects and the draw rate with the start.
79
+ - `pnpm screenshots` also makes the realistic pictures; `scripts/make-textures.py` makes the textures from NASA's sources.
80
+
3
81
  ## 0.4.0
4
82
 
5
83
  The outlines now come from chizu, the controls from kazoku-ui 0.9, and the release from the family's shared workflow.
package/NOTICE.md CHANGED
@@ -16,6 +16,44 @@ Each outline's English name, Japanese name and country code come from **chizu**'
16
16
  **kuni**'s (https://github.com/johnmorrisdotca/kuni, also by John Morris) and Unicode CLDR's
17
17
  (https://www.unicode.org/license.txt) and Wikidata's (CC0). chizu's own NOTICE.md has the terms.
18
18
 
19
+ ## The realistic Earth's pictures
20
+
21
+ The pictures in `textures/` (and `dist/textures/`) are made by `scripts/make-textures.py` from four NASA Earth Observatory images, resized and
22
+ re-encoded as WebP. NASA says its content "generally are not subject to copyright in the United States" and asks that "NASA should be acknowledged as the
23
+ source of the material" (https://www.nasa.gov/nasa-brand-center/images-and-media/, read 2026-11-02). These are NASA's own images, not third-party
24
+ material, so no other licence applies. This package is not endorsed by NASA and uses none of NASA's insignia or logotype.
25
+
26
+ | Picture | Source | Credit |
27
+ |---|---|---|
28
+ | `day-*.webp` | Blue Marble: Next Generation with topography and bathymetry, September 2004, 5400 x 2700 (https://eoimages.gsfc.nasa.gov/images/imagerecords/73000/73801/world.topo.bathy.200409.3x5400x2700.jpg, Visible Earth 73801) | NASA Earth Observatory (Reto Stöckli, Blue Marble Next Generation) |
29
+ | `water-*.webp` | made by `scripts/make-textures.py` from the day picture: where it is blue and dark | as above |
30
+ | `night-*.webp` | Earth at Night, Black Marble 2016 color map at 0.1 degree, 3600 x 1800 (https://eoimages.gsfc.nasa.gov/images/imagerecords/144000/144898/BlackMarble_2016_01deg.jpg, Visible Earth 144898) | NASA Earth Observatory, Suomi NPP VIIRS data (Miguel Roman, NASA's Goddard Space Flight Center) |
31
+ | `clouds-*.webp` | Blue Marble clouds, 2048 x 1024 (https://eoimages.gsfc.nasa.gov/images/imagerecords/57000/57747/cloud_combined_2048.jpg, Visible Earth 57747) | NASA Earth Observatory (Reto Stöckli) |
32
+
33
+ The credit names are NASA's usual lines for these series; the Visible Earth pages (now at science.nasa.gov/earth/earth-observatory) did not show a credit line in the
34
+ text read on 2026-11-02, so check them if you need the exact wording for print.
35
+
36
+ ## The Moon's picture
37
+
38
+ `moon-*.webp` is made by `scripts/make-textures.py` from NASA's Scientific Visualization Studio item 4720, "Moon: LROC colour mosaic" (https://svs.gsfc.nasa.gov/4720/,
39
+ `lroc_color_2k.jpg`), a natural-colour mosaic of the Lunar Reconnaissance Orbiter's wide-angle camera (Arizona State University and NASA/GSFC). NASA's page asks: "Please give credit for this
40
+ item to: NASA's Scientific Visualization Studio" (Visualizer Ernie Wright, USRA; Scientist Noah Petro, NASA/GSFC). Same NASA terms as above.
41
+
42
+ ## The planets' places
43
+
44
+ `<chikyu-space>` computes positions with **astronomy-engine** (https://github.com/cosinekitty/astronomy, MIT, copyright Don Cross), the page's own optional peer dependency: this package does not
45
+ bundle or ship it. The planets are drawn as plain colours, from no picture.
46
+
47
+ ## Sun position
48
+
49
+ `src/realistic/sun.ts` uses the low-precision solar position formulas of NOAA's solar calculator (https://gml.noaa.gov/grad/solcalc/, after Jean Meeus,
50
+ *Astronomical Algorithms*). Formulas are not copyrightable; the code is this package's own and MIT.
51
+
52
+ ## three.js
53
+
54
+ The realistic look draws with three.js (https://threejs.org, MIT, copyright the three.js authors), the page's own optional peer dependency; this package
55
+ does not bundle or ship it.
56
+
19
57
  ## Projection
20
58
 
21
59
  The orthographic projection, the spherical clipping and the SVG path generation are **d3-geo**
@@ -25,7 +63,7 @@ d3-geo is the package's projection dependency.
25
63
  ## Shared view controls
26
64
 
27
65
  The turn, tilt, zoom, pan and touch controls are **kazoku-ui** (https://github.com/johnmorrisdotca/kazoku-ui),
28
- also by John Morris, under the MIT licence. The package has no third-party dependencies of its own.
66
+ also by John Morris, under the MIT licence. Its shared 3D renderer draws the realistic Earth.
29
67
 
30
68
  ## Marks
31
69
 
package/README.md CHANGED
@@ -9,41 +9,143 @@ Country outlines in the same thin-line style as Hako Devices and Uchusen Rockets
9
9
  <img alt="TypeScript" src="https://img.shields.io/badge/types-TypeScript-3178c6">
10
10
  </p>
11
11
 
12
+ <p align="center"><a href="https://johnmorrisdotca.github.io/chikyu-earth/"><strong>Open the demo →</strong></a> · <a href="https://johnmorrisdotca.github.io/chikyu-earth/embed.html">Embed page</a> · <a href="https://johnmorrisdotca.github.io/chikyu-earth/docs/">Docs</a></p>
13
+
12
14
  <p align="center"><img alt="The line-drawn globe, Europe and Africa in view, with the shared control bar" src="docs/images/line-desk.png" width="640"></p>
13
15
 
14
- ## One minute
16
+ ## Install and use
15
17
 
16
18
  ```sh
17
19
  npm install @johnmorrisdotca/chikyu-earth
18
20
  ```
19
21
 
22
+ Or 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.
23
+
24
+ ### In a plain HTML page
25
+
26
+ One script tag from [jsDelivr](https://www.jsdelivr.com/package/npm/@johnmorrisdotca/chikyu-earth) and the tag. (From unpkg, with the realistic Earth, and pinning a version: [the CDN guide](docs/guides/html-and-cdn.md).)
27
+
20
28
  ```html
21
- <script type="module">
22
- import "@johnmorrisdotca/kazoku-ui/view-controls/define";
23
- import "@johnmorrisdotca/chikyu-earth/element";
24
- </script>
29
+ <!doctype html>
30
+ <html lang="en">
31
+ <head>
32
+ <meta charset="utf-8" />
33
+ <meta name="viewport" content="width=device-width, initial-scale=1" />
34
+ <title>Chikyu Earth from jsDelivr</title>
35
+ <script type="module" src="https://cdn.jsdelivr.net/npm/@johnmorrisdotca/chikyu-earth/element/+esm"></script>
36
+ </head>
37
+ <body>
38
+ <chikyu-earth center="139.7,35.7" look="thick" graticule size="320"></chikyu-earth>
39
+ </body>
40
+ </html>
41
+ ```
25
42
 
26
- <div id="globe" tabindex="0">
27
- <chikyu-earth size="420"></chikyu-earth>
28
- </div>
29
- <kazoku-view-controls id="controls" for="globe" address controls="advanced" tilt-max="90" speed="0.004178" autoplay></kazoku-view-controls>
43
+ The globe appears centred where you say; with no `center` it centres on the reader (the browser asks for their location; until they answer, and if they decline, it starts on the Greenwich meridian). `look` is `line` or `thick`.
44
+
45
+ ### With the shared controls
46
+
47
+ The [kazoku-ui](https://github.com/johnmorrisdotca/kazoku-ui) view controls turn, tip, zoom and pan it, and keep the view in the address. One listener passes their camera on:
48
+
49
+ ```html
50
+ <!doctype html>
51
+ <html lang="en">
52
+ <head>
53
+ <meta charset="utf-8" />
54
+ <meta name="viewport" content="width=device-width, initial-scale=1" />
55
+ <title>Chikyu Earth with the shared controls</title>
56
+ <script type="module">
57
+ import "https://cdn.jsdelivr.net/npm/@johnmorrisdotca/kazoku-ui/view-controls/define/+esm";
58
+ import "https://cdn.jsdelivr.net/npm/@johnmorrisdotca/chikyu-earth/element/+esm";
59
+
60
+ const earth = document.querySelector("chikyu-earth");
61
+ document.querySelector("kazoku-view-controls").addEventListener("kazoku-viewchange", (event) => {
62
+ earth.setView(event.detail, event.detail.final);
63
+ });
64
+ </script>
65
+ </head>
66
+ <body>
67
+ <div id="globe" tabindex="0">
68
+ <chikyu-earth size="420" look="thick" center="139.7,35.7"></chikyu-earth>
69
+ </div>
70
+ <kazoku-view-controls for="globe" address controls="advanced" tilt-max="90" speed="0.004178"></kazoku-view-controls>
71
+ </body>
72
+ </html>
73
+ ```
74
+
75
+ 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.
30
76
 
77
+ ### In React
78
+
79
+ 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](docs/guides/frameworks.md).)
80
+
81
+ ```tsx
82
+ import { useEffect, useRef } from "react";
83
+
84
+ export function ChikyuEarth({ center = "139.7,35.7", look = "thick" }: { center?: string; look?: "line" | "thick" }) {
85
+ const host = useRef<HTMLDivElement>(null);
86
+ useEffect(() => {
87
+ // The element needs a browser, so it is imported here, never at the top of the file: a server render never reaches an effect.
88
+ void import("@johnmorrisdotca/chikyu-earth/element");
89
+ }, []);
90
+ return (
91
+ <div ref={host}>
92
+ <chikyu-earth center={center} look={look} graticule />
93
+ </div>
94
+ );
95
+ }
96
+ ```
97
+
98
+ ### Every other way
99
+
100
+ | How | Where |
101
+ |---|---|
102
+ | A script tag from jsDelivr or unpkg, the realistic Earth from a CDN | [CDN guide](docs/guides/html-and-cdn.md) |
103
+ | An ES module in Vite or webpack | [bundlers guide](docs/guides/bundlers.md) |
104
+ | React, Vue, Svelte, Angular; Next.js, Nuxt, SvelteKit | [frameworks guide](docs/guides/frameworks.md) |
105
+ | An `<iframe>` of the embed page, no script of your own | [iframe guide](docs/guides/embed-in-an-iframe.md) |
106
+ | TypeScript types, an SVG string on a server, Node | [TypeScript and Node guide](docs/guides/typescript-and-node.md) |
107
+ | The web component (`<chikyu-earth>`, `<chikyu-earth-realistic>`) | every one of the above; its attributes are in [The element](#the-element) |
108
+ | Something does not appear | [troubleshooting](docs/guides/troubleshooting.md) |
109
+
110
+ The guides are also in Japanese (日本語), one language to a page: [docs/guides/ja/](docs/guides/ja/getting-started.md).
111
+
112
+ ## The Earth from space
113
+
114
+ 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
115
+ 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.
116
+
117
+ <p align="center"><img alt="The Earth from space: Asia and the Pacific by day, with clouds and the sun glint" src="docs/images/realistic-desk.png" width="560"></p>
118
+
119
+ ```html
31
120
  <script type="module">
32
- const earth = document.querySelector("chikyu-earth");
33
- document.getElementById("controls").addEventListener("kazoku-viewchange", (event) => {
34
- earth.setView(event.detail, event.detail.final);
35
- });
121
+ import "@johnmorrisdotca/chikyu-earth/realistic/element";
36
122
  </script>
123
+ <chikyu-earth-realistic center="139.7,35.7" time="2026-06-21T03:00Z" texture-base="/textures/"></chikyu-earth-realistic>
37
124
  ```
38
125
 
39
- The globe appears, centred on the reader (the browser asks for their location; until they answer, and if they
40
- decline, it starts on the Greenwich meridian). The shared control bar turns, tips, zooms and pans it. Auto-turn
41
- moves at the Earth's own rate: `0.004178` degrees a second, one sidereal day — 23 h 56 min 4.0905 s — per revolution.
126
+ 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,
127
+ at most 30 times a second while it does, in one WebGL context, with textures that grow as you zoom and are freed after. All of it, the budget and the tests:
128
+ [docs/realistic.md](docs/realistic.md).
42
129
 
43
- Centre it yourself instead:
130
+ ## The Sun, the Moon and the planets
44
131
 
45
- ```html
46
- <chikyu-earth center="139.7,35.7" style="thick" graticule></chikyu-earth>
132
+ `<chikyu-space>` (`@johnmorrisdotca/chikyu-earth/space/element`) places the Earth, the Moon, the Sun and the planets where they are at a date and time, with the Moon's phase and the Earth's day side
133
+ 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, and a zoom from the Earth to the solar system. Positions are
134
+ computed in the browser by astronomy-engine (MIT), nothing is fetched. [docs/space.md](docs/space.md).
135
+
136
+ <p align="center"><img alt="The solar system on 2 November 2026 in the compressed scale: orbits round the Sun, the planets named" src="docs/images/space-solar.png" width="420"></p>
137
+
138
+ ## Markers
139
+
140
+ 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
141
+ 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](docs/markers.md).
142
+
143
+ ```ts no-run
144
+ import "@johnmorrisdotca/chikyu-earth/element";
145
+ import { attachMarkers } from "@johnmorrisdotca/chikyu-earth/markers";
146
+
147
+ const markers = attachMarkers(document.querySelector("chikyu-earth")!);
148
+ markers.add({ id: "tokyo", lon: 139.69, lat: 35.69, label: "Tokyo", group: "Cities" });
47
149
  ```
48
150
 
49
151
  ## Controls
@@ -57,12 +159,14 @@ rotate or drag controls.
57
159
  <kazoku-view-controls id="controls" for="globe" address controls="advanced" tilt-max="90" speed="0.004178" autoplay></kazoku-view-controls>
58
160
  ```
59
161
 
60
- ```ts
162
+ ```ts no-run
163
+ import "@johnmorrisdotca/chikyu-earth/element";
61
164
  import "@johnmorrisdotca/kazoku-ui/view-controls/define";
165
+ import type { ViewChangeDetail } from "@johnmorrisdotca/kazoku-ui/view-controls/element";
62
166
 
63
- const earth = document.querySelector("chikyu-earth");
64
- document.getElementById("controls").addEventListener("kazoku-viewchange", (event) => {
65
- const { yaw, tilt, zoom, panX, panY, final } = event.detail;
167
+ const earth = document.querySelector("chikyu-earth")!;
168
+ document.getElementById("controls")!.addEventListener("kazoku-viewchange", (event) => {
169
+ const { yaw, tilt, zoom, panX, panY, final } = (event as CustomEvent<ViewChangeDetail>).detail;
66
170
  earth.setView({ yaw, tilt, zoom, panX, panY }, final);
67
171
  });
68
172
  ```
@@ -92,7 +196,7 @@ The rotation is the pair d3-geo's `rotate` takes: `[-longitude, -latitude]` cent
92
196
  | --- | --- | --- |
93
197
  | `size` | Width and height of the square SVG, in pixels. | `320` |
94
198
  | `center` | `"longitude,latitude"` to centre on. Wins over geolocation. | the reader's location, else `0,0` |
95
- | `style` | `line` or `thick`. | `line` |
199
+ | `look` | `line` or `thick`. (`style` is the older name for it: a framework reads `style` as CSS, so use `look` there.) | `line` |
96
200
  | `graticule` | Draw a light graticule under the countries. | off |
97
201
 
98
202
  `setView(view, final = true)` applies a shared controller's `{ yaw, tilt, zoom, panX, panY }`. Every call updates
@@ -117,6 +221,77 @@ countryList().find((c) => c.alpha2 === "JP"); // { name: "Japan", ja: "日本",
117
221
 
118
222
  To take newer outlines, update `@johnmorrisdotca/chizu`; there is no data file in this repository.
119
223
 
224
+ ## The name
225
+
226
+ Chikyu (地球, ちきゅう) is Japanese for the Earth.
227
+
228
+ ## The family
229
+
230
+ <!-- family:start (made by scripts/family-readme.mjs from scripts/family-template.mjs; change those, not this) -->
231
+ Chikyu Earth is one of thirty-three packages, each made for the same site, each at
232
+ [github.com/johnmorrisdotca](https://github.com/johnmorrisdotca) or [github.com/spxis](https://github.com/spxis). The code of every one is MIT.
233
+
234
+ **Games — board**
235
+
236
+ - [Domino](https://github.com/johnmorrisdotca/domino) (ドミノ): dominoes and Mexican Train. [Demo](https://johnmorrisdotca.github.io/domino/).
237
+ - [Gunjin](https://github.com/johnmorrisdotca/gunjin) (軍人): five hidden-rank strategy games with pass-the-device play. [Demo](https://johnmorrisdotca.github.io/gunjin/).
238
+ - [Narabe](https://github.com/johnmorrisdotca/narabe) (並べ): one rules engine for abstract board games, from gomoku and Reversi to Go and checkers. [Demo](https://johnmorrisdotca.github.io/narabe/).
239
+ - [Sugoroku](https://github.com/johnmorrisdotca/sugoroku) (双六): backgammon and its variants, with the doubling cube and match play. [Demo](https://johnmorrisdotca.github.io/sugoroku/).
240
+ - [Tenka](https://github.com/johnmorrisdotca/tenka) (天下): world conquest for two to six, on a map of the real world. [Demo](https://johnmorrisdotca.github.io/tenka/).
241
+
242
+ **Games — cards & tiles**
243
+
244
+ - [Hitotsu](https://github.com/johnmorrisdotca/hitotsu) (一つ): a colour-card shedding game for two to eight, with the house rules people play. [Demo](https://johnmorrisdotca.github.io/hitotsu/).
245
+ - [Jarajara](https://github.com/johnmorrisdotca/jarajara) (ジャラジャラ): mahjong tiles drawn as SVG, stacked layouts, and the matching solitaire Awase. [Demo](https://johnmorrisdotca.github.io/jarajara/).
246
+ - [Kumimoji](https://github.com/johnmorrisdotca/kumimoji) (組み文字): a crossword tile race, in English and Japanese kana. [Demo](https://johnmorrisdotca.github.io/kumimoji/).
247
+ - [Toranpu](https://github.com/johnmorrisdotca/toranpu) (トランプ): a deck of playing cards, card games with computer players, and solitaires. [Demo](https://johnmorrisdotca.github.io/toranpu/).
248
+
249
+ **Games — puzzles**
250
+
251
+ - [Houseki](https://github.com/johnmorrisdotca/houseki) (宝石): gem and stone matching puzzles: falling triplets, stone collapse, colour chains and gem swap. [Demo](https://johnmorrisdotca.github.io/houseki/).
252
+ - [Jirai](https://github.com/johnmorrisdotca/jirai) (地雷): minesweeper on shaped grids with verified no-guess boards. [Demo](https://johnmorrisdotca.github.io/jirai/).
253
+ - [Karakuri](https://github.com/johnmorrisdotca/karakuri) (からくり): eight hyper-casual puzzle games, some of them physics: draw a shield, pull pins, cut ropes, slide blocks, pour tubes. [Demo](https://johnmorrisdotca.github.io/karakuri/).
254
+ - [Kazu](https://github.com/johnmorrisdotca/kazu) (数): grid number puzzles: Sudoku and its variants, Futoshiki and Skyscrapers. [Demo](https://johnmorrisdotca.github.io/kazu/).
255
+ - [Kyuubu](https://github.com/johnmorrisdotca/kyuubu) (キューブ): a turning cube for the browser, 2×2 to 7×7, with record solves to replay. [Demo](https://johnmorrisdotca.github.io/kyuubu/).
256
+ - [Meikyuu](https://github.com/johnmorrisdotca/meikyuu) (迷宮): mazes on squares, hexagons, triangles and circles, made from a seed and drawn through with a finger or the mouse. [Demo](https://johnmorrisdotca.github.io/meikyuu/).
257
+ - [Suido](https://github.com/johnmorrisdotca/suido) (水道): a pipe puzzle: turn the pieces until the water reaches every drain. [Demo](https://johnmorrisdotca.github.io/suido/).
258
+ - [Tobiishi](https://github.com/johnmorrisdotca/tobiishi) (飛び石): peg solitaire with nine boards and seeded solvable challenges. [Demo](https://johnmorrisdotca.github.io/tobiishi/).
259
+ - [Tsunagi](https://github.com/johnmorrisdotca/tsunagi) (繋ぎ): a line-joining logic puzzle whose every level has exactly one answer. [Demo](https://johnmorrisdotca.github.io/tsunagi/).
260
+
261
+ **Games — dice & random**
262
+
263
+ - [Korokoro](https://github.com/johnmorrisdotca/korokoro) (コロコロ): dice, with notation, exact odds, real sounds and the dice of many games. [Demo](https://johnmorrisdotca.github.io/korokoro/).
264
+ - [Tane](https://github.com/johnmorrisdotca/tane) (種): seeded random numbers and daily seeds, the same in every browser and on every server. [Demo](https://johnmorrisdotca.github.io/tane/).
265
+
266
+ **Language**
267
+
268
+ - [Bushu](https://github.com/johnmorrisdotca/bushu) (部首): find a kanji by the parts it is made of. [Demo](https://johnmorrisdotca.github.io/bushu/).
269
+ - [Hikidashi](https://github.com/johnmorrisdotca/hikidashi) (引き出し): a drawer of small Japanese text tools: era dates, kanji numerals, readings and sentence difficulty. [Demo](https://johnmorrisdotca.github.io/hikidashi/).
270
+ - [Kotoba](https://github.com/johnmorrisdotca/kotoba) (言葉): word lists and word-game rules in English, French, German and Japanese. [Demo](https://johnmorrisdotca.github.io/kotoba/).
271
+
272
+ **Geography & data**
273
+
274
+ - [address-plus](https://github.com/johnmorrisdotca/address-plus) (アドレスプラス): parse and format addresses in the United States, Canada, Japan, Australia, France, Germany and the United Kingdom. [Demo](https://johnmorrisdotca.github.io/address-plus/).
275
+ - [Chikyu Earth](https://github.com/johnmorrisdotca/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](https://johnmorrisdotca.github.io/chikyu-earth/).
276
+ - [Chizu](https://github.com/johnmorrisdotca/chizu) (地図): maps of the world and of countries' regions, in English and Japanese, with a quiz and callouts. [Demo](https://johnmorrisdotca.github.io/chizu/).
277
+ - [Hata](https://github.com/johnmorrisdotca/hata) (旗): country and regional flags as SVG, at their true proportions and keyed by ISO code. [Demo](https://johnmorrisdotca.github.io/hata/).
278
+ - [Kuni](https://github.com/johnmorrisdotca/kuni) (国): countries and their regions, with ISO codes and names in English and Japanese. [Demo](https://johnmorrisdotca.github.io/kuni/).
279
+
280
+ **Sports**
281
+
282
+ - [Dougu Sports](https://github.com/johnmorrisdotca/dougu-sports) (道具): sports emblems as SVG: trophies, medals, crests, and the ball and gear of every sport, with optional 3D turning. [Demo](https://johnmorrisdotca.github.io/dougu-sports/).
283
+ - [Kyogijo Stadiums](https://github.com/johnmorrisdotca/kyogijo-stadiums) (競技場): sports fields, rinks, courts and ballparks drawn to scale as SVG, with each team and the score on them. [Demo](https://johnmorrisdotca.github.io/kyogijo-stadiums/).
284
+ - [Senshu Jerseys](https://github.com/johnmorrisdotca/senshu-jerseys) (選手): sports jerseys, sweaters, kits, caps, helmets and retired-number banners as SVG, front and back, with optional 2.5D turning. [Demo](https://johnmorrisdotca.github.io/senshu-jerseys/).
285
+ - [Taisen Brackets](https://github.com/johnmorrisdotca/taisen-brackets) (対戦): a sport-agnostic tournament bracket, drawn as SVG, from a list of ties. [Demo](https://johnmorrisdotca.github.io/taisen-brackets/).
286
+
287
+ **Developer tools**
288
+
289
+ - [REST in Pieces](https://github.com/spxis/rest-in-pieces) (レスト・イン・ピーシーズ): seeded test data and REST APIs for frontend development, with latency and error drills. [Demo](https://spxis.github.io/rest-in-pieces/).
290
+
291
+
292
+ **This package is Chikyu Earth.** The demos of all thirty-three share one header and footer, so each links the rest.
293
+ <!-- family:end -->
294
+
120
295
  ## The rest
121
296
 
122
297
  [CONTRIBUTING.md](CONTRIBUTING.md) · [docs/](docs/index.md) · [NOTICE.md](NOTICE.md) ·
@@ -1,3 +1,14 @@
1
1
  import type { FeatureCollection, Geometry } from "geojson";
2
2
  import type { CountryProps } from "./types.ts";
3
+ /**
4
+ * Every country the globe draws, as GeoJSON in longitude and latitude (177 features, Antarctica included), each with its English name, its Japanese name and its two-letter code.
5
+ *
6
+ * @example
7
+ * ```ts
8
+ * import { COUNTRIES } from "@johnmorrisdotca/chikyu-earth";
9
+ *
10
+ * const japan = COUNTRIES.features.find((feature) => feature.properties.alpha2 === "JP");
11
+ * console.log(japan?.properties.name, japan?.properties.ja, COUNTRIES.features.length);
12
+ * ```
13
+ */
3
14
  export declare const COUNTRIES: FeatureCollection<Geometry, CountryProps>;
package/dist/countries.js CHANGED
@@ -1,6 +1,17 @@
1
1
  // The country outlines: chizu's world-geo (Natural Earth 1:110m, WGS84 longitude and latitude) shaped for the globe.
2
2
  // Names are chizu's own English and Japanese; the alpha-2 code is its two-letter code, null for the three places with none.
3
3
  import WORLD_GEO from "@johnmorrisdotca/chizu/world-geo";
4
+ /**
5
+ * Every country the globe draws, as GeoJSON in longitude and latitude (177 features, Antarctica included), each with its English name, its Japanese name and its two-letter code.
6
+ *
7
+ * @example
8
+ * ```ts
9
+ * import { COUNTRIES } from "@johnmorrisdotca/chikyu-earth";
10
+ *
11
+ * const japan = COUNTRIES.features.find((feature) => feature.properties.alpha2 === "JP");
12
+ * console.log(japan?.properties.name, japan?.properties.ja, COUNTRIES.features.length);
13
+ * ```
14
+ */
4
15
  export const COUNTRIES = {
5
16
  type: "FeatureCollection",
6
17
  features: WORLD_GEO.features.map((feature) => ({
package/dist/element.d.ts CHANGED
@@ -1,7 +1,25 @@
1
- import type { GlobeView } from "./types.ts";
1
+ import type { OverlayHost } from "./markers/layer.ts";
2
+ import type { GeoPoint, GlobeView } from "./types.ts";
3
+ /**
4
+ * The `<chikyu-earth>` custom element: the line globe, drawn as SVG in its shadow root. Importing this entry point registers the tag once. It takes the attributes `size` (pixels, 320 by default), `center` (`"lon,lat"`; wins over the browser's location), `look` (`line` or `thick`; `style` is the older name for it, and a framework that reads `style` as CSS cannot use it) and `graticule`, and a shared view controller's camera through `setView`.
5
+ *
6
+ * @example
7
+ * ```ts no-run
8
+ * import type { ChikyuEarth } from "@johnmorrisdotca/chikyu-earth/element";
9
+ *
10
+ * const earth = document.createElement("chikyu-earth") as ChikyuEarth;
11
+ * earth.setAttribute("center", "139.7,35.7");
12
+ * earth.setAttribute("look", "thick");
13
+ * document.body.append(earth);
14
+ * ```
15
+ */
2
16
  export declare class ChikyuEarth extends HTMLElement {
3
17
  #private;
4
18
  static observedAttributes: string[];
19
+ /** Where the view is centred now: the `center` attribute, else the reader's place once the browser has answered. */
20
+ get centre(): GeoPoint;
21
+ /** A box laid over the globe for markers (see `@johnmorrisdotca/chikyu-earth/markers`): where it is, the pose of the last drawing, and a way to hear the next. */
22
+ get overlay(): OverlayHost;
5
23
  connectedCallback(): void;
6
24
  attributeChangedCallback(name: string, _old: string | null, value: string | null): void;
7
25
  /**
@@ -10,3 +28,8 @@ export declare class ChikyuEarth extends HTMLElement {
10
28
  */
11
29
  setView(view: GlobeView, final?: boolean): void;
12
30
  }
31
+ declare global {
32
+ interface HTMLElementTagNameMap {
33
+ "chikyu-earth": ChikyuEarth;
34
+ }
35
+ }
package/dist/element.js CHANGED
@@ -2,7 +2,7 @@
2
2
  // it opens centred on where you are (the `center` attribute wins over geolocation). Importing registers it once.
3
3
  import { globe } from "./globe.js";
4
4
  import { cleanStyle } from "./styles.js";
5
- import { HOME_VIEW } from "./view.js";
5
+ import { globeBaseScale, HOME_VIEW, lookAt } from "./view.js";
6
6
  const readCentre = (value) => {
7
7
  if (!value)
8
8
  return null;
@@ -13,11 +13,43 @@ const readCentre = (value) => {
13
13
  return null;
14
14
  return { lon, lat };
15
15
  };
16
+ /**
17
+ * The `<chikyu-earth>` custom element: the line globe, drawn as SVG in its shadow root. Importing this entry point registers the tag once. It takes the attributes `size` (pixels, 320 by default), `center` (`"lon,lat"`; wins over the browser's location), `look` (`line` or `thick`; `style` is the older name for it, and a framework that reads `style` as CSS cannot use it) and `graticule`, and a shared view controller's camera through `setView`.
18
+ *
19
+ * @example
20
+ * ```ts no-run
21
+ * import type { ChikyuEarth } from "@johnmorrisdotca/chikyu-earth/element";
22
+ *
23
+ * const earth = document.createElement("chikyu-earth") as ChikyuEarth;
24
+ * earth.setAttribute("center", "139.7,35.7");
25
+ * earth.setAttribute("look", "thick");
26
+ * document.body.append(earth);
27
+ * ```
28
+ */
16
29
  export class ChikyuEarth extends HTMLElement {
17
- static observedAttributes = ["center", "style", "size", "graticule"];
30
+ static observedAttributes = ["center", "look", "style", "size", "graticule"];
18
31
  #centre = { lon: 0, lat: 0 };
19
32
  #view = { ...HOME_VIEW };
20
33
  #drawn = { ...HOME_VIEW };
34
+ #listeners = new Set();
35
+ #overlay;
36
+ #pose = null;
37
+ /** Where the view is centred now: the `center` attribute, else the reader's place once the browser has answered. */
38
+ get centre() {
39
+ return { ...this.#centre };
40
+ }
41
+ /** A box laid over the globe for markers (see `@johnmorrisdotca/chikyu-earth/markers`): where it is, the pose of the last drawing, and a way to hear the next. */
42
+ get overlay() {
43
+ this.#ensureShell();
44
+ return {
45
+ overlayRoot: this.#overlay,
46
+ pose: this.#pose,
47
+ subscribe: (listener) => {
48
+ this.#listeners.add(listener);
49
+ return () => this.#listeners.delete(listener);
50
+ },
51
+ };
52
+ }
21
53
  connectedCallback() {
22
54
  this.#centre = readCentre(this.getAttribute("center")) ?? { lon: 0, lat: 0 };
23
55
  this.#render();
@@ -59,14 +91,47 @@ export class ChikyuEarth extends HTMLElement {
59
91
  const y = this.#view.panY - this.#drawn.panY;
60
92
  svg.style.transformOrigin = "50% 50%";
61
93
  svg.style.transform = zoom === 1 && x === 0 && y === 0 ? "" : `translate(${x}px, ${y}px) scale(${zoom})`;
94
+ this.#publish(svg.style.transform);
95
+ }
96
+ /** The shell: the picture's holder and the overlay for markers, made once; a redraw replaces only the picture. */
97
+ #ensureShell() {
98
+ const root = this.shadowRoot ?? this.attachShadow({ mode: "open" });
99
+ if (!this.#overlay || !root.contains(this.#overlay)) {
100
+ root.innerHTML = `<style>:host{display:block;position:relative}.holder svg{display:block;width:100%;height:auto}.overlay{position:absolute;inset:0;pointer-events:none;transform-origin:50% 50%}</style><div class="holder"></div><div class="overlay"></div>`;
101
+ this.#overlay = root.querySelector(".overlay");
102
+ }
103
+ return root;
104
+ }
105
+ #publish(transform) {
106
+ if (this.#listeners.size === 0) {
107
+ this.#pose = null;
108
+ return;
109
+ }
110
+ const size = Number(this.getAttribute("size")) || 320;
111
+ const k = (this.clientWidth || size) / size;
112
+ const look = lookAt(this.#centre, this.#drawn);
113
+ const pose = {
114
+ lon: look.lon,
115
+ lat: look.lat,
116
+ radius: globeBaseScale(size) * this.#drawn.zoom * k,
117
+ cx: (size / 2 + this.#drawn.panX) * k,
118
+ cy: (size / 2 + this.#drawn.panY) * k,
119
+ width: size * k,
120
+ height: size * k,
121
+ transform,
122
+ };
123
+ this.#pose = pose;
124
+ for (const listener of this.#listeners)
125
+ listener(pose);
62
126
  }
63
127
  #render() {
64
128
  const size = Number(this.getAttribute("size")) || 320;
65
- const style = cleanStyle(this.getAttribute("style"));
129
+ const style = cleanStyle(this.getAttribute("look") ?? this.getAttribute("style"));
66
130
  const svg = globe({ size, style, centre: this.#centre, view: this.#view, graticule: this.hasAttribute("graticule") });
67
- const root = this.shadowRoot ?? this.attachShadow({ mode: "open" });
68
- root.innerHTML = `<style>:host{display:block}svg{display:block;width:100%;height:auto}</style>${svg}`;
131
+ const root = this.#ensureShell();
132
+ root.querySelector(".holder").innerHTML = svg;
69
133
  this.#drawn = { ...this.#view };
134
+ this.#publish("");
70
135
  }
71
136
  }
72
137
  if (typeof customElements !== "undefined" && !customElements.get("chikyu-earth")) {
package/dist/globe.d.ts CHANGED
@@ -1,3 +1,17 @@
1
1
  import type { GlobeOptions } from "./types.ts";
2
- /** The globe as an SVG string, turned to `rotation` and drawn in `style`, `size` pixels square. */
2
+ /**
3
+ * The globe as an SVG string, turned to `rotation` and drawn in `style`, `size` pixels square. It is pure: the same options always give the same markup, so it runs on a server, in a test or in a build step with no DOM.
4
+ *
5
+ * @param options - Size, turn, look and graticule; every one has a default, so `globe()` draws a 320-pixel globe facing the Greenwich meridian.
6
+ * @returns One `<svg>` element as text, with the country outlines as paths.
7
+ *
8
+ * @example
9
+ * ```ts
10
+ * import { globe } from "@johnmorrisdotca/chikyu-earth";
11
+ *
12
+ * const svg = globe({ size: 240, rotation: [-139.7, -35.7], style: "line" });
13
+ * console.log(svg.slice(0, 60));
14
+ * console.log(svg.length > 10_000);
15
+ * ```
16
+ */
3
17
  export declare function globe(options?: GlobeOptions): string;