worldorbit 2.5.17 → 3.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 (203) hide show
  1. package/README.md +91 -18
  2. package/dist/browser/core/dist/atlas-edit.d.ts +11 -0
  3. package/dist/browser/core/dist/atlas-edit.js +347 -0
  4. package/dist/browser/core/dist/atlas-utils.d.ts +22 -0
  5. package/dist/browser/core/dist/atlas-utils.js +189 -0
  6. package/dist/browser/core/dist/atlas-validate.d.ts +2 -0
  7. package/dist/browser/core/dist/atlas-validate.js +488 -0
  8. package/dist/browser/core/dist/diagnostics.d.ts +10 -0
  9. package/dist/browser/core/dist/diagnostics.js +109 -0
  10. package/dist/browser/core/dist/draft-parse.d.ts +3 -0
  11. package/dist/browser/core/dist/draft-parse.js +1654 -0
  12. package/dist/browser/core/dist/draft.d.ts +21 -0
  13. package/dist/browser/core/dist/draft.js +482 -0
  14. package/dist/browser/core/dist/errors.d.ts +7 -0
  15. package/dist/browser/core/dist/errors.js +16 -0
  16. package/dist/browser/core/dist/format.d.ts +4 -0
  17. package/dist/browser/core/dist/format.js +613 -0
  18. package/dist/browser/core/dist/index.d.ts +29 -0
  19. package/dist/browser/core/dist/index.js +35 -6101
  20. package/dist/browser/core/dist/load.d.ts +4 -0
  21. package/dist/browser/core/dist/load.js +182 -0
  22. package/dist/browser/core/dist/markdown.d.ts +2 -0
  23. package/dist/browser/core/dist/markdown.js +37 -0
  24. package/dist/browser/core/dist/normalize.d.ts +2 -0
  25. package/dist/browser/core/dist/normalize.js +312 -0
  26. package/dist/browser/core/dist/parse.d.ts +2 -0
  27. package/dist/browser/core/dist/parse.js +133 -0
  28. package/dist/browser/core/dist/scene.d.ts +3 -0
  29. package/dist/browser/core/dist/scene.js +1901 -0
  30. package/dist/browser/core/dist/schema.d.ts +8 -0
  31. package/dist/browser/core/dist/schema.js +298 -0
  32. package/dist/browser/core/dist/spatial-scene.d.ts +3 -0
  33. package/dist/browser/core/dist/spatial-scene.js +420 -0
  34. package/dist/browser/core/dist/tokenize.d.ts +4 -0
  35. package/dist/browser/core/dist/tokenize.js +68 -0
  36. package/dist/browser/core/dist/types.d.ts +637 -0
  37. package/dist/browser/core/dist/types.js +1 -0
  38. package/dist/browser/core/dist/validate.d.ts +2 -0
  39. package/dist/browser/core/dist/validate.js +56 -0
  40. package/dist/browser/editor/dist/editor.d.ts +2 -0
  41. package/dist/browser/editor/dist/editor.js +3700 -0
  42. package/dist/browser/editor/dist/index.d.ts +2 -0
  43. package/dist/browser/editor/dist/index.js +1 -11702
  44. package/dist/browser/editor/dist/types.d.ts +59 -0
  45. package/dist/browser/editor/dist/types.js +1 -0
  46. package/dist/browser/markdown/dist/html.d.ts +3 -0
  47. package/dist/browser/markdown/dist/html.js +64 -0
  48. package/dist/browser/markdown/dist/index.d.ts +4 -0
  49. package/dist/browser/markdown/dist/index.js +3 -5766
  50. package/dist/browser/markdown/dist/rehype.d.ts +10 -0
  51. package/dist/browser/markdown/dist/rehype.js +49 -0
  52. package/dist/browser/markdown/dist/remark.d.ts +9 -0
  53. package/dist/browser/markdown/dist/remark.js +28 -0
  54. package/dist/browser/markdown/dist/types.d.ts +11 -0
  55. package/dist/browser/markdown/dist/types.js +1 -0
  56. package/dist/browser/viewer/dist/atlas-state.d.ts +12 -0
  57. package/dist/browser/viewer/dist/atlas-state.js +269 -0
  58. package/dist/browser/viewer/dist/atlas-viewer.d.ts +2 -0
  59. package/dist/browser/viewer/dist/atlas-viewer.js +495 -0
  60. package/dist/browser/viewer/dist/custom-element.d.ts +1 -0
  61. package/dist/browser/viewer/dist/custom-element.js +78 -0
  62. package/dist/browser/viewer/dist/embed.d.ts +24 -0
  63. package/dist/browser/viewer/dist/embed.js +172 -0
  64. package/dist/browser/viewer/dist/errors.d.ts +6 -0
  65. package/dist/browser/viewer/dist/errors.js +12 -0
  66. package/dist/browser/viewer/dist/index.d.ts +10 -0
  67. package/dist/browser/viewer/dist/index.js +9 -7901
  68. package/dist/browser/viewer/dist/minimap.d.ts +3 -0
  69. package/dist/browser/viewer/dist/minimap.js +63 -0
  70. package/dist/browser/viewer/dist/render.d.ts +6 -0
  71. package/dist/browser/viewer/dist/render.js +670 -0
  72. package/dist/browser/viewer/dist/runtime-3d.d.ts +19 -0
  73. package/dist/browser/viewer/dist/runtime-3d.js +494 -0
  74. package/dist/browser/viewer/dist/theme.d.ts +4 -0
  75. package/dist/browser/viewer/dist/theme.js +103 -0
  76. package/dist/browser/viewer/dist/tooltip.d.ts +3 -0
  77. package/dist/browser/viewer/dist/tooltip.js +198 -0
  78. package/dist/browser/viewer/dist/types.d.ts +292 -0
  79. package/dist/browser/viewer/dist/types.js +1 -0
  80. package/dist/browser/viewer/dist/vendor/three.module.js +53032 -0
  81. package/dist/browser/viewer/dist/viewer-state.d.ts +19 -0
  82. package/dist/browser/viewer/dist/viewer-state.js +162 -0
  83. package/dist/browser/viewer/dist/viewer.d.ts +2 -0
  84. package/dist/browser/viewer/dist/viewer.js +1662 -0
  85. package/dist/unpkg/core/dist/atlas-edit.d.ts +11 -0
  86. package/dist/unpkg/core/dist/atlas-edit.js +347 -0
  87. package/dist/unpkg/core/dist/atlas-utils.d.ts +22 -0
  88. package/dist/unpkg/core/dist/atlas-utils.js +189 -0
  89. package/dist/unpkg/core/dist/atlas-validate.d.ts +2 -0
  90. package/dist/unpkg/core/dist/atlas-validate.js +488 -0
  91. package/dist/unpkg/core/dist/diagnostics.d.ts +10 -0
  92. package/dist/unpkg/core/dist/diagnostics.js +109 -0
  93. package/dist/unpkg/core/dist/draft-parse.d.ts +3 -0
  94. package/dist/unpkg/core/dist/draft-parse.js +1654 -0
  95. package/dist/unpkg/core/dist/draft.d.ts +21 -0
  96. package/dist/unpkg/core/dist/draft.js +482 -0
  97. package/dist/unpkg/core/dist/errors.d.ts +7 -0
  98. package/dist/unpkg/core/dist/errors.js +16 -0
  99. package/dist/unpkg/core/dist/format.d.ts +4 -0
  100. package/dist/unpkg/core/dist/format.js +613 -0
  101. package/dist/unpkg/core/dist/index.d.ts +29 -0
  102. package/dist/unpkg/core/dist/index.js +35 -6173
  103. package/dist/unpkg/core/dist/load.d.ts +4 -0
  104. package/dist/unpkg/core/dist/load.js +182 -0
  105. package/dist/unpkg/core/dist/markdown.d.ts +2 -0
  106. package/dist/unpkg/core/dist/markdown.js +37 -0
  107. package/dist/unpkg/core/dist/normalize.d.ts +2 -0
  108. package/dist/unpkg/core/dist/normalize.js +312 -0
  109. package/dist/unpkg/core/dist/parse.d.ts +2 -0
  110. package/dist/unpkg/core/dist/parse.js +133 -0
  111. package/dist/unpkg/core/dist/scene.d.ts +3 -0
  112. package/dist/unpkg/core/dist/scene.js +1901 -0
  113. package/dist/unpkg/core/dist/schema.d.ts +8 -0
  114. package/dist/unpkg/core/dist/schema.js +298 -0
  115. package/dist/unpkg/core/dist/spatial-scene.d.ts +3 -0
  116. package/dist/unpkg/core/dist/spatial-scene.js +420 -0
  117. package/dist/unpkg/core/dist/tokenize.d.ts +4 -0
  118. package/dist/unpkg/core/dist/tokenize.js +68 -0
  119. package/dist/unpkg/core/dist/types.d.ts +637 -0
  120. package/dist/unpkg/core/dist/types.js +1 -0
  121. package/dist/unpkg/core/dist/validate.d.ts +2 -0
  122. package/dist/unpkg/core/dist/validate.js +56 -0
  123. package/dist/unpkg/editor/dist/editor.d.ts +2 -0
  124. package/dist/unpkg/editor/dist/editor.js +3700 -0
  125. package/dist/unpkg/editor/dist/index.d.ts +2 -0
  126. package/dist/unpkg/editor/dist/index.js +1 -11727
  127. package/dist/unpkg/editor/dist/types.d.ts +59 -0
  128. package/dist/unpkg/editor/dist/types.js +1 -0
  129. package/dist/unpkg/markdown/dist/html.d.ts +3 -0
  130. package/dist/unpkg/markdown/dist/html.js +64 -0
  131. package/dist/unpkg/markdown/dist/index.d.ts +4 -0
  132. package/dist/unpkg/markdown/dist/index.js +3 -5794
  133. package/dist/unpkg/markdown/dist/rehype.d.ts +10 -0
  134. package/dist/unpkg/markdown/dist/rehype.js +49 -0
  135. package/dist/unpkg/markdown/dist/remark.d.ts +9 -0
  136. package/dist/unpkg/markdown/dist/remark.js +28 -0
  137. package/dist/unpkg/markdown/dist/types.d.ts +11 -0
  138. package/dist/unpkg/markdown/dist/types.js +1 -0
  139. package/dist/unpkg/viewer/dist/atlas-state.d.ts +12 -0
  140. package/dist/unpkg/viewer/dist/atlas-state.js +269 -0
  141. package/dist/unpkg/viewer/dist/atlas-viewer.d.ts +2 -0
  142. package/dist/unpkg/viewer/dist/atlas-viewer.js +495 -0
  143. package/dist/unpkg/viewer/dist/custom-element.d.ts +1 -0
  144. package/dist/unpkg/viewer/dist/custom-element.js +78 -0
  145. package/dist/unpkg/viewer/dist/embed.d.ts +24 -0
  146. package/dist/unpkg/viewer/dist/embed.js +172 -0
  147. package/dist/unpkg/viewer/dist/errors.d.ts +6 -0
  148. package/dist/unpkg/viewer/dist/errors.js +12 -0
  149. package/dist/unpkg/viewer/dist/index.d.ts +10 -0
  150. package/dist/unpkg/viewer/dist/index.js +9 -7958
  151. package/dist/unpkg/viewer/dist/minimap.d.ts +3 -0
  152. package/dist/unpkg/viewer/dist/minimap.js +63 -0
  153. package/dist/unpkg/viewer/dist/render.d.ts +6 -0
  154. package/dist/unpkg/viewer/dist/render.js +670 -0
  155. package/dist/unpkg/viewer/dist/runtime-3d.d.ts +19 -0
  156. package/dist/unpkg/viewer/dist/runtime-3d.js +494 -0
  157. package/dist/unpkg/viewer/dist/theme.d.ts +4 -0
  158. package/dist/unpkg/viewer/dist/theme.js +103 -0
  159. package/dist/unpkg/viewer/dist/tooltip.d.ts +3 -0
  160. package/dist/unpkg/viewer/dist/tooltip.js +198 -0
  161. package/dist/unpkg/viewer/dist/types.d.ts +292 -0
  162. package/dist/unpkg/viewer/dist/types.js +1 -0
  163. package/dist/unpkg/viewer/dist/vendor/three.module.js +53032 -0
  164. package/dist/unpkg/viewer/dist/viewer-state.d.ts +19 -0
  165. package/dist/unpkg/viewer/dist/viewer-state.js +162 -0
  166. package/dist/unpkg/viewer/dist/viewer.d.ts +2 -0
  167. package/dist/unpkg/viewer/dist/viewer.js +1662 -0
  168. package/dist/unpkg/worldorbit-core.min.js +1 -12
  169. package/dist/unpkg/worldorbit-editor.min.js +1 -894
  170. package/dist/unpkg/worldorbit-markdown.min.js +1 -103
  171. package/dist/unpkg/worldorbit-viewer.min.js +1 -259
  172. package/dist/unpkg/worldorbit.js +2 -9243
  173. package/dist/unpkg/worldorbit.min.js +2 -263
  174. package/package.json +1 -1
  175. package/packages/core/dist/atlas-edit.js +1 -1
  176. package/packages/core/dist/atlas-validate.js +99 -10
  177. package/packages/core/dist/draft-parse.js +190 -15
  178. package/packages/core/dist/draft.js +50 -11
  179. package/packages/core/dist/format.js +36 -5
  180. package/packages/core/dist/index.d.ts +1 -0
  181. package/packages/core/dist/index.js +1 -0
  182. package/packages/core/dist/load.js +9 -2
  183. package/packages/core/dist/scene.js +158 -24
  184. package/packages/core/dist/spatial-scene.d.ts +3 -0
  185. package/packages/core/dist/spatial-scene.js +420 -0
  186. package/packages/core/dist/types.d.ts +124 -2
  187. package/packages/editor/dist/editor.js +130 -8
  188. package/packages/editor/dist/types.d.ts +4 -0
  189. package/packages/markdown/dist/html.js +10 -3
  190. package/packages/viewer/dist/atlas-state.js +8 -2
  191. package/packages/viewer/dist/atlas-viewer.js +20 -8
  192. package/packages/viewer/dist/custom-element.js +18 -4
  193. package/packages/viewer/dist/embed.d.ts +5 -1
  194. package/packages/viewer/dist/embed.js +58 -24
  195. package/packages/viewer/dist/errors.d.ts +6 -0
  196. package/packages/viewer/dist/errors.js +12 -0
  197. package/packages/viewer/dist/index.d.ts +1 -0
  198. package/packages/viewer/dist/index.js +1 -0
  199. package/packages/viewer/dist/runtime-3d.d.ts +19 -0
  200. package/packages/viewer/dist/runtime-3d.js +494 -0
  201. package/packages/viewer/dist/types.d.ts +25 -3
  202. package/packages/viewer/dist/vendor/three.module.js +53032 -0
  203. package/packages/viewer/dist/viewer.js +517 -41
