@jgengine/core 0.10.0 → 0.11.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 (607) hide show
  1. package/CHANGELOG.md +13 -2
  2. package/LICENSE +203 -661
  3. package/README.md +1 -1
  4. package/dist/ai/crowd.d.ts +55 -0
  5. package/dist/ai/crowd.js +114 -0
  6. package/dist/ai/flock.d.ts +5 -2
  7. package/dist/ai/flock.js +5 -2
  8. package/dist/ai/groupAssist.d.ts +1 -0
  9. package/dist/ai/groupAssist.js +1 -0
  10. package/dist/ai/heatSystem.d.ts +76 -0
  11. package/dist/ai/heatSystem.js +97 -0
  12. package/dist/ai/interestScheduler.d.ts +107 -0
  13. package/dist/ai/interestScheduler.js +118 -0
  14. package/dist/ai/jobBoard.d.ts +1 -0
  15. package/dist/ai/jobBoard.js +1 -0
  16. package/dist/ai/laneSelect.d.ts +5 -2
  17. package/dist/ai/laneSelect.js +5 -2
  18. package/dist/ai/mobBrain.d.ts +1 -0
  19. package/dist/ai/mobBrain.js +1 -0
  20. package/dist/ai/spawnDirector.d.ts +7 -2
  21. package/dist/ai/spawnDirector.js +18 -15
  22. package/dist/ai/spawnPoint.d.ts +3 -1
  23. package/dist/ai/spawnPoint.js +3 -1
  24. package/dist/ai/targetAcquisition.d.ts +84 -0
  25. package/dist/ai/targetAcquisition.js +92 -0
  26. package/dist/anim/easing.d.ts +19 -0
  27. package/dist/anim/easing.js +19 -0
  28. package/dist/anim/oscillator.d.ts +12 -0
  29. package/dist/anim/oscillator.js +25 -0
  30. package/dist/area/areaEffectField.d.ts +127 -0
  31. package/dist/area/areaEffectField.js +175 -0
  32. package/dist/area/stackPolicy.d.ts +47 -0
  33. package/dist/area/stackPolicy.js +99 -0
  34. package/dist/authoring.d.ts +1 -0
  35. package/dist/authoring.js +1 -0
  36. package/dist/board/laneBoard.d.ts +13 -0
  37. package/dist/board/laneBoard.js +13 -0
  38. package/dist/board/timelineBoard.d.ts +10 -0
  39. package/dist/board/timelineBoard.js +10 -0
  40. package/dist/combat/abilityKit.d.ts +18 -0
  41. package/dist/combat/abilityKit.js +24 -9
  42. package/dist/combat/animationState.d.ts +5 -0
  43. package/dist/combat/animationState.js +5 -0
  44. package/dist/combat/breakMeters.d.ts +10 -0
  45. package/dist/combat/breakMeters.js +10 -0
  46. package/dist/combat/castRunner.d.ts +5 -0
  47. package/dist/combat/castRunner.js +5 -0
  48. package/dist/combat/comboPoints.d.ts +5 -0
  49. package/dist/combat/comboPoints.js +5 -0
  50. package/dist/combat/comboString.d.ts +5 -0
  51. package/dist/combat/comboString.js +5 -0
  52. package/dist/combat/damageInterceptors.d.ts +192 -0
  53. package/dist/combat/damageInterceptors.js +251 -0
  54. package/dist/combat/damageMatchup.d.ts +68 -0
  55. package/dist/combat/damageMatchup.js +42 -0
  56. package/dist/combat/damageResolution.d.ts +63 -0
  57. package/dist/combat/damageResolution.js +50 -0
  58. package/dist/combat/death.d.ts +7 -1
  59. package/dist/combat/death.js +5 -0
  60. package/dist/combat/deathReason.d.ts +14 -0
  61. package/dist/combat/deathReason.js +1 -0
  62. package/dist/combat/defensiveWindow.d.ts +5 -0
  63. package/dist/combat/defensiveWindow.js +5 -0
  64. package/dist/combat/dotField.d.ts +5 -1
  65. package/dist/combat/dotField.js +5 -1
  66. package/dist/combat/downed.d.ts +5 -0
  67. package/dist/combat/downed.js +5 -0
  68. package/dist/combat/effects.d.ts +5 -0
  69. package/dist/combat/effects.js +5 -0
  70. package/dist/combat/encounterSequence.d.ts +258 -0
  71. package/dist/combat/encounterSequence.js +426 -0
  72. package/dist/combat/hitReaction.d.ts +57 -1
  73. package/dist/combat/hitReaction.js +45 -5
  74. package/dist/combat/magazine.d.ts +54 -0
  75. package/dist/combat/magazine.js +96 -0
  76. package/dist/combat/projectiles.d.ts +5 -0
  77. package/dist/combat/projectiles.js +32 -14
  78. package/dist/combat/receivedDamage.d.ts +117 -0
  79. package/dist/combat/receivedDamage.js +92 -0
  80. package/dist/combat/regenShield.d.ts +5 -1
  81. package/dist/combat/regenShield.js +5 -1
  82. package/dist/combat/renderCues.d.ts +51 -0
  83. package/dist/combat/renderCues.js +44 -0
  84. package/dist/combat/resourcePool.d.ts +5 -0
  85. package/dist/combat/resourcePool.js +5 -0
  86. package/dist/combat/rewardAllocation.d.ts +121 -0
  87. package/dist/combat/rewardAllocation.js +251 -0
  88. package/dist/combat/shotOrigin.d.ts +18 -1
  89. package/dist/combat/shotOrigin.js +39 -0
  90. package/dist/combat/statusApplication.d.ts +96 -0
  91. package/dist/combat/statusApplication.js +81 -0
  92. package/dist/combat/telegraph.d.ts +11 -2
  93. package/dist/combat/telegraph.js +11 -2
  94. package/dist/combat/thresholdCrossings.d.ts +85 -0
  95. package/dist/combat/thresholdCrossings.js +116 -0
  96. package/dist/combat.d.ts +34 -0
  97. package/dist/combat.js +34 -0
  98. package/dist/commands/commandRegistry.d.ts +11 -0
  99. package/dist/commands/commandRegistry.js +9 -2
  100. package/dist/crafting/crop.d.ts +18 -0
  101. package/dist/crafting/crop.js +18 -0
  102. package/dist/crafting/production.d.ts +5 -0
  103. package/dist/crafting/production.js +5 -0
  104. package/dist/devtools/rewriteTunables.d.ts +17 -0
  105. package/dist/devtools/rewriteTunables.js +276 -0
  106. package/dist/devtools/saveEndpoint.d.ts +46 -0
  107. package/dist/devtools/saveEndpoint.js +48 -0
  108. package/dist/devtools/transformTunables.d.ts +3 -0
  109. package/dist/devtools/transformTunables.js +3 -0
  110. package/dist/devtools/tunableSchema.d.ts +31 -0
  111. package/dist/devtools/tunableSchema.js +31 -0
  112. package/dist/economy/currency.d.ts +12 -1
  113. package/dist/economy/currency.js +12 -1
  114. package/dist/economy/listingBook.d.ts +91 -0
  115. package/dist/economy/listingBook.js +144 -0
  116. package/dist/economy/resourceLedger.d.ts +222 -0
  117. package/dist/economy/resourceLedger.js +353 -0
  118. package/dist/economy/sharedWallet.d.ts +14 -0
  119. package/dist/economy/sharedWallet.js +14 -0
  120. package/dist/economy/techTree.d.ts +12 -0
  121. package/dist/economy/techTree.js +12 -0
  122. package/dist/economy/wallet.d.ts +26 -2
  123. package/dist/economy/wallet.js +35 -6
  124. package/dist/editor/commands.d.ts +190 -7
  125. package/dist/editor/commands.js +727 -55
  126. package/dist/editor/document.d.ts +159 -13
  127. package/dist/editor/document.js +750 -19
  128. package/dist/editor/grid.d.ts +229 -0
  129. package/dist/editor/grid.js +366 -0
  130. package/dist/editor/gridAdapters.d.ts +80 -0
  131. package/dist/editor/gridAdapters.js +134 -0
  132. package/dist/editor/index.d.ts +73 -6
  133. package/dist/editor/index.js +6 -2
  134. package/dist/editor/liveSync.d.ts +127 -0
  135. package/dist/editor/liveSync.js +249 -0
  136. package/dist/editor/runtimeInspector.d.ts +88 -0
  137. package/dist/editor/runtimeInspector.js +239 -0
  138. package/dist/editor/types.d.ts +107 -1
  139. package/dist/faction/reputation.d.ts +5 -0
  140. package/dist/faction/reputation.js +5 -0
  141. package/dist/format/distance.d.ts +17 -0
  142. package/dist/format/distance.js +18 -0
  143. package/dist/format/duration.d.ts +27 -0
  144. package/dist/format/duration.js +45 -0
  145. package/dist/format/speed.d.ts +17 -0
  146. package/dist/format/speed.js +25 -0
  147. package/dist/game/connectedPlayers.d.ts +6 -4
  148. package/dist/game/connectedPlayers.js +2 -2
  149. package/dist/game/cosmetics.d.ts +9 -0
  150. package/dist/game/cosmetics.js +16 -0
  151. package/dist/game/defineGame.d.ts +100 -2
  152. package/dist/game/defineGame.js +39 -2
  153. package/dist/game/defineSystem.d.ts +88 -0
  154. package/dist/game/defineSystem.js +45 -0
  155. package/dist/game/dialogue.d.ts +33 -0
  156. package/dist/game/dialogue.js +21 -0
  157. package/dist/game/events.d.ts +35 -13
  158. package/dist/game/events.js +5 -0
  159. package/dist/game/feed.d.ts +33 -0
  160. package/dist/game/feed.js +35 -2
  161. package/dist/game/gamePhase.d.ts +11 -0
  162. package/dist/game/gamePhase.js +16 -0
  163. package/dist/game/leaderboard.d.ts +5 -0
  164. package/dist/game/leaderboard.js +5 -0
  165. package/dist/game/loadout.d.ts +5 -0
  166. package/dist/game/loadout.js +5 -0
  167. package/dist/game/lootFilter.d.ts +2 -0
  168. package/dist/game/lootFilter.js +2 -0
  169. package/dist/game/lootPipeline.d.ts +164 -0
  170. package/dist/game/lootPipeline.js +216 -0
  171. package/dist/game/lootTable.d.ts +19 -2
  172. package/dist/game/lootTable.js +15 -5
  173. package/dist/game/objectives.d.ts +43 -0
  174. package/dist/game/objectives.js +36 -0
  175. package/dist/game/paramLayers.d.ts +148 -0
  176. package/dist/game/paramLayers.js +185 -0
  177. package/dist/game/ping.d.ts +5 -0
  178. package/dist/game/ping.js +5 -0
  179. package/dist/game/playableGame.d.ts +92 -7
  180. package/dist/game/quest.d.ts +8 -0
  181. package/dist/game/quest.js +29 -0
  182. package/dist/game/race.d.ts +141 -0
  183. package/dist/game/race.js +169 -0
  184. package/dist/game/recordBook.d.ts +3 -1
  185. package/dist/game/recordBook.js +4 -1
  186. package/dist/game/ruleSelection.d.ts +75 -0
  187. package/dist/game/ruleSelection.js +127 -0
  188. package/dist/game/runDraft.d.ts +5 -0
  189. package/dist/game/runDraft.js +5 -0
  190. package/dist/game/saveStore.d.ts +111 -0
  191. package/dist/game/saveStore.js +312 -0
  192. package/dist/game/snapshotHistory.d.ts +67 -0
  193. package/dist/game/snapshotHistory.js +95 -0
  194. package/dist/game/social.d.ts +38 -1
  195. package/dist/game/social.js +71 -0
  196. package/dist/game/spawnPoints.d.ts +5 -0
  197. package/dist/game/spawnPoints.js +5 -0
  198. package/dist/game/systemRuntime.d.ts +50 -0
  199. package/dist/game/systemRuntime.js +157 -0
  200. package/dist/game/systemSchedule.d.ts +72 -0
  201. package/dist/game/systemSchedule.js +242 -0
  202. package/dist/game/toasts.d.ts +43 -0
  203. package/dist/game/toasts.js +44 -0
  204. package/dist/game/trade.d.ts +10 -0
  205. package/dist/game/trade.js +10 -0
  206. package/dist/game/unlocks.d.ts +8 -0
  207. package/dist/game/unlocks.js +16 -0
  208. package/dist/game/vfxInstance.d.ts +138 -0
  209. package/dist/game/vfxInstance.js +96 -0
  210. package/dist/game/worldItem.d.ts +17 -4
  211. package/dist/game/worldItem.js +17 -4
  212. package/dist/gameplay.d.ts +91 -0
  213. package/dist/gameplay.js +91 -0
  214. package/dist/index.d.ts +5 -14
  215. package/dist/index.js +5 -14
  216. package/dist/input/actionBindings.d.ts +23 -6
  217. package/dist/input/actionBindings.js +23 -6
  218. package/dist/input/axisInput.d.ts +7 -2
  219. package/dist/input/axisInput.js +7 -2
  220. package/dist/input/controlGroups.d.ts +67 -0
  221. package/dist/input/controlGroups.js +41 -0
  222. package/dist/input/touchScheme.d.ts +82 -6
  223. package/dist/input/touchScheme.js +123 -10
  224. package/dist/interaction/lockpick.d.ts +61 -0
  225. package/dist/interaction/lockpick.js +168 -0
  226. package/dist/interaction/proximityPrompt.d.ts +2 -0
  227. package/dist/interaction/proximityPrompt.js +2 -0
  228. package/dist/interaction/qte.d.ts +5 -0
  229. package/dist/interaction/qte.js +5 -0
  230. package/dist/interaction/skillCheck.d.ts +5 -0
  231. package/dist/interaction/skillCheck.js +5 -0
  232. package/dist/inventory/inventoryModel.d.ts +12 -0
  233. package/dist/inventory/inventoryModel.js +12 -0
  234. package/dist/inventory/shapedGrid.d.ts +16 -0
  235. package/dist/inventory/shapedGrid.js +16 -0
  236. package/dist/inventory/slotModel.d.ts +10 -0
  237. package/dist/inventory/slotModel.js +10 -0
  238. package/dist/item/durability.d.ts +5 -0
  239. package/dist/item/durability.js +5 -0
  240. package/dist/item/itemIdentity.d.ts +171 -0
  241. package/dist/item/itemIdentity.js +138 -0
  242. package/dist/item/itemInstanceRegistry.d.ts +32 -0
  243. package/dist/item/itemInstanceRegistry.js +34 -0
  244. package/dist/item/itemgen.d.ts +163 -0
  245. package/dist/item/itemgen.js +151 -0
  246. package/dist/item/modularItem.d.ts +5 -0
  247. package/dist/item/modularItem.js +5 -0
  248. package/dist/item/use.d.ts +5 -0
  249. package/dist/item/use.js +5 -0
  250. package/dist/item/useBehavior.d.ts +142 -0
  251. package/dist/item/useBehavior.js +105 -0
  252. package/dist/item/weapon.d.ts +5 -0
  253. package/dist/item/weapon.js +5 -0
  254. package/dist/math/scalar.d.ts +25 -0
  255. package/dist/math/scalar.js +47 -0
  256. package/dist/meta/changelog.d.ts +4 -1
  257. package/dist/meta/changelog.js +16 -2
  258. package/dist/movement/avoidance.d.ts +45 -0
  259. package/dist/movement/avoidance.js +123 -0
  260. package/dist/movement/cameraRig.d.ts +8 -0
  261. package/dist/movement/cameraRig.js +8 -0
  262. package/dist/movement/dash.d.ts +11 -0
  263. package/dist/movement/dash.js +11 -0
  264. package/dist/movement/formation.d.ts +135 -0
  265. package/dist/movement/formation.js +194 -0
  266. package/dist/movement/glideModel.d.ts +5 -0
  267. package/dist/movement/glideModel.js +5 -0
  268. package/dist/movement/grappleSwing.d.ts +5 -0
  269. package/dist/movement/grappleSwing.js +5 -0
  270. package/dist/movement/leaderTrail.d.ts +5 -0
  271. package/dist/movement/leaderTrail.js +5 -0
  272. package/dist/movement/movementModel.d.ts +35 -8
  273. package/dist/movement/movementModel.js +42 -14
  274. package/dist/movement/playerMovement.js +65 -10
  275. package/dist/movement/poseState.d.ts +13 -0
  276. package/dist/movement/poseState.js +16 -0
  277. package/dist/movement/steering.d.ts +8 -0
  278. package/dist/movement/steering.js +18 -0
  279. package/dist/multiplayer/combatSnapshot.d.ts +3 -0
  280. package/dist/multiplayer/combatSnapshot.js +3 -0
  281. package/dist/multiplayer/lagCompensation.d.ts +5 -0
  282. package/dist/multiplayer/lagCompensation.js +5 -0
  283. package/dist/multiplayer/presenceModel.d.ts +9 -1
  284. package/dist/multiplayer/presenceModel.js +9 -1
  285. package/dist/multiplayer/simultaneousCommit.d.ts +3 -0
  286. package/dist/multiplayer/simultaneousCommit.js +3 -0
  287. package/dist/multiplayer.d.ts +11 -0
  288. package/dist/multiplayer.js +11 -0
  289. package/dist/nav/pathFollow.d.ts +57 -0
  290. package/dist/nav/pathFollow.js +109 -0
  291. package/dist/orders/orderKinds.d.ts +156 -0
  292. package/dist/orders/orderKinds.js +197 -0
  293. package/dist/orders/orderQueue.d.ts +208 -0
  294. package/dist/orders/orderQueue.js +211 -0
  295. package/dist/physics/drivableVehicle.d.ts +29 -0
  296. package/dist/physics/drivableVehicle.js +16 -0
  297. package/dist/physics/kinematicVehicle.d.ts +21 -1
  298. package/dist/physics/kinematicVehicle.js +23 -8
  299. package/dist/physics/physicsWorld.d.ts +24 -12
  300. package/dist/physics/physicsWorld.js +11 -5
  301. package/dist/physics/radialImpulse.d.ts +25 -0
  302. package/dist/physics/radialImpulse.js +27 -0
  303. package/dist/procedural.d.ts +3 -0
  304. package/dist/procedural.js +3 -0
  305. package/dist/progression/statGraph.d.ts +116 -0
  306. package/dist/progression/statGraph.js +318 -0
  307. package/dist/puzzle/cellGrid.d.ts +9 -0
  308. package/dist/puzzle/cellGrid.js +9 -0
  309. package/dist/puzzle/fallingPiece.d.ts +9 -0
  310. package/dist/puzzle/fallingPiece.js +9 -0
  311. package/dist/puzzle/nonogram.d.ts +39 -0
  312. package/dist/puzzle/nonogram.js +136 -0
  313. package/dist/random/nameGen.d.ts +5 -0
  314. package/dist/random/nameGen.js +5 -0
  315. package/dist/random/pick.d.ts +8 -0
  316. package/dist/random/pick.js +31 -0
  317. package/dist/random/rng.d.ts +22 -0
  318. package/dist/random/rng.js +28 -8
  319. package/dist/random/seedLink.d.ts +4 -0
  320. package/dist/random/seedLink.js +4 -0
  321. package/dist/relation/keyedValues.d.ts +54 -0
  322. package/dist/relation/keyedValues.js +115 -0
  323. package/dist/relation/thresholds.d.ts +62 -0
  324. package/dist/relation/thresholds.js +62 -0
  325. package/dist/render/color.d.ts +12 -0
  326. package/dist/render/color.js +26 -0
  327. package/dist/render/lookPreset.d.ts +41 -0
  328. package/dist/render/lookPreset.js +29 -0
  329. package/dist/render/postProcessing.d.ts +20 -0
  330. package/dist/render/postProcessing.js +21 -1
  331. package/dist/rules/predicate.d.ts +53 -0
  332. package/dist/rules/predicate.js +64 -0
  333. package/dist/rules/ruleEffects.d.ts +38 -0
  334. package/dist/rules/ruleEffects.js +37 -0
  335. package/dist/rules/triggeredRules.d.ts +160 -0
  336. package/dist/rules/triggeredRules.js +241 -0
  337. package/dist/runtime/adapter.d.ts +42 -3
  338. package/dist/runtime/adapter.js +44 -1
  339. package/dist/runtime/cameraDirector.d.ts +1 -0
  340. package/dist/runtime/cameraDirector.js +1 -0
  341. package/dist/runtime/commandRunner.d.ts +1 -0
  342. package/dist/runtime/commandRunner.js +1 -0
  343. package/dist/runtime/context/combatFx.d.ts +23 -0
  344. package/dist/runtime/context/combatFx.js +161 -0
  345. package/dist/runtime/context/registries.d.ts +13 -0
  346. package/dist/runtime/context/registries.js +84 -0
  347. package/dist/runtime/context/worldItems.d.ts +21 -0
  348. package/dist/runtime/context/worldItems.js +37 -0
  349. package/dist/runtime/descriptors/baseline.d.ts +48 -0
  350. package/dist/runtime/descriptors/baseline.js +134 -0
  351. package/dist/runtime/descriptors/features.d.ts +74 -0
  352. package/dist/runtime/descriptors/features.js +281 -0
  353. package/dist/runtime/gameContext.d.ts +114 -13
  354. package/dist/runtime/gameContext.js +303 -395
  355. package/dist/runtime/gameRuntime.d.ts +1 -0
  356. package/dist/runtime/gameRuntime.js +1 -0
  357. package/dist/runtime/headlessRunner.d.ts +60 -0
  358. package/dist/runtime/headlessRunner.js +44 -0
  359. package/dist/runtime/hostPersistence.d.ts +12 -0
  360. package/dist/runtime/hostPersistence.js +12 -0
  361. package/dist/runtime/hostedGameRunner.d.ts +8 -3
  362. package/dist/runtime/hostedGameRunner.js +26 -3
  363. package/dist/runtime/hostedWorldSession.d.ts +12 -4
  364. package/dist/runtime/hostedWorldSession.js +11 -4
  365. package/dist/runtime/inputSnapshot.d.ts +8 -3
  366. package/dist/runtime/inputSnapshot.js +6 -2
  367. package/dist/runtime/motionIntents.d.ts +11 -2
  368. package/dist/runtime/motionIntents.js +16 -2
  369. package/dist/runtime/perContext.d.ts +15 -0
  370. package/dist/runtime/perContext.js +21 -0
  371. package/dist/runtime/runtimeSave.d.ts +79 -0
  372. package/dist/runtime/runtimeSave.js +105 -0
  373. package/dist/runtime/save.d.ts +4 -0
  374. package/dist/runtime/save.js +4 -0
  375. package/dist/runtime/snapshot.d.ts +7 -0
  376. package/dist/runtime/snapshot.js +7 -0
  377. package/dist/runtime/visibility.d.ts +2 -1
  378. package/dist/runtime/visibility.js +2 -1
  379. package/dist/runtime/worldChannel.d.ts +7 -3
  380. package/dist/runtime/worldChannel.js +51 -6
  381. package/dist/runtime/worldMirror.d.ts +14 -2
  382. package/dist/runtime/worldMirror.js +15 -2
  383. package/dist/runtime/worldProjection.d.ts +47 -0
  384. package/dist/runtime/worldProjection.js +52 -0
  385. package/dist/runtime/worldReplication.d.ts +30 -7
  386. package/dist/runtime/worldReplication.js +41 -9
  387. package/dist/runtime/worldSnapshot.d.ts +30 -3
  388. package/dist/runtime/worldSnapshot.js +20 -5
  389. package/dist/scene/assetCatalog.d.ts +21 -0
  390. package/dist/scene/assetCatalog.js +4 -0
  391. package/dist/scene/assetDiagnostics.d.ts +69 -0
  392. package/dist/scene/assetDiagnostics.js +110 -0
  393. package/dist/scene/assetGenerator.d.ts +65 -0
  394. package/dist/scene/assetGenerator.js +64 -0
  395. package/dist/scene/assetSpace.d.ts +137 -0
  396. package/dist/scene/assetSpace.js +259 -0
  397. package/dist/scene/authoredTriggers.d.ts +169 -0
  398. package/dist/scene/authoredTriggers.js +340 -0
  399. package/dist/scene/behaviorRuntime.d.ts +75 -0
  400. package/dist/scene/behaviorRuntime.js +217 -0
  401. package/dist/scene/behaviors.d.ts +14 -2
  402. package/dist/scene/behaviors.js +7 -2
  403. package/dist/scene/bodyBind.d.ts +60 -0
  404. package/dist/scene/bodyBind.js +51 -0
  405. package/dist/scene/builtinSceneKinds.d.ts +5 -0
  406. package/dist/scene/builtinSceneKinds.js +62 -0
  407. package/dist/scene/colliders.d.ts +13 -1
  408. package/dist/scene/colliders.js +37 -1
  409. package/dist/scene/entityStats.d.ts +11 -2
  410. package/dist/scene/entityStats.js +11 -2
  411. package/dist/scene/entityStore.d.ts +12 -1
  412. package/dist/scene/entityStore.js +15 -0
  413. package/dist/scene/facing.d.ts +18 -0
  414. package/dist/scene/facing.js +26 -0
  415. package/dist/scene/modelSockets.d.ts +33 -0
  416. package/dist/scene/modelSockets.js +29 -0
  417. package/dist/scene/objectQuery.d.ts +2 -0
  418. package/dist/scene/objectQuery.js +2 -0
  419. package/dist/scene/objectStore.d.ts +4 -0
  420. package/dist/scene/objectStore.js +6 -0
  421. package/dist/scene/possession.d.ts +8 -0
  422. package/dist/scene/possession.js +14 -0
  423. package/dist/scene/roster.d.ts +3 -0
  424. package/dist/scene/roster.js +12 -0
  425. package/dist/scene/sceneKinds.d.ts +240 -0
  426. package/dist/scene/sceneKinds.js +214 -0
  427. package/dist/scene/sceneOwnership.d.ts +169 -0
  428. package/dist/scene/sceneOwnership.js +179 -0
  429. package/dist/scene/selectionBookmarks.d.ts +93 -0
  430. package/dist/scene/selectionBookmarks.js +122 -0
  431. package/dist/scene/vehicleSeat.d.ts +68 -0
  432. package/dist/scene/vehicleSeat.js +59 -0
  433. package/dist/sensor/concealment.d.ts +3 -0
  434. package/dist/sensor/concealment.js +3 -0
  435. package/dist/sensor/freezeMonitor.d.ts +1 -0
  436. package/dist/sensor/freezeMonitor.js +1 -0
  437. package/dist/sensor/frustumSensor.d.ts +7 -3
  438. package/dist/sensor/frustumSensor.js +7 -3
  439. package/dist/sensor/hiddenStateProbe.d.ts +5 -2
  440. package/dist/sensor/hiddenStateProbe.js +5 -2
  441. package/dist/sensor/recordingBuffer.d.ts +2 -1
  442. package/dist/sensor/recordingBuffer.js +2 -1
  443. package/dist/sensor/replayLoop.d.ts +6 -2
  444. package/dist/sensor/replayLoop.js +6 -2
  445. package/dist/sensor/revealQuery.d.ts +2 -1
  446. package/dist/sensor/revealQuery.js +2 -1
  447. package/dist/sensor/visionCone.d.ts +10 -3
  448. package/dist/sensor/visionCone.js +10 -3
  449. package/dist/session/contestedChannel.d.ts +1 -0
  450. package/dist/session/contestedChannel.js +1 -0
  451. package/dist/session/extraction.d.ts +1 -0
  452. package/dist/session/extraction.js +1 -0
  453. package/dist/session/roles.d.ts +6 -0
  454. package/dist/session/roles.js +6 -0
  455. package/dist/session/roundState.d.ts +8 -0
  456. package/dist/session/roundState.js +2 -0
  457. package/dist/settings/settingsModel.d.ts +1 -0
  458. package/dist/settings/settingsModel.js +1 -0
  459. package/dist/stats/accumulatorMeter.d.ts +6 -0
  460. package/dist/stats/accumulatorMeter.js +6 -0
  461. package/dist/stats/eventMeter.d.ts +5 -0
  462. package/dist/stats/eventMeter.js +5 -0
  463. package/dist/stats/rollCheck.d.ts +5 -0
  464. package/dist/stats/rollCheck.js +5 -0
  465. package/dist/stats/statModifiers.d.ts +5 -0
  466. package/dist/stats/statModifiers.js +5 -0
  467. package/dist/store/defineKeyedStore.d.ts +38 -0
  468. package/dist/store/defineKeyedStore.js +42 -0
  469. package/dist/store/defineStore.d.ts +33 -0
  470. package/dist/store/defineStore.js +35 -0
  471. package/dist/store/observableKeyedStore.d.ts +5 -0
  472. package/dist/store/observableKeyedStore.js +34 -2
  473. package/dist/survival/decayMeter.d.ts +55 -0
  474. package/dist/survival/decayMeter.js +130 -55
  475. package/dist/survival/moodle.d.ts +2 -0
  476. package/dist/survival/regionHealth.d.ts +6 -0
  477. package/dist/survival/regionHealth.js +5 -0
  478. package/dist/tactics/fallingGrid.d.ts +4 -2
  479. package/dist/tactics/fallingGrid.js +4 -2
  480. package/dist/tactics/predictiveQuery.d.ts +3 -0
  481. package/dist/tactics/predictiveQuery.js +3 -0
  482. package/dist/tactics/snapshot.d.ts +2 -0
  483. package/dist/tactics/snapshot.js +2 -0
  484. package/dist/tactics/surface.d.ts +1 -0
  485. package/dist/tactics/surface.js +1 -0
  486. package/dist/tactics/tacticalGrid.d.ts +1 -0
  487. package/dist/tactics/tacticalGrid.js +1 -0
  488. package/dist/time/beatClock.d.ts +14 -4
  489. package/dist/time/beatClock.js +14 -4
  490. package/dist/time/calendarClock.d.ts +3 -0
  491. package/dist/time/calendarClock.js +3 -0
  492. package/dist/time/idleProgress.d.ts +4 -0
  493. package/dist/time/idleProgress.js +4 -0
  494. package/dist/time/simClock.d.ts +2 -0
  495. package/dist/time/simClock.js +20 -5
  496. package/dist/ui/actionModel.d.ts +110 -0
  497. package/dist/ui/actionModel.js +159 -0
  498. package/dist/ui/gameLayout.d.ts +30 -11
  499. package/dist/ui/gameLayout.js +30 -11
  500. package/dist/ui/hudDocument.d.ts +114 -0
  501. package/dist/ui/hudDocument.js +220 -0
  502. package/dist/ui/hudLayout.d.ts +33 -1
  503. package/dist/ui/hudLayout.js +204 -17
  504. package/dist/ui/selectionModel.d.ts +92 -0
  505. package/dist/ui/selectionModel.js +88 -0
  506. package/dist/ui/tooltipModel.d.ts +63 -0
  507. package/dist/ui/tooltipModel.js +82 -0
  508. package/dist/ui.d.ts +15 -0
  509. package/dist/ui.js +15 -0
  510. package/dist/visibility/bounds.d.ts +8 -1
  511. package/dist/visibility/bounds.js +8 -1
  512. package/dist/visibility/frustum.d.ts +12 -3
  513. package/dist/visibility/frustum.js +12 -3
  514. package/dist/work/jobQueue.d.ts +201 -0
  515. package/dist/work/jobQueue.js +253 -0
  516. package/dist/work/unitTraining.d.ts +58 -0
  517. package/dist/work/unitTraining.js +52 -0
  518. package/dist/world/authoredObjects.d.ts +58 -0
  519. package/dist/world/authoredObjects.js +69 -0
  520. package/dist/world/buildingGenerator.d.ts +18 -0
  521. package/dist/world/buildingGenerator.js +62 -0
  522. package/dist/world/buildings.d.ts +5 -0
  523. package/dist/world/buildings.js +5 -0
  524. package/dist/world/catenary.d.ts +22 -0
  525. package/dist/world/catenary.js +69 -0
  526. package/dist/world/features.d.ts +115 -7
  527. package/dist/world/features.js +56 -5
  528. package/dist/world/footprintGrid.d.ts +59 -0
  529. package/dist/world/footprintGrid.js +141 -0
  530. package/dist/world/geometry.d.ts +64 -0
  531. package/dist/world/geometry.js +94 -0
  532. package/dist/world/grassKind.d.ts +51 -0
  533. package/dist/world/grassKind.js +101 -0
  534. package/dist/world/pathInstances.d.ts +27 -0
  535. package/dist/world/pathInstances.js +27 -0
  536. package/dist/world/pathTerrain.d.ts +80 -0
  537. package/dist/world/pathTerrain.js +142 -0
  538. package/dist/world/placeAsset.d.ts +81 -0
  539. package/dist/world/placeAsset.js +77 -0
  540. package/dist/world/placement.d.ts +4 -0
  541. package/dist/world/placement.js +4 -0
  542. package/dist/world/placementController.d.ts +6 -0
  543. package/dist/world/placementController.js +6 -0
  544. package/dist/world/polyline.d.ts +34 -0
  545. package/dist/world/polyline.js +81 -0
  546. package/dist/world/roads.d.ts +8 -0
  547. package/dist/world/roads.js +38 -0
  548. package/dist/world/scatterRegion.d.ts +164 -0
  549. package/dist/world/scatterRegion.js +409 -0
  550. package/dist/world/sceneShapes.d.ts +43 -0
  551. package/dist/world/sceneShapes.js +1 -0
  552. package/dist/world/segment.d.ts +27 -0
  553. package/dist/world/segment.js +43 -0
  554. package/dist/world/soilKind.d.ts +48 -0
  555. package/dist/world/soilKind.js +92 -0
  556. package/dist/world/spatialSample.d.ts +241 -0
  557. package/dist/world/spatialSample.js +465 -0
  558. package/dist/world/terraform.d.ts +213 -1
  559. package/dist/world/terraform.js +655 -20
  560. package/dist/world/terrain.d.ts +119 -20
  561. package/dist/world/terrain.js +247 -41
  562. package/dist/world/terrainGuides.d.ts +182 -0
  563. package/dist/world/terrainGuides.js +343 -0
  564. package/dist/world/vec2.d.ts +81 -0
  565. package/dist/world/vec2.js +128 -0
  566. package/dist/world/vec3.d.ts +49 -0
  567. package/dist/world/vec3.js +76 -0
  568. package/dist/world/vegetation.d.ts +71 -0
  569. package/dist/world/vegetation.js +151 -0
  570. package/dist/world/visibilityField.d.ts +154 -0
  571. package/dist/world/visibilityField.js +271 -0
  572. package/dist/world/volumetricClouds.d.ts +52 -0
  573. package/dist/world/volumetricClouds.js +43 -0
  574. package/dist/world/walls.d.ts +9 -0
  575. package/dist/world/walls.js +9 -0
  576. package/dist/world/waterKind.d.ts +55 -0
  577. package/dist/world/waterKind.js +99 -0
  578. package/dist/world.d.ts +132 -0
  579. package/dist/world.js +132 -0
  580. package/package.json +32 -8
  581. package/skills/jgengine/SKILL.md +51 -0
  582. package/skills/jgengine/api.md +434 -0
  583. package/skills/jgengine/capabilities.md +29 -0
  584. package/skills/jgengine/reference-cartridge.md +72 -0
  585. package/skills/jgengine-combat/SKILL.md +34 -0
  586. package/skills/jgengine-combat/api.md +549 -0
  587. package/skills/jgengine-combat/capabilities.md +169 -0
  588. package/skills/jgengine-combat/reference.md +98 -0
  589. package/skills/jgengine-gameplay/SKILL.md +39 -0
  590. package/skills/jgengine-gameplay/api.md +1794 -0
  591. package/skills/jgengine-gameplay/capabilities.md +378 -0
  592. package/skills/jgengine-gameplay/reference-systems.md +60 -0
  593. package/skills/jgengine-world/SKILL.md +38 -0
  594. package/skills/jgengine-world/api.md +2652 -0
  595. package/skills/jgengine-world/capabilities.md +370 -0
  596. package/skills/jgengine-world/reference.md +222 -0
  597. package/dist/cartridge/runtime.d.ts +0 -15
  598. package/dist/cartridge/runtime.js +0 -556
  599. package/dist/cartridge/spec.d.ts +0 -188
  600. package/dist/cartridge/spec.js +0 -19
  601. package/dist/cartridge/validate.d.ts +0 -2
  602. package/dist/cartridge/validate.js +0 -78
  603. package/dist/store/engineStore.d.ts +0 -22
  604. package/dist/store/engineStore.js +0 -50
  605. package/dist/store/features.d.ts +0 -10
  606. package/dist/store/features.js +0 -23
  607. package/llms.txt +0 -5389
