@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 +11 -3
- package/package.json +2 -2
- package/src/__tests__/skykit-browser.test.js +52 -0
- package/src/__tests__/skykit.test.js +53 -1
- package/src/embed.js +21 -2
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-
|
|
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`,
|
|
82
|
-
|
|
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.
|
|
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.
|
|
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:
|
|
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 {
|
|
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
|
-
...(
|
|
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
|