worldorbit 2.6.0 → 3.0.1

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 (196) hide show
  1. package/README.md +20 -9
  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 -6542
  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 -12250
  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 -6179
  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 -8334
  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 -6614
  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 -12275
  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 -6207
  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 -8391
  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 +10 -10
  169. package/dist/unpkg/worldorbit-editor.min.js +4109 -256
  170. package/dist/unpkg/worldorbit-markdown.min.js +26 -26
  171. package/dist/unpkg/worldorbit-viewer.min.js +3945 -92
  172. package/dist/unpkg/worldorbit.js +32219 -199
  173. package/dist/unpkg/worldorbit.min.js +3949 -96
  174. package/package.json +1 -1
  175. package/packages/core/dist/index.d.ts +1 -0
  176. package/packages/core/dist/index.js +1 -0
  177. package/packages/core/dist/spatial-scene.d.ts +3 -0
  178. package/packages/core/dist/spatial-scene.js +420 -0
  179. package/packages/core/dist/types.d.ts +105 -0
  180. package/packages/editor/dist/editor.js +25 -4
  181. package/packages/editor/dist/types.d.ts +4 -0
  182. package/packages/markdown/dist/html.js +10 -3
  183. package/packages/viewer/dist/atlas-state.js +3 -0
  184. package/packages/viewer/dist/atlas-viewer.js +1 -0
  185. package/packages/viewer/dist/custom-element.js +18 -4
  186. package/packages/viewer/dist/embed.d.ts +5 -1
  187. package/packages/viewer/dist/embed.js +58 -24
  188. package/packages/viewer/dist/errors.d.ts +6 -0
  189. package/packages/viewer/dist/errors.js +12 -0
  190. package/packages/viewer/dist/index.d.ts +1 -0
  191. package/packages/viewer/dist/index.js +1 -0
  192. package/packages/viewer/dist/runtime-3d.d.ts +19 -0
  193. package/packages/viewer/dist/runtime-3d.js +494 -0
  194. package/packages/viewer/dist/types.d.ts +21 -2
  195. package/packages/viewer/dist/vendor/three.module.js +53032 -0
  196. package/packages/viewer/dist/viewer.js +501 -41