package/README.md CHANGED
@@ -29,7 +29,7 @@ WorldOrbit is not intended to be a real-world astronomy simulator or a high-prec
29
29
  ## Quick Example
30
30
 
31
31
  ```worldorbit
32
- schema 2.1
32
+ schema 2.5
33
33
 
34
34
  system Iyath
35
35
  title "Iyath System"
@@ -37,7 +37,7 @@ system Iyath
37
37
  referencePlane ecliptic
38
38
 
39
39
  defaults
40
- view isometric
40
+ view orthographic
41
41
  scale presentation
42
42
  preset atlas-card
43
43
  theme atlas
@@ -46,6 +46,16 @@ group inner-system
46
46
  label "Inner System"
47
47
  color #d9b37a
48
48
 
49
+ viewpoint eclipse
50
+ label "Eclipse View"
51
+ projection perspective
52
+ camera
53
+ azimuth 36
54
+ elevation 22
55
+ distance 6
56
+ layers background guides orbits-back events objects labels metadata
57
+ events naar-eclipse
58
+
49
59
  object star Iyath
50
60
 
51
61
  object planet Naar
@@ -57,6 +67,15 @@ object planet Naar
57
67
  phase 42deg
58
68
  atmosphere nitrogen-oxygen
59
69
  groups inner-system
70
+
71
+ object moon Seyra
72
+ orbit Naar
73
+ distance 384400km
74
+
75
+ event naar-eclipse
76
+ kind solar-eclipse
77
+ target Naar
78
+ participants Iyath Naar Seyra
60
79
  ````
61
80
 
62
81
  ## Installation
@@ -99,7 +118,7 @@ For direct browser usage, use the browser bundle:
99
118
  <html>
100
119
  <head>
101
120
  <meta charset="utf-8" />
102
- <script src="https://unpkg.com/worldorbit@2.5.17/dist/unpkg/worldorbit.min.js"></script>
121
+ <script src="https://unpkg.com/worldorbit@3.0.0/dist/unpkg/worldorbit.min.js"></script>
103
122
  <style>
104
123
  html, body {
105
124
  margin: 0;
@@ -118,7 +137,7 @@ For direct browser usage, use the browser bundle:
118
137
 
119
138
  <script>
120
139
  const source = `
