worldorbit 3.0.6 → 3.1.0
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 +2 -2
- package/dist/browser/core/dist/atlas-edit.js +5 -1
- package/dist/browser/core/dist/atlas-validate.js +1 -1
- package/dist/browser/core/dist/draft-parse.js +14 -9
- package/dist/browser/core/dist/draft.d.ts +1 -0
- package/dist/browser/core/dist/draft.js +4 -2
- package/dist/browser/core/dist/format.js +5 -3
- package/dist/browser/core/dist/load.js +3 -2
- package/dist/browser/core/dist/normalize.js +36 -0
- package/dist/browser/core/dist/parse.js +54 -0
- package/dist/browser/core/dist/scene.js +1 -0
- package/dist/browser/core/dist/types.d.ts +21 -1
- package/dist/browser/viewer/dist/runtime-3d.js +396 -117
- package/dist/browser/viewer/dist/theme.js +27 -0
- package/dist/browser/viewer/dist/types.d.ts +17 -0
- package/dist/browser/viewer/dist/viewer.js +51 -0
- package/dist/unpkg/core/dist/atlas-edit.js +5 -1
- package/dist/unpkg/core/dist/atlas-validate.js +1 -1
- package/dist/unpkg/core/dist/draft-parse.js +14 -9
- package/dist/unpkg/core/dist/draft.d.ts +1 -0
- package/dist/unpkg/core/dist/draft.js +4 -2
- package/dist/unpkg/core/dist/format.js +5 -3
- package/dist/unpkg/core/dist/load.js +3 -2
- package/dist/unpkg/core/dist/normalize.js +36 -0
- package/dist/unpkg/core/dist/parse.js +54 -0
- package/dist/unpkg/core/dist/scene.js +1 -0
- package/dist/unpkg/core/dist/types.d.ts +21 -1
- package/dist/unpkg/viewer/dist/runtime-3d.js +396 -117
- package/dist/unpkg/viewer/dist/theme.js +27 -0
- package/dist/unpkg/viewer/dist/types.d.ts +17 -0
- package/dist/unpkg/viewer/dist/viewer.js +51 -0
- package/dist/unpkg/worldorbit-core.min.js +9 -9
- package/dist/unpkg/worldorbit-editor.min.js +360 -356
- package/dist/unpkg/worldorbit-markdown.min.js +20 -20
- package/dist/unpkg/worldorbit-viewer.min.js +210 -206
- package/dist/unpkg/worldorbit.js +557 -120
- package/dist/unpkg/worldorbit.min.js +216 -212
- package/package.json +1 -1
- package/packages/core/dist/atlas-edit.js +5 -1
- package/packages/core/dist/atlas-validate.js +1 -1
- package/packages/core/dist/draft-parse.js +14 -9
- package/packages/core/dist/draft.d.ts +1 -0
- package/packages/core/dist/draft.js +4 -2
- package/packages/core/dist/format.js +5 -3
- package/packages/core/dist/load.js +3 -2
- package/packages/core/dist/normalize.js +36 -0
- package/packages/core/dist/parse.js +54 -0
- package/packages/core/dist/scene.js +1 -0
- package/packages/core/dist/types.d.ts +21 -1
- package/packages/viewer/dist/runtime-3d.js +396 -117
- package/packages/viewer/dist/theme.js +27 -0
- package/packages/viewer/dist/types.d.ts +17 -0
- package/packages/viewer/dist/viewer.js +51 -0
package/dist/unpkg/worldorbit.js
CHANGED
|
@@ -31171,9 +31171,14 @@ void main() {
|
|
|
31171
31171
|
function parseWorldOrbit(source) {
|
|
31172
31172
|
const lines = source.split(/\r?\n/);
|
|
31173
31173
|
const objects = [];
|
|
31174
|
+
let themeNode = null;
|
|
31174
31175
|
let currentObject = null;
|
|
31175
31176
|
let inInfoBlock = false;
|
|
31177
|
+
let inThemeBlock = false;
|
|
31176
31178
|
let infoIndent = null;
|
|
31179
|
+
let themeIndent = null;
|
|
31180
|
+
let themeBlockIndent = null;
|
|
31181
|
+
let currentThemeBlock = null;
|
|
31177
31182
|
for (let index = 0; index < lines.length; index++) {
|
|
31178
31183
|
const rawLine = lines[index];
|
|
31179
31184
|
const lineNumber = index + 1;
|
|
@@ -31190,12 +31195,48 @@ void main() {
|
|
|
31190
31195
|
}
|
|
31191
31196
|
if (indent === 0) {
|
|
31192
31197
|
inInfoBlock = false;
|
|
31198
|
+
inThemeBlock = false;
|
|
31193
31199
|
infoIndent = null;
|
|
31200
|
+
themeIndent = null;
|
|
31201
|
+
themeBlockIndent = null;
|
|
31202
|
+
currentThemeBlock = null;
|
|
31203
|
+
if (tokens.length >= 1 && tokens[0].value === "theme") {
|
|
31204
|
+
inThemeBlock = true;
|
|
31205
|
+
themeIndent = 0;
|
|
31206
|
+
themeNode = {
|
|
31207
|
+
type: "theme",
|
|
31208
|
+
preset: tokens.length >= 2 ? tokens[1].value : null,
|
|
31209
|
+
blocks: [],
|
|
31210
|
+
location: { line: lineNumber, column: tokens[0].column }
|
|
31211
|
+
};
|
|
31212
|
+
continue;
|
|
31213
|
+
}
|
|
31194
31214
|
const objectNode = parseObjectHeader(tokens, lineNumber);
|
|
31195
31215
|
objects.push(objectNode);
|
|
31196
31216
|
currentObject = objectNode;
|
|
31197
31217
|
continue;
|
|
31198
31218
|
}
|
|
31219
|
+
if (inThemeBlock) {
|
|
31220
|
+
if (tokens.length >= 2 && tokens[0].value === "preset" && (!themeBlockIndent || indent <= themeBlockIndent)) {
|
|
31221
|
+
if (themeNode) {
|
|
31222
|
+
themeNode.preset = tokens[1].value;
|
|
31223
|
+
}
|
|
31224
|
+
continue;
|
|
31225
|
+
}
|
|
31226
|
+
if (currentThemeBlock && themeBlockIndent !== null && indent > themeBlockIndent) {
|
|
31227
|
+
currentThemeBlock.fields.push(parseThemeField(tokens, lineNumber));
|
|
31228
|
+
} else {
|
|
31229
|
+
themeBlockIndent = indent;
|
|
31230
|
+
currentThemeBlock = {
|
|
31231
|
+
type: "theme-block",
|
|
31232
|
+
target: tokens[0].value,
|
|
31233
|
+
fields: [],
|
|
31234
|
+
location: { line: lineNumber, column: tokens[0].column }
|
|
31235
|
+
};
|
|
31236
|
+
themeNode?.blocks.push(currentThemeBlock);
|
|
31237
|
+
}
|
|
31238
|
+
continue;
|
|
31239
|
+
}
|
|
31199
31240
|
if (!currentObject) {
|
|
31200
31241
|
throw new WorldOrbitError("Indented line without parent object", lineNumber, indent + 1);
|
|
31201
31242
|
}
|
|
@@ -31215,6 +31256,7 @@ void main() {
|
|
|
31215
31256
|
}
|
|
31216
31257
|
return {
|
|
31217
31258
|
type: "document",
|
|
31259
|
+
theme: themeNode,
|
|
31218
31260
|
objects
|
|
31219
31261
|
};
|
|
31220
31262
|
}
|
|
@@ -31285,6 +31327,17 @@ void main() {
|
|
|
31285
31327
|
location: { line, column: tokens[0].column }
|
|
31286
31328
|
};
|
|
31287
31329
|
}
|
|
31330
|
+
function parseThemeField(tokens, line) {
|
|
31331
|
+
if (tokens.length < 2) {
|
|
31332
|
+
throw new WorldOrbitError("Invalid theme field line", line, tokens[0]?.column ?? 1);
|
|
31333
|
+
}
|
|
31334
|
+
return {
|
|
31335
|
+
type: "field",
|
|
31336
|
+
key: tokens[0].value,
|
|
31337
|
+
values: tokens.slice(1).map((token) => token.value),
|
|
31338
|
+
location: { line, column: tokens[0].column }
|
|
31339
|
+
};
|
|
31340
|
+
}
|
|
31288
31341
|
function parseInfoEntry(tokens, line) {
|
|
31289
31342
|
if (tokens.length < 2) {
|
|
31290
31343
|
throw new WorldOrbitError("Invalid info entry", line, tokens[0]?.column ?? 1);
|
|
@@ -31309,6 +31362,7 @@ void main() {
|
|
|
31309
31362
|
function normalizeDocument(ast) {
|
|
31310
31363
|
let system = null;
|
|
31311
31364
|
const objects = [];
|
|
31365
|
+
const theme = ast.theme ? normalizeTheme(ast.theme) : null;
|
|
31312
31366
|
for (const node of ast.objects) {
|
|
31313
31367
|
const normalized = normalizeObject(node);
|
|
31314
31368
|
if (node.objectType === "system") {
|
|
@@ -31324,6 +31378,7 @@ void main() {
|
|
|
31324
31378
|
format: "worldorbit",
|
|
31325
31379
|
version: "1.0",
|
|
31326
31380
|
schemaVersion: "1.0",
|
|
31381
|
+
theme,
|
|
31327
31382
|
system,
|
|
31328
31383
|
groups: [],
|
|
31329
31384
|
relations: [],
|
|
@@ -31331,6 +31386,40 @@ void main() {
|
|
|
31331
31386
|
objects
|
|
31332
31387
|
};
|
|
31333
31388
|
}
|
|
31389
|
+
function normalizeTheme(node) {
|
|
31390
|
+
const styles = {};
|
|
31391
|
+
for (const block of node.blocks) {
|
|
31392
|
+
const fieldMap = collectFields(block.fields);
|
|
31393
|
+
styles[block.target] = normalizeThemeProperties(fieldMap);
|
|
31394
|
+
}
|
|
31395
|
+
return {
|
|
31396
|
+
preset: node.preset,
|
|
31397
|
+
styles
|
|
31398
|
+
};
|
|
31399
|
+
}
|
|
31400
|
+
function normalizeThemeProperties(fieldMap) {
|
|
31401
|
+
const result = {};
|
|
31402
|
+
for (const [key, field] of fieldMap.entries()) {
|
|
31403
|
+
if (field.values.length === 1) {
|
|
31404
|
+
const rawValue = field.values[0];
|
|
31405
|
+
if (rawValue === "true") {
|
|
31406
|
+
result[key] = true;
|
|
31407
|
+
continue;
|
|
31408
|
+
}
|
|
31409
|
+
if (rawValue === "false") {
|
|
31410
|
+
result[key] = false;
|
|
31411
|
+
continue;
|
|
31412
|
+
}
|
|
31413
|
+
const num = Number(rawValue);
|
|
31414
|
+
if (!Number.isNaN(num) && rawValue.trim() !== "") {
|
|
31415
|
+
result[key] = num;
|
|
31416
|
+
continue;
|
|
31417
|
+
}
|
|
31418
|
+
}
|
|
31419
|
+
result[key] = field.values.join(" ");
|
|
31420
|
+
}
|
|
31421
|
+
return result;
|
|
31422
|
+
}
|
|
31334
31423
|
function normalizeObject(node) {
|
|
31335
31424
|
const mergedFields = [...node.inlineFields, ...node.blockFields];
|
|
31336
31425
|
validateFieldCompatibility(node.objectType, mergedFields);
|
|
@@ -32751,7 +32840,7 @@ void main() {
|
|
|
32751
32840
|
}
|
|
32752
32841
|
function parseViewpointGroups(value, document2, relationships, objectMap) {
|
|
32753
32842
|
return splitListValue(value).map((entry) => {
|
|
32754
|
-
if (document2.schemaVersion === "2.1" || document2.schemaVersion === "2.5" || document2.groups.some((group) => group.id === entry)) {
|
|
32843
|
+
if (document2.schemaVersion === "2.1" || document2.schemaVersion === "2.5" || document2.schemaVersion === "2.6.1" || document2.groups.some((group) => group.id === entry)) {
|
|
32755
32844
|
return entry;
|
|
32756
32845
|
}
|
|
32757
32846
|
if (entry.startsWith("wo-") && entry.endsWith("-group")) {
|
|
@@ -33941,9 +34030,10 @@ void main() {
|
|
|
33941
34030
|
}
|
|
33942
34031
|
return {
|
|
33943
34032
|
format: "worldorbit",
|
|
33944
|
-
version: "2.
|
|
33945
|
-
schemaVersion: "2.
|
|
34033
|
+
version: "2.6.1",
|
|
34034
|
+
schemaVersion: "2.6.1",
|
|
33946
34035
|
sourceVersion: document2.version,
|
|
34036
|
+
theme: document2.theme ?? null,
|
|
33947
34037
|
system,
|
|
33948
34038
|
groups: structuredClone(document2.groups ?? []),
|
|
33949
34039
|
relations: structuredClone(document2.relations ?? []),
|
|
@@ -33972,6 +34062,7 @@ void main() {
|
|
|
33972
34062
|
format: "worldorbit",
|
|
33973
34063
|
version: "1.0",
|
|
33974
34064
|
schemaVersion: document2.version,
|
|
34065
|
+
theme: document2.theme ?? null,
|
|
33975
34066
|
system,
|
|
33976
34067
|
groups: structuredClone(document2.groups ?? []),
|
|
33977
34068
|
relations: structuredClone(document2.relations ?? []),
|
|
@@ -34397,22 +34488,22 @@ void main() {
|
|
|
34397
34488
|
];
|
|
34398
34489
|
function formatDocument(document2, options = {}) {
|
|
34399
34490
|
const schema = options.schema ?? "auto";
|
|
34400
|
-
const useDraft = schema === "2.0" || schema === "2.1" || schema === "2.5" || schema === "2.0-draft" || document2.version === "2.0" || document2.version === "2.1" || document2.version === "2.5" || document2.version === "2.0-draft";
|
|
34491
|
+
const useDraft = schema === "2.0" || schema === "2.1" || schema === "2.5" || schema === "2.6.1" || schema === "2.0-draft" || document2.version === "2.0" || document2.version === "2.1" || document2.version === "2.5" || document2.version === "2.6.1" || document2.version === "2.0-draft";
|
|
34401
34492
|
if (useDraft) {
|
|
34402
34493
|
if (schema === "2.0-draft") {
|
|
34403
|
-
const legacyDraftDocument = document2.version === "2.0-draft" ? document2 : document2.version === "2.0" || document2.version === "2.1" || document2.version === "2.5" ? {
|
|
34494
|
+
const legacyDraftDocument = document2.version === "2.0-draft" ? document2 : document2.version === "2.0" || document2.version === "2.1" || document2.version === "2.5" || document2.version === "2.6.1" ? {
|
|
34404
34495
|
...document2,
|
|
34405
34496
|
version: "2.0-draft",
|
|
34406
34497
|
schemaVersion: "2.0-draft"
|
|
34407
34498
|
} : upgradeDocumentToDraftV2(document2);
|
|
34408
34499
|
return formatDraftDocument(legacyDraftDocument);
|
|
34409
34500
|
}
|
|
34410
|
-
const atlasDocument = document2.version === "2.0" || document2.version === "2.1" || document2.version === "2.5" ? document2 : document2.version === "2.0-draft" ? {
|
|
34501
|
+
const atlasDocument = document2.version === "2.0" || document2.version === "2.1" || document2.version === "2.5" || document2.version === "2.6.1" ? document2 : document2.version === "2.0-draft" ? {
|
|
34411
34502
|
...document2,
|
|
34412
34503
|
version: "2.0",
|
|
34413
34504
|
schemaVersion: "2.0"
|
|
34414
34505
|
} : upgradeDocumentToV2(document2);
|
|
34415
|
-
if ((schema === "2.0" || schema === "2.1" || schema === "2.5") && atlasDocument.version !== schema) {
|
|
34506
|
+
if ((schema === "2.0" || schema === "2.1" || schema === "2.5" || schema === "2.6.1") && atlasDocument.version !== schema) {
|
|
34416
34507
|
return formatAtlasDocument({
|
|
34417
34508
|
...atlasDocument,
|
|
34418
34509
|
version: schema,
|
|
@@ -35166,7 +35257,7 @@ void main() {
|
|
|
35166
35257
|
}
|
|
35167
35258
|
function validateViewpoint(viewpoint, groupIds, eventIds, sourceSchemaVersion, diagnostics, objectMap) {
|
|
35168
35259
|
const filter = viewpoint.filter;
|
|
35169
|
-
if (sourceSchemaVersion === "2.1" || sourceSchemaVersion === "2.5") {
|
|
35260
|
+
if (sourceSchemaVersion === "2.1" || sourceSchemaVersion === "2.5" || sourceSchemaVersion === "2.6.1") {
|
|
35170
35261
|
if (filter) {
|
|
35171
35262
|
for (const groupId of filter.groupIds) {
|
|
35172
35263
|
if (!groupIds.has(groupId)) {
|
|
@@ -35730,6 +35821,7 @@ void main() {
|
|
|
35730
35821
|
const baseDocument = {
|
|
35731
35822
|
format: "worldorbit",
|
|
35732
35823
|
sourceVersion: "1.0",
|
|
35824
|
+
theme: null,
|
|
35733
35825
|
system,
|
|
35734
35826
|
groups,
|
|
35735
35827
|
relations,
|
|
@@ -35763,11 +35855,11 @@ void main() {
|
|
|
35763
35855
|
return document2;
|
|
35764
35856
|
}
|
|
35765
35857
|
function assertDraftSchemaHeader(tokens, line) {
|
|
35766
|
-
if (tokens.length !== 2 || tokens[0].value.toLowerCase() !== "schema" || !["2.0-draft", "2.0", "2.1", "2.5"].includes(tokens[1].value.toLowerCase())) {
|
|
35767
|
-
throw new WorldOrbitError('Expected atlas header "schema 2.0", "schema 2.1", "schema 2.5", or legacy "schema 2.0-draft"', line, tokens[0]?.column ?? 1);
|
|
35858
|
+
if (tokens.length !== 2 || tokens[0].value.toLowerCase() !== "schema" || !["2.0-draft", "2.0", "2.1", "2.5", "2.6.1"].includes(tokens[1].value.toLowerCase())) {
|
|
35859
|
+
throw new WorldOrbitError('Expected atlas header "schema 2.0", "schema 2.1", "schema 2.5", "schema 2.6.1", or legacy "schema 2.0-draft"', line, tokens[0]?.column ?? 1);
|
|
35768
35860
|
}
|
|
35769
35861
|
const version = tokens[1].value.toLowerCase();
|
|
35770
|
-
return version === "2.5" ? "2.5" : version === "2.1" ? "2.1" : version === "2.0-draft" ? "2.0-draft" : "2.0";
|
|
35862
|
+
return version === "2.6.1" ? "2.6.1" : version === "2.5" ? "2.5" : version === "2.1" ? "2.1" : version === "2.0-draft" ? "2.0-draft" : "2.0";
|
|
35771
35863
|
}
|
|
35772
35864
|
function startTopLevelSection(tokens, line, sourceSchemaVersion, diagnostics, system, objectNodes, groups, relations, events, eventPoseNodes, viewpointIds, annotationIds, groupIds, relationIds, eventIds, flags) {
|
|
35773
35865
|
const keyword = tokens[0]?.value.toLowerCase();
|
|
@@ -37063,6 +37155,8 @@ void main() {
|
|
|
37063
37155
|
return 2;
|
|
37064
37156
|
case "2.5":
|
|
37065
37157
|
return 3;
|
|
37158
|
+
case "2.6.1":
|
|
37159
|
+
return 4;
|
|
37066
37160
|
}
|
|
37067
37161
|
}
|
|
37068
37162
|
function preprocessAtlasSource(source) {
|
|
@@ -37152,12 +37246,16 @@ void main() {
|
|
|
37152
37246
|
}
|
|
37153
37247
|
|
|
37154
37248
|
// packages/core/dist/atlas-edit.js
|
|
37155
|
-
function createEmptyAtlasDocument(systemId = "WorldOrbit", version = "2.
|
|
37249
|
+
function createEmptyAtlasDocument(systemId = "WorldOrbit", version = "2.6.1") {
|
|
37156
37250
|
return {
|
|
37157
37251
|
format: "worldorbit",
|
|
37158
37252
|
version,
|
|
37159
37253
|
schemaVersion: version,
|
|
37160
37254
|
sourceVersion: "1.0",
|
|
37255
|
+
theme: {
|
|
37256
|
+
preset: "blueprint",
|
|
37257
|
+
styles: {}
|
|
37258
|
+
},
|
|
37161
37259
|
system: {
|
|
37162
37260
|
type: "system",
|
|
37163
37261
|
id: systemId,
|
|
@@ -37516,7 +37614,7 @@ void main() {
|
|
|
37516
37614
|
return "2.1";
|
|
37517
37615
|
}
|
|
37518
37616
|
if (ATLAS_SCHEMA_25_PATTERN.test(trimmed)) {
|
|
37519
|
-
return "2.
|
|
37617
|
+
return "2.6.1";
|
|
37520
37618
|
}
|
|
37521
37619
|
if (ATLAS_SCHEMA_PATTERN.test(trimmed)) {
|
|
37522
37620
|
return "2.0";
|
|
@@ -37578,7 +37676,7 @@ void main() {
|
|
|
37578
37676
|
}
|
|
37579
37677
|
function loadWorldOrbitSourceWithDiagnostics(source) {
|
|
37580
37678
|
const schemaVersion = detectWorldOrbitSchemaVersion(source);
|
|
37581
|
-
if (schemaVersion === "2.0" || schemaVersion === "2.0-draft" || schemaVersion === "2.1" || schemaVersion === "2.5") {
|
|
37679
|
+
if (schemaVersion === "2.0" || schemaVersion === "2.0-draft" || schemaVersion === "2.1" || schemaVersion === "2.5" || schemaVersion === "2.6.1") {
|
|
37582
37680
|
return loadAtlasSourceWithDiagnostics(source, schemaVersion);
|
|
37583
37681
|
}
|
|
37584
37682
|
let ast;
|
|
@@ -37777,6 +37875,15 @@ void main() {
|
|
|
37777
37875
|
starCore: "#ffcc67",
|
|
37778
37876
|
starStroke: "rgba(255, 245, 203, 0.85)",
|
|
37779
37877
|
starGlow: "#ffe8a3",
|
|
37878
|
+
spaceFog: "#07131d",
|
|
37879
|
+
starfield: "rgba(226, 239, 255, 0.9)",
|
|
37880
|
+
starfieldDim: "rgba(164, 194, 228, 0.45)",
|
|
37881
|
+
objectSpecular: "#f5f8ff",
|
|
37882
|
+
orbitOpacity: 0.34,
|
|
37883
|
+
orbitBandOpacity: 0.24,
|
|
37884
|
+
selectionHalo: "rgba(255, 214, 139, 0.9)",
|
|
37885
|
+
atmosphere: "rgba(143, 202, 255, 0.4)",
|
|
37886
|
+
cometTail: "rgba(193, 243, 255, 0.7)",
|
|
37780
37887
|
fontFamily: '"Segoe UI Variable", "Bahnschrift", sans-serif',
|
|
37781
37888
|
displayFont: '"Bahnschrift", "Segoe UI Variable", sans-serif'
|
|
37782
37889
|
},
|
|
@@ -37800,6 +37907,15 @@ void main() {
|
|
|
37800
37907
|
starCore: "#e5f98c",
|
|
37801
37908
|
starStroke: "rgba(246, 255, 217, 0.9)",
|
|
37802
37909
|
starGlow: "#fffab4",
|
|
37910
|
+
spaceFog: "#071723",
|
|
37911
|
+
starfield: "rgba(220, 255, 245, 0.9)",
|
|
37912
|
+
starfieldDim: "rgba(124, 212, 195, 0.42)",
|
|
37913
|
+
objectSpecular: "#ecfffb",
|
|
37914
|
+
orbitOpacity: 0.3,
|
|
37915
|
+
orbitBandOpacity: 0.22,
|
|
37916
|
+
selectionHalo: "rgba(120, 255, 215, 0.85)",
|
|
37917
|
+
atmosphere: "rgba(120, 255, 215, 0.32)",
|
|
37918
|
+
cometTail: "rgba(181, 255, 236, 0.68)",
|
|
37803
37919
|
fontFamily: '"Segoe UI Variable", "Bahnschrift", sans-serif',
|
|
37804
37920
|
displayFont: '"Bahnschrift", "Segoe UI Variable", sans-serif'
|
|
37805
37921
|
},
|
|
@@ -37823,6 +37939,15 @@ void main() {
|
|
|
37823
37939
|
starCore: "#ffb766",
|
|
37824
37940
|
starStroke: "rgba(255, 236, 205, 0.88)",
|
|
37825
37941
|
starGlow: "#ffe2ad",
|
|
37942
|
+
spaceFog: "#1c0d12",
|
|
37943
|
+
starfield: "rgba(255, 232, 214, 0.88)",
|
|
37944
|
+
starfieldDim: "rgba(255, 176, 138, 0.38)",
|
|
37945
|
+
objectSpecular: "#fff0e6",
|
|
37946
|
+
orbitOpacity: 0.3,
|
|
37947
|
+
orbitBandOpacity: 0.24,
|
|
37948
|
+
selectionHalo: "rgba(255, 178, 125, 0.85)",
|
|
37949
|
+
atmosphere: "rgba(255, 190, 140, 0.26)",
|
|
37950
|
+
cometTail: "rgba(255, 214, 173, 0.62)",
|
|
37826
37951
|
fontFamily: '"Segoe UI Variable", "Bahnschrift", sans-serif',
|
|
37827
37952
|
displayFont: '"Bahnschrift", "Segoe UI Variable", sans-serif'
|
|
37828
37953
|
}
|
|
@@ -38872,10 +38997,12 @@ void main() {
|
|
|
38872
38997
|
let currentVisibleObjectIds = /* @__PURE__ */ new Set();
|
|
38873
38998
|
let currentSelectedObjectId = null;
|
|
38874
38999
|
let currentHoveredObjectId = null;
|
|
38875
|
-
let currentTimeSeconds = 0;
|
|
38876
39000
|
let currentPositions = /* @__PURE__ */ new Map();
|
|
38877
39001
|
let pendingUpdate = null;
|
|
38878
39002
|
let destroyed = false;
|
|
39003
|
+
let smoothedCameraPosition = null;
|
|
39004
|
+
let smoothedCameraTarget = null;
|
|
39005
|
+
let currentEnvironmentKey = "";
|
|
38879
39006
|
const objectVisuals = /* @__PURE__ */ new Map();
|
|
38880
39007
|
const orbitVisuals = /* @__PURE__ */ new Map();
|
|
38881
39008
|
const raycastTargets = [];
|
|
@@ -38884,7 +39011,7 @@ void main() {
|
|
|
38884
39011
|
return;
|
|
38885
39012
|
}
|
|
38886
39013
|
const scene3d = new THREE.Scene();
|
|
38887
|
-
const camera = new THREE.PerspectiveCamera(
|
|
39014
|
+
const camera = new THREE.PerspectiveCamera(46, 1, 0.1, 24e3);
|
|
38888
39015
|
const renderer = new THREE.WebGLRenderer({
|
|
38889
39016
|
antialias: true,
|
|
38890
39017
|
alpha: true,
|
|
@@ -38894,27 +39021,40 @@ void main() {
|
|
|
38894
39021
|
renderer.domElement.dataset.worldorbit3dCanvas = "true";
|
|
38895
39022
|
root.innerHTML = "";
|
|
38896
39023
|
root.append(renderer.domElement);
|
|
38897
|
-
const ambientLight = new THREE.AmbientLight(16777215,
|
|
38898
|
-
const
|
|
38899
|
-
|
|
38900
|
-
|
|
39024
|
+
const ambientLight = new THREE.AmbientLight(16777215, 0.24);
|
|
39025
|
+
const fillLight = new THREE.DirectionalLight(13625855, 0.36);
|
|
39026
|
+
const rimLight = new THREE.DirectionalLight(8304895, 0.24);
|
|
39027
|
+
const keyLight = new THREE.PointLight(16773327, 2.6, 0, 2);
|
|
39028
|
+
fillLight.position.set(-360, 260, 220);
|
|
39029
|
+
rimLight.position.set(340, 180, -280);
|
|
38901
39030
|
const orbitLayer = new THREE.Group();
|
|
38902
39031
|
const objectLayer = new THREE.Group();
|
|
39032
|
+
const starfield = createStarfield(THREE, 320);
|
|
39033
|
+
const raycaster = new THREE.Raycaster();
|
|
39034
|
+
raycaster.params.Line = { threshold: 7 };
|
|
39035
|
+
scene3d.add(ambientLight);
|
|
39036
|
+
scene3d.add(fillLight);
|
|
39037
|
+
scene3d.add(rimLight);
|
|
39038
|
+
scene3d.add(keyLight);
|
|
39039
|
+
scene3d.add(starfield);
|
|
38903
39040
|
scene3d.add(orbitLayer);
|
|
38904
39041
|
scene3d.add(objectLayer);
|
|
38905
|
-
const raycaster = new THREE.Raycaster();
|
|
38906
|
-
raycaster.params.Line = { threshold: 10 };
|
|
38907
39042
|
runtime = {
|
|
38908
39043
|
THREE,
|
|
38909
39044
|
scene3d,
|
|
38910
39045
|
camera,
|
|
38911
39046
|
renderer,
|
|
39047
|
+
ambientLight,
|
|
39048
|
+
fillLight,
|
|
39049
|
+
rimLight,
|
|
38912
39050
|
keyLight,
|
|
39051
|
+
starfield,
|
|
38913
39052
|
orbitLayer,
|
|
38914
39053
|
objectLayer,
|
|
38915
39054
|
raycaster,
|
|
38916
39055
|
pointer: new THREE.Vector2()
|
|
38917
39056
|
};
|
|
39057
|
+
configureRenderer(renderer, THREE, "balanced");
|
|
38918
39058
|
if (pendingUpdate) {
|
|
38919
39059
|
applyUpdate(pendingUpdate);
|
|
38920
39060
|
}
|
|
@@ -38973,6 +39113,8 @@ void main() {
|
|
|
38973
39113
|
destroyed = true;
|
|
38974
39114
|
pendingUpdate = null;
|
|
38975
39115
|
runtime?.renderer.dispose();
|
|
39116
|
+
runtime?.starfield?.geometry?.dispose?.();
|
|
39117
|
+
runtime?.starfield?.material?.dispose?.();
|
|
38976
39118
|
root.remove();
|
|
38977
39119
|
objectVisuals.clear();
|
|
38978
39120
|
orbitVisuals.clear();
|
|
@@ -38991,7 +39133,16 @@ void main() {
|
|
|
38991
39133
|
currentVisibleObjectIds = next.visibleObjectIds;
|
|
38992
39134
|
currentSelectedObjectId = next.selectedObjectId;
|
|
38993
39135
|
currentHoveredObjectId = next.hoveredObjectId;
|
|
38994
|
-
|
|
39136
|
+
configureRenderer(runtime.renderer, runtime.THREE, currentRenderOptions?.quality ?? "balanced");
|
|
39137
|
+
const nextEnvironmentKey = JSON.stringify({
|
|
39138
|
+
theme: currentRenderOptions?.theme ?? null,
|
|
39139
|
+
quality: currentRenderOptions?.quality ?? "balanced",
|
|
39140
|
+
style3d: currentRenderOptions?.style3d ?? "symbolic"
|
|
39141
|
+
});
|
|
39142
|
+
if (nextEnvironmentKey !== currentEnvironmentKey) {
|
|
39143
|
+
updateEnvironment(runtime, currentRenderOptions);
|
|
39144
|
+
currentEnvironmentKey = nextEnvironmentKey;
|
|
39145
|
+
}
|
|
38995
39146
|
if (sceneChanged) {
|
|
38996
39147
|
rebuildScene(next.spatialScene);
|
|
38997
39148
|
}
|
|
@@ -39001,8 +39152,9 @@ void main() {
|
|
|
39001
39152
|
updateOrbitTransforms();
|
|
39002
39153
|
updateVisibility();
|
|
39003
39154
|
updateInteractionState();
|
|
39155
|
+
updateLighting();
|
|
39004
39156
|
updateCamera();
|
|
39005
|
-
|
|
39157
|
+
runtime.renderer.render(runtime.scene3d, runtime.camera);
|
|
39006
39158
|
}
|
|
39007
39159
|
function rebuildScene(spatialScene) {
|
|
39008
39160
|
if (!runtime) {
|
|
@@ -39013,8 +39165,9 @@ void main() {
|
|
|
39013
39165
|
objectVisuals.clear();
|
|
39014
39166
|
orbitVisuals.clear();
|
|
39015
39167
|
raycastTargets.length = 0;
|
|
39168
|
+
smoothedCameraPosition = null;
|
|
39169
|
+
smoothedCameraTarget = null;
|
|
39016
39170
|
const theme = resolveTheme(currentRenderOptions?.theme);
|
|
39017
|
-
runtime.scene3d.background = new runtime.THREE.Color(theme.backgroundStart);
|
|
39018
39171
|
for (const orbit of spatialScene.orbits) {
|
|
39019
39172
|
const visual = createOrbitVisual2(runtime.THREE, orbit, theme);
|
|
39020
39173
|
runtime.orbitLayer.add(visual.root);
|
|
@@ -39032,10 +39185,9 @@ void main() {
|
|
|
39032
39185
|
for (const object of currentScene?.objects ?? []) {
|
|
39033
39186
|
const visual = objectVisuals.get(object.objectId);
|
|
39034
39187
|
const position = currentPositions.get(object.objectId);
|
|
39035
|
-
if (
|
|
39036
|
-
|
|
39188
|
+
if (visual && position) {
|
|
39189
|
+
visual.root.position.set(position.x, position.y, position.z);
|
|
39037
39190
|
}
|
|
39038
|
-
visual.root.position.set(position.x, position.y, position.z);
|
|
39039
39191
|
}
|
|
39040
39192
|
}
|
|
39041
39193
|
function updateOrbitTransforms() {
|
|
@@ -39056,8 +39208,7 @@ void main() {
|
|
|
39056
39208
|
continue;
|
|
39057
39209
|
}
|
|
39058
39210
|
const hideStructure = layers.structures === false && (object.object.type === "structure" || object.object.type === "phenomenon");
|
|
39059
|
-
|
|
39060
|
-
visual.root.visible = !object.hidden && currentVisibleObjectIds.has(object.objectId) && !hideStructure && !hideObjects;
|
|
39211
|
+
visual.root.visible = !object.hidden && currentVisibleObjectIds.has(object.objectId) && layers.objects !== false && !hideStructure;
|
|
39061
39212
|
}
|
|
39062
39213
|
for (const orbit of currentScene?.orbits ?? []) {
|
|
39063
39214
|
const visual = orbitVisuals.get(orbit.objectId);
|
|
@@ -39073,14 +39224,27 @@ void main() {
|
|
|
39073
39224
|
return;
|
|
39074
39225
|
}
|
|
39075
39226
|
for (const visual of objectVisuals.values()) {
|
|
39076
|
-
|
|
39077
|
-
const
|
|
39227
|
+
const selected = currentSelectedObjectId === visual.objectId;
|
|
39228
|
+
const hovered = currentHoveredObjectId === visual.objectId;
|
|
39229
|
+
applyVisualState(runtime.THREE, visual.materials, selected, hovered);
|
|
39230
|
+
const scale = selected ? 1.16 : hovered ? 1.08 : 1;
|
|
39078
39231
|
visual.root.scale.set(scale, scale, scale);
|
|
39232
|
+
if (visual.halo) {
|
|
39233
|
+
visual.halo.visible = selected || hovered;
|
|
39234
|
+
}
|
|
39079
39235
|
}
|
|
39080
39236
|
for (const visual of orbitVisuals.values()) {
|
|
39081
|
-
applyVisualState(runtime.THREE, visual.materials,
|
|
39237
|
+
applyVisualState(runtime.THREE, visual.materials, currentSelectedObjectId === visual.objectId, currentHoveredObjectId === visual.objectId);
|
|
39082
39238
|
}
|
|
39083
39239
|
}
|
|
39240
|
+
function updateLighting() {
|
|
39241
|
+
if (!runtime || !currentScene) {
|
|
39242
|
+
return;
|
|
39243
|
+
}
|
|
39244
|
+
const primaryStar = currentScene.objects.find((object) => object.object.type === "star" && !object.hidden) ?? null;
|
|
39245
|
+
const starPosition = primaryStar ? currentPositions.get(primaryStar.objectId) ?? primaryStar.position : { x: 0, y: 40, z: 0 };
|
|
39246
|
+
runtime.keyLight.position.set(starPosition.x, starPosition.y + 20, starPosition.z);
|
|
39247
|
+
}
|
|
39084
39248
|
function updateCamera() {
|
|
39085
39249
|
if (!runtime || !currentScene || !currentState) {
|
|
39086
39250
|
return;
|
|
@@ -39088,19 +39252,27 @@ void main() {
|
|
|
39088
39252
|
const sceneCamera = currentRenderOptions?.camera ?? currentScene.camera;
|
|
39089
39253
|
const bounds = currentScene.contentBounds;
|
|
39090
39254
|
const size = Math.max(bounds.width, bounds.depth, bounds.height, 160);
|
|
39091
|
-
const yaw = degreesToRadians3((sceneCamera?.azimuth ??
|
|
39092
|
-
const pitch = degreesToRadians3(clampValue(sceneCamera?.elevation ??
|
|
39093
|
-
const zoomDistanceFactor = clampValue(2.
|
|
39094
|
-
const semanticDistance = clampValue(sceneCamera?.distance ??
|
|
39095
|
-
const distance = clampValue(size * zoomDistanceFactor * (semanticDistance /
|
|
39255
|
+
const yaw = degreesToRadians3((sceneCamera?.azimuth ?? 30) + currentState.rotationDeg);
|
|
39256
|
+
const pitch = degreesToRadians3(clampValue(sceneCamera?.elevation ?? 22, -75, 75));
|
|
39257
|
+
const zoomDistanceFactor = clampValue(2.2 / Math.max(currentState.scale, 0.1), 0.35, 7.2);
|
|
39258
|
+
const semanticDistance = clampValue(sceneCamera?.distance ?? 5.4, 2, 24);
|
|
39259
|
+
const distance = clampValue(size * zoomDistanceFactor * (semanticDistance / 5.4), 24, 8e3);
|
|
39096
39260
|
const panFactor = Math.max(size / 900, 0.12);
|
|
39097
39261
|
const target = new runtime.THREE.Vector3(bounds.center.x - currentState.translateX * panFactor, bounds.center.y, bounds.center.z - currentState.translateY * panFactor);
|
|
39098
|
-
runtime.
|
|
39099
|
-
|
|
39262
|
+
const desiredPosition = new runtime.THREE.Vector3(target.x + distance * Math.cos(pitch) * Math.sin(yaw), target.y + distance * Math.sin(pitch), target.z + distance * Math.cos(pitch) * Math.cos(yaw));
|
|
39263
|
+
const smoothing = (currentRenderOptions?.style3d ?? "symbolic") === "cinematic" ? 0.16 : 0.32;
|
|
39264
|
+
if (!smoothedCameraPosition || !smoothedCameraTarget) {
|
|
39265
|
+
smoothedCameraPosition = desiredPosition.clone();
|
|
39266
|
+
smoothedCameraTarget = target.clone();
|
|
39267
|
+
} else {
|
|
39268
|
+
smoothedCameraPosition.lerp(desiredPosition, smoothing);
|
|
39269
|
+
smoothedCameraTarget.lerp(target, smoothing);
|
|
39270
|
+
}
|
|
39271
|
+
runtime.camera.position.copy(smoothedCameraPosition);
|
|
39272
|
+
runtime.camera.lookAt(smoothedCameraTarget);
|
|
39100
39273
|
if (sceneCamera?.roll) {
|
|
39101
39274
|
runtime.camera.rotation.z = degreesToRadians3(sceneCamera.roll);
|
|
39102
39275
|
}
|
|
39103
|
-
runtime.keyLight.position.copy(runtime.camera.position);
|
|
39104
39276
|
}
|
|
39105
39277
|
function resizeRenderer(spatialScene) {
|
|
39106
39278
|
if (!runtime) {
|
|
@@ -39112,35 +39284,63 @@ void main() {
|
|
|
39112
39284
|
runtime.camera.aspect = width / height;
|
|
39113
39285
|
runtime.camera.updateProjectionMatrix();
|
|
39114
39286
|
}
|
|
39115
|
-
function renderNow() {
|
|
39116
|
-
if (!runtime) {
|
|
39117
|
-
return;
|
|
39118
|
-
}
|
|
39119
|
-
runtime.renderer.render(runtime.scene3d, runtime.camera);
|
|
39120
|
-
}
|
|
39121
39287
|
}
|
|
39122
39288
|
function createObjectVisual(THREE, object, theme) {
|
|
39123
39289
|
const root = new THREE.Group();
|
|
39124
39290
|
root.userData.objectId = object.objectId;
|
|
39125
39291
|
const baseColor = object.fillColor ?? colorForObject(object);
|
|
39126
|
-
const
|
|
39127
|
-
|
|
39128
|
-
|
|
39129
|
-
emissiveIntensity: object.object.type === "star" ? 0.6 : 0.08,
|
|
39130
|
-
transparent: true,
|
|
39131
|
-
opacity: object.object.type === "phenomenon" ? 0.7 : 1
|
|
39132
|
-
});
|
|
39133
|
-
const geometry = geometryForObject(THREE, object);
|
|
39134
|
-
const body = new THREE.Mesh(geometry, material);
|
|
39292
|
+
const materials = [];
|
|
39293
|
+
const bodyMaterial = materialForObject(THREE, object, baseColor, theme);
|
|
39294
|
+
const body = new THREE.Mesh(geometryForObject(THREE, object), bodyMaterial.material);
|
|
39135
39295
|
body.userData.objectId = object.objectId;
|
|
39136
39296
|
root.add(body);
|
|
39137
|
-
|
|
39138
|
-
|
|
39139
|
-
|
|
39140
|
-
|
|
39141
|
-
|
|
39142
|
-
|
|
39143
|
-
|
|
39297
|
+
materials.push(bodyMaterial);
|
|
39298
|
+
if (shouldRenderAtmosphere(object)) {
|
|
39299
|
+
const atmosphereMaterial = {
|
|
39300
|
+
material: new THREE.MeshBasicMaterial({
|
|
39301
|
+
color: theme.atmosphere,
|
|
39302
|
+
transparent: true,
|
|
39303
|
+
opacity: 0.24,
|
|
39304
|
+
depthWrite: false,
|
|
39305
|
+
side: 2
|
|
39306
|
+
}),
|
|
39307
|
+
baseColor: theme.atmosphere,
|
|
39308
|
+
baseOpacity: 0.24,
|
|
39309
|
+
hoveredOpacity: 0.34,
|
|
39310
|
+
selectedOpacity: 0.42
|
|
39311
|
+
};
|
|
39312
|
+
const atmosphere = new THREE.Mesh(new THREE.SphereGeometry(Math.max(object.visualRadius, 2) * 1.16, 20, 14), atmosphereMaterial.material);
|
|
39313
|
+
atmosphere.userData.objectId = object.objectId;
|
|
39314
|
+
root.add(atmosphere);
|
|
39315
|
+
materials.push(atmosphereMaterial);
|
|
39316
|
+
}
|
|
39317
|
+
if (object.object.type === "comet") {
|
|
39318
|
+
const tailMaterial = {
|
|
39319
|
+
material: new THREE.MeshBasicMaterial({
|
|
39320
|
+
color: theme.cometTail,
|
|
39321
|
+
transparent: true,
|
|
39322
|
+
opacity: 0.36,
|
|
39323
|
+
depthWrite: false
|
|
39324
|
+
}),
|
|
39325
|
+
baseColor: theme.cometTail,
|
|
39326
|
+
baseOpacity: 0.36,
|
|
39327
|
+
hoveredOpacity: 0.48,
|
|
39328
|
+
selectedOpacity: 0.56
|
|
39329
|
+
};
|
|
39330
|
+
const tail = new THREE.Mesh(new THREE.ConeGeometry(Math.max(object.visualRadius * 0.55, 2), Math.max(object.visualRadius * 2.8, 8), 12, 1, true), tailMaterial.material);
|
|
39331
|
+
tail.position.set(-Math.max(object.visualRadius * 1.4, 4), 0, 0);
|
|
39332
|
+
tail.rotation.z = -Math.PI / 2;
|
|
39333
|
+
tail.userData.objectId = object.objectId;
|
|
39334
|
+
root.add(tail);
|
|
39335
|
+
materials.push(tailMaterial);
|
|
39336
|
+
}
|
|
39337
|
+
const halo = createHalo(THREE, object, theme);
|
|
39338
|
+
if (halo) {
|
|
39339
|
+
halo.visible = false;
|
|
39340
|
+
halo.userData.objectId = object.objectId;
|
|
39341
|
+
root.add(halo);
|
|
39342
|
+
}
|
|
39343
|
+
return { objectId: object.objectId, root, halo, materials };
|
|
39144
39344
|
}
|
|
39145
39345
|
function createOrbitVisual2(THREE, orbit, theme) {
|
|
39146
39346
|
const root = new THREE.Group();
|
|
@@ -39148,60 +39348,174 @@ void main() {
|
|
|
39148
39348
|
root.rotation.y = degreesToRadians3(orbit.rotationDeg);
|
|
39149
39349
|
root.rotation.x = degreesToRadians3(orbit.inclinationDeg);
|
|
39150
39350
|
const baseColor = orbit.object.properties.color ?? theme.orbit;
|
|
39151
|
-
const materials = [];
|
|
39152
39351
|
if (orbit.band) {
|
|
39153
|
-
const
|
|
39154
|
-
|
|
39155
|
-
|
|
39156
|
-
|
|
39157
|
-
|
|
39158
|
-
|
|
39159
|
-
|
|
39160
|
-
|
|
39352
|
+
const material2 = {
|
|
39353
|
+
material: new THREE.MeshBasicMaterial({
|
|
39354
|
+
color: baseColor,
|
|
39355
|
+
transparent: true,
|
|
39356
|
+
opacity: theme.orbitBandOpacity,
|
|
39357
|
+
side: 2,
|
|
39358
|
+
depthWrite: false
|
|
39359
|
+
}),
|
|
39360
|
+
baseColor,
|
|
39361
|
+
baseOpacity: theme.orbitBandOpacity,
|
|
39362
|
+
hoveredOpacity: Math.min(theme.orbitBandOpacity + 0.1, 0.58),
|
|
39363
|
+
selectedOpacity: Math.min(theme.orbitBandOpacity + 0.18, 0.72),
|
|
39364
|
+
hoveredColor: theme.accent,
|
|
39365
|
+
selectedColor: theme.accentStrong
|
|
39366
|
+
};
|
|
39367
|
+
const mesh = new THREE.Mesh(bandGeometryForOrbit(THREE, orbit), material2.material);
|
|
39161
39368
|
mesh.userData.objectId = orbit.objectId;
|
|
39162
39369
|
root.add(mesh);
|
|
39163
|
-
materials
|
|
39164
|
-
}
|
|
39165
|
-
|
|
39370
|
+
return { objectId: orbit.objectId, root, materials: [material2] };
|
|
39371
|
+
}
|
|
39372
|
+
const material = {
|
|
39373
|
+
material: new THREE.LineBasicMaterial({
|
|
39166
39374
|
color: baseColor,
|
|
39167
39375
|
transparent: true,
|
|
39168
|
-
opacity:
|
|
39169
|
-
})
|
|
39170
|
-
|
|
39171
|
-
|
|
39172
|
-
|
|
39173
|
-
|
|
39174
|
-
|
|
39175
|
-
|
|
39176
|
-
}
|
|
39376
|
+
opacity: theme.orbitOpacity
|
|
39377
|
+
}),
|
|
39378
|
+
baseColor,
|
|
39379
|
+
baseOpacity: theme.orbitOpacity,
|
|
39380
|
+
hoveredOpacity: Math.min(theme.orbitOpacity + 0.18, 0.72),
|
|
39381
|
+
selectedOpacity: Math.min(theme.orbitOpacity + 0.3, 0.88),
|
|
39382
|
+
hoveredColor: theme.accent,
|
|
39383
|
+
selectedColor: theme.accentStrong
|
|
39384
|
+
};
|
|
39385
|
+
const geometry = new THREE.BufferGeometry().setFromPoints(sampleOrbitPoints(THREE, orbit, 120));
|
|
39386
|
+
const line = new THREE.LineLoop(geometry, material.material);
|
|
39387
|
+
line.userData.objectId = orbit.objectId;
|
|
39388
|
+
root.add(line);
|
|
39389
|
+
return { objectId: orbit.objectId, root, materials: [material] };
|
|
39390
|
+
}
|
|
39391
|
+
function materialForObject(THREE, object, baseColor, theme) {
|
|
39392
|
+
if (object.object.type === "star") {
|
|
39393
|
+
return {
|
|
39394
|
+
material: new THREE.MeshStandardMaterial({
|
|
39395
|
+
color: baseColor,
|
|
39396
|
+
emissive: new THREE.Color(theme.starGlow),
|
|
39397
|
+
emissiveIntensity: 1.2,
|
|
39398
|
+
roughness: 0.35,
|
|
39399
|
+
metalness: 0.02
|
|
39400
|
+
}),
|
|
39401
|
+
baseColor,
|
|
39402
|
+
baseOpacity: 1,
|
|
39403
|
+
hoveredOpacity: 1,
|
|
39404
|
+
selectedOpacity: 1,
|
|
39405
|
+
hoveredColor: theme.starCore,
|
|
39406
|
+
selectedColor: "#fff2c4",
|
|
39407
|
+
baseEmissive: theme.starGlow,
|
|
39408
|
+
hoveredEmissive: theme.starGlow,
|
|
39409
|
+
selectedEmissive: "#fff6cc",
|
|
39410
|
+
baseEmissiveIntensity: 1.2,
|
|
39411
|
+
hoveredEmissiveIntensity: 1.5,
|
|
39412
|
+
selectedEmissiveIntensity: 1.8
|
|
39413
|
+
};
|
|
39414
|
+
}
|
|
39415
|
+
if (object.object.type === "phenomenon") {
|
|
39416
|
+
return {
|
|
39417
|
+
material: new THREE.MeshPhongMaterial({
|
|
39418
|
+
color: baseColor,
|
|
39419
|
+
transparent: true,
|
|
39420
|
+
opacity: 0.7,
|
|
39421
|
+
emissive: new THREE.Color(baseColor),
|
|
39422
|
+
emissiveIntensity: 0.32,
|
|
39423
|
+
shininess: 90
|
|
39424
|
+
}),
|
|
39425
|
+
baseColor,
|
|
39426
|
+
baseOpacity: 0.7,
|
|
39427
|
+
hoveredOpacity: 0.82,
|
|
39428
|
+
selectedOpacity: 0.9,
|
|
39429
|
+
hoveredColor: theme.accent,
|
|
39430
|
+
selectedColor: theme.selectionHalo,
|
|
39431
|
+
baseEmissive: baseColor,
|
|
39432
|
+
hoveredEmissive: theme.accent,
|
|
39433
|
+
selectedEmissive: theme.selectionHalo,
|
|
39434
|
+
baseEmissiveIntensity: 0.32,
|
|
39435
|
+
hoveredEmissiveIntensity: 0.52,
|
|
39436
|
+
selectedEmissiveIntensity: 0.74
|
|
39437
|
+
};
|
|
39438
|
+
}
|
|
39439
|
+
const shininess = object.object.type === "structure" ? 70 : object.object.type === "ring" ? 42 : object.object.type === "belt" ? 26 : 36;
|
|
39177
39440
|
return {
|
|
39178
|
-
|
|
39179
|
-
|
|
39180
|
-
|
|
39181
|
-
|
|
39441
|
+
material: new THREE.MeshPhongMaterial({
|
|
39442
|
+
color: baseColor,
|
|
39443
|
+
specular: new THREE.Color(theme.objectSpecular),
|
|
39444
|
+
shininess,
|
|
39445
|
+
transparent: false,
|
|
39446
|
+
opacity: 1,
|
|
39447
|
+
emissive: new THREE.Color(0),
|
|
39448
|
+
emissiveIntensity: 0.02
|
|
39449
|
+
}),
|
|
39450
|
+
baseColor,
|
|
39451
|
+
baseOpacity: 1,
|
|
39452
|
+
hoveredOpacity: 1,
|
|
39453
|
+
selectedOpacity: 1,
|
|
39454
|
+
hoveredColor: shiftColorLightness(THREE, baseColor, 0.08),
|
|
39455
|
+
selectedColor: shiftColorLightness(THREE, baseColor, 0.16),
|
|
39456
|
+
hoveredEmissive: "#8fcaff",
|
|
39457
|
+
selectedEmissive: theme.selectionHalo,
|
|
39458
|
+
baseEmissiveIntensity: 0.02,
|
|
39459
|
+
hoveredEmissiveIntensity: 0.12,
|
|
39460
|
+
selectedEmissiveIntensity: 0.22
|
|
39182
39461
|
};
|
|
39183
39462
|
}
|
|
39184
39463
|
function geometryForObject(THREE, object) {
|
|
39185
39464
|
const radius = Math.max(object.visualRadius, 2);
|
|
39186
39465
|
switch (object.object.type) {
|
|
39187
39466
|
case "star":
|
|
39188
|
-
return new THREE.SphereGeometry(radius * 1.
|
|
39467
|
+
return new THREE.SphereGeometry(radius * 1.14, 34, 24);
|
|
39189
39468
|
case "structure":
|
|
39190
|
-
return
|
|
39469
|
+
return geometryForStructure(THREE, object, radius);
|
|
39191
39470
|
case "phenomenon":
|
|
39192
|
-
return new THREE.
|
|
39471
|
+
return new THREE.IcosahedronGeometry(radius * 1.12, 1);
|
|
39193
39472
|
case "belt":
|
|
39473
|
+
return new THREE.TorusGeometry(Math.max(radius * 1.15, 4), Math.max(radius * 0.28, 1), 10, 24);
|
|
39194
39474
|
case "ring":
|
|
39195
|
-
return new THREE.
|
|
39475
|
+
return new THREE.TorusGeometry(Math.max(radius, 4), Math.max(radius * 0.18, 0.8), 10, 30);
|
|
39476
|
+
case "asteroid":
|
|
39477
|
+
return new THREE.DodecahedronGeometry(radius, 0);
|
|
39478
|
+
case "comet":
|
|
39479
|
+
return new THREE.SphereGeometry(radius * 0.94, 18, 14);
|
|
39196
39480
|
default:
|
|
39197
|
-
return new THREE.SphereGeometry(radius,
|
|
39481
|
+
return new THREE.SphereGeometry(radius, 24, 18);
|
|
39198
39482
|
}
|
|
39199
39483
|
}
|
|
39484
|
+
function geometryForStructure(THREE, object, radius) {
|
|
39485
|
+
const kind = String(object.object.properties.kind ?? "").toLowerCase();
|
|
39486
|
+
if (kind.includes("relay")) {
|
|
39487
|
+
return new THREE.OctahedronGeometry(radius * 1.15, 0);
|
|
39488
|
+
}
|
|
39489
|
+
if (kind.includes("elevator") || kind.includes("skyhook")) {
|
|
39490
|
+
return new THREE.CylinderGeometry(radius * 0.36, radius * 0.52, radius * 2.4, 10);
|
|
39491
|
+
}
|
|
39492
|
+
if (kind.includes("station")) {
|
|
39493
|
+
return new THREE.TorusKnotGeometry(radius * 0.6, Math.max(radius * 0.18, 0.6), 42, 8);
|
|
39494
|
+
}
|
|
39495
|
+
return new THREE.BoxGeometry(radius * 1.45, radius * 1.2, radius * 1.45);
|
|
39496
|
+
}
|
|
39497
|
+
function createHalo(THREE, object, theme) {
|
|
39498
|
+
const radius = Math.max(object.visualRadius, 2);
|
|
39499
|
+
const geometry = object.object.type === "structure" ? new THREE.BoxGeometry(radius * 2.2, radius * 2.2, radius * 2.2) : new THREE.SphereGeometry(radius * 1.38, 18, 14);
|
|
39500
|
+
return new THREE.Mesh(geometry, new THREE.MeshBasicMaterial({
|
|
39501
|
+
color: theme.selectionHalo,
|
|
39502
|
+
transparent: true,
|
|
39503
|
+
opacity: 0.18,
|
|
39504
|
+
depthWrite: false,
|
|
39505
|
+
side: 1
|
|
39506
|
+
}));
|
|
39507
|
+
}
|
|
39508
|
+
function shouldRenderAtmosphere(object) {
|
|
39509
|
+
if (object.object.type !== "planet" && object.object.type !== "moon") {
|
|
39510
|
+
return false;
|
|
39511
|
+
}
|
|
39512
|
+
return object.object.properties.atmosphere !== void 0;
|
|
39513
|
+
}
|
|
39200
39514
|
function bandGeometryForOrbit(THREE, orbit) {
|
|
39201
39515
|
const thickness = Math.max(orbit.bandThickness ?? 8, 3);
|
|
39202
39516
|
const points = sampleOrbitPoints(THREE, orbit, 72);
|
|
39203
39517
|
const curve = new THREE.CatmullRomCurve3(points, true);
|
|
39204
|
-
return new THREE.TubeGeometry(curve,
|
|
39518
|
+
return new THREE.TubeGeometry(curve, 144, thickness * 0.18, 10, true);
|
|
39205
39519
|
}
|
|
39206
39520
|
function sampleOrbitPoints(THREE, orbit, segments = 96) {
|
|
39207
39521
|
const points = [];
|
|
@@ -39213,6 +39527,94 @@ void main() {
|
|
|
39213
39527
|
}
|
|
39214
39528
|
return points;
|
|
39215
39529
|
}
|
|
39530
|
+
function createStarfield(THREE, count) {
|
|
39531
|
+
const geometry = new THREE.BufferGeometry();
|
|
39532
|
+
const positions = new Float32Array(count * 3);
|
|
39533
|
+
const colors = new Float32Array(count * 3);
|
|
39534
|
+
for (let index = 0; index < count; index += 1) {
|
|
39535
|
+
const offset = index * 3;
|
|
39536
|
+
const radius = 1800 + Math.random() * 2600;
|
|
39537
|
+
const theta = Math.random() * Math.PI * 2;
|
|
39538
|
+
const phi = Math.acos(2 * Math.random() - 1);
|
|
39539
|
+
positions[offset] = radius * Math.sin(phi) * Math.cos(theta);
|
|
39540
|
+
positions[offset + 1] = radius * Math.cos(phi) * 0.45;
|
|
39541
|
+
positions[offset + 2] = radius * Math.sin(phi) * Math.sin(theta);
|
|
39542
|
+
}
|
|
39543
|
+
geometry.setAttribute("position", new THREE.BufferAttribute(positions, 3));
|
|
39544
|
+
geometry.setAttribute("color", new THREE.BufferAttribute(colors, 3));
|
|
39545
|
+
return new THREE.Points(geometry, new THREE.PointsMaterial({
|
|
39546
|
+
size: 5,
|
|
39547
|
+
transparent: true,
|
|
39548
|
+
opacity: 0.84,
|
|
39549
|
+
depthWrite: false,
|
|
39550
|
+
vertexColors: true,
|
|
39551
|
+
sizeAttenuation: true
|
|
39552
|
+
}));
|
|
39553
|
+
}
|
|
39554
|
+
function configureRenderer(renderer, THREE, quality) {
|
|
39555
|
+
const pixelRatioCap = quality === "high" ? 2.4 : quality === "low" ? 1.2 : 1.8;
|
|
39556
|
+
renderer.setPixelRatio?.(Math.min(globalThis.window?.devicePixelRatio ?? 1, pixelRatioCap));
|
|
39557
|
+
if ("outputColorSpace" in renderer && "SRGBColorSpace" in THREE) {
|
|
39558
|
+
renderer.outputColorSpace = THREE.SRGBColorSpace;
|
|
39559
|
+
} else if ("outputEncoding" in renderer && "sRGBEncoding" in THREE) {
|
|
39560
|
+
renderer.outputEncoding = THREE.sRGBEncoding;
|
|
39561
|
+
}
|
|
39562
|
+
if ("ACESFilmicToneMapping" in THREE) {
|
|
39563
|
+
renderer.toneMapping = THREE.ACESFilmicToneMapping;
|
|
39564
|
+
}
|
|
39565
|
+
}
|
|
39566
|
+
function updateEnvironment(runtime, renderOptions) {
|
|
39567
|
+
const theme = resolveTheme(renderOptions?.theme);
|
|
39568
|
+
const quality = renderOptions?.quality ?? "balanced";
|
|
39569
|
+
const style3d = renderOptions?.style3d ?? "symbolic";
|
|
39570
|
+
const count = quality === "high" ? 520 : quality === "low" ? 180 : 320;
|
|
39571
|
+
const positions = new Float32Array(count * 3);
|
|
39572
|
+
const colors = new Float32Array(count * 3);
|
|
39573
|
+
const bright = new runtime.THREE.Color(theme.starfield);
|
|
39574
|
+
const dim = new runtime.THREE.Color(theme.starfieldDim);
|
|
39575
|
+
for (let index = 0; index < count; index += 1) {
|
|
39576
|
+
const offset = index * 3;
|
|
39577
|
+
const radius = 1800 + Math.random() * 2600;
|
|
39578
|
+
const theta = Math.random() * Math.PI * 2;
|
|
39579
|
+
const phi = Math.acos(2 * Math.random() - 1);
|
|
39580
|
+
positions[offset] = radius * Math.sin(phi) * Math.cos(theta);
|
|
39581
|
+
positions[offset + 1] = radius * Math.cos(phi) * 0.45;
|
|
39582
|
+
positions[offset + 2] = radius * Math.sin(phi) * Math.sin(theta);
|
|
39583
|
+
const color = Math.random() > 0.72 ? bright : dim;
|
|
39584
|
+
colors[offset] = color.r;
|
|
39585
|
+
colors[offset + 1] = color.g;
|
|
39586
|
+
colors[offset + 2] = color.b;
|
|
39587
|
+
}
|
|
39588
|
+
runtime.scene3d.background = new runtime.THREE.Color(theme.backgroundStart);
|
|
39589
|
+
runtime.scene3d.fog = new runtime.THREE.FogExp2(theme.spaceFog, 85e-5);
|
|
39590
|
+
runtime.ambientLight.intensity = style3d === "cinematic" ? 0.18 : 0.26;
|
|
39591
|
+
runtime.fillLight.intensity = style3d === "cinematic" ? 0.32 : 0.4;
|
|
39592
|
+
runtime.rimLight.intensity = style3d === "cinematic" ? 0.28 : 0.22;
|
|
39593
|
+
runtime.renderer.toneMappingExposure = style3d === "cinematic" ? 1.18 : 1.08;
|
|
39594
|
+
runtime.starfield.geometry.setAttribute("position", new runtime.THREE.BufferAttribute(positions, 3));
|
|
39595
|
+
runtime.starfield.geometry.setAttribute("color", new runtime.THREE.BufferAttribute(colors, 3));
|
|
39596
|
+
runtime.starfield.material.opacity = quality === "high" ? 0.96 : quality === "low" ? 0.72 : 0.84;
|
|
39597
|
+
runtime.starfield.material.size = quality === "high" ? 5.5 : quality === "low" ? 4.25 : 5;
|
|
39598
|
+
}
|
|
39599
|
+
function applyVisualState(THREE, materials, selected, hovered) {
|
|
39600
|
+
for (const entry of materials) {
|
|
39601
|
+
const material = entry.material;
|
|
39602
|
+
if (!material) {
|
|
39603
|
+
continue;
|
|
39604
|
+
}
|
|
39605
|
+
const color = selected ? entry.selectedColor ?? entry.baseColor : hovered ? entry.hoveredColor ?? entry.baseColor : entry.baseColor;
|
|
39606
|
+
material.color?.set?.(new THREE.Color(color));
|
|
39607
|
+
if (typeof material.opacity === "number") {
|
|
39608
|
+
material.opacity = selected ? entry.selectedOpacity : hovered ? entry.hoveredOpacity : entry.baseOpacity;
|
|
39609
|
+
material.transparent = material.opacity < 0.999;
|
|
39610
|
+
}
|
|
39611
|
+
const emissive = selected ? entry.selectedEmissive ?? entry.baseEmissive : hovered ? entry.hoveredEmissive ?? entry.baseEmissive : entry.baseEmissive;
|
|
39612
|
+
material.emissive?.set?.(emissive ? new THREE.Color(emissive) : new THREE.Color(0));
|
|
39613
|
+
if ("emissiveIntensity" in material) {
|
|
39614
|
+
material.emissiveIntensity = selected ? entry.selectedEmissiveIntensity ?? entry.baseEmissiveIntensity ?? 0 : hovered ? entry.hoveredEmissiveIntensity ?? entry.baseEmissiveIntensity ?? 0 : entry.baseEmissiveIntensity ?? 0;
|
|
39615
|
+
}
|
|
39616
|
+
}
|
|
39617
|
+
}
|
|
39216
39618
|
function colorForObject(object) {
|
|
39217
39619
|
switch (object.object.type) {
|
|
39218
39620
|
case "star":
|
|
@@ -39235,35 +39637,23 @@ void main() {
|
|
|
39235
39637
|
return "#b8f2ff";
|
|
39236
39638
|
}
|
|
39237
39639
|
}
|
|
39238
|
-
function
|
|
39239
|
-
const color = new THREE.Color(
|
|
39240
|
-
|
|
39241
|
-
|
|
39242
|
-
} else if (hovered) {
|
|
39243
|
-
color.offsetHSL(0, 0, 0.08);
|
|
39244
|
-
}
|
|
39245
|
-
for (const material of materials) {
|
|
39246
|
-
if (!material) {
|
|
39247
|
-
continue;
|
|
39248
|
-
}
|
|
39249
|
-
material.color?.set?.(color);
|
|
39250
|
-
if (typeof material.opacity === "number") {
|
|
39251
|
-
material.opacity = selected ? 0.85 : hovered ? 0.72 : material.transparent ? 0.55 : 1;
|
|
39252
|
-
}
|
|
39253
|
-
material.emissive?.set?.(selected ? new THREE.Color("#ffdda9") : hovered ? new THREE.Color("#cfe9ff") : new THREE.Color(0));
|
|
39254
|
-
material.emissiveIntensity = selected ? 0.28 : hovered ? 0.14 : material.emissiveIntensity ?? 0.08;
|
|
39255
|
-
}
|
|
39640
|
+
function shiftColorLightness(THREE, colorValue, delta) {
|
|
39641
|
+
const color = new THREE.Color(colorValue);
|
|
39642
|
+
color.offsetHSL(0, 0, delta);
|
|
39643
|
+
return `#${color.getHexString()}`;
|
|
39256
39644
|
}
|
|
39257
39645
|
function clearGroup(group) {
|
|
39258
39646
|
while (group.children.length > 0) {
|
|
39259
39647
|
const child = group.children[0];
|
|
39260
39648
|
group.remove(child);
|
|
39261
|
-
child.
|
|
39262
|
-
|
|
39263
|
-
|
|
39264
|
-
|
|
39265
|
-
|
|
39266
|
-
|
|
39649
|
+
child.traverse?.((node) => {
|
|
39650
|
+
node.geometry?.dispose?.();
|
|
39651
|
+
if (Array.isArray(node.material)) {
|
|
39652
|
+
node.material.forEach((entry) => entry?.dispose?.());
|
|
39653
|
+
} else {
|
|
39654
|
+
node.material?.dispose?.();
|
|
39655
|
+
}
|
|
39656
|
+
});
|
|
39267
39657
|
}
|
|
39268
39658
|
}
|
|
39269
39659
|
function ensureWebGLSupport() {
|
|
@@ -39527,6 +39917,8 @@ void main() {
|
|
|
39527
39917
|
preset: options.preset,
|
|
39528
39918
|
projection: options.projection,
|
|
39529
39919
|
viewMode: options.viewMode ?? "2d",
|
|
39920
|
+
quality: options.quality ?? "balanced",
|
|
39921
|
+
style3d: options.style3d ?? "symbolic",
|
|
39530
39922
|
camera: options.camera ? { ...options.camera } : null,
|
|
39531
39923
|
scaleModel: options.scaleModel ? { ...options.scaleModel } : void 0,
|
|
39532
39924
|
theme: options.theme,
|
|
@@ -40710,6 +41102,9 @@ void main() {
|
|
|
40710
41102
|
if (label.hidden || !visibleObjectIds.has(label.objectId)) {
|
|
40711
41103
|
continue;
|
|
40712
41104
|
}
|
|
41105
|
+
if (is3DView() && !shouldRender3DLabel(label.objectId, visibleObjectIds)) {
|
|
41106
|
+
continue;
|
|
41107
|
+
}
|
|
40713
41108
|
const point = is3DView() ? runtime3d?.projectObjectToContainer(label.objectId) ?? null : project2DScenePointToContainer({ x: label.x, y: label.y });
|
|
40714
41109
|
if (!point) {
|
|
40715
41110
|
continue;
|
|
@@ -40749,6 +41144,40 @@ void main() {
|
|
|
40749
41144
|
function isEventVisible(event, visibleObjectIds) {
|
|
40750
41145
|
return event.objectIds.some((objectId) => visibleObjectIds.has(objectId));
|
|
40751
41146
|
}
|
|
41147
|
+
function shouldRender3DLabel(objectId, visibleObjectIds) {
|
|
41148
|
+
if (!is3DView()) {
|
|
41149
|
+
return true;
|
|
41150
|
+
}
|
|
41151
|
+
if (objectId === state.selectedObjectId || objectId === hoveredObjectId) {
|
|
41152
|
+
return true;
|
|
41153
|
+
}
|
|
41154
|
+
const object = getObjectById(objectId);
|
|
41155
|
+
if (!object || object.hidden || !visibleObjectIds.has(objectId)) {
|
|
41156
|
+
return false;
|
|
41157
|
+
}
|
|
41158
|
+
if (object.object.type === "star") {
|
|
41159
|
+
return true;
|
|
41160
|
+
}
|
|
41161
|
+
const selected = state.selectedObjectId ? buildObjectDetails(state.selectedObjectId) : null;
|
|
41162
|
+
const hovered = hoveredObjectId ? buildObjectDetails(hoveredObjectId) : null;
|
|
41163
|
+
const selectedFocus = selected ? /* @__PURE__ */ new Set([
|
|
41164
|
+
selected.objectId,
|
|
41165
|
+
...selected.renderObject.ancestorIds,
|
|
41166
|
+
...selected.renderObject.childIds
|
|
41167
|
+
]) : null;
|
|
41168
|
+
const hoveredFocus = hovered ? /* @__PURE__ */ new Set([
|
|
41169
|
+
hovered.objectId,
|
|
41170
|
+
...hovered.renderObject.ancestorIds,
|
|
41171
|
+
...hovered.renderObject.childIds
|
|
41172
|
+
]) : null;
|
|
41173
|
+
if (selectedFocus?.has(objectId) || hoveredFocus?.has(objectId)) {
|
|
41174
|
+
return true;
|
|
41175
|
+
}
|
|
41176
|
+
if (object.semanticGroupIds.length > 0 && object.visualRadius >= 12) {
|
|
41177
|
+
return true;
|
|
41178
|
+
}
|
|
41179
|
+
return object.childIds.length > 0 && object.visualRadius >= 10;
|
|
41180
|
+
}
|
|
40752
41181
|
function createScreenLabelElement(descriptor) {
|
|
40753
41182
|
const element = document.createElement("div");
|
|
40754
41183
|
element.className = `wo-viewer-label wo-viewer-label-${descriptor.kind}`;
|
|
@@ -40885,7 +41314,9 @@ void main() {
|
|
|
40885
41314
|
layers: renderOptions.layers ? { ...renderOptions.layers } : void 0,
|
|
40886
41315
|
theme: renderOptions.theme && typeof renderOptions.theme === "object" ? { ...renderOptions.theme } : renderOptions.theme,
|
|
40887
41316
|
activeEventId: renderOptions.activeEventId ?? null,
|
|
40888
|
-
viewMode: renderOptions.viewMode ?? "2d"
|
|
41317
|
+
viewMode: renderOptions.viewMode ?? "2d",
|
|
41318
|
+
quality: renderOptions.quality ?? "balanced",
|
|
41319
|
+
style3d: renderOptions.style3d ?? "symbolic"
|
|
40889
41320
|
};
|
|
40890
41321
|
}
|
|
40891
41322
|
function mergeRenderOptions(current, next) {
|
|
@@ -40903,7 +41334,9 @@ void main() {
|
|
|
40903
41334
|
...next.layers
|
|
40904
41335
|
} : current.layers ? { ...current.layers } : void 0,
|
|
40905
41336
|
theme: next.theme && typeof next.theme === "object" ? { ...next.theme } : next.theme ?? current.theme,
|
|
40906
|
-
viewMode: next.viewMode ?? current.viewMode ?? "2d"
|
|
41337
|
+
viewMode: next.viewMode ?? current.viewMode ?? "2d",
|
|
41338
|
+
quality: next.quality ?? current.quality ?? "balanced",
|
|
41339
|
+
style3d: next.style3d ?? current.style3d ?? "symbolic"
|
|
40907
41340
|
};
|
|
40908
41341
|
}
|
|
40909
41342
|
function hasSceneAffectingRenderOptions(options) {
|
|
@@ -41117,6 +41550,10 @@ void main() {
|
|
|
41117
41550
|
position: absolute;
|
|
41118
41551
|
display: grid;
|
|
41119
41552
|
gap: 2px;
|
|
41553
|
+
padding: 4px 8px;
|
|
41554
|
+
border-radius: 999px;
|
|
41555
|
+
background: linear-gradient(180deg, rgba(5, 16, 26, 0.72), rgba(5, 16, 26, 0.38));
|
|
41556
|
+
border: 1px solid rgba(164, 194, 228, 0.16);
|
|
41120
41557
|
color: #edf6ff;
|
|
41121
41558
|
font-family: "Segoe UI Variable", "Segoe UI", sans-serif;
|
|
41122
41559
|
line-height: 1.15;
|