@johnmorrisdotca/wakusei-planets 0.5.1 → 0.6.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.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,17 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.6.0 - 2026-11-03
4
+
5
+ The demo's pickers, and a scale that is a scale.
6
+
7
+ - **A compact picker** (MODULES-285): the ten bodies in one row, and when the one chosen has moons, its moons on the row below, in the same place; no long list down the page. The moons' own section is gone. Every picture in it is a picture, in the line, the realistic and the painted look: a test looks at all 35 (10 bodies and 25 moons) for blank and single-colour pictures. (The broken thumbnails of 0.3.0 were the tiles being drawn to scale, which 0.3.1 stopped.) The same picker is in "Put it in your page" (MODULES-286), so the body for the code is chosen beside the code; Copy's word can be read (it was ink on ink).
8
+ - **The buttons under the view stay where they are** (MODULES-283): one push button for each body of the system (the planet and its moons), the chosen one pressed, and others pressed with it to see them side by side under the view, at equal sizes or at their true relative sizes (`span-km`), kept in the address (`?with=phobos,deimos&rel=1`). The orbit-distance layout is not made yet.
9
+ - **To scale says what it is against** (MODULES-284): "Its planet" (for a moon), "Earth" or "Sun", and draws it so: Deimos is 0.0018 times Mars's radius, a magnified picture beside it with a line, the caption says so. `?scale=1&ref=planet`.
10
+ - **Deimos is drawn whole** (MODULES-287): an irregular body reaches past its mean radius along its longest axis, and its picture was cut off at the sides.
11
+ - **Every body is fitted by its globe** (MODULES-293): at about half the view's height, the same for all, so Saturn's rings, the Sun's glow and a haze have room, and the Sun is no smaller than a planet. `fit="tight"` on an element gives the old fit (thumbnails).
12
+ - **The sky shows the real phase** (MODULES-294): in "As seen from Earth" the night side is dark (no wrapped terminator, no rim of air round it), so Venus a few days from new is a thin crescent, not a full disc.
13
+ - **A line under every choice** (MODULES-298) says what it does, in English and Japanese, always on the page and tied to its button with `aria-describedby`.
14
+
3
15
  ## 0.5.1 - 2026-11-03
4
16
 
5
17
  - kazoku-ui 0.12.0: the demo's view controls have a zoom slider, on top of 0.11's Centre button and exact grab.
package/README.md CHANGED
@@ -13,9 +13,9 @@ A clean line drawing, a shaded realistic drawing, or a painted surface map, with
13
13
 
14
14
  <p align="center"><a href="https://johnmorrisdotca.github.io/wakusei-planets/"><strong>Open the demo →</strong></a> · <a href="https://johnmorrisdotca.github.io/wakusei-planets/embed.html">Embed page</a> · <a href="https://johnmorrisdotca.github.io/wakusei-planets/docs/">Docs</a></p>
15
15
 
16
- <p align="center"><img alt="Jupiter and Saturn drawn in the realistic look, and Saturn as a line drawing" src="https://raw.githubusercontent.com/johnmorrisdotca/wakusei-planets/v0.5.1/docs/images/hero-desk.png" width="640"></p>
16
+ <p align="center"><img alt="Jupiter and Saturn drawn in the realistic look, and Saturn as a line drawing" src="https://raw.githubusercontent.com/johnmorrisdotca/wakusei-planets/v0.6.0/docs/images/hero-desk.png" width="640"></p>
17
17
 
18
- <p align="center"><img alt="Every body at one scale, the Earth among them: each small body has a magnified picture joined by a line, and the Sun shows only its edge" src="https://raw.githubusercontent.com/johnmorrisdotca/wakusei-planets/v0.5.1/docs/images/lineup-desk.png" width="640"></p>
18
+ <p align="center"><img alt="Every body at one scale, the Earth among them: each small body has a magnified picture joined by a line, and the Sun shows only its edge" src="https://raw.githubusercontent.com/johnmorrisdotca/wakusei-planets/v0.6.0/docs/images/lineup-desk.png" width="640"></p>
19
19
 
20
20
  ## One minute
21
21
 
package/dist/element.d.ts CHANGED
@@ -25,7 +25,7 @@ export type WakuseiState = "line" | "loading" | "still" | "live" | "lost" | "una
25
25
  * console.log(TEXTURE_BASE);