@@ -1,4 +1,33 @@
1
- /** Builds a fresh, empty editor document to start authoring a scene from scratch. */
1
+ import { cloneEditorUiDocument, decodeEditorUiDocument } from "../ui/hudDocument.js";
2
+ import { migrateTerrainSnapshot } from "../world/terraform.js";
3
+ import { cloneGridLayer, migrateGridLayer, } from "./grid.js";
4
+ function migrateGrids(grids) {
5
+ return grids === undefined ? undefined : grids.map(migrateGridLayer);
6
+ }
7
+ function upsertGrids(base, overlay) {
8
+ if (base === undefined && overlay === undefined)
9
+ return undefined;
10
+ const byId = new Map();
11
+ for (const layer of base ?? [])
12
+ byId.set(layer.id, cloneGridLayer(layer));
13
+ for (const layer of overlay ?? [])
14
+ byId.set(layer.id, cloneGridLayer(layer));
15
+ return [...byId.values()];
16
+ }
17
+ /** Spread-ready non-placeable fields preserved across document rebuilds. @internal */
18
+ export function editorDocumentExtras(doc) {
19
+ return {
20
+ prefabs: doc.prefabs,
21
+ collections: doc.collections,
22
+ catalogs: doc.catalogs,
23
+ ...(doc.grids === undefined ? {} : { grids: doc.grids }),
24
+ ...(doc.terrain === undefined ? {} : { terrain: doc.terrain }),
25
+ ...(doc.ui === undefined ? {} : { ui: doc.ui }),
26
+ };
27
+ }
28
+ /** Builds a fresh, empty editor document to start authoring a scene from scratch.
29
+ * @internal
30
+ */
2
31
  export function createEmptyEditorDocument() {
3
32
  return {
4
33
  version: 1,
@@ -6,10 +35,32 @@ export function createEmptyEditorDocument() {
6
35
  volumes: [],
7
36
  paths: [],
8
37
  annotations: [],
38
+ prefabs: [],
39
+ collections: [],
40
+ catalogs: [],
41
+ };
42
+ }
43
+ function cloneCatalogEntry(entry) {
44
+ return {
45
+ id: entry.id,
46
+ ...(entry.label === undefined ? {} : { label: entry.label }),
47
+ ...(entry.meta === undefined ? {} : { meta: { ...entry.meta } }),
9
48
  };
10
49
  }
11
- /** Deep-copies an editor document so edits never mutate the source. */
50
+ function cloneCatalogs(catalogs) {
51
+ return (catalogs ?? []).map((catalog) => ({
52
+ id: catalog.id,
53
+ entries: catalog.entries.map(cloneCatalogEntry),
54
+ }));
55
+ }
56
+ /**
57
+ * Deep-copies an editor document so edits never mutate the source. The terrain snapshot is
58
+ * shared by reference: sculpt commands replace it wholesale (copy-on-write), never mutate it in
59
+ * place, so history snapshots stay cheap even on large heightfields.
60
+ * @internal
61
+ */
12
62
  export function cloneEditorDocument(doc) {
63
+ const ui = cloneEditorUiDocument(doc.ui);
13
64
  return {
14
65
  version: 1,
15
66
  markers: doc.markers.map((marker) => ({
@@ -33,52 +84,255 @@ export function cloneEditorDocument(doc) {
33
84
  position: { ...note.position },
34
85
  ...(note.meta === undefined ? {} : { meta: { ...note.meta } }),
35
86
  })),
87
+ prefabs: doc.prefabs.map((prefab) => ({
88
+ ...prefab,
89
+ fragment: {
90
+ markers: prefab.fragment.markers.map((marker) => ({ ...marker, position: { ...marker.position } })),
91
+ volumes: prefab.fragment.volumes.map((volume) => ({ ...volume, center: { ...volume.center } })),
92
+ paths: prefab.fragment.paths.map((path) => ({ ...path, points: path.points.map((point) => ({ ...point })) })),
93
+ annotations: prefab.fragment.annotations.map((note) => ({ ...note, position: { ...note.position } })),
94
+ },
95
+ })),
96
+ collections: doc.collections.map((collection) => ({ ...collection, memberIds: [...collection.memberIds] })),
97
+ catalogs: cloneCatalogs(doc.catalogs),
98
+ ...(doc.grids === undefined ? {} : { grids: doc.grids.map(cloneGridLayer) }),
99
+ ...(doc.terrain === undefined ? {} : { terrain: doc.terrain }),
100
+ ...(ui === undefined ? {} : { ui }),
36
101
  };
37
102
  }
38
103
  function asArray(value) {
39
104
  return value === undefined ? [] : [...value];
40
105
  }
41
- /** Resolves a game's `editorLayers` export — document, partial data, or factory — into a full document. */
106
+ function upsertCatalogEntries(base, overlay) {
107
+ return upsertById(base.map(cloneCatalogEntry), overlay.map(cloneCatalogEntry));
108
+ }
109
+ function upsertCatalogs(base, overlay) {
110
+ const byId = new Map((base ?? []).map((catalog) => [catalog.id, { id: catalog.id, entries: catalog.entries.map(cloneCatalogEntry) }]));
111
+ for (const catalog of overlay ?? []) {
112
+ const existing = byId.get(catalog.id);
113
+ byId.set(catalog.id, {
114
+ id: catalog.id,
115
+ entries: existing === undefined ? catalog.entries.map(cloneCatalogEntry) : upsertCatalogEntries(existing.entries, catalog.entries),
116
+ });
117
+ }
118
+ return [...byId.values()];
119
+ }
120
+ /** Resolves a game's `editorLayers` export — document, partial data, or factory — into a full document.
121
+ * @internal
122
+ */
42
123
  export function normalizeEditorLayers(input) {
43
124
  if (input === undefined || input === null)
44
125
  return createEmptyEditorDocument();
45
126
  const resolved = typeof input === "function" ? input() : input;
127
+ const ui = cloneEditorUiDocument(resolved.ui);
46
128
  return {
47
129
  version: 1,
48
130
  markers: asArray(resolved.markers),
49
131
  volumes: asArray(resolved.volumes),
50
132
  paths: asArray(resolved.paths),
51
133
  annotations: asArray(resolved.annotations),
134
+ prefabs: asArray(resolved.prefabs),
135
+ collections: asArray(resolved.collections),
136
+ catalogs: cloneCatalogs(resolved.catalogs),
137
+ ...(migrateGrids(resolved.grids) === undefined ? {} : { grids: migrateGrids(resolved.grids) }),
138
+ ...(resolved.terrain === undefined ? {} : { terrain: migrateTerrainSnapshot(resolved.terrain) }),
139
+ ...(ui === undefined ? {} : { ui }),
52
140
  };
53
141
  }
54
- /** Combines multiple editor documents' markers, volumes, paths, and notes into one. */
142
+ /**
143
+ * Reserves `id` in `taken` and returns it unchanged when free; otherwise mints the next free
144
+ * `<id>_copy`/`<id>_copyN` suffix and reserves that instead. The one place object ids are made
145
+ * unique across a document's markers/volumes/paths/annotations as a single global namespace, so a
146
+ * merged-in or imported object can never silently shadow an existing object in another collection.
147
+ * @internal
148
+ */
149
+ export function ensureUniqueEditorId(id, taken) {
150
+ if (!taken.has(id)) {
151
+ taken.add(id);
152
+ return id;
153
+ }
154
+ let candidate = `${id}_copy`;
155
+ let n = 2;
156
+ while (taken.has(candidate)) {
157
+ candidate = `${id}_copy${n}`;
158
+ n += 1;
159
+ }
160
+ taken.add(candidate);
161
+ return candidate;
162
+ }
163
+ /** Combines multiple editor documents' markers, volumes, paths, notes, prefabs, and collections
164
+ * into one, re-idding any placeable object whose id collides with one already merged in — across
165
+ * all four collections, since selection/parenting/removal treat those ids as one document-global
166
+ * namespace.
167
+ * @internal
168
+ */
55
169
  export function mergeEditorDocuments(...docs) {
56
170
  const out = createEmptyEditorDocument();
171
+ const taken = new Set();
172
+ const remap = (item) => {
173
+ const id = ensureUniqueEditorId(item.id, taken);
174
+ return id === item.id ? item : { ...item, id };
175
+ };
57
176
  for (const doc of docs) {
58
- out.markers.push(...doc.markers);
59
- out.volumes.push(...doc.volumes);
60
- out.paths.push(...doc.paths);
61
- out.annotations.push(...doc.annotations);
177
+ out.markers.push(...doc.markers.map(remap));
178
+ out.volumes.push(...doc.volumes.map(remap));
179
+ out.paths.push(...doc.paths.map(remap));
180
+ out.annotations.push(...doc.annotations.map(remap));
181
+ out.prefabs.push(...doc.prefabs);
182
+ out.collections.push(...doc.collections);
183
+ out.catalogs = upsertCatalogs(out.catalogs, doc.catalogs);
184
+ const mergedGrids = upsertGrids(out.grids, doc.grids);
185
+ if (mergedGrids !== undefined)
186
+ out.grids = mergedGrids;
187
+ if (doc.terrain !== undefined)
188
+ out.terrain = doc.terrain;
189
+ if (doc.ui !== undefined) {
190
+ out.ui = {
191
+ panels: {
192
+ ...(out.ui?.panels ?? {}),
193
+ ...Object.fromEntries(Object.entries(doc.ui.panels).map(([id, panel]) => [id, { ...panel }])),
194
+ },
195
+ };
196
+ }
62
197
  }
63
198
  return out;
64
199
  }
65
- /** Looks up a marker by id in an editor document. */
200
+ /** Extracts the subset of a document matching the given ids — the clipboard fragment for copy/paste.
201
+ * @internal
202
+ */
203
+ export function extractEditorFragment(doc, ids) {
204
+ const wanted = new Set(ids);
205
+ return cloneEditorDocument({
206
+ version: 1,
207
+ markers: doc.markers.filter((marker) => wanted.has(marker.id)),
208
+ volumes: doc.volumes.filter((volume) => wanted.has(volume.id)),
209
+ paths: doc.paths.filter((path) => wanted.has(path.id)),
210
+ annotations: doc.annotations.filter((note) => wanted.has(note.id)),
211
+ prefabs: [],
212
+ collections: [],
213
+ catalogs: [],
214
+ });
215
+ }
216
+ /** Counts every object in a document across markers, volumes, paths, and notes.
217
+ * @internal
218
+ */
219
+ export function editorDocumentSize(doc) {
220
+ return doc.markers.length + doc.volumes.length + doc.paths.length + doc.annotations.length;
221
+ }
222
+ /** Looks up a prefab by id in an editor document.
223
+ * @internal
224
+ */
225
+ export function findEditorPrefab(doc, id) {
226
+ return doc.prefabs.find((prefab) => prefab.id === id);
227
+ }
228
+ /** Looks up a named collection / selection set by id in an editor document.
229
+ * @internal
230
+ */
231
+ export function findEditorCollection(doc, id) {
232
+ return doc.collections.find((collection) => collection.id === id);
233
+ }
234
+ /**
235
+ * Looks up a gameplay data catalog by id on the scene document.
236
+ * @capability editor-catalogs Find a persisted catalog bag by id.
237
+ */
238
+ export function findEditorCatalog(doc, id) {
239
+ return doc.catalogs.find((catalog) => catalog.id === id);
240
+ }
241
+ /**
242
+ * Looks up one entry inside a gameplay data catalog.
243
+ * @capability editor-catalogs Find a catalog entry's meta bag by catalog + entry id.
244
+ */
245
+ export function findEditorCatalogEntry(doc, catalogId, entryId) {
246
+ return findEditorCatalog(doc, catalogId)?.entries.find((entry) => entry.id === entryId);
247
+ }
248
+ /**
249
+ * Seeds default catalog rows from game-exported definitions into a document: missing catalogs and
250
+ * missing entries are filled from the definition; existing document values win (overlay already applied).
251
+ * @capability editor-catalogs Seed scene-document catalogs from game-exported schemas.
252
+ */
253
+ export function seedEditorCatalogs(doc, definitions) {
254
+ if (definitions.length === 0)
255
+ return doc;
256
+ const next = cloneCatalogs(doc.catalogs);
257
+ for (const definition of definitions) {
258
+ const existingIndex = next.findIndex((catalog) => catalog.id === definition.id);
259
+ const existing = existingIndex >= 0 ? next[existingIndex] : undefined;
260
+ const byId = new Map((existing?.entries ?? []).map((entry) => [entry.id, cloneCatalogEntry(entry)]));
261
+ for (const entry of definition.entries) {
262
+ if (!byId.has(entry.id))
263
+ byId.set(entry.id, cloneCatalogEntry(entry));
264
+ }
265
+ const catalog = {
266
+ id: definition.id,
267
+ entries: [...byId.values()],
268
+ };
269
+ if (existingIndex >= 0)
270
+ next[existingIndex] = catalog;
271
+ else
272
+ next.push(catalog);
273
+ }
274
+ return { ...doc, catalogs: next };
275
+ }
276
+ /** True when an object id is a member of any locked collection — blocks move/delete on it.
277
+ * @internal
278
+ */
279
+ export function isEditorObjectLocked(doc, id) {
280
+ return doc.collections.some((collection) => collection.locked === true && collection.memberIds.includes(id));
281
+ }
282
+ /**
283
+ * Extracts the selected ids into a prefab fragment centered on their own bounds centroid, so the
284
+ * same prefab reinserts consistently regardless of where in the scene (or which game) it lands.
285
+ * @internal
286
+ */
287
+ export function createPrefabFragment(doc, ids) {
288
+ const extracted = extractEditorFragment(doc, ids);
289
+ const bounds = editorDocumentBounds(extracted);
290
+ const origin = bounds === null
291
+ ? { x: 0, y: 0, z: 0 }
292
+ : {
293
+ x: (bounds.min.x + bounds.max.x) / 2,
294
+ y: (bounds.min.y + bounds.max.y) / 2,
295
+ z: (bounds.min.z + bounds.max.z) / 2,
296
+ };
297
+ const shift = (point) => ({
298
+ x: point.x - origin.x,
299
+ y: point.y - origin.y,
300
+ z: point.z - origin.z,
301
+ });
302
+ return {
303
+ markers: extracted.markers.map((marker) => ({ ...marker, position: shift(marker.position) })),
304
+ volumes: extracted.volumes.map((volume) => ({ ...volume, center: shift(volume.center) })),
305
+ paths: extracted.paths.map((path) => ({ ...path, points: path.points.map(shift) })),
306
+ annotations: extracted.annotations.map((note) => ({ ...note, position: shift(note.position) })),
307
+ };
308
+ }
309
+ /** Looks up a marker by id in an editor document.
310
+ * @internal
311
+ */
66
312
  export function findEditorMarker(doc, id) {
67
313
  return doc.markers.find((marker) => marker.id === id);
68
314
  }
69
- /** Looks up a volume by id in an editor document. */
315
+ /** Looks up a volume by id in an editor document.
316
+ * @internal
317
+ */
70
318
  export function findEditorVolume(doc, id) {
71
319
  return doc.volumes.find((volume) => volume.id === id);
72
320
  }
73
- /** Looks up a path by id in an editor document. */
321
+ /** Looks up a path by id in an editor document.
322
+ * @internal
323
+ */
74
324
  export function findEditorPath(doc, id) {
75
325
  return doc.paths.find((path) => path.id === id);
76
326
  }
77
- /** Looks up an annotation note by id in an editor document. */
327
+ /** Looks up an annotation note by id in an editor document.
328
+ * @internal
329
+ */
78
330
  export function findEditorNote(doc, id) {
79
331
  return doc.annotations.find((note) => note.id === id);
80
332
  }
81
- /** Lists the distinct marker, volume, and path kinds authored in a document. */
333
+ /** Lists the distinct marker, volume, and path kinds authored in a document.
334
+ * @internal
335
+ */
82
336
  export function listEditorKinds(doc) {
83
337
  const markers = new Set();
84
338
  const volumes = new Set();
@@ -95,19 +349,496 @@ export function listEditorKinds(doc) {
95
349
  paths: [...paths].sort(),
96
350
  };
97
351
  }
98
- /** Serializes an editor document to JSON text for saving or export. */
352
+ function editorNodes(doc) {
353
+ return [...doc.markers, ...doc.volumes, ...doc.paths, ...doc.annotations];
354
+ }
355
+ /** The id of an object's parent, or undefined when it is a root (or unknown).
356
+ * @internal
357
+ */
358
+ export function editorParentOf(doc, id) {
359
+ return editorNodes(doc).find((node) => node.id === id)?.parentId;
360
+ }
361
+ /** The direct child ids of an object (empty when it has none).
362
+ * @internal
363
+ */
364
+ export function editorChildren(doc, parentId) {
365
+ return editorNodes(doc)
366
+ .filter((node) => node.parentId === parentId)
367
+ .map((node) => node.id);
368
+ }
369
+ /** Object ids with no parent (or whose parent no longer exists) — the roots of the hierarchy.
370
+ * @internal
371
+ */
372
+ export function editorRoots(doc) {
373
+ const ids = new Set(editorNodes(doc).map((node) => node.id));
374
+ return editorNodes(doc)
375
+ .filter((node) => node.parentId === undefined || !ids.has(node.parentId))
376
+ .map((node) => node.id);
377
+ }
378
+ /** Every descendant id of the given ids (children, grandchildren, …), excluding the inputs.
379
+ * @internal
380
+ */
381
+ export function collectDescendants(doc, ids) {
382
+ const childrenByParent = new Map();
383
+ for (const node of editorNodes(doc)) {
384
+ if (node.parentId === undefined)
385
+ continue;
386
+ const bucket = childrenByParent.get(node.parentId);
387
+ if (bucket === undefined)
388
+ childrenByParent.set(node.parentId, [node.id]);
389
+ else
390
+ bucket.push(node.id);
391
+ }
392
+ const out = new Set();
393
+ const stack = [...ids];
394
+ while (stack.length > 0) {
395
+ const current = stack.pop();
396
+ for (const child of childrenByParent.get(current) ?? []) {
397
+ if (out.has(child))
398
+ continue;
399
+ out.add(child);
400
+ stack.push(child);
401
+ }
402
+ }
403
+ return out;
404
+ }
405
+ /** True when parenting `id` under `parentId` would form a cycle (or parent itself to itself).
406
+ * @internal
407
+ */
408
+ export function wouldCreateCycle(doc, id, parentId) {
409
+ if (parentId === null)
410
+ return false;
411
+ if (parentId === id)
412
+ return true;
413
+ return collectDescendants(doc, [id]).has(parentId);
414
+ }
415
+ /** Serializes an editor document to JSON text for saving or export.
416
+ * @internal
417
+ */
99
418
  export function exportEditorDocumentJson(doc, pretty = true) {
100
419
  return JSON.stringify(doc, null, pretty ? 2 : undefined);
101
420
  }
102
- /** Parses JSON text back into a normalized editor document. */
421
+ function isPlainObject(value) {
422
+ return typeof value === "object" && value !== null && !Array.isArray(value);
423
+ }
424
+ function decodeArray(value, path, decodeItem, errors) {
425
+ if (value === undefined)
426
+ return [];
427
+ if (!Array.isArray(value)) {
428
+ errors.push({ path, message: "expected an array" });
429
+ return [];
430
+ }
431
+ const out = [];
432
+ value.forEach((item, index) => {
433
+ const decoded = decodeItem(item, `${path}[${index}]`, errors);
434
+ if (decoded !== null)
435
+ out.push(decoded);
436
+ });
437
+ return out;
438
+ }
439
+ function decodeVec3(value, path, errors) {
440
+ if (!isPlainObject(value) || typeof value.x !== "number" || typeof value.y !== "number" || typeof value.z !== "number") {
441
+ errors.push({ path, message: "expected {x,y,z} numbers" });
442
+ return null;
443
+ }
444
+ return { x: value.x, y: value.y, z: value.z };
445
+ }
446
+ function decodeMeta(value, path, errors) {
447
+ if (value === undefined)
448
+ return undefined;
449
+ if (!isPlainObject(value)) {
450
+ errors.push({ path, message: "expected an object" });
451
+ return undefined;
452
+ }
453
+ return value;
454
+ }
455
+ function decodeMarker(item, path, errors) {
456
+ if (!isPlainObject(item)) {
457
+ errors.push({ path, message: "expected an object" });
458
+ return null;
459
+ }
460
+ if (typeof item.id !== "string")
461
+ errors.push({ path: `${path}.id`, message: "expected a string" });
462
+ if (typeof item.kind !== "string")
463
+ errors.push({ path: `${path}.kind`, message: "expected a string" });
464
+ const position = decodeVec3(item.position, `${path}.position`, errors);
465
+ if (typeof item.id !== "string" || typeof item.kind !== "string" || position === null)
466
+ return null;
467
+ const marker = { id: item.id, kind: item.kind, position };
468
+ if (typeof item.rotationY === "number")
469
+ marker.rotationY = item.rotationY;
470
+ if (typeof item.color === "string")
471
+ marker.color = item.color;
472
+ if (typeof item.label === "string")
473
+ marker.label = item.label;
474
+ if (typeof item.catalogId === "string")
475
+ marker.catalogId = item.catalogId;
476
+ if (typeof item.parentId === "string")
477
+ marker.parentId = item.parentId;
478
+ const meta = decodeMeta(item.meta, `${path}.meta`, errors);
479
+ if (meta !== undefined)
480
+ marker.meta = meta;
481
+ return marker;
482
+ }
483
+ const VOLUME_SHAPES = new Set(["sphere", "cylinder", "box"]);
484
+ function decodeVolume(item, path, errors) {
485
+ if (!isPlainObject(item)) {
486
+ errors.push({ path, message: "expected an object" });
487
+ return null;
488
+ }
489
+ if (typeof item.id !== "string")
490
+ errors.push({ path: `${path}.id`, message: "expected a string" });
491
+ if (typeof item.kind !== "string")
492
+ errors.push({ path: `${path}.kind`, message: "expected a string" });
493
+ const validShape = typeof item.shape === "string" && VOLUME_SHAPES.has(item.shape);
494
+ if (!validShape)
495
+ errors.push({ path: `${path}.shape`, message: "expected sphere | cylinder | box" });
496
+ const center = decodeVec3(item.center, `${path}.center`, errors);
497
+ if (typeof item.id !== "string" || typeof item.kind !== "string" || !validShape || center === null)
498
+ return null;
499
+ const volume = { id: item.id, kind: item.kind, shape: item.shape, center };
500
+ if (typeof item.radius === "number")
501
+ volume.radius = item.radius;
502
+ if (typeof item.height === "number")
503
+ volume.height = item.height;
504
+ if (item.halfExtents !== undefined) {
505
+ const halfExtents = decodeVec3(item.halfExtents, `${path}.halfExtents`, errors);
506
+ if (halfExtents !== null)
507
+ volume.halfExtents = halfExtents;
508
+ }
509
+ if (typeof item.color === "string")
510
+ volume.color = item.color;
511
+ if (typeof item.label === "string")
512
+ volume.label = item.label;
513
+ if (typeof item.parentId === "string")
514
+ volume.parentId = item.parentId;
515
+ const meta = decodeMeta(item.meta, `${path}.meta`, errors);
516
+ if (meta !== undefined)
517
+ volume.meta = meta;
518
+ return volume;
519
+ }
520
+ function decodePath(item, path, errors) {
521
+ if (!isPlainObject(item)) {
522
+ errors.push({ path, message: "expected an object" });
523
+ return null;
524
+ }
525
+ if (typeof item.id !== "string")
526
+ errors.push({ path: `${path}.id`, message: "expected a string" });
527
+ if (typeof item.kind !== "string")
528
+ errors.push({ path: `${path}.kind`, message: "expected a string" });
529
+ const validPoints = Array.isArray(item.points);
530
+ if (!validPoints)
531
+ errors.push({ path: `${path}.points`, message: "expected an array" });
532
+ const points = validPoints
533
+ ? decodeArray(item.points, `${path}.points`, decodeVec3, errors)
534
+ : [];
535
+ if (typeof item.id !== "string" || typeof item.kind !== "string" || !validPoints)
536
+ return null;
537
+ const decodedPath = { id: item.id, kind: item.kind, points };
538
+ if (typeof item.width === "number")
539
+ decodedPath.width = item.width;
540
+ if (typeof item.color === "string")
541
+ decodedPath.color = item.color;
542
+ if (typeof item.label === "string")
543
+ decodedPath.label = item.label;
544
+ if (typeof item.parentId === "string")
545
+ decodedPath.parentId = item.parentId;
546
+ const meta = decodeMeta(item.meta, `${path}.meta`, errors);
547
+ if (meta !== undefined)
548
+ decodedPath.meta = meta;
549
+ return decodedPath;
550
+ }
551
+ function decodeNote(item, path, errors) {
552
+ if (!isPlainObject(item)) {
553
+ errors.push({ path, message: "expected an object" });
554
+ return null;
555
+ }
556
+ if (typeof item.id !== "string")
557
+ errors.push({ path: `${path}.id`, message: "expected a string" });
558
+ if (typeof item.text !== "string")
559
+ errors.push({ path: `${path}.text`, message: "expected a string" });
560
+ const position = decodeVec3(item.position, `${path}.position`, errors);
561
+ if (typeof item.id !== "string" || typeof item.text !== "string" || position === null)
562
+ return null;
563
+ const note = { id: item.id, text: item.text, position };
564
+ if (typeof item.color === "string")
565
+ note.color = item.color;
566
+ if (typeof item.parentId === "string")
567
+ note.parentId = item.parentId;
568
+ const meta = decodeMeta(item.meta, `${path}.meta`, errors);
569
+ if (meta !== undefined)
570
+ note.meta = meta;
571
+ return note;
572
+ }
573
+ function decodeFragmentContent(value, path, errors) {
574
+ if (!isPlainObject(value)) {
575
+ errors.push({ path, message: "expected an object" });
576
+ return null;
577
+ }
578
+ return {
579
+ markers: decodeArray(value.markers, `${path}.markers`, decodeMarker, errors),
580
+ volumes: decodeArray(value.volumes, `${path}.volumes`, decodeVolume, errors),
581
+ paths: decodeArray(value.paths, `${path}.paths`, decodePath, errors),
582
+ annotations: decodeArray(value.annotations, `${path}.annotations`, decodeNote, errors),
583
+ };
584
+ }
585
+ function decodePrefab(item, path, errors) {
586
+ if (!isPlainObject(item)) {
587
+ errors.push({ path, message: "expected an object" });
588
+ return null;
589
+ }
590
+ if (typeof item.id !== "string")
591
+ errors.push({ path: `${path}.id`, message: "expected a string" });
592
+ if (typeof item.name !== "string")
593
+ errors.push({ path: `${path}.name`, message: "expected a string" });
594
+ const fragment = decodeFragmentContent(item.fragment, `${path}.fragment`, errors);
595
+ if (typeof item.id !== "string" || typeof item.name !== "string" || fragment === null)
596
+ return null;
597
+ return { id: item.id, name: item.name, fragment };
598
+ }
599
+ function decodeCollection(item, path, errors) {
600
+ if (!isPlainObject(item)) {
601
+ errors.push({ path, message: "expected an object" });
602
+ return null;
603
+ }
604
+ if (typeof item.id !== "string")
605
+ errors.push({ path: `${path}.id`, message: "expected a string" });
606
+ if (typeof item.name !== "string")
607
+ errors.push({ path: `${path}.name`, message: "expected a string" });
608
+ const memberIds = [];
609
+ if (!Array.isArray(item.memberIds)) {
610
+ errors.push({ path: `${path}.memberIds`, message: "expected an array of strings" });
611
+ }
612
+ else {
613
+ item.memberIds.forEach((member, index) => {
614
+ if (typeof member === "string")
615
+ memberIds.push(member);
616
+ else
617
+ errors.push({ path: `${path}.memberIds[${index}]`, message: "expected a string" });
618
+ });
619
+ }
620
+ if (typeof item.id !== "string" || typeof item.name !== "string" || !Array.isArray(item.memberIds))
621
+ return null;
622
+ const collection = { id: item.id, name: item.name, memberIds };
623
+ if (typeof item.color === "string")
624
+ collection.color = item.color;
625
+ if (typeof item.locked === "boolean")
626
+ collection.locked = item.locked;
627
+ if (typeof item.visible === "boolean")
628
+ collection.visible = item.visible;
629
+ return collection;
630
+ }
631
+ function decodeCatalogEntry(item, path, errors) {
632
+ if (!isPlainObject(item)) {
633
+ errors.push({ path, message: "expected an object" });
634
+ return null;
635
+ }
636
+ if (typeof item.id !== "string") {
637
+ errors.push({ path: `${path}.id`, message: "expected a string" });
638
+ return null;
639
+ }
640
+ const entry = { id: item.id };
641
+ if (typeof item.label === "string")
642
+ entry.label = item.label;
643
+ const meta = decodeMeta(item.meta, `${path}.meta`, errors);
644
+ if (meta !== undefined)
645
+ entry.meta = meta;
646
+ return entry;
647
+ }
648
+ function decodeCatalog(item, path, errors) {
649
+ if (!isPlainObject(item)) {
650
+ errors.push({ path, message: "expected an object" });
651
+ return null;
652
+ }
653
+ if (typeof item.id !== "string") {
654
+ errors.push({ path: `${path}.id`, message: "expected a string" });
655
+ return null;
656
+ }
657
+ const entries = decodeArray(item.entries, `${path}.entries`, decodeCatalogEntry, errors);
658
+ return { id: item.id, entries };
659
+ }
660
+ const GRID_AXES = new Set(["xz", "xy"]);
661
+ function decodeGridPaletteEntry(item, path, errors) {
662
+ if (!isPlainObject(item)) {
663
+ errors.push({ path, message: "expected an object" });
664
+ return null;
665
+ }
666
+ if (typeof item.id !== "string") {
667
+ errors.push({ path: `${path}.id`, message: "expected a string" });
668
+ return null;
669
+ }
670
+ const entry = { id: item.id };
671
+ if (typeof item.label === "string")
672
+ entry.label = item.label;
673
+ if (typeof item.glyph === "string")
674
+ entry.glyph = item.glyph;
675
+ if (typeof item.color === "string")
676
+ entry.color = item.color;
677
+ const meta = decodeMeta(item.meta, `${path}.meta`, errors);
678
+ if (meta !== undefined)
679
+ entry.meta = meta;
680
+ return entry;
681
+ }
682
+ function decodeGridLayer(item, path, errors) {
683
+ if (!isPlainObject(item)) {
684
+ errors.push({ path, message: "expected an object" });
685
+ return null;
686
+ }
687
+ if (typeof item.id !== "string")
688
+ errors.push({ path: `${path}.id`, message: "expected a string" });
689
+ if (typeof item.kind !== "string")
690
+ errors.push({ path: `${path}.kind`, message: "expected a string" });
691
+ const origin = decodeVec3(item.origin, `${path}.origin`, errors);
692
+ if (typeof item.cellSize !== "number")
693
+ errors.push({ path: `${path}.cellSize`, message: "expected a number" });
694
+ if (typeof item.cols !== "number")
695
+ errors.push({ path: `${path}.cols`, message: "expected a number" });
696
+ if (typeof item.rows !== "number")
697
+ errors.push({ path: `${path}.rows`, message: "expected a number" });
698
+ const cellsValue = item.cells;
699
+ const validCells = isPlainObject(cellsValue);
700
+ if (!validCells)
701
+ errors.push({ path: `${path}.cells`, message: "expected an object" });
702
+ if (typeof item.id !== "string" ||
703
+ typeof item.kind !== "string" ||
704
+ origin === null ||
705
+ typeof item.cellSize !== "number" ||
706
+ typeof item.cols !== "number" ||
707
+ typeof item.rows !== "number" ||
708
+ !validCells) {
709
+ return null;
710
+ }
711
+ const cells = {};
712
+ for (const [key, value] of Object.entries(cellsValue)) {
713
+ if (typeof value !== "string") {
714
+ errors.push({ path: `${path}.cells.${key}`, message: "expected a string value id" });
715
+ continue;
716
+ }
717
+ cells[key] = value;
718
+ }
719
+ const layer = {
720
+ id: item.id,
721
+ kind: item.kind,
722
+ origin,
723
+ cellSize: item.cellSize,
724
+ cols: item.cols,
725
+ rows: item.rows,
726
+ cells,
727
+ };
728
+ if (typeof item.label === "string")
729
+ layer.label = item.label;
730
+ if (typeof item.axes === "string" && GRID_AXES.has(item.axes))
731
+ layer.axes = item.axes;
732
+ if (typeof item.empty === "string")
733
+ layer.empty = item.empty;
734
+ if (typeof item.visible === "boolean")
735
+ layer.visible = item.visible;
736
+ if (typeof item.parentId === "string")
737
+ layer.parentId = item.parentId;
738
+ if (typeof item.schemaVersion === "number")
739
+ layer.schemaVersion = item.schemaVersion;
740
+ if (Array.isArray(item.palette)) {
741
+ layer.palette = decodeArray(item.palette, `${path}.palette`, decodeGridPaletteEntry, errors);
742
+ }
743
+ const meta = decodeMeta(item.meta, `${path}.meta`, errors);
744
+ if (meta !== undefined)
745
+ layer.meta = meta;
746
+ return migrateGridLayer(layer);
747
+ }
748
+ /**
749
+ * The authoritative decoder/migrator for an editor document arriving from outside this process
750
+ * (disk, network, an agent's `import_document` RPC): validates every field with a path-specific
751
+ * diagnostic on failure instead of trusting the shape, then migrates forward — routes any embedded
752
+ * terrain through {@link migrateTerrainSnapshot} and normalizes `version` to the one this build
753
+ * understands. Every other loader in this module funnels through here.
754
+ * @internal
755
+ */
756
+ export function decodeEditorDocument(raw) {
757
+ if (!isPlainObject(raw)) {
758
+ return { ok: false, errors: [{ path: "$", message: "editor document must be an object" }] };
759
+ }
760
+ const errors = [];
761
+ const markers = decodeArray(raw.markers, "$.markers", decodeMarker, errors);
762
+ const volumes = decodeArray(raw.volumes, "$.volumes", decodeVolume, errors);
763
+ const paths = decodeArray(raw.paths, "$.paths", decodePath, errors);
764
+ const annotations = decodeArray(raw.annotations, "$.annotations", decodeNote, errors);
765
+ const prefabs = decodeArray(raw.prefabs, "$.prefabs", decodePrefab, errors);
766
+ const collections = decodeArray(raw.collections, "$.collections", decodeCollection, errors);
767
+ const catalogs = decodeArray(raw.catalogs, "$.catalogs", decodeCatalog, errors);
768
+ const grids = raw.grids === undefined ? undefined : decodeArray(raw.grids, "$.grids", decodeGridLayer, errors);
769
+ if (raw.terrain !== undefined && !isPlainObject(raw.terrain)) {
770
+ errors.push({ path: "$.terrain", message: "expected an object" });
771
+ }
772
+ if (errors.length > 0)
773
+ return { ok: false, errors };
774
+ const terrain = raw.terrain === undefined ? undefined : migrateTerrainSnapshot(raw.terrain);
775
+ const ui = decodeEditorUiDocument(raw.ui);
776
+ return {
777
+ ok: true,
778
+ document: {
779
+ version: 1,
780
+ markers,
781
+ volumes,
782
+ paths,
783
+ annotations,
784
+ prefabs,
785
+ collections,
786
+ catalogs,
787
+ ...(grids === undefined ? {} : { grids }),
788
+ ...(terrain === undefined ? {} : { terrain }),
789
+ ...(ui === undefined ? {} : { ui }),
790
+ },
791
+ };
792
+ }
793
+ /** Parses JSON text back into a normalized editor document, throwing a message that names every
794
+ * field that failed to decode when the shape is malformed.
795
+ * @internal
796
+ */
103
797
  export function importEditorDocumentJson(raw) {
104
798
  const parsed = JSON.parse(raw);
105
- if (parsed === null || typeof parsed !== "object") {
106
- throw new Error("editor document must be an object");
799
+ const decoded = decodeEditorDocument(parsed);
800
+ if (!decoded.ok) {
801
+ throw new Error(`invalid editor document: ${decoded.errors.map((e) => `${e.path} ${e.message}`).join("; ")}`);
107
802
  }
108
- return normalizeEditorLayers(parsed);
803
+ return decoded.document;
804
+ }
805
+ function upsertById(base, overlay) {
806
+ const overlayIds = new Set(overlay.map((item) => item.id));
807
+ return [...base.filter((item) => !overlayIds.has(item.id)), ...overlay];
808
+ }
809
+ /**
810
+ * Applies a saved editor document on top of a game's derived layers: overlay objects replace
811
+ * same-id base objects and new overlay objects are appended, so editor saves win over source
812
+ * data until they are folded back in.
813
+ * @internal
814
+ */
815
+ export function applyEditorDocumentOverlay(base, overlay) {
816
+ const terrain = overlay.terrain ?? base.terrain;
817
+ const ui = overlay.ui === undefined
818
+ ? cloneEditorUiDocument(base.ui)
819
+ : {
820
+ panels: {
821
+ ...(base.ui?.panels ?? {}),
822
+ ...Object.fromEntries(Object.entries(overlay.ui.panels).map(([id, panel]) => [id, { ...panel }])),
823
+ },
824
+ };
825
+ return {
826
+ version: 1,
827
+ markers: upsertById(base.markers, overlay.markers),
828
+ volumes: upsertById(base.volumes, overlay.volumes),
829
+ paths: upsertById(base.paths, overlay.paths),
830
+ annotations: upsertById(base.annotations, overlay.annotations),
831
+ prefabs: upsertById(base.prefabs, overlay.prefabs),
832
+ collections: upsertById(base.collections, overlay.collections),
833
+ catalogs: upsertCatalogs(base.catalogs, overlay.catalogs),
834
+ ...(upsertGrids(base.grids, overlay.grids) === undefined ? {} : { grids: upsertGrids(base.grids, overlay.grids) }),
835
+ ...(terrain === undefined ? {} : { terrain }),
836
+ ...(ui === undefined ? {} : { ui }),
837
+ };
109
838
  }
110
- /** Computes the world-space min/max bounds spanning every object in a document, or null if empty. */
839
+ /** Computes the world-space min/max bounds spanning every object in a document, or null if empty.
840
+ * @internal
841
+ */
111
842
  export function editorDocumentBounds(doc) {
112
843
  let minX = Infinity;
113
844
  let minY = Infinity;