@found-in-space/skykit 0.2.0-alpha.1 → 0.2.0-alpha.20260528
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 +142 -11
- package/examples/custom-object-layer/custom-object-layer.js +1 -24
- package/examples/xr-free-roam/index.html +62 -4
- package/examples/xr-free-roam/xr-free-roam.css +249 -18
- package/examples/xr-free-roam/xr-free-roam.js +675 -274
- package/package.json +22 -6
- package/src/__tests__/skykit-anchored-images.test.js +32 -4
- package/src/__tests__/skykit-browser.test.js +267 -0
- package/src/__tests__/skykit-data.test.js +131 -0
- package/src/__tests__/skykit-parallax.test.js +4 -4
- package/src/__tests__/skykit-touch-os.test.js +71 -0
- package/src/__tests__/skykit-xr.test.js +179 -2
- package/src/__tests__/skykit.test.js +142 -506
- package/src/actions.js +0 -8
- package/src/anchored-images.js +14 -15
- package/src/browser-addons.d.ts +16 -0
- package/src/browser-addons.js +155 -0
- package/src/browser-constellations.d.ts +13 -0
- package/src/browser-constellations.js +387 -0
- package/src/browser.d.ts +81 -0
- package/src/browser.js +192 -13
- package/src/data.d.ts +133 -0
- package/src/data.js +447 -0
- package/src/embed.d.ts +5 -0
- package/src/embed.js +53 -2
- package/src/hr-diagram.js +23 -5
- package/src/index.d.ts +21 -73
- package/src/index.js +0 -1
- package/src/plugins.js +22 -708
- package/src/three-shim.d.ts +32 -0
- package/src/touch-os.d.ts +70 -0
- package/src/touch-os.js +275 -0
- package/src/utils.js +96 -6
- package/src/viewer-entry.d.ts +10 -0
- package/src/viewer-entry.js +4 -0
- package/src/viewer.js +110 -12
- package/src/xr/plugins.js +298 -13
- package/src/xr/session.js +60 -14
- package/src/xr.d.ts +40 -0
- package/src/xr.js +2 -0
package/README.md
CHANGED
|
@@ -20,6 +20,20 @@ strategies. SkyKit passes strategies through to provider sessions; it does not
|
|
|
20
20
|
redefine planning, inspect strategy kinds, or hide loader registries behind
|
|
21
21
|
string names.
|
|
22
22
|
|
|
23
|
+
## Website Use-Cases
|
|
24
|
+
|
|
25
|
+
The beginner website entries are use-case bounded:
|
|
26
|
+
|
|
27
|
+
| Use-case | Website owner says | Public entry |
|
|
28
|
+
| --- | --- | --- |
|
|
29
|
+
| Viewer | "Put stars on my page and let me customize the scene." | `embed.js`, `viewer.js` |
|
|
30
|
+
| Data | "Give me star data so I can render, list, map, or game it myself." | `data.js` |
|
|
31
|
+
|
|
32
|
+
`embed.js` is the no-code viewer entry. It is not a separate use-case.
|
|
33
|
+
`viewer.js` is the JavaScript-customizable viewer entry. `data.js` is renderer
|
|
34
|
+
independent. Authored chapters stay in website or lesson code and call SkyKit
|
|
35
|
+
navigation actions directly.
|
|
36
|
+
|
|
23
37
|
## Paste into a static page or CMS
|
|
24
38
|
|
|
25
39
|
For the beginner path, use the auto-booting embed. Paste this into a static HTML
|
|
@@ -36,7 +50,7 @@ page or a CMS custom HTML block:
|
|
|
36
50
|
|
|
37
51
|
<script
|
|
38
52
|
type="module"
|
|
39
|
-
src="https://esm.sh/@found-in-space/skykit/embed?bundle"
|
|
53
|
+
src="https://esm.sh/@found-in-space/skykit@0.2.0-alpha.2/embed?bundle&deps=three@0.170.0"
|
|
40
54
|
></script>
|
|
41
55
|
```
|
|
42
56
|
|
|
@@ -55,19 +69,73 @@ Optional attributes keep small tweaks HTML-only:
|
|
|
55
69
|
data-skykit-magnitude="7"
|
|
56
70
|
data-skykit-speed="4"
|
|
57
71
|
data-skykit-exposure="2600"
|
|
72
|
+
data-skykit-look-at="ra=4.496h, dec=16.948"
|
|
73
|
+
data-skykit-mouse-mode="strafe"
|
|
74
|
+
data-skykit-persistent-cache="off"
|
|
58
75
|
style="width: 100%; height: 520px; background: #02040b"
|
|
59
76
|
></div>
|
|
60
77
|
```
|
|
61
78
|
|
|
79
|
+
`data-skykit-look-at` accepts RA/Dec text such as
|
|
80
|
+
`ra=4.496h, dec=16.948`, decimal degrees such as `67.447,16.948`, or a
|
|
81
|
+
parsec-space `x,y,z` target for exact generated coordinates. `data-skykit-mouse-mode`
|
|
82
|
+
defaults to `grab`; use `look` or `strafe` for the first-person mouse-look
|
|
83
|
+
direction, or `none` to disable mouse drag controls. Persistent browser Cache API
|
|
84
|
+
storage is enabled by default for octree ranges; set
|
|
85
|
+
`data-skykit-persistent-cache="off"` to keep caching session-only.
|
|
86
|
+
|
|
62
87
|
The host dispatches `skykit-browser-ready` with `{ browser, viewer }` in
|
|
63
88
|
`event.detail` after startup, and `skykit-browser-error` if startup fails. The
|
|
64
|
-
embed
|
|
89
|
+
embed also installs a small `Skykit` global for noob-path scripts:
|
|
65
90
|
|
|
66
|
-
|
|
67
|
-
|
|
91
|
+
```js
|
|
92
|
+
const browser = await Skykit.whenReady();
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
Pages can host multiple viewers. Pass a selector or element to choose one:
|
|
96
|
+
|
|
97
|
+
```js
|
|
98
|
+
const browser = await Skykit.whenReady('#orion-viewer');
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
Pin the package CDN URL to a released SkyKit version when publishing long-lived
|
|
102
|
+
pages, for example
|
|
68
103
|
`https://esm.sh/@found-in-space/skykit@x.y.z/embed?bundle&deps=three@0.170.0`.
|
|
69
104
|
|
|
70
|
-
|
|
105
|
+
Optional first-party capabilities stay out of the initial browser until they are
|
|
106
|
+
requested. This keeps the one-script noob path while avoiding bundle bloat.
|
|
107
|
+
|
|
108
|
+
```html
|
|
109
|
+
<div
|
|
110
|
+
data-skykit-browser
|
|
111
|
+
data-skykit-constellations="western"
|
|
112
|
+
data-skykit-constellation-art="off"
|
|
113
|
+
style="width:100%;height:520px;background:#02040b"
|
|
114
|
+
></div>
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
For small scripted interactions, use the browser handle:
|
|
118
|
+
|
|
119
|
+
```html
|
|
120
|
+
<script type="module">
|
|
121
|
+
import {
|
|
122
|
+
SKYKIT_ACTIONS,
|
|
123
|
+
createSkykitNavigationPlugin,
|
|
124
|
+
} from 'https://esm.sh/@found-in-space/skykit';
|
|
125
|
+
|
|
126
|
+
const browser = await Skykit.whenReady();
|
|
127
|
+
await browser.install(createSkykitNavigationPlugin());
|
|
128
|
+
|
|
129
|
+
document.querySelector('#orion').addEventListener('click', () => {
|
|
130
|
+
browser.viewer.actions.invoke(SKYKIT_ACTIONS.navigation.transitionTo, {
|
|
131
|
+
view: { lookAt: 'ra=5.919h, dec=7.407' },
|
|
132
|
+
movement: { durationSecs: 3 },
|
|
133
|
+
});
|
|
134
|
+
});
|
|
135
|
+
</script>
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
## Create a Viewer from JavaScript
|
|
71
139
|
|
|
72
140
|
If your site has a module script, npm, or a bundler, call the helper directly:
|
|
73
141
|
|
|
@@ -76,7 +144,7 @@ If your site has a module script, npm, or a bundler, call the helper directly:
|
|
|
76
144
|
<pre id="status">Loading stars...</pre>
|
|
77
145
|
|
|
78
146
|
<script type="module">
|
|
79
|
-
import { createSkykitBrowser } from '
|
|
147
|
+
import { createSkykitBrowser } from 'https://esm.sh/@found-in-space/skykit@0.2.0-alpha.2/viewer?bundle&deps=three@0.170.0';
|
|
80
148
|
|
|
81
149
|
await createSkykitBrowser({
|
|
82
150
|
host: '#viewer',
|
|
@@ -91,10 +159,52 @@ The helper still returns the pieces when a lesson wants to grow:
|
|
|
91
159
|
const sky = await createSkykitBrowser('#viewer');
|
|
92
160
|
|
|
93
161
|
sky.viewer.requestViewState({ observerPc: { x: 4, y: 0, z: -8 } });
|
|
162
|
+
sky.addObject(marker, {
|
|
163
|
+
positionPc: { x: 17.574, y: 42.316, z: 13.963 },
|
|
164
|
+
});
|
|
94
165
|
sky.loop.stop();
|
|
95
166
|
await sky.dispose();
|
|
96
167
|
```
|
|
97
168
|
|
|
169
|
+
For npm or bundlers, use the same beginner entry:
|
|
170
|
+
|
|
171
|
+
```js
|
|
172
|
+
import { THREE, createSkykitBrowser } from '@found-in-space/skykit/viewer';
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
## Use Star Data Without a Viewer
|
|
176
|
+
|
|
177
|
+
Use `data.js` when SkyKit should supply rows and your app should own rendering:
|
|
178
|
+
|
|
179
|
+
```js
|
|
180
|
+
import { loadStarRows } from 'https://esm.sh/@found-in-space/skykit@0.2.0-alpha.2/data?bundle';
|
|
181
|
+
|
|
182
|
+
const stars = await loadStarRows({
|
|
183
|
+
limitingMagnitude: 6.5,
|
|
184
|
+
maxStars: 100,
|
|
185
|
+
sortBy: 'apparentMagnitude',
|
|
186
|
+
});
|
|
187
|
+
|
|
188
|
+
console.table(stars);
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
For games and maps, load a local volume and hand rows to Canvas, PixiJS,
|
|
192
|
+
Phaser, SVG, or your own renderer:
|
|
193
|
+
|
|
194
|
+
```js
|
|
195
|
+
const stars = await loadStarRows({
|
|
196
|
+
centerPc: { x: 0, y: 0, z: 0 },
|
|
197
|
+
radiusPc: 50,
|
|
198
|
+
maxStars: 2000,
|
|
199
|
+
});
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
## Author Chapters
|
|
203
|
+
|
|
204
|
+
Keep named chapters in the website or lesson script. Each chapter can call
|
|
205
|
+
navigation actions such as `skykit:navigation.transitionTo` and
|
|
206
|
+
`skykit:navigation.orbit` from its own `goTo(id)` dispatcher.
|
|
207
|
+
|
|
98
208
|
Use the lower-level factories when a lesson is teaching composition or replacing
|
|
99
209
|
a part of the stack:
|
|
100
210
|
|
|
@@ -208,7 +318,7 @@ names, not renderer or loader factory names:
|
|
|
208
318
|
SKYKIT_ACTIONS.ship.moveForward; // "skykit:ship.move.forward"
|
|
209
319
|
SKYKIT_CONTROLS.observer.parallaxOffset; // "skykit:observer.control.parallaxOffset"
|
|
210
320
|
SKYKIT_ACTIONS.viewer.reset; // "skykit:viewer.reset"
|
|
211
|
-
SKYKIT_ACTIONS.
|
|
321
|
+
SKYKIT_ACTIONS.navigation.transitionTo; // "skykit:navigation.transitionTo"
|
|
212
322
|
```
|
|
213
323
|
|
|
214
324
|
Plugins can add their own namespaces:
|
|
@@ -221,13 +331,13 @@ const firePlugin = (ctx) => {
|
|
|
221
331
|
};
|
|
222
332
|
```
|
|
223
333
|
|
|
224
|
-
DOM buttons, touch surfaces, keyboard bindings, XR controls,
|
|
225
|
-
tools can all call the same action:
|
|
334
|
+
DOM buttons, touch surfaces, keyboard bindings, XR controls, app-owned chapters,
|
|
335
|
+
and debug tools can all call the same action:
|
|
226
336
|
|
|
227
337
|
```js
|
|
228
338
|
button.addEventListener('click', () => {
|
|
229
|
-
viewer.actions.invoke(
|
|
230
|
-
|
|
339
|
+
viewer.actions.invoke('website:chapter.goTo', {
|
|
340
|
+
id: 'hyades-arrival',
|
|
231
341
|
});
|
|
232
342
|
});
|
|
233
343
|
```
|
|
@@ -263,6 +373,27 @@ For a slightly more playful example, see `examples/plugin-lab.js`. It builds
|
|
|
263
373
|
app-owned Three objects and action-driven annotations from the same public hooks
|
|
264
374
|
a learner would use.
|
|
265
375
|
|
|
376
|
+
The pasteable browser embed has a smaller add-on convention for noob pages:
|
|
377
|
+
|
|
378
|
+
```js
|
|
379
|
+
Skykit.registerBrowserAddon({
|
|
380
|
+
id: 'lesson:marker',
|
|
381
|
+
install({ browser, THREE }) {
|
|
382
|
+
const marker = new THREE.Mesh(
|
|
383
|
+
new THREE.SphereGeometry(0.02),
|
|
384
|
+
new THREE.MeshBasicMaterial({ color: 0xffcc00 }),
|
|
385
|
+
);
|
|
386
|
+
const handle = browser.addObject(marker, {
|
|
387
|
+
positionPc: { x: 17.574, y: 42.316, z: 13.963 },
|
|
388
|
+
});
|
|
389
|
+
return () => handle.dispose();
|
|
390
|
+
},
|
|
391
|
+
});
|
|
392
|
+
```
|
|
393
|
+
|
|
394
|
+
See `docs/skykit-browser-plugins.md` for the browser add-on spec,
|
|
395
|
+
`Skykit.whenReady()`, and first-party constellation support.
|
|
396
|
+
|
|
266
397
|
Browser lessons:
|
|
267
398
|
|
|
268
399
|
- `examples/free-roam-lesson/` composes streamed stars, keyboard navigation,
|
|
@@ -145,7 +145,7 @@ function createInitialViewState() {
|
|
|
145
145
|
observerPc: { x: 0, y: 0, z: 0 },
|
|
146
146
|
coordinateUnitsPerParsec: UNITS_PER_PARSEC,
|
|
147
147
|
limitingMagnitude: 7.5,
|
|
148
|
-
|
|
148
|
+
lookAt: { targetPc: HYADES_CENTER_PC },
|
|
149
149
|
};
|
|
150
150
|
}
|
|
151
151
|
|
|
@@ -332,29 +332,6 @@ function toRenderPosition(pointPc) {
|
|
|
332
332
|
);
|
|
333
333
|
}
|
|
334
334
|
|
|
335
|
-
function lookAtFromOriginWithNorthUp(targetPc) {
|
|
336
|
-
const forward = new THREE.Vector3(targetPc.x, targetPc.y, targetPc.z).normalize();
|
|
337
|
-
const north = new THREE.Vector3(0, 0, 1);
|
|
338
|
-
let up = north.clone().sub(forward.clone().multiplyScalar(north.dot(forward)));
|
|
339
|
-
if (up.lengthSq() < 1e-8) {
|
|
340
|
-
up = new THREE.Vector3(0, 1, 0);
|
|
341
|
-
}
|
|
342
|
-
up.normalize();
|
|
343
|
-
|
|
344
|
-
const backward = forward.clone().negate();
|
|
345
|
-
const right = up.clone().cross(backward).normalize();
|
|
346
|
-
up = backward.clone().cross(right).normalize();
|
|
347
|
-
|
|
348
|
-
const matrix = new THREE.Matrix4().makeBasis(right, up, backward);
|
|
349
|
-
const quaternion = new THREE.Quaternion().setFromRotationMatrix(matrix);
|
|
350
|
-
return {
|
|
351
|
-
x: quaternion.x,
|
|
352
|
-
y: quaternion.y,
|
|
353
|
-
z: quaternion.z,
|
|
354
|
-
w: quaternion.w,
|
|
355
|
-
};
|
|
356
|
-
}
|
|
357
|
-
|
|
358
335
|
function directionFromRaDec(raDeg, decDeg) {
|
|
359
336
|
const ra = THREE.MathUtils.degToRad(raDeg);
|
|
360
337
|
const dec = THREE.MathUtils.degToRad(decDeg);
|
|
@@ -10,10 +10,68 @@
|
|
|
10
10
|
<body>
|
|
11
11
|
<main class="xr-free-roam-shell">
|
|
12
12
|
<div class="viewer-shell" data-viewer></div>
|
|
13
|
-
<
|
|
14
|
-
<
|
|
15
|
-
|
|
16
|
-
|
|
13
|
+
<section class="xr-preflight" data-preflight aria-labelledby="xr-preflight-title">
|
|
14
|
+
<div class="xr-preflight-copy">
|
|
15
|
+
<p class="xr-kicker">SkyKit XR</p>
|
|
16
|
+
<h1 id="xr-preflight-title">Free Roam Preflight</h1>
|
|
17
|
+
<p>
|
|
18
|
+
Choose the rendering defaults for this headset run, then enter the immersive session.
|
|
19
|
+
</p>
|
|
20
|
+
<dl class="xr-status-list">
|
|
21
|
+
<div>
|
|
22
|
+
<dt>WebXR</dt>
|
|
23
|
+
<dd data-xr-supported>Checking</dd>
|
|
24
|
+
</div>
|
|
25
|
+
<div>
|
|
26
|
+
<dt>Scale</dt>
|
|
27
|
+
<dd data-setting-value="worldScaleLog10">1 m/pc</dd>
|
|
28
|
+
</div>
|
|
29
|
+
<div>
|
|
30
|
+
<dt>Stars</dt>
|
|
31
|
+
<dd data-setting-value="limitingMagnitude">Mag 7.5</dd>
|
|
32
|
+
</div>
|
|
33
|
+
</dl>
|
|
34
|
+
</div>
|
|
35
|
+
|
|
36
|
+
<form class="xr-settings" data-xr-settings>
|
|
37
|
+
<fieldset>
|
|
38
|
+
<legend>Rendering</legend>
|
|
39
|
+
<label>
|
|
40
|
+
<span>Magnitude limit</span>
|
|
41
|
+
<output data-setting-value="limitingMagnitude">7.5</output>
|
|
42
|
+
<input data-setting="limitingMagnitude" type="range" min="4" max="10" step="0.1" value="7.5" />
|
|
43
|
+
</label>
|
|
44
|
+
<label>
|
|
45
|
+
<span>Exposure</span>
|
|
46
|
+
<output data-setting-value="exposureLog10">100,000</output>
|
|
47
|
+
<input data-setting="exposureLog10" type="range" min="3.5" max="5.5" step="0.05" value="5" />
|
|
48
|
+
</label>
|
|
49
|
+
<label>
|
|
50
|
+
<span>World scale</span>
|
|
51
|
+
<output data-setting-value="worldScaleLog10">1 m/pc</output>
|
|
52
|
+
<input data-setting="worldScaleLog10" type="range" min="-3" max="0" step="0.05" value="0" />
|
|
53
|
+
</label>
|
|
54
|
+
</fieldset>
|
|
55
|
+
|
|
56
|
+
<fieldset>
|
|
57
|
+
<legend>Session Flags</legend>
|
|
58
|
+
<label class="xr-toggle">
|
|
59
|
+
<input data-setting="nearFloor" type="checkbox" checked />
|
|
60
|
+
<span>Near-star readability floor</span>
|
|
61
|
+
</label>
|
|
62
|
+
<label class="xr-toggle">
|
|
63
|
+
<input data-setting="constellationArt" type="checkbox" checked />
|
|
64
|
+
<span>Constellation art</span>
|
|
65
|
+
</label>
|
|
66
|
+
</fieldset>
|
|
67
|
+
|
|
68
|
+
<div class="xr-actions" aria-label="XR actions">
|
|
69
|
+
<button class="xr-primary-action" type="button" data-action="enter-xr">Enter VR</button>
|
|
70
|
+
<button type="button" data-action="exit-xr" hidden disabled>Exit VR</button>
|
|
71
|
+
</div>
|
|
72
|
+
<p class="xr-session-status" data-session-status>Idle</p>
|
|
73
|
+
</form>
|
|
74
|
+
</section>
|
|
17
75
|
</main>
|
|
18
76
|
<script type="module" src="./xr-free-roam.js"></script>
|
|
19
77
|
</body>
|
|
@@ -2,9 +2,20 @@ html,
|
|
|
2
2
|
body {
|
|
3
3
|
margin: 0;
|
|
4
4
|
width: 100%;
|
|
5
|
+
min-width: 320px;
|
|
5
6
|
height: 100%;
|
|
6
7
|
overflow: hidden;
|
|
7
|
-
background: #
|
|
8
|
+
background: #05070b;
|
|
9
|
+
color: #f4efe2;
|
|
10
|
+
font: 16px/1.45 "Avenir Next", Avenir, "Segoe UI", sans-serif;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
* {
|
|
14
|
+
box-sizing: border-box;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
[hidden] {
|
|
18
|
+
display: none !important;
|
|
8
19
|
}
|
|
9
20
|
|
|
10
21
|
.xr-free-roam-shell,
|
|
@@ -13,39 +24,259 @@ body {
|
|
|
13
24
|
inset: 0;
|
|
14
25
|
}
|
|
15
26
|
|
|
27
|
+
.xr-free-roam-shell {
|
|
28
|
+
background:
|
|
29
|
+
linear-gradient(90deg, rgba(5, 7, 11, 0.96) 0%, rgba(5, 7, 11, 0.84) 46%, rgba(5, 7, 11, 0.58) 100%),
|
|
30
|
+
#05070b;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
.viewer-shell {
|
|
34
|
+
z-index: 0;
|
|
35
|
+
opacity: 0.34;
|
|
36
|
+
filter: saturate(0.78) contrast(1.08);
|
|
37
|
+
pointer-events: none;
|
|
38
|
+
transition: opacity 0.18s ease, filter 0.18s ease;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
.xr-free-roam-shell.is-presenting .viewer-shell {
|
|
42
|
+
opacity: 1;
|
|
43
|
+
filter: none;
|
|
44
|
+
pointer-events: auto;
|
|
45
|
+
}
|
|
46
|
+
|
|
16
47
|
.viewer-shell canvas {
|
|
17
48
|
display: block;
|
|
18
49
|
width: 100%;
|
|
19
50
|
height: 100%;
|
|
20
|
-
cursor:
|
|
51
|
+
cursor: default;
|
|
21
52
|
touch-action: none;
|
|
22
53
|
user-select: none;
|
|
23
54
|
}
|
|
24
55
|
|
|
25
|
-
.
|
|
26
|
-
|
|
56
|
+
.xr-preflight {
|
|
57
|
+
position: fixed;
|
|
58
|
+
inset: 0;
|
|
59
|
+
z-index: 10;
|
|
60
|
+
display: grid;
|
|
61
|
+
grid-template-columns: minmax(0, 1fr) minmax(320px, 430px);
|
|
62
|
+
gap: clamp(24px, 5vw, 72px);
|
|
63
|
+
align-items: center;
|
|
64
|
+
width: 100%;
|
|
65
|
+
height: 100%;
|
|
66
|
+
padding: clamp(24px, 6vh, 72px) clamp(18px, 7vw, 92px);
|
|
67
|
+
overflow: auto;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
.xr-free-roam-shell.is-presenting .xr-preflight {
|
|
71
|
+
display: none;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
.xr-preflight-copy {
|
|
75
|
+
max-width: 720px;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
.xr-kicker {
|
|
79
|
+
margin: 0 0 10px;
|
|
80
|
+
color: #6fd7c3;
|
|
81
|
+
font-size: 0.82rem;
|
|
82
|
+
font-weight: 700;
|
|
83
|
+
text-transform: uppercase;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
.xr-preflight h1 {
|
|
87
|
+
margin: 0;
|
|
88
|
+
max-width: 11ch;
|
|
89
|
+
color: #fff9e8;
|
|
90
|
+
font-size: clamp(2.6rem, 6vh, 5.6rem);
|
|
91
|
+
line-height: 0.96;
|
|
92
|
+
font-weight: 760;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
.xr-preflight-copy > p:not(.xr-kicker) {
|
|
96
|
+
max-width: 46rem;
|
|
97
|
+
margin: 22px 0 0;
|
|
98
|
+
color: #cfc7b8;
|
|
99
|
+
font-size: 1.08rem;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
.xr-status-list {
|
|
103
|
+
display: grid;
|
|
104
|
+
grid-template-columns: repeat(3, minmax(0, 1fr));
|
|
105
|
+
gap: 1px;
|
|
106
|
+
max-width: 620px;
|
|
107
|
+
margin: 34px 0 0;
|
|
108
|
+
padding: 1px;
|
|
109
|
+
background: rgba(244, 239, 226, 0.14);
|
|
110
|
+
border-radius: 8px;
|
|
111
|
+
overflow: hidden;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
.xr-status-list div {
|
|
115
|
+
min-width: 0;
|
|
116
|
+
padding: 13px 14px;
|
|
117
|
+
background: rgba(15, 18, 18, 0.88);
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
.xr-status-list dt {
|
|
121
|
+
color: #a7b2ac;
|
|
122
|
+
font-size: 0.76rem;
|
|
123
|
+
font-weight: 700;
|
|
124
|
+
text-transform: uppercase;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
.xr-status-list dd {
|
|
128
|
+
margin: 4px 0 0;
|
|
129
|
+
color: #fff6dd;
|
|
130
|
+
font-weight: 700;
|
|
131
|
+
overflow-wrap: anywhere;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
.xr-settings {
|
|
135
|
+
display: grid;
|
|
136
|
+
gap: 14px;
|
|
137
|
+
width: min(100%, 430px);
|
|
138
|
+
padding: 18px;
|
|
139
|
+
border: 1px solid rgba(244, 239, 226, 0.18);
|
|
140
|
+
border-radius: 8px;
|
|
141
|
+
background: rgba(14, 17, 16, 0.88);
|
|
142
|
+
box-shadow: 0 24px 80px rgba(0, 0, 0, 0.28);
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
.xr-settings fieldset {
|
|
146
|
+
display: grid;
|
|
147
|
+
gap: 14px;
|
|
148
|
+
min-width: 0;
|
|
149
|
+
margin: 0;
|
|
150
|
+
padding: 0 0 16px;
|
|
151
|
+
border: 0;
|
|
152
|
+
border-bottom: 1px solid rgba(244, 239, 226, 0.13);
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
.xr-settings fieldset:last-of-type {
|
|
156
|
+
padding-bottom: 2px;
|
|
157
|
+
border-bottom: 0;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
.xr-settings legend {
|
|
161
|
+
padding: 0;
|
|
162
|
+
color: #d9b779;
|
|
163
|
+
font-size: 0.82rem;
|
|
164
|
+
font-weight: 760;
|
|
165
|
+
text-transform: uppercase;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
.xr-settings label:not(.xr-toggle) {
|
|
169
|
+
display: grid;
|
|
170
|
+
grid-template-columns: 1fr auto;
|
|
171
|
+
gap: 8px 14px;
|
|
172
|
+
align-items: center;
|
|
173
|
+
color: #f4efe2;
|
|
174
|
+
font-weight: 650;
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
.xr-settings output {
|
|
178
|
+
color: #9ddbd1;
|
|
179
|
+
font-variant-numeric: tabular-nums;
|
|
180
|
+
font-weight: 760;
|
|
181
|
+
text-align: right;
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
.xr-settings input[type="range"] {
|
|
185
|
+
grid-column: 1 / -1;
|
|
186
|
+
width: 100%;
|
|
187
|
+
accent-color: #d9b779;
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
.xr-toggle {
|
|
191
|
+
display: grid;
|
|
192
|
+
grid-template-columns: 22px 1fr;
|
|
193
|
+
gap: 10px;
|
|
194
|
+
align-items: center;
|
|
195
|
+
min-height: 32px;
|
|
196
|
+
color: #e8dfcf;
|
|
197
|
+
font-weight: 650;
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
.xr-toggle input {
|
|
201
|
+
width: 18px;
|
|
202
|
+
height: 18px;
|
|
203
|
+
accent-color: #6fd7c3;
|
|
27
204
|
}
|
|
28
205
|
|
|
29
206
|
.xr-actions {
|
|
30
|
-
position: fixed;
|
|
31
|
-
top: 16px;
|
|
32
|
-
right: 16px;
|
|
33
|
-
z-index: 10;
|
|
34
207
|
display: flex;
|
|
35
|
-
|
|
208
|
+
flex-wrap: wrap;
|
|
209
|
+
gap: 10px;
|
|
36
210
|
}
|
|
37
211
|
|
|
38
212
|
.xr-actions button {
|
|
39
|
-
min-height:
|
|
40
|
-
padding: 0
|
|
41
|
-
border: 1px solid rgba(
|
|
213
|
+
min-height: 42px;
|
|
214
|
+
padding: 0 16px;
|
|
215
|
+
border: 1px solid rgba(244, 239, 226, 0.24);
|
|
42
216
|
border-radius: 8px;
|
|
43
|
-
background: rgba(
|
|
44
|
-
color: #
|
|
45
|
-
font:
|
|
217
|
+
background: rgba(244, 239, 226, 0.08);
|
|
218
|
+
color: #fff9e8;
|
|
219
|
+
font: inherit;
|
|
220
|
+
font-weight: 760;
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
.xr-actions button:hover:not(:disabled) {
|
|
224
|
+
border-color: rgba(244, 239, 226, 0.72);
|
|
225
|
+
background: rgba(244, 239, 226, 0.13);
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
.xr-actions button:disabled {
|
|
229
|
+
cursor: not-allowed;
|
|
230
|
+
opacity: 0.55;
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
.xr-actions .xr-primary-action {
|
|
234
|
+
min-width: 144px;
|
|
235
|
+
border-color: rgba(217, 183, 121, 0.72);
|
|
236
|
+
background: #d9b779;
|
|
237
|
+
color: #101313;
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
.xr-actions .xr-primary-action:hover:not(:disabled) {
|
|
241
|
+
border-color: #ffe0a6;
|
|
242
|
+
background: #e8c987;
|
|
46
243
|
}
|
|
47
244
|
|
|
48
|
-
.xr-
|
|
49
|
-
|
|
50
|
-
|
|
245
|
+
.xr-session-status {
|
|
246
|
+
min-height: 1.4em;
|
|
247
|
+
margin: 0;
|
|
248
|
+
color: #a7b2ac;
|
|
249
|
+
font-size: 0.88rem;
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
@media (max-width: 820px) {
|
|
253
|
+
.xr-preflight {
|
|
254
|
+
grid-template-columns: 1fr;
|
|
255
|
+
align-content: start;
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
.xr-preflight h1 {
|
|
259
|
+
max-width: 13ch;
|
|
260
|
+
font-size: clamp(2.3rem, 12vw, 4.4rem);
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
.xr-status-list {
|
|
264
|
+
grid-template-columns: 1fr;
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
.xr-settings {
|
|
268
|
+
width: 100%;
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
@media (max-height: 640px) and (min-width: 821px) {
|
|
273
|
+
.xr-preflight {
|
|
274
|
+
align-items: start;
|
|
275
|
+
padding-top: 28px;
|
|
276
|
+
padding-bottom: 28px;
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
.xr-preflight h1 {
|
|
280
|
+
font-size: 3.4rem;
|
|
281
|
+
}
|
|
51
282
|
}
|