@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,110 @@
1
+ /**
2
+ * Pure, zero-dependency classification of a model-asset fetch before it reaches
3
+ * a GLTF parser. Runtime loaders hand the raw response (status, content type,
4
+ * and the first bytes) to {@link classifyAssetResponse} so a missing or
5
+ * mis-served file surfaces as an actionable diagnostic naming the broken asset
6
+ * contract, instead of the opaque "Unexpected token < in JSON" parse error a
7
+ * dev-server HTML fallback otherwise produces. No `fetch`, DOM, or three.js
8
+ * dependency lives here — callers supply the already-read bytes.
9
+ */
10
+ /** GLB little-endian magic — the ASCII "glTF" at byte 0 of a binary glTF container. @internal */
11
+ export const GLB_MAGIC_ASCII = "glTF";
12
+ function startsWithAscii(bytes, ascii) {
13
+ if (bytes.length < ascii.length)
14
+ return false;
15
+ for (let i = 0; i < ascii.length; i += 1) {
16
+ if (bytes[i] !== ascii.charCodeAt(i))
17
+ return false;
18
+ }
19
+ return true;
20
+ }
21
+ /** Skip a UTF-8 BOM and leading ASCII whitespace, returning the index of the first meaningful byte. */
22
+ function firstNonBlank(bytes) {
23
+ let i = 0;
24
+ if (bytes.length >= 3 && bytes[0] === 0xef && bytes[1] === 0xbb && bytes[2] === 0xbf)
25
+ i = 3;
26
+ while (i < bytes.length) {
27
+ const b = bytes[i];
28
+ // space, tab, CR, LF
29
+ if (b === 0x20 || b === 0x09 || b === 0x0d || b === 0x0a)
30
+ i += 1;
31
+ else
32
+ break;
33
+ }
34
+ return i;
35
+ }
36
+ /**
37
+ * Classify the leading bytes of a response body by their format signature, with
38
+ * no HTTP context. Recognizes GLB (`glTF` magic), glTF-JSON (a leading `{`), an
39
+ * HTML fallback page (`<!doctype`, `<html`, or a bare `<`), and a few common
40
+ * non-model binaries (PNG, JPEG, ZIP) so they can be reported as unsupported
41
+ * rather than corrupt.
42
+ */
43
+ export function readByteSignature(bytes) {
44
+ if (bytes.length === 0)
45
+ return "empty";
46
+ if (startsWithAscii(bytes, GLB_MAGIC_ASCII))
47
+ return "glb";
48
+ if (bytes.length >= 8 && bytes[0] === 0x89 && bytes[1] === 0x50 && bytes[2] === 0x4e && bytes[3] === 0x47) {
49
+ return "png";
50
+ }
51
+ if (bytes.length >= 3 && bytes[0] === 0xff && bytes[1] === 0xd8 && bytes[2] === 0xff)
52
+ return "jpeg";
53
+ if (bytes.length >= 4 && bytes[0] === 0x50 && bytes[1] === 0x4b && bytes[2] === 0x03 && bytes[3] === 0x04) {
54
+ return "zip";
55
+ }
56
+ const start = firstNonBlank(bytes);
57
+ const head = bytes[start];
58
+ if (head === undefined)
59
+ return "empty";
60
+ // '<' — an HTML document served where a model was expected.
61
+ if (head === 0x3c)
62
+ return "html";
63
+ // '{' — glTF-JSON (the non-binary .gltf form) is a parseable model.
64
+ if (head === 0x7b)
65
+ return "gltf-json";
66
+ return "unknown";
67
+ }
68
+ function describe(logicalId, url) {
69
+ return logicalId === undefined ? `"${url}"` : `"${logicalId}" (${url})`;
70
+ }
71
+ /**
72
+ * Turn a {@link AssetResponseProbe} into an {@link AssetLoadDiagnosis}. HTTP
73
+ * status is checked first (a `>= 400` or `0` status is `missing`), then the
74
+ * `Content-Type` and byte signature decide between an HTML fallback, a
75
+ * parseable model (`ok`), an unsupported-but-recognizable format, and otherwise
76
+ * corrupt bytes. The returned `message` always names the asset and URL and, for
77
+ * failures, points at the likely fix (provision the pack, check the serving path).
78
+ *
79
+ * @capability asset-load-diagnostics classify a model fetch (missing / HTML fallback / corrupt / unsupported) before parsing
80
+ */
81
+ export function classifyAssetResponse(probe) {
82
+ const { url, logicalId, status, statusText, contentType, bytes } = probe;
83
+ const signature = bytes === undefined ? "empty" : readByteSignature(bytes);
84
+ const who = describe(logicalId, url);
85
+ const finish = (kind, message) => ({
86
+ kind,
87
+ ok: kind === "ok",
88
+ url,
89
+ ...(logicalId === undefined ? {} : { logicalId }),
90
+ byteSignature: signature,
91
+ message,
92
+ });
93
+ if (status !== undefined && (status === 0 || status >= 400)) {
94
+ const suffix = statusText === undefined || statusText.length === 0 ? "" : ` ${statusText}`;
95
+ return finish("missing", `Asset ${who} did not load: HTTP ${status}${suffix}. The file is not being served — provision the pack (e.g. \`assets pull <source>\`) or check the model path.`);
96
+ }
97
+ const htmlContentType = contentType !== undefined && contentType.toLowerCase().includes("text/html");
98
+ if (signature === "html" || (htmlContentType && signature !== "glb" && signature !== "gltf-json")) {
99
+ return finish("html", `Asset ${who} resolved to an HTML page, not a model — the dev server returned its fallback document because the file is missing. Provision the pack (\`assets pull <source>\`) so the bytes exist under the served path.`);
100
+ }
101
+ if (signature === "glb" || signature === "gltf-json")
102
+ return finish("ok", `Asset ${who} loaded (${signature}).`);
103
+ if (signature === "png" || signature === "jpeg" || signature === "zip") {
104
+ return finish("unsupported", `Asset ${who} is a ${signature} file, not a GLB/glTF model — the reference points at the wrong file or the wrong loader is being used.`);
105
+ }
106
+ if (signature === "empty") {
107
+ return finish("corrupt", `Asset ${who} returned an empty body — the file exists but has no bytes. Re-provision the pack or remove the reference.`);
108
+ }
109
+ return finish("corrupt", `Asset ${who} is not a recognizable GLB/glTF model (leading bytes do not match any known signature). The file is likely truncated or corrupt — re-provision the pack.`);
110
+ }
@@ -0,0 +1,65 @@
1
+ /**
2
+ * The generator-asset seam: register a parametric asset generator (`generate(params, seed) → parts`)
3
+ * so a slider-driven prop (a bookcase with width/shelves/book-density, a building with floors/bays)
4
+ * lives in the catalog alongside static GLBs. A placed instance stores only `{ assetId, params, seed }`
5
+ * — the geometry is re-resolved at runtime, never baked. Schema drives the inspector via #809. The
6
+ * generic seam is engine; concrete generators (building, bookcase) are adopters registered from
7
+ * game/example code — the building generator is the one engine adopter, as a proof it composes.
8
+ *
9
+ * @capability asset-generator seeded parametric geometry registered as a placeable asset
10
+ */
11
+ import { type ParamSchema, type ParsedParams } from "./sceneKinds.js";
12
+ /** One generated primitive part — a box/panel placed in the asset's local space. */
13
+ export interface GeneratedPart {
14
+ id: string;
15
+ /** Optional semantic tag (shelf, board, book, wall, window …) for materials/inspection. */
16
+ kind?: string;
17
+ /** Local-space center. */
18
+ position: readonly [number, number, number];
19
+ /** Full box dimensions (w, h, d) in meters. */
20
+ size: readonly [number, number, number];
21
+ rotationY?: number;
22
+ /** Hex color; the renderer falls back to a neutral material when absent. */
23
+ color?: string;
24
+ }
25
+ /** A resolved generator asset: its parts plus the overall local-space bounds (min/max corners). */
26
+ export interface GeneratedAsset {
27
+ parts: GeneratedPart[];
28
+ bounds: {
29
+ min: readonly [number, number, number];
30
+ max: readonly [number, number, number];
31
+ };
32
+ /**
33
+ * The declared local-space direction the asset's "front" faces (a bookcase's open/book face, a
34
+ * building's entrance) — so a camera rig or placement tool can orient it without hand-tuned
35
+ * `rotationY`. Omit to use the convention default, +Z (`DEFAULT_FORWARD` in `./facing`); every
36
+ * generator should build its front toward +Z unless it declares otherwise.
37
+ */
38
+ forward?: readonly [number, number, number];
39
+ }
40
+ /** A registered asset generator — schema drives the inspector; `generate` is a pure seeded function. */
41
+ export interface AssetGeneratorDefinition {
42
+ id: string;
43
+ label: string;
44
+ schema: ParamSchema;
45
+ /** Deterministic geometry from validated params + a seed string. Same inputs → same parts. */
46
+ generate: (params: ParsedParams, seed: string) => GeneratedAsset;
47
+ }
48
+ /** Register a parametric asset generator. Idempotent per id (last wins); call at module load. */
49
+ export declare function registerAssetGenerator(definition: AssetGeneratorDefinition): void;
50
+ /** The registered generator for an id, or undefined. @internal */
51
+ export declare function getAssetGenerator(id: string): AssetGeneratorDefinition | undefined;
52
+ /** Every registered generator, in registration order. @internal */
53
+ export declare function listAssetGenerators(): AssetGeneratorDefinition[];
54
+ /**
55
+ * Compute bounds from parts (each part is an axis-aligned box at its center) — a helper generators
56
+ * return so callers can frame/ground the asset without re-deriving it.
57
+ */
58
+ export declare function partsBounds(parts: readonly GeneratedPart[]): GeneratedAsset["bounds"];
59
+ /**
60
+ * Re-resolve a placed generator instance from its stored `meta` (`{ assetId, seed, ...params }`): look
61
+ * up the generator, parse its params off `meta` against the schema, and generate. Returns null when
62
+ * `assetId` names no registered generator. This is what a runtime renderer calls per placed instance.
63
+ * @internal
64
+ */
65
+ export declare function resolveGeneratorAsset(meta: Record<string, unknown> | undefined): GeneratedAsset | null;
@@ -0,0 +1,64 @@
1
+ /**
2
+ * The generator-asset seam: register a parametric asset generator (`generate(params, seed) → parts`)
3
+ * so a slider-driven prop (a bookcase with width/shelves/book-density, a building with floors/bays)
4
+ * lives in the catalog alongside static GLBs. A placed instance stores only `{ assetId, params, seed }`
5
+ * — the geometry is re-resolved at runtime, never baked. Schema drives the inspector via #809. The
6
+ * generic seam is engine; concrete generators (building, bookcase) are adopters registered from
7
+ * game/example code — the building generator is the one engine adopter, as a proof it composes.
8
+ *
9
+ * @capability asset-generator seeded parametric geometry registered as a placeable asset
10
+ */
11
+ import { parseParams } from "./sceneKinds.js";
12
+ const generators = new Map();
13
+ /** Register a parametric asset generator. Idempotent per id (last wins); call at module load. */
14
+ export function registerAssetGenerator(definition) {
15
+ generators.set(definition.id, definition);
16
+ }
17
+ /** The registered generator for an id, or undefined. @internal */
18
+ export function getAssetGenerator(id) {
19
+ return generators.get(id);
20
+ }
21
+ /** Every registered generator, in registration order. @internal */
22
+ export function listAssetGenerators() {
23
+ return [...generators.values()];
24
+ }
25
+ /**
26
+ * Compute bounds from parts (each part is an axis-aligned box at its center) — a helper generators
27
+ * return so callers can frame/ground the asset without re-deriving it.
28
+ */
29
+ export function partsBounds(parts) {
30
+ if (parts.length === 0)
31
+ return { min: [0, 0, 0], max: [0, 0, 0] };
32
+ let minX = Infinity;
33
+ let minY = Infinity;
34
+ let minZ = Infinity;
35
+ let maxX = -Infinity;
36
+ let maxY = -Infinity;
37
+ let maxZ = -Infinity;
38
+ for (const part of parts) {
39
+ minX = Math.min(minX, part.position[0] - part.size[0] / 2);
40
+ minY = Math.min(minY, part.position[1] - part.size[1] / 2);
41
+ minZ = Math.min(minZ, part.position[2] - part.size[2] / 2);
42
+ maxX = Math.max(maxX, part.position[0] + part.size[0] / 2);
43
+ maxY = Math.max(maxY, part.position[1] + part.size[1] / 2);
44
+ maxZ = Math.max(maxZ, part.position[2] + part.size[2] / 2);
45
+ }
46
+ return { min: [minX, minY, minZ], max: [maxX, maxY, maxZ] };
47
+ }
48
+ /**
49
+ * Re-resolve a placed generator instance from its stored `meta` (`{ assetId, seed, ...params }`): look
50
+ * up the generator, parse its params off `meta` against the schema, and generate. Returns null when
51
+ * `assetId` names no registered generator. This is what a runtime renderer calls per placed instance.
52
+ * @internal
53
+ */
54
+ export function resolveGeneratorAsset(meta) {
55
+ const assetId = typeof meta?.["assetId"] === "string" ? meta["assetId"] : undefined;
56
+ if (assetId === undefined)
57
+ return null;
58
+ const generator = generators.get(assetId);
59
+ if (generator === undefined)
60
+ return null;
61
+ const seed = typeof meta?.["seed"] === "string" ? meta["seed"] : assetId;
62
+ const params = parseParams(generator.schema, meta);
63
+ return generator.generate(params, seed);
64
+ }
@@ -0,0 +1,137 @@
1
+ import type { Aabb, Footprint, Vec2 } from "../world/geometry.js";
2
+ /**
3
+ * Wrap `degrees` into `[0, 360)` — the canonical heading range every policy and conversion here works
4
+ * in. Non-finite input collapses to `0` so bad metadata never leaks a `NaN` heading downstream.
5
+ * @capability asset-heading normalize a placement heading into the engine's degree convention
6
+ */
7
+ export declare function normalizeDegrees(degrees: number): number;
8
+ /**
9
+ * Convert a compass heading (degrees, `0` = engine north, increasing clockwise) into the Three.js
10
+ * Y-rotation (radians, wrapped to `(-PI, PI]`) a renderer applies. Sign matches
11
+ * `world/placementController.quarterTurnsToRotationY`, so heading `90` equals one clockwise quarter
12
+ * turn. This is the one place degrees cross into the private radian space Three.js requires.
13
+ * @capability asset-heading turn a north-relative degree heading into a Three.js Y-rotation
14
+ */
15
+ export declare function headingToRotationY(headingDegrees: number): number;
16
+ /**
17
+ * Inverse of {@link headingToRotationY}: recover the `[0, 360)` compass heading from a Three.js
18
+ * Y-rotation. Lets a gizmo or inspector present radians as the degrees authors edit.
19
+ * @capability asset-heading read a Three.js Y-rotation back as a north-relative degree heading
20
+ */
21
+ export declare function rotationYToHeading(rotationY: number): number;
22
+ /** Bridge the legacy 0–3 quarter-turn placement model onto degrees (each turn is 90 degrees clockwise). @internal */
23
+ export declare function quarterTurnsToHeading(quarterTurns: number): number;
24
+ /**
25
+ * A per-asset/per-tool rotation constraint, authored as data instead of hardcoded in build code:
26
+ * `locked` pins every placement to one heading, `snap` quantizes to an increment (15, 45, …), and
27
+ * `free` allows any heading. Serializable — this is the shape stored on a catalog entry or a tool.
28
+ */
29
+ export type PlacementRotationPolicy = {
30
+ readonly mode: "locked";
31
+ readonly degrees?: number;
32
+ } | {
33
+ readonly mode: "snap";
34
+ readonly snapDegrees: number;
35
+ } | {
36
+ readonly mode: "free";
37
+ };
38
+ /**
39
+ * Quantize `degrees` to the nearest multiple of `increment` (both in the `[0, 360)` convention). A
40
+ * non-positive increment is treated as free rotation and only normalizes. The math behind a
41
+ * `snap`-mode {@link PlacementRotationPolicy}.
42
+ * @capability placement-rotation snap a heading to a fixed degree increment
43
+ */
44
+ export declare function snapHeading(degrees: number, increment: number): number;
45
+ /**
46
+ * Resolve a raw drag/scroll heading through a {@link PlacementRotationPolicy} into the heading a
47
+ * placement should actually commit: `locked` ignores the input for its fixed heading, `snap` quantizes,
48
+ * `free` (or an absent policy) normalizes. Deterministic — the single interpreter preview, editor
49
+ * placement, and runtime spawning share instead of each re-implementing the modes.
50
+ * @capability placement-rotation apply a rotation policy to a candidate placement heading
51
+ */
52
+ export declare function applyRotationPolicy(degrees: number, policy: PlacementRotationPolicy | undefined): number;
53
+ /**
54
+ * Where a model's pivot sits within its footprint: `center` (origin at the footprint center),
55
+ * `corner` (origin at the min-X/min-Z corner), or a normalized `{ x, z }` fraction in `[-0.5, 0.5]`.
56
+ */
57
+ export type AssetAnchor = "center" | "corner" | {
58
+ readonly x: number;
59
+ readonly z: number;
60
+ };
61
+ /**
62
+ * Catalog-level asset-space metadata: how a model is authored relative to the engine, owned by the
63
+ * catalog entry rather than re-derived per game. Every field is optional so an unmeasured asset stays
64
+ * valid; {@link resolveFacingRotationY}/{@link assetUnitScale}/{@link resolveAnchorOffset} supply the
65
+ * documented defaults.
66
+ */
67
+ export interface AssetSpace {
68
+ /** Compass heading (degrees, `0` = north) the model's front visually points at `rotationY = 0`. Default `0`. */
69
+ forwardDegrees?: number;
70
+ /** Multiply source-space lengths by this to reach engine meters (a kit's native tile size correction). Default `1`. */
71
+ unitScale?: number;
72
+ /** Authored footprint in engine meters — the grid/placement extent, independent of the raw mesh bounds. */
73
+ footprint?: Footprint;
74
+ /** Authored grid cell size in engine meters this asset snaps to. */
75
+ gridSize?: number;
76
+ /** Where the model origin sits within {@link footprint}. Default `center`. */
77
+ anchor?: AssetAnchor;
78
+ /** Optional asset-local placement bounds (XZ) a tool clamps a drop position into. */
79
+ bounds?: Aabb;
80
+ /** Default rotation constraint when this asset is placed. Absent means free rotation. */
81
+ rotation?: PlacementRotationPolicy;
82
+ }
83
+ /**
84
+ * The Three.js Y-rotation that makes a model whose front is authored at `forwardDegrees` visually point
85
+ * `headingDegrees` (engine north = `0`). This is the catalog-owned replacement for per-game corrective
86
+ * yaw: a model authored facing south (`forwardDegrees: 180`) placed toward north resolves to `Math.PI`.
87
+ * @capability asset-facing resolve a placement heading into a Three.js Y-rotation using canonical forward
88
+ */
89
+ export declare function resolveFacingRotationY(headingDegrees: number, space?: Pick<AssetSpace, "forwardDegrees">): number;
90
+ /** The effective, guarded unit scale for an asset — a finite positive `unitScale`, else `1`. @internal */
91
+ export declare function assetUnitScale(space?: Pick<AssetSpace, "unitScale">): number;
92
+ /**
93
+ * Convert a source-space length to engine meters through the asset's {@link AssetSpace.unitScale} — the
94
+ * data-owned replacement for per-game scale constants (a native ~4-unit kit tile down to a 1-unit grid).
95
+ * @capability asset-units convert a source-space length to engine meters via catalog unit scale
96
+ */
97
+ export declare function toEngineUnits(sourceValue: number, space?: Pick<AssetSpace, "unitScale">): number;
98
+ /**
99
+ * The pivot's offset from the footprint center, in engine meters, implied by {@link AssetSpace.anchor}
100
+ * and {@link AssetSpace.footprint}. `center` yields `[0, 0]`; `corner` yields the min corner; a
101
+ * normalized `{ x, z }` scales by the footprint. Subtract it to seat a footprint centered on a point.
102
+ * @capability asset-anchor resolve a model's pivot offset from its footprint center
103
+ */
104
+ export declare function resolveAnchorOffset(space?: Pick<AssetSpace, "anchor" | "footprint">): Vec2;
105
+ /**
106
+ * The axis-aligned footprint extent after rotating a rectangular {@link Footprint} by `headingDegrees`
107
+ * — footprint-aware placement: a 90-degree turn swaps width/depth, and arbitrary headings grow the
108
+ * bounding box so overlap and snap checks see the space the rotated asset truly occupies.
109
+ * @capability asset-footprint rotate a rectangular footprint into its axis-aligned extent
110
+ */
111
+ export declare function rotatedFootprint(footprint: Footprint, headingDegrees: number): Footprint;
112
+ /** One problem found by {@link validateAssetSpace}: which metadata field and why it is invalid. */
113
+ export interface AssetSpaceIssue {
114
+ field: string;
115
+ message: string;
116
+ }
117
+ /**
118
+ * Report contradictory or malformed asset-space metadata so catalog generation can reject it before it
119
+ * reaches a tool: non-finite headings, non-positive scales/sizes, inverted bounds, unknown anchors, and
120
+ * ill-formed rotation policies (a `snap` with a non-positive increment, an unknown `mode`). An empty
121
+ * array means valid. Validation lives here so tools consume resolved metadata instead of reinterpreting.
122
+ * @capability asset-space validate catalog asset-space metadata during index generation
123
+ */
124
+ export declare function validateAssetSpace(raw: unknown): AssetSpaceIssue[];
125
+ /**
126
+ * Parse an untrusted rotation policy (from a scene document or catalog JSON) into a valid
127
+ * {@link PlacementRotationPolicy}, defaulting to `free` when absent or malformed. The lenient companion
128
+ * to {@link validateAssetSpace} for the read path.
129
+ * @capability placement-rotation parse a serialized rotation policy, defaulting to free
130
+ */
131
+ export declare function parseRotationPolicy(raw: unknown): PlacementRotationPolicy;
132
+ /**
133
+ * Parse untrusted JSON into an {@link AssetSpace}, dropping malformed fields, or `undefined` when
134
+ * nothing valid remains — the round-trippable read path for serialized catalog/scene metadata.
135
+ * @capability asset-space parse serialized asset-space metadata into a validated shape
136
+ */
137
+ export declare function parseAssetSpace(raw: unknown): AssetSpace | undefined;
@@ -0,0 +1,259 @@
1
+ /**
2
+ * Asset-space metadata + placement rotation policy: the catalog-owned description of how a model sits
3
+ * in its source space and how a placement tool may rotate it. Games author scenes against engine north
4
+ * (heading `0` degrees, increasing clockwise) instead of transplanting per-game yaw offsets and magic
5
+ * scales; the catalog entry ({@link "scene/assetCatalog".ModelAssetRef}) is the upstream owner of the
6
+ * correction. Public APIs speak degrees; the only radians here are the private Three.js Y-rotation this
7
+ * module converts to, matching `world/placementController`'s `quarterTurnsToRotationY` sign so a
8
+ * quarter turn still equals 90 degrees clockwise. Pure and serializable — no three.js, no allocation of
9
+ * shared state — so preview, placement, and runtime spawning share one interpretation.
10
+ */
11
+ const DEG2RAD = Math.PI / 180;
12
+ const RAD2DEG = 180 / Math.PI;
13
+ const FULL_TURN = 360;
14
+ function clamp(value, min, max) {
15
+ return value < min ? min : value > max ? max : value;
16
+ }
17
+ /**
18
+ * Wrap `degrees` into `[0, 360)` — the canonical heading range every policy and conversion here works
19
+ * in. Non-finite input collapses to `0` so bad metadata never leaks a `NaN` heading downstream.
20
+ * @capability asset-heading normalize a placement heading into the engine's degree convention
21
+ */
22
+ export function normalizeDegrees(degrees) {
23
+ if (!Number.isFinite(degrees))
24
+ return 0;
25
+ const wrapped = degrees % FULL_TURN;
26
+ return wrapped < 0 ? wrapped + FULL_TURN : wrapped;
27
+ }
28
+ function wrapRadians(radians) {
29
+ let r = radians % (2 * Math.PI);
30
+ if (r <= -Math.PI)
31
+ r += 2 * Math.PI;
32
+ if (r > Math.PI)
33
+ r -= 2 * Math.PI;
34
+ return r + 0; // normalize -0 to 0
35
+ }
36
+ /**
37
+ * Convert a compass heading (degrees, `0` = engine north, increasing clockwise) into the Three.js
38
+ * Y-rotation (radians, wrapped to `(-PI, PI]`) a renderer applies. Sign matches
39
+ * `world/placementController.quarterTurnsToRotationY`, so heading `90` equals one clockwise quarter
40
+ * turn. This is the one place degrees cross into the private radian space Three.js requires.
41
+ * @capability asset-heading turn a north-relative degree heading into a Three.js Y-rotation
42
+ */
43
+ export function headingToRotationY(headingDegrees) {
44
+ return wrapRadians(-normalizeDegrees(headingDegrees) * DEG2RAD);
45
+ }
46
+ /**
47
+ * Inverse of {@link headingToRotationY}: recover the `[0, 360)` compass heading from a Three.js
48
+ * Y-rotation. Lets a gizmo or inspector present radians as the degrees authors edit.
49
+ * @capability asset-heading read a Three.js Y-rotation back as a north-relative degree heading
50
+ */
51
+ export function rotationYToHeading(rotationY) {
52
+ return normalizeDegrees(-rotationY * RAD2DEG);
53
+ }
54
+ /** Bridge the legacy 0–3 quarter-turn placement model onto degrees (each turn is 90 degrees clockwise). @internal */
55
+ export function quarterTurnsToHeading(quarterTurns) {
56
+ return normalizeDegrees(Math.round(quarterTurns) * 90);
57
+ }
58
+ /**
59
+ * Quantize `degrees` to the nearest multiple of `increment` (both in the `[0, 360)` convention). A
60
+ * non-positive increment is treated as free rotation and only normalizes. The math behind a
61
+ * `snap`-mode {@link PlacementRotationPolicy}.
62
+ * @capability placement-rotation snap a heading to a fixed degree increment
63
+ */
64
+ export function snapHeading(degrees, increment) {
65
+ if (!(increment > 0))
66
+ return normalizeDegrees(degrees);
67
+ return normalizeDegrees(Math.round(normalizeDegrees(degrees) / increment) * increment);
68
+ }
69
+ /**
70
+ * Resolve a raw drag/scroll heading through a {@link PlacementRotationPolicy} into the heading a
71
+ * placement should actually commit: `locked` ignores the input for its fixed heading, `snap` quantizes,
72
+ * `free` (or an absent policy) normalizes. Deterministic — the single interpreter preview, editor
73
+ * placement, and runtime spawning share instead of each re-implementing the modes.
74
+ * @capability placement-rotation apply a rotation policy to a candidate placement heading
75
+ */
76
+ export function applyRotationPolicy(degrees, policy) {
77
+ if (policy === undefined || policy.mode === "free")
78
+ return normalizeDegrees(degrees);
79
+ if (policy.mode === "locked")
80
+ return normalizeDegrees(policy.degrees ?? 0);
81
+ return snapHeading(degrees, policy.snapDegrees);
82
+ }
83
+ /**
84
+ * The Three.js Y-rotation that makes a model whose front is authored at `forwardDegrees` visually point
85
+ * `headingDegrees` (engine north = `0`). This is the catalog-owned replacement for per-game corrective
86
+ * yaw: a model authored facing south (`forwardDegrees: 180`) placed toward north resolves to `Math.PI`.
87
+ * @capability asset-facing resolve a placement heading into a Three.js Y-rotation using canonical forward
88
+ */
89
+ export function resolveFacingRotationY(headingDegrees, space) {
90
+ return headingToRotationY(headingDegrees - (space?.forwardDegrees ?? 0));
91
+ }
92
+ /** The effective, guarded unit scale for an asset — a finite positive `unitScale`, else `1`. @internal */
93
+ export function assetUnitScale(space) {
94
+ const s = space?.unitScale;
95
+ return typeof s === "number" && Number.isFinite(s) && s > 0 ? s : 1;
96
+ }
97
+ /**
98
+ * Convert a source-space length to engine meters through the asset's {@link AssetSpace.unitScale} — the
99
+ * data-owned replacement for per-game scale constants (a native ~4-unit kit tile down to a 1-unit grid).
100
+ * @capability asset-units convert a source-space length to engine meters via catalog unit scale
101
+ */
102
+ export function toEngineUnits(sourceValue, space) {
103
+ return sourceValue * assetUnitScale(space);
104
+ }
105
+ /**
106
+ * The pivot's offset from the footprint center, in engine meters, implied by {@link AssetSpace.anchor}
107
+ * and {@link AssetSpace.footprint}. `center` yields `[0, 0]`; `corner` yields the min corner; a
108
+ * normalized `{ x, z }` scales by the footprint. Subtract it to seat a footprint centered on a point.
109
+ * @capability asset-anchor resolve a model's pivot offset from its footprint center
110
+ */
111
+ export function resolveAnchorOffset(space) {
112
+ const w = space?.footprint?.w ?? 0;
113
+ const d = space?.footprint?.d ?? 0;
114
+ const anchor = space?.anchor ?? "center";
115
+ let fx = 0;
116
+ let fz = 0;
117
+ if (anchor === "corner") {
118
+ fx = -0.5;
119
+ fz = -0.5;
120
+ }
121
+ else if (typeof anchor === "object") {
122
+ fx = clamp(anchor.x, -0.5, 0.5);
123
+ fz = clamp(anchor.z, -0.5, 0.5);
124
+ }
125
+ return [fx * w, fz * d];
126
+ }
127
+ /**
128
+ * The axis-aligned footprint extent after rotating a rectangular {@link Footprint} by `headingDegrees`
129
+ * — footprint-aware placement: a 90-degree turn swaps width/depth, and arbitrary headings grow the
130
+ * bounding box so overlap and snap checks see the space the rotated asset truly occupies.
131
+ * @capability asset-footprint rotate a rectangular footprint into its axis-aligned extent
132
+ */
133
+ export function rotatedFootprint(footprint, headingDegrees) {
134
+ const rad = normalizeDegrees(headingDegrees) * DEG2RAD;
135
+ const cos = Math.abs(Math.cos(rad));
136
+ const sin = Math.abs(Math.sin(rad));
137
+ return {
138
+ w: footprint.w * cos + footprint.d * sin,
139
+ d: footprint.w * sin + footprint.d * cos,
140
+ };
141
+ }
142
+ function isRecord(value) {
143
+ return typeof value === "object" && value !== null;
144
+ }
145
+ function finitePositive(value) {
146
+ return typeof value === "number" && Number.isFinite(value) && value > 0;
147
+ }
148
+ function validateRotationPolicy(raw) {
149
+ if (!isRecord(raw))
150
+ return [{ field: "mode", message: "expected an object" }];
151
+ if (raw.mode === "free")
152
+ return [];
153
+ if (raw.mode === "locked") {
154
+ return raw.degrees !== undefined && (typeof raw.degrees !== "number" || !Number.isFinite(raw.degrees))
155
+ ? [{ field: "degrees", message: "expected a finite number" }]
156
+ : [];
157
+ }
158
+ if (raw.mode === "snap") {
159
+ return finitePositive(raw.snapDegrees) ? [] : [{ field: "snapDegrees", message: "expected a positive number" }];
160
+ }
161
+ return [{ field: "mode", message: "expected 'locked', 'snap', or 'free'" }];
162
+ }
163
+ /**
164
+ * Report contradictory or malformed asset-space metadata so catalog generation can reject it before it
165
+ * reaches a tool: non-finite headings, non-positive scales/sizes, inverted bounds, unknown anchors, and
166
+ * ill-formed rotation policies (a `snap` with a non-positive increment, an unknown `mode`). An empty
167
+ * array means valid. Validation lives here so tools consume resolved metadata instead of reinterpreting.
168
+ * @capability asset-space validate catalog asset-space metadata during index generation
169
+ */
170
+ export function validateAssetSpace(raw) {
171
+ const issues = [];
172
+ if (!isRecord(raw)) {
173
+ issues.push({ field: "", message: "expected an object" });
174
+ return issues;
175
+ }
176
+ if (raw.forwardDegrees !== undefined && (typeof raw.forwardDegrees !== "number" || !Number.isFinite(raw.forwardDegrees))) {
177
+ issues.push({ field: "forwardDegrees", message: "expected a finite number" });
178
+ }
179
+ if (raw.unitScale !== undefined && !finitePositive(raw.unitScale)) {
180
+ issues.push({ field: "unitScale", message: "expected a positive number" });
181
+ }
182
+ if (raw.gridSize !== undefined && !finitePositive(raw.gridSize)) {
183
+ issues.push({ field: "gridSize", message: "expected a positive number" });
184
+ }
185
+ if (raw.footprint !== undefined) {
186
+ const fp = raw.footprint;
187
+ if (!isRecord(fp) || !finitePositive(fp.w) || !finitePositive(fp.d)) {
188
+ issues.push({ field: "footprint", message: "expected { w > 0, d > 0 }" });
189
+ }
190
+ }
191
+ if (raw.anchor !== undefined) {
192
+ const a = raw.anchor;
193
+ const named = a === "center" || a === "corner";
194
+ const explicit = isRecord(a) && typeof a.x === "number" && typeof a.z === "number";
195
+ if (!named && !explicit)
196
+ issues.push({ field: "anchor", message: "expected 'center', 'corner', or { x, z }" });
197
+ }
198
+ if (raw.bounds !== undefined) {
199
+ const b = raw.bounds;
200
+ if (!isRecord(b) || typeof b.minX !== "number" || typeof b.maxX !== "number" || typeof b.minZ !== "number" || typeof b.maxZ !== "number") {
201
+ issues.push({ field: "bounds", message: "expected an Aabb" });
202
+ }
203
+ else if (b.maxX < b.minX || b.maxZ < b.minZ) {
204
+ issues.push({ field: "bounds", message: "max must be >= min" });
205
+ }
206
+ }
207
+ if (raw.rotation !== undefined) {
208
+ issues.push(...validateRotationPolicy(raw.rotation).map((m) => ({ field: `rotation.${m.field}`, message: m.message })));
209
+ }
210
+ return issues;
211
+ }
212
+ /**
213
+ * Parse an untrusted rotation policy (from a scene document or catalog JSON) into a valid
214
+ * {@link PlacementRotationPolicy}, defaulting to `free` when absent or malformed. The lenient companion
215
+ * to {@link validateAssetSpace} for the read path.
216
+ * @capability placement-rotation parse a serialized rotation policy, defaulting to free
217
+ */
218
+ export function parseRotationPolicy(raw) {
219
+ if (isRecord(raw)) {
220
+ if (raw.mode === "locked") {
221
+ return typeof raw.degrees === "number" && Number.isFinite(raw.degrees)
222
+ ? { mode: "locked", degrees: normalizeDegrees(raw.degrees) }
223
+ : { mode: "locked" };
224
+ }
225
+ if (raw.mode === "snap" && finitePositive(raw.snapDegrees))
226
+ return { mode: "snap", snapDegrees: raw.snapDegrees };
227
+ }
228
+ return { mode: "free" };
229
+ }
230
+ /**
231
+ * Parse untrusted JSON into an {@link AssetSpace}, dropping malformed fields, or `undefined` when
232
+ * nothing valid remains — the round-trippable read path for serialized catalog/scene metadata.
233
+ * @capability asset-space parse serialized asset-space metadata into a validated shape
234
+ */
235
+ export function parseAssetSpace(raw) {
236
+ if (!isRecord(raw))
237
+ return undefined;
238
+ const out = {};
239
+ if (typeof raw.forwardDegrees === "number" && Number.isFinite(raw.forwardDegrees))
240
+ out.forwardDegrees = normalizeDegrees(raw.forwardDegrees);
241
+ if (finitePositive(raw.unitScale))
242
+ out.unitScale = raw.unitScale;
243
+ if (finitePositive(raw.gridSize))
244
+ out.gridSize = raw.gridSize;
245
+ if (isRecord(raw.footprint) && finitePositive(raw.footprint.w) && finitePositive(raw.footprint.d)) {
246
+ out.footprint = { w: raw.footprint.w, d: raw.footprint.d };
247
+ }
248
+ if (raw.anchor === "center" || raw.anchor === "corner")
249
+ out.anchor = raw.anchor;
250
+ else if (isRecord(raw.anchor) && typeof raw.anchor.x === "number" && typeof raw.anchor.z === "number") {
251
+ out.anchor = { x: raw.anchor.x, z: raw.anchor.z };
252
+ }
253
+ if (isRecord(raw.bounds) && typeof raw.bounds.minX === "number" && typeof raw.bounds.maxX === "number" && typeof raw.bounds.minZ === "number" && typeof raw.bounds.maxZ === "number") {
254
+ out.bounds = { minX: raw.bounds.minX, maxX: raw.bounds.maxX, minZ: raw.bounds.minZ, maxZ: raw.bounds.maxZ };
255
+ }
256
+ if (isRecord(raw.rotation))
257
+ out.rotation = parseRotationPolicy(raw.rotation);
258
+ return Object.keys(out).length === 0 ? undefined : out;
259
+ }