@johnmorrisdotca/wakusei-planets 0.6.0 → 0.11.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 (58) hide show
  1. package/CHANGELOG.md +49 -0
  2. package/NOTICE.md +16 -1
  3. package/README.md +19 -4
  4. package/dist/bodies/all.d.ts +2 -0
  5. package/dist/bodies/all.js +2 -0
  6. package/dist/bodies/dwarfs.d.ts +1 -0
  7. package/dist/bodies/dwarfs.js +31 -0
  8. package/dist/bodies/moons-dwarf.d.ts +1 -0
  9. package/dist/bodies/moons-dwarf.js +6 -0
  10. package/dist/bodies/moons-neptune.js +1 -0
  11. package/dist/bodies/moons-pluto.js +1 -1
  12. package/dist/bodies/moons-saturn.js +3 -2
  13. package/dist/data/dwarf.d.ts +16 -0
  14. package/dist/data/dwarf.js +24 -0
  15. package/dist/data/orbits.d.ts +2 -2
  16. package/dist/data/orbits.js +4 -0
  17. package/dist/element.d.ts +4 -2
  18. package/dist/element.js +4 -0
  19. package/dist/embed.d.ts +35 -1
  20. package/dist/embed.js +78 -37
  21. package/dist/ephemeris.d.ts +6 -6
  22. package/dist/ephemeris.js +33 -12
  23. package/dist/facts.d.ts +44 -6
  24. package/dist/facts.js +32 -3
  25. package/dist/index.d.ts +3 -2
  26. package/dist/index.js +3 -2
  27. package/dist/line.js +7 -4
  28. package/dist/portrait/element.d.ts +77 -0
  29. package/dist/portrait/element.js +545 -0
  30. package/dist/portrait/model.d.ts +297 -0
  31. package/dist/portrait/model.js +711 -0
  32. package/dist/portrait/overlay.d.ts +50 -0
  33. package/dist/portrait/overlay.js +173 -0
  34. package/dist/portrait/pose.d.ts +13 -0
  35. package/dist/portrait/pose.js +31 -0
  36. package/dist/portrait/scene3d.d.ts +38 -0
  37. package/dist/portrait/scene3d.js +123 -0
  38. package/dist/pose.d.ts +7 -5
  39. package/dist/pose.js +25 -11
  40. package/dist/scene/body.d.ts +1 -1
  41. package/dist/scene/glsl.js +10 -1
  42. package/dist/scene/painter.d.ts +7 -0
  43. package/dist/scene/painter.js +9 -1
  44. package/dist/textures/ceres-1024.webp +0 -0
  45. package/dist/textures/ceres-512.webp +0 -0
  46. package/dist/textures/charon-1024.webp +0 -0
  47. package/dist/textures/charon-512.webp +0 -0
  48. package/dist/textures/dione-1024.webp +0 -0
  49. package/dist/textures/dione-512.webp +0 -0
  50. package/dist/textures/iapetus-1024.webp +0 -0
  51. package/dist/textures/iapetus-512.webp +0 -0
  52. package/dist/textures/tethys-1024.webp +0 -0
  53. package/dist/textures/tethys-512.webp +0 -0
  54. package/dist/textures/triton-1024.webp +0 -0
  55. package/dist/textures/triton-512.webp +0 -0
  56. package/dist/version.d.ts +1 -1
  57. package/dist/version.js +1 -1
  58. package/package.json +18 -1