26
26
  * ```
27
27
  */
28
- export declare const TEXTURE_BASE = "https://cdn.jsdelivr.net/npm/@johnmorrisdotca/wakusei-planets@0.5.1/dist/textures/";
28
+ export declare const TEXTURE_BASE = "https://cdn.jsdelivr.net/npm/@johnmorrisdotca/wakusei-planets@0.6.0/dist/textures/";
29
29
  /**
30
30
  * Where the sharpest surface pictures are: the files of this exact version in the repository, on jsDelivr's GitHub address. The npm package holds only the two smaller widths, so a page that
31
31
  * never zooms in never fetches them. Set `texture-far-base` on an element to serve them yourself.
@@ -37,7 +37,7 @@ export declare const TEXTURE_BASE = "https://cdn.jsdelivr.net/npm/@johnmorrisdot
37
37
  * console.log(TEXTURE_FAR_BASE);
38
38
  * ```
39
39
  */
40
- export declare const TEXTURE_FAR_BASE = "https://cdn.jsdelivr.net/gh/johnmorrisdotca/wakusei-planets@v0.5.1/textures/";
40
+ export declare const TEXTURE_FAR_BASE = "https://cdn.jsdelivr.net/gh/johnmorrisdotca/wakusei-planets@v0.6.0/textures/";
41
41
  /**
42
42
  * The `<wakusei-body>` custom element: a body of the solar system, drawn in a look.
43
43
  *
package/dist/element.js CHANGED
@@ -48,6 +48,8 @@ const readTime = (value) => {
48
48
  return Number.isFinite(ms) ? ms : undefined;
49
49
  };
50
50
  /** The half-width of the picture, in body radii, for a body alone, with a scale to another body, or with its moons. */