121
- schema 2.1
140
+ schema 2.5
122
141
 
123
142
  system Iyath
124
143
  epoch "JY-0001.0"
@@ -176,13 +195,13 @@ The editor is optional. The core format remains text-first.
176
195
  New atlas authoring should start with:
177
196
 
178
197
  ```worldorbit
179
- schema 2.1
198
+ schema 2.5
180
199
  ```
181
200
 
182
201
  Example:
183
202
 
184
203
  ```worldorbit
185
- schema 2.1
204
+ schema 2.5
186
205
 
187
206
  system Iyath
188
207
  title "Iyath System"
@@ -190,7 +209,7 @@ system Iyath
190
209
  referencePlane ecliptic
191
210
 
192
211
  defaults
193
- view isometric
212
+ view orthographic
194
213
  scale presentation
195
214
  preset atlas-card
196
215
  theme atlas
@@ -203,7 +222,12 @@ group inner-system
203
222
  viewpoint overview
204
223
  label "Atlas Overview"
205
224
  summary "Fit the whole system."
206
- projection isometric
225
+ projection orthographic
226
+ camera
227
+ azimuth 24
228
+ elevation 18
229
+ layers background guides orbits-back events objects labels metadata
230
+ events naar-eclipse
207
231
  filter
208
232
  groups inner-system
209
233
 
@@ -225,9 +249,47 @@ object planet Naar
225
249
  groups inner-system
226
250
  image /demo/assets/naar-map.png
227
251
  atmosphere nitrogen-oxygen
252
+
253
+ object moon Seyra
254
+ orbit Naar
255
+ distance 384400km
256
+ groups inner-system
257
+
258
+ event naar-eclipse
259
+ kind solar-eclipse
260
+ label "Naar Eclipse"
261
+ target Naar
262
+ participants Iyath Naar Seyra
263
+ epoch "JY-0001.0"
264
+ referencePlane ecliptic
265
+
266
+ positions
267
+ pose Naar
268
+ orbit Iyath
269
+ semiMajor 1.18au
270
+ phase 90deg
271
+
272
+ pose Seyra
273
+ orbit Naar
274
+ distance 384400km
275
+ phase 90deg
228
276
  ```
