spacemap 0.1.24 → 0.1.25

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 CHANGED
@@ -240,6 +240,15 @@ export declare interface ClockState {
240
240
  live: boolean;
241
241
  }
242
242
 
243
+ /** The nearest the camera comes to a body, in km. Both change as the body's
244
+ * relief and finer imagery load. */
245
+ export declare interface ClosestApproach {
246
+ /** From the body's centre to its ground under the camera. */
247
+ groundKm: number;
248
+ /** How far over that ground the camera stops. */
249
+ clearanceKm: number;
250
+ }
251
+
243
252
  /** What both maps take: where to put it, where its data comes from, and what
244
253
  * language to read it in. */
245
254
  declare interface CommonOptions {
@@ -2176,6 +2185,10 @@ export declare class SpaceMap {
2176
2185
  setLimits(limits: CameraLimits): this;
2177
2186
  /** The limits as they stand. */
2178
2187
  getLimits(): CameraLimits;
2188
+ /** How near the map lets the camera come to what it orbits, where the
2189
+ * camera is now, whatever {@link SpaceMap.setLimits} adds. Null while
2190
+ * nothing is focused. */
2191
+ getClosestApproach(): ClosestApproach | null;
2179
2192
  private applyLimits;
2180
2193
  private applyGestures;
2181
2194
  /* Excluded from this release type: setStarSelectEnabled */
package/index.js CHANGED
@@ -17623,19 +17623,60 @@ function isModelBearing(body) {
17623
17623
  var modelLoader = new GLTFLoader();
17624
17624
  modelLoader.setMeshoptDecoder(MeshoptDecoder);
17625
17625
  var _loader = modelLoader;
17626
- var _bundleMetaCache = /* @__PURE__ */ new Map();
17627
- function fetchBundleMeta(slug) {
17628
- let p = _bundleMetaCache.get(slug);
17629
- if (!p) {
17630
- p = fetch(versionedUrl(`/v1/models/${slug}/metadata.json`, "models")).then((r) => r.json());
17631
- _bundleMetaCache.set(slug, p);
17632
- p.catch(() => _bundleMetaCache.delete(slug));
17626
+ function modelUrl(slug, tier) {
17627
+ return versionedUrl(`/v1/models/${slug}/${tier}.glb`, "models");
17628
+ }
17629
+ async function loadModelBundle(slug, tier) {
17630
+ const first = await loadTier(slug, tier);
17631
+ if (!first || textureAllowed(first.meta.exports[tier]?.distribution)) return first;
17632
+ disposeGltf(first.gltf.scene);
17633
+ const other = tier === "high" ? "low" : "high";
17634
+ if (!first.meta.tiers?.includes(other)) return null;
17635
+ if (!textureAllowed(first.meta.exports[other]?.distribution)) return null;
17636
+ const second = await loadTier(slug, other);
17637
+ if (!second || textureAllowed(second.meta.exports[other]?.distribution)) return second;
17638
+ disposeGltf(second.gltf.scene);
17639
+ return null;
17640
+ }
17641
+ async function loadTier(slug, tier) {
17642
+ const gltf = await _loader.loadAsync(modelUrl(slug, tier));
17643
+ const meta = (gltf.asset?.extras)?.spacemap;
17644
+ if (!meta?.exports?.high) {
17645
+ disposeGltf(gltf.scene);
17646
+ console.warn(`models/${slug}/${tier}.glb carries no payload`);
17647
+ return null;
17633
17648
  }
17634
- return p;
17649
+ return {
17650
+ gltf,
17651
+ meta,
17652
+ tier
17653
+ };
17654
+ }
17655
+ var _tiers;
17656
+ function fetchModelTiers() {
17657
+ if (!_tiers) {
17658
+ const p = fetch(versionedUrl("/v1/models/tiers.json", "models")).then((r) => {
17659
+ if (!r.ok) throw new Error(`models/tiers.json: ${r.status}`);
17660
+ return r.json();
17661
+ }).then((d) => d.bundles ?? {}).catch((e) => {
17662
+ console.warn("models/tiers.json did not load:", e);
17663
+ if (_tiers === p) _tiers = void 0;
17664
+ return {};
17665
+ });
17666
+ _tiers = p;
17667
+ }
17668
+ return _tiers;
17669
+ }
17670
+ async function bundleTiers(slug) {
17671
+ return (await fetchModelTiers())[slug];
17635
17672
  }
17636
- function allowedTier(meta) {
17637
- if (textureAllowed(meta.exports.high.distribution)) return "high";
17638
- if (meta.exports.low && textureAllowed(meta.exports.low.distribution)) return "low";
17673
+ function tierAllowed(tiers, tier) {
17674
+ const info = tiers[tier];
17675
+ return !!info && textureAllowed(info.distribution);
17676
+ }
17677
+ function allowedTier(tiers) {
17678
+ if (!tiers) return "high";
17679
+ return ["high", "low"].find((tier) => tierAllowed(tiers, tier));
17639
17680
  }
17640
17681
  function shapeModelCredit(meta) {
17641
17682
  return meta.credit ?? meta.exports.high.credit;
@@ -17700,13 +17741,13 @@ async function loadSpacecraftModel(bo, modelScene, ctx) {
17700
17741
  if ((bo.modelLoadEpoch ?? 0) !== epoch) return;
17701
17742
  if (bo.mesh) bo.mesh.visible = false;
17702
17743
  setHaloLoading(bo, true);
17703
- const meta = await fetchBundleMeta(slug);
17704
- const tier = allowedTier(meta);
17705
- if (!tier) {
17744
+ const wanted = allowedTier(await bundleTiers(slug));
17745
+ const loaded = wanted && await loadModelBundle(slug, wanted);
17746
+ if (!loaded) {
17706
17747
  bo.noPhysical = "model";
17707
17748
  return;
17708
17749
  }
17709
- const gltf = await _loader.loadAsync(versionedUrl(`/v1/models/${slug}/${tier}.glb`, "models"));
17750
+ const { gltf, meta, tier } = loaded;
17710
17751
  if ((bo.modelLoadEpoch ?? 0) !== epoch || !bo.mesh) {
17711
17752
  disposeGltf(gltf.scene);
17712
17753
  return;
@@ -17758,20 +17799,9 @@ async function loadNaturalBodyModel(bo, ctx) {
17758
17799
  return;
17759
17800
  }
17760
17801
  if (detail.global?.orientation && !bo.body.orientation) applyBodyOrientation(bo.body, detail.global.orientation, detail.global.nut_prec, ctx);
17761
- const metaPromise = fetchBundleMeta(slug);
17762
- const gltf = await _loader.loadAsync(versionedUrl(`/v1/models/${slug}/high.glb`, "models"));
17763
- if ((bo.modelLoadEpoch ?? 0) !== epoch) {
17764
- disposeGltf(gltf.scene);
17765
- return;
17766
- }
17767
- let meta;
17768
- try {
17769
- meta = await metaPromise;
17770
- } catch (e) {
17771
- disposeGltf(gltf.scene);
17772
- console.warn(`Failed to load shape-model metadata for ${slug}:`, e);
17773
- return;
17774
- }
17802
+ const loaded = await loadModelBundle(slug, "high");
17803
+ if (!loaded) return;
17804
+ const { gltf, meta } = loaded;
17775
17805
  if ((bo.modelLoadEpoch ?? 0) !== epoch) {
17776
17806
  disposeGltf(gltf.scene);
17777
17807
  return;
@@ -37261,6 +37291,7 @@ var TIGHT_FAR_RELEASE = 2.3;
37261
37291
  var SUN_PROXY_FAR_FRACTION = .9;
37262
37292
  var _sunLiftDir = new Vector3();
37263
37293
  var _lookDir = new Vector3();
37294
+ var _groundDir = new Vector3();
37264
37295
  var SPIN_FOLLOW_NONE = 2;
37265
37296
  var _spinNow = new Quaternion();
37266
37297
  var _spinStep = new Quaternion();
@@ -38673,6 +38704,15 @@ var SceneRenderer = class SceneRenderer {
38673
38704
  const cam = this.camera;
38674
38705
  return !(cam.position.distanceToSquared(pos) <= cam.position.lengthSq() * 1e-10 && 8 * (1 - Math.abs(cam.quaternion.dot(quat))) <= 1e-8);
38675
38706
  }
38707
+ groundUnderCamera() {
38708
+ const body = this.focusController?.current;
38709
+ if (!body) return null;
38710
+ const down = _groundDir.copy(this.controls.orbitPosition).normalize();
38711
+ return {
38712
+ groundKm: this.motionGround.radiusKm(body, down) ?? effectiveRadiusKm(body.data),
38713
+ clearanceKm: this.motionGround.clearanceKm(body)
38714
+ };
38715
+ }
38676
38716
  lookSurfaceRadius = (direction) => {
38677
38717
  const focused = this.focusController.current;
38678
38718
  if (this.holdingCamera || this.focus.aim || !focused) return null;
@@ -42348,6 +42388,9 @@ var SpaceMap = class {
42348
42388
  getLimits() {
42349
42389
  return { ...this.limits };
42350
42390
  }
42391
+ getClosestApproach() {
42392
+ return this.renderer?.groundUnderCamera() ?? null;
42393
+ }
42351
42394
  applyLimits() {
42352
42395
  const l = this.limits;
42353
42396
  const band = {};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "spacemap",
3
- "version": "0.1.24",
3
+ "version": "0.1.25",
4
4
  "description": "The map of the Solar System from spacemap.co, on your website!",
5
5
  "keywords": ["solar system", "spacecraft", "orbits", "map", "three.js"],
6
6
  "homepage": "https://spacemap.co",