@jgengine/core 0.9.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 (631) hide show
  1. package/CHANGELOG.md +34 -3
  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 +19 -1
  21. package/dist/ai/spawnDirector.js +53 -26
  22. package/dist/ai/spawnPoint.d.ts +7 -0
  23. package/dist/ai/spawnPoint.js +7 -0
  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/audio/audioFalloff.d.ts +5 -2
  35. package/dist/audio/music.d.ts +53 -0
  36. package/dist/audio/music.js +34 -0
  37. package/dist/audio/synth.d.ts +60 -0
  38. package/dist/audio/synth.js +8 -0
  39. package/dist/authoring.d.ts +15 -0
  40. package/dist/authoring.js +15 -0
  41. package/dist/board/laneBoard.d.ts +13 -0
  42. package/dist/board/laneBoard.js +13 -0
  43. package/dist/board/timelineBoard.d.ts +10 -0
  44. package/dist/board/timelineBoard.js +10 -0
  45. package/dist/combat/abilityKit.d.ts +18 -0
  46. package/dist/combat/abilityKit.js +24 -9
  47. package/dist/combat/animationState.d.ts +5 -0
  48. package/dist/combat/animationState.js +5 -0
  49. package/dist/combat/breakMeters.d.ts +10 -0
  50. package/dist/combat/breakMeters.js +10 -0
  51. package/dist/combat/castRunner.d.ts +5 -0
  52. package/dist/combat/castRunner.js +5 -0
  53. package/dist/combat/comboPoints.d.ts +5 -0
  54. package/dist/combat/comboPoints.js +5 -0
  55. package/dist/combat/comboString.d.ts +5 -0
  56. package/dist/combat/comboString.js +5 -0
  57. package/dist/combat/damageInterceptors.d.ts +192 -0
  58. package/dist/combat/damageInterceptors.js +251 -0
  59. package/dist/combat/damageMatchup.d.ts +68 -0
  60. package/dist/combat/damageMatchup.js +42 -0
  61. package/dist/combat/damageResolution.d.ts +63 -0
  62. package/dist/combat/damageResolution.js +50 -0
  63. package/dist/combat/death.d.ts +7 -1
  64. package/dist/combat/death.js +5 -0
  65. package/dist/combat/deathReason.d.ts +14 -0
  66. package/dist/combat/deathReason.js +1 -0
  67. package/dist/combat/defensiveWindow.d.ts +5 -0
  68. package/dist/combat/defensiveWindow.js +5 -0
  69. package/dist/combat/dotField.d.ts +47 -0
  70. package/dist/combat/dotField.js +52 -0
  71. package/dist/combat/downed.d.ts +5 -0
  72. package/dist/combat/downed.js +5 -0
  73. package/dist/combat/effects.d.ts +5 -0
  74. package/dist/combat/effects.js +5 -0
  75. package/dist/combat/encounterSequence.d.ts +258 -0
  76. package/dist/combat/encounterSequence.js +426 -0
  77. package/dist/combat/hitReaction.d.ts +57 -1
  78. package/dist/combat/hitReaction.js +45 -5
  79. package/dist/combat/magazine.d.ts +54 -0
  80. package/dist/combat/magazine.js +96 -0
  81. package/dist/combat/projectiles.d.ts +7 -2
  82. package/dist/combat/projectiles.js +48 -17
  83. package/dist/combat/receivedDamage.d.ts +117 -0
  84. package/dist/combat/receivedDamage.js +92 -0
  85. package/dist/combat/regenShield.d.ts +39 -0
  86. package/dist/combat/regenShield.js +49 -0
  87. package/dist/combat/renderCues.d.ts +51 -0
  88. package/dist/combat/renderCues.js +44 -0
  89. package/dist/combat/resourcePool.d.ts +5 -0
  90. package/dist/combat/resourcePool.js +5 -0
  91. package/dist/combat/rewardAllocation.d.ts +121 -0
  92. package/dist/combat/rewardAllocation.js +251 -0
  93. package/dist/combat/shotOrigin.d.ts +30 -1
  94. package/dist/combat/shotOrigin.js +70 -2
  95. package/dist/combat/statusApplication.d.ts +96 -0
  96. package/dist/combat/statusApplication.js +81 -0
  97. package/dist/combat/telegraph.d.ts +11 -2
  98. package/dist/combat/telegraph.js +11 -2
  99. package/dist/combat/thresholdCrossings.d.ts +85 -0
  100. package/dist/combat/thresholdCrossings.js +116 -0
  101. package/dist/combat.d.ts +34 -0
  102. package/dist/combat.js +34 -0
  103. package/dist/commands/commandRegistry.d.ts +11 -0
  104. package/dist/commands/commandRegistry.js +9 -2
  105. package/dist/crafting/crop.d.ts +18 -0
  106. package/dist/crafting/crop.js +18 -0
  107. package/dist/crafting/production.d.ts +5 -0
  108. package/dist/crafting/production.js +5 -0
  109. package/dist/devtools/rewriteTunables.d.ts +17 -0
  110. package/dist/devtools/rewriteTunables.js +276 -0
  111. package/dist/devtools/saveEndpoint.d.ts +46 -0
  112. package/dist/devtools/saveEndpoint.js +48 -0
  113. package/dist/devtools/transformTunables.d.ts +3 -0
  114. package/dist/devtools/transformTunables.js +3 -0
  115. package/dist/devtools/tunableSchema.d.ts +31 -0
  116. package/dist/devtools/tunableSchema.js +31 -0
  117. package/dist/economy/currency.d.ts +12 -1
  118. package/dist/economy/currency.js +12 -1
  119. package/dist/economy/listingBook.d.ts +91 -0
  120. package/dist/economy/listingBook.js +144 -0
  121. package/dist/economy/resourceLedger.d.ts +222 -0
  122. package/dist/economy/resourceLedger.js +353 -0
  123. package/dist/economy/sharedWallet.d.ts +14 -0
  124. package/dist/economy/sharedWallet.js +14 -0
  125. package/dist/economy/techTree.d.ts +12 -0
  126. package/dist/economy/techTree.js +12 -0
  127. package/dist/economy/wallet.d.ts +26 -2
  128. package/dist/economy/wallet.js +35 -6
  129. package/dist/editor/commands.d.ts +248 -0
  130. package/dist/editor/commands.js +865 -0
  131. package/dist/editor/document.d.ts +186 -0
  132. package/dist/editor/document.js +884 -0
  133. package/dist/editor/grid.d.ts +229 -0
  134. package/dist/editor/grid.js +366 -0
  135. package/dist/editor/gridAdapters.d.ts +80 -0
  136. package/dist/editor/gridAdapters.js +134 -0
  137. package/dist/editor/index.d.ts +97 -0
  138. package/dist/editor/index.js +10 -0
  139. package/dist/editor/liveSync.d.ts +127 -0
  140. package/dist/editor/liveSync.js +249 -0
  141. package/dist/editor/runtimeInspector.d.ts +88 -0
  142. package/dist/editor/runtimeInspector.js +239 -0
  143. package/dist/editor/types.d.ts +175 -0
  144. package/dist/editor/types.js +29 -0
  145. package/dist/faction/reputation.d.ts +5 -0
  146. package/dist/faction/reputation.js +5 -0
  147. package/dist/format/distance.d.ts +17 -0
  148. package/dist/format/distance.js +18 -0
  149. package/dist/format/duration.d.ts +27 -0
  150. package/dist/format/duration.js +45 -0
  151. package/dist/format/speed.d.ts +17 -0
  152. package/dist/format/speed.js +25 -0
  153. package/dist/game/connectedPlayers.d.ts +30 -0
  154. package/dist/game/connectedPlayers.js +21 -0
  155. package/dist/game/cosmetics.d.ts +9 -0
  156. package/dist/game/cosmetics.js +16 -0
  157. package/dist/game/defineGame.d.ts +141 -2
  158. package/dist/game/defineGame.js +39 -1
  159. package/dist/game/defineSystem.d.ts +88 -0
  160. package/dist/game/defineSystem.js +45 -0
  161. package/dist/game/dialogue.d.ts +33 -0
  162. package/dist/game/dialogue.js +21 -0
  163. package/dist/game/events.d.ts +50 -13
  164. package/dist/game/events.js +5 -0
  165. package/dist/game/feed.d.ts +33 -0
  166. package/dist/game/feed.js +35 -2
  167. package/dist/game/gamePhase.d.ts +11 -0
  168. package/dist/game/gamePhase.js +16 -0
  169. package/dist/game/keyValueStore.d.ts +25 -0
  170. package/dist/game/keyValueStore.js +61 -0
  171. package/dist/game/leaderboard.d.ts +5 -0
  172. package/dist/game/leaderboard.js +5 -0
  173. package/dist/game/levelSequence.d.ts +24 -2
  174. package/dist/game/levelSequence.js +51 -2
  175. package/dist/game/loadout.d.ts +5 -0
  176. package/dist/game/loadout.js +5 -0
  177. package/dist/game/lootFilter.d.ts +2 -0
  178. package/dist/game/lootFilter.js +2 -0
  179. package/dist/game/lootPipeline.d.ts +164 -0
  180. package/dist/game/lootPipeline.js +216 -0
  181. package/dist/game/lootTable.d.ts +21 -0
  182. package/dist/game/lootTable.js +15 -4
  183. package/dist/game/modelAnimation.d.ts +8 -0
  184. package/dist/game/modelAnimation.js +18 -0
  185. package/dist/game/objectives.d.ts +43 -0
  186. package/dist/game/objectives.js +36 -0
  187. package/dist/game/paramLayers.d.ts +148 -0
  188. package/dist/game/paramLayers.js +185 -0
  189. package/dist/game/ping.d.ts +5 -0
  190. package/dist/game/ping.js +5 -0
  191. package/dist/game/playableGame.d.ts +160 -12
  192. package/dist/game/quest.d.ts +8 -0
  193. package/dist/game/quest.js +29 -0
  194. package/dist/game/race.d.ts +141 -0
  195. package/dist/game/race.js +169 -0
  196. package/dist/game/recordBook.d.ts +5 -5
  197. package/dist/game/recordBook.js +4 -1
  198. package/dist/game/ruleSelection.d.ts +75 -0
  199. package/dist/game/ruleSelection.js +127 -0
  200. package/dist/game/runDraft.d.ts +5 -0
  201. package/dist/game/runDraft.js +5 -0
  202. package/dist/game/saveStore.d.ts +111 -0
  203. package/dist/game/saveStore.js +312 -0
  204. package/dist/game/snapshotHistory.d.ts +67 -0
  205. package/dist/game/snapshotHistory.js +95 -0
  206. package/dist/game/social.d.ts +38 -1
  207. package/dist/game/social.js +71 -0
  208. package/dist/game/spawnPoints.d.ts +5 -0
  209. package/dist/game/spawnPoints.js +5 -0
  210. package/dist/game/systemRuntime.d.ts +50 -0
  211. package/dist/game/systemRuntime.js +157 -0
  212. package/dist/game/systemSchedule.d.ts +72 -0
  213. package/dist/game/systemSchedule.js +242 -0
  214. package/dist/game/toasts.d.ts +43 -0
  215. package/dist/game/toasts.js +44 -0
  216. package/dist/game/trade.d.ts +10 -0
  217. package/dist/game/trade.js +10 -0
  218. package/dist/game/unlocks.d.ts +8 -0
  219. package/dist/game/unlocks.js +16 -0
  220. package/dist/game/vfxInstance.d.ts +138 -0
  221. package/dist/game/vfxInstance.js +96 -0
  222. package/dist/game/worldItem.d.ts +17 -4
  223. package/dist/game/worldItem.js +17 -4
  224. package/dist/gameplay.d.ts +91 -0
  225. package/dist/gameplay.js +91 -0
  226. package/dist/index.d.ts +5 -7
  227. package/dist/index.js +5 -7
  228. package/dist/input/actionBindings.d.ts +24 -5
  229. package/dist/input/actionBindings.js +23 -5
  230. package/dist/input/axisInput.d.ts +13 -1
  231. package/dist/input/axisInput.js +22 -1
  232. package/dist/input/controlGroups.d.ts +67 -0
  233. package/dist/input/controlGroups.js +41 -0
  234. package/dist/input/touchScheme.d.ts +82 -6
  235. package/dist/input/touchScheme.js +123 -10
  236. package/dist/interaction/contextMenu.d.ts +1 -0
  237. package/dist/interaction/contextMenu.js +1 -0
  238. package/dist/interaction/lockpick.d.ts +61 -0
  239. package/dist/interaction/lockpick.js +168 -0
  240. package/dist/interaction/proximityPrompt.d.ts +5 -1
  241. package/dist/interaction/proximityPrompt.js +5 -3
  242. package/dist/interaction/qte.d.ts +5 -0
  243. package/dist/interaction/qte.js +5 -0
  244. package/dist/interaction/skillCheck.d.ts +5 -0
  245. package/dist/interaction/skillCheck.js +5 -0
  246. package/dist/inventory/inventoryModel.d.ts +12 -0
  247. package/dist/inventory/inventoryModel.js +12 -0
  248. package/dist/inventory/shapedGrid.d.ts +16 -0
  249. package/dist/inventory/shapedGrid.js +16 -0
  250. package/dist/inventory/slotModel.d.ts +10 -0
  251. package/dist/inventory/slotModel.js +10 -0
  252. package/dist/item/durability.d.ts +5 -0
  253. package/dist/item/durability.js +5 -0
  254. package/dist/item/itemIdentity.d.ts +171 -0
  255. package/dist/item/itemIdentity.js +138 -0
  256. package/dist/item/itemInstanceRegistry.d.ts +32 -0
  257. package/dist/item/itemInstanceRegistry.js +34 -0
  258. package/dist/item/itemgen.d.ts +163 -0
  259. package/dist/item/itemgen.js +151 -0
  260. package/dist/item/modularItem.d.ts +5 -0
  261. package/dist/item/modularItem.js +5 -0
  262. package/dist/item/use.d.ts +5 -0
  263. package/dist/item/use.js +5 -0
  264. package/dist/item/useBehavior.d.ts +142 -0
  265. package/dist/item/useBehavior.js +105 -0
  266. package/dist/item/weapon.d.ts +5 -0
  267. package/dist/item/weapon.js +5 -0
  268. package/dist/math/scalar.d.ts +25 -0
  269. package/dist/math/scalar.js +47 -0
  270. package/dist/meta/changelog.d.ts +4 -1
  271. package/dist/meta/changelog.js +36 -1
  272. package/dist/movement/avoidance.d.ts +45 -0
  273. package/dist/movement/avoidance.js +123 -0
  274. package/dist/movement/cameraRig.d.ts +8 -0
  275. package/dist/movement/cameraRig.js +8 -0
  276. package/dist/movement/dash.d.ts +11 -0
  277. package/dist/movement/dash.js +11 -0
  278. package/dist/movement/formation.d.ts +135 -0
  279. package/dist/movement/formation.js +194 -0
  280. package/dist/movement/glideModel.d.ts +5 -0
  281. package/dist/movement/glideModel.js +5 -0
  282. package/dist/movement/grappleSwing.d.ts +5 -0
  283. package/dist/movement/grappleSwing.js +5 -0
  284. package/dist/movement/leaderTrail.d.ts +5 -0
  285. package/dist/movement/leaderTrail.js +5 -0
  286. package/dist/movement/movementModel.d.ts +38 -7
  287. package/dist/movement/movementModel.js +54 -13
  288. package/dist/movement/playerMovement.d.ts +41 -0
  289. package/dist/movement/playerMovement.js +236 -0
  290. package/dist/movement/poseState.d.ts +13 -0
  291. package/dist/movement/poseState.js +16 -0
  292. package/dist/movement/steering.d.ts +8 -0
  293. package/dist/movement/steering.js +18 -0
  294. package/dist/multiplayer/combatSnapshot.d.ts +3 -0
  295. package/dist/multiplayer/combatSnapshot.js +3 -0
  296. package/dist/multiplayer/lagCompensation.d.ts +5 -0
  297. package/dist/multiplayer/lagCompensation.js +5 -0
  298. package/dist/multiplayer/presenceModel.d.ts +9 -1
  299. package/dist/multiplayer/presenceModel.js +9 -1
  300. package/dist/multiplayer/simultaneousCommit.d.ts +3 -0
  301. package/dist/multiplayer/simultaneousCommit.js +3 -0
  302. package/dist/multiplayer.d.ts +11 -0
  303. package/dist/multiplayer.js +11 -0
  304. package/dist/nav/pathFollow.d.ts +57 -0
  305. package/dist/nav/pathFollow.js +109 -0
  306. package/dist/orders/orderKinds.d.ts +156 -0
  307. package/dist/orders/orderKinds.js +197 -0
  308. package/dist/orders/orderQueue.d.ts +208 -0
  309. package/dist/orders/orderQueue.js +211 -0
  310. package/dist/physics/drivableVehicle.d.ts +29 -0
  311. package/dist/physics/drivableVehicle.js +16 -0
  312. package/dist/physics/kinematicVehicle.d.ts +21 -1
  313. package/dist/physics/kinematicVehicle.js +23 -8
  314. package/dist/physics/physicsWorld.d.ts +24 -12
  315. package/dist/physics/physicsWorld.js +11 -5
  316. package/dist/physics/radialImpulse.d.ts +25 -0
  317. package/dist/physics/radialImpulse.js +27 -0
  318. package/dist/procedural.d.ts +3 -0
  319. package/dist/procedural.js +3 -0
  320. package/dist/progression/statGraph.d.ts +116 -0
  321. package/dist/progression/statGraph.js +318 -0
  322. package/dist/puzzle/cellGrid.d.ts +9 -0
  323. package/dist/puzzle/cellGrid.js +9 -0
  324. package/dist/puzzle/fallingPiece.d.ts +9 -0
  325. package/dist/puzzle/fallingPiece.js +9 -0
  326. package/dist/puzzle/nonogram.d.ts +39 -0
  327. package/dist/puzzle/nonogram.js +136 -0
  328. package/dist/random/nameGen.d.ts +5 -0
  329. package/dist/random/nameGen.js +5 -0
  330. package/dist/random/pick.d.ts +8 -0
  331. package/dist/random/pick.js +31 -0
  332. package/dist/random/rng.d.ts +24 -0
  333. package/dist/random/rng.js +30 -8
  334. package/dist/random/seedLink.d.ts +4 -0
  335. package/dist/random/seedLink.js +4 -0
  336. package/dist/relation/keyedValues.d.ts +54 -0
  337. package/dist/relation/keyedValues.js +115 -0
  338. package/dist/relation/thresholds.d.ts +62 -0
  339. package/dist/relation/thresholds.js +62 -0
  340. package/dist/render/color.d.ts +12 -0
  341. package/dist/render/color.js +26 -0
  342. package/dist/render/lookPreset.d.ts +41 -0
  343. package/dist/render/lookPreset.js +29 -0
  344. package/dist/render/postProcessing.d.ts +76 -0
  345. package/dist/render/postProcessing.js +21 -0
  346. package/dist/rules/predicate.d.ts +53 -0
  347. package/dist/rules/predicate.js +64 -0
  348. package/dist/rules/ruleEffects.d.ts +38 -0
  349. package/dist/rules/ruleEffects.js +37 -0
  350. package/dist/rules/triggeredRules.d.ts +160 -0
  351. package/dist/rules/triggeredRules.js +241 -0
  352. package/dist/runtime/adapter.d.ts +58 -0
  353. package/dist/runtime/adapter.js +54 -5
  354. package/dist/runtime/cameraDirector.d.ts +1 -0
  355. package/dist/runtime/cameraDirector.js +1 -0
  356. package/dist/runtime/commandRunner.d.ts +1 -0
  357. package/dist/runtime/commandRunner.js +1 -0
  358. package/dist/runtime/context/combatFx.d.ts +23 -0
  359. package/dist/runtime/context/combatFx.js +161 -0
  360. package/dist/runtime/context/registries.d.ts +13 -0
  361. package/dist/runtime/context/registries.js +84 -0
  362. package/dist/runtime/context/worldItems.d.ts +21 -0
  363. package/dist/runtime/context/worldItems.js +37 -0
  364. package/dist/runtime/descriptors/baseline.d.ts +48 -0
  365. package/dist/runtime/descriptors/baseline.js +134 -0
  366. package/dist/runtime/descriptors/features.d.ts +74 -0
  367. package/dist/runtime/descriptors/features.js +281 -0
  368. package/dist/runtime/gameContext.d.ts +163 -19
  369. package/dist/runtime/gameContext.js +385 -339
  370. package/dist/runtime/gameRuntime.d.ts +1 -0
  371. package/dist/runtime/gameRuntime.js +1 -0
  372. package/dist/runtime/headlessRunner.d.ts +60 -0
  373. package/dist/runtime/headlessRunner.js +44 -0
  374. package/dist/runtime/hostPersistence.d.ts +12 -0
  375. package/dist/runtime/hostPersistence.js +12 -0
  376. package/dist/runtime/hostedGameRunner.d.ts +54 -0
  377. package/dist/runtime/hostedGameRunner.js +85 -0
  378. package/dist/runtime/hostedWorldSession.d.ts +73 -0
  379. package/dist/runtime/hostedWorldSession.js +64 -0
  380. package/dist/runtime/inputSnapshot.d.ts +21 -3
  381. package/dist/runtime/inputSnapshot.js +8 -2
  382. package/dist/runtime/motionIntents.d.ts +12 -1
  383. package/dist/runtime/motionIntents.js +26 -1
  384. package/dist/runtime/perContext.d.ts +15 -0
  385. package/dist/runtime/perContext.js +21 -0
  386. package/dist/runtime/runtimeSave.d.ts +79 -0
  387. package/dist/runtime/runtimeSave.js +105 -0
  388. package/dist/runtime/save.d.ts +4 -0
  389. package/dist/runtime/save.js +4 -0
  390. package/dist/runtime/snapshot.d.ts +7 -0
  391. package/dist/runtime/snapshot.js +7 -0
  392. package/dist/runtime/visibility.d.ts +2 -1
  393. package/dist/runtime/visibility.js +2 -1
  394. package/dist/runtime/worldChannel.d.ts +62 -0
  395. package/dist/runtime/worldChannel.js +114 -0
  396. package/dist/runtime/worldMirror.d.ts +36 -0
  397. package/dist/runtime/worldMirror.js +44 -0
  398. package/dist/runtime/worldProjection.d.ts +47 -0
  399. package/dist/runtime/worldProjection.js +52 -0
  400. package/dist/runtime/worldReplication.d.ts +69 -0
  401. package/dist/runtime/worldReplication.js +217 -0
  402. package/dist/runtime/worldSnapshot.d.ts +44 -0
  403. package/dist/runtime/worldSnapshot.js +30 -0
  404. package/dist/scene/assetCatalog.d.ts +22 -0
  405. package/dist/scene/assetCatalog.js +4 -0
  406. package/dist/scene/assetDiagnostics.d.ts +69 -0
  407. package/dist/scene/assetDiagnostics.js +110 -0
  408. package/dist/scene/assetGenerator.d.ts +65 -0
  409. package/dist/scene/assetGenerator.js +64 -0
  410. package/dist/scene/assetSpace.d.ts +137 -0
  411. package/dist/scene/assetSpace.js +259 -0
  412. package/dist/scene/authoredTriggers.d.ts +169 -0
  413. package/dist/scene/authoredTriggers.js +340 -0
  414. package/dist/scene/behaviorRuntime.d.ts +75 -0
  415. package/dist/scene/behaviorRuntime.js +217 -0
  416. package/dist/scene/behaviors.d.ts +14 -2
  417. package/dist/scene/behaviors.js +7 -2
  418. package/dist/scene/bodyBind.d.ts +60 -0
  419. package/dist/scene/bodyBind.js +51 -0
  420. package/dist/scene/builtinSceneKinds.d.ts +5 -0
  421. package/dist/scene/builtinSceneKinds.js +62 -0
  422. package/dist/scene/colliders.d.ts +18 -0
  423. package/dist/scene/colliders.js +61 -1
  424. package/dist/scene/entityStats.d.ts +13 -0
  425. package/dist/scene/entityStats.js +30 -0
  426. package/dist/scene/entityStore.d.ts +41 -1
  427. package/dist/scene/entityStore.js +75 -0
  428. package/dist/scene/facing.d.ts +18 -0
  429. package/dist/scene/facing.js +26 -0
  430. package/dist/scene/modelSockets.d.ts +33 -0
  431. package/dist/scene/modelSockets.js +29 -0
  432. package/dist/scene/objectQuery.d.ts +2 -0
  433. package/dist/scene/objectQuery.js +2 -0
  434. package/dist/scene/objectStore.d.ts +4 -0
  435. package/dist/scene/objectStore.js +6 -0
  436. package/dist/scene/possession.d.ts +8 -0
  437. package/dist/scene/possession.js +14 -0
  438. package/dist/scene/roster.d.ts +3 -0
  439. package/dist/scene/roster.js +12 -0
  440. package/dist/scene/sceneKinds.d.ts +240 -0
  441. package/dist/scene/sceneKinds.js +214 -0
  442. package/dist/scene/sceneOwnership.d.ts +169 -0
  443. package/dist/scene/sceneOwnership.js +179 -0
  444. package/dist/scene/selectionBookmarks.d.ts +93 -0
  445. package/dist/scene/selectionBookmarks.js +122 -0
  446. package/dist/scene/vehicleSeat.d.ts +68 -0
  447. package/dist/scene/vehicleSeat.js +59 -0
  448. package/dist/sensor/concealment.d.ts +3 -0
  449. package/dist/sensor/concealment.js +3 -0
  450. package/dist/sensor/freezeMonitor.d.ts +1 -0
  451. package/dist/sensor/freezeMonitor.js +1 -0
  452. package/dist/sensor/frustumSensor.d.ts +7 -3
  453. package/dist/sensor/frustumSensor.js +7 -3
  454. package/dist/sensor/hiddenStateProbe.d.ts +5 -2
  455. package/dist/sensor/hiddenStateProbe.js +5 -2
  456. package/dist/sensor/recordingBuffer.d.ts +2 -1
  457. package/dist/sensor/recordingBuffer.js +2 -1
  458. package/dist/sensor/replayLoop.d.ts +6 -2
  459. package/dist/sensor/replayLoop.js +6 -2
  460. package/dist/sensor/revealQuery.d.ts +2 -1
  461. package/dist/sensor/revealQuery.js +2 -1
  462. package/dist/sensor/visionCone.d.ts +10 -3
  463. package/dist/sensor/visionCone.js +10 -3
  464. package/dist/session/contestedChannel.d.ts +1 -0
  465. package/dist/session/contestedChannel.js +1 -0
  466. package/dist/session/extraction.d.ts +1 -0
  467. package/dist/session/extraction.js +1 -0
  468. package/dist/session/roles.d.ts +6 -0
  469. package/dist/session/roles.js +6 -0
  470. package/dist/session/roundState.d.ts +8 -0
  471. package/dist/session/roundState.js +2 -0
  472. package/dist/settings/settingsModel.d.ts +1 -0
  473. package/dist/settings/settingsModel.js +1 -0
  474. package/dist/stats/accumulatorMeter.d.ts +6 -0
  475. package/dist/stats/accumulatorMeter.js +6 -0
  476. package/dist/stats/eventMeter.d.ts +5 -0
  477. package/dist/stats/eventMeter.js +5 -0
  478. package/dist/stats/rollCheck.d.ts +5 -0
  479. package/dist/stats/rollCheck.js +5 -0
  480. package/dist/stats/statModifiers.d.ts +5 -0
  481. package/dist/stats/statModifiers.js +5 -0
  482. package/dist/store/defineKeyedStore.d.ts +38 -0
  483. package/dist/store/defineKeyedStore.js +42 -0
  484. package/dist/store/defineStore.d.ts +33 -0
  485. package/dist/store/defineStore.js +35 -0
  486. package/dist/store/observableKeyedStore.d.ts +9 -0
  487. package/dist/store/observableKeyedStore.js +43 -2
  488. package/dist/survival/decayMeter.d.ts +55 -0
  489. package/dist/survival/decayMeter.js +130 -55
  490. package/dist/survival/moodle.d.ts +2 -0
  491. package/dist/survival/regionHealth.d.ts +6 -0
  492. package/dist/survival/regionHealth.js +5 -0
  493. package/dist/tactics/fallingGrid.d.ts +6 -4
  494. package/dist/tactics/fallingGrid.js +6 -4
  495. package/dist/tactics/predictiveQuery.d.ts +3 -0
  496. package/dist/tactics/predictiveQuery.js +3 -0
  497. package/dist/tactics/snapshot.d.ts +2 -0
  498. package/dist/tactics/snapshot.js +2 -0
  499. package/dist/tactics/surface.d.ts +1 -0
  500. package/dist/tactics/surface.js +1 -0
  501. package/dist/tactics/tacticalGrid.d.ts +1 -0
  502. package/dist/tactics/tacticalGrid.js +1 -0
  503. package/dist/time/beatClock.d.ts +14 -4
  504. package/dist/time/beatClock.js +14 -4
  505. package/dist/time/calendarClock.d.ts +3 -0
  506. package/dist/time/calendarClock.js +3 -0
  507. package/dist/time/idleProgress.d.ts +4 -0
  508. package/dist/time/idleProgress.js +4 -0
  509. package/dist/time/simClock.d.ts +2 -0
  510. package/dist/time/simClock.js +20 -5
  511. package/dist/ui/actionModel.d.ts +110 -0
  512. package/dist/ui/actionModel.js +159 -0
  513. package/dist/ui/gameLayout.d.ts +144 -0
  514. package/dist/ui/gameLayout.js +148 -0
  515. package/dist/ui/hudDocument.d.ts +114 -0
  516. package/dist/ui/hudDocument.js +220 -0
  517. package/dist/ui/hudLayout.d.ts +33 -1
  518. package/dist/ui/hudLayout.js +204 -17
  519. package/dist/ui/orientation.d.ts +39 -0
  520. package/dist/ui/orientation.js +49 -0
  521. package/dist/ui/selectionModel.d.ts +92 -0
  522. package/dist/ui/selectionModel.js +88 -0
  523. package/dist/ui/swingTimer.d.ts +42 -0
  524. package/dist/ui/swingTimer.js +38 -0
  525. package/dist/ui/tooltipModel.d.ts +63 -0
  526. package/dist/ui/tooltipModel.js +82 -0
  527. package/dist/ui.d.ts +15 -0
  528. package/dist/ui.js +15 -0
  529. package/dist/visibility/bounds.d.ts +8 -1
  530. package/dist/visibility/bounds.js +8 -1
  531. package/dist/visibility/frustum.d.ts +12 -3
  532. package/dist/visibility/frustum.js +12 -3
  533. package/dist/visibility/spatialIndex.js +34 -20
  534. package/dist/work/jobQueue.d.ts +201 -0
  535. package/dist/work/jobQueue.js +253 -0
  536. package/dist/work/unitTraining.d.ts +58 -0
  537. package/dist/work/unitTraining.js +52 -0
  538. package/dist/world/authoredObjects.d.ts +58 -0
  539. package/dist/world/authoredObjects.js +69 -0
  540. package/dist/world/buildingGenerator.d.ts +18 -0
  541. package/dist/world/buildingGenerator.js +62 -0
  542. package/dist/world/buildings.d.ts +5 -0
  543. package/dist/world/buildings.js +5 -0
  544. package/dist/world/catenary.d.ts +22 -0
  545. package/dist/world/catenary.js +69 -0
  546. package/dist/world/environmentSummary.d.ts +11 -2
  547. package/dist/world/environmentSummary.js +11 -1
  548. package/dist/world/features.d.ts +244 -7
  549. package/dist/world/features.js +92 -4
  550. package/dist/world/footprintGrid.d.ts +59 -0
  551. package/dist/world/footprintGrid.js +141 -0
  552. package/dist/world/geometry.d.ts +64 -0
  553. package/dist/world/geometry.js +94 -0
  554. package/dist/world/grassKind.d.ts +51 -0
  555. package/dist/world/grassKind.js +101 -0
  556. package/dist/world/pathInstances.d.ts +27 -0
  557. package/dist/world/pathInstances.js +27 -0
  558. package/dist/world/pathTerrain.d.ts +80 -0
  559. package/dist/world/pathTerrain.js +142 -0
  560. package/dist/world/placeAsset.d.ts +81 -0
  561. package/dist/world/placeAsset.js +77 -0
  562. package/dist/world/placement.d.ts +4 -0
  563. package/dist/world/placement.js +4 -0
  564. package/dist/world/placementController.d.ts +6 -0
  565. package/dist/world/placementController.js +6 -0
  566. package/dist/world/polyline.d.ts +34 -0
  567. package/dist/world/polyline.js +81 -0
  568. package/dist/world/roads.d.ts +55 -0
  569. package/dist/world/roads.js +184 -0
  570. package/dist/world/scatterRegion.d.ts +164 -0
  571. package/dist/world/scatterRegion.js +409 -0
  572. package/dist/world/sceneShapes.d.ts +43 -0
  573. package/dist/world/sceneShapes.js +1 -0
  574. package/dist/world/segment.d.ts +27 -0
  575. package/dist/world/segment.js +43 -0
  576. package/dist/world/soilKind.d.ts +48 -0
  577. package/dist/world/soilKind.js +92 -0
  578. package/dist/world/spatialSample.d.ts +241 -0
  579. package/dist/world/spatialSample.js +465 -0
  580. package/dist/world/streets.d.ts +80 -0
  581. package/dist/world/streets.js +144 -0
  582. package/dist/world/terraform.d.ts +213 -1
  583. package/dist/world/terraform.js +655 -20
  584. package/dist/world/terrain.d.ts +138 -12
  585. package/dist/world/terrain.js +346 -28
  586. package/dist/world/terrainGuides.d.ts +182 -0
  587. package/dist/world/terrainGuides.js +343 -0
  588. package/dist/world/vec2.d.ts +81 -0
  589. package/dist/world/vec2.js +128 -0
  590. package/dist/world/vec3.d.ts +49 -0
  591. package/dist/world/vec3.js +76 -0
  592. package/dist/world/vegetation.d.ts +71 -0
  593. package/dist/world/vegetation.js +151 -0
  594. package/dist/world/visibilityField.d.ts +154 -0
  595. package/dist/world/visibilityField.js +271 -0
  596. package/dist/world/volumetricClouds.d.ts +52 -0
  597. package/dist/world/volumetricClouds.js +43 -0
  598. package/dist/world/walls.d.ts +9 -0
  599. package/dist/world/walls.js +9 -0
  600. package/dist/world/waterKind.d.ts +55 -0
  601. package/dist/world/waterKind.js +99 -0
  602. package/dist/world.d.ts +132 -0
  603. package/dist/world.js +132 -0
  604. package/package.json +32 -8
  605. package/skills/jgengine/SKILL.md +51 -0
  606. package/skills/jgengine/api.md +434 -0
  607. package/skills/jgengine/capabilities.md +29 -0
  608. package/skills/jgengine/reference-cartridge.md +72 -0
  609. package/skills/jgengine-combat/SKILL.md +34 -0
  610. package/skills/jgengine-combat/api.md +549 -0
  611. package/skills/jgengine-combat/capabilities.md +169 -0
  612. package/skills/jgengine-combat/reference.md +98 -0
  613. package/skills/jgengine-gameplay/SKILL.md +39 -0
  614. package/skills/jgengine-gameplay/api.md +1794 -0
  615. package/skills/jgengine-gameplay/capabilities.md +378 -0
  616. package/skills/jgengine-gameplay/reference-systems.md +60 -0
  617. package/skills/jgengine-world/SKILL.md +38 -0
  618. package/skills/jgengine-world/api.md +2652 -0
  619. package/skills/jgengine-world/capabilities.md +370 -0
  620. package/skills/jgengine-world/reference.md +222 -0
  621. package/dist/cartridge/runtime.d.ts +0 -15
  622. package/dist/cartridge/runtime.js +0 -556
  623. package/dist/cartridge/spec.d.ts +0 -188
  624. package/dist/cartridge/spec.js +0 -19
  625. package/dist/cartridge/validate.d.ts +0 -2
  626. package/dist/cartridge/validate.js +0 -78
  627. package/dist/store/engineStore.d.ts +0 -22
  628. package/dist/store/engineStore.js +0 -50
  629. package/dist/store/features.d.ts +0 -10
  630. package/dist/store/features.js +0 -23
  631. package/llms.txt +0 -4983