229
277
 
230
- Schema `2.1` adds comments, semantic `group` and `relation` sections, object-level `epoch` and `referencePlane`, declarative resonance and validation hints, and optional structured lore blocks such as `climate`, `habitability`, and `settlement`.
278
+ ## What's New In Schema 2.5
279
+
280
+ Schema `2.5` keeps Schema `2.1` fully readable and adds a clearer 3D-ready authoring surface without turning WorldOrbit into a full 3D engine.
281
+
282
+ It adds:
283
+
284
+ * new viewpoint projections: `orthographic` and `perspective`
285
+ * a Schema-level `camera` block with `azimuth`, `elevation`, optional `roll`, and optional `distance`
286
+ * clearer inheritance for `epoch` and `referencePlane` across system, object, event, and pose contexts
287
+ * more stable event snapshots, where missing pose fields fall back to object, event, and system context instead of implying empty values
288
+ * stronger validation around viewpoints, camera fields, event/pose consistency, and ambiguous authoring combinations
289
+
290
+ Schema `2.5` still does **not** add full 3D coordinates, meshes, materials, quaternions, lighting, or simulation-heavy orbital solving.
291
+
292
+ Schema `2.1` already added comments, semantic `group` and `relation` sections, declarative `event` sections with per-event `positions`/`pose` snapshots, viewpoint-linked `events`, object-level `epoch` and `referencePlane`, declarative resonance and validation hints, and optional structured lore blocks such as `climate`, `habitability`, and `settlement`.
231
293
 
232
294
  Stable `1.0` source is still accepted. Canonical `schema 2.0` source remains fully supported, and legacy `schema 2.0-draft` files stay readable as a compatibility path with a deprecation diagnostic.
233
295
 
@@ -248,7 +310,7 @@ planet Naar orbit Iyath distance 1.18au
248
310
  `.trim());
249
311
 
250
312
  const loaded = loadWorldOrbitSource(`
251
- schema 2.1
313
+ schema 2.5
252
314
 
253
315
  system Iyath
254
316
  object star Iyath
@@ -289,6 +351,7 @@ createInteractiveViewer(document.getElementById("preview"), {
289
351
  document: loaded.document,
290
352
  projection: "isometric",
291
353
  theme: "atlas",
354
+ viewMode: "3d",
292
355
  });
