@motioncomplex/cosmos-lib 1.0.9

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 (47) hide show
  1. package/README.md +125 -0
  2. package/dist/api.d.ts +246 -0
  3. package/dist/cache.d.ts +11 -0
  4. package/dist/clock.d.ts +181 -0
  5. package/dist/constants.d.ts +43 -0
  6. package/dist/data/constellations.d.ts +58 -0
  7. package/dist/data/cutouts.d.ts +70 -0
  8. package/dist/data/deep-sky.d.ts +27 -0
  9. package/dist/data/images.d.ts +147 -0
  10. package/dist/data/index.d.ts +422 -0
  11. package/dist/data/messier.d.ts +61 -0
  12. package/dist/data/ps1-files.d.ts +11 -0
  13. package/dist/data/showers.d.ts +62 -0
  14. package/dist/data/solar-system.d.ts +34 -0
  15. package/dist/data/stars.d.ts +57 -0
  16. package/dist/data/textures.d.ts +67 -0
  17. package/dist/eclipse.d.ts +176 -0
  18. package/dist/index.cjs +1 -0
  19. package/dist/index.d.ts +237 -0
  20. package/dist/index.js +713 -0
  21. package/dist/math.d.ts +532 -0
  22. package/dist/media-DVOcIMa1.js +252 -0
  23. package/dist/media-DlE7RKBL.cjs +1 -0
  24. package/dist/media.d.ts +217 -0
  25. package/dist/moon.d.ts +170 -0
  26. package/dist/planner.d.ts +224 -0
  27. package/dist/react/index.cjs +1 -0
  28. package/dist/react/index.d.ts +167 -0
  29. package/dist/react/index.js +163 -0
  30. package/dist/skymap-hittest.d.ts +69 -0
  31. package/dist/skymap-interactive-CLg6FA0X.js +6377 -0
  32. package/dist/skymap-interactive-D2OZFwJ7.cjs +1 -0
  33. package/dist/skymap-interactive.d.ts +153 -0
  34. package/dist/skymap.d.ts +172 -0
  35. package/dist/sun.d.ts +119 -0
  36. package/dist/three/factories.d.ts +160 -0
  37. package/dist/three/flight.d.ts +116 -0
  38. package/dist/three/index.cjs +20 -0
  39. package/dist/three/index.d.ts +21 -0
  40. package/dist/three/index.js +404 -0
  41. package/dist/three/lod.d.ts +100 -0
  42. package/dist/three/shaders.d.ts +22 -0
  43. package/dist/three/types.d.ts +169 -0
  44. package/dist/transitions.d.ts +246 -0
  45. package/dist/types.d.ts +730 -0
  46. package/dist/units.d.ts +132 -0
  47. package/package.json +93 -0
