worldorbit 2.5.16 → 2.5.17

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 (34) hide show
  1. package/README.md +1 -1
  2. package/dist/browser/core/dist/index.js +750 -73
  3. package/dist/browser/editor/dist/index.js +1303 -135
  4. package/dist/browser/markdown/dist/index.js +631 -72
  5. package/dist/browser/viewer/dist/index.js +658 -77
  6. package/dist/unpkg/core/dist/index.js +750 -73
  7. package/dist/unpkg/editor/dist/index.js +1303 -135
  8. package/dist/unpkg/markdown/dist/index.js +631 -72
  9. package/dist/unpkg/viewer/dist/index.js +658 -77
  10. package/dist/unpkg/worldorbit-core.min.js +12 -12
  11. package/dist/unpkg/worldorbit-editor.min.js +284 -202
  12. package/dist/unpkg/worldorbit-markdown.min.js +66 -58
  13. package/dist/unpkg/worldorbit-viewer.min.js +76 -68
  14. package/dist/unpkg/worldorbit.js +797 -78
  15. package/dist/unpkg/worldorbit.min.js +80 -72
  16. package/package.json +1 -1
  17. package/packages/core/dist/atlas-edit.js +74 -0
  18. package/packages/core/dist/atlas-validate.js +122 -8
  19. package/packages/core/dist/draft-parse.js +212 -8
  20. package/packages/core/dist/draft.d.ts +5 -2
  21. package/packages/core/dist/draft.js +59 -3
  22. package/packages/core/dist/format.js +63 -1
  23. package/packages/core/dist/normalize.js +1 -0
  24. package/packages/core/dist/scene.js +248 -46
  25. package/packages/core/dist/types.d.ts +41 -2
  26. package/packages/editor/dist/editor.js +597 -61
  27. package/packages/editor/dist/types.d.ts +3 -1
  28. package/packages/viewer/dist/atlas-state.js +6 -0
  29. package/packages/viewer/dist/atlas-viewer.js +1 -0
  30. package/packages/viewer/dist/render.js +31 -2
  31. package/packages/viewer/dist/theme.js +1 -0
  32. package/packages/viewer/dist/tooltip.js +9 -0
  33. package/packages/viewer/dist/types.d.ts +8 -1
  34. package/packages/viewer/dist/viewer.js +12 -1
