@found-in-space/skykit 0.2.0-alpha.20260530 → 0.2.0-alpha.20260531

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -69,17 +69,25 @@ Optional attributes keep small tweaks HTML-only:
69
69
  data-skykit-magnitude="7"
70
70
  data-skykit-speed="4"
71
71
  data-skykit-exposure="2600"
72
- data-skykit-look-at="05h 36m 12.81s, −01° 12′ 06.9″"
72
+ data-skykit-observer="06h 45m 08.9s, -16d 42m 58s, 2.64pc"
73
+ data-skykit-look-at="05h 35m 17.3s, -05d 23m 28s, 414pc"
74
+ data-skykit-coordinate-origin="solar"
73
75
  data-skykit-mouse-mode="strafe"
74
76
  data-skykit-persistent-cache="off"
75
77
  style="width: 100%; height: 520px; background: #02040b"
76
78
  ></div>
77
79
  ```
78
80
 
81
+ `data-skykit-observer` accepts fixed parsec-space `x,y,z` coordinates or
82
+ RA/Dec/distance text such as `06h 45m 08.9s, -16d 42m 58s, 2.64pc`.
79
83
  `data-skykit-look-at` accepts RA/Dec text such as
80
84
  `05h 36m 12.81s, −01° 12′ 06.9″`, decimal degrees such as
81
- `84.053393,-1.201926`, or a parsec-space `x,y,z` target for exact generated
82
- coordinates. `data-skykit-mouse-mode` defaults to `grab`; use `look` or
85
+ `84.053393,-1.201926`, RA/Dec/distance text for a fixed heliocentric target,
86
+ or a parsec-space `x,y,z` target for exact generated coordinates.
87
+ RA/Dec/distance resolves from the solar origin; pure RA/Dec remains a
88
+ directional look. `data-skykit-coordinate-origin="solar"` is accepted as
89
+ clarifying markup, while observer-relative shorthand is not part of this alpha
90
+ embed yet. `data-skykit-mouse-mode` defaults to `grab`; use `look` or
83
91
  `strafe` for the first-person mouse-look direction, or `none` to disable mouse
84
92
  drag controls. Persistent browser Cache API storage is enabled by default for
85
93
  octree ranges; set
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@found-in-space/skykit",
3
- "version": "0.2.0-alpha.20260530",
3
+ "version": "0.2.0-alpha.20260531",
4
4
  "description": "Slim composition and teaching layer for Found in Space packages",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -72,7 +72,7 @@
72
72
  "@found-in-space/anchored-image": "0.2.0-alpha.0",
73
73
  "@found-in-space/hr-diagram": "0.2.0-alpha.1",
74
74
  "@found-in-space/meta-sidecar-provider": "0.2.0-alpha.1",
75
- "@found-in-space/spatial": "0.2.0-alpha.20260529",
75
+ "@found-in-space/spatial": "0.2.0-alpha.20260530",
76
76
  "@found-in-space/star-octree-provider": "0.2.0-alpha.1",
77
77
  "@found-in-space/star-trees": "0.2.0-alpha.0",
78
78
  "@found-in-space/three-star-field": "0.2.0-alpha.0"
@@ -137,6 +137,35 @@ test('createSkykitBrowser accepts startup lookAt and mouse look mode', async ()
137
137
  });
138
138
  });
139
139
 
140
+ test('createSkykitBrowser starts from observer and solar RA/Dec distance lookAt', async () => {
141
+ await withFakeWindow(async () => {
142
+ const browser = await createSkykitBrowser({
143
+ host: createHost(),
144
+ status: false,
145
+ renderer: createRenderer(),
146
+ provider: createProvider(),
147
+ starField: createStarField(),
148
+ autoResize: false,
149
+ autoDispose: false,
150
+ autoStart: false,
151
+ lookAt: { raDeg: 90, decDeg: 0, distancePc: 10 },
152
+ view: {
153
+ observerPc: { x: 1, y: 0, z: 0 },
154
+ },
155
+ });
156
+
157
+ const view = browser.viewer.getViewState();
158
+ assert.deepEqual(view.observerPc, { x: 1, y: 0, z: 0 });
159
+ assertVectorApprox(view.targetPc, { x: 0, y: 10, z: 0 });
160
+ assertVectorApprox(
161
+ localVectorFromView(view, { x: 0, y: 0, z: -1 }),
162
+ normalizeVector({ x: -1, y: 10, z: 0 }),
163
+ );
164
+
165
+ await browser.dispose();
166
+ });
167
+ });
168
+
140
169
  test('createSkykitBrowser can disable mouse drag controls', async () => {
141
170
  await withFakeWindow(async () => {
142
171
  const browser = await createSkykitBrowser({
@@ -532,3 +561,26 @@ function createStarField() {
532
561
  },
533
562
  };
534
563
  }
564
+
565
+ function localVectorFromView(view, vector) {
566
+ const q = view.orientationIcrs ?? { x: 0, y: 0, z: 0, w: 1 };
567
+ const result = new THREE.Vector3(vector.x, vector.y, vector.z).applyQuaternion(
568
+ new THREE.Quaternion(q.x, q.y, q.z, q.w),
569
+ );
570
+ return { x: result.x, y: result.y, z: result.z };
571
+ }
572
+
573
+ function assertVectorApprox(actual, expected, epsilon = 1e-9) {
574
+ assert.ok(Math.abs(actual.x - expected.x) < epsilon, `x ${actual.x} !== ${expected.x}`);
575
+ assert.ok(Math.abs(actual.y - expected.y) < epsilon, `y ${actual.y} !== ${expected.y}`);
576
+ assert.ok(Math.abs(actual.z - expected.z) < epsilon, `z ${actual.z} !== ${expected.z}`);
577
+ }
578
+
579
+ function normalizeVector(vector) {
580
+ const length = Math.hypot(vector.x, vector.y, vector.z);
581
+ return {
582
+ x: vector.x / length,
583
+ y: vector.y / length,
584
+ z: vector.z / length,
585
+ };
586
+ }
@@ -7,6 +7,9 @@ import {
7
7
  encodeMorton3D,
8
8
  } from '@found-in-space/star-trees';
9
9
 
10
+ import {
11
+ resolveSpatialTarget,
12
+ } from '@found-in-space/spatial';
10
13
  import {
11
14
  SKYKIT_ACTION_NAMESPACE,
12
15
  SKYKIT_ACTIONS,
@@ -35,6 +38,7 @@ import {
35
38
  createStreamingStarLayer,
36
39
  createStreamingStarsPlugin,
37
40
  installSkykitDebugGlobal,
41
+ parseSpatialLookAtText,
38
42
  } from '../index.js';
39
43
 
40
44
  function createHost() {
@@ -327,6 +331,37 @@ test('viewer derives camera orientation from lookAt targets, sky coordinates, an
327
331
  );
328
332
  await alnilamViewer.dispose();
329
333
 
334
+ const siriusSpec = parseSpatialLookAtText('06h 45m 08.9s, -16d 42m 58s, 2.64pc');
335
+ const orionSpec = parseSpatialLookAtText('05h 35m 17.3s, -05d 23m 28s, 414pc');
336
+ const siriusPc = resolveSpatialTarget(siriusSpec);
337
+ const orionPc = resolveSpatialTarget(orionSpec);
338
+ assert.ok(siriusPc && orionPc && orionSpec);
339
+ const solarTargetViewer = await createSkykitViewer({
340
+ renderer: createRenderer(),
341
+ view: {
342
+ observerPc: siriusPc,
343
+ lookAt: orionSpec,
344
+ },
345
+ });
346
+ view = solarTargetViewer.getViewState();
347
+ assertVectorApprox(view.observerPc, siriusPc);
348
+ assertVectorApprox(view.targetPc, orionPc);
349
+ assertVectorApprox(
350
+ localVectorFromView(view, { x: 0, y: 0, z: -1 }),
351
+ normalizeVector(subtractVectors(orionPc, siriusPc)),
352
+ );
353
+
354
+ const movedObserver = { x: -8, y: 3, z: 11 };
355
+ solarTargetViewer.requestViewState({ observerPc: movedObserver, lookAt: orionSpec }, 'test-solar-radec');
356
+ solarTargetViewer.update(0);
357
+ view = solarTargetViewer.getViewState();
358
+ assertVectorApprox(view.targetPc, orionPc);
359
+ assertVectorApprox(
360
+ localVectorFromView(view, { x: 0, y: 0, z: -1 }),
361
+ normalizeVector(subtractVectors(orionPc, movedObserver)),
362
+ );
363
+ await solarTargetViewer.dispose();
364
+
330
365
  const starViewer = await createSkykitViewer({
331
366
  renderer: createRenderer(),
332
367
  view: { lookAt: { star: 'hyades' } },
@@ -1541,7 +1576,7 @@ test('navigation transition action restores pose with independent lane durations
1541
1576
  });
1542
1577
  viewer.update(1);
1543
1578
  viewer.update(0);
1544
- assert.deepEqual(viewer.getViewState().observerPc, { x: 20, y: 0, z: 0 });
1579
+ assert.deepEqual(viewer.getViewState().observerPc, { x: 10, y: 0, z: 0 });
1545
1580
  assert.deepEqual(viewer.getViewState().orientationIcrs, orientationAfterExplicitTransition);
1546
1581
 
1547
1582
  await viewer.actions.invoke(SKYKIT_ACTIONS.navigation.transitionTo, {
@@ -1984,6 +2019,23 @@ function assertVectorApprox(actual, expected, epsilon = 1e-9) {
1984
2019
  assert.ok(Math.abs(actual.z - expected.z) < epsilon, `z ${actual.z} !== ${expected.z}`);
1985
2020
  }
1986
2021
 
2022
+ function subtractVectors(a, b) {
2023
+ return {
2024
+ x: a.x - b.x,
2025
+ y: a.y - b.y,
2026
+ z: a.z - b.z,
2027
+ };
2028
+ }
2029
+
2030
+ function normalizeVector(vector) {
2031
+ const length = Math.hypot(vector.x, vector.y, vector.z);
2032
+ return {
2033
+ x: vector.x / length,
2034
+ y: vector.y / length,
2035
+ z: vector.z / length,
2036
+ };
2037
+ }
2038
+
1987
2039
  function directionFromRaDec(raDeg, decDeg) {
1988
2040
  const ra = raDeg * Math.PI / 180;
1989
2041
  const dec = decDeg * Math.PI / 180;
package/src/embed.js CHANGED
@@ -1,4 +1,7 @@
1
- import { parseSpatialLookAtText } from '@found-in-space/spatial';
1
+ import {
2
+ parseSpatialLookAtText,
3
+ resolveSpatialTarget,
4
+ } from '@found-in-space/spatial';
2
5
 
3
6
  import {
4
7
  installSkykitBrowserGlobal,
@@ -59,7 +62,14 @@ async function installRequestedCapabilities(host, browser) {
59
62
  /** @param {Element} host */
60
63
  function readOptions(host) {
61
64
  const data = isHtmlElement(host) ? host.dataset : {};
65
+ const observerPc = data.skykitObserver ? parseSpatialTargetText(data.skykitObserver) : null;
62
66
  const lookAt = data.skykitLookAt ? parseSpatialLookAtText(data.skykitLookAt) : null;
67
+ const view = observerPc || lookAt
68
+ ? {
69
+ ...(observerPc ? { observerPc } : {}),
70
+ ...(lookAt ? { lookAt } : {}),
71
+ }
72
+ : null;
63
73
  return {
64
74
  host,
65
75
  ...(data.skykitStatus ? { status: data.skykitStatus } : {}),
@@ -68,10 +78,19 @@ function readOptions(host) {
68
78
  ...(data.skykitExposure ? { exposure: Number(data.skykitExposure) } : {}),
69
79
  ...(data.skykitMouseMode ? { mouseMode: data.skykitMouseMode } : {}),
70
80
  ...(data.skykitPersistentCache ? { persistentCache: data.skykitPersistentCache } : {}),
71
- ...(lookAt ? { view: { lookAt } } : {}),
81
+ ...(view ? { view } : {}),
72
82
  };
73
83
  }
74
84
 
85
+ /** @param {string} text */
86
+ function parseSpatialTargetText(text) {
87
+ const targetSpec = parseSpatialLookAtText(text);
88
+ const target = resolveSpatialTarget(targetSpec);
89
+ return target && typeof /** @type {Promise<unknown>} */ (target).then !== 'function'
90
+ ? target
91
+ : null;
92
+ }
93
+
75
94
  /**
76
95
  * @param {Element} host
77
96
  * @param {import('./browser.d.ts').SkykitBrowser} browser