51
+ /** The half-width of a body's picture, in its radii, when it has no scale of its own: the globe takes a little under half the height, so its rings, glow and haze have room round it. */
52
+ const ROOM = 2.2;
51
53
  function extentOf(id, options) {
52
54
  const f = BODIES[id];
53
55
  if (options.moons === true && id in BODIES && f.parent === undefined && id !== "sun") {
@@ -59,7 +61,11 @@ function extentOf(id, options) {
59
61
  return options.spanKm / f.radiusKm;
60
62
  if (options.scaleTo !== undefined)
61
63
  return (BODIES[options.scaleTo].radiusKm * 1.06) / f.radiusKm;
62
- return Math.max(id === "sun" ? 1.55 : 1.06, ringReach(f) * 1.04);
64
+ if (options.tight !== true)
65
+ return ROOM;
66
+ // tight (a thumbnail): the picture holds the body and its rings, and an irregular body (Deimos, Phobos, Nix, Hydra) whole along its longest axis
67
+ const longest = f.axesKm === undefined ? 1 : Math.max(...f.axesKm) / f.radiusKm;
68
+ return Math.max(1.06, ringReach(f) * 1.04, longest * 1.06);
63
69
  }
64
70
  /** Keep the body in the picture: at least a quarter of its width stays inside the edge, however far the view is moved. `pan` is in half-widths of the picture. */
65
71
  function clampPan(pan, extent, zoom) {
@@ -91,7 +97,7 @@ const TEMPLATE = `<style>
91
97
  * ```
92
98
  */
93
99
  export class WakuseiBody extends HTMLElement {
94
- static observedAttributes = ["body", "look", "size", "time", "tilt", "pitch", "phase", "meridian", "turn", "rate", "moons", "range", "scale-to", "span-km", "live", "texture-base", "texture-far-base", "lang", "labels"];
100
+ static observedAttributes = ["body", "look", "size", "time", "tilt", "pitch", "phase", "meridian", "turn", "rate", "moons", "range", "scale-to", "span-km", "fit", "live", "texture-base", "texture-far-base", "lang", "labels"];
95
101
  #stage;
96
102
  #state = "line";
97
103
  #renderer;
@@ -293,7 +299,7 @@ export class WakuseiBody extends HTMLElement {
293
299
  const scaleTo = this.getAttribute("scale-to");
294
300
  const range = this.hasAttribute("range") ? num(this.getAttribute("range"), 0) : undefined;
295
301
  const span = num(this.getAttribute("span-km"), 0);
296
- const extent = extentOf(this.body, { ...(span > 0 ? { spanKm: span } : {}), ...(scaleTo !== null && scaleTo in BODIES ? { scaleTo } : {}), moons: r.moons, ...(range !== undefined && range > 0 ? { range } : {}) });
302
+ const extent = extentOf(this.body, { ...(this.getAttribute("fit") === "tight" ? { tight: true } : {}), ...(span > 0 ? { spanKm: span } : {}), ...(scaleTo !== null && scaleTo in BODIES ? { scaleTo } : {}), moons: r.moons, ...(range !== undefined && range > 0 ? { range } : {}) });
297
303
  const moons = r.moons
298
304
  ? frame.moons
299
305
  .filter((m) => m.distance <= extent * 1.05)
@@ -303,7 +309,7 @@ export class WakuseiBody extends HTMLElement {
303
309
  return { id: m.id, x: rotated[0], y: rotated[1], z: rotated[2], ...(orbit !== undefined ? { orbit: tiltBy === 0 ? orbit : this.#tiltedOrbit(m.id, orbit, tiltBy) } : {}) };
304
310
  })
305
311
  : undefined;
306
- return { pose: { pole, meridian, light }, extent, zoom: this.#zoom, panX: clampPan(this.#panX, extent, this.#zoom), panY: clampPan(this.#panY, extent, this.#zoom), ...(moons !== undefined ? { moons } : {}) };
312
+ return { pose: { pole, meridian, light }, extent, sky: frame.time !== undefined, zoom: this.#zoom, panX: clampPan(this.#panX, extent, this.#zoom), panY: clampPan(this.#panY, extent, this.#zoom), ...(moons !== undefined ? { moons } : {}) };
307
313
  }
308
314
  #tilted = new Map();
309
315
  #tiltedOrbit(id, orbit, tilt) {
@@ -442,7 +448,7 @@ export class WakuseiBody extends HTMLElement {
442
448
  size,
443
449
  pose: scene.pose,
444
450
  ...(r.moons ? { moons: true, ...(frame.time !== undefined ? { time: frame.time } : {}), range: scene.extent, moonsAt: (scene.moons ?? []).map((m) => ({ id: m.id, x: m.x, y: m.y, z: m.z, distance: Math.hypot(m.x, m.y, m.z) })), orbits: new Map((scene.moons ?? []).filter((m) => m.orbit !== undefined).map((m) => [m.id, m.orbit])) } : {}),
445
- ...(scaleTo !== null || this.hasAttribute("span-km") ? { fill: this.#fill() } : {}),
451
+ ...(scaleTo !== null || this.hasAttribute("span-km") || this.getAttribute("fit") !== "tight" ? { fill: this.#fill() } : {}),
446
452
  ...(this.getAttribute("lang") === "ja" ? { lang: "ja" } : {}),
447
453
  ...(this.getAttribute("labels") === "off" ? { labels: false } : {}),
448
454
  ...(stroke !== "" ? { stroke } : {}),
@@ -532,7 +538,7 @@ export class WakuseiBody extends HTMLElement {
532
538
  const scaleTo = this.getAttribute("scale-to");
533
539
  const span = num(this.getAttribute("span-km"), 0);
534
540
  const half = span > 0 ? span : scaleTo !== null && scaleTo in BODIES ? BODIES[scaleTo].radiusKm * 1.06 : 0;
535
- return half > 0 ? Math.max(0.01, Math.min(1, BODIES[this.body].radiusKm / half)) : 1;
541
+ return half > 0 ? Math.max(0.01, Math.min(1, BODIES[this.body].radiusKm / half)) : this.getAttribute("fit") === "tight" ? 1 : 1 / ROOM;
536
542
  }
537
543
  /** Make the view's still, once, when it is in sight. */
538
544
  #still() {
package/dist/line.js CHANGED
@@ -227,7 +227,7 @@ export function lineSvg(id, options = {}) {
227
227
  if (options.moons === true && facts.parent === undefined && id !== "sun")
228
228
  return systemSvg(id, options, size, stroke, paper, hair, head);
229
229
  const pose = poseFor(id, options);
230
- const reach = Math.max(ringReach(facts), id === "sun" ? 1.26 : 1);
230
+ const reach = Math.max(ringReach(facts), id === "sun" ? 1.08 : 1);
231
231
  const fit = options.fill === undefined ? 0.94 / reach : options.fill;
232
232
  const zoom = options.zoom ?? 1;
233
233
  const frame = { cx: (size / 2) * (1 - (options.panX ?? 0)), cy: (size / 2) * (1 + (options.panY ?? 0)), r: (size / 2) * fit * zoom };
@@ -23,6 +23,8 @@ export interface SceneState {
23
23
  panX: number;
24
24
  panY: number;
25
25
  moons?: readonly MoonDraw[];
26
+ /** The body is drawn as the sky shows it at a date: its real phase, with no light on the night side from a wrapped terminator or a rim of air. */
27
+ sky?: boolean;
26
28
  /** The smallest a moon is drawn, in CSS pixels across its radius. Default 2.5. */
27
29
  minMoonPx?: number;
28
30
  /** The colour of the orbit lines, `#rrggbb`. */
@@ -23,6 +23,7 @@ function makeBodyMaterial(T, look, painted) {
23
23
  uWrap: { value: look.wrap ?? (a === undefined ? 0.04 : 0.3) },
24
24
  uAtmos: { value: col3(T, a?.colour ?? [0, 0, 0]) },
25
25
  uAtmosPow: { value: a?.power ?? 3 },
26
+ uRimBase: { value: 0.12 },
26
27
  uEmissive: { value: look.emissive === true ? 1 : 0 },
27
28
  uRingN: { value: new T.Vector3(0, 1, 0) },
28
29
  uRingR: { value: new T.Vector2(1, 2) },
@@ -56,6 +57,8 @@ export function createBodyItem(options) {
56
57
  const geometry = assets.acquire("wk:sphere", () => new T.SphereGeometry(1, 128, 64), (g) => g.dispose());
57
58
  const shader = assets.acquire(`wk:body:${options.id}:r`, () => makeBodyMaterial(T, look, false), (m) => m.dispose());
58
59
  const paintedMaterial = wantPainted ? assets.acquire(`wk:body:${options.id}:p`, () => makeBodyMaterial(T, look, true), (m) => m.dispose()) : undefined;
60
+ const baseWrap = look.wrap ?? (look.atmosphere === undefined ? 0.04 : 0.3);
61
+ const baseAmbient = look.ambient ?? 0.04;
59
62
  const scene = new T.Scene();
60
63
  const camera = new T.OrthographicCamera(-1, 1, 1, -1, 0.1, 400);
61
64
  camera.position.set(0, 0, 200);
@@ -279,8 +282,15 @@ export function createBodyItem(options) {
279
282
  mat.uniforms.uRingTex.value = ringTexture;
280
283
  }
281
284
  }
282
- for (const mat of [shader, paintedMaterial])
283
- mat?.uniforms.uLight.value.copy(v3(T, state.pose.light));
285
+ for (const mat of [shader, paintedMaterial]) {
286
+ if (mat === undefined)
287
+ continue;
288
+ mat.uniforms.uLight.value.copy(v3(T, state.pose.light));
289
+ const sky = state.sky === true;
290
+ mat.uniforms.uWrap.value = sky ? 0.02 : (mat === paintedMaterial ? baseWrap : baseWrap);
291
+ mat.uniforms.uAmbient.value = sky ? 0.012 : baseAmbient;
292
+ mat.uniforms.uRimBase.value = sky ? 0.02 : 0.12;
293
+ }
284
294
  if (glow !== undefined)
285
295
  glow.scale.setScalar(1);
286
296
  // a sharper picture, when the disc is big enough to show it
@@ -61,6 +61,7 @@ uniform float uLimb;
61
61
  uniform float uWrap;
62
62
  uniform vec3 uAtmos;
63
63
  uniform float uAtmosPow;
64
+ uniform float uRimBase;
64
65
  uniform float uEmissive;
65
66
  uniform vec3 uRingN;
66
67
  uniform vec2 uRingR;
@@ -106,7 +107,7 @@ void main() {
106
107
  vec3 alb = pow(s.rgb, vec3(2.2));
107
108
  vec3 lit = alb * (uAmbient + (1.0 - uAmbient) * diff * 1.18);
108
109
  float rim = pow(1.0 - mu, uAtmosPow);
109
- lit += pow(uAtmos, vec3(2.2)) * rim * (0.12 + 0.88 * clamp(dg * 1.6 + 0.35, 0.0, 1.0));
110
+ lit += pow(uAtmos, vec3(2.2)) * rim * (uRimBase + (1.0 - uRimBase) * clamp(dg * 1.6 + 0.35, 0.0, 1.0));
110
111
  lit *= mix(1.0, pow(mu, 0.45), uLimb);
111
112
  gl_FragColor = vec4(pow(lit, vec3(1.0 / 2.2)), 1.0);
112
113
  }`;
@@ -87,6 +87,7 @@ function paint(T, id, context, bases) {
87
87
  uWrap: { value: look.wrap ?? (a === undefined ? 0.04 : 0.3) },
88
88
  uAtmos: { value: new T.Vector3(...(a?.colour ?? [0, 0, 0])) },
89
89
  uAtmosPow: { value: a?.power ?? 3 },
90
+ uRimBase: { value: 0.12 },
90
91
  uEmissive: { value: look.emissive === true ? 1 : 0 },
91
92
  uRingN: { value: new T.Vector3(0, 1, 0) },
92
93
  uRingR: { value: new T.Vector2(1, 2) },
package/dist/version.d.ts CHANGED
@@ -1 +1 @@
1
- export declare const VERSION = "0.5.1";
1
+ export declare const VERSION = "0.6.0";
package/dist/version.js CHANGED
@@ -1 +1 @@
1
- export const VERSION = "0.5.1";
1
+ export const VERSION = "0.6.0";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@johnmorrisdotca/wakusei-planets",
3
- "version": "0.5.1",
3
+ "version": "0.6.0",
4
4
  "description": "Wakusei Planets 惑星 — The Sun, planets and moons for the web: each as a clean line drawing, a shaded realistic drawing or a painted surface map, with real sizes, axial tilt and rotation as data, and positions of the moons for any date and time. SVG for the lines, three.js (optional) for the rest.",
5
5
  "keywords": [
6
6
  "planets",