spacemap 0.1.0 → 0.1.2

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/index.d.ts ADDED
@@ -0,0 +1,2175 @@
1
+ import { Object3D } from 'three';
2
+
3
+ export declare type Anchor = InertialAnchor | SurfaceAnchor;
4
+
5
+ export declare type ArrowKey = 'previous' | 'next';
6
+
7
+ /** Boot-time benchmark result (see perf/atmosphere-calibration.ts). */
8
+ declare interface AtmosphereCalibration {
9
+ /** GPU + resolution identity the run is valid for — a mismatch re-calibrates. */
10
+ key: string;
11
+ tier: ResolvedAtmosphereTier;
12
+ /** Worse-scenario median per measured tier, so thresholds can be re-derived
13
+ * without another run. */
14
+ worstMs: Partial<Record<ResolvedAtmosphereTier, number>>;
15
+ }
16
+
17
+ /**
18
+ * Quality knobs for the atmosphere shells. Ray march cost is
19
+ * primarySteps × (lightSteps + shadow work) per fragment, over the planet's
20
+ * whole footprint — tiers pick compile-time defines instead of forking shaders.
21
+ */
22
+ declare interface AtmosphereQualityConfig {
23
+ /** View-ray march samples. */
24
+ primarySteps: number;
25
+ /** Sun-ray samples per view sample. */
26
+ lightSteps: number;
27
+ /** March eclipse occluders (moon shadows sweeping the air column). */
28
+ eclipseShadows: boolean;
29
+ /** March the ring-shadow profile through the air column. */
30
+ ringShadows: boolean;
31
+ /** Sky rendered from inside a shell (BackSide flip + opaque-depth prepass + skybox dimming). Off = shell vanishes once entered. */
32
+ insideView: boolean;
33
+ /** Sun-transmittance tints (sunset light, disc chroma, corona). Off on low tiers: surface march covers full-screen landed terrain. */
34
+ sunTint: boolean;
35
+ /** Piecewise Mie density profiles (Venus decks, Titan haze): two LUT taps per sample instead of one exp — high/ultra. */
36
+ layeredDensity: boolean;
37
+ /** Ground-bounce boost on multiple-scatter ambient. Reuses already-marched densities — free, on everywhere. */
38
+ groundAlbedo: boolean;
39
+ /** Mars seasonal dust/pressure cycle. CPU-only, on everywhere. */
40
+ seasonal: boolean;
41
+ /** Refraction lift of the Sun seen from inside a shell. CPU-only, on everywhere. */
42
+ refraction: boolean;
43
+ }
44
+
45
+ declare type AtmosphereQualityTier = 'auto' | ResolvedAtmosphereTier;
46
+
47
+ export declare class AttributionControl implements Control<SpaceMap> {
48
+ private stop;
49
+ onAdd(map: SpaceMap): HTMLElement;
50
+ onRemove(): void;
51
+ getDefaultPosition(): ControlPosition;
52
+ }
53
+
54
+ /** Initial great-circle bearing from `a` to `b`, degrees clockwise from
55
+ * north; east-positive longitudes as the export lists them. */
56
+ export declare function bearingDeg(a: LonLat, b: LonLat): number;
57
+
58
+ declare interface Body_2 {
59
+ /** Export id, as every method that takes a body takes it: `"naif-499"`. */
60
+ id: string;
61
+ /** In the map's reading language; null for a catalogued object with no name. */
62
+ name: string | null;
63
+ type: BodyType;
64
+ /** Only on asteroids. */
65
+ orbitClass?: OrbitClass;
66
+ /** What it orbits, always a major body or a barycentre. */
67
+ parentId: string;
68
+ /** Null where the catalogue quotes no size. */
69
+ radiusKm: number | null;
70
+ /** False while the object has no position at the map's date — outside its
71
+ * ephemeris, or catalogued with no orbit at all. Nothing may be framed on
72
+ * it: the camera would fly to a stand-in place. */
73
+ placed: boolean;
74
+ }
75
+ export { Body_2 as Body }
76
+
77
+ /** Pictures a host has put on a body. Each is a URL the browser can load, and
78
+ * what is left out is the map's own. */
79
+ export declare interface BodyAppearance {
80
+ /** The surface map, drawn the way every body's is: equirectangular, east to
81
+ * the right, with longitude 0 in the middle. */
82
+ surface?: string;
83
+ /** Lights on the unlit side, drawn where the map draws city lights. */
84
+ night?: string;
85
+ /** A layer over the surface, its alpha the cover. */
86
+ clouds?: string;
87
+ }
88
+
89
+ /** Object kinds a host can act on. The asteroid sub-types collapse into
90
+ * `asteroid`, whose dynamical family is {@link Body.orbitClass}. */
91
+ export declare type BodyType = 'barycenter' | 'lagrange-point' | 'star' | 'planet' | 'dwarf-planet' | 'moon' | 'asteroid' | 'comet' | 'spacecraft' | 'debris' | 'surface-feature' | 'unknown';
92
+
93
+ /** The four sides of a longitude and latitude box, in order. The corners alone
94
+ * would be enough on an equirectangular map and wrong on every other one, so
95
+ * the edges are walked and left for {@link pathFor} to fill in. */
96
+ export declare function boxRing(latMin: number, latMax: number, lonMin: number, lonSpan: number): LonLat[];
97
+
98
+ /** A suspension of the map's own camera control, for as long as it is held. */
99
+ export declare interface CameraHold {
100
+ /** Put the camera at `pose` from the next frame on. Call it from the map's
101
+ * `frame` event to drive a path. */
102
+ set(pose: CameraPose): void;
103
+ /** Give the camera back to the map, orbiting the focused body from
104
+ * wherever the hold left it. */
105
+ release(): void;
106
+ readonly held: boolean;
107
+ }
108
+
109
+ /**
110
+ * How far the reader may take the camera, and which objects they may put it
111
+ * around. Everything left out is unrestricted.
112
+ *
113
+ * These gate reader input and nothing else. {@link SpaceMap.flyTo},
114
+ * {@link SpaceMap.jumpTo}, {@link SpaceMap.panTo} and a held camera go where
115
+ * they are told, outside the limits included; the reader's next gesture brings
116
+ * the camera back inside. That is a deliberate departure from Mapbox, where
117
+ * `maxBounds` holds the map wherever the move came from.
118
+ */
119
+ export declare interface CameraLimits {
120
+ /** How close and how far the reader may get to the focused body's centre. */
121
+ minDistanceKm?: number;
122
+ maxDistanceKm?: number;
123
+ /** The band of the focused body the reader may look down from, in the same
124
+ * body-fixed degrees {@link SpaceMap.getCamera} reports. A longitude band
125
+ * may run through the antimeridian: 170 to −170 is the twenty degrees
126
+ * across it. One edge alone leaves the other at the antimeridian. */
127
+ minLat?: number;
128
+ maxLat?: number;
129
+ minLon?: number;
130
+ maxLon?: number;
131
+ /** Export ids of the only objects a reader click may focus. Any of them when
132
+ * left out. */
133
+ bodies?: string[];
134
+ }
135
+
136
+ /** Where the camera sits: over a place on a body, at a distance from it. */
137
+ export declare interface CameraOptions {
138
+ /** The body the camera orbits, by export id — `"naif-499"` for Mars. */
139
+ body?: string;
140
+ /** The place on it the camera looks down at, in degrees. */
141
+ lat?: number;
142
+ lon?: number;
143
+ /** How far the camera is from the body's centre, in kilometres. */
144
+ distanceKm?: number;
145
+ }
146
+
147
+ /** Where the camera is and what it looks at. */
148
+ export declare interface CameraPose {
149
+ position: Anchor;
150
+ target: Anchor;
151
+ /** Which way is up, on ecliptic J2000 axes. The ecliptic north pole when
152
+ * left out; a pose looking straight along it needs one of its own. */
153
+ up?: OffsetKm;
154
+ }
155
+
156
+ /** The camera as it stands. `body` is what it orbits, which is also what the
157
+ * map draws in most detail. */
158
+ export declare interface CameraState {
159
+ body: string;
160
+ lat: number;
161
+ lon: number;
162
+ distanceKm: number;
163
+ }
164
+
165
+ /** Somewhere to move the camera to. What is left out is left as it is. */
166
+ export declare interface CameraTarget extends CameraOptions {
167
+ /** A feature on `body` to look at, rather than the body as a whole. Its
168
+ * size frames the view, so `distanceKm` is not needed. */
169
+ feature?: FeatureRef;
170
+ }
171
+
172
+ export declare interface Circle extends Shape {
173
+ /** Draw it at another radius, in kilometres. */
174
+ setRadiusKm(radiusKm: number): void;
175
+ }
176
+
177
+ export declare interface CircleOptions extends ShapeStyle {
178
+ /** The middle of the circle. */
179
+ anchor: Anchor;
180
+ /** Distance from the anchor, in kilometres. */
181
+ radiusKm: number;
182
+ /** Which way the circle's plane faces, on ecliptic J2000 axes. The ecliptic
183
+ * north pole when left out, which lays the ring in the plane the planets
184
+ * go round in. A ring that has to turn with the body under it is a surface
185
+ * circle instead. */
186
+ normal?: OffsetKm;
187
+ /** Points round the ring. More is rounder; the default is round enough to
188
+ * fill the frame without corners. */
189
+ steps?: number;
190
+ }
191
+
192
+ /** A ring of `steps` points at `radiusKm` from the origin, in the plane at
193
+ * right angles to `normal`. */
194
+ export declare function circlePoints(radiusKm: number, options?: CirclePointsOptions): OffsetKm[];
195
+
196
+ export declare interface CirclePointsOptions {
197
+ /** Which way the circle's plane faces. The ecliptic north pole when left
198
+ * out, which draws a ring in the plane the planets go round in. */
199
+ normal?: OffsetKm;
200
+ /** Points round the ring. */
201
+ steps?: number;
202
+ }
203
+
204
+ /** The clock as the host sees it, sent whenever any of it changes. */
205
+ export declare interface ClockState {
206
+ /** Simulation time, Julian date and as a `Date`. */
207
+ jd: number;
208
+ date: Date;
209
+ playing: boolean;
210
+ /** Simulated seconds per real second, and which way time runs. */
211
+ timeScale: number;
212
+ direction: 1 | -1;
213
+ /** The clock tracks wall-clock time. */
214
+ live: boolean;
215
+ }
216
+
217
+ /** What both maps take: where to put it, where its data comes from, and what
218
+ * language to read it in. */
219
+ declare interface CommonOptions {
220
+ /** The element to build the map in, or a selector that finds one. */
221
+ container: HTMLElement | string;
222
+ /** Root of the data export; the production CDN when omitted. Page-wide,
223
+ * like everything on the host: the last map created sets it, and data
224
+ * already fetched keeps the origin it came from. */
225
+ dataUrl?: string;
226
+ /** Root of the image export. Its own origin in production, since the data
227
+ * origin does not serve pictures; a mirror that serves both sets this to
228
+ * the same place as `dataUrl`. */
229
+ imagesUrl?: string;
230
+ /** BCP-47 tag that picks localized names; English when omitted. */
231
+ locale?: string;
232
+ /** Replaces the English wording the map renders itself, one key at a time. */
233
+ messages?: Partial<CoreMessages>;
234
+ /** Draw the imagery whose licence forbids commercial reuse — off by
235
+ * default, because only the page knows whether it is a commercial one.
236
+ * Turning it on covers the Uranus map, which otherwise renders in its
237
+ * fallback colour, and the Huygens descent panorama of Titan, which is
238
+ * otherwise a place on the map with no sphere to open; the page accepts
239
+ * each one's terms by asking for it, and the credit line naming its
240
+ * author is a condition of them, not a courtesy. Some maps are ours for
241
+ * spacemap.co alone and this does not reach them. */
242
+ includeNonCommercial?: boolean;
243
+ }
244
+
245
+ /** Replace the host: what an override leaves out goes back to its default, so
246
+ * a second embed on the page does not inherit the first one's settings.
247
+ * Messages are the one thing filled in key by key — an override names the few
248
+ * it wants reworded and the rest stay English. */
249
+ export declare function configureHost(overrides: HostOverrides): void;
250
+
251
+ /** One piece of chrome. `M` is the map it is written for. */
252
+ export declare interface Control<M = unknown> {
253
+ /** Build the element to place in the corner. Called once, when added. */
254
+ onAdd(map: M): HTMLElement;
255
+ /** Release whatever `onAdd` set up. The element itself is removed either way. */
256
+ onRemove?(map: M): void;
257
+ /** Corner to use when the host names none; top-right otherwise. */
258
+ getDefaultPosition?(): ControlPosition;
259
+ }
260
+
261
+ export declare type ControlPosition = 'top-left' | 'top-right' | 'bottom-left' | 'bottom-right';
262
+
263
+ /**
264
+ * What the core (scene, math, fetch) needs from whoever embeds it — the
265
+ * SvelteKit app today, the SDK later. Read lazily through {@link host} so the
266
+ * host can configure it at boot without import-order games; the defaults are
267
+ * what a bare embed gets. Conditions the scene reports back travel the other
268
+ * way, as map events.
269
+ */
270
+ /** Scene text the core renders itself; everything else is the host's to format.
271
+ * Spelled out rather than typed off the app's message bundle, which would
272
+ * put every message of the app into the SDK's types. */
273
+ export declare interface CoreMessages {
274
+ body_note_no_model: () => string;
275
+ body_note_no_radius: () => string;
276
+ carried_by_scene_label: (inputs: {
277
+ carrier: string;
278
+ }) => string;
279
+ scene_canvas_label: () => string;
280
+ attribution_orbits: () => string;
281
+ attribution_imagery: () => string;
282
+ credits_see_all: () => string;
283
+ layer_surface: () => string;
284
+ layer_clouds: () => string;
285
+ layer_night: () => string;
286
+ layer_graticule: () => string;
287
+ layer_nomenclature: () => string;
288
+ cooperative_wheel: () => string;
289
+ cooperative_wheel_mac: () => string;
290
+ cooperative_touch: () => string;
291
+ }
292
+
293
+ /**
294
+ * Conditions the scene reports while it runs: the clock has left the data, or
295
+ * it stopped at a probe's data wall. Raw dates and ids, never sentences — the
296
+ * page around the map words them and decides how they are shown.
297
+ */
298
+ /** A coverage edge the clock has crossed, and where it lies. */
299
+ export declare interface CoverageEdge {
300
+ side: 'before' | 'after';
301
+ jd: number;
302
+ }
303
+
304
+ /** The clock stopped at the focused probe's trajectory data wall. */
305
+ export declare interface CoveragePauseNotice {
306
+ topic: 'coverage-pause';
307
+ name: string;
308
+ direction: 'forward' | 'backward';
309
+ jd: number;
310
+ }
311
+
312
+ /** Mount a flat map of one body's surface and resolve once its first picture
313
+ * is loaded. Rejects when the body has no map texture or the data does not
314
+ * load. */
315
+ export declare function createFlatMap(options: FlatMapCreateOptions): Promise<FlatMap>;
316
+
317
+ /** Mount a map and resolve once it is worth looking at: the opening body
318
+ * placed, and the one-off quality benchmark done — that measures the GPU, so
319
+ * it must not run while the reader is already moving the camera. The small
320
+ * bodies go on streaming in behind the map this returns.
321
+ *
322
+ * Rejects when WebGL is unavailable, or when the data fails before there is
323
+ * anything to look at; a failure past that point arrives as an `error` event. */
324
+ export declare function createMap(options: MapOptions): Promise<SpaceMap>;
325
+
326
+ /** Stand inside a panorama and resolve once the first one is on screen. The
327
+ * three-dimensional part is all there is: the picture, the arrows to the
328
+ * neighbours on the traverse, and the credit line. What a page shows around
329
+ * it — the panorama's date and place, a list to pick from, a map of the
330
+ * traverse — is its own to build from {@link PanoramaView.getPanoramas},
331
+ * {@link PanoramaView.getNeighbours} and the `load` and `viewchange` events.
332
+ *
333
+ * Rejects when the body has no panoramas, or the one asked for is not among
334
+ * them; a failure past that point arrives as an `error` event. */
335
+ export declare function createPanorama(options: PanoramaCreateOptions): Promise<PanoramaView>;
336
+
337
+ /** Build a projection. The result is immutable — turning the globe or moving
338
+ * the central meridian means building another one, which costs nothing but
339
+ * the extent sampling. */
340
+ export declare function createProjection(id: ProjectionId, options?: ProjectionOptions): Projection;
341
+
342
+ /** Convert a JS Date to Julian Date. */
343
+ export declare function dateToJD(date: Date): number;
344
+
345
+ /** What a bare embed renders with: everything on, quality measured at boot and
346
+ * remembered per device. Reactive, so the calibration's tier reaches the
347
+ * renderer through the same effects a host's own store drives. */
348
+ export declare function defaultSceneSettings(): SceneSettings;
349
+
350
+ /**
351
+ * A Keplerian orbit, propagated from its epoch by the mean motion the elements
352
+ * carry. Defined at every date, so an object on one is always drawn.
353
+ */
354
+ export declare function elements(options: ElementsOptions): InertialAnchor;
355
+
356
+ export declare interface ElementsOptions {
357
+ /** What the orbit is round; the Sun when left out. */
358
+ body?: string;
359
+ /** The export's own elements: `a` in astronomical units, angles in degrees,
360
+ * `n` in degrees a day, `epoch` a Julian date. Set `equatorial` when the
361
+ * angles are referenced to Earth's equator rather than the ecliptic. */
362
+ elements: OrbitalElements;
363
+ }
364
+
365
+ export declare interface Extent {
366
+ minX: number;
367
+ minY: number;
368
+ maxX: number;
369
+ maxY: number;
370
+ }
371
+
372
+ /** A named surface feature, as a `featureselect` event carries it. */
373
+ export declare interface FeatureRef {
374
+ featureId: number;
375
+ /** Planetographic degrees, IAU convention. */
376
+ lat: number;
377
+ lon: number;
378
+ diameterM: number;
379
+ }
380
+
381
+ export declare interface FeatureSelect extends FeatureRef {
382
+ bodyId: string;
383
+ }
384
+
385
+ /** A move onto a named feature, which is the one thing the camera can turn to
386
+ * without travelling. */
387
+ export declare interface FeatureTarget extends CameraTarget {
388
+ feature: FeatureRef;
389
+ }
390
+
391
+ /** `fetcher` takes the `fetch` a SvelteKit `load` is handed, so the request
392
+ * joins the page's own load rather than starting a second one. */
393
+ export declare function fetchPanoramaIndex(fetcher?: (url: string) => Promise<Response>): Promise<PanoramaBodySummary[]>;
394
+
395
+ /** Every panorama taken on a body, mission by mission in time order. The view
396
+ * reads the same list when it opens; a page that decides which panorama to
397
+ * open reads it first. Empty when the body has none. */
398
+ export declare function fetchPanoramas(bodyId: string): Promise<PanoramaEntry[]>;
399
+
400
+ export declare function findPanorama(entries: PanoramaEntry[], at: string | null): PanoramaEntry | null;
401
+
402
+ /** A place that does not move: on a body's surface, or at a fixed offset from
403
+ * its centre. It is already an anchor — this names it beside the trajectories
404
+ * that do move. */
405
+ export declare function fixed(place: Anchor): Anchor;
406
+
407
+ export declare class FlatAttributionControl implements Control<FlatMap> {
408
+ private off;
409
+ onAdd(map: FlatMap): HTMLElement;
410
+ onRemove(): void;
411
+ getDefaultPosition(): ControlPosition;
412
+ }
413
+
414
+ export declare interface FlatBoxOptions extends FlatShapeStyle {
415
+ latMin: number;
416
+ latMax: number;
417
+ lonMin: number;
418
+ /** Degrees of longitude the box covers, east from `lonMin`. */
419
+ lonSpan: number;
420
+ }
421
+
422
+ export declare interface FlatCircleOptions extends FlatShapeStyle {
423
+ center: LonLat;
424
+ /** Radius as an angle at the body's centre. */
425
+ radiusDeg?: number;
426
+ /** Radius along the surface. Needs the body's radius to be known — see
427
+ * `FlatMap.bodyRadiusKm`; ignored when it is not. */
428
+ radiusKm?: number;
429
+ }
430
+
431
+ export declare class FlatMap {
432
+ private container;
433
+ private readonly root;
434
+ private readonly canvas;
435
+ private readonly svg;
436
+ private readonly layerGroup;
437
+ private readonly shapeGroup;
438
+ private readonly markerLayer;
439
+ private readonly ctx;
440
+ /* Excluded from this release type: overlay */
441
+ private bodyId;
442
+ private sources;
443
+ private layerList;
444
+ private projection;
445
+ private projectionId;
446
+ private projectionOptions;
447
+ private view;
448
+ private limits;
449
+ /** The reader has moved the view since the last programmatic one, so the
450
+ * limits apply to it. A {@link setView} lands where it was told. */
451
+ private limitsArmed;
452
+ private jd;
453
+ private cooperative;
454
+ /** The body's mean radius, so a circle can be drawn in kilometres. */
455
+ bodyRadiusKm: number | null;
456
+ /** The pictures this map draws, by URL, with the key of its claim on the
457
+ * shared store. Other maps of the same body claim the same pictures. */
458
+ private readonly bitmaps;
459
+ private readonly rasters;
460
+ private readonly pending;
461
+ /** Pictures the export does not have. Remembered, or every pan would ask
462
+ * for them again and report the same failure. */
463
+ private readonly missing;
464
+ /** Bumped whenever the map moves to another body, so work started for the
465
+ * one being left can tell that it is no longer wanted. */
466
+ private generation;
467
+ /** Teardowns for controls mounted inside the map's box. */
468
+ private controls;
469
+ /* Excluded from this release type: attribution */
470
+ /** Dragging the map about — a globe turns, a rectangle slides. */
471
+ readonly dragPan: GestureHandler;
472
+ /** The wheel and the pinch. */
473
+ readonly scrollZoom: GestureHandler;
474
+ /** The wheel and one finger belong to the page, not the map. */
475
+ readonly cooperativeGestures: GestureHandler;
476
+ private lookup;
477
+ private lookupKey;
478
+ private buffer;
479
+ private frame;
480
+ private resizeObserver;
481
+ private readonly listeners;
482
+ private announcedReady;
483
+ private disposed;
484
+ /** Set while a gesture is in flight, to draw coarsely until it stops. */
485
+ private moving;
486
+ /** The width of a settled frame, in device pixels. */
487
+ private sharpWidth;
488
+ /** Running cost of one drawn pixel, which sets the resolution of a moving
489
+ * frame. Zero until the first draw has been timed. */
490
+ private msPerPixel;
491
+ private settleTimer;
492
+ /** Which layers have been asked for, by id — the host's opening choice and
493
+ * every change since. Kept apart from the layers themselves, which are
494
+ * rebuilt per body: what the reader switched on should outlast a body that
495
+ * happens not to have it. */
496
+ private readonly chosenVisibility;
497
+ /** Layers the host added itself. Kept aside from the body's own, so
498
+ * changing body rebuilds one set without discarding the other. */
499
+ private readonly customLayers;
500
+ constructor(options?: FlatMapOptions);
501
+ /* Excluded from this release type: mount */
502
+ /** Hang a control in one of the map's corners; top-right unless the control
503
+ * or the caller names another. Adding the same control twice does nothing. */
504
+ addControl(control: Control<FlatMap>, position?: ControlPosition): this;
505
+ /** Take a control back off. The credit line is not one a host may remove —
506
+ * the imagery terms the pictures are published under require it. */
507
+ removeControl(control: Control<FlatMap>): this;
508
+ /** Take the map back out of its container. It is finished afterwards; open
509
+ * another with {@link createFlatMap}. */
510
+ remove(): void;
511
+ /* Excluded from this release type: unmount */
512
+ /* Excluded from this release type: load */
513
+ /**
514
+ * Take a body on: find out what it has, and only then show it.
515
+ *
516
+ * Nothing of the body already on screen is let go until the new one is known
517
+ * to have a map at all, so asking for a body that has none leaves the map as
518
+ * it was and rejects, rather than emptying it first.
519
+ */
520
+ private adopt;
521
+ /** Let go of the pictures and the layers of the body being left behind. The
522
+ * generation moves with them, so a fetch still in flight for that body
523
+ * drops what it decodes instead of holding it for nothing. */
524
+ private release;
525
+ private buildLayers;
526
+ /** Every layer of the body on screen, in drawing order, with the label and
527
+ * the credit each carries. */
528
+ get layers(): LayerInfo[];
529
+ /** The layer ids alone, so a switcher can be built the same way on either
530
+ * map. Which ids there are depends on the body: not every one has clouds
531
+ * or a night side. */
532
+ getLayers(): string[];
533
+ isLayerVisible(id: string): boolean;
534
+ /** Credits for everything currently drawn — what the embed has to show. */
535
+ get credits(): LayerCredit[];
536
+ setLayerVisible(id: string, visible: boolean): void;
537
+ setLayerOpacity(id: string, opacity: number): void;
538
+ /** A picture of the host's own, wrapped round the body the same way the
539
+ * export's are: longitude across, latitude down, −180° at the left edge. */
540
+ addRasterLayer(spec: {
541
+ id: string;
542
+ label?: string;
543
+ url: string;
544
+ opacity?: number;
545
+ blend?: 'normal' | 'add';
546
+ visible?: boolean;
547
+ credit?: LayerCredit;
548
+ }): void;
549
+ /** A layer the host draws itself, given the view to draw for. Where a
550
+ * vector terrain map or a coverage grid goes. */
551
+ addVectorLayer(spec: {
552
+ id: string;
553
+ label?: string;
554
+ visible?: boolean;
555
+ credit?: LayerCredit;
556
+ render: VectorLayer['render'];
557
+ prepare?: VectorLayer['prepare'];
558
+ }): void;
559
+ get projectionName(): ProjectionId;
560
+ static get projections(): readonly ProjectionId[];
561
+ setProjection(id: ProjectionId, options?: ProjectionOptions): void;
562
+ /** Where the map is, as a place rather than as plane coordinates — the
563
+ * middle of the frame. A globe is turned to face it and a rectangle is slid
564
+ * to it, so what {@link setView} is given is what this reads back. */
565
+ get viewState(): FlatViewState;
566
+ setView(view: Partial<FlatViewState>): void;
567
+ /**
568
+ * Replace the reader's limits, whole. What the new set leaves out is
569
+ * unrestricted again, except `maxZoom`, which goes back to 16.
570
+ *
571
+ * Limits gate reader input only: {@link setView} lands where it was told,
572
+ * and the reader's next gesture brings the view back inside.
573
+ */
574
+ setLimits(limits: FlatMapLimits): this;
575
+ /** The limits as they stand. */
576
+ getLimits(): FlatMapLimits;
577
+ /** The moment the map is of. Moves the clouds and, on Earth, the season. */
578
+ setTime(jd: number): void;
579
+ setBody(bodyId: string): Promise<void>;
580
+ /** Screen pixel for a place, relative to the map's own box. */
581
+ project(lon: number, lat: number): [number, number] | null;
582
+ /** The place under a pixel of the map's box, or null off the world. */
583
+ unproject(px: number, py: number): LonLat | null;
584
+ addPolyline(options: FlatPolylineOptions): FlatShape;
585
+ addPolygon(options: FlatPolygonOptions): FlatShape;
586
+ addBox(options: FlatBoxOptions): FlatShape;
587
+ addCircle(options: FlatCircleOptions): FlatShape;
588
+ addMarker(options: FlatMarkerOptions): FlatMarker;
589
+ /** Remove every drawing the host has added, leaving the layers alone. */
590
+ clearDrawings(): void;
591
+ /** Listen for `event`. The returned function stops listening, which is the
592
+ * same thing {@link off} does. */
593
+ on<K extends keyof FlatMapEvents>(event: K, listener: FlatMapEvents[K]): () => void;
594
+ /** Listen for the next `event` only. */
595
+ once<K extends keyof FlatMapEvents>(event: K, listener: FlatMapEvents[K]): () => void;
596
+ off<K extends keyof FlatMapEvents>(event: K, listener: FlatMapEvents[K]): void;
597
+ private emit;
598
+ private tier;
599
+ /**
600
+ * How many pixels across the world this view can show.
601
+ *
602
+ * An equirectangular map draws the picture at the width of the world. Every
603
+ * other projection samples a readable copy, which has a maximum width. A
604
+ * finer tier than this shows nothing more. It only costs a larger decode,
605
+ * which is hundreds of megabytes for a 16k picture.
606
+ */
607
+ private usableSourceWidth;
608
+ /** The width of a settled frame, in device pixels. A gesture makes the
609
+ * canvas coarse, but the picture copy stays at this width. */
610
+ private deviceWidth;
611
+ /** The width of the readable copy. It holds about two times the detail the
612
+ * view shows. The power of two lets a zoom gesture reuse one copy. */
613
+ private workingWidth;
614
+ /** The width a picture is decoded at. The resampler reads no more than its
615
+ * working width, and no tier holds more than its own. An equirectangular
616
+ * map draws the picture whole. */
617
+ private decodeWidth;
618
+ /** The pictures the view needs, each with the tier it is taken from. */
619
+ private picturesInUse;
620
+ /** Fetch and decode whatever the current view needs but has not got. */
621
+ private loadVisible;
622
+ /** Release the pictures of a tier the view has left behind. */
623
+ private dropUnused;
624
+ /** Hold a picture for a URL and release the one held before. A map draws
625
+ * one size of a picture at a time. */
626
+ private hold;
627
+ /** The readable copy the resampler samples, from the shared store. */
628
+ private rasterFor;
629
+ /** Release every claim this map holds on the shared pictures. */
630
+ private dropTextures;
631
+ private viewport;
632
+ /** Draw on the next frame. Repeated calls in one frame draw once. */
633
+ render(): void;
634
+ /** Draw coarsely now and sharply when the movement stops. */
635
+ private renderMoving;
636
+ private draw;
637
+ /**
638
+ * What one pixel of the last few resampled frames cost, in milliseconds.
639
+ * Kept as a running mean so one slow frame — the browser busy elsewhere —
640
+ * does not decide the resolution on its own.
641
+ */
642
+ private record;
643
+ /**
644
+ * The fraction of full resolution a moving frame is drawn at, from what the
645
+ * projection has been measured to cost rather than from a list of which ones
646
+ * are slow. A projection that fits the budget is left alone.
647
+ *
648
+ * `full` is the pixel count the frame would have at full resolution, not the
649
+ * count the last frame happened to be drawn at — measuring against a canvas
650
+ * that is already coarse would let the scale chase its own tail.
651
+ */
652
+ private interactionScale;
653
+ /** The rim of a globe is cut by the compositor rather than left to the
654
+ * raster, whose staircase would show whenever it is drawn coarsely. */
655
+ private clipToDisc;
656
+ private drawRaster;
657
+ private drawVector;
658
+ /** One finger drags the page, so the browser needs it back. */
659
+ private applyCooperative;
660
+ private attachInteraction;
661
+ /**
662
+ * A drag turns a globe and slides a rectangle. Both keep the place under
663
+ * the pointer roughly under it, which is what makes the gesture feel like
664
+ * moving the map rather than moving a camera.
665
+ */
666
+ private drag;
667
+ /** Zoom about a point, so what is under the pointer stays under it. */
668
+ private zoomBy;
669
+ }
670
+
671
+ export declare interface FlatMapCreateOptions extends CommonOptions, FlatMapOptions {
672
+ controls?: Control<FlatMap>[];
673
+ /** Listeners attached before the first load, so a slow or failed load is
674
+ * observable while it runs. Later ones go through {@link FlatMap.on}. */
675
+ events?: {
676
+ [K in keyof FlatMapEvents]?: FlatMapEvents[K];
677
+ };
678
+ }
679
+
680
+ export declare interface FlatMapEvents {
681
+ /** The first surface picture is on screen. */
682
+ ready: () => void;
683
+ error: (error: Error) => void;
684
+ viewchange: (view: FlatViewState) => void;
685
+ layerschange: (layers: LayerInfo[]) => void;
686
+ /** Where the reader clicked, or null for a click off the world. */
687
+ click: (at: LonLat | null, event: PointerEvent) => void;
688
+ pointermove: (at: LonLat | null, event: PointerEvent) => void;
689
+ }
690
+
691
+ /** The gestures the flat map hangs a handler off for. */
692
+ export declare type FlatMapGesture = 'dragPan' | 'scrollZoom';
693
+
694
+ /**
695
+ * How far the reader may take the view. Everything left out is unrestricted,
696
+ * beyond the two things the map holds to whatever it is told: the whole world
697
+ * is the furthest out it goes, and the frame is never let off the map.
698
+ *
699
+ * These gate reader input and nothing else. {@link FlatMap.setView} goes where
700
+ * it is told, outside the limits included; the reader's next gesture brings the
701
+ * view back inside.
702
+ */
703
+ export declare interface FlatMapLimits {
704
+ /** 1 is the whole world; the reader may not go under it either way. */
705
+ minZoom?: number;
706
+ maxZoom?: number;
707
+ /** The band of the surface the middle of the frame may sit in. A longitude
708
+ * band may run through the antimeridian: 170 to −170 is the twenty degrees
709
+ * across it. One edge alone leaves the other at the antimeridian. */
710
+ minLon?: number;
711
+ maxLon?: number;
712
+ minLat?: number;
713
+ maxLat?: number;
714
+ }
715
+
716
+ export declare interface FlatMapOptions {
717
+ /** Body to draw, by export id — `"naif-399"` for Earth, `"naif-499"` for
718
+ * Mars. Earth when left out. */
719
+ body?: string;
720
+ projection?: ProjectionId;
721
+ /** Meridian and parallel the map is centred on. The parallel only turns the
722
+ * two globe projections; the others are always centred on the equator. */
723
+ centerLon?: number;
724
+ centerLat?: number;
725
+ /** How far from the centre a globe projection reaches, in degrees. */
726
+ clipAngle?: number;
727
+ /** 1 shows the whole world. */
728
+ zoom?: number;
729
+ /** The moment the map is of, which picks the cloud snapshot and the month
730
+ * of a seasonal surface. Now when left out. */
731
+ jd?: number;
732
+ /** Which layers start switched on, by id. The surface always is. */
733
+ layers?: Record<string, boolean>;
734
+ /** Whether the reader may move the map at all. True unless it is said
735
+ * otherwise; false switches every gesture off. */
736
+ interactive?: boolean;
737
+ /** Gestures to start on or off one at a time, over whatever `interactive`
738
+ * said. Each is a handler on the map afterwards. */
739
+ interactions?: Partial<Record<FlatMapGesture, boolean>>;
740
+ /** The map inside a page the reader scrolls past: the wheel scrolls the page
741
+ * unless ctrl (⌘ on a Mac) is held, and one finger drags the page rather
742
+ * than the map. A hint says so whenever the plain gesture is tried. */
743
+ cooperativeGestures?: boolean;
744
+ /** How far the reader may take the view. Reader input only — see
745
+ * {@link FlatMap.setLimits}. */
746
+ limits?: FlatMapLimits;
747
+ }
748
+
749
+ export declare interface FlatMarker {
750
+ readonly element: HTMLElement;
751
+ setPosition(at: LonLat): void;
752
+ setVisible(visible: boolean): void;
753
+ remove(): void;
754
+ }
755
+
756
+ export declare interface FlatMarkerOptions {
757
+ at: LonLat;
758
+ /** The host's element, placed over the map as it is. A plain dot when left
759
+ * out. */
760
+ element?: HTMLElement;
761
+ /** Which point of the element sits on the place, 0 to 1 in its own box.
762
+ * Its centre by default. */
763
+ align?: readonly [number, number];
764
+ className?: string;
765
+ /** Take pointer events. Off by default, as for a shape: the map is dragged
766
+ * through the marker layer unless a marker opts back in. */
767
+ interactive?: boolean;
768
+ }
769
+
770
+ export declare interface FlatPolygonOptions extends Omit<FlatPolylineOptions, 'closed'> {
771
+ points: readonly LonLat[];
772
+ }
773
+
774
+ export declare interface FlatPolylineOptions extends FlatShapeStyle {
775
+ points: readonly LonLat[];
776
+ /** How the space between the given points is filled: along the parallels
777
+ * and meridians, or the short way over the sphere. */
778
+ interpolate?: Interpolation;
779
+ /** Join the last point back to the first. */
780
+ closed?: boolean;
781
+ }
782
+
783
+ /** A drawing on the map, for as long as the host keeps it. */
784
+ export declare interface FlatShape {
785
+ /** The element itself, for a host that wants to style or animate it: a
786
+ * group holding the shape's outline and, for an area, its fill, drawn
787
+ * apart so the fill can stop at the limb of a globe where the outline
788
+ * goes out of sight. */
789
+ readonly node: SVGGElement;
790
+ /** Replace the geometry, keeping the styling. */
791
+ setPoints(points: readonly LonLat[]): void;
792
+ setVisible(visible: boolean): void;
793
+ remove(): void;
794
+ }
795
+
796
+ export declare interface FlatShapeStyle {
797
+ /** Stroke colour: any CSS colour. White when left out. */
798
+ color?: string;
799
+ /** Stroke width in screen pixels, held at every zoom. */
800
+ widthPx?: number;
801
+ /** 0 to 1, over the whole shape. */
802
+ opacity?: number;
803
+ /** Fill colour for an area. Unfilled when left out. */
804
+ fill?: string;
805
+ fillOpacity?: number;
806
+ /** SVG dash pattern, e.g. `"4 3"`. */
807
+ dash?: string;
808
+ /** Added to the element, for styling from the host's own stylesheet. */
809
+ className?: string;
810
+ /** Take pointer events. Off by default, so drawings never get in the way of
811
+ * panning the map under them. */
812
+ interactive?: boolean;
813
+ onclick?: (event: PointerEvent) => void;
814
+ onpointerenter?: (event: PointerEvent) => void;
815
+ onpointerleave?: (event: PointerEvent) => void;
816
+ /** Names the shape for a screen reader, which also makes it focusable. */
817
+ ariaLabel?: string;
818
+ }
819
+
820
+ export declare interface FlatViewState {
821
+ projection: ProjectionId;
822
+ zoom: number;
823
+ centerLon: number;
824
+ centerLat: number;
825
+ }
826
+
827
+ export declare interface FocusChange {
828
+ body: Body_2 | undefined;
829
+ /** The first settle after boot. */
830
+ initial: boolean;
831
+ /** The camera orbits a surface feature; `body` is its host. */
832
+ feature: boolean;
833
+ }
834
+
835
+ /**
836
+ * One reader gesture, switched on and off on its own. Mapbox hangs a handler
837
+ * like this off the map for each gesture it knows, and both maps here do the
838
+ * same, so `map.scrollZoom.disable()` reads alike on either of them.
839
+ */
840
+ export declare class GestureHandler {
841
+ private enabled;
842
+ private readonly apply;
843
+ /* Excluded from this release type: __constructor */
844
+ enable(): void;
845
+ disable(): void;
846
+ isEnabled(): boolean;
847
+ private set;
848
+ }
849
+
850
+ /** Meridians and parallels every `stepDeg`, each as its own run of places.
851
+ * Meridians are drawn pole to pole and parallels right round, so the grid
852
+ * bends with whatever projection draws it. */
853
+ export declare function graticule(stepDeg?: number): LonLat[][];
854
+
855
+ /** Great-circle distance on a sphere of `radiusKm`, in metres. Rover steps
856
+ * are metres on a body thousands of kilometres across, so the ellipsoid's
857
+ * flattening changes nothing a reader would see. Any two places will do: a
858
+ * panorama is one, and so is a point a reader named. */
859
+ export declare function groundDistanceM(a: LonLat, b: LonLat, radiusKm: number): number;
860
+
861
+ export declare interface Host {
862
+ /** Root of the data export; versioned files hang off it. */
863
+ dataUrl: string;
864
+ /** Root of the image export, on its own origin in production. */
865
+ imagesUrl: string;
866
+ /** Root of the live tracking feed, rewritten every few minutes on an origin
867
+ * of its own so it never waits on a catalogue deploy. */
868
+ liveUrl: string;
869
+ /** BCP-47 tag of the reading language: picks localized names and drives Intl. */
870
+ locale: () => string;
871
+ messages: CoreMessages;
872
+ /** Link target of a body's scene label. */
873
+ bodyHref: (id: string, name: string) => string;
874
+ /** How far down the `distribution` ladder this embed may draw surface maps
875
+ * (docs/export-format/textures.md). `open` is the maps anyone may serve,
876
+ * `non-commercial` adds those whose licence bars commercial reuse, and
877
+ * `site-only` adds those cleared for spacemap.co alone. A bare embed gets
878
+ * `open`: it cannot accept a licence for the page it sits on. */
879
+ textures: TextureDistribution;
880
+ }
881
+
882
+ /** Overrides, with messages filled in one key at a time. */
883
+ export declare type HostOverrides = Partial<Omit<Host, 'messages'>> & {
884
+ messages?: Partial<CoreMessages>;
885
+ };
886
+
887
+ export declare interface Icon extends Shape {
888
+ /** The `<img>` itself, for a host that wants to listen to it or style it
889
+ * further. */
890
+ readonly element: HTMLImageElement;
891
+ setUrl(url: string): void;
892
+ }
893
+
894
+ export declare interface IconOptions {
895
+ anchor: Anchor;
896
+ /** Where the picture comes from. Anything an `<img>` takes, a data URL
897
+ * included. */
898
+ url: string;
899
+ /** Width in screen pixels. The picture's own width when left out. */
900
+ widthPx?: number;
901
+ /** Height in screen pixels. Follows the width when left out. */
902
+ heightPx?: number;
903
+ /** Which point of the picture sits on the anchor, 0 to 1 in its own box.
904
+ * Defaults to its centre. */
905
+ align?: readonly [number, number];
906
+ /** Hide it when its place has turned to the far side of the body it sits
907
+ * on. */
908
+ occlude?: boolean;
909
+ /** 0 to 1. */
910
+ opacity?: number;
911
+ /** Take pointer events, so the host's own listeners on {@link Icon.element}
912
+ * fire. Off by default: the camera is dragged through the label layer. */
913
+ interactive?: boolean;
914
+ className?: string;
915
+ /** Describes the picture to a screen reader. Empty by default, which is
916
+ * what a decorative picture should say. */
917
+ alt?: string;
918
+ }
919
+
920
+ /** Fixed in the body's inertial frame: it travels with the body but does not
921
+ * turn with it. The body's centre when the offset is left out. An offset read
922
+ * from a function is a trajectory — see {@link samples}, {@link elements} and
923
+ * {@link tle} — and a date it says nothing about returns null, which leaves
924
+ * whatever the anchor carries undrawn. */
925
+ export declare interface InertialAnchor {
926
+ body: string;
927
+ offsetKm?: OffsetKm | ((jd: number) => OffsetKm | null);
928
+ }
929
+
930
+ /** How the space between two given points is filled in. */
931
+ export declare type Interpolation =
932
+ /** Even in longitude and latitude — what a chart box or a graticule wants,
933
+ * since its edges follow the parallels and meridians. */
934
+ 'linear'
935
+ /** The short way over the sphere, which is what a flight path or a ground
936
+ * track means by a straight line. */
937
+ | 'geodesic';
938
+
939
+ /** Convert a Julian Date to a JS Date. */
940
+ export declare function jdToDate(jd: number): Date;
941
+
942
+ /** The same, for a move that does not animate: framing a body against another
943
+ * one only makes sense as a placement, never as a flight. */
944
+ export declare interface JumpTarget extends CameraTarget {
945
+ /** Put this other body — the Sun, usually — behind the one being framed. */
946
+ facing?: string;
947
+ /** How far above the ecliptic to look from, in degrees. */
948
+ elevationDeg?: number;
949
+ }
950
+
951
+ /** Kilometres as astronomical units. Orbital elements are quoted with their
952
+ * semi-major axis in AU wherever the map reads them, and that is the one
953
+ * distance on the public surface which is not in kilometres. */
954
+ export declare function kmToAu(km: number): number;
955
+
956
+ export declare interface Label extends Shape {
957
+ /** The element the text is in, for a host that wants to listen to it or
958
+ * style it further. */
959
+ readonly element: HTMLElement;
960
+ setText(text: string): void;
961
+ }
962
+
963
+ export declare interface LabelOptions {
964
+ anchor: Anchor;
965
+ text: string;
966
+ /** Any CSS colour. White when left out. */
967
+ color?: string;
968
+ fontSizePx?: number;
969
+ /** Which point of the text sits on the anchor, 0 to 1 in its own box.
970
+ * Defaults to its centre. */
971
+ align?: readonly [number, number];
972
+ /** Hide the label when its place has turned to the far side of the body it
973
+ * sits on. */
974
+ occlude?: boolean;
975
+ /** Take pointer events, so the host's own listeners on {@link Label.element}
976
+ * fire. Off by default: the camera is dragged through the label layer. */
977
+ interactive?: boolean;
978
+ /** Added to the element, for styling from the host's own stylesheet. */
979
+ className?: string;
980
+ }
981
+
982
+ export declare type Layer = RasterLayer | VectorLayer;
983
+
984
+ /** Who a layer's imagery belongs to. Carried up to the credit line, which the
985
+ * data's terms require an embed to show. */
986
+ export declare interface LayerCredit {
987
+ organisation: string;
988
+ source: string;
989
+ attribution?: string;
990
+ }
991
+
992
+ /** A layer as a host sees it. */
993
+ export declare interface LayerInfo {
994
+ id: string;
995
+ label: string;
996
+ kind: 'raster' | 'vector';
997
+ visible: boolean;
998
+ credit?: LayerCredit;
999
+ }
1000
+
1001
+ /** A place. Longitude east-positive, latitude north-positive, both degrees. */
1002
+ export declare interface LonLat {
1003
+ lon: number;
1004
+ lat: number;
1005
+ }
1006
+
1007
+ /** Every layer, in the order a switcher should offer them: the objects first,
1008
+ * then the chrome drawn around them. */
1009
+ export declare const MAP_LAYERS: readonly ["planets", "dwarfPlanets", "moons", "asteroids", "comets", "spacecraft", "satellites", "debris", "orbits", "labels", "nomenclature", "stars"];
1010
+
1011
+ export declare interface MapEvents {
1012
+ focuschange: (e: FocusChange) => void;
1013
+ /** The camera came to rest around the focused body. */
1014
+ camera: (view: CameraState) => void;
1015
+ /** A nomenclature label was clicked; carries what a fly-to needs. */
1016
+ featureselect: (e: FeatureSelect) => void;
1017
+ /** User-promoted bodies that can be cleared (the focused one excluded). */
1018
+ userpromoted: (count: number) => void;
1019
+ contextlost: () => void;
1020
+ contextrestored: () => void;
1021
+ /** The clock moved, or its play state, rate or direction changed. */
1022
+ clock: (e: ClockState) => void;
1023
+ /** Data loading started or finished, the one-off quality benchmark
1024
+ * included; `false` means the map is ready to look at. */
1025
+ loading: (loading: boolean) => void;
1026
+ /** Boot progress, 0 to 1, monotonic within one load. */
1027
+ progress: (fraction: number) => void;
1028
+ /** The data could not be loaded. The map stays mounted and empty. */
1029
+ error: (message: string) => void;
1030
+ /** The export was republished while this map was open: its data is now a
1031
+ * version behind, and reloading the page picks the new one up. */
1032
+ datastale: () => void;
1033
+ /** A condition worth telling the reader about; one live notice per topic. */
1034
+ notice: (notice: Notice) => void;
1035
+ /** That topic's condition cleared. */
1036
+ noticedismiss: (topic: NoticeTopic) => void;
1037
+ /** A layer was switched, by the host or by a control on the map. Carries
1038
+ * the ids left visible, which is what a switcher redraws from. */
1039
+ layerschange: (visible: MapLayerId[]) => void;
1040
+ /** Once per drawn frame, with the bodies at that frame's positions and the
1041
+ * camera not yet moved. `dtMs` is 0 after a skipped frame. */
1042
+ frame: (e: {
1043
+ jd: number;
1044
+ dtMs: number;
1045
+ }) => void;
1046
+ }
1047
+
1048
+ /** The gestures the map hangs a handler off for. */
1049
+ export declare type MapGesture = 'dragRotate' | 'scrollZoom' | 'keyboard' | 'bodySelect' | 'featureSelect';
1050
+
1051
+ export declare type MapLayerId = (typeof MAP_LAYERS)[number];
1052
+
1053
+ /** A host's object on the map, for as long as the host keeps it. */
1054
+ export declare interface MapObject {
1055
+ readonly id: string;
1056
+ readonly name: string | null;
1057
+ /** Where it is, as the anchor it was given — hand it to a camera hold to
1058
+ * follow the object, or to a drawing to hang something off it. */
1059
+ readonly position: Anchor;
1060
+ /** Kilometres from the body it is measured from, on ecliptic J2000 axes, at
1061
+ * `jd`. Null where the trajectory says nothing; a fixed place on a surface
1062
+ * answers null too, since it is not measured as an offset. */
1063
+ positionKm(jd: number): readonly [number, number, number] | null;
1064
+ /** Move it, including onto another body or another trajectory. */
1065
+ setPosition(position: Anchor): void;
1066
+ setVisible(visible: boolean): void;
1067
+ remove(): void;
1068
+ }
1069
+
1070
+ export declare interface MapObjectModel {
1071
+ /** The host's own three.js object, added to the map's scene as it is. The
1072
+ * map never loads one: build it, or load it with a loader of your own. */
1073
+ object3d: Object3D;
1074
+ /** How big it is drawn, in metres across its longest dimension — the real
1075
+ * size of the craft, arrays and booms deployed. Drawn in the units the
1076
+ * object3d was built in when left out. */
1077
+ scaleM?: number;
1078
+ /** Never draw it smaller than this many pixels across. A twelve-metre
1079
+ * satellite is nothing at all from a planetary view; this keeps it
1080
+ * visible, at the cost of its true size. */
1081
+ minPx?: number;
1082
+ }
1083
+
1084
+ export declare interface MapObjectOptions {
1085
+ /** The host's own id, unique on this map. One is made up when left out. */
1086
+ id?: string;
1087
+ /** What it is called, for the label and for the host's own use. */
1088
+ name?: string;
1089
+ /** Where it is, at any date: a fixed place, or a trajectory. */
1090
+ position: Anchor;
1091
+ model?: MapObjectModel;
1092
+ /** Write the name beside it, in the map's own way of drawing a label. */
1093
+ label?: boolean;
1094
+ /** Hide the label while the object is behind the body it is measured from.
1095
+ * The model is hidden by the body itself, whatever this says. */
1096
+ occludeLabel?: boolean;
1097
+ }
1098
+
1099
+ /**
1100
+ * The objects a host has put on the map, by id. Adding one draws it from the
1101
+ * next frame; removing one takes it away with whatever it drew.
1102
+ */
1103
+ export declare interface MapObjects {
1104
+ /** Put an object on the map. An id already in use is replaced, so a host
1105
+ * driving the collection from its own state does not double up. */
1106
+ add(options: MapObjectOptions): MapObject;
1107
+ get(id: string): MapObject | undefined;
1108
+ /** Every object on the map, in the order they were added. */
1109
+ all(): MapObject[];
1110
+ /** Take them all away. The map's own drawings are left alone. */
1111
+ clear(): void;
1112
+ }
1113
+
1114
+ export declare interface MapOptions extends CommonOptions, SpaceMapOptions {
1115
+ /** Controls to hang on the map, each in the corner it asks for. The credit
1116
+ * line is always there and is not one of them. */
1117
+ controls?: Control<SpaceMap>[];
1118
+ /** Listeners attached before the first load, so the boot's `progress`,
1119
+ * `loading` and `error` events are observable while it runs. Later ones go
1120
+ * through {@link SpaceMap.on}. */
1121
+ events?: {
1122
+ [K in keyof MapEvents]?: MapEvents[K];
1123
+ };
1124
+ }
1125
+
1126
+ /** A marker on the map, for as long as the host keeps it. */
1127
+ export declare interface Marker {
1128
+ readonly element: HTMLElement;
1129
+ /** Move it, including onto another body. */
1130
+ setAnchor(anchor: Anchor): void;
1131
+ /** Show or hide it without giving up its place. */
1132
+ setVisible(visible: boolean): void;
1133
+ remove(): void;
1134
+ }
1135
+
1136
+ export declare interface MarkerOptions {
1137
+ anchor: Anchor;
1138
+ /** The host's element. It is moved into the map's label layer as it is,
1139
+ * keeping its own classes and listeners. */
1140
+ element: HTMLElement;
1141
+ /** Which point of the element sits on the anchor, 0 to 1 in its own box.
1142
+ * Defaults to its centre. */
1143
+ align?: readonly [number, number];
1144
+ /** Hide the marker when its place has turned to the far side of the body
1145
+ * it sits on. Only that body is tested, never another one in front. */
1146
+ occlude?: boolean;
1147
+ }
1148
+
1149
+ export declare interface Neighbour {
1150
+ entry: PanoramaEntry;
1151
+ /** Ground distance from the current panorama, metres. */
1152
+ distanceM: number;
1153
+ /** Initial bearing to it, degrees clockwise from north. */
1154
+ bearingDeg: number;
1155
+ }
1156
+
1157
+ export declare interface Neighbours {
1158
+ previous: Neighbour | null;
1159
+ next: Neighbour | null;
1160
+ }
1161
+
1162
+ /** The entries before and after `current` on the same mission's traverse.
1163
+ * The list is already mission-then-time ordered, so neighbours are adjacent
1164
+ * rows until the mission changes. */
1165
+ export declare function neighboursOf(entries: PanoramaEntry[], current: PanoramaEntry, radiusKm: number): Neighbours;
1166
+
1167
+ export declare type Notice = OutOfRangeNotice | CoveragePauseNotice;
1168
+
1169
+ export declare type NoticeTopic = Notice['topic'];
1170
+
1171
+ /** Kilometres on ecliptic J2000 axes, x toward the equinox and z toward the
1172
+ * ecliptic north pole. */
1173
+ export declare type OffsetKm = readonly [number, number, number];
1174
+
1175
+ export declare interface OrbitalElements {
1176
+ a: number;
1177
+ e: number;
1178
+ i: number;
1179
+ om: number;
1180
+ w: number;
1181
+ ma: number;
1182
+ n: number;
1183
+ epoch: number;
1184
+ /**
1185
+ * Secular drift rates (deg/day) applied to om and w. Populated for SPICE
1186
+ * moons via the Method C mean-element fit so the propagated orbit tracks
1187
+ * J2-driven nodal/apsidal precession. Absent (or zero) means the angles
1188
+ * are static — the default for Horizons/SBDB-sourced bodies.
1189
+ */
1190
+ omDot?: number;
1191
+ wDot?: number;
1192
+ q?: number;
1193
+ tp?: number;
1194
+ /**
1195
+ * True when i/om/w are referenced to Earth's mean equator of J2000 instead of
1196
+ * the ecliptic. TLE-sourced Earth satellites (CelesTrak) are in TEME, treated
1197
+ * here as equatorial; everything else (Horizons/SPICE) is ecliptic J2000.
1198
+ */
1199
+ equatorial?: boolean;
1200
+ }
1201
+
1202
+ /** Dynamical family of an asteroid, from its SBDB orbit class. */
1203
+ export declare type OrbitClass = 'inner' | 'main-belt' | 'trojan' | 'centaur' | 'tno';
1204
+
1205
+ /** Which groups lack data at the current time. */
1206
+ export declare interface OutOfRangeNotice {
1207
+ topic: 'out-of-range';
1208
+ focusedOutOfRange: boolean;
1209
+ /** Zone-level satellite coverage: past the archive, or inside a hole. */
1210
+ satellites: {
1211
+ side: 'after';
1212
+ jd: number;
1213
+ } | {
1214
+ side: 'gap';
1215
+ } | null;
1216
+ majorBodies: CoverageEdge | {
1217
+ side: 'outside';
1218
+ } | null;
1219
+ }
1220
+
1221
+ /** The product id, which names one panorama and no other. A stop held for
1222
+ * days leaves several mosaics sharing a time and a place, so the time and
1223
+ * place together do not. */
1224
+ export declare function panoramaAt(entry: PanoramaEntry): string;
1225
+
1226
+ export declare class PanoramaAttributionControl implements Control<PanoramaView> {
1227
+ private off;
1228
+ onAdd(view: PanoramaView): HTMLElement;
1229
+ onRemove(): void;
1230
+ getDefaultPosition(): ControlPosition;
1231
+ }
1232
+
1233
+ export declare interface PanoramaBodySummary {
1234
+ id: string;
1235
+ missions: PanoramaMissionSummary[];
1236
+ }
1237
+
1238
+ export declare interface PanoramaCreateOptions extends CommonOptions, PanoramaViewOptions {
1239
+ /** Controls to hang on the view, each in the corner it asks for. The credit
1240
+ * line is always there and is not one of them. */
1241
+ controls?: Control<PanoramaView>[];
1242
+ /** Listeners attached before the first load, so a slow or failed load is
1243
+ * observable while it runs. Later ones go through {@link PanoramaView.on}. */
1244
+ events?: {
1245
+ [K in keyof PanoramaViewEvents]?: PanoramaViewEvents[K];
1246
+ };
1247
+ }
1248
+
1249
+ /** One ground-level sphere texture placed on a body: `v1/panoramas/{id}.webp`,
1250
+ * an equirectangular image whose left edge is north and whose azimuth runs
1251
+ * clockwise. Transparent texels are directions the mosaic never observed. */
1252
+ export declare interface PanoramaEntry {
1253
+ id: string;
1254
+ /** Mission slug the traverse belongs to (`perseverance`, `curiosity`). */
1255
+ mission?: string;
1256
+ instrument?: string;
1257
+ sol?: number;
1258
+ /** Capture start, ISO 8601. Orders the traverse within a mission. */
1259
+ time: string;
1260
+ time_end?: string;
1261
+ /** Planetocentric latitude and east longitude of the rover, degrees. */
1262
+ lat: number;
1263
+ lon: number;
1264
+ elevation_m?: number;
1265
+ /** How far the marker may sit from where the camera stood, metres. Present
1266
+ * only where the traverse bounds the position rather than naming it. */
1267
+ position_uncertainty_m?: number;
1268
+ /** Height of the camera above the surface, metres. Present only where the
1269
+ * view was taken from the air, as Huygens' descent mosaic was. */
1270
+ altitude_m?: number;
1271
+ title?: string;
1272
+ /** Image azimuth of true north, degrees clockwise from the left edge.
1273
+ * Zero, and meaningless, where `orientation` is `unknown`; absent with
1274
+ * the rest of the sphere's geometry where the imagery is withheld. */
1275
+ north_offset_deg?: number;
1276
+ /** How north was established, absent where the archive itself states it.
1277
+ * `unknown` means the sphere sits at an arbitrary azimuth, so nothing
1278
+ * may be drawn or written as a heading. The full set `export/panoramas.py`
1279
+ * writes — a wider union would erase the literals and stop checking. */
1280
+ orientation?: 'unknown' | 'caption-aligned' | 'matched to an archival sphere';
1281
+ /** `estimated` where the sphere's angular bounds were fitted to a
1282
+ * published flat image rather than read from an archive label. */
1283
+ geometry?: 'estimated';
1284
+ /** True where the archive's own coordinate overlay is still drawn on the
1285
+ * texture, which makes it lower quality than the rest. Recorded so such
1286
+ * imagery can be found and replaced; nothing renders it. */
1287
+ source_grid?: boolean;
1288
+ /** Image azimuth where the observed span begins, with its width; absent
1289
+ * when the archive label carried no coverage geometry. */
1290
+ azimuth_start_deg?: number;
1291
+ hfov_deg?: number;
1292
+ /** Solid-angle share of the sphere the mosaic covers, percent. */
1293
+ sphere_percent?: number;
1294
+ color?: string;
1295
+ credit?: string;
1296
+ credit_url?: string;
1297
+ source_url?: string;
1298
+ /** `withheld` where the release's reuse terms are unsettled: the stop is
1299
+ * published as a place and a date, and no texture exists to fetch. */
1300
+ imagery?: 'withheld';
1301
+ /** How far down the host's texture ladder this sphere may be drawn; absent
1302
+ * where its terms allow any use. */
1303
+ distribution?: TextureDistribution;
1304
+ }
1305
+
1306
+ /** One probe's coverage on a body, as `export/panoramas.py` writes it. */
1307
+ export declare interface PanoramaMissionSummary {
1308
+ mission: string;
1309
+ /** `probe-<id>` of the craft that drove this traverse; absent where the
1310
+ * spacecraft table does not describe it. */
1311
+ probe?: string;
1312
+ count: number;
1313
+ first_time: string;
1314
+ last_time: string;
1315
+ /** False where no stop on the traverse publishes a sphere: the places are
1316
+ * on the map, and there is nothing to open. */
1317
+ imagery?: boolean;
1318
+ }
1319
+
1320
+ export declare class PanoramaView {
1321
+ private readonly bodyId;
1322
+ private readonly openAt;
1323
+ /** The host's opening direction, spent on the first panorama. */
1324
+ private openingView;
1325
+ private readonly interactive;
1326
+ private readonly followArrows;
1327
+ private limits;
1328
+ /* Excluded from this release type: attribution */
1329
+ private container;
1330
+ private readonly root;
1331
+ private renderer;
1332
+ private controls;
1333
+ private resizeObserver;
1334
+ private readonly scene;
1335
+ private readonly camera;
1336
+ private readonly sphere;
1337
+ /** The heading and elevation grid, drawn over the canvas in 2D so its
1338
+ * lines and labels keep one weight at every zoom. */
1339
+ private readonly angleCanvas;
1340
+ private readonly angleContext;
1341
+ private angleGridVisible;
1342
+ private readonly arrows;
1343
+ private readonly arrowGeometry;
1344
+ private readonly raycaster;
1345
+ private readonly loader;
1346
+ private texture;
1347
+ private loadToken;
1348
+ private frame;
1349
+ private disposed;
1350
+ private entries;
1351
+ private radiusKm;
1352
+ private current;
1353
+ private neighbours;
1354
+ private view;
1355
+ private readonly pointers;
1356
+ private pinchDistance;
1357
+ private dragStart;
1358
+ private hovered;
1359
+ private gyroEnabled;
1360
+ /** The device heading that stands for the view's own heading; taken from
1361
+ * the first reading so switching the sensor on does not spin the view. */
1362
+ private gyroOrigin;
1363
+ private readonly gyroEuler;
1364
+ private readonly gyroQuaternion;
1365
+ private readonly gyroScreen;
1366
+ private readonly gyroDirection;
1367
+ private readonly lookAt;
1368
+ private readonly ndc;
1369
+ private readonly gridPoint;
1370
+ private readonly viewDirection;
1371
+ private readonly listeners;
1372
+ constructor(options: PanoramaViewOptions);
1373
+ /** Put the view's own box inside `container`. */
1374
+ mount(container: HTMLElement): void;
1375
+ /** Fetch the body's list and open the panorama asked for, or its first. */
1376
+ load(): Promise<void>;
1377
+ addControl(control: Control<PanoramaView>, position?: ControlPosition): this;
1378
+ removeControl(control: Control<PanoramaView>): this;
1379
+ /** Take the view down and let go of everything it holds. */
1380
+ remove(): void;
1381
+ /** Every panorama of the body, mission by mission in time order. */
1382
+ getPanoramas(): readonly PanoramaEntry[];
1383
+ getCurrent(): PanoramaEntry | null;
1384
+ /** The panoramas before and after the current one on its traverse. */
1385
+ getNeighbours(): Neighbours | null;
1386
+ /** Show a panorama: an entry from the list, its id, or its `time,lat,lon`
1387
+ * key. Resolves once it is on screen; a newer call supersedes one still
1388
+ * in flight. */
1389
+ open(target: PanoramaEntry | string): Promise<void>;
1390
+ /** Open the previous or next panorama on the traverse, when there is one. */
1391
+ step(key: ArrowKey): Promise<void>;
1392
+ private byKey;
1393
+ getView(): PanoramaViewState;
1394
+ /** Turn or zoom the view, within its limits. */
1395
+ setView(view: Partial<PanoramaViewState>): void;
1396
+ getLimits(): PanoramaViewLimits;
1397
+ /** Bound the view; the current one moves inside the bounds at once. An
1398
+ * empty object frees it. */
1399
+ setLimits(limits: PanoramaViewLimits): void;
1400
+ /** Turn the view by moving the device instead of dragging. Resolves with
1401
+ * whether the sensor is now driving the view: a device without one, or one
1402
+ * that withholds permission, leaves it off. */
1403
+ setGyroEnabled(enabled: boolean): Promise<boolean>;
1404
+ isGyroEnabled(): boolean;
1405
+ private readonly onDeviceOrientation;
1406
+ on<K extends keyof PanoramaViewEvents>(event: K, listener: PanoramaViewEvents[K]): () => void;
1407
+ once<K extends keyof PanoramaViewEvents>(event: K, listener: PanoramaViewEvents[K]): () => void;
1408
+ off<K extends keyof PanoramaViewEvents>(event: K, listener: PanoramaViewEvents[K]): void;
1409
+ private emit;
1410
+ /** Turn the view to the imagery, before its first frame is drawn. */
1411
+ private faceCoverage;
1412
+ private loadTexture;
1413
+ private setArrowTargets;
1414
+ private invalidate;
1415
+ /** Lay a grid of headings and elevations over the view, every ten degrees. */
1416
+ setAngleGridVisible(visible: boolean): void;
1417
+ /** Show or hide the arrows to the neighbouring panoramas. */
1418
+ setArrowsVisible(visible: boolean): void;
1419
+ private resize;
1420
+ private render;
1421
+ /** Drawn after projection so grid weight and type stay constant across the view. */
1422
+ private drawAngleGrid;
1423
+ private traceAngleLine;
1424
+ private projectAngle;
1425
+ /** Degrees of view per pixel dragged, so a drag follows the finger at any zoom. */
1426
+ private degreesPerPixel;
1427
+ private arrowAt;
1428
+ private pressArrow;
1429
+ private readonly onPointerDown;
1430
+ private readonly onPointerMove;
1431
+ /** A press is a click when one pointer went down and barely moved. A
1432
+ * non-interactive view takes no pointer down, so every release is one. */
1433
+ private readonly onPointerUp;
1434
+ private readonly onPointerCancel;
1435
+ private pinchSpan;
1436
+ private zoom;
1437
+ private readonly onWheel;
1438
+ private readonly onKeyDown;
1439
+ }
1440
+
1441
+ export declare interface PanoramaViewEvents {
1442
+ /** The body's list is in; the first panorama is being fetched. */
1443
+ ready: () => void;
1444
+ /** This panorama is on screen. */
1445
+ load: (entry: PanoramaEntry) => void;
1446
+ error: (error: Error) => void;
1447
+ viewchange: (view: PanoramaViewState) => void;
1448
+ /** An arrow was pressed. */
1449
+ step: (target: {
1450
+ key: ArrowKey;
1451
+ entry: PanoramaEntry;
1452
+ }) => void;
1453
+ /** Where the arrows landed on screen, after each frame. */
1454
+ arrows: (anchors: Partial<Record<ArrowKey, ScreenAnchor>>) => void;
1455
+ }
1456
+
1457
+ /** How far the reader may look and zoom. Headings run clockwise from the
1458
+ * first to the second, so `[300, 60]` is the arc across north; a pair of
1459
+ * equal values locks that axis. Each pair sits inside the view's own range. */
1460
+ export declare interface PanoramaViewLimits {
1461
+ heading?: [from: number, to: number];
1462
+ pitch?: [min: number, max: number];
1463
+ fov?: [min: number, max: number];
1464
+ }
1465
+
1466
+ export declare interface PanoramaViewOptions {
1467
+ /** Body whose panoramas to show, by export id — `"naif-499"` for Mars. */
1468
+ body: string;
1469
+ /** The panorama to open first: its id, or its `time,lat,lon` key. The
1470
+ * body's first when left out. */
1471
+ at?: string;
1472
+ /** Where to look first. Without them the view faces the imagery: the
1473
+ * middle of a partial sweep, pitched to lie inside it; north on a full
1474
+ * one. */
1475
+ heading?: number;
1476
+ pitch?: number;
1477
+ fov?: number;
1478
+ /** Whether the reader may turn the view: drag, pinch, wheel and the arrow
1479
+ * keys. True unless said otherwise. */
1480
+ interactive?: boolean;
1481
+ /** Bounds on the view; none unless said otherwise. */
1482
+ limits?: PanoramaViewLimits;
1483
+ /** Draw the arrows to the previous and next panorama. True unless said
1484
+ * otherwise. */
1485
+ arrows?: boolean;
1486
+ /** Whether pressing an arrow opens the panorama it points at. True unless
1487
+ * said otherwise; a host that keeps the panorama in its own URL turns it
1488
+ * off and opens the target itself on `step`. */
1489
+ followArrows?: boolean;
1490
+ }
1491
+
1492
+ export declare interface PanoramaViewState {
1493
+ /** Compass heading, degrees clockwise from north. */
1494
+ heading: number;
1495
+ /** Degrees above the horizon. */
1496
+ pitch: number;
1497
+ /** Vertical field of view, degrees. */
1498
+ fov: number;
1499
+ }
1500
+
1501
+ /**
1502
+ * An SVG path for a run of places. Empty when none of it is on the map, so a
1503
+ * caller can render the result straight into `d` either way.
1504
+ *
1505
+ * A closed shape is cut at the seam first, so each piece of it is a shape in
1506
+ * its own right and can be filled. A globe has no seam, only a limb, and its
1507
+ * shapes are never cut on the far side. What the limb of a globe cuts is left open
1508
+ * instead: there the shape really does carry on out of sight, and joining the
1509
+ * loose ends would draw an edge it does not have. The area inside such a
1510
+ * shape is {@link areaFor}.
1511
+ */
1512
+ export declare function pathFor(points: readonly LonLat[], viewport: Viewport, options?: PathOptions): string;
1513
+
1514
+ declare interface PathOptions {
1515
+ interpolate?: Interpolation;
1516
+ /** Degrees of arc per step. Smaller is smoother and slower; the default
1517
+ * keeps a full-frame curve visually smooth without flooding the path. */
1518
+ stepDeg?: number;
1519
+ /** Join the last point back to the first. */
1520
+ closed?: boolean;
1521
+ }
1522
+
1523
+ /** Two unit vectors across the plane at right angles to `normal` and to each
1524
+ * other. Any direction at all does for the first one as long as it is not the
1525
+ * normal itself, so the ecliptic pole stands in wherever the normal is. */
1526
+ export declare function planeBasis(normal: OffsetKm): [OffsetKm, OffsetKm];
1527
+
1528
+ export declare interface Polygon extends Shape {
1529
+ /** Replace the outline, keeping everything else. */
1530
+ setPoints(points: readonly OffsetKm[]): void;
1531
+ }
1532
+
1533
+ export declare interface PolygonOptions extends ShapeStyle {
1534
+ /** What carries the area: its points are measured from here. */
1535
+ anchor: Anchor;
1536
+ /** The outline in order, kilometres on ecliptic J2000 axes from the anchor.
1537
+ * The last point joins back to the first; three or more, and fewer draws
1538
+ * nothing. */
1539
+ points: readonly OffsetKm[];
1540
+ }
1541
+
1542
+ export declare interface Polyline {
1543
+ /** Replace the points, keeping everything else. */
1544
+ setPoints(points: readonly OffsetKm[]): void;
1545
+ /** Move the line onto another place or body. */
1546
+ setAnchor(anchor: Anchor): void;
1547
+ setVisible(visible: boolean): void;
1548
+ remove(): void;
1549
+ }
1550
+
1551
+ export declare interface PolylineOptions {
1552
+ /** What carries the line: its points are measured from here, so a line
1553
+ * round a body travels with it. */
1554
+ anchor: Anchor;
1555
+ /** The line's points in order, kilometres on ecliptic J2000 axes from the
1556
+ * anchor. Two or more; fewer draws nothing. */
1557
+ points: readonly OffsetKm[];
1558
+ /** CSS colour name or hex string. White when left out. */
1559
+ color?: string;
1560
+ /** Width in screen pixels, held at any distance. */
1561
+ widthPx?: number;
1562
+ /** 0 to 1. */
1563
+ opacity?: number;
1564
+ /** Fade the line toward its last point, the way an orbit trail fades
1565
+ * behind a body. */
1566
+ fade?: boolean;
1567
+ /** Join the last point back to the first. */
1568
+ closed?: boolean;
1569
+ }
1570
+
1571
+ export declare interface Projection {
1572
+ readonly id: ProjectionId;
1573
+ /** Meridian down the middle of the map. */
1574
+ readonly centerLon: number;
1575
+ /** True when the map's eastern and western edges are the same meridian, so a
1576
+ * line drawn across the seam jumps the width of the world. */
1577
+ readonly cyclic: boolean;
1578
+ /** True when the world fills its whole extent, so a copy laid beside it
1579
+ * meets its edge exactly. Only such a map is repeated east–west: setting a
1580
+ * pointed world against its own curve leaves lens-shaped gaps and reads as
1581
+ * two worlds rather than one carrying on, so those are drawn once and
1582
+ * panning stops at the edge instead of wrapping. */
1583
+ readonly rectangular: boolean;
1584
+ /** True when the world is a disc rather than a rectangle: the corners of the
1585
+ * extent are outside the map, and a point can be hidden behind the globe. */
1586
+ readonly azimuthal: boolean;
1587
+ readonly extent: Extent;
1588
+ /** Plane coordinates, or null where the place is not on the map. */
1589
+ forward(lon: number, lat: number): [number, number] | null;
1590
+ /** Longitude and latitude, or null where the plane point is off the world. */
1591
+ inverse(x: number, y: number): [number, number] | null;
1592
+ /** The whole row at `y` at once, or null where no part of it is on the map.
1593
+ * Only the projections that map a row to a single parallel have one; the
1594
+ * two that show a globe do not, and are resampled pixel by pixel. */
1595
+ rowInverse?(y: number): ProjectionRow | null;
1596
+ }
1597
+
1598
+ /** The ids, in the order above. Read off the builders so a projection cannot be
1599
+ * added and then go unoffered and untested. */
1600
+ export declare const PROJECTION_IDS: readonly ProjectionId[];
1601
+
1602
+ /** Width over height of the whole world, for sizing a frame that holds it. */
1603
+ export declare function projectionAspect(projection: Projection): number;
1604
+
1605
+ /**
1606
+ * Projections for the flat map: degrees of longitude and latitude onto a
1607
+ * plane, and back. Each one is a pure pair of functions plus the extent its
1608
+ * world fills. The view, the raster warp and the vector overlay are all
1609
+ * written against that shape, so a new projection needs nothing but a new
1610
+ * entry here.
1611
+ *
1612
+ * Longitude is east-positive and latitude is north-positive, matching the IAU
1613
+ * planetographic convention the export uses.
1614
+ */
1615
+ export declare type ProjectionId = 'equirectangular' | 'equalEarth' | 'mollweide' | 'sinusoidal' | 'robinson' | 'orthographic' | 'stereographic';
1616
+
1617
+ export declare interface ProjectionOptions {
1618
+ /** Meridian down the middle of the map. */
1619
+ centerLon?: number;
1620
+ /** Parallel at the middle. Azimuthal projections only — the cylindrical and
1621
+ * pseudocylindrical ones are always centred on the equator. */
1622
+ centerLat?: number;
1623
+ /** Degrees from the centre past which the map is blank. Azimuthal only;
1624
+ * ignored elsewhere, where the whole world always fits. */
1625
+ clipAngle?: number;
1626
+ }
1627
+
1628
+ /**
1629
+ * A whole row of the plane resolved at once, for the projections where that is
1630
+ * possible: on a cylindrical or pseudocylindrical map every point of a row
1631
+ * lies on one parallel, and longitude runs linearly across it.
1632
+ *
1633
+ * That turns the resampling walk from one inverse projection per pixel into
1634
+ * one per row plus a multiply, which is most of what the flat map costs.
1635
+ */
1636
+ declare interface ProjectionRow {
1637
+ /** The parallel this row of the plane falls on. */
1638
+ lat: number;
1639
+ /** Degrees of longitude per unit of abscissa, from the central meridian. */
1640
+ lonPerX: number;
1641
+ /** Abscissa past which the row leaves the map — half the world's width at
1642
+ * this latitude, which narrows toward the poles on a pointed projection. */
1643
+ maxAbsX: number;
1644
+ }
1645
+
1646
+ declare interface RasterLayer {
1647
+ readonly kind: 'raster';
1648
+ id: string;
1649
+ label: string;
1650
+ visible: boolean;
1651
+ opacity: number;
1652
+ blend: 'normal' | 'add';
1653
+ credit?: LayerCredit;
1654
+ /** The picture to draw for a moment in time, at a resolution tier. Bundles
1655
+ * that do not change with either ignore both. */
1656
+ url(jd: number, tier: string): string;
1657
+ /** Tiers the bundle was actually written at. */
1658
+ tiers: readonly string[];
1659
+ }
1660
+
1661
+ declare type ResolvedAtmosphereTier = 'low' | 'medium' | 'high' | 'ultra';
1662
+
1663
+ /**
1664
+ * A list of states the map reads between. Between two states the path is a
1665
+ * cubic through both of them, tangent to the slope each state's neighbours
1666
+ * imply — the smooth curve a coasting object actually follows, where a
1667
+ * straight line between states would cut every corner of an orbit. Outside the
1668
+ * range the states cover the object is not drawn: a list that has run out is
1669
+ * not evidence of where anything is.
1670
+ */
1671
+ export declare function samples(options: SamplesOptions): InertialAnchor;
1672
+
1673
+ export declare interface SamplesOptions {
1674
+ /** What the states are measured from; the Sun when left out. */
1675
+ body?: string;
1676
+ /** Two or more states. They are sorted by date, so they may be given in any
1677
+ * order; fewer than two places nothing. */
1678
+ samples: readonly TrajectorySample[];
1679
+ }
1680
+
1681
+ /**
1682
+ * The display settings the scene reads. The app's persisted store satisfies
1683
+ * this structurally; an embed passes its own or takes the default. One per
1684
+ * page, registered through {@link setSceneSettings}: the tier and quality
1685
+ * helpers run deep in material code with no map instance at hand.
1686
+ */
1687
+ export declare interface SceneSettings {
1688
+ resolvedReducedMotion: boolean;
1689
+ viewMode: 'map' | 'immersive';
1690
+ showClouds: boolean;
1691
+ showAtmospheres: boolean;
1692
+ atmosphereQuality: AtmosphereQualityTier;
1693
+ atmosphereAutoTier: ResolvedAtmosphereTier | null;
1694
+ atmosphereCalibration: AtmosphereCalibration | null;
1695
+ atmoQualityOverrides: Partial<AtmosphereQualityConfig>;
1696
+ highAmbient: boolean;
1697
+ realisticLighting: boolean;
1698
+ overexposeRings: boolean;
1699
+ showShapeMesh: boolean;
1700
+ showSurfaceTexture: boolean;
1701
+ showDisplacement: boolean;
1702
+ showSelfShadow: boolean;
1703
+ showHaloDebug: boolean;
1704
+ maxPartsPerZone: number;
1705
+ /** Written by the boot calibration and the perf governor. */
1706
+ setAtmosphereCalibration(v: AtmosphereCalibration | null): void;
1707
+ setAtmosphereAutoTier(v: ResolvedAtmosphereTier | null): void;
1708
+ }
1709
+
1710
+ /** Where an arrow sits on screen, for a label the host hangs beside it. */
1711
+ export declare interface ScreenAnchor {
1712
+ x: number;
1713
+ y: number;
1714
+ /** In front of the camera and inside the frame. */
1715
+ visible: boolean;
1716
+ }
1717
+
1718
+ /** A drawing on the map, for as long as the host keeps it. */
1719
+ export declare interface Shape {
1720
+ /** Move it onto another place or body. */
1721
+ setAnchor(anchor: Anchor): void;
1722
+ /** Show or hide it without giving up its place. */
1723
+ setVisible(visible: boolean): void;
1724
+ remove(): void;
1725
+ }
1726
+
1727
+ export declare interface ShapeStyle {
1728
+ /** Any CSS colour. White when left out. */
1729
+ color?: string;
1730
+ /** Outline width in screen pixels, held at any distance. Zero leaves the
1731
+ * outline out, for an area drawn as a fill alone. */
1732
+ widthPx?: number;
1733
+ /** 0 to 1, over the outline. */
1734
+ opacity?: number;
1735
+ /** Fill colour for an area. An area is filled in its own colour unless it
1736
+ * says otherwise; a circle is a ring until it is given one. */
1737
+ fill?: string;
1738
+ /** 0 to 1, over the fill. */
1739
+ fillOpacity?: number;
1740
+ }
1741
+
1742
+ /**
1743
+ * Simulation clock. Advances Julian Date by real elapsed time × timeScale;
1744
+ * timeScale === 0 means paused. `play()` re-resumes the previous non-zero scale.
1745
+ */
1746
+ export declare class SimClock {
1747
+ jd: number;
1748
+ timeScale: number;
1749
+ direction: 1 | -1;
1750
+ /* Excluded from this release type: seeked */
1751
+ /* Excluded from this release type: jumps */
1752
+ /* Excluded from this release type: settledJd */
1753
+ /** True while the clock still tracks wall-clock time: started at now and
1754
+ * never paused, jumped, reversed or run at another speed since. The URL
1755
+ * writes `now` instead of a date while this holds, so a shared link stays
1756
+ * live. */
1757
+ live: boolean;
1758
+ private lastRealMs;
1759
+ private prevScale;
1760
+ private stops;
1761
+ private settleTimer;
1762
+ constructor(initialJd: number, live?: boolean);
1763
+ /* Excluded from this release type: tick */
1764
+ /* Excluded from this release type: setBoundaryStops */
1765
+ /** Caller passes the unsigned magnitude; direction is applied here. */
1766
+ setTimeScale(magnitude: number): void;
1767
+ toggleDirection(): void;
1768
+ /* Excluded from this release type: setJD */
1769
+ /** Seek, and mark it as a discrete jump so listeners can react to the one
1770
+ * move rather than to a stream of them. */
1771
+ jumpTo(jd: number): void;
1772
+ /** Rest the settled date on where the clock stands now. */
1773
+ private settle;
1774
+ /** The same, once a drag holds still. A clock still playing is left alone: it
1775
+ * never comes to rest, and the pause that ends it settles it anyway. */
1776
+ private settleAfterPause;
1777
+ /* Excluded from this release type: sweepTo */
1778
+ pause(): void;
1779
+ play(): void;
1780
+ /** Back to wall-clock time; live again only if playback is at 1×, since a
1781
+ * paused or fast clock drifts off it at once. */
1782
+ now(): void;
1783
+ get playing(): boolean;
1784
+ /** The moment the map is showing. */
1785
+ get date(): Date;
1786
+ /** Show another moment, as one deliberate move. */
1787
+ setDate(date: Date): void;
1788
+ }
1789
+
1790
+ /**
1791
+ * A ring of places all the same angular distance from a centre — the flat
1792
+ * map's circle, which is a circle on the globe and rarely one on the plane.
1793
+ *
1794
+ * Swept as a rotation in three dimensions rather than by the spherical
1795
+ * bearing formula, which divides by the cosine of the centre's latitude and so
1796
+ * collapses a cap drawn round a pole onto a single meridian.
1797
+ */
1798
+ export declare function smallCircle(center: LonLat, radiusDeg: number, steps?: number): LonLat[];
1799
+
1800
+ export declare class SpaceMap {
1801
+ /* Excluded from this release type: ctx */
1802
+ readonly clock: SimClock;
1803
+ /* Excluded from this release type: initialView */
1804
+ /* Excluded from this release type: renderer */
1805
+ /* Excluded from this release type: webglError */
1806
+ /* Excluded from this release type: contextLost */
1807
+ /* Excluded from this release type: focusedBody */
1808
+ /* Excluded from this release type: attribution */
1809
+ /** Objects of the host's own: a spacecraft, a station, a body the export
1810
+ * has never heard of. */
1811
+ readonly objects: MapObjects;
1812
+ /** Dragging to turn the camera round the focused body. A two-finger drag and
1813
+ * a right-drag go with it: they are the same gesture to a reader told the
1814
+ * camera does not move. */
1815
+ readonly dragRotate: GestureHandler;
1816
+ /** The wheel and the pinch. */
1817
+ readonly scrollZoom: GestureHandler;
1818
+ /** Arrow keys to turn, +/− to zoom, on the focused canvas. */
1819
+ readonly keyboard: GestureHandler;
1820
+ /** Clicking an object to focus it. */
1821
+ readonly bodySelect: GestureHandler;
1822
+ /** Clicking a named surface feature, which the map reports as a
1823
+ * `featureselect` event. */
1824
+ readonly featureSelect: GestureHandler;
1825
+ /** The wheel and one finger belong to the page, not the map. */
1826
+ readonly cooperativeGestures: GestureHandler;
1827
+ private container;
1828
+ private canvas;
1829
+ private labelLayer;
1830
+ private stopWatching;
1831
+ private controls;
1832
+ private lostPanelTimer;
1833
+ private cooperative;
1834
+ private limits;
1835
+ private initialFocusPending;
1836
+ private pendingFocusId;
1837
+ /** Retires the host's hold on the camera. Kept so that a second hold, or
1838
+ * unmounting, can take the camera off the hold before it. */
1839
+ private retireCameraHold;
1840
+ private readonly listeners;
1841
+ constructor(options?: SpaceMapOptions);
1842
+ /** Listen for `event`. The returned function stops listening, which is the
1843
+ * same thing {@link off} does. */
1844
+ on<K extends keyof MapEvents>(event: K, listener: MapEvents[K]): () => void;
1845
+ /** Listen for the next `event` only. */
1846
+ once<K extends keyof MapEvents>(event: K, listener: MapEvents[K]): () => void;
1847
+ off<K extends keyof MapEvents>(event: K, listener: MapEvents[K]): void;
1848
+ private emit;
1849
+ /** What the map knows about an object it has loaded; undefined for one it
1850
+ * has not, which for a small body may simply mean not yet. */
1851
+ getBody(id: string): Body_2 | undefined;
1852
+ /** The object the camera orbits. A surface feature reports its host body. */
1853
+ getFocusedBody(): Body_2 | undefined;
1854
+ /** Ids of the objects orbiting `id` that this map has loaded. Loading is
1855
+ * driven by focus and by the clock, so the list grows as the reader moves. */
1856
+ getChildren(id: string): string[];
1857
+ /* Excluded from this release type: load */
1858
+ /* Excluded from this release type: open */
1859
+ /* Excluded from this release type: applyInitialView */
1860
+ /* Excluded from this release type: mount */
1861
+ /** Hang a control in one of the map's corners; top-right unless the control
1862
+ * or the caller names another. Adding the same control twice does nothing. */
1863
+ addControl(control: Control<SpaceMap>, position?: ControlPosition): this;
1864
+ /** Take a control back off. The credit line is not one a host may remove —
1865
+ * the imagery terms the map draws under require it. */
1866
+ removeControl(control: Control<SpaceMap>): this;
1867
+ /** Stop rendering and take the map's DOM back out of the container. The map
1868
+ * is finished afterwards; open another with {@link createMap}. */
1869
+ remove(): void;
1870
+ /* Excluded from this release type: unmount */
1871
+ /** Reactions that outlive any one caller. Each reads its signal before the
1872
+ * renderer call so the dependency is tracked from the first run. */
1873
+ private watch;
1874
+ /* Excluded from this release type: applySettings */
1875
+ private callbacks;
1876
+ private readonly onKeyDown;
1877
+ private readonly onContextLost;
1878
+ private readonly onContextRestored;
1879
+ private readonly onVisibility;
1880
+ /**
1881
+ * Fly the camera to a body, or to a named feature on one. Resolves when the
1882
+ * flight lands. Whatever the target leaves out the map frames itself, so
1883
+ * `{ body }` alone is the ordinary way to move.
1884
+ */
1885
+ flyTo(target: CameraTarget): Promise<void>;
1886
+ /** Turn to a feature on the body already framed, without travelling to it —
1887
+ * the move a click on its label makes. Resolves when the camera comes
1888
+ * round. */
1889
+ panTo(target: FeatureTarget): Promise<void>;
1890
+ /** Put the camera somewhere at once, with no flight: what a page restoring a
1891
+ * stored view wants, where a flight from nowhere would read as a lurch. */
1892
+ jumpTo(target: JumpTarget): this;
1893
+ /** Where the camera is now. Null before the first frame, and while nothing
1894
+ * is focused. */
1895
+ getCamera(): CameraState | null;
1896
+ /**
1897
+ * Switch a layer on or off. The change is a drawing decision and lands on
1898
+ * the next frame: nothing is fetched, whatever is switched on.
1899
+ *
1900
+ * That is the other half of the `layers` option, which is a downloading
1901
+ * decision — a layer switched off there is never fetched, so switching it
1902
+ * back on here shows nothing. Switch off at open time what the map is not
1903
+ * for, and switch here what the reader is to have a say in.
1904
+ */
1905
+ setLayerVisible(id: MapLayerId, visible: boolean): this;
1906
+ isLayerVisible(id: MapLayerId): boolean;
1907
+ /** Every layer id, so a switcher can be built without spelling them out. */
1908
+ getLayers(): MapLayerId[];
1909
+ /** Earth's satellites and its debris ride one point cloud, so leaving one
1910
+ * kind out means repacking it. Everything else is decided per frame. */
1911
+ private onLayerChange;
1912
+ /**
1913
+ * Replace the reader's limits, whole. What the new set leaves out is
1914
+ * unrestricted again, so `setLimits({})` lifts them all.
1915
+ *
1916
+ * Limits gate reader input only: a flight or a jump lands where it was told
1917
+ * to, and the reader's next gesture brings the camera back inside.
1918
+ */
1919
+ setLimits(limits: CameraLimits): this;
1920
+ /** The limits as they stand. */
1921
+ getLimits(): CameraLimits;
1922
+ private applyLimits;
1923
+ private applyGestures;
1924
+ /** A wheel the page is to keep never reaches the orbit controls. It is not
1925
+ * cancelled, so the page scrolls as it would over any other element. */
1926
+ private readonly onWheelCapture;
1927
+ /** One finger is the page's; the orbit controls already ignore it, so this
1928
+ * is only here to say why nothing moved. */
1929
+ private readonly onTouchMove;
1930
+ private toFeature;
1931
+ /** The focus controller reports how long its move takes. One frame past
1932
+ * that: the camera is placed during the render after the move ends, so a
1933
+ * host reading it the moment the flight is over would be a frame behind. */
1934
+ private settled;
1935
+ /** A move with no body named moves around the one already focused. */
1936
+ private targetBody;
1937
+ /** Camera distance in scene units: what was asked for, else a distance that
1938
+ * frames the body, else where the camera already is. */
1939
+ private framing;
1940
+ /* Excluded from this release type: focusOnBody */
1941
+ /* Excluded from this release type: snapToBody */
1942
+ /* Excluded from this release type: snapToBodyFacing */
1943
+ /* Excluded from this release type: focusOnFeature */
1944
+ /* Excluded from this release type: setFocusTarget */
1945
+ /** Where the camera is and what it orbits, as anchors a host can store,
1946
+ * change and hand back to {@link holdCamera}. Null before the first frame
1947
+ * or while nothing is focused. */
1948
+ getPose(): CameraPose | null;
1949
+ /** Take the camera off the map's own controls and place it yourself. The
1950
+ * focused body still decides what is drawn in detail, so hold and focus
1951
+ * the same body when you move in close. */
1952
+ holdCamera(): CameraHold;
1953
+ /** Pin the host's own element to a place on the map. It is drawn in the
1954
+ * map's label layer, so it pans with the scene and is removed with it. */
1955
+ addMarker(options: MarkerOptions): Marker;
1956
+ /** Draw a line on the map. Its points are measured from an anchor, so a
1957
+ * line round a body travels with it. */
1958
+ addPolyline(options: PolylineOptions): Polyline;
1959
+ /** Draw an area on the map, measured from an anchor like a line. It is
1960
+ * filled in its own colour unless the host says otherwise. */
1961
+ addPolygon(options: PolygonOptions): Polygon;
1962
+ /** Draw a circle round a place — an orbit's reach, a distance from a body.
1963
+ * It is a ring rather than a disc unless the host asks for a fill, since
1964
+ * what it is drawn round is usually the point. */
1965
+ addCircle(options: CircleOptions): Circle;
1966
+ /** Write a word at a place, in the map's own way of drawing one. A marker
1967
+ * is for an element the host has styled itself. */
1968
+ addLabel(options: LabelOptions): Label;
1969
+ /** Draw a picture at a place. It holds its size on screen wherever the
1970
+ * camera goes. */
1971
+ addIcon(options: IconOptions): Icon;
1972
+ /** Draw a line on a body's surface, following its curve and turning with
1973
+ * it. The places are longitude and latitude, as the flat map's are. */
1974
+ addSurfacePolyline(options: SurfacePolylineOptions): SurfaceShape;
1975
+ /** Draw an area on a body's surface. It is filled in its own colour unless
1976
+ * the host says otherwise, and closes itself. */
1977
+ addSurfacePolygon(options: SurfacePolygonOptions): SurfaceShape;
1978
+ /** Draw a cap on a body's surface: a footprint, a range, a horizon. */
1979
+ addSurfaceCircle(options: SurfaceCircleOptions): SurfaceShape;
1980
+ /** Remove every drawing the host has added, leaving the map itself alone.
1981
+ * Objects the host has put on the map are not drawings and stay;
1982
+ * {@link objects}.clear() takes those. */
1983
+ clearDrawings(): void;
1984
+ /**
1985
+ * Put the host's own pictures on a body the map already knows, in place of
1986
+ * the ones the export publishes: a surface map, lights for the unlit side,
1987
+ * a cloud layer. Each is a URL, and what is left out stays the map's own,
1988
+ * so `setBodyAppearance(id, {})` gives the body its own imagery back.
1989
+ *
1990
+ * A picture given here is what the body wears at every distance. The map's
1991
+ * own imagery is chosen by how much of the screen the body fills, and there
1992
+ * is nothing to choose once a host has said what it looks like.
1993
+ */
1994
+ setBodyAppearance(id: string, appearance: BodyAppearance): this;
1995
+ /** A cap's radius as an angle, from whichever of the two ways the host gave
1996
+ * it. A radius in kilometres needs the body's own radius, which an
1997
+ * unloaded body has not published yet. */
1998
+ private capRadiusDeg;
1999
+ /** Add a drawing and hand it the way back out. */
2000
+ private track;
2001
+ private requireCanvas;
2002
+ private requireRenderer;
2003
+ setNorthReference(id: string | null): void;
2004
+ setUserLocation(latitude: number, longitude: number): void;
2005
+ clearUserPromoted(): void;
2006
+ /* Excluded from this release type: setSelectedFeature */
2007
+ /* Excluded from this release type: setTravelPath */
2008
+ /* Excluded from this release type: setOrbitPreview */
2009
+ /* Excluded from this release type: setTravelHover */
2010
+ /* Excluded from this release type: focusOnPathPoint */
2011
+ /* Excluded from this release type: trackPathPoint */
2012
+ /** Stop drawing while opaque UI covers the map. */
2013
+ setCovered(covered: boolean): void;
2014
+ }
2015
+
2016
+ export declare interface SpaceMapOptions {
2017
+ /** Display settings for the page; defaults suit a bare embed. */
2018
+ settings?: SceneSettings;
2019
+ /** Simulation start, wall-clock time when omitted. `live` keeps the clock
2020
+ * on wall-clock time; defaults to true only when no date is given. */
2021
+ date?: Date;
2022
+ live?: boolean;
2023
+ /** Where the map opens. */
2024
+ view?: CameraOptions;
2025
+ /** Whether the reader may move the map at all. True unless it is said
2026
+ * otherwise; false switches every gesture off. */
2027
+ interactive?: boolean;
2028
+ /** Gestures to start on or off one at a time, over whatever `interactive`
2029
+ * said. Each is a handler on the map afterwards. */
2030
+ interactions?: Partial<Record<MapGesture, boolean>>;
2031
+ /** The map inside a page the reader scrolls past: the wheel scrolls the page
2032
+ * unless ctrl (⌘ on a Mac) is held, and one finger drags the page rather
2033
+ * than the map. A hint says so whenever the plain gesture is tried. */
2034
+ cooperativeGestures?: boolean;
2035
+ /** Where the reader may take the camera. Reader input only — see
2036
+ * {@link SpaceMap.setLimits}. */
2037
+ limits?: CameraLimits;
2038
+ /** Which layers the map draws, by id; everything left out is drawn. A layer
2039
+ * switched off here is never fetched — see {@link SpaceMap.setLayerVisible}
2040
+ * for what that costs later. */
2041
+ layers?: Partial<Record<MapLayerId, boolean>>;
2042
+ }
2043
+
2044
+ /** A place on (or above) the body's surface, turning with it. */
2045
+ export declare interface SurfaceAnchor {
2046
+ body: string;
2047
+ latitude: number;
2048
+ longitude: number;
2049
+ /** Height above the body's mean radius; on the surface when left out. */
2050
+ altitudeKm?: number;
2051
+ }
2052
+
2053
+ export declare interface SurfaceCircleOptions extends ShapeStyle {
2054
+ body: string;
2055
+ center: LonLat;
2056
+ /** Radius as an angle at the body's centre. */
2057
+ radiusDeg?: number;
2058
+ /** Radius along the surface. Needs the body's radius to be known; ignored
2059
+ * when it is not. */
2060
+ radiusKm?: number;
2061
+ steps?: number;
2062
+ altitudeKm?: number;
2063
+ }
2064
+
2065
+ export declare interface SurfacePolygonOptions extends SurfaceShapeOptions {
2066
+ /** Filled in its own colour when left out; an area on a body is drawn to be
2067
+ * seen as one. */
2068
+ fill?: string;
2069
+ }
2070
+
2071
+ export declare interface SurfacePolylineOptions extends SurfaceShapeOptions {
2072
+ /** Join the last place back to the first. */
2073
+ closed?: boolean;
2074
+ }
2075
+
2076
+ /** A shape on a body's surface, for as long as the host keeps it. */
2077
+ export declare interface SurfaceShape {
2078
+ /** Replace the places, keeping everything else. */
2079
+ setPoints(points: readonly LonLat[]): void;
2080
+ setVisible(visible: boolean): void;
2081
+ remove(): void;
2082
+ }
2083
+
2084
+ export declare interface SurfaceShapeOptions extends ShapeStyle {
2085
+ /** Export id of the body it is drawn on. */
2086
+ body: string;
2087
+ /** The shape in longitude and latitude, degrees. The same list draws on the
2088
+ * flat map. */
2089
+ points: readonly LonLat[];
2090
+ /** How the space between the given places is filled: along the parallels
2091
+ * and meridians, or the short way over the surface. */
2092
+ interpolate?: Interpolation;
2093
+ /** Degrees of arc per step between the given places. Smaller is smoother
2094
+ * and slower. */
2095
+ stepDeg?: number;
2096
+ /** Height above the surface. A little above it by default, so the shape is
2097
+ * not lost in the surface's own depth; give it a height of its own for a
2098
+ * track flown rather than walked. */
2099
+ altitudeKm?: number;
2100
+ }
2101
+
2102
+ /** Who may serve a surface map, widest first. A body whose map this embed may
2103
+ * not draw renders in its fallback colour, as an untextured body does. */
2104
+ declare type TextureDistribution = 'open' | 'non-commercial' | 'site-only';
2105
+
2106
+ /**
2107
+ * Two lines of a NORAD element set, propagated with SGP4 — the model the
2108
+ * elements are fitted for, so a satellite's nodal drift and drag are in the
2109
+ * position rather than a mean ellipse. The orbit is round Earth, since that is
2110
+ * what a TLE describes.
2111
+ *
2112
+ * Accuracy falls away from the element set's epoch, a few days either side
2113
+ * being the usual working range. A set SGP4 will not take, and a date it
2114
+ * cannot be propagated to — a decayed satellite, most often — leave the object
2115
+ * undrawn.
2116
+ */
2117
+ export declare function tle(line1: string, line2: string): InertialAnchor;
2118
+
2119
+ /** One state on a sampled trajectory: a date, and where the object was on it. */
2120
+ export declare interface TrajectorySample {
2121
+ /** Julian date. */
2122
+ jd: number;
2123
+ /** Kilometres from the reference body on ecliptic J2000 axes. */
2124
+ km: OffsetKm;
2125
+ }
2126
+
2127
+ export declare interface VectorLayer {
2128
+ readonly kind: 'vector';
2129
+ id: string;
2130
+ label: string;
2131
+ visible: boolean;
2132
+ credit?: LayerCredit;
2133
+ /** Fill `group` with what this layer looks like in this view. The group is
2134
+ * emptied first, so a layer only ever adds. */
2135
+ render(viewport: Viewport, group: SVGGElement): void;
2136
+ /** Loading anything it needs. Re-rendered when it resolves. */
2137
+ prepare?(): Promise<void>;
2138
+ dispose?(): void;
2139
+ }
2140
+
2141
+ /** Plane point a screen pixel would fall on, and back again. */
2142
+ export declare class Viewport {
2143
+ readonly projection: Projection;
2144
+ readonly width: number;
2145
+ readonly height: number;
2146
+ readonly view: ViewState;
2147
+ /** Pixels per unit of the projection's plane. */
2148
+ readonly scale: number;
2149
+ constructor(projection: Projection, width: number, height: number, view: ViewState);
2150
+ toScreen(x: number, y: number): [number, number];
2151
+ fromScreen(px: number, py: number): [number, number];
2152
+ /** Screen pixel for a place, or null where it is not on the map. */
2153
+ project(lon: number, lat: number): [number, number] | null;
2154
+ /** Place under a screen pixel, or null where the pixel is off the world. */
2155
+ unproject(px: number, py: number): [number, number] | null;
2156
+ /** How wide the whole world is in pixels — the jump that tells a drawn line
2157
+ * it has crossed the seam rather than moved. */
2158
+ get worldWidthPx(): number;
2159
+ /** Whether the map should be drawn again either side of itself. */
2160
+ get repeatsHorizontally(): boolean;
2161
+ /** Screen offsets of every copy of the world that reaches into the frame,
2162
+ * the map's own always first. Anything drawn on the map is drawn once per
2163
+ * offset, so a shape near the seam shows on both sides of it. */
2164
+ get repeatShifts(): number[];
2165
+ }
2166
+
2167
+ export declare interface ViewState {
2168
+ /** 1 fits the whole world in the frame; 2 shows half of it. */
2169
+ zoom: number;
2170
+ /** Point of the plane the frame is centred on. */
2171
+ centerX: number;
2172
+ centerY: number;
2173
+ }
2174
+
2175
+ export { }