@@ -0,0 +1,884 @@
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
+ */
31
+ export function createEmptyEditorDocument() {
32
+ return {
33
+ version: 1,
34
+ markers: [],
35
+ volumes: [],
36
+ paths: [],
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 } }),
48
+ };
49
+ }
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
+ */
62
+ export function cloneEditorDocument(doc) {
63
+ const ui = cloneEditorUiDocument(doc.ui);
64
+ return {
65
+ version: 1,
66
+ markers: doc.markers.map((marker) => ({
67
+ ...marker,
68
+ position: { ...marker.position },
69
+ ...(marker.meta === undefined ? {} : { meta: { ...marker.meta } }),
70
+ })),
71
+ volumes: doc.volumes.map((volume) => ({
72
+ ...volume,
73
+ center: { ...volume.center },
74
+ ...(volume.halfExtents === undefined ? {} : { halfExtents: { ...volume.halfExtents } }),
75
+ ...(volume.meta === undefined ? {} : { meta: { ...volume.meta } }),
76
+ })),
77
+ paths: doc.paths.map((path) => ({
78
+ ...path,
79
+ points: path.points.map((point) => ({ ...point })),
80
+ ...(path.meta === undefined ? {} : { meta: { ...path.meta } }),
81
+ })),
82
+ annotations: doc.annotations.map((note) => ({
83
+ ...note,
84
+ position: { ...note.position },
85
+ ...(note.meta === undefined ? {} : { meta: { ...note.meta } }),
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 }),
101
+ };
102
+ }
103
+ function asArray(value) {
104
+ return value === undefined ? [] : [...value];
105
+ }
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
+ */
123
+ export function normalizeEditorLayers(input) {
124
+ if (input === undefined || input === null)
125
+ return createEmptyEditorDocument();
126
+ const resolved = typeof input === "function" ? input() : input;
127
+ const ui = cloneEditorUiDocument(resolved.ui);
128
+ return {
129
+ version: 1,
130
+ markers: asArray(resolved.markers),
131
+ volumes: asArray(resolved.volumes),
132
+ paths: asArray(resolved.paths),
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 }),
140
+ };
141
+ }
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
+ */
169
+ export function mergeEditorDocuments(...docs) {
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
+ };
176
+ for (const doc of docs) {
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
+ }
197
+ }
198
+ return out;
199
+ }
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
+ */
312
+ export function findEditorMarker(doc, id) {
313
+ return doc.markers.find((marker) => marker.id === id);
314
+ }
315
+ /** Looks up a volume by id in an editor document.
316
+ * @internal
317
+ */
318
+ export function findEditorVolume(doc, id) {
319
+ return doc.volumes.find((volume) => volume.id === id);
320
+ }
321
+ /** Looks up a path by id in an editor document.
322
+ * @internal
323
+ */
324
+ export function findEditorPath(doc, id) {
325
+ return doc.paths.find((path) => path.id === id);
326
+ }
327
+ /** Looks up an annotation note by id in an editor document.
328
+ * @internal
329
+ */
330
+ export function findEditorNote(doc, id) {
331
+ return doc.annotations.find((note) => note.id === id);
332
+ }
333
+ /** Lists the distinct marker, volume, and path kinds authored in a document.
334
+ * @internal
335
+ */
336
+ export function listEditorKinds(doc) {
337
+ const markers = new Set();
338
+ const volumes = new Set();
339
+ const paths = new Set();
340
+ for (const marker of doc.markers)
341
+ markers.add(marker.kind);
342
+ for (const volume of doc.volumes)
343
+ volumes.add(volume.kind);
344
+ for (const path of doc.paths)
345
+ paths.add(path.kind);
346
+ return {
347
+ markers: [...markers].sort(),
348
+ volumes: [...volumes].sort(),
349
+ paths: [...paths].sort(),
350
+ };
351
+ }
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
+ */
418
+ export function exportEditorDocumentJson(doc, pretty = true) {
419
+ return JSON.stringify(doc, null, pretty ? 2 : undefined);
420
+ }
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
+ */
797
+ export function importEditorDocumentJson(raw) {
798
+ const parsed = JSON.parse(raw);
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("; ")}`);
802
+ }
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
+ };
838
+ }
839
+ /** Computes the world-space min/max bounds spanning every object in a document, or null if empty.
840
+ * @internal
841
+ */
842
+ export function editorDocumentBounds(doc) {
843
+ let minX = Infinity;
844
+ let minY = Infinity;
845
+ let minZ = Infinity;
846
+ let maxX = -Infinity;
847
+ let maxY = -Infinity;
848
+ let maxZ = -Infinity;
849
+ let any = false;
850
+ const include = (x, y, z) => {
851
+ any = true;
852
+ if (x < minX)
853
+ minX = x;
854
+ if (y < minY)
855
+ minY = y;
856
+ if (z < minZ)
857
+ minZ = z;
858
+ if (x > maxX)
859
+ maxX = x;
860
+ if (y > maxY)
861
+ maxY = y;
862
+ if (z > maxZ)
863
+ maxZ = z;
864
+ };
865
+ for (const marker of doc.markers) {
866
+ include(marker.position.x, marker.position.y, marker.position.z);
867
+ }
868
+ for (const volume of doc.volumes) {
869
+ include(volume.center.x, volume.center.y, volume.center.z);
870
+ }
871
+ for (const path of doc.paths) {
872
+ for (const point of path.points)
873
+ include(point.x, point.y, point.z);
874
+ }
875
+ for (const note of doc.annotations) {
876
+ include(note.position.x, note.position.y, note.position.z);
877
+ }
878
+ if (!any)
879
+ return null;
880
+ return {
881
+ min: { x: minX, y: minY, z: minZ },
882
+ max: { x: maxX, y: maxY, z: maxZ },
883
+ };
884
+ }