@@ -0,0 +1,297 @@
1
+ import { type BodyId, type Look } from "../facts.ts";
2
+ /** How the automatic layout arranges the bodies. */
3
+ export type Arrange = "row" | "arc" | "grid" | "orbit";
4
+ /** `true`: every size to scale. `readable`: sizes squeezed together so a small body can still be seen. */
5
+ export type ScaleMode = "true" | "readable";
6
+ export type Background = "black" | "stars" | "gradient" | "transparent";
7
+ /**
8
+ * One body in the scene: which body, where it is and how big, how it is turned and how fast it turns by itself.
9
+ *
10
+ * @example
11
+ * ```ts
12
+ * import { addBody, defaultPortrait, type PortraitItem } from "@johnmorrisdotca/wakusei-planets";
13
+ *
14
+ * const saturn: PortraitItem = addBody(defaultPortrait(), "saturn").items[0]!;
15
+ * console.log(saturn.body, saturn.turn);
16
+ * ```
17
+ */
18
+ export interface Item {
19
+ body: BodyId;
20
+ x: number;
21
+ y: number;
22
+ /** The radius, in scene units. */
23
+ r: number;
24
+ /** The longitude at the middle of the disc, degrees east (with a date: turned this much from the real one). */
25
+ spin: number;
26
+ /** The pole's lean on the page, degrees; the body's own tilt when left out. */
27
+ tilt?: number;
28
+ /** How far the viewer looks over the pole, degrees; the usual for the body when left out. */
29
+ pitch?: number;
30
+ /** Degrees a second it turns by itself, eastward. */
31
+ turn: number;
32
+ }
33
+ /**
34
+ * A portrait scene: the bodies, back to front, and how they are arranged, sized, lit and drawn. Plain data: keep it, change it by making a new one, and `encodeScene` it for an address.
35
+ *
36
+ * @example
37
+ * ```ts
38
+ * import { addBody, defaultPortrait, type Portrait } from "@johnmorrisdotca/wakusei-planets";
39
+ *
40
+ * const scene: Portrait = addBody(addBody(defaultPortrait(), "jupiter"), "io");
41
+ * console.log(scene.items.length, scene.layout, scene.scale);
42
+ * ```
43
+ */
44
+ export interface Portrait {
45
+ /** Back to front. */
46
+ items: Item[];
47
+ /** `auto`: the layout places and sizes every body. `manual`: the positions and sizes below are used as they are. */
48
+ layout: "auto" | "manual";
49
+ arrange: Arrange;
50
+ scale: ScaleMode;
51
+ /** `auto`: a planet's moons that are in the scene go round it in orbit order. `manual`: each body is placed by itself. */
52
+ moons: "auto" | "manual";
53
+ look: Look;
54
+ bg: Background;
55
+ /** Width over height. */
56
+ aspect: number;
57
+ /** Where the Sun is: `az` clockwise from the top of the picture, `el` toward the viewer (0 along the page, 90 straight at it), degrees. */
58
+ light: {
59
+ az: number;
60
+ el: number;
61
+ };
62
+ labels: boolean;
63
+ orbits: boolean;
64
+ shadows: boolean;
65
+ /** The body as the Earth sees it on this date (ISO), or `undefined` for a portrait. */
66
+ date: string | undefined;
67
+ /** The view in a manual layout: the centre and the half-height, in scene units. An automatic layout always fits. */
68
+ camera: {
69
+ x: number;
70
+ y: number;
71
+ h: number;
72
+ };
73
+ }
74
+ /**
75
+ * A body of a scene as the layout puts it: its place and size now (stored, or worked out by an automatic layout), and how far its picture reaches past the disc.
76
+ *
77
+ * @example
78
+ * ```ts
79
+ * import { addBody, defaultPortrait, layoutPortrait, type PlacedItem } from "@johnmorrisdotca/wakusei-planets";
80
+ *
81
+ * const placed: PlacedItem[] = layoutPortrait(addBody(defaultPortrait(), "saturn")).placed;
82
+ * console.log(placed[0]?.reach, placed[0]?.r);
83
+ * ```
84
+ */
85
+ export interface Placed extends Item {
86
+ index: number;
87
+ /** How far the picture of the body reaches from its centre (rings, the Sun's glow), in scene units. */
88
+ reach: number;
89
+ }
90
+ /**
91
+ * What a layout works out for a scene: every body placed, and the camera that holds them (its centre and half-height, in the scene's units).
92
+ *
93
+ * @example
94
+ * ```ts
95
+ * import { addBody, defaultPortrait, layoutPortrait, type PortraitLayout } from "@johnmorrisdotca/wakusei-planets";
96
+ *
97
+ * const layout: PortraitLayout = layoutPortrait(addBody(defaultPortrait(), "mars"));
98
+ * console.log(layout.camera.h);
99
+ * ```
100
+ */
101
+ export interface Resolved {
102
+ placed: Placed[];
103
+ camera: {
104
+ x: number;
105
+ y: number;
106
+ h: number;
107
+ };
108
+ }
109
+ export declare const ASPECTS: readonly (readonly [string, number])[];
110
+ export declare const MAX_ITEMS = 40;
111
+ /** The Sun, then each planet and dwarf planet followed by its moons nearest first: the order a layout and a row of buttons use. */
112
+ export declare const ORDER: readonly BodyId[];
113
+ export declare const rankOf: (id: BodyId) => number;
114
+ /**
115
+ * An empty scene with the usual settings: an automatic row, readable sizes, the stars behind, the Sun upper left.
116
+ *
117
+ * @returns A new scene with no bodies.
118
+ *
119
+ * @example
120
+ * ```ts
121
+ * import { defaultPortrait } from "@johnmorrisdotca/wakusei-planets";
122
+ *
123
+ * console.log(defaultPortrait().bg);
124
+ * ```
125
+ */
126
+ export declare function defaultPortrait(): Portrait;
127
+ /** How far the picture of a body reaches past its disc, in its radii: Saturn's rings, the Sun's glow. */
128
+ export declare const reachOf: (id: BodyId) => number;
129
+ /** Raw sizes for the bodies, in any unit, in proportion: true to scale, or squeezed (a root of the radius) with the smallest lifted to a tenth of the largest so every body can be seen. */
130
+ export declare function sizesFor(ids: readonly BodyId[], mode: ScaleMode): number[];
131
+ /** The camera that holds every body with a margin: its centre and half-height. */
132
+ export declare function fitCamera(placed: readonly Pick<Placed, "x" | "y" | "reach">[], aspect: number, margin?: number, labels?: boolean): {
133
+ x: number;
134
+ y: number;
135
+ h: number;
136
+ };
137
+ /**
138
+ * Where every body is and how big, and the camera that holds them. A manual scene gives what it stores. An automatic one works it out (a row, an arc or a grid, a planet's moons round it in orbit
139
+ * order) and fits the camera, so its units are the camera's half-height.
140
+ *
141
+ * @param scene - The scene.
142
+ * @returns Every body placed, back to front, and the camera.
143
+ *
144
+ * @example
145
+ * ```ts
146
+ * import { addBody, defaultPortrait, layoutPortrait } from "@johnmorrisdotca/wakusei-planets";
147
+ *
148
+ * const { placed } = layoutPortrait(addBody(addBody(defaultPortrait(), "earth"), "moon"));
149
+ * console.log(placed.map((item) => `${item.body} ${item.x.toFixed(2)}`).join(", "));
150
+ * ```
151
+ */
152
+ export declare function resolve(scene: Portrait): Resolved;
153
+ /** A manual layout with every body where the automatic one has it now. */
154
+ export declare function freeze(p: Portrait): Portrait;
155
+ /** The automatic layout again. */
156
+ export declare function auto(p: Portrait): Portrait;
157
+ /**
158
+ * Add a body to a scene (once), in its place in the order of the sky for an automatic layout, or at the front and to the right of the others for a manual one.
159
+ *
160
+ * @param scene - The scene to add to; it is not changed.
161
+ * @param body - The body's name.
162
+ * @returns A new scene with the body, or the same one when it is already there.
163
+ *
164
+ * @example
165
+ * ```ts
166
+ * import { addBody, defaultPortrait } from "@johnmorrisdotca/wakusei-planets";
167
+ *
168
+ * const scene = addBody(addBody(defaultPortrait(), "saturn"), "earth");
169
+ * console.log(scene.items.map((item) => item.body).join(", "));
170
+ * ```
171
+ */
172
+ export declare function addBody(scene: Portrait, body: BodyId): Portrait;
173
+ export declare function removeBody(p: Portrait, body: BodyId): Portrait;
174
+ /** Add the moons of a planet that are not in the scene yet, in orbit order. */
175
+ export declare function addMoons(p: Portrait, planet: BodyId): Portrait;
176
+ /** Move one body to a new place in the list: the front is the end. */
177
+ export declare function moveInOrder(p: Portrait, from: number, to: number): Portrait;
178
+ /** Change one body's fields. */
179
+ export declare function setItem(p: Portrait, index: number, change: Partial<Item>): Portrait;
180
+ /** Change the portrait's own settings. A change to manual layout keeps every body where it is on the page. */
181
+ export declare function setPortrait(p: Portrait, change: Partial<Omit<Portrait, "items">>): Portrait;
182
+ /** Every body sized by a scale, keeping the largest as it is (a manual layout's way to go back to true or readable sizes). */
183
+ export declare function rescale(p: Portrait, mode: ScaleMode): Portrait;
184
+ /** Move the camera to the middle of the bodies, keeping its zoom. */
185
+ export declare function centreCamera(p: Portrait): Portrait;
186
+ /** Zoom out or in so every body is in the picture. */
187
+ export declare function fitAll(p: Portrait): Portrait;
188
+ /** The scene's units to pixels: a body at the camera's centre is in the middle of a picture `width` by `height`. */
189
+ export declare function toScreen(camera: Resolved["camera"], width: number, height: number): {
190
+ px(x: number): number;
191
+ py(y: number): number;
192
+ scale: number;
193
+ };
194
+ /** The inverse: a pixel to the scene's units. */
195
+ export declare function fromScreen(camera: Resolved["camera"], width: number, height: number, x: number, y: number): {
196
+ x: number;
197
+ y: number;
198
+ };
199
+ /** The index of the body under a point (scene units), front first; a body smaller than `slop` is still hit within it. */
200
+ export declare function hitTest(placed: readonly Placed[], x: number, y: number, slop?: number): number;
201
+ export interface Guide {
202
+ axis: "x" | "y";
203
+ at: number;
204
+ }
205
+ /** Where a body being dragged snaps: its middle and edges to the middle and edges of the others and to the middle of the picture, within `tolerance` (scene units). */
206
+ export declare function snap(moving: {
207
+ x: number;
208
+ y: number;
209
+ r: number;
210
+ }, others: readonly {
211
+ x: number;
212
+ y: number;
213
+ r: number;
214
+ }[], centre: {
215
+ x: number;
216
+ y: number;
217
+ }, tolerance: number): {
218
+ x: number;
219
+ y: number;
220
+ guides: Guide[];
221
+ };
222
+ /** The Sun's direction as a unit vector in the picture's frame (x right, y up, z toward the viewer). */
223
+ export declare function lightVector(light: {
224
+ az: number;
225
+ el: number;
226
+ }): [number, number, number];
227
+ export interface History {
228
+ readonly current: Portrait;
229
+ readonly canUndo: boolean;
230
+ readonly canRedo: boolean;
231
+ /** Remember a new state (a finished change). */
232
+ push(next: Portrait): void;
233
+ /** Make the newest step this state instead of a new step (a change that goes on: a key held, a slider dragged). */
234
+ replace(next: Portrait): void;
235
+ undo(): Portrait;
236
+ redo(): Portrait;
237
+ }
238
+ /** The states a scene has been through, to step back and forward over. A state is never changed, so each is kept as it is. */
239
+ export declare function createHistory(initial: Portrait, limit?: number): History;
240
+ /**
241
+ * The scene as one short piece of text that is safe in an address: fields joined by `~`, each `name:value`, then one `body_x_y_r_spin_tilt_pitch_turn` for each body, back to front. An empty scene is an empty string.
242
+ *
243
+ * @param scene - The scene.
244
+ * @returns The text.
245
+ *
246
+ * @example
247
+ * ```ts
248
+ * import { addBody, defaultPortrait, encodeScene } from "@johnmorrisdotca/wakusei-planets";
249
+ *
250
+ * console.log(encodeScene(addBody(defaultPortrait(), "mars")));
251
+ * ```
252
+ */
253
+ export declare function encodeScene(scene: Portrait): string;
254
+ /**
255
+ * The scene from its text. Anything it does not understand is left at its default and a body it does not know is dropped, so any text gives a scene.
256
+ *
257
+ * @param text - Text from `encodeScene`, or anything.
258
+ * @returns The scene.
259
+ *
260
+ * @example
261
+ * ```ts
262
+ * import { decodeScene } from "@johnmorrisdotca/wakusei-planets";
263
+ *
264
+ * console.log(decodeScene("look:painted~jupiter_0_0_0.3_0").items[0]?.body);
265
+ * ```
266
+ */
267
+ export declare function decodeScene(text: string): Portrait;
268
+ /**
269
+ * A ready-made scene with its name in English and Japanese.
270
+ *
271
+ * @example
272
+ * ```ts
273
+ * import { PORTRAIT_PRESETS, type PortraitPreset } from "@johnmorrisdotca/wakusei-planets";
274
+ *
275
+ * const first: PortraitPreset = PORTRAIT_PRESETS[0]!;
276
+ * console.log(first.id, first.name.en);
277
+ * ```
278
+ */
279
+ export interface Preset {
280
+ id: string;
281
+ name: {
282
+ en: string;
283
+ ja: string;
284
+ };
285
+ scene: Portrait;
286
+ }
287
+ /**
288
+ * Ready-made scenes to start from: a family photo of the Sun and the planets, the gas giants to scale, Jupiter and the Galileans, the Earth and the Moon to scale (size and distance), Mars and its moons at their true distance, and the inner planets round the Sun.
289
+ *
290
+ * @example
291
+ * ```ts
292
+ * import { PORTRAIT_PRESETS } from "@johnmorrisdotca/wakusei-planets";
293
+ *
294
+ * console.log(PORTRAIT_PRESETS.map((preset) => preset.id).join(", "));
295
+ * ```
296
+ */
297
+ export declare const PRESETS: readonly Preset[];