293
356
  ```
294
357
 
@@ -351,7 +414,7 @@ const atlasDocument = upgradeDocumentToV2(stable.document, {
351
414
  preset: "atlas-card",
352
415
  });
353
416
 
354
- const atlasSource = formatDocument(atlasDocument, { schema: "2.1" });
417
+ const atlasSource = formatDocument(atlasDocument, { schema: "2.5" });
355
418
  const loaded = loadWorldOrbitSource(atlasSource);
356
419
  const parsedAtlas = parseWorldOrbitAtlas(atlasSource);
357
420
  const scene = renderDocumentToScene(loaded.document, {
@@ -365,22 +428,25 @@ const scene = renderDocumentToScene(loaded.document, {
365
428
 
366
429
  ## Viewer Capabilities
367
430
 
368
- Viewer features in `v2.5` include:
431
+ Viewer features in `v3.0.0` include:
369
432
 
370
433
  * scene-based SVG rendering
371
- * projections: `topdown` and `isometric`
434
+ * renderer-neutral spatial scenes through `renderDocumentToSpatialScene(...)`
435
+ * a full 3D viewer mode on the same documents and placements as 2D
436
+ * deterministic orbit animation with play, pause, reset, and speed controls
437
+ * projections: `topdown`, `isometric`, `orthographic`, and `perspective`
372
438
  * theme presets: `atlas`, `nightglass`, `ember`
373
- * layer controls for background, guides, orbits, objects, labels, metadata, and relations
439
+ * layer controls for background, guides, orbits, events, objects, labels, metadata, and relations
374
440
  * selection, hover, focus, fit, pan, zoom, and rotate
375
441
  * tooltip cards and object detail payloads
376
442
  * viewpoints, filters, search, and bookmark capture
377
443
  * deep-linkable atlas state
378
444
  * embeddable viewer custom elements
379
- * semantic group filters, relation overlays, and schema 2.1 detail metadata
445
+ * semantic group filters, relation and event overlays, active event scenes, Schema 2.5 camera metadata, and event/object reference-context detail metadata
380
446
 
381
447
  ## Markdown Integration
382
448
 
383
- Use `worldorbit/markdown` to transform fenced `worldorbit` blocks into static or interactive output.
449
+ Use `worldorbit/markdown` to transform fenced `worldorbit` blocks into static output, interactive 2D output, or interactive 3D output.
384
450
 
385
451
  ```ts
386
452
  import rehypeStringify from "rehype-stringify";
