worldorbit 3.2.2 → 5.0.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.
Files changed (82) hide show
  1. package/README.md +543 -543
  2. package/dist/browser/core/dist/atlas-edit.js +146 -1
  3. package/dist/browser/core/dist/atlas-validate.js +105 -10
  4. package/dist/browser/core/dist/draft-parse.js +461 -17
  5. package/dist/browser/core/dist/draft.d.ts +2 -1
  6. package/dist/browser/core/dist/draft.js +26 -4
  7. package/dist/browser/core/dist/format.js +126 -5
  8. package/dist/browser/core/dist/index.d.ts +1 -0
  9. package/dist/browser/core/dist/index.js +1 -0
  10. package/dist/browser/core/dist/load.js +12 -2
  11. package/dist/browser/core/dist/normalize.js +1 -0
  12. package/dist/browser/core/dist/scene.js +226 -5
  13. package/dist/browser/core/dist/schema.js +11 -1
  14. package/dist/browser/core/dist/solver.d.ts +33 -0
  15. package/dist/browser/core/dist/solver.js +99 -0
  16. package/dist/browser/core/dist/spatial-scene.js +56 -0
  17. package/dist/browser/core/dist/types.d.ts +130 -4
  18. package/dist/browser/editor/dist/editor.js +844 -719
  19. package/dist/browser/editor/dist/types.d.ts +2 -1
  20. package/dist/browser/viewer/dist/minimap.js +9 -7
  21. package/dist/browser/viewer/dist/render.js +78 -18
  22. package/dist/browser/viewer/dist/runtime-3d.js +2 -0
  23. package/dist/browser/viewer/dist/theme.js +1 -0
  24. package/dist/browser/viewer/dist/types.d.ts +7 -0
  25. package/dist/browser/viewer/dist/viewer.js +34 -3
  26. package/dist/obsidian-plugin/README.md +141 -124
  27. package/dist/obsidian-plugin/main.js +82 -68
  28. package/dist/unpkg/core/dist/atlas-edit.js +146 -1
  29. package/dist/unpkg/core/dist/atlas-validate.js +105 -10
  30. package/dist/unpkg/core/dist/draft-parse.js +461 -17
  31. package/dist/unpkg/core/dist/draft.d.ts +2 -1
  32. package/dist/unpkg/core/dist/draft.js +26 -4
  33. package/dist/unpkg/core/dist/format.js +126 -5
  34. package/dist/unpkg/core/dist/index.d.ts +1 -0
  35. package/dist/unpkg/core/dist/index.js +1 -0
  36. package/dist/unpkg/core/dist/load.js +12 -2
  37. package/dist/unpkg/core/dist/normalize.js +1 -0
  38. package/dist/unpkg/core/dist/scene.js +226 -5
  39. package/dist/unpkg/core/dist/schema.js +11 -1
  40. package/dist/unpkg/core/dist/solver.d.ts +33 -0
  41. package/dist/unpkg/core/dist/solver.js +99 -0
  42. package/dist/unpkg/core/dist/spatial-scene.js +56 -0
  43. package/dist/unpkg/core/dist/types.d.ts +130 -4
  44. package/dist/unpkg/editor/dist/editor.js +844 -719
  45. package/dist/unpkg/editor/dist/types.d.ts +2 -1
  46. package/dist/unpkg/viewer/dist/minimap.js +9 -7
  47. package/dist/unpkg/viewer/dist/render.js +78 -18
  48. package/dist/unpkg/viewer/dist/runtime-3d.js +2 -0
  49. package/dist/unpkg/viewer/dist/theme.js +1 -0
  50. package/dist/unpkg/viewer/dist/types.d.ts +7 -0
  51. package/dist/unpkg/viewer/dist/viewer.js +34 -3
  52. package/dist/unpkg/worldorbit-core.min.js +12 -12
  53. package/dist/unpkg/worldorbit-editor.min.js +381 -340
  54. package/dist/unpkg/worldorbit-markdown.min.js +47 -33
  55. package/dist/unpkg/worldorbit-viewer.min.js +238 -224
  56. package/dist/unpkg/worldorbit.js +1218 -46
  57. package/dist/unpkg/worldorbit.min.js +242 -228
  58. package/package.json +5 -1
  59. package/packages/core/dist/atlas-edit.js +146 -1
  60. package/packages/core/dist/atlas-validate.js +105 -10
  61. package/packages/core/dist/draft-parse.js +461 -17
  62. package/packages/core/dist/draft.d.ts +2 -1
  63. package/packages/core/dist/draft.js +26 -4
  64. package/packages/core/dist/format.js +126 -5
  65. package/packages/core/dist/index.d.ts +1 -0
  66. package/packages/core/dist/index.js +1 -0
  67. package/packages/core/dist/load.js +12 -2
  68. package/packages/core/dist/normalize.js +1 -0
  69. package/packages/core/dist/scene.js +226 -5
  70. package/packages/core/dist/schema.js +11 -1
  71. package/packages/core/dist/solver.d.ts +33 -0
  72. package/packages/core/dist/solver.js +99 -0
  73. package/packages/core/dist/spatial-scene.js +56 -0
  74. package/packages/core/dist/types.d.ts +130 -4
  75. package/packages/editor/dist/editor.js +844 -719
  76. package/packages/editor/dist/types.d.ts +2 -1
  77. package/packages/viewer/dist/minimap.js +9 -7
  78. package/packages/viewer/dist/render.js +78 -18
  79. package/packages/viewer/dist/runtime-3d.js +2 -0
  80. package/packages/viewer/dist/theme.js +1 -0
  81. package/packages/viewer/dist/types.d.ts +7 -0
  82. package/packages/viewer/dist/viewer.js +34 -3