@@ -0,0 +1,494 @@
1
+ import { evaluateSpatialSceneAtTime, } from "@worldorbit/core";
2
+ import { WorldOrbit3DUnavailableError } from "./errors.js";
3
+ import { resolveTheme } from "./theme.js";
4
+ const VIEW_ROOT_CLASS = "wo-viewer-3d-root";
5
+ let threeModulePromise = null;
6
+ export function createViewer3DRuntime(container) {
7
+ ensureWebGLSupport();
8
+ const root = document.createElement("div");
9
+ root.className = VIEW_ROOT_CLASS;
10
+ root.dataset.worldorbit3d = "true";
11
+ root.innerHTML = `<div class="wo-viewer-3d-loading">Loading 3D view...</div>`;
12
+ container.innerHTML = "";
13
+ container.append(root);
14
+ let runtime = null;
15
+ let currentScene = null;
16
+ let currentRenderOptions = null;
17
+ let currentState = null;
18
+ let currentVisibleObjectIds = new Set();
19
+ let currentSelectedObjectId = null;
20
+ let currentHoveredObjectId = null;
21
+ let currentTimeSeconds = 0;
22
+ let currentPositions = new Map();
23
+ let pendingUpdate = null;
24
+ let destroyed = false;
25
+ const objectVisuals = new Map();
26
+ const orbitVisuals = new Map();
27
+ const raycastTargets = [];
28
+ void loadThreeModule()
29
+ .then((THREE) => {
30
+ if (destroyed) {
31
+ return;
32
+ }
33
+ const scene3d = new THREE.Scene();
34
+ const camera = new THREE.PerspectiveCamera(52, 1, 0.1, 20_000);
35
+ const renderer = new THREE.WebGLRenderer({
36
+ antialias: true,
37
+ alpha: true,
38
+ preserveDrawingBuffer: true,
39
+ });
40
+ renderer.domElement.classList.add("wo-viewer-3d-canvas");
41
+ renderer.domElement.dataset.worldorbit3dCanvas = "true";
42
+ root.innerHTML = "";
43
+ root.append(renderer.domElement);
44
+ const ambientLight = new THREE.AmbientLight(0xffffff, 1.2);
45
+ const keyLight = new THREE.PointLight(0xffffff, 1.35, 0, 2);
46
+ scene3d.add(ambientLight);
47
+ scene3d.add(keyLight);
48
+ const orbitLayer = new THREE.Group();
49
+ const objectLayer = new THREE.Group();
50
+ scene3d.add(orbitLayer);
51
+ scene3d.add(objectLayer);
52
+ const raycaster = new THREE.Raycaster();
53
+ raycaster.params.Line = { threshold: 10 };
54
+ runtime = {
55
+ THREE,
56
+ scene3d,
57
+ camera,
58
+ renderer,
59
+ keyLight,
60
+ orbitLayer,
61
+ objectLayer,
62
+ raycaster,
63
+ pointer: new THREE.Vector2(),
64
+ };
65
+ if (pendingUpdate) {
66
+ applyUpdate(pendingUpdate);
67
+ }
68
+ })
69
+ .catch((error) => {
70
+ if (destroyed) {
71
+ return;
72
+ }
73
+ root.innerHTML = `<div class="wo-viewer-3d-loading is-error">${escapeHtml(error instanceof Error ? error.message : "WorldOrbit 3D could not be initialized.")}</div>`;
74
+ });
75
+ return {
76
+ update(next) {
77
+ pendingUpdate = next;
78
+ applyUpdate(next);
79
+ },
80
+ hitTest(clientX, clientY) {
81
+ if (!runtime || !currentScene) {
82
+ return null;
83
+ }
84
+ const rect = runtime.renderer.domElement.getBoundingClientRect();
85
+ if (!rect.width || !rect.height) {
86
+ return null;
87
+ }
88
+ runtime.pointer.x = ((clientX - rect.left) / rect.width) * 2 - 1;
89
+ runtime.pointer.y = -((clientY - rect.top) / rect.height) * 2 + 1;
90
+ runtime.raycaster.setFromCamera(runtime.pointer, runtime.camera);
91
+ const intersections = runtime.raycaster.intersectObjects(raycastTargets, true);
92
+ for (const hit of intersections) {
93
+ const objectId = resolveUserDataObjectId(hit.object);
94
+ if (objectId) {
95
+ return objectId;
96
+ }
97
+ }
98
+ return null;
99
+ },
100
+ projectObjectToContainer(objectId) {
101
+ if (!runtime) {
102
+ return null;
103
+ }
104
+ const position = currentPositions.get(objectId);
105
+ if (!position) {
106
+ return null;
107
+ }
108
+ const vector = new runtime.THREE.Vector3(position.x, position.y, position.z);
109
+ vector.project(runtime.camera);
110
+ if (vector.z > 1) {
111
+ return null;
112
+ }
113
+ const rect = runtime.renderer.domElement.getBoundingClientRect();
114
+ const containerRect = container.getBoundingClientRect();
115
+ return {
116
+ x: rect.left -
117
+ containerRect.left +
118
+ ((vector.x + 1) / 2) * rect.width,
119
+ y: rect.top -
120
+ containerRect.top +
121
+ ((1 - vector.y) / 2) * rect.height,
122
+ };
123
+ },
124
+ destroy() {
125
+ destroyed = true;
126
+ pendingUpdate = null;
127
+ runtime?.renderer.dispose();
128
+ root.remove();
129
+ objectVisuals.clear();
130
+ orbitVisuals.clear();
131
+ raycastTargets.length = 0;
132
+ runtime = null;
133
+ },
134
+ };
135
+ function applyUpdate(next) {
136
+ if (!runtime) {
137
+ return;
138
+ }
139
+ const sceneChanged = currentScene !== next.spatialScene;
140
+ currentScene = next.spatialScene;
141
+ currentRenderOptions = next.renderOptions;
142
+ currentState = next.state;
143
+ currentVisibleObjectIds = next.visibleObjectIds;
144
+ currentSelectedObjectId = next.selectedObjectId;
145
+ currentHoveredObjectId = next.hoveredObjectId;
146
+ currentTimeSeconds = next.timeSeconds;
147
+ if (sceneChanged) {
148
+ rebuildScene(next.spatialScene);
149
+ }
150
+ resizeRenderer(next.spatialScene);
151
+ currentPositions = evaluateSpatialSceneAtTime(next.spatialScene, next.timeSeconds);
152
+ updateObjectTransforms();
153
+ updateOrbitTransforms();
154
+ updateVisibility();
155
+ updateInteractionState();
156
+ updateCamera();
157
+ renderNow();
158
+ }
159
+ function rebuildScene(spatialScene) {
160
+ if (!runtime) {
161
+ return;
162
+ }
163
+ clearGroup(runtime.orbitLayer);
164
+ clearGroup(runtime.objectLayer);
165
+ objectVisuals.clear();
166
+ orbitVisuals.clear();
167
+ raycastTargets.length = 0;
168
+ const theme = resolveTheme(currentRenderOptions?.theme);
169
+ runtime.scene3d.background = new runtime.THREE.Color(theme.backgroundStart);
170
+ for (const orbit of spatialScene.orbits) {
171
+ const visual = createOrbitVisual(runtime.THREE, orbit, theme);
172
+ runtime.orbitLayer.add(visual.root);
173
+ orbitVisuals.set(orbit.objectId, visual);
174
+ raycastTargets.push(visual.root);
175
+ }
176
+ for (const object of spatialScene.objects) {
177
+ const visual = createObjectVisual(runtime.THREE, object, theme);
178
+ runtime.objectLayer.add(visual.root);
179
+ objectVisuals.set(object.objectId, visual);
180
+ raycastTargets.push(visual.root);
181
+ }
182
+ }
183
+ function updateObjectTransforms() {
184
+ for (const object of currentScene?.objects ?? []) {
185
+ const visual = objectVisuals.get(object.objectId);
186
+ const position = currentPositions.get(object.objectId);
187
+ if (!visual || !position) {
188
+ continue;
189
+ }
190
+ visual.root.position.set(position.x, position.y, position.z);
191
+ }
192
+ }
193
+ function updateOrbitTransforms() {
194
+ for (const orbit of currentScene?.orbits ?? []) {
195
+ const visual = orbitVisuals.get(orbit.objectId);
196
+ if (!visual) {
197
+ continue;
198
+ }
199
+ const parentPosition = currentPositions.get(orbit.parentId);
200
+ visual.root.position.set(parentPosition?.x ?? orbit.center.x, parentPosition?.y ?? orbit.center.y, parentPosition?.z ?? orbit.center.z);
201
+ }
202
+ }
203
+ function updateVisibility() {
204
+ const layers = currentRenderOptions?.layers ?? {};
205
+ for (const object of currentScene?.objects ?? []) {
206
+ const visual = objectVisuals.get(object.objectId);
207
+ if (!visual) {
208
+ continue;
209
+ }
210
+ const hideStructure = layers.structures === false &&
211
+ (object.object.type === "structure" || object.object.type === "phenomenon");
212
+ const hideObjects = layers.objects === false;
213
+ visual.root.visible =
214
+ !object.hidden &&
215
+ currentVisibleObjectIds.has(object.objectId) &&
216
+ !hideStructure &&
217
+ !hideObjects;
218
+ }
219
+ for (const orbit of currentScene?.orbits ?? []) {
220
+ const visual = orbitVisuals.get(orbit.objectId);
221
+ if (!visual) {
222
+ continue;
223
+ }
224
+ const hideStructure = layers.structures === false &&
225
+ (orbit.object.type === "structure" || orbit.object.type === "phenomenon");
226
+ visual.root.visible =
227
+ !orbit.hidden &&
228
+ currentVisibleObjectIds.has(orbit.objectId) &&
229
+ layers.orbits !== false &&
230
+ !hideStructure;
231
+ }
232
+ }
233
+ function updateInteractionState() {
234
+ if (!runtime) {
235
+ return;
236
+ }
237
+ for (const visual of objectVisuals.values()) {
238
+ applyVisualState(runtime.THREE, visual.materials, visual.baseColor, currentSelectedObjectId === visual.objectId, currentHoveredObjectId === visual.objectId);
239
+ const scale = currentSelectedObjectId === visual.objectId
240
+ ? 1.2
241
+ : currentHoveredObjectId === visual.objectId
242
+ ? 1.1
243
+ : 1;
244
+ visual.root.scale.set(scale, scale, scale);
245
+ }
246
+ for (const visual of orbitVisuals.values()) {
247
+ applyVisualState(runtime.THREE, visual.materials, visual.baseColor, currentSelectedObjectId === visual.objectId, currentHoveredObjectId === visual.objectId);
248
+ }
249
+ }
250
+ function updateCamera() {
251
+ if (!runtime || !currentScene || !currentState) {
252
+ return;
253
+ }
254
+ const sceneCamera = currentRenderOptions?.camera ?? currentScene.camera;
255
+ const bounds = currentScene.contentBounds;
256
+ const size = Math.max(bounds.width, bounds.depth, bounds.height, 160);
257
+ const yaw = degreesToRadians((sceneCamera?.azimuth ?? 34) + currentState.rotationDeg);
258
+ const pitch = degreesToRadians(clampValue(sceneCamera?.elevation ?? 24, -75, 75));
259
+ const zoomDistanceFactor = clampValue(2.4 / Math.max(currentState.scale, 0.1), 0.35, 8);
260
+ const semanticDistance = clampValue(sceneCamera?.distance ?? 6, 2, 24);
261
+ const distance = clampValue(size * zoomDistanceFactor * (semanticDistance / 6), 28, 8_000);
262
+ const panFactor = Math.max(size / 900, 0.12);
263
+ const target = new runtime.THREE.Vector3(bounds.center.x - currentState.translateX * panFactor, bounds.center.y, bounds.center.z - currentState.translateY * panFactor);
264
+ runtime.camera.position.set(target.x + distance * Math.cos(pitch) * Math.sin(yaw), target.y + distance * Math.sin(pitch), target.z + distance * Math.cos(pitch) * Math.cos(yaw));
265
+ runtime.camera.lookAt(target);
266
+ if (sceneCamera?.roll) {
267
+ runtime.camera.rotation.z = degreesToRadians(sceneCamera.roll);
268
+ }
269
+ runtime.keyLight.position.copy(runtime.camera.position);
270
+ }
271
+ function resizeRenderer(spatialScene) {
272
+ if (!runtime) {
273
+ return;
274
+ }
275
+ const width = Math.max(1, Math.round(container.clientWidth || spatialScene.width || 960));
276
+ const height = Math.max(1, Math.round(container.clientHeight || spatialScene.height || 560));
277
+ runtime.renderer.setSize(width, height, false);
278
+ runtime.camera.aspect = width / height;
279
+ runtime.camera.updateProjectionMatrix();
280
+ }
281
+ function renderNow() {
282
+ if (!runtime) {
283
+ return;
284
+ }
285
+ runtime.renderer.render(runtime.scene3d, runtime.camera);
286
+ }
287
+ }
288
+ function createObjectVisual(THREE, object, theme) {
289
+ const root = new THREE.Group();
290
+ root.userData.objectId = object.objectId;
291
+ const baseColor = object.fillColor ?? colorForObject(object);
292
+ const material = new THREE.MeshPhongMaterial({
293
+ color: baseColor,
294
+ emissive: object.object.type === "star"
295
+ ? new THREE.Color(theme.starGlow)
296
+ : new THREE.Color(0x000000),
297
+ emissiveIntensity: object.object.type === "star" ? 0.6 : 0.08,
298
+ transparent: true,
299
+ opacity: object.object.type === "phenomenon" ? 0.7 : 1,
300
+ });
301
+ const geometry = geometryForObject(THREE, object);
302
+ const body = new THREE.Mesh(geometry, material);
303
+ body.userData.objectId = object.objectId;
304
+ root.add(body);
305
+ return {
306
+ objectId: object.objectId,
307
+ root,
308
+ body,
309
+ materials: [material],
310
+ baseColor,
311
+ };
312
+ }
313
+ function createOrbitVisual(THREE, orbit, theme) {
314
+ const root = new THREE.Group();
315
+ root.userData.objectId = orbit.objectId;
316
+ root.rotation.y = degreesToRadians(orbit.rotationDeg);
317
+ root.rotation.x = degreesToRadians(orbit.inclinationDeg);
318
+ const baseColor = orbit.object.properties.color ?? theme.orbit;
319
+ const materials = [];
320
+ if (orbit.band) {
321
+ const material = new THREE.MeshBasicMaterial({
322
+ color: baseColor,
323
+ transparent: true,
324
+ opacity: 0.42,
325
+ side: 2,
326
+ });
327
+ const geometry = bandGeometryForOrbit(THREE, orbit);
328
+ const mesh = new THREE.Mesh(geometry, material);
329
+ mesh.userData.objectId = orbit.objectId;
330
+ root.add(mesh);
331
+ materials.push(material);
332
+ }
333
+ else {
334
+ const material = new THREE.LineBasicMaterial({
335
+ color: baseColor,
336
+ transparent: true,
337
+ opacity: 0.55,
338
+ });
339
+ const points = sampleOrbitPoints(THREE, orbit);
340
+ const geometry = new THREE.BufferGeometry().setFromPoints(points);
341
+ const line = new THREE.LineLoop(geometry, material);
342
+ line.userData.objectId = orbit.objectId;
343
+ root.add(line);
344
+ materials.push(material);
345
+ }
346
+ return {
347
+ objectId: orbit.objectId,
348
+ root,
349
+ materials,
350
+ baseColor,
351
+ };
352
+ }
353
+ function geometryForObject(THREE, object) {
354
+ const radius = Math.max(object.visualRadius, 2);
355
+ switch (object.object.type) {
356
+ case "star":
357
+ return new THREE.SphereGeometry(radius * 1.12, 28, 20);
358
+ case "structure":
359
+ return new THREE.BoxGeometry(radius * 1.5, radius * 1.5, radius * 1.5);
360
+ case "phenomenon":
361
+ return new THREE.OctahedronGeometry(radius * 1.25, 0);
362
+ case "belt":
363
+ case "ring":
364
+ return new THREE.OctahedronGeometry(Math.max(radius * 0.85, 3), 0);
365
+ default:
366
+ return new THREE.SphereGeometry(radius, 20, 14);
367
+ }
368
+ }
369
+ function bandGeometryForOrbit(THREE, orbit) {
370
+ const thickness = Math.max(orbit.bandThickness ?? 8, 3);
371
+ const points = sampleOrbitPoints(THREE, orbit, 72);
372
+ const curve = new THREE.CatmullRomCurve3(points, true);
373
+ return new THREE.TubeGeometry(curve, 128, thickness * 0.28, 10, true);
374
+ }
375
+ function sampleOrbitPoints(THREE, orbit, segments = 96) {
376
+ const points = [];
377
+ const semiMajor = Math.max(orbit.semiMajor, orbit.radius ?? 1, 1);
378
+ const semiMinor = Math.max(orbit.semiMinor, orbit.radius ?? 1, 1);
379
+ for (let index = 0; index < segments; index += 1) {
380
+ const angle = (index / segments) * Math.PI * 2;
381
+ points.push(new THREE.Vector3(Math.cos(angle) * semiMajor, 0, Math.sin(angle) * semiMinor));
382
+ }
383
+ return points;
384
+ }
385
+ function colorForObject(object) {
386
+ switch (object.object.type) {
387
+ case "star":
388
+ return "#ffd36a";
389
+ case "planet":
390
+ return "#73b6ff";
391
+ case "moon":
392
+ return "#d8dde8";
393
+ case "belt":
394
+ return "#b8926a";
395
+ case "ring":
396
+ return "#cdbf9a";
397
+ case "structure":
398
+ return "#ffce8a";
399
+ case "phenomenon":
400
+ return "#7ce6ff";
401
+ case "asteroid":
402
+ return "#cdb5a1";
403
+ case "comet":
404
+ return "#b8f2ff";
405
+ }
406
+ }
407
+ function applyVisualState(THREE, materials, baseColor, selected, hovered) {
408
+ const color = new THREE.Color(baseColor);
409
+ if (selected) {
410
+ color.offsetHSL(0, 0, 0.16);
411
+ }
412
+ else if (hovered) {
413
+ color.offsetHSL(0, 0, 0.08);
414
+ }
415
+ for (const material of materials) {
416
+ if (!material) {
417
+ continue;
418
+ }
419
+ material.color?.set?.(color);
420
+ if (typeof material.opacity === "number") {
421
+ material.opacity = selected ? 0.85 : hovered ? 0.72 : material.transparent ? 0.55 : 1;
422
+ }
423
+ material.emissive?.set?.(selected ? new THREE.Color("#ffdda9") : hovered ? new THREE.Color("#cfe9ff") : new THREE.Color(0x000000));
424
+ material.emissiveIntensity = selected ? 0.28 : hovered ? 0.14 : material.emissiveIntensity ?? 0.08;
425
+ }
426
+ }
427
+ function clearGroup(group) {
428
+ while (group.children.length > 0) {
429
+ const child = group.children[0];
430
+ group.remove(child);
431
+ child.geometry?.dispose?.();
432
+ if (Array.isArray(child.material)) {
433
+ child.material.forEach((entry) => entry?.dispose?.());
434
+ }
435
+ else {
436
+ child.material?.dispose?.();
437
+ }
438
+ }
439
+ }
440
+ function ensureWebGLSupport() {
441
+ if (typeof document === "undefined") {
442
+ throw new WorldOrbit3DUnavailableError();
443
+ }
444
+ const navigatorLike = document.defaultView?.navigator ??
445
+ globalThis.window?.navigator ??
446
+ (typeof navigator !== "undefined" ? navigator : undefined);
447
+ if (/jsdom/i.test(navigatorLike?.userAgent ?? "")) {
448
+ throw new WorldOrbit3DUnavailableError("WorldOrbit 3D needs WebGL support, but this environment did not provide it.");
449
+ }
450
+ const canvas = document.createElement("canvas");
451
+ const tryGetContext = (kind) => {
452
+ try {
453
+ return canvas.getContext?.(kind) ?? null;
454
+ }
455
+ catch {
456
+ return null;
457
+ }
458
+ };
459
+ const context = tryGetContext("webgl2") ??
460
+ tryGetContext("webgl") ??
461
+ tryGetContext("experimental-webgl");
462
+ if (!context) {
463
+ throw new WorldOrbit3DUnavailableError("WorldOrbit 3D needs WebGL support, but this environment did not provide it.");
464
+ }
465
+ }
466
+ function resolveUserDataObjectId(target) {
467
+ let cursor = target;
468
+ while (cursor) {
469
+ if (typeof cursor.userData?.objectId === "string") {
470
+ return cursor.userData.objectId;
471
+ }
472
+ cursor = cursor.parent;
473
+ }
474
+ return null;
475
+ }
476
+ function clampValue(value, min, max) {
477
+ return Math.min(Math.max(value, min), max);
478
+ }
479
+ function degreesToRadians(value) {
480
+ return (value * Math.PI) / 180;
481
+ }
482
+ function escapeHtml(value) {
483
+ return value
484
+ .replaceAll("&", "&amp;")
485
+ .replaceAll("<", "&lt;")
486
+ .replaceAll(">", "&gt;")
487
+ .replaceAll('"', "&quot;");
488
+ }
489
+ function loadThreeModule() {
490
+ if (!threeModulePromise) {
491
+ threeModulePromise = import("./vendor/three.module.js");
492
+ }
493
+ return threeModulePromise;
494
+ }
@@ -1,6 +1,7 @@
1
- import type { CoordinatePoint, RenderOrbitVisual, RenderProjectionFallback, RenderPresetName, RenderSceneEvent, RenderSceneGroup, RenderSceneLabel, RenderScaleModel, RenderScene, RenderSceneObject, RenderSceneViewpoint, SceneRenderOptions, ViewProjection, WorldOrbitObject, WorldOrbitDocument, WorldOrbitViewCamera } from "@worldorbit/core";
1
+ import type { CoordinatePoint, RenderOrbitVisual, RenderProjectionFallback, RenderPresetName, RenderSceneEvent, RenderSceneGroup, RenderSceneLabel, RenderScaleModel, RenderScene, RenderSceneObject, RenderSceneViewpoint, SceneRenderOptions, SpatialScene, ViewProjection, WorldOrbitObject, WorldOrbitDocument, WorldOrbitViewCamera } from "@worldorbit/core";
2
2
  export type WorldOrbitThemeName = "atlas" | "nightglass" | "ember";