@@ -61,6 +61,7 @@ var WorldOrbit = (() => {
61
61
  background: true,
62
62
  guides: true,
63
63
  relations: true,
64
+ events: true,
64
65
  orbits: true,
65
66
  objects: true,
66
67
  labels: true,
@@ -212,12 +213,14 @@ var WorldOrbit = (() => {
212
213
  return {
213
214
  version: "2.0",
214
215
  viewpointId,
216
+ activeEventId: renderOptions.activeEventId ?? null,
215
217
  viewerState: { ...viewerState },
216
218
  renderOptions: {
217
219
  preset: renderOptions.preset,
218
220
  projection: renderOptions.projection,
219
221
  layers: renderOptions.layers ? { ...renderOptions.layers } : void 0,
220
- scaleModel: renderOptions.scaleModel ? { ...renderOptions.scaleModel } : void 0
222
+ scaleModel: renderOptions.scaleModel ? { ...renderOptions.scaleModel } : void 0,
223
+ activeEventId: renderOptions.activeEventId ?? null
221
224
  },
222
225
  filter: normalizeViewerFilter(filter)
223
226
  };
@@ -230,6 +233,7 @@ var WorldOrbit = (() => {
230
233
  return {
231
234
  version: "2.0",
232
235
  viewpointId: raw.viewpointId ?? null,
236
+ activeEventId: raw.activeEventId ?? raw.renderOptions?.activeEventId ?? null,
233
237
  viewerState: {
234
238
  scale: raw.viewerState?.scale ?? 1,
235
239
  rotationDeg: raw.viewerState?.rotationDeg ?? 0,
@@ -241,7 +245,8 @@ var WorldOrbit = (() => {
241
245
  preset: raw.renderOptions?.preset,
242
246
  projection: raw.renderOptions?.projection,
243
247
  layers: raw.renderOptions?.layers ? { ...raw.renderOptions.layers } : void 0,
244
- scaleModel: raw.renderOptions?.scaleModel ? { ...raw.renderOptions.scaleModel } : void 0
248
+ scaleModel: raw.renderOptions?.scaleModel ? { ...raw.renderOptions.scaleModel } : void 0,
249
+ activeEventId: raw.activeEventId ?? raw.renderOptions?.activeEventId ?? null
245
250
  },
246
251
  filter: normalizeViewerFilter(raw.filter ?? null)
247
252
  };
@@ -257,7 +262,8 @@ var WorldOrbit = (() => {
257
262
  renderOptions: {
258
263
  ...atlasState.renderOptions,
259
264
  layers: atlasState.renderOptions.layers ? { ...atlasState.renderOptions.layers } : void 0,
260
- scaleModel: atlasState.renderOptions.scaleModel ? { ...atlasState.renderOptions.scaleModel } : void 0
265
+ scaleModel: atlasState.renderOptions.scaleModel ? { ...atlasState.renderOptions.scaleModel } : void 0,
266
+ activeEventId: atlasState.renderOptions.activeEventId ?? null
261
267
  },
262
268
  filter: atlasState.filter ? { ...atlasState.filter } : null
263
269
  }
@@ -275,6 +281,7 @@ var WorldOrbit = (() => {
275
281
  background: viewpoint.layers.background,
276
282
  guides: viewpoint.layers.guides,
277
283
  relations: viewpoint.layers.relations,
284
+ events: viewpoint.layers.events,
278
285
  orbits: viewpoint.layers["orbits-front"] === void 0 && viewpoint.layers["orbits-back"] === void 0 ? void 0 : viewpoint.layers["orbits-front"] !== false || viewpoint.layers["orbits-back"] !== false,
279
286
  objects: viewpoint.layers.objects,
280
287
  labels: viewpoint.layers.labels,
@@ -922,6 +929,7 @@ var WorldOrbit = (() => {
922
929
  system,
923
930
  groups: [],
924
931
  relations: [],
932
+ events: [],
925
933
  objects
926
934
  };
927
935
  }
@@ -1305,8 +1313,10 @@ var WorldOrbit = (() => {
1305
1313
  const scaleModel = resolveScaleModel(layoutPreset, options.scaleModel);
1306
1314
  const spacingFactor = layoutPresetSpacing(layoutPreset);
1307
1315
  const systemId = document2.system?.id ?? null;
1308
- const objectMap = new Map(document2.objects.map((object) => [object.id, object]));
1309
- const relationships = buildSceneRelationships(document2.objects, objectMap);
1316
+ const activeEventId = options.activeEventId ?? null;
1317
+ const effectiveObjects = createEffectiveObjects(document2.objects, document2.events ?? [], activeEventId);
1318
+ const objectMap = new Map(effectiveObjects.map((object) => [object.id, object]));
1319
+ const relationships = buildSceneRelationships(effectiveObjects, objectMap);
1310
1320
  const positions = /* @__PURE__ */ new Map();
1311
1321
  const orbitDrafts = [];
1312
1322
  const leaderDrafts = [];
@@ -1315,7 +1325,7 @@ var WorldOrbit = (() => {
1315
1325
  const atObjects = [];
1316
1326
  const surfaceChildren = /* @__PURE__ */ new Map();
1317
1327
  const orbitChildren = /* @__PURE__ */ new Map();
1318
- for (const object of document2.objects) {
1328
+ for (const object of effectiveObjects) {
1319
1329
  const placement = object.placement;
1320
1330
  if (!placement) {
1321
1331
  rootObjects.push(object);
@@ -1410,13 +1420,14 @@ var WorldOrbit = (() => {
1410
1420
  const objects = [...positions.values()].map((position) => createSceneObject(position, scaleModel, relationships));
1411
1421
  const orbitVisuals = orbitDrafts.map((draft) => createOrbitVisual(draft, relationships.groupIds.get(draft.object.id) ?? null));
1412
1422
  const leaders = leaderDrafts.map((draft) => createLeaderLine(draft));
1413
- const labels = createSceneLabels(objects, height, scaleModel.labelMultiplier);
1423
+ const labels = createSceneLabels(objects, width, height, scaleModel.labelMultiplier);
1414
1424
  const relations = createSceneRelations(document2, objects);
1415
- const layers = createSceneLayers(orbitVisuals, relations, leaders, objects, labels);
1416
- const groups = createSceneGroups(objects, orbitVisuals, leaders, labels, relationships);
1425
+ const events = createSceneEvents(document2.events ?? [], objects, activeEventId);
1426
+ const layers = createSceneLayers(orbitVisuals, relations, events, leaders, objects, labels);
1427
+ const groups = createSceneGroups(objects, orbitVisuals, leaders, labels, relationships, scaleModel.labelMultiplier);
1417
1428
  const semanticGroups = createSceneSemanticGroups(document2, objects);
1418
1429
  const viewpoints = createSceneViewpoints(document2, projection, frame.preset, relationships, objectMap);
1419
- const contentBounds = calculateContentBounds(width, height, objects, orbitVisuals, leaders, labels);
1430
+ const contentBounds = calculateContentBounds(width, height, objects, orbitVisuals, leaders, labels, scaleModel.labelMultiplier);
1420
1431
  return {
1421
1432
  width,
1422
1433
  height,
@@ -1442,6 +1453,8 @@ var WorldOrbit = (() => {
1442
1453
  groups,
1443
1454
  semanticGroups,
1444
1455
  viewpoints,
1456
+ events,
1457
+ activeEventId,
1445
1458
  objects,
1446
1459
  orbitVisuals,
1447
1460
  relations,
@@ -1460,6 +1473,35 @@ var WorldOrbit = (() => {
1460
1473
  y: center.y + dx * sin + dy * cos
1461
1474
  };
1462
1475
  }
1476
+ function createEffectiveObjects(objects, events, activeEventId) {
1477
+ const cloned = objects.map((object) => structuredClone(object));
1478
+ if (!activeEventId) {
1479
+ return cloned;
1480
+ }
1481
+ const activeEvent = events.find((event) => event.id === activeEventId);
1482
+ if (!activeEvent) {
1483
+ return cloned;
1484
+ }
1485
+ const objectMap = new Map(cloned.map((object) => [object.id, object]));
1486
+ for (const pose of activeEvent.positions) {
1487
+ const object = objectMap.get(pose.objectId);
1488
+ if (!object) {
1489
+ continue;
1490
+ }
1491
+ object.placement = pose.placement ? structuredClone(pose.placement) : null;
1492
+ if (pose.inner) {
1493
+ object.properties.inner = { ...pose.inner };
1494
+ } else {
1495
+ delete object.properties.inner;
1496
+ }
1497
+ if (pose.outer) {
1498
+ object.properties.outer = { ...pose.outer };
1499
+ } else {
1500
+ delete object.properties.outer;
1501
+ }
1502
+ }
1503
+ return cloned;
1504
+ }
1463
1505
  function resolveLayoutPreset(document2) {
1464
1506
  const rawScale = String(document2.system?.properties.scale ?? "balanced").toLowerCase();
1465
1507
  switch (rawScale) {
@@ -1615,24 +1657,14 @@ var WorldOrbit = (() => {
1615
1657
  hidden: draft.object.properties.hidden === true
1616
1658
  };
1617
1659
  }
1618
- function createSceneLabels(objects, sceneHeight, labelMultiplier) {
1660
+ function createSceneLabels(objects, sceneWidth, sceneHeight, labelMultiplier) {
1619
1661
  const labels = [];
1620
1662
  const occupied = [];
1621
- const visibleObjects = [...objects].filter((object) => !object.hidden && object.object.renderHints?.renderLabel !== false).sort((left, right) => left.sortKey - right.sortKey);
1663
+ const objectMap = new Map(objects.map((object) => [object.objectId, object]));
1664
+ const visibleObjects = [...objects].filter((object) => !object.hidden && object.object.renderHints?.renderLabel !== false).sort(compareLabelPlacementOrder);
1622
1665
  for (const object of visibleObjects) {
1623
- const direction = object.y > sceneHeight * 0.62 ? -1 : 1;
1624
- const labelHalfWidth = estimateLabelHalfWidth(object, labelMultiplier);
1625
- let labelY = object.y + direction * (object.radius + 18 * labelMultiplier);
1626
- let secondaryY = labelY + direction * (16 * labelMultiplier);
1627
- let bounds = createLabelRect(object.x, labelY, secondaryY, labelHalfWidth, direction);
1628
- let attempts = 0;
1629
- while (occupied.some((entry) => rectsOverlap(entry, bounds)) && attempts < 10) {
1630
- labelY += direction * 14 * labelMultiplier;
1631
- secondaryY += direction * 14 * labelMultiplier;
1632
- bounds = createLabelRect(object.x, labelY, secondaryY, labelHalfWidth, direction);
1633
- attempts += 1;
1634
- }
1635
- occupied.push(bounds);
1666
+ const placement = selectLabelPlacement(object, objectMap, occupied, sceneWidth, sceneHeight, labelMultiplier) ?? createLabelPlacement(object, defaultVerticalDirection(object, objectMap.get(object.parentId ?? "") ?? null, sceneHeight), 0, labelMultiplier);
1667
+ occupied.push(createLabelRect(object, placement, labelMultiplier));
1636
1668
  labels.push({
1637
1669
  renderId: `${object.renderId}-label`,
1638
1670
  objectId: object.objectId,
@@ -1641,17 +1673,128 @@ var WorldOrbit = (() => {
1641
1673
  semanticGroupIds: [...object.semanticGroupIds],
1642
1674
  label: object.label,
1643
1675
  secondaryLabel: object.secondaryLabel,
1644
- x: object.x,
1645
- y: labelY,
1646
- secondaryY,
1647
- textAnchor: "middle",
1648
- direction: direction < 0 ? "above" : "below",
1676
+ x: placement.x,
1677
+ y: placement.labelY,
1678
+ secondaryY: placement.secondaryY,
1679
+ textAnchor: placement.textAnchor,
1680
+ direction: placement.direction,
1649
1681
  hidden: object.hidden
1650
1682
  });
1651
1683
  }
1652
1684
  return labels;
1653
1685
  }
1654
- function createSceneLayers(orbitVisuals, relations, leaders, objects, labels) {
1686
+ function compareLabelPlacementOrder(left, right) {
1687
+ const priorityDiff = labelPlacementPriority(left) - labelPlacementPriority(right);
1688
+ if (priorityDiff !== 0) {
1689
+ return priorityDiff;
1690
+ }
1691
+ const renderPriorityDiff = (right.object.renderHints?.renderPriority ?? 0) - (left.object.renderHints?.renderPriority ?? 0);
1692
+ if (renderPriorityDiff !== 0) {
1693
+ return renderPriorityDiff;
1694
+ }
1695
+ return left.sortKey - right.sortKey;
1696
+ }
1697
+ function labelPlacementPriority(object) {
1698
+ switch (object.object.type) {
1699
+ case "star":
1700
+ return 0;
1701
+ case "planet":
1702
+ return 1;
1703
+ case "moon":
1704
+ return 2;
1705
+ case "belt":
1706
+ case "ring":
1707
+ return 3;
1708
+ case "asteroid":
1709
+ case "comet":
1710
+ return 4;
1711
+ case "structure":
1712
+ case "phenomenon":
1713
+ return 5;
1714
+ }
1715
+ }
1716
+ function selectLabelPlacement(object, objectMap, occupied, sceneWidth, sceneHeight, labelMultiplier) {
1717
+ for (const direction of preferredLabelDirections(object, objectMap, sceneWidth, sceneHeight)) {
1718
+ const maxAttempts = direction === "left" || direction === "right" ? 4 : 6;
1719
+ for (let attempt = 0; attempt <= maxAttempts; attempt += 1) {
1720
+ const placement = createLabelPlacement(object, direction, attempt, labelMultiplier);
1721
+ const rect = createLabelRect(object, placement, labelMultiplier);
1722
+ if (!occupied.some((entry) => rectsOverlap(entry, rect))) {
1723
+ return placement;
1724
+ }
1725
+ }
1726
+ }
1727
+ return null;
1728
+ }
1729
+ function preferredLabelDirections(object, objectMap, sceneWidth, sceneHeight) {
1730
+ const parent = object.parentId ? objectMap.get(object.parentId) ?? null : null;
1731
+ const vertical = defaultVerticalDirection(object, parent, sceneHeight);
1732
+ const oppositeVertical = vertical === "below" ? "above" : "below";
1733
+ const horizontal = defaultHorizontalDirection(object, parent, sceneWidth);
1734
+ const oppositeHorizontal = horizontal === "right" ? "left" : "right";
1735
+ const preferHorizontal = object.object.type === "structure" || object.object.type === "phenomenon" || object.object.placement?.mode === "at" || object.object.placement?.mode === "surface" || object.object.placement?.mode === "free";
1736
+ return preferHorizontal ? [horizontal, vertical, oppositeHorizontal, oppositeVertical] : [vertical, horizontal, oppositeVertical, oppositeHorizontal];
1737
+ }
1738
+ function defaultVerticalDirection(object, parent, sceneHeight) {
1739
+ if (parent && Math.abs(object.y - parent.y) > 6) {
1740
+ return object.y >= parent.y ? "below" : "above";
1741
+ }
1742
+ return object.y > sceneHeight * 0.62 ? "above" : "below";
1743
+ }
1744
+ function defaultHorizontalDirection(object, parent, sceneWidth) {
1745
+ if (parent && Math.abs(object.x - parent.x) > 6) {
1746
+ return object.x >= parent.x ? "right" : "left";
1747
+ }
1748
+ return object.x >= sceneWidth / 2 ? "right" : "left";
1749
+ }
1750
+ function createLabelPlacement(object, direction, attempt, labelMultiplier) {
1751
+ const step = 14 * labelMultiplier;
1752
+ switch (direction) {
1753
+ case "above": {
1754
+ const labelY = object.y - (object.radius + 18 * labelMultiplier + attempt * step);
1755
+ return {
1756
+ x: object.x,
1757
+ labelY,
1758
+ secondaryY: labelY - 16 * labelMultiplier,
1759
+ textAnchor: "middle",
1760
+ direction
1761
+ };
1762
+ }
1763
+ case "below": {
1764
+ const labelY = object.y + object.radius + 18 * labelMultiplier + attempt * step;
1765
+ return {
1766
+ x: object.x,
1767
+ labelY,
1768
+ secondaryY: labelY + 16 * labelMultiplier,
1769
+ textAnchor: "middle",
1770
+ direction
1771
+ };
1772
+ }
1773
+ case "left": {
1774
+ const x = object.x - (object.visualRadius + 16 * labelMultiplier + attempt * step);
1775
+ const labelY = object.y - 4 * labelMultiplier;
1776
+ return {
1777
+ x,
1778
+ labelY,
1779
+ secondaryY: labelY + 16 * labelMultiplier,
1780
+ textAnchor: "end",
1781
+ direction
1782
+ };
1783
+ }
1784
+ case "right": {
1785
+ const x = object.x + object.visualRadius + 16 * labelMultiplier + attempt * step;
1786
+ const labelY = object.y - 4 * labelMultiplier;
1787
+ return {
1788
+ x,
1789
+ labelY,
1790
+ secondaryY: labelY + 16 * labelMultiplier,
1791
+ textAnchor: "start",
1792
+ direction
1793
+ };
1794
+ }
1795
+ }
1796
+ }
1797
+ function createSceneLayers(orbitVisuals, relations, events, leaders, objects, labels) {
1655
1798
  const backOrbitIds = orbitVisuals.filter((visual) => !visual.hidden && Boolean(visual.backArcPath)).map((visual) => visual.renderId);
1656
1799
  const frontOrbitIds = orbitVisuals.filter((visual) => !visual.hidden).map((visual) => visual.renderId);
1657
1800
  return [
@@ -1666,6 +1809,10 @@ var WorldOrbit = (() => {
1666
1809
  id: "relations",
1667
1810
  renderIds: relations.filter((relation) => !relation.hidden).map((relation) => relation.renderId)
1668
1811
  },
1812
+ {
1813
+ id: "events",
1814
+ renderIds: events.filter((event) => !event.hidden).map((event) => event.renderId)
1815
+ },
1669
1816
  {
1670
1817
  id: "objects",
1671
1818
  renderIds: objects.filter((object) => !object.hidden).map((object) => object.renderId)
@@ -1677,7 +1824,7 @@ var WorldOrbit = (() => {
1677
1824
  { id: "metadata", renderIds: ["wo-title", "wo-subtitle", "wo-meta"] }
1678
1825
  ];
1679
1826
  }
1680
- function createSceneGroups(objects, orbitVisuals, leaders, labels, relationships) {
1827
+ function createSceneGroups(objects, orbitVisuals, leaders, labels, relationships, labelMultiplier) {
1681
1828
  const groups = /* @__PURE__ */ new Map();
1682
1829
  const ensureGroup = (groupId) => {
1683
1830
  if (!groupId) {
@@ -1726,7 +1873,7 @@ var WorldOrbit = (() => {
1726
1873
  }
1727
1874
  }
1728
1875
  for (const group of groups.values()) {
1729
- group.contentBounds = calculateGroupBounds(group, objects, orbitVisuals, leaders, labels);
1876
+ group.contentBounds = calculateGroupBounds(group, objects, orbitVisuals, leaders, labels, labelMultiplier);
1730
1877
  }
1731
1878
  return [...groups.values()].sort((left, right) => left.label.localeCompare(right.label));
1732
1879
  }
@@ -1760,6 +1907,29 @@ var WorldOrbit = (() => {
1760
1907
  };
1761
1908
  }).sort((left, right) => left.relation.id.localeCompare(right.relation.id));
1762
1909
  }
1910
+ function createSceneEvents(events, objects, activeEventId) {
1911
+ const objectMap = new Map(objects.map((object) => [object.objectId, object]));
1912
+ return events.map((event) => {
1913
+ const objectIds = [.../* @__PURE__ */ new Set([
1914
+ ...event.targetObjectId ? [event.targetObjectId] : [],
1915
+ ...event.participantObjectIds
1916
+ ])];
1917
+ const positions = objectIds.map((objectId) => objectMap.get(objectId)).filter(Boolean);
1918
+ const centroidX = positions.length > 0 ? positions.reduce((sum, object) => sum + object.x, 0) / positions.length : 0;
1919
+ const centroidY = positions.length > 0 ? positions.reduce((sum, object) => sum + object.y, 0) / positions.length : 0;
1920
+ return {
1921
+ renderId: `${createRenderId(event.id)}-event`,
1922
+ eventId: event.id,
1923
+ event,
1924
+ objectIds,
1925
+ participantIds: [...event.participantObjectIds],
1926
+ targetObjectId: event.targetObjectId,
1927
+ x: centroidX,
1928
+ y: centroidY,
1929
+ hidden: event.hidden || positions.length === 0 || positions.every((object) => object.hidden) || activeEventId !== null && event.id !== activeEventId
1930
+ };
1931
+ }).sort((left, right) => left.event.id.localeCompare(right.event.id));
1932
+ }
1763
1933
  function createSceneViewpoints(document2, projection, preset, relationships, objectMap) {
1764
1934
  const generatedOverview = createGeneratedOverviewViewpoint(document2, projection, preset);
1765
1935
  const drafts = /* @__PURE__ */ new Map();
@@ -1813,6 +1983,7 @@ var WorldOrbit = (() => {
1813
1983
  summary: "Fit the whole system with the current atlas defaults.",
1814
1984
  objectId: null,
1815
1985
  selectedObjectId: null,
1986
+ eventIds: [],
1816
1987
  projection,
1817
1988
  preset,
1818
1989
  rotationDeg: 0,
@@ -1849,6 +2020,9 @@ var WorldOrbit = (() => {
1849
2020
  draft.select = normalizedValue;
1850
2021
  }
1851
2022
  return;
2023
+ case "events":
2024
+ draft.eventIds = splitListValue(normalizedValue);
2025
+ return;
1852
2026
  case "projection":
1853
2027
  case "view":
1854
2028
  draft.projection = parseViewProjection(normalizedValue) ?? projection;
@@ -1905,6 +2079,7 @@ var WorldOrbit = (() => {
1905
2079
  summary: draft.summary?.trim() || createViewpointSummary(label, objectId, filter),
1906
2080
  objectId,
1907
2081
  selectedObjectId,
2082
+ eventIds: [...new Set(draft.eventIds ?? [])],
1908
2083
  projection: draft.projection ?? projection,
1909
2084
  preset: draft.preset ?? preset,
1910
2085
  rotationDeg: draft.rotationDeg ?? 0,
@@ -1962,7 +2137,7 @@ var WorldOrbit = (() => {
1962
2137
  next["orbits-front"] = enabled;
1963
2138
  continue;
1964
2139
  }
1965
- if (rawLayer === "background" || rawLayer === "guides" || rawLayer === "orbits-back" || rawLayer === "orbits-front" || rawLayer === "relations" || rawLayer === "objects" || rawLayer === "labels" || rawLayer === "metadata") {
2140
+ if (rawLayer === "background" || rawLayer === "guides" || rawLayer === "orbits-back" || rawLayer === "orbits-front" || rawLayer === "relations" || rawLayer === "events" || rawLayer === "objects" || rawLayer === "labels" || rawLayer === "metadata") {
1966
2141
  next[rawLayer] = enabled;
1967
2142
  }
1968
2143
  }
@@ -2010,7 +2185,7 @@ var WorldOrbit = (() => {
2010
2185
  }
2011
2186
  return parts.join(" - ");
2012
2187
  }
2013
- function calculateContentBounds(width, height, objects, orbitVisuals, leaders, labels) {
2188
+ function calculateContentBounds(width, height, objects, orbitVisuals, leaders, labels, labelMultiplier) {
2014
2189
  let minX = Number.POSITIVE_INFINITY;
2015
2190
  let minY = Number.POSITIVE_INFINITY;
2016
2191
  let maxX = Number.NEGATIVE_INFINITY;
@@ -2040,7 +2215,7 @@ var WorldOrbit = (() => {
2040
2215
  for (const label of labels) {
2041
2216
  if (label.hidden)
2042
2217
  continue;
2043
- includeLabelBounds(label, include);
2218
+ includeLabelBounds(label, include, labelMultiplier);
2044
2219
  }
2045
2220
  if (!Number.isFinite(minX) || !Number.isFinite(minY)) {
2046
2221
  return createBounds(0, 0, width, height);
@@ -2078,13 +2253,10 @@ var WorldOrbit = (() => {
2078
2253
  include(object.x - object.visualRadius - 24, object.y - object.visualRadius - 16);
2079
2254
  include(object.x + object.visualRadius + 24, object.y + object.visualRadius + 36);
2080
2255
  }
2081
- function includeLabelBounds(label, include) {
2082
- const labelScale = 1;
2083
- const labelHalfWidth = estimateLabelHalfWidthFromText(label.label, label.secondaryLabel, labelScale);
2084
- include(label.x - labelHalfWidth, label.y - 18);
2085
- include(label.x + labelHalfWidth, label.y + 8);
2086
- include(label.x - labelHalfWidth, label.secondaryY - 14);
2087
- include(label.x + labelHalfWidth, label.secondaryY + 8);
2256
+ function includeLabelBounds(label, include, labelMultiplier) {
2257
+ const bounds = createLabelRectFromText(label.x, label.y, label.secondaryY, label.textAnchor, label.direction, label.label, label.secondaryLabel, labelMultiplier);
2258
+ include(bounds.left, bounds.top);
2259
+ include(bounds.right, bounds.bottom);
2088
2260
  }
2089
2261
  function placeObject(object, x, y, depth, positions, orbitDrafts, leaderDrafts, context) {
2090
2262
  if (positions.has(object.id)) {
@@ -2474,7 +2646,7 @@ var WorldOrbit = (() => {
2474
2646
  return null;
2475
2647
  }
2476
2648
  }
2477
- function calculateGroupBounds(group, objects, orbitVisuals, leaders, labels) {
2649
+ function calculateGroupBounds(group, objects, orbitVisuals, leaders, labels, labelMultiplier) {
2478
2650
  let minX = Number.POSITIVE_INFINITY;
2479
2651
  let minY = Number.POSITIVE_INFINITY;
2480
2652
  let maxX = Number.NEGATIVE_INFINITY;
@@ -2503,7 +2675,7 @@ var WorldOrbit = (() => {
2503
2675
  }
2504
2676
  for (const label of labels) {
2505
2677
  if (!label.hidden && group.labelIds.includes(label.objectId)) {
2506
- includeLabelBounds(label, include);
2678
+ includeLabelBounds(label, include, labelMultiplier);
2507
2679
  }
2508
2680
  }
2509
2681
  if (!Number.isFinite(minX) || !Number.isFinite(minY)) {
@@ -2528,12 +2700,28 @@ var WorldOrbit = (() => {
2528
2700
  }
2529
2701
  return current.id;
2530
2702
  }
2531
- function createLabelRect(x, labelY, secondaryY, labelHalfWidth, direction) {
2703
+ function createLabelRect(object, placement, labelMultiplier) {
2704
+ return createLabelRectFromText(placement.x, placement.labelY, placement.secondaryY, placement.textAnchor, placement.direction, object.label, object.secondaryLabel, labelMultiplier);
2705
+ }
2706
+ function createLabelRectFromText(x, labelY, secondaryY, textAnchor, direction, label, secondaryLabel, labelMultiplier) {
2707
+ const labelHalfWidth = estimateLabelHalfWidthFromText(label, secondaryLabel, labelMultiplier);
2708
+ const labelWidth = labelHalfWidth * 2;
2709
+ const topPadding = direction === "above" ? 18 : 12;
2710
+ const bottomPadding = direction === "above" ? 8 : 12;
2711
+ let left = x - labelHalfWidth;
2712
+ let right = x + labelHalfWidth;
2713
+ if (textAnchor === "start") {
2714
+ left = x;
2715
+ right = x + labelWidth;
2716
+ } else if (textAnchor === "end") {
2717
+ left = x - labelWidth;
2718
+ right = x;
2719
+ }
2532
2720
  return {
2533
- left: x - labelHalfWidth,
2534
- right: x + labelHalfWidth,
2535
- top: Math.min(labelY, secondaryY) - (direction < 0 ? 18 : 12),
2536
- bottom: Math.max(labelY, secondaryY) + (direction < 0 ? 8 : 12)
2721
+ left,
2722
+ right,
2723
+ top: Math.min(labelY, secondaryY) - topPadding,
2724
+ bottom: Math.max(labelY, secondaryY) + bottomPadding
2537
2725
  };
2538
2726
  }
2539
2727
  function rectsOverlap(left, right) {
@@ -2720,11 +2908,6 @@ var WorldOrbit = (() => {
2720
2908
  function customColorFor(value) {
2721
2909
  return typeof value === "string" && value.trim() ? value : void 0;
2722
2910
  }
2723
- function estimateLabelHalfWidth(object, labelMultiplier) {
2724
- const primaryWidth = object.label.length * 4.6 * labelMultiplier + 18;
2725
- const secondaryWidth = object.secondaryLabel.length * 3.9 * labelMultiplier + 18;
2726
- return Math.max(primaryWidth, secondaryWidth, object.visualRadius + 18);
2727
- }
2728
2911
  function estimateLabelHalfWidthFromText(label, secondaryLabel, labelMultiplier) {
2729
2912
  const primaryWidth = label.length * 4.6 * labelMultiplier + 18;
2730
2913
  const secondaryWidth = secondaryLabel.length * 3.9 * labelMultiplier + 18;
@@ -2741,7 +2924,7 @@ var WorldOrbit = (() => {
2741
2924
  }
2742
2925
 
2743
2926
  // packages/core/dist/draft.js
2744
- function materializeAtlasDocument(document2) {
2927
+ function materializeAtlasDocument(document2, options = {}) {
2745
2928
  const system = document2.system ? {
2746
2929
  type: "system",
2747
2930
  id: document2.system.id,
@@ -2752,6 +2935,8 @@ var WorldOrbit = (() => {
2752
2935
  properties: materializeDraftSystemProperties(document2.system),
2753
2936
  info: materializeDraftSystemInfo(document2.system)
2754
2937
  } : null;
2938
+ const objects = document2.objects.map(cloneWorldOrbitObject);
2939
+ applyEventPoseOverrides(objects, document2.events ?? [], options.activeEventId ?? null);
2755
2940
  return {
2756
2941
  format: "worldorbit",
2757
2942
  version: "1.0",
@@ -2759,7 +2944,8 @@ var WorldOrbit = (() => {
2759
2944
  system,
2760
2945
  groups: structuredClone(document2.groups ?? []),
2761
2946
  relations: structuredClone(document2.relations ?? []),
2762
- objects: document2.objects.map(cloneWorldOrbitObject)
2947
+ events: document2.events.map(cloneWorldOrbitEvent),
2948
+ objects
2763
2949
  };
2764
2950
  }
2765
2951
  function cloneWorldOrbitObject(object) {
@@ -2781,6 +2967,52 @@ var WorldOrbit = (() => {
2781
2967
  info: { ...object.info }
2782
2968
  };
2783
2969
  }
2970
+ function cloneWorldOrbitEvent(event) {
2971
+ return {
2972
+ ...event,
2973
+ participantObjectIds: [...event.participantObjectIds],
2974
+ tags: [...event.tags],
2975
+ positions: event.positions.map(cloneWorldOrbitEventPose)
2976
+ };
2977
+ }
2978
+ function cloneWorldOrbitEventPose(pose) {
2979
+ return {
2980
+ objectId: pose.objectId,
2981
+ placement: clonePlacement(pose.placement),
2982
+ inner: pose.inner ? { ...pose.inner } : void 0,
2983
+ outer: pose.outer ? { ...pose.outer } : void 0
2984
+ };
2985
+ }
2986
+ function clonePlacement(placement) {
2987
+ return placement ? structuredClone(placement) : null;
2988
+ }
2989
+ function applyEventPoseOverrides(objects, events, activeEventId) {
2990
+ if (!activeEventId) {
2991
+ return;
2992
+ }
2993
+ const event = events.find((entry) => entry.id === activeEventId);
2994
+ if (!event) {
2995
+ return;
2996
+ }
2997
+ const objectMap = new Map(objects.map((object) => [object.id, object]));
2998
+ for (const pose of event.positions) {
2999
+ const object = objectMap.get(pose.objectId);
3000
+ if (!object) {
3001
+ continue;
3002
+ }
3003
+ object.placement = clonePlacement(pose.placement);
3004
+ if (pose.inner) {
3005
+ object.properties.inner = { ...pose.inner };
3006
+ } else {
3007
+ delete object.properties.inner;
3008
+ }
3009
+ if (pose.outer) {
3010
+ object.properties.outer = { ...pose.outer };
3011
+ } else {
3012
+ delete object.properties.outer;
3013
+ }
3014
+ }
3015
+ }
2784
3016
  function cloneProperties(properties) {
2785
3017
  const next = {};
2786
3018
  for (const [key, value] of Object.entries(properties)) {
@@ -2869,6 +3101,9 @@ var WorldOrbit = (() => {
2869
3101
  if ((viewpoint.filter?.groupIds.length ?? 0) > 0) {
2870
3102
  info2[`${prefix}.groups`] = viewpoint.filter?.groupIds.join(" ") ?? "";
2871
3103
  }
3104
+ if (viewpoint.events.length > 0) {
3105
+ info2[`${prefix}.events`] = viewpoint.events.join(" ");
3106
+ }
2872
3107
  }
2873
3108
  for (const annotation of system.annotations) {
2874
3109
  const prefix = `annotation.${annotation.id}`;
@@ -2893,7 +3128,7 @@ var WorldOrbit = (() => {
2893
3128
  if (orbitFront !== void 0 || orbitBack !== void 0) {
2894
3129
  tokens.push(orbitFront !== false || orbitBack !== false ? "orbits" : "-orbits");
2895
3130
  }
2896
- for (const key of ["background", "guides", "relations", "objects", "labels", "metadata"]) {
3131
+ for (const key of ["background", "guides", "relations", "events", "objects", "labels", "metadata"]) {
2897
3132
  if (layers[key] !== void 0) {
2898
3133
  tokens.push(layers[key] ? key : `-${key}`);
2899
3134
  }
@@ -3067,6 +3302,7 @@ var WorldOrbit = (() => {
3067
3302
  const diagnostics = [];
3068
3303
  const objectMap = new Map(document2.objects.map((object) => [object.id, object]));
3069
3304
  const groupIds = new Set(document2.groups.map((group) => group.id));
3305
+ const eventIds = new Set(document2.events.map((event) => event.id));
3070
3306
  if (!document2.system) {
3071
3307
  diagnostics.push(error("validate.system.required", "Atlas documents must declare exactly one system."));
3072
3308
  }
@@ -3076,6 +3312,7 @@ var WorldOrbit = (() => {
3076
3312
  ["viewpoint", document2.system?.viewpoints.map((viewpoint) => viewpoint.id) ?? []],
3077
3313
  ["annotation", document2.system?.annotations.map((annotation) => annotation.id) ?? []],
3078
3314
  ["relation", document2.relations.map((relation) => relation.id)],
3315
+ ["event", document2.events.map((event) => event.id)],
3079
3316
  ["object", document2.objects.map((object) => object.id)]
3080
3317
  ]) {
3081
3318
  for (const id of ids) {
@@ -3091,11 +3328,14 @@ var WorldOrbit = (() => {
3091
3328
  validateRelation(relation, objectMap, diagnostics);
3092
3329
  }
3093
3330
  for (const viewpoint of document2.system?.viewpoints ?? []) {
3094
- validateViewpointFilter(viewpoint.filter, groupIds, sourceSchemaVersion, diagnostics, viewpoint.id);
3331
+ validateViewpoint(viewpoint.filter, viewpoint.events ?? [], groupIds, eventIds, sourceSchemaVersion, diagnostics, viewpoint.id);
3095
3332
  }
3096
3333
  for (const object of document2.objects) {
3097
3334
  validateObject(object, document2.system, objectMap, groupIds, diagnostics);
3098
3335
  }
3336
+ for (const event of document2.events) {
3337
+ validateEvent(event, objectMap, diagnostics);
3338
+ }
3099
3339
  return diagnostics;
3100
3340
  }
3101
3341
  function validateRelation(relation, objectMap, diagnostics) {
@@ -3113,13 +3353,19 @@ var WorldOrbit = (() => {
3113
3353
  diagnostics.push(error("validate.relation.kind.required", `Relation "${relation.id}" is missing a "kind" value.`));
3114
3354
  }
3115
3355
  }
3116
- function validateViewpointFilter(filter, groupIds, sourceSchemaVersion, diagnostics, viewpointId) {
3117
- if (!filter || sourceSchemaVersion !== "2.1") {
3118
- return;
3119
- }
3120
- for (const groupId of filter.groupIds) {
3121
- if (!groupIds.has(groupId)) {
3122
- diagnostics.push(warn("validate.viewpoint.group.unknown", `Unknown group "${groupId}" in viewpoint "${viewpointId}".`));
3356
+ function validateViewpoint(filter, eventRefs, groupIds, eventIds, sourceSchemaVersion, diagnostics, viewpointId) {
3357
+ if (sourceSchemaVersion === "2.1") {
3358
+ if (filter) {
3359
+ for (const groupId of filter.groupIds) {
3360
+ if (!groupIds.has(groupId)) {
3361
+ diagnostics.push(warn("validate.viewpoint.group.unknown", `Unknown group "${groupId}" in viewpoint "${viewpointId}".`, void 0, `viewpoint.${viewpointId}.groups`));
3362
+ }
3363
+ }
3364
+ }
3365
+ for (const eventId of eventRefs) {
3366
+ if (!eventIds.has(eventId)) {
3367
+ diagnostics.push(warn("validate.viewpoint.event.unknown", `Unknown event "${eventId}" in viewpoint "${viewpointId}".`, void 0, `viewpoint.${viewpointId}.events`));
3368
+ }
3123
3369
  }
3124
3370
  }
3125
3371
  }
@@ -3205,6 +3451,103 @@ var WorldOrbit = (() => {
3205
3451
  }
3206
3452
  }
3207
3453
  }
3454
+ function validateEvent(event, objectMap, diagnostics) {
3455
+ const fieldPrefix = `event.${event.id}`;
3456
+ const referencedIds = /* @__PURE__ */ new Set();
3457
+ if (!event.kind.trim()) {
3458
+ diagnostics.push(error("validate.event.kind.required", `Event "${event.id}" is missing a "kind" value.`, void 0, `${fieldPrefix}.kind`));
3459
+ }
3460
+ if (!event.targetObjectId && event.participantObjectIds.length === 0) {
3461
+ diagnostics.push(error("validate.event.references.required", `Event "${event.id}" must define a "target" or at least one participant.`, void 0, `${fieldPrefix}.participants`));
3462
+ }
3463
+ if (event.targetObjectId) {
3464
+ referencedIds.add(event.targetObjectId);
3465
+ if (!objectMap.has(event.targetObjectId)) {
3466
+ diagnostics.push(error("validate.event.target.unknown", `Unknown event target "${event.targetObjectId}" on "${event.id}".`, void 0, `${fieldPrefix}.target`));
3467
+ }
3468
+ }
3469
+ const seenParticipants = /* @__PURE__ */ new Set();
3470
+ for (const participantId of event.participantObjectIds) {
3471
+ referencedIds.add(participantId);
3472
+ if (seenParticipants.has(participantId)) {
3473
+ diagnostics.push(warn("validate.event.participants.duplicate", `Event "${event.id}" repeats participant "${participantId}".`, void 0, `${fieldPrefix}.participants`));
3474
+ continue;
3475
+ }
3476
+ seenParticipants.add(participantId);
3477
+ if (!objectMap.has(participantId)) {
3478
+ diagnostics.push(error("validate.event.participants.unknown", `Unknown event participant "${participantId}" on "${event.id}".`, void 0, `${fieldPrefix}.participants`));
3479
+ }
3480
+ }
3481
+ if (event.targetObjectId && event.participantObjectIds.length > 0 && !event.participantObjectIds.includes(event.targetObjectId)) {
3482
+ diagnostics.push(warn("validate.event.target.notParticipant", `Event "${event.id}" defines a target outside its participants list.`, void 0, `${fieldPrefix}.target`));
3483
+ }
3484
+ if (event.positions.length === 0) {
3485
+ diagnostics.push(warn("validate.event.positions.missing", `Event "${event.id}" has no positions block and cannot drive a scene snapshot.`, void 0, `${fieldPrefix}.positions`));
3486
+ }
3487
+ if (/(?:^|[-_])(solar-eclipse|lunar-eclipse|transit|occultation)(?:$|[-_])/.test(event.kind) && referencedIds.size < 3) {
3488
+ diagnostics.push(warn("validate.event.kind.participants", `Event "${event.id}" looks like an eclipse or transit but references fewer than three bodies.`, void 0, `${fieldPrefix}.participants`));
3489
+ }
3490
+ const poseIds = /* @__PURE__ */ new Set();
3491
+ for (const pose of event.positions) {
3492
+ const poseFieldPrefix = `${fieldPrefix}.pose.${pose.objectId}`;
3493
+ if (poseIds.has(pose.objectId)) {
3494
+ diagnostics.push(error("validate.event.pose.duplicate", `Event "${event.id}" defines "${pose.objectId}" more than once in positions.`, void 0, poseFieldPrefix));
3495
+ continue;
3496
+ }
3497
+ poseIds.add(pose.objectId);
3498
+ const object = objectMap.get(pose.objectId);
3499
+ if (!object) {
3500
+ diagnostics.push(error("validate.event.pose.object.unknown", `Unknown event pose object "${pose.objectId}" on "${event.id}".`, void 0, poseFieldPrefix));
3501
+ continue;
3502
+ }
3503
+ if (!referencedIds.has(pose.objectId)) {
3504
+ diagnostics.push(warn("validate.event.pose.unreferenced", `Event pose "${pose.objectId}" on "${event.id}" is not listed in target/participants.`, void 0, poseFieldPrefix));
3505
+ }
3506
+ validateEventPose(pose, object, objectMap, diagnostics, poseFieldPrefix, event.id);
3507
+ }
3508
+ }
3509
+ function validateEventPose(pose, object, objectMap, diagnostics, fieldPrefix, eventId) {
3510
+ const placement = pose.placement;
3511
+ if (!placement) {
3512
+ diagnostics.push(error("validate.event.pose.placement.required", `Event "${eventId}" pose "${pose.objectId}" is missing a placement mode.`, void 0, fieldPrefix));
3513
+ return;
3514
+ }
3515
+ if (placement.mode === "orbit") {
3516
+ if (!objectMap.has(placement.target)) {
3517
+ diagnostics.push(error("validate.event.pose.orbit.target.unknown", `Unknown event orbit target "${placement.target}" on "${eventId}:${pose.objectId}".`, void 0, `${fieldPrefix}.orbit`));
3518
+ }
3519
+ if (placement.distance && placement.semiMajor) {
3520
+ diagnostics.push(error("validate.event.pose.orbit.distanceConflict", `Event "${eventId}" pose "${pose.objectId}" cannot declare both "distance" and "semiMajor".`, void 0, `${fieldPrefix}.distance`));
3521
+ }
3522
+ return;
3523
+ }
3524
+ if (placement.mode === "surface") {
3525
+ const target = objectMap.get(placement.target);
3526
+ if (!target) {
3527
+ diagnostics.push(error("validate.event.pose.surface.target.unknown", `Unknown event surface target "${placement.target}" on "${eventId}:${pose.objectId}".`, void 0, `${fieldPrefix}.surface`));
3528
+ } else if (!SURFACE_TARGET_TYPES2.has(target.type)) {
3529
+ diagnostics.push(error("validate.event.pose.surface.target.invalid", `Event surface target "${placement.target}" on "${eventId}:${pose.objectId}" is not surface-capable.`, void 0, `${fieldPrefix}.surface`));
3530
+ }
3531
+ return;
3532
+ }
3533
+ if (placement.mode === "at") {
3534
+ if (object.type !== "structure" && object.type !== "phenomenon") {
3535
+ diagnostics.push(error("validate.event.pose.at.objectType", `Only structures and phenomena may use "at" placement in events; found "${object.type}" on "${eventId}:${pose.objectId}".`, void 0, `${fieldPrefix}.at`));
3536
+ }
3537
+ const reference = placement.reference;
3538
+ if (reference.kind === "named" && !objectMap.has(reference.name)) {
3539
+ diagnostics.push(error("validate.event.pose.at.target.unknown", `Unknown event at-reference target "${placement.target}" on "${eventId}:${pose.objectId}".`, void 0, `${fieldPrefix}.at`));
3540
+ } else if (reference.kind === "anchor" && !objectMap.has(reference.objectId)) {
3541
+ diagnostics.push(error("validate.event.pose.anchor.target.unknown", `Unknown event anchor target "${reference.objectId}" on "${eventId}:${pose.objectId}".`, void 0, `${fieldPrefix}.at`));
3542
+ } else if (reference.kind === "lagrange") {
3543
+ if (!objectMap.has(reference.primary)) {
3544
+ diagnostics.push(error("validate.event.pose.lagrange.primary.unknown", `Unknown event Lagrange target "${reference.primary}" on "${eventId}:${pose.objectId}".`, void 0, `${fieldPrefix}.at`));
3545
+ } else if (reference.secondary && !objectMap.has(reference.secondary)) {
3546
+ diagnostics.push(error("validate.event.pose.lagrange.secondary.unknown", `Unknown event Lagrange target "${reference.secondary}" on "${eventId}:${pose.objectId}".`, void 0, `${fieldPrefix}.at`));
3547
+ }
3548
+ }
3549
+ }
3550
+ }
3208
3551
  function validateAtTarget(object, objectMap, diagnostics) {
3209
3552
  const reference = object.placement?.mode === "at" ? object.placement.reference : null;
3210
3553
  if (!reference) {
@@ -3405,6 +3748,21 @@ var WorldOrbit = (() => {
3405
3748
  });
3406
3749
  }
3407
3750
  var DRAFT_OBJECT_FIELD_KEYS = new Set(DRAFT_OBJECT_FIELD_SPECS.keys());
3751
+ var EVENT_POSE_FIELD_KEYS = /* @__PURE__ */ new Set([
3752
+ "orbit",
3753
+ "distance",
3754
+ "semiMajor",
3755
+ "eccentricity",
3756
+ "period",
3757
+ "angle",
3758
+ "inclination",
3759
+ "phase",
3760
+ "at",
3761
+ "surface",
3762
+ "free",
3763
+ "inner",
3764
+ "outer"
3765
+ ]);
3408
3766
  function parseWorldOrbitAtlas(source) {
3409
3767
  return parseAtlasSource(source);
3410
3768
  }
@@ -3419,12 +3777,15 @@ var WorldOrbit = (() => {
3419
3777
  const objectNodes = [];
3420
3778
  const groups = [];
3421
3779
  const relations = [];
3780
+ const events = [];
3781
+ const eventPoseNodes = /* @__PURE__ */ new Map();
3422
3782
  let sawDefaults = false;
3423
3783
  let sawAtlas = false;
3424
3784
  const viewpointIds = /* @__PURE__ */ new Set();
3425
3785
  const annotationIds = /* @__PURE__ */ new Set();
3426
3786
  const groupIds = /* @__PURE__ */ new Set();
3427
3787
  const relationIds = /* @__PURE__ */ new Set();
3788
+ const eventIds = /* @__PURE__ */ new Set();
3428
3789
  for (let index = 0; index < lines.length; index++) {
3429
3790
  const rawLine = lines[index];
3430
3791
  const lineNumber = index + 1;
@@ -3455,7 +3816,7 @@ var WorldOrbit = (() => {
3455
3816
  continue;
3456
3817
  }
3457
3818
  if (indent === 0) {
3458
- section = startTopLevelSection(tokens, lineNumber, sourceSchemaVersion, diagnostics, system, objectNodes, groups, relations, viewpointIds, annotationIds, groupIds, relationIds, { sawDefaults, sawAtlas });
3819
+ section = startTopLevelSection(tokens, lineNumber, sourceSchemaVersion, diagnostics, system, objectNodes, groups, relations, events, eventPoseNodes, viewpointIds, annotationIds, groupIds, relationIds, eventIds, { sawDefaults, sawAtlas });
3459
3820
  if (section.kind === "system") {
3460
3821
  system = section.system;
3461
3822
  } else if (section.kind === "defaults") {
@@ -3474,6 +3835,7 @@ var WorldOrbit = (() => {
3474
3835
  throw new WorldOrbitError('Missing required atlas schema header "schema 2.0"');
3475
3836
  }
3476
3837
  const objects = objectNodes.map((node) => normalizeDraftObject(node, sourceSchemaVersion, diagnostics));
3838
+ const normalizedEvents = events.map((event) => normalizeDraftEvent(event, eventPoseNodes.get(event.id) ?? []));
3477
3839
  const outputVersion = forcedOutputVersion ?? (sourceSchemaVersion === "2.0-draft" ? "2.0" : sourceSchemaVersion);
3478
3840
  const baseDocument = {
3479
3841
  format: "worldorbit",
@@ -3481,6 +3843,7 @@ var WorldOrbit = (() => {
3481
3843
  system,
3482
3844
  groups,
3483
3845
  relations,
3846
+ events: normalizedEvents,
3484
3847
  objects,
3485
3848
  diagnostics
3486
3849
  };
@@ -3516,7 +3879,7 @@ var WorldOrbit = (() => {
3516
3879
  const version = tokens[1].value.toLowerCase();
3517
3880
  return version === "2.1" ? "2.1" : version === "2.0-draft" ? "2.0-draft" : "2.0";
3518
3881
  }
3519
- function startTopLevelSection(tokens, line, sourceSchemaVersion, diagnostics, system, objectNodes, groups, relations, viewpointIds, annotationIds, groupIds, relationIds, flags) {
3882
+ function startTopLevelSection(tokens, line, sourceSchemaVersion, diagnostics, system, objectNodes, groups, relations, events, eventPoseNodes, viewpointIds, annotationIds, groupIds, relationIds, eventIds, flags) {
3520
3883
  const keyword = tokens[0]?.value.toLowerCase();
3521
3884
  switch (keyword) {
3522
3885
  case "system":
@@ -3553,7 +3916,7 @@ var WorldOrbit = (() => {
3553
3916
  if (!system) {
3554
3917
  throw new WorldOrbitError('Atlas section "viewpoint" requires a preceding system declaration', line, tokens[0].column);
3555
3918
  }
3556
- return startViewpointSection(tokens, line, system, viewpointIds);
3919
+ return startViewpointSection(tokens, line, system, viewpointIds, sourceSchemaVersion, diagnostics);
3557
3920
  case "annotation":
3558
3921
  if (!system) {
3559
3922
  throw new WorldOrbitError('Atlas section "annotation" requires a preceding system declaration', line, tokens[0].column);
@@ -3565,6 +3928,9 @@ var WorldOrbit = (() => {
3565
3928
  case "relation":
3566
3929
  warnIfSchema21Feature(sourceSchemaVersion, diagnostics, "relation", { line, column: tokens[0].column });
3567
3930
  return startRelationSection(tokens, line, relations, relationIds);
3931
+ case "event":
3932
+ warnIfSchema21Feature(sourceSchemaVersion, diagnostics, "event", { line, column: tokens[0].column });
3933
+ return startEventSection(tokens, line, events, eventPoseNodes, eventIds, sourceSchemaVersion, diagnostics);
3568
3934
  case "object":
3569
3935
  return startObjectSection(tokens, line, sourceSchemaVersion, diagnostics, objectNodes);
3570
3936
  default:
@@ -3601,7 +3967,7 @@ var WorldOrbit = (() => {
3601
3967
  seenFields: /* @__PURE__ */ new Set()
3602
3968
  };
3603
3969
  }
3604
- function startViewpointSection(tokens, line, system, viewpointIds) {
3970
+ function startViewpointSection(tokens, line, system, viewpointIds, sourceSchemaVersion, diagnostics) {
3605
3971
  if (tokens.length !== 2) {
3606
3972
  throw new WorldOrbitError("Invalid viewpoint declaration", line, tokens[0]?.column ?? 1);
3607
3973
  }
@@ -3618,6 +3984,7 @@ var WorldOrbit = (() => {
3618
3984
  summary: "",
3619
3985
  focusObjectId: null,
3620
3986
  selectedObjectId: null,
3987
+ events: [],
3621
3988
  projection: system.defaults.view,
3622
3989
  preset: system.defaults.preset,
3623
3990
  zoom: null,
@@ -3630,6 +3997,8 @@ var WorldOrbit = (() => {
3630
3997
  return {
3631
3998
  kind: "viewpoint",
3632
3999
  viewpoint,
4000
+ sourceSchemaVersion,
4001
+ diagnostics,
3633
4002
  seenFields: /* @__PURE__ */ new Set(),
3634
4003
  inFilter: false,
3635
4004
  filterIndent: null,
@@ -3720,6 +4089,49 @@ var WorldOrbit = (() => {
3720
4089
  seenFields: /* @__PURE__ */ new Set()
3721
4090
  };
3722
4091
  }
4092
+ function startEventSection(tokens, line, events, eventPoseNodes, eventIds, sourceSchemaVersion, diagnostics) {
4093
+ if (tokens.length !== 2) {
4094
+ throw new WorldOrbitError("Invalid event declaration", line, tokens[0]?.column ?? 1);
4095
+ }
4096
+ const id = normalizeIdentifier(tokens[1].value);
4097
+ if (!id) {
4098
+ throw new WorldOrbitError("Event id must not be empty", line, tokens[1].column);
4099
+ }
4100
+ if (eventIds.has(id)) {
4101
+ throw new WorldOrbitError(`Duplicate event id "${id}"`, line, tokens[1].column);
4102
+ }
4103
+ const event = {
4104
+ id,
4105
+ kind: "",
4106
+ label: humanizeIdentifier2(id),
4107
+ summary: null,
4108
+ targetObjectId: null,
4109
+ participantObjectIds: [],
4110
+ timing: null,
4111
+ visibility: null,
4112
+ tags: [],
4113
+ color: null,
4114
+ hidden: false,
4115
+ positions: []
4116
+ };
4117
+ const rawPoses = [];
4118
+ events.push(event);
4119
+ eventPoseNodes.set(id, rawPoses);
4120
+ eventIds.add(id);
4121
+ return {
4122
+ kind: "event",
4123
+ event,
4124
+ sourceSchemaVersion,
4125
+ diagnostics,
4126
+ seenFields: /* @__PURE__ */ new Set(),
4127
+ rawPoses,
4128
+ inPositions: false,
4129
+ positionsIndent: null,
4130
+ activePose: null,
4131
+ poseIndent: null,
4132
+ activePoseSeenFields: /* @__PURE__ */ new Set()
4133
+ };
4134
+ }
3723
4135
  function startObjectSection(tokens, line, sourceSchemaVersion, diagnostics, objectNodes) {
3724
4136
  if (tokens.length < 3) {
3725
4137
  throw new WorldOrbitError("Invalid atlas object declaration", line, tokens[0]?.column ?? 1);
@@ -3776,6 +4188,9 @@ var WorldOrbit = (() => {
3776
4188
  case "relation":
3777
4189
  applyRelationField(section, tokens, line);
3778
4190
  return;
4191
+ case "event":
4192
+ applyEventField(section, indent, tokens, line);
4193
+ return;
3779
4194
  case "object":
3780
4195
  applyObjectField(section, indent, tokens, line);
3781
4196
  return;
@@ -3902,7 +4317,14 @@ var WorldOrbit = (() => {
3902
4317
  section.viewpoint.rotationDeg = parseFiniteNumber2(value, line, tokens[0].column, "rotation");
3903
4318
  return;
3904
4319
  case "layers":
3905
- section.viewpoint.layers = parseLayerTokens(tokens.slice(1), line);
4320
+ section.viewpoint.layers = parseLayerTokens(tokens.slice(1), line, section.sourceSchemaVersion, section.diagnostics);
4321
+ return;
4322
+ case "events":
4323
+ warnIfSchema21Feature(section.sourceSchemaVersion, section.diagnostics, "viewpoint.events", {
4324
+ line,
4325
+ column: tokens[0].column
4326
+ });
4327
+ section.viewpoint.events = parseTokenList(tokens.slice(1), line, "events");
3906
4328
  return;
3907
4329
  default:
3908
4330
  throw new WorldOrbitError(`Unknown viewpoint field "${tokens[0].value}"`, line, tokens[0].column);
@@ -4007,6 +4429,106 @@ var WorldOrbit = (() => {
4007
4429
  throw new WorldOrbitError(`Unknown relation field "${tokens[0].value}"`, line, tokens[0].column);
4008
4430
  }
4009
4431
  }
4432
+ function applyEventField(section, indent, tokens, line) {
4433
+ if (section.activePose && indent <= (section.poseIndent ?? 0)) {
4434
+ section.activePose = null;
4435
+ section.poseIndent = null;
4436
+ section.activePoseSeenFields.clear();
4437
+ }
4438
+ if (!section.activePose && section.inPositions && indent <= (section.positionsIndent ?? 0)) {
4439
+ section.inPositions = false;
4440
+ section.positionsIndent = null;
4441
+ }
4442
+ if (section.activePose) {
4443
+ section.activePose.fields.push(parseEventPoseField(tokens, line, section.activePoseSeenFields));
4444
+ return;
4445
+ }
4446
+ if (section.inPositions) {
4447
+ if (tokens.length !== 2 || tokens[0].value.toLowerCase() !== "pose") {
4448
+ throw new WorldOrbitError(`Unknown event positions field "${tokens[0].value}"`, line, tokens[0]?.column ?? 1);
4449
+ }
4450
+ const objectId = tokens[1].value;
4451
+ if (!objectId.trim()) {
4452
+ throw new WorldOrbitError("Event pose object id must not be empty", line, tokens[1].column);
4453
+ }
4454
+ const rawPose = {
4455
+ objectId,
4456
+ fields: [],
4457
+ location: { line, column: tokens[0].column }
4458
+ };
4459
+ section.rawPoses.push(rawPose);
4460
+ section.activePose = rawPose;
4461
+ section.poseIndent = indent;
4462
+ section.activePoseSeenFields = /* @__PURE__ */ new Set();
4463
+ return;
4464
+ }
4465
+ if (tokens.length === 1 && tokens[0].value.toLowerCase() === "positions") {
4466
+ if (section.seenFields.has("positions")) {
4467
+ throw new WorldOrbitError('Duplicate event field "positions"', line, tokens[0].column);
4468
+ }
4469
+ section.seenFields.add("positions");
4470
+ section.inPositions = true;
4471
+ section.positionsIndent = indent;
4472
+ return;
4473
+ }
4474
+ const key = requireUniqueField(tokens, section.seenFields, line);
4475
+ switch (key) {
4476
+ case "kind":
4477
+ section.event.kind = joinFieldValue(tokens, line);
4478
+ return;
4479
+ case "label":
4480
+ section.event.label = joinFieldValue(tokens, line);
4481
+ return;
4482
+ case "summary":
4483
+ section.event.summary = joinFieldValue(tokens, line);
4484
+ return;
4485
+ case "target":
4486
+ section.event.targetObjectId = joinFieldValue(tokens, line);
4487
+ return;
4488
+ case "participants":
4489
+ section.event.participantObjectIds = parseTokenList(tokens.slice(1), line, "participants");
4490
+ return;
4491
+ case "timing":
4492
+ section.event.timing = joinFieldValue(tokens, line);
4493
+ return;
4494
+ case "visibility":
4495
+ section.event.visibility = joinFieldValue(tokens, line);
4496
+ return;
4497
+ case "tags":
4498
+ section.event.tags = parseTokenList(tokens.slice(1), line, "tags");
4499
+ return;
4500
+ case "color":
4501
+ section.event.color = joinFieldValue(tokens, line);
4502
+ return;
4503
+ case "hidden":
4504
+ section.event.hidden = parseAtlasBoolean(joinFieldValue(tokens, line), "hidden", {
4505
+ line,
4506
+ column: tokens[0].column
4507
+ });
4508
+ return;
4509
+ default:
4510
+ throw new WorldOrbitError(`Unknown event field "${tokens[0].value}"`, line, tokens[0].column);
4511
+ }
4512
+ }
4513
+ function parseEventPoseField(tokens, line, seenFields) {
4514
+ if (tokens.length < 2) {
4515
+ throw new WorldOrbitError("Invalid event pose field line", line, tokens[0]?.column ?? 1);
4516
+ }
4517
+ const key = tokens[0].value;
4518
+ if (!EVENT_POSE_FIELD_KEYS.has(key)) {
4519
+ throw new WorldOrbitError(`Unknown event pose field "${key}"`, line, tokens[0].column);
4520
+ }
4521
+ if (seenFields.has(key)) {
4522
+ throw new WorldOrbitError(`Duplicate event pose field "${key}"`, line, tokens[0].column);
4523
+ }
4524
+ seenFields.add(key);
4525
+ return {
4526
+ type: "field",
4527
+ key,
4528
+ values: tokens.slice(1).map((token) => token.value),
4529
+ location: { line, column: tokens[0].column }
4530
+ };
4531
+ }
4010
4532
  function applyObjectField(section, indent, tokens, line) {
4011
4533
  if (section.activeBlock && indent <= (section.blockIndent ?? 0)) {
4012
4534
  section.activeBlock = null;
@@ -4065,7 +4587,7 @@ var WorldOrbit = (() => {
4065
4587
  function parseObjectTypeTokens(tokens, line) {
4066
4588
  return parseTokenList(tokens, line, "objectTypes").filter((value) => value === "star" || value === "planet" || value === "moon" || value === "belt" || value === "asteroid" || value === "comet" || value === "ring" || value === "structure" || value === "phenomenon");
4067
4589
  }
4068
- function parseLayerTokens(tokens, line) {
4590
+ function parseLayerTokens(tokens, line, sourceSchemaVersion, diagnostics) {
4069
4591
  const layers = {};
4070
4592
  for (const token of parseTokenList(tokens, line, "layers")) {
4071
4593
  const enabled = !token.startsWith("-") && !token.startsWith("!");
@@ -4075,7 +4597,13 @@ var WorldOrbit = (() => {
4075
4597
  layers["orbits-front"] = enabled;
4076
4598
  continue;
4077
4599
  }
4078
- if (raw === "background" || raw === "guides" || raw === "orbits-back" || raw === "orbits-front" || raw === "relations" || raw === "objects" || raw === "labels" || raw === "metadata") {
4600
+ if (raw === "background" || raw === "guides" || raw === "orbits-back" || raw === "orbits-front" || raw === "relations" || raw === "events" || raw === "objects" || raw === "labels" || raw === "metadata") {
4601
+ if (raw === "events" && sourceSchemaVersion && diagnostics) {
4602
+ warnIfSchema21Feature(sourceSchemaVersion, diagnostics, "layers.events", {
4603
+ line,
4604
+ column: tokens[0]?.column ?? 1
4605
+ });
4606
+ }
4079
4607
  layers[raw] = enabled;
4080
4608
  }
4081
4609
  }
@@ -4214,7 +4742,7 @@ var WorldOrbit = (() => {
4214
4742
  }
4215
4743
  function normalizeDraftObject(node, sourceSchemaVersion, diagnostics) {
4216
4744
  const fieldMap = collectDraftFields(node.fields);
4217
- const placement = extractDraftPlacement(node.objectType, fieldMap);
4745
+ const placement = extractPlacementFromFieldMap(fieldMap);
4218
4746
  const properties = normalizeDraftProperties(node.objectType, fieldMap);
4219
4747
  const groups = parseOptionalTokenList(fieldMap.get("groups")?.[0]);
4220
4748
  const epoch = parseOptionalJoinedValue(fieldMap.get("epoch")?.[0]);
@@ -4266,6 +4794,24 @@ var WorldOrbit = (() => {
4266
4794
  }
4267
4795
  return object;
4268
4796
  }
4797
+ function normalizeDraftEvent(event, rawPoses) {
4798
+ return {
4799
+ ...event,
4800
+ participantObjectIds: [...new Set(event.participantObjectIds)],
4801
+ tags: [...new Set(event.tags)],
4802
+ positions: rawPoses.map((pose) => normalizeDraftEventPose(pose))
4803
+ };
4804
+ }
4805
+ function normalizeDraftEventPose(rawPose) {
4806
+ const fieldMap = collectDraftFields(rawPose.fields);
4807
+ const placement = extractPlacementFromFieldMap(fieldMap);
4808
+ return {
4809
+ objectId: rawPose.objectId,
4810
+ placement,
4811
+ inner: parseOptionalUnitField(fieldMap.get("inner")?.[0], "inner"),
4812
+ outer: parseOptionalUnitField(fieldMap.get("outer")?.[0], "outer")
4813
+ };
4814
+ }
4269
4815
  function collectDraftFields(fields) {
4270
4816
  const grouped = /* @__PURE__ */ new Map();
4271
4817
  for (const field of fields) {
@@ -4282,7 +4828,7 @@ var WorldOrbit = (() => {
4282
4828
  }
4283
4829
  return grouped;
4284
4830
  }
4285
- function extractDraftPlacement(objectType, fieldMap) {
4831
+ function extractPlacementFromFieldMap(fieldMap) {
4286
4832
  const orbitField = fieldMap.get("orbit")?.[0];
4287
4833
  const atField = fieldMap.get("at")?.[0];
4288
4834
  const surfaceField = fieldMap.get("surface")?.[0];
@@ -4893,6 +5439,7 @@ var WorldOrbit = (() => {
4893
5439
  const orbitMarkup = layers.orbits ? renderOrbitLayer(scene, visibleObjectIds, layers.structures) : { back: "", front: "" };
4894
5440
  const leaderMarkup = layers.guides ? scene.leaders.filter((leader) => !leader.hidden).filter((leader) => visibleObjectIds.has(leader.objectId)).filter((leader) => layers.structures || !isStructureLike(leader.object)).map((leader) => `<line class="wo-leader wo-leader-${leader.mode}" x1="${leader.x1}" y1="${leader.y1}" x2="${leader.x2}" y2="${leader.y2}" data-render-id="${escapeXml(leader.renderId)}" data-group-id="${escapeAttribute(leader.groupId ?? "")}" />`).join("") : "";
4895
5441
  const relationMarkup = layers.relations ? scene.relations.filter((relation) => !relation.hidden).filter((relation) => visibleObjectIds.has(relation.fromObjectId) && visibleObjectIds.has(relation.toObjectId)).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)}" />`).join("") : "";
5442
+ const eventMarkup = layers.events ? scene.events.filter((event) => !event.hidden).map((event) => renderSceneEventOverlay(scene, event, visibleObjectIds, theme)).join("") : "";
4896
5443
  const objectMarkup = layers.objects ? visibleObjects.map((object) => renderSceneObject(object, options.selectedObjectId ?? null, theme)).join("") : "";
4897
5444
  const labelMarkup = layers.labels ? visibleLabels.map((label) => renderSceneLabel(scene, label, options.selectedObjectId ?? null)).join("") : "";
4898
5445
  const metadataMarkup = layers.metadata ? `<text class="wo-title" x="56" y="64">${escapeXml(scene.title)}</text>
@@ -4928,6 +5475,9 @@ var WorldOrbit = (() => {
4928
5475
  .wo-orbit-front { opacity: 0.9; }
4929
5476
  .wo-orbit-band { stroke: ${theme.orbitBand}; stroke-linecap: round; }
4930
5477
  .wo-relation { stroke: ${theme.relation}; stroke-width: 2; stroke-dasharray: 10 6; }
5478
+ .wo-event-line { stroke: ${theme.accent}; stroke-width: 1.6; stroke-dasharray: 5 5; opacity: 0.72; }
5479
+ .wo-event-node { fill: ${theme.accent}; stroke: ${theme.selected}; stroke-width: 1.4; opacity: 0.92; }
5480
+ .wo-event-label { fill: ${theme.accent}; font-family: ${theme.fontFamily}; font-weight: 700; letter-spacing: 0.04em; text-transform: uppercase; }
4931
5481
  .wo-leader { stroke: ${theme.leader}; stroke-width: 1.5; stroke-dasharray: 6 5; }
4932
5482
  .wo-label { fill: ${theme.ink}; font-family: ${theme.fontFamily}; font-weight: 600; letter-spacing: 0.02em; }
4933
5483
  .wo-label-secondary { fill: ${theme.muted}; font-family: ${theme.fontFamily}; font-weight: 500; }
@@ -4962,6 +5512,7 @@ var WorldOrbit = (() => {
4962
5512
  ${layers.orbits ? `<g data-layer-id="orbits-back">${orbitMarkup.back}</g>` : ""}
4963
5513
  ${layers.guides ? `<g data-layer-id="guides">${leaderMarkup}</g>` : ""}
4964
5514
  ${layers.relations ? `<g data-layer-id="relations">${relationMarkup}</g>` : ""}
5515
+ ${layers.events ? `<g data-layer-id="events">${eventMarkup}</g>` : ""}
4965
5516
  ${layers.objects ? `<g data-layer-id="objects">${objectMarkup}</g>` : ""}
4966
5517
  ${layers.orbits ? `<g data-layer-id="orbits-front">${orbitMarkup.front}</g>` : ""}
4967
5518
  ${layers.labels ? `<g data-layer-id="labels">${labelMarkup}</g>` : ""}
@@ -4969,6 +5520,20 @@ var WorldOrbit = (() => {
4969
5520
  </g>
4970
5521
  </g>
4971
5522
  </svg>`;
5523
+ }
5524
+ function renderSceneEventOverlay(scene, event, visibleObjectIds, theme) {
5525
+ const participants = event.objectIds.filter((objectId) => visibleObjectIds.has(objectId)).map((objectId) => scene.objects.find((object) => object.objectId === objectId && !object.hidden)).filter(Boolean);
5526
+ if (participants.length === 0) {
5527
+ return "";
5528
+ }
5529
+ const stroke = event.event.color || theme.accent;
5530
+ const label = event.event.label || event.event.id;
5531
+ const lineMarkup = participants.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)}" />`).join("");
5532
+ return `<g class="wo-event" data-render-id="${escapeXml(event.renderId)}" data-event-id="${escapeAttribute(event.eventId)}">
5533
+ ${lineMarkup}
5534
+ <circle class="wo-event-node" cx="${event.x}" cy="${event.y}" r="5" fill="${escapeAttribute(stroke)}" />
5535
+ <text class="wo-event-label" x="${event.x}" y="${event.y - 10}" text-anchor="middle" font-size="10">${escapeXml(label)}</text>
5536
+ </g>`;
4972
5537
  }
4973
5538
  function renderDocumentToSvg(document2, options = {}) {
4974
5539
  return renderSceneToSvg(renderDocumentToScene(document2, options), options);
@@ -5568,6 +6133,13 @@ var WorldOrbit = (() => {
5568
6133
  value: `${details.object.resonance.targetObjectId} ${details.object.resonance.ratio}`
5569
6134
  });
5570
6135
  }
6136
+ if (details.relatedEvents.length > 0) {
6137
+ fields.set("events", {
6138
+ key: "events",
6139
+ label: "Events",
6140
+ value: details.relatedEvents.map((event) => event.event.label || event.event.id).join(", ")
6141
+ });
6142
+ }
5571
6143
  if (placement?.mode === "at") {
5572
6144
  fields.set("placement", {
5573
6145
  key: "placement",
@@ -5982,6 +6554,12 @@ var WorldOrbit = (() => {
5982
6554
  emitAtlasStateChange();
5983
6555
  return true;
5984
6556
  },
6557
+ getActiveEventId() {
6558
+ return renderOptions.activeEventId ?? null;
6559
+ },
6560
+ setActiveEvent(id) {
6561
+ api.setRenderOptions({ activeEventId: id });
6562
+ },
5985
6563
  search(query, limit = 12) {
5986
6564
  return searchSceneObjects(scene, query, limit);
5987
6565
  },
@@ -6246,6 +6824,7 @@ var WorldOrbit = (() => {
6246
6824
  orbit: scene.orbitVisuals.find((orbit) => orbit.objectId === renderObject.objectId && !orbit.hidden) ?? null,
6247
6825
  relatedOrbits: scene.orbitVisuals.filter((orbit) => !orbit.hidden && (orbit.objectId === renderObject.objectId || renderObject.ancestorIds.includes(orbit.objectId) || renderObject.childIds.includes(orbit.objectId))),
6248
6826
  relations: scene.relations.filter((relation) => !relation.hidden && (relation.fromObjectId === renderObject.objectId || relation.toObjectId === renderObject.objectId)),
6827
+ relatedEvents: scene.events.filter((event) => !event.hidden && (event.targetObjectId === renderObject.objectId || event.objectIds.includes(renderObject.objectId))),
6249
6828
  parent: getObjectById(renderObject.parentId),
6250
6829
  children: renderObject.childIds.map((childId) => getObjectById(childId)).filter(Boolean),
6251
6830
  ancestors: renderObject.ancestorIds.map((ancestorId) => getObjectById(ancestorId)).filter(Boolean),
@@ -6562,7 +7141,8 @@ var WorldOrbit = (() => {
6562
7141
  filter: renderOptions.filter ? { ...renderOptions.filter } : void 0,
6563
7142
  scaleModel: renderOptions.scaleModel ? { ...renderOptions.scaleModel } : void 0,
6564
7143
  layers: renderOptions.layers ? { ...renderOptions.layers } : void 0,
6565
- theme: renderOptions.theme && typeof renderOptions.theme === "object" ? { ...renderOptions.theme } : renderOptions.theme
7144
+ theme: renderOptions.theme && typeof renderOptions.theme === "object" ? { ...renderOptions.theme } : renderOptions.theme,
7145
+ activeEventId: renderOptions.activeEventId ?? null
6566
7146
  };
6567
7147
  }
6568
7148
  function mergeRenderOptions(current, next) {
@@ -6582,7 +7162,7 @@ var WorldOrbit = (() => {
6582
7162
  };
6583
7163
  }
6584
7164
  function hasSceneAffectingRenderOptions(options) {
6585
- return options.width !== void 0 || options.height !== void 0 || options.padding !== void 0 || options.preset !== void 0 || options.projection !== void 0 || options.scaleModel !== void 0;
7165
+ return options.width !== void 0 || options.height !== void 0 || options.padding !== void 0 || options.preset !== void 0 || options.projection !== void 0 || options.scaleModel !== void 0 || options.activeEventId !== void 0;
6586
7166
  }
6587
7167
  function resolveSourceRenderOptions2(loaded, renderOptions) {
6588
7168
  const atlasDocument = loaded.atlasDocument ?? loaded.draftDocument;
@@ -7192,6 +7772,7 @@ var WorldOrbit = (() => {
7192
7772
  groupCount: activeViewer.getScene().groups.length,
7193
7773
  semanticGroupCount: activeViewer.getScene().semanticGroups.length,
7194
7774
  relationCount: activeViewer.getScene().relations.length,
7775
+ eventCount: activeViewer.getScene().events.length,
7195
7776
  viewpointCount: activeViewer.getScene().viewpoints.length
7196
7777
  }
7197
7778
  };