@@ -393,7 +459,7 @@ import { remarkWorldOrbit } from "worldorbit/markdown";
393
459
  const html = String(
394
460
  await unified()
395
461
  .use(remarkParse)
396
- .use(remarkWorldOrbit, { mode: "interactive" })
462
+ .use(remarkWorldOrbit, { mode: "interactive-3d" })
397
463
  .use(remarkRehype, { allowDangerousHtml: true })
398
464
  .use(rehypeStringify, { allowDangerousHtml: true })
399
465
  .process(markdownSource),
@@ -406,7 +472,7 @@ In the browser:
406
472
  import { mountWorldOrbitEmbeds } from "worldorbit/viewer";
407
473
 
408
474
  mountWorldOrbitEmbeds(document, {
409
- mode: "interactive",
475
+ mode: "interactive-3d",
410
476
  });
411
477
  ```
412
478
 
@@ -415,6 +481,11 @@ mountWorldOrbitEmbeds(document, {
415
481
  Examples live in:
416
482
 
417
483
  * [examples/minimal.worldorbit](./examples/minimal.worldorbit)
484
+ * [examples/minimal-3d.worldorbit](./examples/minimal-3d.worldorbit)
485
+ * [examples/showcase-3d.worldorbit](./examples/showcase-3d.worldorbit)
486
+ * [examples/schema25-camera.worldorbit](./examples/schema25-camera.worldorbit)
487
+ * [examples/schema25-event-snapshot.worldorbit](./examples/schema25-event-snapshot.worldorbit)
488
+ * [examples/studio.schema25.worldorbit](./examples/studio.schema25.worldorbit)
418
489
  * [examples/iyath.worldorbit](./examples/iyath.worldorbit)
419
490
  * [examples/iyath.schema2.worldorbit](./examples/iyath.schema2.worldorbit)
420
491
  * [examples/iyath.schema21.worldorbit](./examples/iyath.schema21.worldorbit)
@@ -430,6 +501,8 @@ Browser-facing examples and demos live in the repository under `demo/`, `studio/
430
501
  * [migration guide: v0.8 to v1.0](./docs/migration-v0.8-to-v1.0.md)
431
502
  * [migration guide: v1 to v2](./docs/migration-v1-to-v2.md)
432
503
  * [migration guide: v2.0 to v2.1](./docs/migration-v2-to-v2.1.md)
504
+ * [migration guide: v2.1 to v2.5](./docs/migration-v2.1-to-v2.5.md)
505
+ * [migration guide: v2.6 to v3.0](./docs/migration-v2.6-to-v3.0.md)
433
506
  * [language reference](./docs/language-reference.md)
434
507
  * [language reference (DE)](./docs/language-reference.de.md)
435
508
  * [API inventory](./docs/api-inventory.md)
@@ -0,0 +1,11 @@
1
+ import type { AtlasDocumentPath, AtlasResolvedDiagnostic, WorldOrbitAtlasDocument, WorldOrbitAtlasDocumentVersion, WorldOrbitDiagnostic } from "./types.js";
2
+ export declare function createEmptyAtlasDocument(systemId?: string, version?: WorldOrbitAtlasDocumentVersion): WorldOrbitAtlasDocument;
3
+ export declare function cloneAtlasDocument(document: WorldOrbitAtlasDocument): WorldOrbitAtlasDocument;
4
+ export declare function listAtlasDocumentPaths(document: WorldOrbitAtlasDocument): AtlasDocumentPath[];
5
+ export declare function getAtlasDocumentNode(document: WorldOrbitAtlasDocument, path: AtlasDocumentPath): unknown;
6
+ export declare function upsertAtlasDocumentNode(document: WorldOrbitAtlasDocument, path: AtlasDocumentPath, value: unknown): WorldOrbitAtlasDocument;
7
+ export declare function updateAtlasDocumentNode(document: WorldOrbitAtlasDocument, path: AtlasDocumentPath, updater: (value: unknown) => unknown): WorldOrbitAtlasDocument;
8
+ export declare function removeAtlasDocumentNode(document: WorldOrbitAtlasDocument, path: AtlasDocumentPath): WorldOrbitAtlasDocument;
9
+ export declare function resolveAtlasDiagnostics(document: WorldOrbitAtlasDocument, diagnostics: WorldOrbitDiagnostic[]): AtlasResolvedDiagnostic[];
10
+ export declare function resolveAtlasDiagnosticPath(document: WorldOrbitAtlasDocument, diagnostic: WorldOrbitDiagnostic): AtlasDocumentPath | null;
11
+ export declare function validateAtlasDocumentWithDiagnostics(document: WorldOrbitAtlasDocument): AtlasResolvedDiagnostic[];
@@ -0,0 +1,347 @@
1
+ import { collectAtlasDiagnostics } from "./atlas-validate.js";
2
+ export function createEmptyAtlasDocument(systemId = "WorldOrbit", version = "2.5") {
3
+ return {
4
+ format: "worldorbit",
5
+ version,
6
+ schemaVersion: version,
7
+ sourceVersion: "1.0",
8
+ system: {
9
+ type: "system",
10
+ id: systemId,
11
+ title: systemId,
12
+ description: null,
13
+ epoch: null,
14
+ referencePlane: null,
15
+ defaults: {
16
+ view: "topdown",
17
+ scale: null,
18
+ units: null,
19
+ preset: null,
20
+ theme: null,
21
+ },
22
+ atlasMetadata: {},
23
+ viewpoints: [],
24
+ annotations: [],
25
+ },
26
+ groups: [],
27
+ relations: [],
28
+ events: [],
29
+ objects: [],
30
+ diagnostics: [],
31
+ };
32
+ }
33
+ export function cloneAtlasDocument(document) {
34
+ return structuredClone(document);
35
+ }
36
+ export function listAtlasDocumentPaths(document) {
37
+ const paths = [{ kind: "system" }, { kind: "defaults" }];
38
+ if (document.system) {
39
+ for (const key of Object.keys(document.system.atlasMetadata).sort()) {
40
+ paths.push({ kind: "metadata", key });
41
+ }
42
+ for (const viewpoint of [...document.system.viewpoints].sort(compareIdLike)) {
43
+ paths.push({ kind: "viewpoint", id: viewpoint.id });
44
+ }
45
+ for (const annotation of [...document.system.annotations].sort(compareIdLike)) {
46
+ paths.push({ kind: "annotation", id: annotation.id });
47
+ }
48
+ }
49
+ for (const group of [...document.groups].sort(compareIdLike)) {
50
+ paths.push({ kind: "group", id: group.id });
51
+ }
52
+ for (const relation of [...document.relations].sort(compareIdLike)) {
53
+ paths.push({ kind: "relation", id: relation.id });
54
+ }
55
+ for (const event of [...document.events].sort(compareIdLike)) {
56
+ paths.push({ kind: "event", id: event.id });
57
+ for (const pose of [...event.positions].sort(comparePoseObjectId)) {
58
+ paths.push({ kind: "event-pose", id: event.id, key: pose.objectId });
59
+ }
60
+ }
61
+ for (const object of [...document.objects].sort(compareIdLike)) {
62
+ paths.push({ kind: "object", id: object.id });
63
+ }
64
+ return paths;
65
+ }
66
+ export function getAtlasDocumentNode(document, path) {
67
+ switch (path.kind) {
68
+ case "system":
69
+ return document.system;
70
+ case "defaults":
71
+ return document.system?.defaults ?? null;
72
+ case "metadata":
73
+ return path.key ? (document.system?.atlasMetadata[path.key] ?? null) : null;
74
+ case "group":
75
+ return path.id ? findGroup(document, path.id) : null;
76
+ case "event":
77
+ return path.id ? findEvent(document, path.id) : null;
78
+ case "event-pose":
79
+ return path.id && path.key ? findEventPose(document, path.id, path.key) : null;
80
+ case "object":
81
+ return path.id ? findObject(document, path.id) : null;
82
+ case "viewpoint":
83
+ return path.id ? findViewpoint(document.system, path.id) : null;
84
+ case "annotation":
85
+ return path.id ? findAnnotation(document.system, path.id) : null;
86
+ case "relation":
87
+ return path.id ? findRelation(document, path.id) : null;
88
+ }
89
+ }
90
+ export function upsertAtlasDocumentNode(document, path, value) {
91
+ const next = cloneAtlasDocument(document);
92
+ const system = ensureSystem(next);
93
+ switch (path.kind) {
94
+ case "system":
95
+ next.system = value;
96
+ return next;
97
+ case "defaults":
98
+ system.defaults = {
99
+ ...system.defaults,
100
+ ...value,
101
+ };
102
+ return next;
103
+ case "metadata":
104
+ if (!path.key) {
105
+ throw new Error('Metadata updates require a "key" value.');
106
+ }
107
+ if (value === null || value === undefined || value === "") {
108
+ delete system.atlasMetadata[path.key];
109
+ }
110
+ else {
111
+ system.atlasMetadata[path.key] = String(value);
112
+ }
113
+ return next;
114
+ case "group":
115
+ if (!path.id) {
116
+ throw new Error('Group updates require an "id" value.');
117
+ }
118
+ upsertById(next.groups, value);
119
+ return next;
120
+ case "event":
121
+ if (!path.id) {
122
+ throw new Error('Event updates require an "id" value.');
123
+ }
124
+ upsertById(next.events, value);
125
+ return next;
126
+ case "event-pose":
127
+ if (!path.id || !path.key) {
128
+ throw new Error('Event pose updates require an event "id" and pose "key" value.');
129
+ }
130
+ upsertEventPose(next.events, path.id, value);
131
+ return next;
132
+ case "object":
133
+ if (!path.id) {
134
+ throw new Error('Object updates require an "id" value.');
135
+ }
136
+ upsertById(next.objects, value);
137
+ return next;
138
+ case "viewpoint":
139
+ if (!path.id) {
140
+ throw new Error('Viewpoint updates require an "id" value.');
141
+ }
142
+ upsertById(system.viewpoints, value);
143
+ return next;
144
+ case "annotation":
145
+ if (!path.id) {
146
+ throw new Error('Annotation updates require an "id" value.');
147
+ }
148
+ upsertById(system.annotations, value);
149
+ return next;
150
+ case "relation":
151
+ if (!path.id) {
152
+ throw new Error('Relation updates require an "id" value.');
153
+ }
154
+ upsertById(next.relations, value);
155
+ return next;
156
+ }
157
+ }
158
+ export function updateAtlasDocumentNode(document, path, updater) {
159
+ return upsertAtlasDocumentNode(document, path, updater(getAtlasDocumentNode(document, path)));
160
+ }
161
+ export function removeAtlasDocumentNode(document, path) {
162
+ const next = cloneAtlasDocument(document);
163
+ const system = ensureSystem(next);
164
+ switch (path.kind) {
165
+ case "metadata":
166
+ if (path.key) {
167
+ delete system.atlasMetadata[path.key];
168
+ }
169
+ return next;
170
+ case "object":
171
+ if (path.id) {
172
+ next.objects = next.objects.filter((object) => object.id !== path.id);
173
+ }
174
+ return next;
175
+ case "group":
176
+ if (path.id) {
177
+ next.groups = next.groups.filter((group) => group.id !== path.id);
178
+ }
179
+ return next;
180
+ case "event":
181
+ if (path.id) {
182
+ next.events = next.events.filter((event) => event.id !== path.id);
183
+ }
184
+ return next;
185
+ case "event-pose":
186
+ if (path.id && path.key) {
187
+ const event = findEvent(next, path.id);
188
+ if (event) {
189
+ event.positions = event.positions.filter((pose) => pose.objectId !== path.key);
190
+ }
191
+ }
192
+ return next;
193
+ case "viewpoint":
194
+ if (path.id) {
195
+ system.viewpoints = system.viewpoints.filter((viewpoint) => viewpoint.id !== path.id);
196
+ }
197
+ return next;
198
+ case "annotation":
199
+ if (path.id) {
200
+ system.annotations = system.annotations.filter((annotation) => annotation.id !== path.id);
201
+ }
202
+ return next;
203
+ case "relation":
204
+ if (path.id) {
205
+ next.relations = next.relations.filter((relation) => relation.id !== path.id);
206
+ }
207
+ return next;
208
+ default:
209
+ return next;
210
+ }
211
+ }
212
+ export function resolveAtlasDiagnostics(document, diagnostics) {
213
+ return diagnostics.map((diagnostic) => ({
214
+ diagnostic,
215
+ path: resolveAtlasDiagnosticPath(document, diagnostic),
216
+ }));
217
+ }
218
+ export function resolveAtlasDiagnosticPath(document, diagnostic) {
219
+ if (diagnostic.objectId && findObject(document, diagnostic.objectId)) {
220
+ return {
221
+ kind: "object",
222
+ id: diagnostic.objectId,
223
+ };
224
+ }
225
+ if (diagnostic.field?.startsWith("group.")) {
226
+ const parts = diagnostic.field.split(".");
227
+ if (parts[1] && findGroup(document, parts[1])) {
228
+ return {
229
+ kind: "group",
230
+ id: parts[1],
231
+ };
232
+ }
233
+ }
234
+ if (diagnostic.field?.startsWith("viewpoint.")) {
235
+ const parts = diagnostic.field.split(".");
236
+ if (parts[1] && findViewpoint(document.system, parts[1])) {
237
+ return {
238
+ kind: "viewpoint",
239
+ id: parts[1],
240
+ };
241
+ }
242
+ }
243
+ if (diagnostic.field?.startsWith("annotation.")) {
244
+ const parts = diagnostic.field.split(".");
245
+ if (parts[1] && findAnnotation(document.system, parts[1])) {
246
+ return {
247
+ kind: "annotation",
248
+ id: parts[1],
249
+ };
250
+ }
251
+ }
252
+ if (diagnostic.field?.startsWith("relation.")) {
253
+ const parts = diagnostic.field.split(".");
254
+ if (parts[1] && findRelation(document, parts[1])) {
255
+ return {
256
+ kind: "relation",
257
+ id: parts[1],
258
+ };
259
+ }
260
+ }
261
+ if (diagnostic.field?.startsWith("event.")) {
262
+ const parts = diagnostic.field.split(".");
263
+ if (parts[1] && findEvent(document, parts[1])) {
264
+ if (parts[2] === "pose" && parts[3] && findEventPose(document, parts[1], parts[3])) {
265
+ return {
266
+ kind: "event-pose",
267
+ id: parts[1],
268
+ key: parts[3],
269
+ };
270
+ }
271
+ return {
272
+ kind: "event",
273
+ id: parts[1],
274
+ };
275
+ }
276
+ }
277
+ if (diagnostic.field && diagnostic.field in ensureSystem(document).atlasMetadata) {
278
+ return {
279
+ kind: "metadata",
280
+ key: diagnostic.field,
281
+ };
282
+ }
283
+ return null;
284
+ }
285
+ export function validateAtlasDocumentWithDiagnostics(document) {
286
+ const diagnostics = [
287
+ ...document.diagnostics,
288
+ ...collectAtlasDiagnostics(document, document.version),
289
+ ];
290
+ return resolveAtlasDiagnostics(document, diagnostics);
291
+ }
292
+ function ensureSystem(document) {
293
+ if (document.system) {
294
+ return document.system;
295
+ }
296
+ document.system = createEmptyAtlasDocument().system;
297
+ return document.system;
298
+ }
299
+ function findObject(document, objectId) {
300
+ return document.objects.find((object) => object.id === objectId) ?? null;
301
+ }
302
+ function findGroup(document, groupId) {
303
+ return document.groups.find((group) => group.id === groupId) ?? null;
304
+ }
305
+ function findRelation(document, relationId) {
306
+ return document.relations.find((relation) => relation.id === relationId) ?? null;
307
+ }
308
+ function findEvent(document, eventId) {
309
+ return document.events.find((event) => event.id === eventId) ?? null;
310
+ }
311
+ function findEventPose(document, eventId, objectId) {
312
+ return findEvent(document, eventId)?.positions.find((pose) => pose.objectId === objectId) ?? null;
313
+ }
314
+ function findViewpoint(system, viewpointId) {
315
+ return system?.viewpoints.find((viewpoint) => viewpoint.id === viewpointId) ?? null;
316
+ }
317
+ function findAnnotation(system, annotationId) {
318
+ return system?.annotations.find((annotation) => annotation.id === annotationId) ?? null;
319
+ }
320
+ function upsertById(items, value) {
321
+ const index = items.findIndex((item) => item.id === value.id);
322
+ if (index === -1) {
323
+ items.push(value);
324
+ items.sort(compareIdLike);
325
+ return;
326
+ }
327
+ items[index] = value;
328
+ }
329
+ function upsertEventPose(events, eventId, value) {
330
+ const event = events.find((entry) => entry.id === eventId);
331
+ if (!event) {
332
+ throw new Error(`Unknown event "${eventId}" for pose update.`);
333
+ }
334
+ const index = event.positions.findIndex((entry) => entry.objectId === value.objectId);
335
+ if (index === -1) {
336
+ event.positions.push(value);
337
+ event.positions.sort(comparePoseObjectId);
338
+ return;
339
+ }
340
+ event.positions[index] = value;
341
+ }
342
+ function compareIdLike(left, right) {
343
+ return left.id.localeCompare(right.id);
344
+ }
345
+ function comparePoseObjectId(left, right) {
346
+ return left.objectId.localeCompare(right.objectId);
347
+ }
@@ -0,0 +1,22 @@
1
+ import type { AstFieldNode, AstSourceLocation, AtReference, NormalizedValue, UnitValue, WorldOrbitObjectType } from "./types.js";
2
+ export interface AtlasFieldLike {
3
+ key: string;
4
+ values: string[];
5
+ location: AstSourceLocation;
6
+ }
7
+ export declare function normalizeIdentifier(value: string): string;
8
+ export declare function humanizeIdentifier(value: string): string;
9
+ export declare function parseAtlasUnitValue(input: string, location?: AstSourceLocation, fieldKey?: string): UnitValue;
10
+ export declare function tryParseAtlasUnitValue(input: string): UnitValue | null;
11
+ export declare function parseAtlasNumber(input: string, key: string, location?: AstSourceLocation): number;
12
+ export declare function parseAtlasBoolean(input: string, key: string, location?: AstSourceLocation): boolean;
13
+ export declare function parseAtlasFieldBoolean(field: AtlasFieldLike): boolean;
14
+ export declare function parseAtlasAtReference(target: string, location?: AstSourceLocation): AtReference;
15
+ export declare function validateAtlasImageSource(value: string, location?: AstSourceLocation): void;
16
+ export declare function normalizeLegacyScalarValue(key: string, values: string[], location: AstSourceLocation): NormalizedValue;
17
+ export declare function ensureAtlasFieldSupported(key: string, objectType: WorldOrbitObjectType, location: AstSourceLocation): void;
18
+ export declare function singleAtlasFieldValue(field: Pick<AtlasFieldLike, "key" | "values" | "location">): string;
19
+ export declare function singleAtlasValue(values: string[], key: string, location?: AstSourceLocation): string;
20
+ export declare function isStructureLikeObjectType(objectType: WorldOrbitObjectType): boolean;
21
+ export declare function cloneNormalizedValue(value: NormalizedValue): NormalizedValue;
22
+ export declare function cloneFieldNode(field: AstFieldNode): AstFieldNode;