@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.
- package/README.md +125 -0
- package/dist/api.d.ts +246 -0
- package/dist/cache.d.ts +11 -0
- package/dist/clock.d.ts +181 -0
- package/dist/constants.d.ts +43 -0
- package/dist/data/constellations.d.ts +58 -0
- package/dist/data/cutouts.d.ts +70 -0
- package/dist/data/deep-sky.d.ts +27 -0
- package/dist/data/images.d.ts +147 -0
- package/dist/data/index.d.ts +422 -0
- package/dist/data/messier.d.ts +61 -0
- package/dist/data/ps1-files.d.ts +11 -0
- package/dist/data/showers.d.ts +62 -0
- package/dist/data/solar-system.d.ts +34 -0
- package/dist/data/stars.d.ts +57 -0
- package/dist/data/textures.d.ts +67 -0
- package/dist/eclipse.d.ts +176 -0
- package/dist/index.cjs +1 -0
- package/dist/index.d.ts +237 -0
- package/dist/index.js +713 -0
- package/dist/math.d.ts +532 -0
- package/dist/media-DVOcIMa1.js +252 -0
- package/dist/media-DlE7RKBL.cjs +1 -0
- package/dist/media.d.ts +217 -0
- package/dist/moon.d.ts +170 -0
- package/dist/planner.d.ts +224 -0
- package/dist/react/index.cjs +1 -0
- package/dist/react/index.d.ts +167 -0
- package/dist/react/index.js +163 -0
- package/dist/skymap-hittest.d.ts +69 -0
- package/dist/skymap-interactive-CLg6FA0X.js +6377 -0
- package/dist/skymap-interactive-D2OZFwJ7.cjs +1 -0
- package/dist/skymap-interactive.d.ts +153 -0
- package/dist/skymap.d.ts +172 -0
- package/dist/sun.d.ts +119 -0
- package/dist/three/factories.d.ts +160 -0
- package/dist/three/flight.d.ts +116 -0
- package/dist/three/index.cjs +20 -0
- package/dist/three/index.d.ts +21 -0
- package/dist/three/index.js +404 -0
- package/dist/three/lod.d.ts +100 -0
- package/dist/three/shaders.d.ts +22 -0
- package/dist/three/types.d.ts +169 -0
- package/dist/transitions.d.ts +246 -0
- package/dist/types.d.ts +730 -0
- package/dist/units.d.ts +132 -0
- 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;
|
package/dist/media.d.ts
ADDED
|
@@ -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
|
+
};
|