@@ -0,0 +1,252 @@
1
+ const d = {
2
+ /**
3
+ * Try a list of image URLs in order and resolve with the first one
4
+ * that loads successfully.
5
+ *
6
+ * Each URL is attempted sequentially; when an image fires its `load`
7
+ * event the promise resolves immediately with that URL. If every URL
8
+ * fires an `error` event the promise is rejected.
9
+ *
10
+ * @param urls - Ordered array of image URLs to attempt, from most
11
+ * preferred to least preferred.
12
+ *
13
+ * @returns The first URL that loaded successfully.
14
+ *
15
+ * @throws {Error} If every URL in the list fails to load.
16
+ *
17
+ * @example
18
+ * ```ts
19
+ * const url = await Media.chainLoad([
20
+ * 'https://esahubble.org/media/archives/images/original/heic0506a.tif',
21
+ * 'https://esahubble.org/media/archives/images/large/heic0506a.jpg',
22
+ * 'https://esahubble.org/media/archives/images/screen/heic0506a.jpg',
23
+ * ])
24
+ * ```
25
+ */
26
+ chainLoad(t) {
27
+ return new Promise((a, e) => {
28
+ const o = (i) => {
29
+ const [r, ...s] = i;
30
+ if (r === void 0) {
31
+ e(new Error("All image URLs failed to load."));
32
+ return;
33
+ }
34
+ const n = new Image();
35
+ n.onload = () => a(r), n.onerror = () => o(s), n.src = r;
36
+ };
37
+ o([...t]);
38
+ });
39
+ },
40
+ /**
41
+ * Progressive image loader that shows a blurred placeholder immediately,
42
+ * then upgrades through quality tiers as each resolves.
43
+ *
44
+ * Works on both `<img>` elements (sets `src`) and any other
45
+ * `HTMLElement` (sets `background-image`). A CSS blur filter is applied
46
+ * while the placeholder is shown, then removed with a smooth transition
47
+ * once the full-quality image is ready.
48
+ *
49
+ * @param target - The DOM element to receive the image. Can be an
50
+ * `HTMLImageElement` or any `HTMLElement` with a
51
+ * background-image style.
52
+ * @param opts - Image source configuration. See
53
+ * {@link ProgressiveImageOptions}.
54
+ *
55
+ * @returns Resolves when the highest available quality tier has been
56
+ * applied (or all tiers have been attempted).
57
+ *
58
+ * @example
59
+ * ```ts
60
+ * const hero = document.getElementById('hero-image')!
61
+ * await Media.progressive(hero, {
62
+ * placeholder: 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQ...',
63
+ * src: 'https://cdn.example.com/andromeda-1280.jpg',
64
+ * srcHD: 'https://cdn.example.com/andromeda-4k.jpg',
65
+ * })
66
+ * ```
67
+ */
68
+ async progressive(t, a) {
69
+ const { placeholder: e, src: o, srcHD: i } = a, r = (s, n) => {
70
+ t instanceof HTMLImageElement ? t.src = s : t.style.backgroundImage = `url('${s}')`, t.style.filter = n ? "blur(10px) saturate(0.6)" : "", t.style.transition = "filter 0.5s ease";
71
+ };
72
+ e && r(e, !0);
73
+ try {
74
+ await this._loadImage(o), r(o, !1);
75
+ } catch {
76
+ }
77
+ if (i)
78
+ try {
79
+ await this._loadImage(i), r(i, !1);
80
+ } catch {
81
+ }
82
+ },
83
+ /**
84
+ * Preload a list of images in the background using concurrent fetches.
85
+ *
86
+ * All URLs are loaded in parallel via `Promise.allSettled`. URLs that
87
+ * fail to load are silently dropped; only successfully loaded URLs are
88
+ * returned.
89
+ *
90
+ * @param urls - Array of image URLs to preload.
91
+ *
92
+ * @returns The subset of `urls` that loaded successfully, preserving
93
+ * original order.
94
+ *
95
+ * @example
96
+ * ```ts
97
+ * const loaded = await Media.preload([
98
+ * 'https://cdn.example.com/m31-thumb.jpg',
99
+ * 'https://cdn.example.com/m42-thumb.jpg',
100
+ * 'https://cdn.example.com/m45-thumb.jpg',
101
+ * ])
102
+ * console.log(`${loaded.length} of 3 images cached`)
103
+ * ```
104
+ */
105
+ async preload(t) {
106
+ return (await Promise.allSettled(t.map((e) => this._loadImage(e)))).filter((e) => e.status === "fulfilled").map((e) => e.value);
107
+ },
108
+ /**
109
+ * Build a Wikimedia Commons URL for a given filename.
110
+ *
111
+ * Uses the `Special:FilePath` redirect, which resolves to the correct
112
+ * CDN path without requiring the internal MD5 hash. When a `width` is
113
+ * provided, the Wikimedia thumbnail API generates a resized version
114
+ * server-side.
115
+ *
116
+ * @param filename - The Wikimedia Commons filename, including extension
117
+ * (e.g. `'Orion_Nebula_-_Hubble_2006_mosaic_18000.jpg'`).
118
+ * @param width - Optional pixel width for on-the-fly thumbnail
119
+ * generation. Omit to get the original-resolution file.
120
+ *
121
+ * @returns A fully-qualified Wikimedia Commons URL.
122
+ *
123
+ * @example
124
+ * ```ts
125
+ * // Original resolution
126
+ * Media.wikimediaUrl('Orion_Nebula_-_Hubble_2006_mosaic_18000.jpg')
127
+ * // => 'https://commons.wikimedia.org/wiki/Special:FilePath/Orion_Nebula...'
128
+ *
129
+ * // 800px thumbnail
130
+ * Media.wikimediaUrl('Crab_Nebula.jpg', 800)
131
+ * // => 'https://commons.wikimedia.org/wiki/Special:FilePath/Crab_Nebula.jpg?width=800'
132
+ * ```
133
+ */
134
+ wikimediaUrl(t, a) {
135
+ const e = `https://commons.wikimedia.org/wiki/Special:FilePath/${encodeURIComponent(t)}`;
136
+ return a ? `${e}?width=${a}` : e;
137
+ },
138
+ /**
139
+ * Build a Cloudinary URL with on-the-fly resizing and format optimisation.
140
+ *
141
+ * Constructs a Cloudinary delivery URL using the `image/upload` path
142
+ * with the specified transformations. Defaults to `crop: 'fill'`,
143
+ * `quality: 'auto'`, and `format: 'auto'` when not overridden.
144
+ *
145
+ * @param cloudName - Your Cloudinary cloud name (e.g. `'my-astro-cloud'`).
146
+ * @param publicId - The image's public ID in your Cloudinary media
147
+ * library (e.g. `'nebulae/m42-mosaic'`).
148
+ * @param opts - Transformation options. See {@link CloudinaryOptions}.
149
+ *
150
+ * @returns A fully-qualified Cloudinary delivery URL with transformations.
151
+ *
152
+ * @example
153
+ * ```ts
154
+ * const url = Media.cloudinaryUrl('my-astro-cloud', 'nebulae/m42-mosaic', {
155
+ * w: 1280,
156
+ * h: 720,
157
+ * q: 80,
158
+ * f: 'webp',
159
+ * crop: 'fill',
160
+ * })
161
+ * // => 'https://res.cloudinary.com/my-astro-cloud/image/upload/c_fill,f_webp,q_80,w_1280,h_720/nebulae/m42-mosaic'
162
+ * ```
163
+ */
164
+ cloudinaryUrl(t, a, e = {}) {
165
+ const { w: o, h: i, q: r = "auto", f: s = "auto", crop: n = "fill" } = e, l = [
166
+ `c_${n}`,
167
+ `f_${s}`,
168
+ `q_${r}`,
169
+ o ? `w_${o}` : null,
170
+ i ? `h_${i}` : null
171
+ ].filter((c) => c !== null).join(",");
172
+ return `https://res.cloudinary.com/${t}/image/upload/${l}/${a}`;
173
+ },
174
+ /**
175
+ * Generate an HTML `srcset` attribute value for responsive images.
176
+ *
177
+ * Maps each width to a URL via the `transformer` callback and joins
178
+ * them into a comma-separated descriptor string suitable for use in
179
+ * an `<img srcset="...">` or `<source srcset="...">` attribute.
180
+ *
181
+ * @param widths - Array of pixel widths to include (e.g.
182
+ * `[640, 1280, 1920]`).
183
+ * @param transformer - A function that receives a width in pixels and
184
+ * returns the corresponding image URL.
185
+ *
186
+ * @returns A `srcset`-formatted string (e.g.
187
+ * `'https://cdn.example.com/img?w=640 640w, ...`).
188
+ *
189
+ * @example
190
+ * ```ts
191
+ * const set = Media.srcset([640, 1280, 1920], w =>
192
+ * Media.cloudinaryUrl('my-cloud', 'galaxy/ngc1300', { w, f: 'webp' }),
193
+ * )
194
+ * // Use in an <img> tag:
195
+ * // <img srcset={set} sizes="100vw" />
196
+ * ```
197
+ */
198
+ srcset(t, a) {
199
+ return t.map((e) => `${a(e)} ${e}w`).join(", ");
200
+ },
201
+ /**
202
+ * Return the optimal image dimensions (in physical pixels) for a given
203
+ * container element, accounting for `window.devicePixelRatio`.
204
+ *
205
+ * Multiplies the element's CSS layout size by the device pixel ratio so
206
+ * that images are sharp on high-DPI (Retina) displays. Falls back to a
207
+ * ratio of `1` when `devicePixelRatio` is unavailable.
208
+ *
209
+ * @param element - The DOM element whose bounding box determines the
210
+ * target dimensions.
211
+ *
212
+ * @returns An object with `width` and `height` in physical (device)
213
+ * pixels, rounded to the nearest integer.
214
+ *
215
+ * @example
216
+ * ```ts
217
+ * const container = document.getElementById('galaxy-viewer')!
218
+ * const { width, height } = Media.optimalSize(container)
219
+ * const url = Media.cloudinaryUrl('my-cloud', 'galaxy/ngc1300', {
220
+ * w: width,
221
+ * h: height,
222
+ * })
223
+ * ```
224
+ */
225
+ optimalSize(t) {
226
+ const a = t.getBoundingClientRect(), e = window.devicePixelRatio || 1;
227
+ return {
228
+ width: Math.round(a.width * e),
229
+ height: Math.round(a.height * e)
230
+ };
231
+ },
232
+ // ── Private ────────────────────────────────────────────────────────────────
233
+ /**
234
+ * Load a single image by URL using the DOM `Image` constructor.
235
+ *
236
+ * @internal This is an implementation detail used by {@link Media.chainLoad},
237
+ * {@link Media.progressive}, and {@link Media.preload}. It is not part of
238
+ * the public API and may change without notice.
239
+ *
240
+ * @param url - The image URL to load.
241
+ * @returns Resolves with the URL on successful load; rejects on error.
242
+ */
243
+ _loadImage(t) {
244
+ return new Promise((a, e) => {
245
+ const o = new Image();
246
+ o.onload = () => a(t), o.onerror = () => e(new Error(`Failed to load image: ${t}`)), o.src = t;
247
+ });
248
+ }
249
+ };
250
+ export {
251
+ d as M
252
+ };
@@ -0,0 +1 @@
1
+ "use strict";const d={chainLoad(t){return new Promise((a,e)=>{const o=r=>{const[i,...s]=r;if(i===void 0){e(new Error("All image URLs failed to load."));return}const n=new Image;n.onload=()=>a(i),n.onerror=()=>o(s),n.src=i};o([...t])})},async progressive(t,a){const{placeholder:e,src:o,srcHD:r}=a,i=(s,n)=>{t instanceof HTMLImageElement?t.src=s:t.style.backgroundImage=`url('${s}')`,t.style.filter=n?"blur(10px) saturate(0.6)":"",t.style.transition="filter 0.5s ease"};e&&i(e,!0);try{await this._loadImage(o),i(o,!1)}catch{}if(r)try{await this._loadImage(r),i(r,!1)}catch{}},async preload(t){return(await Promise.allSettled(t.map(e=>this._loadImage(e)))).filter(e=>e.status==="fulfilled").map(e=>e.value)},wikimediaUrl(t,a){const e=`https://commons.wikimedia.org/wiki/Special:FilePath/${encodeURIComponent(t)}`;return a?`${e}?width=${a}`:e},cloudinaryUrl(t,a,e={}){const{w:o,h:r,q:i="auto",f:s="auto",crop:n="fill"}=e,l=[`c_${n}`,`f_${s}`,`q_${i}`,o?`w_${o}`:null,r?`h_${r}`:null].filter(c=>c!==null).join(",");return`https://res.cloudinary.com/${t}/image/upload/${l}/${a}`},srcset(t,a){return t.map(e=>`${a(e)} ${e}w`).join(", ")},optimalSize(t){const a=t.getBoundingClientRect(),e=window.devicePixelRatio||1;return{width:Math.round(a.width*e),height:Math.round(a.height*e)}},_loadImage(t){return new Promise((a,e)=>{const o=new Image;o.onload=()=>a(t),o.onerror=()=>e(new Error(`Failed to load image: ${t}`)),o.src=t})}};exports.Media=d;
@@ -0,0 +1,217 @@
1
+ import type { ProgressiveImageOptions, CloudinaryOptions } from './types.js';
2
+ /**
3
+ * Browser-side utilities for loading, transforming, and optimising
4
+ * astronomical imagery.
5
+ *
6
+ * All methods that load images use the DOM `Image` constructor and are
7
+ * therefore intended for browser environments only.
8
+ *
9
+ * @example
10
+ * ```ts
11
+ * import { Media } from 'cosmos-lib'
12
+ *
13
+ * // Load the best available image from a priority list
14
+ * const url = await Media.chainLoad([
15
+ * 'https://cdn.example.com/nebula-hd.jpg',
16
+ * 'https://cdn.example.com/nebula-sd.jpg',
17
+ * ])
18
+ * document.querySelector('img')!.src = url
19
+ * ```
20
+ */
21
+ export declare const Media: {
22
+ /**
23
+ * Try a list of image URLs in order and resolve with the first one
24
+ * that loads successfully.
25
+ *
26
+ * Each URL is attempted sequentially; when an image fires its `load`
27
+ * event the promise resolves immediately with that URL. If every URL
28
+ * fires an `error` event the promise is rejected.
29
+ *
30
+ * @param urls - Ordered array of image URLs to attempt, from most
31
+ * preferred to least preferred.
32
+ *
33
+ * @returns The first URL that loaded successfully.
34
+ *
35
+ * @throws {Error} If every URL in the list fails to load.
36
+ *
37
+ * @example
38
+ * ```ts
39
+ * const url = await Media.chainLoad([
40
+ * 'https://esahubble.org/media/archives/images/original/heic0506a.tif',
41
+ * 'https://esahubble.org/media/archives/images/large/heic0506a.jpg',
42
+ * 'https://esahubble.org/media/archives/images/screen/heic0506a.jpg',
43
+ * ])
44
+ * ```
45
+ */
46
+ readonly chainLoad: (urls: string[]) => Promise<string>;
47
+ /**
48
+ * Progressive image loader that shows a blurred placeholder immediately,
49
+ * then upgrades through quality tiers as each resolves.
50
+ *
51
+ * Works on both `<img>` elements (sets `src`) and any other
52
+ * `HTMLElement` (sets `background-image`). A CSS blur filter is applied
53
+ * while the placeholder is shown, then removed with a smooth transition
54
+ * once the full-quality image is ready.
55
+ *
56
+ * @param target - The DOM element to receive the image. Can be an
57
+ * `HTMLImageElement` or any `HTMLElement` with a
58
+ * background-image style.
59
+ * @param opts - Image source configuration. See
60
+ * {@link ProgressiveImageOptions}.
61
+ *
62
+ * @returns Resolves when the highest available quality tier has been
63
+ * applied (or all tiers have been attempted).
64
+ *
65
+ * @example
66
+ * ```ts
67
+ * const hero = document.getElementById('hero-image')!
68
+ * await Media.progressive(hero, {
69
+ * placeholder: 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQ...',
70
+ * src: 'https://cdn.example.com/andromeda-1280.jpg',
71
+ * srcHD: 'https://cdn.example.com/andromeda-4k.jpg',
72
+ * })
73
+ * ```
74
+ */
75
+ readonly progressive: (target: HTMLImageElement | HTMLElement, opts: ProgressiveImageOptions) => Promise<void>;
76
+ /**
77
+ * Preload a list of images in the background using concurrent fetches.
78
+ *
79
+ * All URLs are loaded in parallel via `Promise.allSettled`. URLs that
80
+ * fail to load are silently dropped; only successfully loaded URLs are
81
+ * returned.
82
+ *
83
+ * @param urls - Array of image URLs to preload.
84
+ *
85
+ * @returns The subset of `urls` that loaded successfully, preserving
86
+ * original order.
87
+ *
88
+ * @example
89
+ * ```ts
90
+ * const loaded = await Media.preload([
91
+ * 'https://cdn.example.com/m31-thumb.jpg',
92
+ * 'https://cdn.example.com/m42-thumb.jpg',
93
+ * 'https://cdn.example.com/m45-thumb.jpg',
94
+ * ])
95
+ * console.log(`${loaded.length} of 3 images cached`)
96
+ * ```
97
+ */
98
+ readonly preload: (urls: string[]) => Promise<string[]>;
99
+ /**
100
+ * Build a Wikimedia Commons URL for a given filename.
101
+ *
102
+ * Uses the `Special:FilePath` redirect, which resolves to the correct
103
+ * CDN path without requiring the internal MD5 hash. When a `width` is
104
+ * provided, the Wikimedia thumbnail API generates a resized version
105
+ * server-side.
106
+ *
107
+ * @param filename - The Wikimedia Commons filename, including extension
108
+ * (e.g. `'Orion_Nebula_-_Hubble_2006_mosaic_18000.jpg'`).
109
+ * @param width - Optional pixel width for on-the-fly thumbnail
110
+ * generation. Omit to get the original-resolution file.
111
+ *
112
+ * @returns A fully-qualified Wikimedia Commons URL.
113
+ *
114
+ * @example
115
+ * ```ts
116
+ * // Original resolution
117
+ * Media.wikimediaUrl('Orion_Nebula_-_Hubble_2006_mosaic_18000.jpg')
118
+ * // => 'https://commons.wikimedia.org/wiki/Special:FilePath/Orion_Nebula...'
119
+ *
120
+ * // 800px thumbnail
121
+ * Media.wikimediaUrl('Crab_Nebula.jpg', 800)
122
+ * // => 'https://commons.wikimedia.org/wiki/Special:FilePath/Crab_Nebula.jpg?width=800'
123
+ * ```
124
+ */
125
+ readonly wikimediaUrl: (filename: string, width?: number) => string;
126
+ /**
127
+ * Build a Cloudinary URL with on-the-fly resizing and format optimisation.
128
+ *
129
+ * Constructs a Cloudinary delivery URL using the `image/upload` path
130
+ * with the specified transformations. Defaults to `crop: 'fill'`,
131
+ * `quality: 'auto'`, and `format: 'auto'` when not overridden.
132
+ *
133
+ * @param cloudName - Your Cloudinary cloud name (e.g. `'my-astro-cloud'`).
134
+ * @param publicId - The image's public ID in your Cloudinary media
135
+ * library (e.g. `'nebulae/m42-mosaic'`).
136
+ * @param opts - Transformation options. See {@link CloudinaryOptions}.
137
+ *
138
+ * @returns A fully-qualified Cloudinary delivery URL with transformations.
139
+ *
140
+ * @example
141
+ * ```ts
142
+ * const url = Media.cloudinaryUrl('my-astro-cloud', 'nebulae/m42-mosaic', {
143
+ * w: 1280,
144
+ * h: 720,
145
+ * q: 80,
146
+ * f: 'webp',
147
+ * crop: 'fill',
148
+ * })
149
+ * // => 'https://res.cloudinary.com/my-astro-cloud/image/upload/c_fill,f_webp,q_80,w_1280,h_720/nebulae/m42-mosaic'
150
+ * ```
151
+ */
152
+ readonly cloudinaryUrl: (cloudName: string, publicId: string, opts?: CloudinaryOptions) => string;
153
+ /**
154
+ * Generate an HTML `srcset` attribute value for responsive images.
155
+ *
156
+ * Maps each width to a URL via the `transformer` callback and joins
157
+ * them into a comma-separated descriptor string suitable for use in
158
+ * an `<img srcset="...">` or `<source srcset="...">` attribute.
159
+ *
160
+ * @param widths - Array of pixel widths to include (e.g.
161
+ * `[640, 1280, 1920]`).
162
+ * @param transformer - A function that receives a width in pixels and
163
+ * returns the corresponding image URL.
164
+ *
165
+ * @returns A `srcset`-formatted string (e.g.
166
+ * `'https://cdn.example.com/img?w=640 640w, ...`).
167
+ *
168
+ * @example
169
+ * ```ts
170
+ * const set = Media.srcset([640, 1280, 1920], w =>
171
+ * Media.cloudinaryUrl('my-cloud', 'galaxy/ngc1300', { w, f: 'webp' }),
172
+ * )
173
+ * // Use in an <img> tag:
174
+ * // <img srcset={set} sizes="100vw" />
175
+ * ```
176
+ */
177
+ readonly srcset: (widths: number[], transformer: (w: number) => string) => string;
178
+ /**
179
+ * Return the optimal image dimensions (in physical pixels) for a given
180
+ * container element, accounting for `window.devicePixelRatio`.
181
+ *
182
+ * Multiplies the element's CSS layout size by the device pixel ratio so
183
+ * that images are sharp on high-DPI (Retina) displays. Falls back to a
184
+ * ratio of `1` when `devicePixelRatio` is unavailable.
185
+ *
186
+ * @param element - The DOM element whose bounding box determines the
187
+ * target dimensions.
188
+ *
189
+ * @returns An object with `width` and `height` in physical (device)
190
+ * pixels, rounded to the nearest integer.
191
+ *
192
+ * @example
193
+ * ```ts
194
+ * const container = document.getElementById('galaxy-viewer')!
195
+ * const { width, height } = Media.optimalSize(container)
196
+ * const url = Media.cloudinaryUrl('my-cloud', 'galaxy/ngc1300', {
197
+ * w: width,
198
+ * h: height,
199
+ * })
200
+ * ```
201
+ */
202
+ readonly optimalSize: (element: Element) => {
203
+ width: number;
204
+ height: number;
205
+ };
206
+ /**
207
+ * Load a single image by URL using the DOM `Image` constructor.
208
+ *
209
+ * @internal This is an implementation detail used by {@link Media.chainLoad},
210
+ * {@link Media.progressive}, and {@link Media.preload}. It is not part of
211
+ * the public API and may change without notice.
212
+ *
213
+ * @param url - The image URL to load.
214
+ * @returns Resolves with the URL on successful load; rejects on error.
215
+ */
216
+ readonly _loadImage: (url: string) => Promise<string>;
217
+ };
package/dist/moon.d.ts ADDED
@@ -0,0 +1,170 @@
1
+ import type { MoonPhase, MoonPosition, ObserverParams, RiseTransitSet } from './types.js';
2
+ export declare const Moon: {
3
+ /**
4
+ * Geocentric equatorial and ecliptic position of the Moon.
5
+ *
6
+ * Computes the Moon's right ascension, declination, distance, ecliptic
7
+ * longitude/latitude, and horizontal parallax for the given date using
8
+ * Meeus' lunar theory with the ELP 2000-82 series truncated to the
9
+ * dominant terms.
10
+ *
11
+ * @remarks
12
+ * The algorithm computes five fundamental arguments (L', D, M, M', F) and
13
+ * evaluates trigonometric series from Meeus Tables 47.A (60 terms for
14
+ * longitude and distance) and 47.B (30 terms for latitude). Eccentricity
15
+ * corrections are applied to terms involving the Sun's mean anomaly M.
16
+ * Three additive corrections (A1, A2, A3) from Meeus p. 338 are included.
17
+ * Nutation is applied to the ecliptic longitude before converting to
18
+ * equatorial coordinates using the true obliquity.
19
+ *
20
+ * @param date - The date and time for which to compute the Moon's position. Defaults to the current date/time.
21
+ * @returns The Moon's geocentric position including RA (0-360°), declination, distance in km,
22
+ * ecliptic longitude (0-360°), ecliptic latitude, and horizontal parallax in degrees.
23
+ *
24
+ * @example
25
+ * ```ts
26
+ * import { Moon } from '@motioncomplex/cosmos-lib'
27
+ *
28
+ * // Moon position at the 2024 vernal equinox
29
+ * const pos = Moon.position(new Date('2024-03-20T03:06:00Z'))
30
+ * console.log(`RA: ${pos.ra.toFixed(4)}°`)
31
+ * console.log(`Dec: ${pos.dec.toFixed(4)}°`)
32
+ * console.log(`Distance: ${pos.distance_km.toFixed(0)} km`)
33
+ * console.log(`Ecliptic Lon: ${pos.eclipticLon.toFixed(4)}°`)
34
+ * console.log(`Ecliptic Lat: ${pos.eclipticLat.toFixed(4)}°`)
35
+ * console.log(`Parallax: ${pos.parallax.toFixed(4)}°`)
36
+ * ```
37
+ */
38
+ readonly position: (date?: Date) => MoonPosition;
39
+ /**
40
+ * Moon phase information for a given date.
41
+ *
42
+ * Computes the lunar phase angle, illuminated fraction, age (days since
43
+ * new moon), and a human-readable phase name based on the difference
44
+ * in ecliptic longitude between the Moon and the Sun.
45
+ *
46
+ * @remarks
47
+ * The phase is determined from the elongation of the Moon from the Sun
48
+ * in ecliptic longitude. The illuminated fraction is derived using the
49
+ * cosine of the phase angle: `(1 - cos(phaseAngle)) / 2`. Phase names
50
+ * are divided into eight equal segments of 0.125 (45°) each, centered
51
+ * on the four principal phases.
52
+ *
53
+ * @param date - The date and time for which to compute the phase. Defaults to the current date/time.
54
+ * @returns An object containing the phase cycle position (0-1), illuminated fraction (0-1),
55
+ * age in days (0-29.5), and the human-readable phase name.
56
+ *
57
+ * @example
58
+ * ```ts
59
+ * import { Moon } from '@motioncomplex/cosmos-lib'
60
+ *
61
+ * // Phase at vernal equinox 2024
62
+ * const p = Moon.phase(new Date('2024-03-20'))
63
+ * console.log(`Phase: ${p.name}`) // e.g. 'waxing-gibbous'
64
+ * console.log(`Illumination: ${(p.illumination * 100).toFixed(0)}%`)
65
+ * console.log(`Age: ${p.age.toFixed(1)} days`)
66
+ * console.log(`Cycle: ${(p.phase * 100).toFixed(1)}%`) // 0% = new, 50% = full
67
+ * ```
68
+ */
69
+ readonly phase: (date?: Date) => MoonPhase;
70
+ /**
71
+ * Find the next occurrence of a specific phase after the given date.
72
+ *
73
+ * Uses an initial estimate based on the current phase position within the
74
+ * synodic month, then refines iteratively using bisection to achieve
75
+ * approximately 1-minute precision (up to 20 refinement iterations).
76
+ *
77
+ * @remarks
78
+ * The algorithm first estimates the time to the target phase from the current
79
+ * phase fraction, then iteratively corrects the estimate by measuring the
80
+ * phase error and adjusting by the proportional fraction of a synodic month.
81
+ * Wrap-around near the 0/1 boundary (new moon) is handled explicitly.
82
+ * Convergence threshold is 0.0001 phase units, corresponding to roughly
83
+ * 4 minutes of time.
84
+ *
85
+ * @param date - Start date from which to search forward. Defaults to the current date/time.
86
+ * @param targetPhase - The phase to find: `'new'`, `'first-quarter'`, `'full'`, or `'last-quarter'`. Defaults to `'full'`.
87
+ * @returns A `Date` representing the approximate moment of the next occurrence of the target phase.
88
+ *
89
+ * @example
90
+ * ```ts
91
+ * import { Moon } from '@motioncomplex/cosmos-lib'
92
+ *
93
+ * // Find the next full moon after the 2024 vernal equinox
94
+ * const fullMoon = Moon.nextPhase(new Date('2024-03-20'), 'full')
95
+ * console.log('Next full moon:', fullMoon.toISOString()) // 2024-03-25
96
+ *
97
+ * // Find the next new moon from today
98
+ * const newMoon = Moon.nextPhase(new Date('2024-03-20'), 'new')
99
+ * console.log('Next new moon:', newMoon.toISOString()) // 2024-04-08
100
+ * ```
101
+ */
102
+ readonly nextPhase: (date?: Date, targetPhase?: "new" | "first-quarter" | "full" | "last-quarter") => Date;
103
+ /**
104
+ * Rise, transit, and set times for the Moon.
105
+ *
106
+ * Computes the times at which the Moon rises above the horizon, transits
107
+ * the local meridian, and sets below the horizon for the given observer
108
+ * location and date.
109
+ *
110
+ * @remarks
111
+ * Uses the Moon's standard altitude of +0.125°, which accounts for the
112
+ * Moon's mean horizontal parallax (approximately 0.95°) minus atmospheric
113
+ * refraction (34 arc-minutes) minus the Moon's mean semi-diameter (about 16
114
+ * arc-minutes). Rise and set times will be `null` if the Moon is circumpolar
115
+ * (always above the horizon) or never rises at the given location and date.
116
+ *
117
+ * @param obs - Observer location and optional date. If `obs.date` is omitted, the current date/time is used.
118
+ * @returns An object with `rise`, `transit`, and `set` times. `rise` and `set` may be `null` at polar latitudes.
119
+ *
120
+ * @example
121
+ * ```ts
122
+ * import { Moon } from '@motioncomplex/cosmos-lib'
123
+ *
124
+ * // Moonrise and moonset in London
125
+ * const rts = Moon.riseTransitSet({ lat: 51.5, lng: -0.1, date: new Date('2024-03-20') })
126
+ * console.log('Moonrise:', rts.rise?.toISOString())
127
+ * console.log('Moon transit:', rts.transit.toISOString())
128
+ * console.log('Moonset:', rts.set?.toISOString())
129
+ * ```
130
+ */
131
+ readonly riseTransitSet: (obs: ObserverParams) => RiseTransitSet;
132
+ /**
133
+ * Optical libration angles (simplified).
134
+ *
135
+ * Returns the apparent tilt of the Moon's face as seen from Earth, caused
136
+ * by the geometry of the Moon's orbit relative to its rotational axis.
137
+ * Optical libration allows observers to see slightly more than 50% of
138
+ * the Moon's surface over time.
139
+ *
140
+ * @remarks
141
+ * This is a simplified calculation of the optical libration only (physical
142
+ * libration is not included). The mean inclination of the lunar equator to
143
+ * the ecliptic is taken as I = 1.5424°. The computation uses the Moon's
144
+ * argument of latitude (F), the longitude of the ascending node (Om), and
145
+ * the current ecliptic position. Based on Meeus, "Astronomical Algorithms",
146
+ * Chapter 53.
147
+ *
148
+ * Libration in longitude (`l`) reveals the eastern or western limb of the
149
+ * Moon, while libration in latitude (`b`) reveals the northern or southern
150
+ * limb. Both values are in degrees, with typical ranges of approximately
151
+ * +/-7.9° for longitude and +/-6.9° for latitude.
152
+ *
153
+ * @param date - The date and time for which to compute the libration. Defaults to the current date/time.
154
+ * @returns An object with `l` (libration in longitude, degrees) and `b` (libration in latitude, degrees).
155
+ *
156
+ * @example
157
+ * ```ts
158
+ * import { Moon } from '@motioncomplex/cosmos-lib'
159
+ *
160
+ * // Libration at the 2024 vernal equinox
161
+ * const lib = Moon.libration(new Date('2024-03-20'))
162
+ * console.log(`Libration in longitude: ${lib.l.toFixed(2)}°`)
163
+ * console.log(`Libration in latitude: ${lib.b.toFixed(2)}°`)
164
+ * ```
165
+ */
166
+ readonly libration: (date?: Date) => {
167
+ l: number;
168
+ b: number;
169
+ };
170
+ };