3
- export type WorldOrbitEmbedMode = "static" | "interactive";
3
+ export type WorldOrbitViewMode = "2d" | "3d";
4
+ export type WorldOrbitEmbedMode = "static" | "interactive" | "interactive-2d" | "interactive-3d";
4
5
  export type TooltipMode = "hover" | "pinned" | "disabled";
5
6
  export interface WorldOrbitTheme {
6
7
  name: string;
@@ -62,6 +63,7 @@ export interface SvgRenderOptions extends SceneRenderOptions {
62
63
  export interface ViewerRenderOptions extends Omit<SvgRenderOptions, "selectedObjectId"> {
63
64
  projection?: "document" | ViewProjection;
64
65
  scaleModel?: Partial<RenderScaleModel>;
66
+ viewMode?: WorldOrbitViewMode;
65
67
  }
66
68
  export interface ViewerState {
67
69
  scale: number;
@@ -115,9 +117,16 @@ export interface ViewerAtlasState {
115
117
  layers?: ViewerLayerOptions;
116
118
  scaleModel?: Partial<RenderScaleModel>;
117
119
  activeEventId?: string | null;
120
+ viewMode?: WorldOrbitViewMode;
118
121
  };
119
122
  filter: ViewerFilter | null;
120
123
  }
124
+ export interface ViewerAnimationState {
125
+ playing: boolean;
126
+ speed: number;
127
+ timeSeconds: number;
128
+ frozenByEvent: boolean;
129
+ }
121
130
  export interface ViewerBookmark {
122
131
  id: string;
123
132
  label: string;
@@ -154,6 +163,7 @@ export interface InteractiveViewerOptions extends ViewerRenderOptions {
154
163
  source?: string;
155
164
  document?: WorldOrbitDocument;
156
165
  scene?: RenderScene;
166
+ spatialScene?: SpatialScene;
157
167
  initialViewpointId?: string;
158
168
  initialSelectionObjectId?: string;
159
169
  initialFilter?: ViewerFilter | null;
@@ -194,11 +204,18 @@ export interface WorldOrbitViewer {
194
204
  getScene(): RenderScene;
195
205
  getRenderOptions(): ViewerRenderOptions;
196
206
  setRenderOptions(options: Partial<ViewerRenderOptions>): void;
207
+ getViewMode(): WorldOrbitViewMode;
208
+ setViewMode(mode: WorldOrbitViewMode): void;
197
209
  listViewpoints(): RenderSceneViewpoint[];
198
210
  getActiveViewpoint(): RenderSceneViewpoint | null;
199
211
  goToViewpoint(id: string): boolean;
200
212
  getActiveEventId(): string | null;
201
213
  setActiveEvent(id: string | null): void;
214
+ playAnimation(): void;
215
+ pauseAnimation(): void;
216
+ resetAnimation(): void;
217
+ setAnimationSpeed(multiplier: number): void;
218
+ getAnimationState(): ViewerAnimationState;
202
219
  search(query: string, limit?: number): ViewerSearchResult[];
203
220
  getFilter(): ViewerFilter | null;
204
221
  setFilter(filter: ViewerFilter | null): void;
@@ -250,11 +267,13 @@ export interface WorldOrbitEmbedPayload {
250
267
  version: "2.0";
251
268
  mode: WorldOrbitEmbedMode;
252
269
  scene: RenderScene;
270
+ spatialScene?: SpatialScene;
253
271
  options?: {
254
272
  theme?: WorldOrbitTheme | WorldOrbitThemeName;
255
273
  layers?: ViewerLayerOptions;
256
274
  subtitle?: string;
257
275
  preset?: SceneRenderOptions["preset"];
276
+ viewMode?: WorldOrbitViewMode;
258
277
  initialViewpointId?: string;
259
278
  initialSelectionObjectId?: string;
260
279
  initialFilter?: ViewerFilter | null;