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
|
@@ -30,6 +30,15 @@ const THEME_PRESETS = {
|
|
|
30
30
|
starCore: "#ffcc67",
|
|
31
31
|
starStroke: "rgba(255, 245, 203, 0.85)",
|
|
32
32
|
starGlow: "#ffe8a3",
|
|
33
|
+
spaceFog: "#07131d",
|
|
34
|
+
starfield: "rgba(226, 239, 255, 0.9)",
|
|
35
|
+
starfieldDim: "rgba(164, 194, 228, 0.45)",
|
|
36
|
+
objectSpecular: "#f5f8ff",
|
|
37
|
+
orbitOpacity: 0.34,
|
|
38
|
+
orbitBandOpacity: 0.24,
|
|
39
|
+
selectionHalo: "rgba(255, 214, 139, 0.9)",
|
|
40
|
+
atmosphere: "rgba(143, 202, 255, 0.4)",
|
|
41
|
+
cometTail: "rgba(193, 243, 255, 0.7)",
|
|
33
42
|
fontFamily: "\"Segoe UI Variable\", \"Bahnschrift\", sans-serif",
|
|
34
43
|
displayFont: "\"Bahnschrift\", \"Segoe UI Variable\", sans-serif"
|
|
35
44
|
},
|
|
@@ -53,6 +62,15 @@ const THEME_PRESETS = {
|
|
|
53
62
|
starCore: "#e5f98c",
|
|
54
63
|
starStroke: "rgba(246, 255, 217, 0.9)",
|
|
55
64
|
starGlow: "#fffab4",
|
|
65
|
+
spaceFog: "#071723",
|
|
66
|
+
starfield: "rgba(220, 255, 245, 0.9)",
|
|
67
|
+
starfieldDim: "rgba(124, 212, 195, 0.42)",
|
|
68
|
+
objectSpecular: "#ecfffb",
|
|
69
|
+
orbitOpacity: 0.3,
|
|
70
|
+
orbitBandOpacity: 0.22,
|
|
71
|
+
selectionHalo: "rgba(120, 255, 215, 0.85)",
|
|
72
|
+
atmosphere: "rgba(120, 255, 215, 0.32)",
|
|
73
|
+
cometTail: "rgba(181, 255, 236, 0.68)",
|
|
56
74
|
fontFamily: "\"Segoe UI Variable\", \"Bahnschrift\", sans-serif",
|
|
57
75
|
displayFont: "\"Bahnschrift\", \"Segoe UI Variable\", sans-serif"
|
|
58
76
|
},
|
|
@@ -76,6 +94,15 @@ const THEME_PRESETS = {
|
|
|
76
94
|
starCore: "#ffb766",
|
|
77
95
|
starStroke: "rgba(255, 236, 205, 0.88)",
|
|
78
96
|
starGlow: "#ffe2ad",
|
|
97
|
+
spaceFog: "#1c0d12",
|
|
98
|
+
starfield: "rgba(255, 232, 214, 0.88)",
|
|
99
|
+
starfieldDim: "rgba(255, 176, 138, 0.38)",
|
|
100
|
+
objectSpecular: "#fff0e6",
|
|
101
|
+
orbitOpacity: 0.3,
|
|
102
|
+
orbitBandOpacity: 0.24,
|
|
103
|
+
selectionHalo: "rgba(255, 178, 125, 0.85)",
|
|
104
|
+
atmosphere: "rgba(255, 190, 140, 0.26)",
|
|
105
|
+
cometTail: "rgba(255, 214, 173, 0.62)",
|
|
79
106
|
fontFamily: "\"Segoe UI Variable\", \"Bahnschrift\", sans-serif",
|
|
80
107
|
displayFont: "\"Bahnschrift\", \"Segoe UI Variable\", sans-serif"
|
|
81
108
|
}
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import type { CoordinatePoint, RenderOrbitVisual, RenderProjectionFallback, RenderPresetName, RenderSceneEvent, RenderSceneGroup, RenderSceneLabel, RenderScaleModel, RenderScene, RenderSceneObject, RenderSceneViewpoint, SceneRenderOptions, SpatialScene, ViewProjection, WorldOrbitObject, WorldOrbitDocument, WorldOrbitViewCamera } from "@worldorbit/core";
|
|
2
2
|
export type WorldOrbitThemeName = "atlas" | "nightglass" | "ember";
|
|
3
3
|
export type WorldOrbitViewMode = "2d" | "3d";
|
|
4
|
+
export type WorldOrbit3DQuality = "low" | "balanced" | "high";
|
|
5
|
+
export type WorldOrbit3DStyle = "symbolic" | "cinematic";
|
|
4
6
|
export type WorldOrbitEmbedMode = "static" | "interactive" | "interactive-2d" | "interactive-3d";
|
|
5
7
|
export type TooltipMode = "hover" | "pinned" | "disabled";
|
|
6
8
|
export interface WorldOrbitTheme {
|
|
@@ -23,6 +25,15 @@ export interface WorldOrbitTheme {
|
|
|
23
25
|
starCore: string;
|
|
24
26
|
starStroke: string;
|
|
25
27
|
starGlow: string;
|
|
28
|
+
spaceFog: string;
|
|
29
|
+
starfield: string;
|
|
30
|
+
starfieldDim: string;
|
|
31
|
+
objectSpecular: string;
|
|
32
|
+
orbitOpacity: number;
|
|
33
|
+
orbitBandOpacity: number;
|
|
34
|
+
selectionHalo: string;
|
|
35
|
+
atmosphere: string;
|
|
36
|
+
cometTail: string;
|
|
26
37
|
fontFamily: string;
|
|
27
38
|
displayFont: string;
|
|
28
39
|
}
|
|
@@ -64,6 +75,8 @@ export interface ViewerRenderOptions extends Omit<SvgRenderOptions, "selectedObj
|
|
|
64
75
|
projection?: "document" | ViewProjection;
|
|
65
76
|
scaleModel?: Partial<RenderScaleModel>;
|
|
66
77
|
viewMode?: WorldOrbitViewMode;
|
|
78
|
+
quality?: WorldOrbit3DQuality;
|
|
79
|
+
style3d?: WorldOrbit3DStyle;
|
|
67
80
|
}
|
|
68
81
|
export interface ViewerState {
|
|
69
82
|
scale: number;
|
|
@@ -118,6 +131,8 @@ export interface ViewerAtlasState {
|
|
|
118
131
|
scaleModel?: Partial<RenderScaleModel>;
|
|
119
132
|
activeEventId?: string | null;
|
|
120
133
|
viewMode?: WorldOrbitViewMode;
|
|
134
|
+
quality?: WorldOrbit3DQuality;
|
|
135
|
+
style3d?: WorldOrbit3DStyle;
|
|
121
136
|
};
|
|
122
137
|
filter: ViewerFilter | null;
|
|
123
138
|
}
|
|
@@ -274,6 +289,8 @@ export interface WorldOrbitEmbedPayload {
|
|
|
274
289
|
subtitle?: string;
|
|
275
290
|
preset?: SceneRenderOptions["preset"];
|
|
276
291
|
viewMode?: WorldOrbitViewMode;
|
|
292
|
+
quality?: WorldOrbit3DQuality;
|
|
293
|
+
style3d?: WorldOrbit3DStyle;
|
|
277
294
|
initialViewpointId?: string;
|
|
278
295
|
initialSelectionObjectId?: string;
|
|
279
296
|
initialFilter?: ViewerFilter | null;
|
|
@@ -45,6 +45,8 @@ export function createInteractiveViewer(container, options) {
|
|
|
45
45
|
preset: options.preset,
|
|
46
46
|
projection: options.projection,
|
|
47
47
|
viewMode: options.viewMode ?? "2d",
|
|
48
|
+
quality: options.quality ?? "balanced",
|
|
49
|
+
style3d: options.style3d ?? "symbolic",
|
|
48
50
|
camera: options.camera ? { ...options.camera } : null,
|
|
49
51
|
scaleModel: options.scaleModel ? { ...options.scaleModel } : undefined,
|
|
50
52
|
theme: options.theme,
|
|
@@ -1318,6 +1320,9 @@ export function createInteractiveViewer(container, options) {
|
|
|
1318
1320
|
if (label.hidden || !visibleObjectIds.has(label.objectId)) {
|
|
1319
1321
|
continue;
|
|
1320
1322
|
}
|
|
1323
|
+
if (is3DView() && !shouldRender3DLabel(label.objectId, visibleObjectIds)) {
|
|
1324
|
+
continue;
|
|
1325
|
+
}
|
|
1321
1326
|
const point = is3DView()
|
|
1322
1327
|
? runtime3d?.projectObjectToContainer(label.objectId) ?? null
|
|
1323
1328
|
: project2DScenePointToContainer({ x: label.x, y: label.y });
|
|
@@ -1361,6 +1366,44 @@ export function createInteractiveViewer(container, options) {
|
|
|
1361
1366
|
function isEventVisible(event, visibleObjectIds) {
|
|
1362
1367
|
return event.objectIds.some((objectId) => visibleObjectIds.has(objectId));
|
|
1363
1368
|
}
|
|
1369
|
+
function shouldRender3DLabel(objectId, visibleObjectIds) {
|
|
1370
|
+
if (!is3DView()) {
|
|
1371
|
+
return true;
|
|
1372
|
+
}
|
|
1373
|
+
if (objectId === state.selectedObjectId || objectId === hoveredObjectId) {
|
|
1374
|
+
return true;
|
|
1375
|
+
}
|
|
1376
|
+
const object = getObjectById(objectId);
|
|
1377
|
+
if (!object || object.hidden || !visibleObjectIds.has(objectId)) {
|
|
1378
|
+
return false;
|
|
1379
|
+
}
|
|
1380
|
+
if (object.object.type === "star") {
|
|
1381
|
+
return true;
|
|
1382
|
+
}
|
|
1383
|
+
const selected = state.selectedObjectId ? buildObjectDetails(state.selectedObjectId) : null;
|
|
1384
|
+
const hovered = hoveredObjectId ? buildObjectDetails(hoveredObjectId) : null;
|
|
1385
|
+
const selectedFocus = selected
|
|
1386
|
+
? new Set([
|
|
1387
|
+
selected.objectId,
|
|
1388
|
+
...selected.renderObject.ancestorIds,
|
|
1389
|
+
...selected.renderObject.childIds,
|
|
1390
|
+
])
|
|
1391
|
+
: null;
|
|
1392
|
+
const hoveredFocus = hovered
|
|
1393
|
+
? new Set([
|
|
1394
|
+
hovered.objectId,
|
|
1395
|
+
...hovered.renderObject.ancestorIds,
|
|
1396
|
+
...hovered.renderObject.childIds,
|
|
1397
|
+
])
|
|
1398
|
+
: null;
|
|
1399
|
+
if (selectedFocus?.has(objectId) || hoveredFocus?.has(objectId)) {
|
|
1400
|
+
return true;
|
|
1401
|
+
}
|
|
1402
|
+
if (object.semanticGroupIds.length > 0 && object.visualRadius >= 12) {
|
|
1403
|
+
return true;
|
|
1404
|
+
}
|
|
1405
|
+
return object.childIds.length > 0 && object.visualRadius >= 10;
|
|
1406
|
+
}
|
|
1364
1407
|
function createScreenLabelElement(descriptor) {
|
|
1365
1408
|
const element = document.createElement("div");
|
|
1366
1409
|
element.className = `wo-viewer-label wo-viewer-label-${descriptor.kind}`;
|
|
@@ -1500,6 +1543,8 @@ function cloneRenderOptions(renderOptions) {
|
|
|
1500
1543
|
: renderOptions.theme,
|
|
1501
1544
|
activeEventId: renderOptions.activeEventId ?? null,
|
|
1502
1545
|
viewMode: renderOptions.viewMode ?? "2d",
|
|
1546
|
+
quality: renderOptions.quality ?? "balanced",
|
|
1547
|
+
style3d: renderOptions.style3d ?? "symbolic",
|
|
1503
1548
|
};
|
|
1504
1549
|
}
|
|
1505
1550
|
function mergeRenderOptions(current, next) {
|
|
@@ -1538,6 +1583,8 @@ function mergeRenderOptions(current, next) {
|
|
|
1538
1583
|
? { ...next.theme }
|
|
1539
1584
|
: next.theme ?? current.theme,
|
|
1540
1585
|
viewMode: next.viewMode ?? current.viewMode ?? "2d",
|
|
1586
|
+
quality: next.quality ?? current.quality ?? "balanced",
|
|
1587
|
+
style3d: next.style3d ?? current.style3d ?? "symbolic",
|
|
1541
1588
|
};
|
|
1542
1589
|
}
|
|
1543
1590
|
function hasSceneAffectingRenderOptions(options) {
|
|
@@ -1758,6 +1805,10 @@ function installViewerOverlayStyles() {
|
|
|
1758
1805
|
position: absolute;
|
|
1759
1806
|
display: grid;
|
|
1760
1807
|
gap: 2px;
|
|
1808
|
+
padding: 4px 8px;
|
|
1809
|
+
border-radius: 999px;
|
|
1810
|
+
background: linear-gradient(180deg, rgba(5, 16, 26, 0.72), rgba(5, 16, 26, 0.38));
|
|
1811
|
+
border: 1px solid rgba(164, 194, 228, 0.16);
|
|
1761
1812
|
color: #edf6ff;
|
|
1762
1813
|
font-family: "Segoe UI Variable", "Segoe UI", sans-serif;
|
|
1763
1814
|
line-height: 1.15;
|
|
@@ -1,10 +1,14 @@
|
|
|
1
1
|
import { collectAtlasDiagnostics } from "./atlas-validate.js";
|
|
2
|
-
export function createEmptyAtlasDocument(systemId = "WorldOrbit", version = "2.
|
|
2
|
+
export function createEmptyAtlasDocument(systemId = "WorldOrbit", version = "2.6.1") {
|
|
3
3
|
return {
|
|
4
4
|
format: "worldorbit",
|
|
5
5
|
version,
|
|
6
6
|
schemaVersion: version,
|
|
7
7
|
sourceVersion: "1.0",
|
|
8
|
+
theme: {
|
|
9
|
+
preset: "blueprint",
|
|
10
|
+
styles: {},
|
|
11
|
+
},
|
|
8
12
|
system: {
|
|
9
13
|
type: "system",
|
|
10
14
|
id: systemId,
|
|
@@ -67,7 +67,7 @@ function validateRelation(relation, objectMap, diagnostics) {
|
|
|
67
67
|
}
|
|
68
68
|
function validateViewpoint(viewpoint, groupIds, eventIds, sourceSchemaVersion, diagnostics, objectMap) {
|
|
69
69
|
const filter = viewpoint.filter;
|
|
70
|
-
if (sourceSchemaVersion === "2.1" || sourceSchemaVersion === "2.5") {
|
|
70
|
+
if (sourceSchemaVersion === "2.1" || sourceSchemaVersion === "2.5" || sourceSchemaVersion === "2.6.1") {
|
|
71
71
|
if (filter) {
|
|
72
72
|
for (const groupId of filter.groupIds) {
|
|
73
73
|
if (!groupIds.has(groupId)) {
|
|
@@ -174,6 +174,7 @@ function parseAtlasSource(source, forcedOutputVersion) {
|
|
|
174
174
|
const baseDocument = {
|
|
175
175
|
format: "worldorbit",
|
|
176
176
|
sourceVersion: "1.0",
|
|
177
|
+
theme: null,
|
|
177
178
|
system,
|
|
178
179
|
groups,
|
|
179
180
|
relations,
|
|
@@ -209,17 +210,19 @@ function parseAtlasSource(source, forcedOutputVersion) {
|
|
|
209
210
|
function assertDraftSchemaHeader(tokens, line) {
|
|
210
211
|
if (tokens.length !== 2 ||
|
|
211
212
|
tokens[0].value.toLowerCase() !== "schema" ||
|
|
212
|
-
!["2.0-draft", "2.0", "2.1", "2.5"].includes(tokens[1].value.toLowerCase())) {
|
|
213
|
-
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);
|
|
213
|
+
!["2.0-draft", "2.0", "2.1", "2.5", "2.6.1"].includes(tokens[1].value.toLowerCase())) {
|
|
214
|
+
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);
|
|
214
215
|
}
|
|
215
216
|
const version = tokens[1].value.toLowerCase();
|
|
216
|
-
return version === "2.
|
|
217
|
-
? "2.
|
|
218
|
-
: version === "2.
|
|
219
|
-
? "2.
|
|
220
|
-
: version === "2.
|
|
221
|
-
? "2.
|
|
222
|
-
: "2.0"
|
|
217
|
+
return version === "2.6.1"
|
|
218
|
+
? "2.6.1"
|
|
219
|
+
: version === "2.5"
|
|
220
|
+
? "2.5"
|
|
221
|
+
: version === "2.1"
|
|
222
|
+
? "2.1"
|
|
223
|
+
: version === "2.0-draft"
|
|
224
|
+
? "2.0-draft"
|
|
225
|
+
: "2.0";
|
|
223
226
|
}
|
|
224
227
|
function startTopLevelSection(tokens, line, sourceSchemaVersion, diagnostics, system, objectNodes, groups, relations, events, eventPoseNodes, viewpointIds, annotationIds, groupIds, relationIds, eventIds, flags) {
|
|
225
228
|
const keyword = tokens[0]?.value.toLowerCase();
|
|
@@ -1563,6 +1566,8 @@ function schemaVersionRank(version) {
|
|
|
1563
1566
|
return 2;
|
|
1564
1567
|
case "2.5":
|
|
1565
1568
|
return 3;
|
|
1569
|
+
case "2.6.1":
|
|
1570
|
+
return 4;
|
|
1566
1571
|
}
|
|
1567
1572
|
}
|
|
1568
1573
|
function preprocessAtlasSource(source) {
|
|
@@ -7,6 +7,7 @@ export declare function upgradeDocumentToDraftV2(document: WorldOrbitDocument, o
|
|
|
7
7
|
schemaVersion: "2.0-draft";
|
|
8
8
|
format: "worldorbit";
|
|
9
9
|
sourceVersion: import("./types.js").WorldOrbitDocumentVersion;
|
|
10
|
+
theme: import("./types.js").NormalizedTheme | null;
|
|
10
11
|
system: WorldOrbitAtlasSystem | null;
|
|
11
12
|
groups: import("./types.js").WorldOrbitGroup[];
|
|
12
13
|
relations: import("./types.js").WorldOrbitRelation[];
|
|
@@ -18,9 +18,10 @@ export function upgradeDocumentToV2(document, options = {}) {
|
|
|
18
18
|
}
|
|
19
19
|
return {
|
|
20
20
|
format: "worldorbit",
|
|
21
|
-
version: "2.
|
|
22
|
-
schemaVersion: "2.
|
|
21
|
+
version: "2.6.1",
|
|
22
|
+
schemaVersion: "2.6.1",
|
|
23
23
|
sourceVersion: document.version,
|
|
24
|
+
theme: document.theme ?? null,
|
|
24
25
|
system,
|
|
25
26
|
groups: structuredClone(document.groups ?? []),
|
|
26
27
|
relations: structuredClone(document.relations ?? []),
|
|
@@ -51,6 +52,7 @@ export function materializeAtlasDocument(document, options = {}) {
|
|
|
51
52
|
format: "worldorbit",
|
|
52
53
|
version: "1.0",
|
|
53
54
|
schemaVersion: document.version,
|
|
55
|
+
theme: document.theme ?? null,
|
|
54
56
|
system,
|
|
55
57
|
groups: structuredClone(document.groups ?? []),
|
|
56
58
|
relations: structuredClone(document.relations ?? []),
|
|
@@ -39,16 +39,18 @@ export function formatDocument(document, options = {}) {
|
|
|
39
39
|
const useDraft = schema === "2.0" ||
|
|
40
40
|
schema === "2.1" ||
|
|
41
41
|
schema === "2.5" ||
|
|
42
|
+
schema === "2.6.1" ||
|
|
42
43
|
schema === "2.0-draft" ||
|
|
43
44
|
document.version === "2.0" ||
|
|
44
45
|
document.version === "2.1" ||
|
|
45
46
|
document.version === "2.5" ||
|
|
47
|
+
document.version === "2.6.1" ||
|
|
46
48
|
document.version === "2.0-draft";
|
|
47
49
|
if (useDraft) {
|
|
48
50
|
if (schema === "2.0-draft") {
|
|
49
51
|
const legacyDraftDocument = document.version === "2.0-draft"
|
|
50
52
|
? document
|
|
51
|
-
: document.version === "2.0" || document.version === "2.1" || document.version === "2.5"
|
|
53
|
+
: document.version === "2.0" || document.version === "2.1" || document.version === "2.5" || document.version === "2.6.1"
|
|
52
54
|
? {
|
|
53
55
|
...document,
|
|
54
56
|
version: "2.0-draft",
|
|
@@ -57,7 +59,7 @@ export function formatDocument(document, options = {}) {
|
|
|
57
59
|
: upgradeDocumentToDraftV2(document);
|
|
58
60
|
return formatDraftDocument(legacyDraftDocument);
|
|
59
61
|
}
|
|
60
|
-
const atlasDocument = document.version === "2.0" || document.version === "2.1" || document.version === "2.5"
|
|
62
|
+
const atlasDocument = document.version === "2.0" || document.version === "2.1" || document.version === "2.5" || document.version === "2.6.1"
|
|
61
63
|
? document
|
|
62
64
|
: document.version === "2.0-draft"
|
|
63
65
|
? {
|
|
@@ -66,7 +68,7 @@ export function formatDocument(document, options = {}) {
|
|
|
66
68
|
schemaVersion: "2.0",
|
|
67
69
|
}
|
|
68
70
|
: upgradeDocumentToV2(document);
|
|
69
|
-
if ((schema === "2.0" || schema === "2.1" || schema === "2.5") && atlasDocument.version !== schema) {
|
|
71
|
+
if ((schema === "2.0" || schema === "2.1" || schema === "2.5" || schema === "2.6.1") && atlasDocument.version !== schema) {
|
|
70
72
|
return formatAtlasDocument({
|
|
71
73
|
...atlasDocument,
|
|
72
74
|
version: schema,
|
|
@@ -22,7 +22,7 @@ export function detectWorldOrbitSchemaVersion(source) {
|
|
|
22
22
|
return "2.1";
|
|
23
23
|
}
|
|
24
24
|
if (ATLAS_SCHEMA_25_PATTERN.test(trimmed)) {
|
|
25
|
-
return "2.
|
|
25
|
+
return "2.6.1";
|
|
26
26
|
}
|
|
27
27
|
if (ATLAS_SCHEMA_PATTERN.test(trimmed)) {
|
|
28
28
|
return "2.0";
|
|
@@ -87,7 +87,8 @@ export function loadWorldOrbitSourceWithDiagnostics(source) {
|
|
|
87
87
|
if (schemaVersion === "2.0" ||
|
|
88
88
|
schemaVersion === "2.0-draft" ||
|
|
89
89
|
schemaVersion === "2.1" ||
|
|
90
|
-
schemaVersion === "2.5"
|
|
90
|
+
schemaVersion === "2.5" ||
|
|
91
|
+
schemaVersion === "2.6.1") {
|
|
91
92
|
return loadAtlasSourceWithDiagnostics(source, schemaVersion);
|
|
92
93
|
}
|
|
93
94
|
let ast;
|
|
@@ -11,6 +11,7 @@ const URL_SCHEME_PATTERN = /^[A-Za-z][A-Za-z0-9+.-]*:/;
|
|
|
11
11
|
export function normalizeDocument(ast) {
|
|
12
12
|
let system = null;
|
|
13
13
|
const objects = [];
|
|
14
|
+
const theme = ast.theme ? normalizeTheme(ast.theme) : null;
|
|
14
15
|
for (const node of ast.objects) {
|
|
15
16
|
const normalized = normalizeObject(node);
|
|
16
17
|
if (node.objectType === "system") {
|
|
@@ -27,6 +28,7 @@ export function normalizeDocument(ast) {
|
|
|
27
28
|
format: "worldorbit",
|
|
28
29
|
version: "1.0",
|
|
29
30
|
schemaVersion: "1.0",
|
|
31
|
+
theme,
|
|
30
32
|
system,
|
|
31
33
|
groups: [],
|
|
32
34
|
relations: [],
|
|
@@ -34,6 +36,40 @@ export function normalizeDocument(ast) {
|
|
|
34
36
|
objects,
|
|
35
37
|
};
|
|
36
38
|
}
|
|
39
|
+
function normalizeTheme(node) {
|
|
40
|
+
const styles = {};
|
|
41
|
+
for (const block of node.blocks) {
|
|
42
|
+
const fieldMap = collectFields(block.fields);
|
|
43
|
+
styles[block.target] = normalizeThemeProperties(fieldMap);
|
|
44
|
+
}
|
|
45
|
+
return {
|
|
46
|
+
preset: node.preset,
|
|
47
|
+
styles,
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
function normalizeThemeProperties(fieldMap) {
|
|
51
|
+
const result = {};
|
|
52
|
+
for (const [key, field] of fieldMap.entries()) {
|
|
53
|
+
if (field.values.length === 1) {
|
|
54
|
+
const rawValue = field.values[0];
|
|
55
|
+
if (rawValue === "true") {
|
|
56
|
+
result[key] = true;
|
|
57
|
+
continue;
|
|
58
|
+
}
|
|
59
|
+
if (rawValue === "false") {
|
|
60
|
+
result[key] = false;
|
|
61
|
+
continue;
|
|
62
|
+
}
|
|
63
|
+
const num = Number(rawValue);
|
|
64
|
+
if (!Number.isNaN(num) && rawValue.trim() !== "") {
|
|
65
|
+
result[key] = num;
|
|
66
|
+
continue;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
result[key] = field.values.join(" ");
|
|
70
|
+
}
|
|
71
|
+
return result;
|
|
72
|
+
}
|
|
37
73
|
function normalizeObject(node) {
|
|
38
74
|
const mergedFields = [...node.inlineFields, ...node.blockFields];
|
|
39
75
|
validateFieldCompatibility(node.objectType, mergedFields);
|
|
@@ -4,9 +4,14 @@ import { getIndent, tokenizeLineDetailed } from "./tokenize.js";
|
|
|
4
4
|
export function parseWorldOrbit(source) {
|
|
5
5
|
const lines = source.split(/\r?\n/);
|
|
6
6
|
const objects = [];
|
|
7
|
+
let themeNode = null;
|
|
7
8
|
let currentObject = null;
|
|
8
9
|
let inInfoBlock = false;
|
|
10
|
+
let inThemeBlock = false;
|
|
9
11
|
let infoIndent = null;
|
|
12
|
+
let themeIndent = null;
|
|
13
|
+
let themeBlockIndent = null;
|
|
14
|
+
let currentThemeBlock = null;
|
|
10
15
|
for (let index = 0; index < lines.length; index++) {
|
|
11
16
|
const rawLine = lines[index];
|
|
12
17
|
const lineNumber = index + 1;
|
|
@@ -23,12 +28,49 @@ export function parseWorldOrbit(source) {
|
|
|
23
28
|
}
|
|
24
29
|
if (indent === 0) {
|
|
25
30
|
inInfoBlock = false;
|
|
31
|
+
inThemeBlock = false;
|
|
26
32
|
infoIndent = null;
|
|
33
|
+
themeIndent = null;
|
|
34
|
+
themeBlockIndent = null;
|
|
35
|
+
currentThemeBlock = null;
|
|
36
|
+
if (tokens.length >= 1 && tokens[0].value === "theme") {
|
|
37
|
+
inThemeBlock = true;
|
|
38
|
+
themeIndent = 0;
|
|
39
|
+
themeNode = {
|
|
40
|
+
type: "theme",
|
|
41
|
+
preset: tokens.length >= 2 ? tokens[1].value : null,
|
|
42
|
+
blocks: [],
|
|
43
|
+
location: { line: lineNumber, column: tokens[0].column },
|
|
44
|
+
};
|
|
45
|
+
continue;
|
|
46
|
+
}
|
|
27
47
|
const objectNode = parseObjectHeader(tokens, lineNumber);
|
|
28
48
|
objects.push(objectNode);
|
|
29
49
|
currentObject = objectNode;
|
|
30
50
|
continue;
|
|
31
51
|
}
|
|
52
|
+
if (inThemeBlock) {
|
|
53
|
+
if (tokens.length >= 2 && tokens[0].value === "preset" && (!themeBlockIndent || indent <= themeBlockIndent)) {
|
|
54
|
+
if (themeNode) {
|
|
55
|
+
themeNode.preset = tokens[1].value;
|
|
56
|
+
}
|
|
57
|
+
continue;
|
|
58
|
+
}
|
|
59
|
+
if (currentThemeBlock && themeBlockIndent !== null && indent > themeBlockIndent) {
|
|
60
|
+
currentThemeBlock.fields.push(parseThemeField(tokens, lineNumber));
|
|
61
|
+
}
|
|
62
|
+
else {
|
|
63
|
+
themeBlockIndent = indent;
|
|
64
|
+
currentThemeBlock = {
|
|
65
|
+
type: "theme-block",
|
|
66
|
+
target: tokens[0].value,
|
|
67
|
+
fields: [],
|
|
68
|
+
location: { line: lineNumber, column: tokens[0].column },
|
|
69
|
+
};
|
|
70
|
+
themeNode?.blocks.push(currentThemeBlock);
|
|
71
|
+
}
|
|
72
|
+
continue;
|
|
73
|
+
}
|
|
32
74
|
if (!currentObject) {
|
|
33
75
|
throw new WorldOrbitError("Indented line without parent object", lineNumber, indent + 1);
|
|
34
76
|
}
|
|
@@ -49,6 +91,7 @@ export function parseWorldOrbit(source) {
|
|
|
49
91
|
}
|
|
50
92
|
return {
|
|
51
93
|
type: "document",
|
|
94
|
+
theme: themeNode,
|
|
52
95
|
objects,
|
|
53
96
|
};
|
|
54
97
|
}
|
|
@@ -120,6 +163,17 @@ function parseField(tokens, line) {
|
|
|
120
163
|
location: { line, column: tokens[0].column },
|
|
121
164
|
};
|
|
122
165
|
}
|
|
166
|
+
function parseThemeField(tokens, line) {
|
|
167
|
+
if (tokens.length < 2) {
|
|
168
|
+
throw new WorldOrbitError("Invalid theme field line", line, tokens[0]?.column ?? 1);
|
|
169
|
+
}
|
|
170
|
+
return {
|
|
171
|
+
type: "field",
|
|
172
|
+
key: tokens[0].value,
|
|
173
|
+
values: tokens.slice(1).map((token) => token.value),
|
|
174
|
+
location: { line, column: tokens[0].column },
|
|
175
|
+
};
|
|
176
|
+
}
|
|
123
177
|
function parseInfoEntry(tokens, line) {
|
|
124
178
|
if (tokens.length < 2) {
|
|
125
179
|
throw new WorldOrbitError("Invalid info entry", line, tokens[0]?.column ?? 1);
|
|
@@ -1064,6 +1064,7 @@ function parseViewpointGroups(value, document, relationships, objectMap) {
|
|
|
1064
1064
|
return splitListValue(value).map((entry) => {
|
|
1065
1065
|
if (document.schemaVersion === "2.1" ||
|
|
1066
1066
|
document.schemaVersion === "2.5" ||
|
|
1067
|
+
document.schemaVersion === "2.6.1" ||
|
|
1067
1068
|
document.groups.some((group) => group.id === entry)) {
|
|
1068
1069
|
return entry;
|
|
1069
1070
|
}
|
|
@@ -2,7 +2,7 @@ export type WorldOrbitObjectType = "system" | "star" | "planet" | "moon" | "belt
|
|
|
2
2
|
export type PlacementMode = "orbit" | "at" | "surface" | "free";
|
|
3
3
|
export type Unit = "au" | "km" | "m" | "ly" | "pc" | "kpc" | "re" | "rj" | "sol" | "me" | "mj" | "s" | "min" | "h" | "d" | "y" | "ky" | "my" | "gy" | "K" | "deg";
|
|
4
4
|
export type WorldOrbitDocumentVersion = "1.0";
|
|
5
|
-
export type WorldOrbitAtlasDocumentVersion = "2.0" | "2.1" | "2.5";
|
|
5
|
+
export type WorldOrbitAtlasDocumentVersion = "2.0" | "2.1" | "2.5" | "2.6.1";
|
|
6
6
|
export type WorldOrbitDraftDocumentVersion = "2.0-draft";
|
|
7
7
|
export type WorldOrbitAnyDocumentVersion = WorldOrbitDocumentVersion | WorldOrbitAtlasDocumentVersion | WorldOrbitDraftDocumentVersion;
|
|
8
8
|
export type ViewProjection = "topdown" | "isometric" | "orthographic" | "perspective";
|
|
@@ -34,8 +34,21 @@ export interface TokenizeOptions {
|
|
|
34
34
|
line?: number;
|
|
35
35
|
columnOffset?: number;
|
|
36
36
|
}
|
|
37
|
+
export interface AstThemeNode {
|
|
38
|
+
type: "theme";
|
|
39
|
+
preset: string | null;
|
|
40
|
+
blocks: AstThemeBlockNode[];
|
|
41
|
+
location: AstSourceLocation;
|
|
42
|
+
}
|
|
43
|
+
export interface AstThemeBlockNode {
|
|
44
|
+
type: "theme-block";
|
|
45
|
+
target: string;
|
|
46
|
+
fields: AstFieldNode[];
|
|
47
|
+
location: AstSourceLocation;
|
|
48
|
+
}
|
|
37
49
|
export interface AstDocument {
|
|
38
50
|
type: "document";
|
|
51
|
+
theme: AstThemeNode | null;
|
|
39
52
|
objects: AstObjectNode[];
|
|
40
53
|
}
|
|
41
54
|
export interface AstObjectNode {
|
|
@@ -59,10 +72,15 @@ export interface AstInfoEntryNode {
|
|
|
59
72
|
value: string;
|
|
60
73
|
location: AstSourceLocation;
|
|
61
74
|
}
|
|
75
|
+
export interface NormalizedTheme {
|
|
76
|
+
preset: string | null;
|
|
77
|
+
styles: Record<string, Record<string, NormalizedValue>>;
|
|
78
|
+
}
|
|
62
79
|
export interface WorldOrbitDocument {
|
|
63
80
|
format: "worldorbit";
|
|
64
81
|
version: WorldOrbitDocumentVersion;
|
|
65
82
|
schemaVersion: WorldOrbitAnyDocumentVersion;
|
|
83
|
+
theme: NormalizedTheme | null;
|
|
66
84
|
system: WorldOrbitSystem | null;
|
|
67
85
|
groups: WorldOrbitGroup[];
|
|
68
86
|
relations: WorldOrbitRelation[];
|
|
@@ -74,6 +92,7 @@ export interface WorldOrbitAtlasDocument {
|
|
|
74
92
|
version: WorldOrbitAtlasDocumentVersion;
|
|
75
93
|
schemaVersion: WorldOrbitAtlasDocumentVersion;
|
|
76
94
|
sourceVersion: WorldOrbitDocumentVersion;
|
|
95
|
+
theme: NormalizedTheme | null;
|
|
77
96
|
system: WorldOrbitAtlasSystem | null;
|
|
78
97
|
groups: WorldOrbitGroup[];
|
|
79
98
|
relations: WorldOrbitRelation[];
|
|
@@ -86,6 +105,7 @@ export interface WorldOrbitDraftDocument {
|
|
|
86
105
|
version: WorldOrbitDraftDocumentVersion;
|
|
87
106
|
schemaVersion: WorldOrbitDraftDocumentVersion;
|
|
88
107
|
sourceVersion: WorldOrbitDocumentVersion;
|
|
108
|
+
theme: NormalizedTheme | null;
|
|
89
109
|
system: WorldOrbitAtlasSystem | null;
|
|
90
110
|
groups: WorldOrbitGroup[];
|
|
91
111
|
relations: WorldOrbitRelation[];
|