@@ -9,6 +9,7 @@ export interface WorldOrbitEditorSnapshot {
9
9
  diagnostics: AtlasResolvedDiagnostic[];
10
10
  selection: WorldOrbitEditorSelection | null;
11
11
  }
12
+ export type WorldOrbitEditorObjectType = WorldOrbitObject["type"] | "craft";
12
13
  export interface WorldOrbitEditorOptions {
13
14
  source?: string;
14
15
  atlasDocument?: WorldOrbitAtlasDocument;
@@ -40,7 +41,7 @@ export interface WorldOrbitEditor {
40
41
  canRedo(): boolean;
41
42
  undo(): boolean;
42
43
  redo(): boolean;
43
- addObject(type?: WorldOrbitObject["type"]): string;
44
+ addObject(type?: WorldOrbitEditorObjectType): string;
44
45
  addEvent(): string;
45
46
  addViewpoint(): string;
46
47
  addAnnotation(): string;
@@ -28,13 +28,13 @@ export function renderViewerMinimap(scene, state, visibleObjects) {
28
28
  return `<circle cx="${formatNumber(x)}" cy="${formatNumber(y)}" r="${formatNumber(radius)}" fill="${fill}" fill-opacity="0.92" />`;
29
29
  })
30
30
  .join("");
31
- return `<div data-worldorbit-minimap="true" style="position:absolute;right:16px;bottom:16px;width:${MINIMAP_WIDTH}px;height:${MINIMAP_HEIGHT}px;padding:8px;border-radius:16px;background:rgba(5, 14, 22, 0.78);border:1px solid rgba(179, 216, 255, 0.16);box-shadow:0 14px 28px rgba(0, 0, 0, 0.24);backdrop-filter:blur(8px);pointer-events:none;">
32
- <svg width="${MINIMAP_WIDTH}" height="${MINIMAP_HEIGHT}" viewBox="0 0 ${MINIMAP_WIDTH} ${MINIMAP_HEIGHT}" role="presentation" aria-hidden="true">
33
- <rect x="0.5" y="0.5" width="${MINIMAP_WIDTH - 1}" height="${MINIMAP_HEIGHT - 1}" rx="12" ry="12" fill="rgba(7, 17, 27, 0.85)" stroke="rgba(179, 216, 255, 0.18)" />
34
- <rect x="${formatNumber(bounds.minX * scale + translateX)}" y="${formatNumber(bounds.minY * scale + translateY)}" width="${formatNumber(bounds.width * scale)}" height="${formatNumber(bounds.height * scale)}" rx="10" ry="10" fill="rgba(163, 209, 255, 0.04)" stroke="rgba(163, 209, 255, 0.16)" />
35
- ${objectsMarkup}
36
- <rect x="${formatNumber(viewport.minX * scale + translateX)}" y="${formatNumber(viewport.minY * scale + translateY)}" width="${formatNumber(viewport.width * scale)}" height="${formatNumber(viewport.height * scale)}" rx="8" ry="8" fill="rgba(255, 180, 100, 0.09)" stroke="rgba(255, 180, 100, 0.88)" stroke-width="1.4" />
37
- </svg>
31
+ return `<div data-worldorbit-minimap="true" style="position:absolute;right:16px;bottom:16px;width:${MINIMAP_WIDTH}px;height:${MINIMAP_HEIGHT}px;padding:8px;border-radius:16px;background:rgba(5, 14, 22, 0.78);border:1px solid rgba(179, 216, 255, 0.16);box-shadow:0 14px 28px rgba(0, 0, 0, 0.24);backdrop-filter:blur(8px);pointer-events:none;">
32
+ <svg width="${MINIMAP_WIDTH}" height="${MINIMAP_HEIGHT}" viewBox="0 0 ${MINIMAP_WIDTH} ${MINIMAP_HEIGHT}" role="presentation" aria-hidden="true">
33
+ <rect x="0.5" y="0.5" width="${MINIMAP_WIDTH - 1}" height="${MINIMAP_HEIGHT - 1}" rx="12" ry="12" fill="rgba(7, 17, 27, 0.85)" stroke="rgba(179, 216, 255, 0.18)" />
34
+ <rect x="${formatNumber(bounds.minX * scale + translateX)}" y="${formatNumber(bounds.minY * scale + translateY)}" width="${formatNumber(bounds.width * scale)}" height="${formatNumber(bounds.height * scale)}" rx="10" ry="10" fill="rgba(163, 209, 255, 0.04)" stroke="rgba(163, 209, 255, 0.16)" />
35
+ ${objectsMarkup}
36
+ <rect x="${formatNumber(viewport.minX * scale + translateX)}" y="${formatNumber(viewport.minY * scale + translateY)}" width="${formatNumber(viewport.width * scale)}" height="${formatNumber(viewport.height * scale)}" rx="8" ry="8" fill="rgba(255, 180, 100, 0.09)" stroke="rgba(255, 180, 100, 0.88)" stroke-width="1.4" />
37
+ </svg>
38
38
  </div>`;
39
39
  }
40
40
  function minimapColorForObject(type) {
@@ -52,6 +52,8 @@ function minimapColorForObject(type) {
52
52
  return "#a7a5b8";
53
53
  case "comet":
54
54
  return "#9ce7ff";
55
+ case "craft":
56
+ return "#ffb47f";
55
57
  case "structure":
56
58
  return "#ff7f5f";
57
59
  case "phenomenon":
@@ -40,6 +40,13 @@ export function renderSceneToSvg(scene, options = {}) {
40
40
  .map((relation) => `<line class="wo-relation" x1="${relation.x1}" y1="${relation.y1}" x2="${relation.x2}" y2="${relation.y2}" data-render-id="${escapeXml(relation.renderId)}" data-relation-id="${escapeAttribute(relation.relationId)}" />`)
41
41
  .join("")
42
42
  : "";
43
+ const trajectoryMarkup = layers.trajectories
44
+ ? renderTrajectoryLayer(scene, visibleObjectIds, {
45
+ showLabels: options.showTrajectoryLabels ?? true,
46
+ showWaypoints: options.showTrajectoryWaypoints ?? true,
47
+ includeStructures: layers.structures,
48
+ })
49
+ : "";
43
50
  const eventMarkup = layers.events
44
51
  ? scene.events
45
52
  .filter((event) => !event.hidden)
@@ -78,25 +85,32 @@ export function renderSceneToSvg(scene, options = {}) {
78
85
  <stop offset="0%" stop-color="${theme.starGlow}" stop-opacity="0.95" />
79
86
  <stop offset="100%" stop-color="${theme.starCore}" stop-opacity="0" />
80
87
  </radialGradient>
81
- <radialGradient id="wo-bg-glow" cx="20%" cy="10%" r="90%">
82
- <stop offset="0%" stop-color="${theme.backgroundGlow}" />
83
- <stop offset="100%" stop-color="transparent" />
84
- </radialGradient>
85
- ${imageDefinitions}
86
- </defs>
88
+ <radialGradient id="wo-bg-glow" cx="20%" cy="10%" r="90%">
89
+ <stop offset="0%" stop-color="${theme.backgroundGlow}" />
90
+ <stop offset="100%" stop-color="transparent" />
91
+ </radialGradient>
92
+ <marker id="wo-trajectory-arrow" markerWidth="12" markerHeight="12" refX="10" refY="6" orient="auto" markerUnits="strokeWidth">
93
+ <path d="M 0 0 L 12 6 L 0 12 z" fill="${theme.accent}" />
94
+ </marker>
95
+ ${imageDefinitions}
96
+ </defs>
87
97
  <style>
88
98
  .wo-bg { fill: url(#wo-bg); }
89
99
  .wo-bg-glow { fill: url(#wo-bg-glow); }
90
100
  .wo-grid { fill: none; stroke: ${theme.guide}; stroke-width: 1; }
91
101
  .wo-orbit { fill: none; stroke: ${theme.orbit}; stroke-width: 1.5; }
92
- .wo-orbit-back { opacity: 0.38; stroke-dasharray: 8 6; }
93
- .wo-orbit-front { opacity: 0.9; }
102
+ .wo-orbit-back { opacity: 0.38; stroke-dasharray: 8 6; }
103
+ .wo-orbit-front { opacity: 0.9; }
94
104
  .wo-orbit-band { stroke: ${theme.orbitBand}; stroke-linecap: round; }
95
105
  .wo-relation { stroke: ${theme.relation}; stroke-width: 2; stroke-dasharray: 10 6; }
106
+ .wo-trajectory { fill: none; stroke: ${theme.accent}; stroke-width: 2.4; stroke-linecap: round; stroke-linejoin: round; opacity: 0.92; }
107
+ .wo-trajectory-waypoint { fill: ${theme.spaceFog}; stroke: ${theme.selected}; stroke-width: 1.4; }
108
+ .wo-trajectory-label { fill: ${theme.accent}; font-family: ${theme.fontFamily}; font-weight: 700; letter-spacing: 0.04em; text-transform: uppercase; }
109
+ .wo-trajectory-date { fill: ${theme.muted}; font-family: ${theme.fontFamily}; font-weight: 500; }
96
110
  .wo-event-line { stroke: ${theme.accent}; stroke-width: 1.6; stroke-dasharray: 5 5; opacity: 0.72; }
97
- .wo-event-node { fill: ${theme.accent}; stroke: ${theme.selected}; stroke-width: 1.4; opacity: 0.92; }
98
- .wo-event-label { fill: ${theme.accent}; font-family: ${theme.fontFamily}; font-weight: 700; letter-spacing: 0.04em; text-transform: uppercase; }
99
- .wo-leader { stroke: ${theme.leader}; stroke-width: 1.5; stroke-dasharray: 6 5; }
111
+ .wo-event-node { fill: ${theme.accent}; stroke: ${theme.selected}; stroke-width: 1.4; opacity: 0.92; }
112
+ .wo-event-label { fill: ${theme.accent}; font-family: ${theme.fontFamily}; font-weight: 700; letter-spacing: 0.04em; text-transform: uppercase; }
113
+ .wo-leader { stroke: ${theme.leader}; stroke-width: 1.5; stroke-dasharray: 6 5; }
100
114
  .wo-label { fill: ${theme.ink}; font-family: ${theme.fontFamily}; font-weight: 600; letter-spacing: 0.02em; }
101
115
  .wo-label-secondary { fill: ${theme.muted}; font-family: ${theme.fontFamily}; font-weight: 500; }
102
116
  .wo-title { fill: ${theme.ink}; font: 700 24px ${theme.displayFont}; letter-spacing: 0.06em; text-transform: uppercase; }
@@ -127,14 +141,15 @@ export function renderSceneToSvg(scene, options = {}) {
127
141
  <g data-worldorbit-world="true">
128
142
  <g data-worldorbit-camera-root="${WORLD_LAYER_ID}" id="${WORLD_LAYER_ID}">
129
143
  <g data-worldorbit-world-content="true">
130
- ${layers.orbits ? `<g data-layer-id="orbits-back">${orbitMarkup.back}</g>` : ""}
131
- ${layers.guides ? `<g data-layer-id="guides">${leaderMarkup}</g>` : ""}
144
+ ${layers.orbits ? `<g data-layer-id="orbits-back">${orbitMarkup.back}</g>` : ""}
145
+ ${layers.guides ? `<g data-layer-id="guides">${leaderMarkup}</g>` : ""}
132
146
  ${layers.relations ? `<g data-layer-id="relations">${relationMarkup}</g>` : ""}
133
147
  ${layers.events ? `<g data-layer-id="events">${eventMarkup}</g>` : ""}
134
148
  ${layers.objects ? `<g data-layer-id="objects">${objectMarkup}</g>` : ""}
135
149
  ${layers.orbits ? `<g data-layer-id="orbits-front">${orbitMarkup.front}</g>` : ""}
150
+ ${layers.trajectories ? `<g data-layer-id="trajectories">${trajectoryMarkup}</g>` : ""}
136
151
  ${layers.labels ? `<g data-layer-id="labels">${labelMarkup}</g>` : ""}
137
- </g>
152
+ </g>
138
153
  </g>
139
154
  </g>
140
155
  </svg>`;
@@ -152,10 +167,51 @@ function renderSceneEventOverlay(scene, event, visibleObjectIds, theme) {
152
167
  const lineMarkup = participants
153
168
  .map((object) => `<line class="wo-event-line" x1="${event.x}" y1="${event.y}" x2="${object.x}" y2="${object.y}" stroke="${escapeAttribute(stroke)}" data-event-id="${escapeAttribute(event.eventId)}" data-object-id="${escapeAttribute(object.objectId)}" />`)
154
169
  .join("");
155
- return `<g class="wo-event" data-render-id="${escapeXml(event.renderId)}" data-event-id="${escapeAttribute(event.eventId)}">
156
- ${lineMarkup}
157
- <circle class="wo-event-node" cx="${event.x}" cy="${event.y}" r="5" fill="${escapeAttribute(stroke)}" />
158
- <text class="wo-event-label" x="${event.x}" y="${event.y - 10}" text-anchor="middle" font-size="10">${escapeXml(label)}</text>
170
+ return `<g class="wo-event" data-render-id="${escapeXml(event.renderId)}" data-event-id="${escapeAttribute(event.eventId)}">
171
+ ${lineMarkup}
172
+ <circle class="wo-event-node" cx="${event.x}" cy="${event.y}" r="5" fill="${escapeAttribute(stroke)}" />
173
+ <text class="wo-event-label" x="${event.x}" y="${event.y - 10}" text-anchor="middle" font-size="10">${escapeXml(label)}</text>
174
+ </g>`;
175
+ }
176
+ function renderTrajectoryLayer(scene, visibleObjectIds, options) {
177
+ return scene.trajectories
178
+ .filter((trajectory) => !trajectory.hidden)
179
+ .filter((trajectory) => trajectory.objectIds.length === 0 || trajectory.objectIds.some((objectId) => visibleObjectIds.has(objectId)))
180
+ .filter((trajectory) => options.includeStructures ||
181
+ !trajectory.objectIds.some((objectId) => {
182
+ const object = scene.objects.find((entry) => entry.objectId === objectId)?.object;
183
+ return object ? isStructureLike(object) : false;
184
+ }))
185
+ .map((trajectory) => {
186
+ const stroke = trajectory.stroke ?? "#f0b464";
187
+ const markerEnd = trajectory.marker === "none" ? "" : ` marker-end="url(#wo-trajectory-arrow)"`;
188
+ const waypointMarkup = trajectory.showWaypoints && options.showWaypoints
189
+ ? trajectory.waypoints
190
+ .filter((waypoint) => !waypoint.hidden)
191
+ .map((waypoint) => renderTrajectoryWaypoint(trajectory, waypoint, options.showLabels))
192
+ .join("")
193
+ : "";
194
+ return `<g class="wo-trajectory-group" data-render-id="${escapeXml(trajectory.renderId)}" data-trajectory-id="${escapeAttribute(trajectory.trajectoryId)}">
195
+ <path class="wo-trajectory wo-trajectory-${trajectory.mode}" d="${trajectory.path}" stroke="${escapeAttribute(stroke)}" stroke-width="${trajectory.strokeWidth}"${markerEnd} />
196
+ ${waypointMarkup}
197
+ </g>`;
198
+ })
199
+ .join("");
200
+ }
201
+ function renderTrajectoryWaypoint(trajectory, waypoint, showLabels) {
202
+ const labelMarkup = showLabels && trajectory.labelMode !== "hidden"
203
+ ? [
204
+ waypoint.label
205
+ ? `<text class="wo-trajectory-label" x="${waypoint.x + 10}" y="${waypoint.y - 10}" font-size="10">${escapeXml(waypoint.label)}</text>`
206
+ : "",
207
+ waypoint.dateLabel
208
+ ? `<text class="wo-trajectory-date" x="${waypoint.x + 10}" y="${waypoint.y + 4}" font-size="9">${escapeXml(waypoint.dateLabel)}</text>`
209
+ : "",
210
+ ].join("")
211
+ : "";
212
+ return `<g class="wo-trajectory-waypoint-group" data-render-id="${escapeXml(waypoint.renderId)}" data-trajectory-id="${escapeAttribute(waypoint.trajectoryId)}">
213
+ <circle class="wo-trajectory-waypoint" cx="${waypoint.x}" cy="${waypoint.y}" r="4.5" />
214
+ ${labelMarkup}
159
215
  </g>`;
160
216
  }
161
217
  export function renderDocumentToSvg(document, options = {}) {
@@ -259,6 +315,8 @@ function renderObjectBody(object, x, y, radius, palette, options = {}) {
259
315
  ? `<circle cx="${x}" cy="${y}" r="${radius}" fill="transparent" stroke="${palette.stroke}" stroke-width="1.4" />`
260
316
  : `<path d="M ${x - radius * 2} ${y + radius * 1.3} Q ${x - radius * 0.7} ${y + radius * 0.3} ${x - radius * 0.45} ${y}" fill="none" stroke="${tail}" stroke-width="${Math.max(2, radius * 0.8)}" stroke-linecap="round" opacity="0.85" />
261
317
  <circle cx="${x}" cy="${y}" r="${radius}" fill="${fill}" stroke="${palette.stroke}" stroke-width="1.4" />`;
318
+ case "craft":
319
+ return `<polygon points="${diamondPoints(x, y, radius * 0.85)}" fill="${fill}" stroke="${palette.stroke}" stroke-width="1.4" />`;
262
320
  case "structure":
263
321
  return `<polygon points="${diamondPoints(x, y, radius)}" fill="${fill}" stroke="${palette.stroke}" stroke-width="1.4" />`;
264
322
  case "phenomenon": {
@@ -443,6 +501,8 @@ function basePaletteForType(type, kind, theme) {
443
501
  return { fill: "#9ce7ff", stroke: "#e7fbff" };
444
502
  case "ring":
445
503
  return { fill: "#e59f7d", stroke: "#fff0d3" };
504
+ case "craft":
505
+ return { fill: "#ffb47f", stroke: "#fff0d3" };
446
506
  case "structure":
447
507
  return { fill: theme.accentStrong, stroke: "#fff2ea" };
448
508
  case "phenomenon":
@@ -686,6 +686,8 @@ function colorForObject(object) {
686
686
  return "#b8926a";
687
687
  case "ring":
688
688
  return "#cdbf9a";
689
+ case "craft":
690
+ return "#ffce8a";
689
691
  case "structure":
690
692
  return "#ffce8a";
691
693
  case "phenomenon":
@@ -4,6 +4,7 @@ const DEFAULT_LAYERS = {
4
4
  relations: true,
5
5
  events: true,
6
6
  orbits: true,
7
+ trajectories: true,
7
8
  objects: true,
8
9
  labels: true,
9
10
  structures: true,
@@ -43,6 +43,7 @@ export interface ViewerLayerOptions {
43
43
  relations?: boolean;
44
44
  events?: boolean;
45
45
  orbits?: boolean;
46
+ trajectories?: boolean;
46
47
  objects?: boolean;
47
48
  labels?: boolean;
48
49
  structures?: boolean;
@@ -77,6 +78,9 @@ export interface ViewerRenderOptions extends Omit<SvgRenderOptions, "selectedObj
77
78
  viewMode?: WorldOrbitViewMode;
78
79
  quality?: WorldOrbit3DQuality;
79
80
  style3d?: WorldOrbit3DStyle;
81
+ trajectoryMode?: "illustrative" | "solver" | "auto";
82
+ showTrajectoryWaypoints?: boolean;
83
+ showTrajectoryLabels?: boolean;
80
84
  }
81
85
  export interface ViewerState {
82
86
  scale: number;
@@ -130,6 +134,9 @@ export interface ViewerAtlasState {
130
134
  layers?: ViewerLayerOptions;
131
135
  scaleModel?: Partial<RenderScaleModel>;
132
136
  bodyScaleMode?: SceneRenderOptions["bodyScaleMode"];
137
+ trajectoryMode?: SceneRenderOptions["trajectoryMode"];
138
+ showTrajectoryWaypoints?: boolean;
139
+ showTrajectoryLabels?: boolean;
133
140
  activeEventId?: string | null;
134
141
  viewMode?: WorldOrbitViewMode;
135
142
  quality?: WorldOrbit3DQuality;
@@ -1086,7 +1086,7 @@ export function createInteractiveViewer(container, options) {
1086
1086
  tooltipRoot.hidden = false;
1087
1087
  tooltipRoot.dataset.mode = resolved.mode;
1088
1088
  tooltipRoot.classList.toggle("is-pinned", resolved.mode === "pinned");
1089
- tooltipRoot.style.pointerEvents = "auto";
1089
+ tooltipRoot.style.pointerEvents = resolved.mode === "pinned" ? "auto" : "none";
1090
1090
  tooltipRoot.style.visibility = "hidden";
1091
1091
  renderTooltipContent(tooltipRoot, tooltipDetails, resolved.mode);
1092
1092
  positionTooltip(tooltipRoot, details.renderObject);
@@ -1691,6 +1691,33 @@ function fallbackSpatialSceneFromRenderScene(scene) {
1691
1691
  hidden: orbit.hidden,
1692
1692
  motion: null,
1693
1693
  })),
1694
+ trajectories: scene.trajectories.map((trajectory) => ({
1695
+ trajectoryId: trajectory.trajectoryId,
1696
+ trajectory: trajectory.trajectory,
1697
+ craftObjectId: trajectory.craftObjectId,
1698
+ mode: trajectory.mode,
1699
+ stroke: trajectory.stroke,
1700
+ strokeWidth: trajectory.strokeWidth,
1701
+ marker: trajectory.marker,
1702
+ labelMode: trajectory.labelMode,
1703
+ showWaypoints: trajectory.showWaypoints,
1704
+ samples: [],
1705
+ waypoints: trajectory.waypoints.map((waypoint) => ({
1706
+ trajectoryId: waypoint.trajectoryId,
1707
+ segmentId: waypoint.segmentId,
1708
+ maneuverId: waypoint.maneuverId,
1709
+ objectId: waypoint.objectId,
1710
+ position: {
1711
+ x: waypoint.x - scene.contentBounds.centerX,
1712
+ y: 0,
1713
+ z: waypoint.y - scene.contentBounds.centerY,
1714
+ },
1715
+ label: waypoint.label,
1716
+ dateLabel: waypoint.dateLabel,
1717
+ hidden: waypoint.hidden,
1718
+ })),
1719
+ hidden: trajectory.hidden,
1720
+ })),
1694
1721
  focusTargets: scene.objects.map((object) => ({
1695
1722
  objectId: object.objectId,
1696
1723
  center: {
@@ -1732,7 +1759,11 @@ function getClosestObjectId(target) {
1732
1759
  if (!(target instanceof Element)) {
1733
1760
  return null;
1734
1761
  }
1735
- return target.closest("[data-object-id]")?.dataset.objectId ?? null;
1762
+ const selectionTarget = target.closest("[data-object-id], [data-orbit-object-id]");
1763
+ if (!selectionTarget) {
1764
+ return null;
1765
+ }
1766
+ return selectionTarget.dataset.objectId ?? selectionTarget.dataset.orbitObjectId ?? null;
1736
1767
  }
1737
1768
  function ensureBrowserEnvironment(container) {
1738
1769
  if (typeof window === "undefined" || typeof document === "undefined") {
@@ -1864,7 +1895,7 @@ function installViewerOverlayStyles() {
1864
1895
  backdrop-filter: blur(12px);
1865
1896
  font: 500 13px/1.5 "Segoe UI Variable", "Segoe UI", sans-serif;
1866
1897
  }
1867
- .wo-viewer-tooltip-root[data-mode="hover"] { pointer-events: auto; }
1898
+ .wo-viewer-tooltip-root[data-mode="hover"] { pointer-events: none; }
1868
1899
  .wo-viewer-tooltip-root[data-mode="pinned"] { pointer-events: auto; }
1869
1900
  .wo-tooltip-card { display: grid; gap: 10px; }
1870
1901
  .wo-tooltip-head { display: grid; grid-template-columns: 52px minmax(0, 1fr); gap: 12px; align-items: center; }