@jgengine/core 0.10.0 → 0.12.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 (727) hide show
  1. package/CHANGELOG.md +39 -2
  2. package/LICENSE +203 -661
  3. package/README.md +1 -1
  4. package/dist/ai/crowd.d.ts +55 -0
  5. package/dist/ai/crowd.js +114 -0
  6. package/dist/ai/flock.d.ts +5 -2
  7. package/dist/ai/flock.js +5 -2
  8. package/dist/ai/groupAssist.d.ts +1 -0
  9. package/dist/ai/groupAssist.js +1 -0
  10. package/dist/ai/heatSystem.d.ts +76 -0
  11. package/dist/ai/heatSystem.js +97 -0
  12. package/dist/ai/interestScheduler.d.ts +107 -0
  13. package/dist/ai/interestScheduler.js +118 -0
  14. package/dist/ai/jobBoard.d.ts +1 -0
  15. package/dist/ai/jobBoard.js +1 -0
  16. package/dist/ai/laneSelect.d.ts +5 -2
  17. package/dist/ai/laneSelect.js +5 -2
  18. package/dist/ai/mobBrain.d.ts +1 -0
  19. package/dist/ai/mobBrain.js +1 -0
  20. package/dist/ai/populationDirector.d.ts +103 -0
  21. package/dist/ai/populationDirector.js +190 -0
  22. package/dist/ai/pursuit.d.ts +56 -0
  23. package/dist/ai/pursuit.js +53 -0
  24. package/dist/ai/spawnDirector.d.ts +7 -2
  25. package/dist/ai/spawnDirector.js +18 -15
  26. package/dist/ai/spawnPoint.d.ts +3 -1
  27. package/dist/ai/spawnPoint.js +3 -1
  28. package/dist/ai/targetAcquisition.d.ts +84 -0
  29. package/dist/ai/targetAcquisition.js +92 -0
  30. package/dist/anim/easing.d.ts +19 -0
  31. package/dist/anim/easing.js +19 -0
  32. package/dist/anim/oscillator.d.ts +12 -0
  33. package/dist/anim/oscillator.js +25 -0
  34. package/dist/area/areaEffectField.d.ts +127 -0
  35. package/dist/area/areaEffectField.js +175 -0
  36. package/dist/area/stackPolicy.d.ts +47 -0
  37. package/dist/area/stackPolicy.js +99 -0
  38. package/dist/authoring.d.ts +2 -1
  39. package/dist/authoring.js +2 -1
  40. package/dist/board/laneBoard.d.ts +13 -0
  41. package/dist/board/laneBoard.js +13 -0
  42. package/dist/board/timelineBoard.d.ts +10 -0
  43. package/dist/board/timelineBoard.js +10 -0
  44. package/dist/combat/abilityKit.d.ts +18 -0
  45. package/dist/combat/abilityKit.js +24 -9
  46. package/dist/combat/animationState.d.ts +5 -0
  47. package/dist/combat/animationState.js +5 -0
  48. package/dist/combat/breakMeters.d.ts +10 -0
  49. package/dist/combat/breakMeters.js +10 -0
  50. package/dist/combat/castRunner.d.ts +5 -0
  51. package/dist/combat/castRunner.js +5 -0
  52. package/dist/combat/comboPoints.d.ts +5 -0
  53. package/dist/combat/comboPoints.js +5 -0
  54. package/dist/combat/comboString.d.ts +5 -0
  55. package/dist/combat/comboString.js +5 -0
  56. package/dist/combat/damageInterceptors.d.ts +192 -0
  57. package/dist/combat/damageInterceptors.js +251 -0
  58. package/dist/combat/damageMatchup.d.ts +68 -0
  59. package/dist/combat/damageMatchup.js +42 -0
  60. package/dist/combat/damageResolution.d.ts +63 -0
  61. package/dist/combat/damageResolution.js +50 -0
  62. package/dist/combat/death.d.ts +7 -1
  63. package/dist/combat/death.js +5 -0
  64. package/dist/combat/deathReason.d.ts +14 -0
  65. package/dist/combat/deathReason.js +1 -0
  66. package/dist/combat/defensiveWindow.d.ts +5 -0
  67. package/dist/combat/defensiveWindow.js +5 -0
  68. package/dist/combat/dotField.d.ts +5 -1
  69. package/dist/combat/dotField.js +5 -1
  70. package/dist/combat/downed.d.ts +5 -0
  71. package/dist/combat/downed.js +5 -0
  72. package/dist/combat/effects.d.ts +5 -0
  73. package/dist/combat/effects.js +5 -0
  74. package/dist/combat/encounterSequence.d.ts +258 -0
  75. package/dist/combat/encounterSequence.js +426 -0
  76. package/dist/combat/hitReaction.d.ts +57 -1
  77. package/dist/combat/hitReaction.js +45 -5
  78. package/dist/combat/magazine.d.ts +54 -0
  79. package/dist/combat/magazine.js +96 -0
  80. package/dist/combat/projectiles.d.ts +5 -0
  81. package/dist/combat/projectiles.js +32 -14
  82. package/dist/combat/receivedDamage.d.ts +117 -0
  83. package/dist/combat/receivedDamage.js +92 -0
  84. package/dist/combat/regenShield.d.ts +5 -1
  85. package/dist/combat/regenShield.js +5 -1
  86. package/dist/combat/renderCues.d.ts +51 -0
  87. package/dist/combat/renderCues.js +44 -0
  88. package/dist/combat/resourcePool.d.ts +5 -0
  89. package/dist/combat/resourcePool.js +5 -0
  90. package/dist/combat/rewardAllocation.d.ts +121 -0
  91. package/dist/combat/rewardAllocation.js +251 -0
  92. package/dist/combat/shotOrigin.d.ts +18 -1
  93. package/dist/combat/shotOrigin.js +39 -0
  94. package/dist/combat/statusApplication.d.ts +96 -0
  95. package/dist/combat/statusApplication.js +81 -0
  96. package/dist/combat/telegraph.d.ts +11 -2
  97. package/dist/combat/telegraph.js +11 -2
  98. package/dist/combat/thresholdCrossings.d.ts +85 -0
  99. package/dist/combat/thresholdCrossings.js +116 -0
  100. package/dist/combat.d.ts +35 -0
  101. package/dist/combat.js +35 -0
  102. package/dist/commands/commandRegistry.d.ts +11 -0
  103. package/dist/commands/commandRegistry.js +9 -2
  104. package/dist/crafting/crop.d.ts +18 -0
  105. package/dist/crafting/crop.js +18 -0
  106. package/dist/crafting/production.d.ts +5 -0
  107. package/dist/crafting/production.js +5 -0
  108. package/dist/devtools/controls.d.ts +38 -0
  109. package/dist/devtools/controls.js +181 -0
  110. package/dist/devtools/devtools.d.ts +5 -197
  111. package/dist/devtools/devtools.js +38 -774
  112. package/dist/devtools/discover.d.ts +32 -0
  113. package/dist/devtools/discover.js +240 -0
  114. package/dist/devtools/fallbackSeams.d.ts +50 -0
  115. package/dist/devtools/fallbackSeams.js +111 -0
  116. package/dist/devtools/frame.d.ts +15 -0
  117. package/dist/devtools/frame.js +247 -0
  118. package/dist/devtools/logs.d.ts +15 -0
  119. package/dist/devtools/logs.js +86 -0
  120. package/dist/devtools/overrides.d.ts +16 -0
  121. package/dist/devtools/overrides.js +66 -0
  122. package/dist/devtools/rewriteTunables.d.ts +17 -0
  123. package/dist/devtools/rewriteTunables.js +276 -0
  124. package/dist/devtools/saveEndpoint.d.ts +46 -0
  125. package/dist/devtools/saveEndpoint.js +48 -0
  126. package/dist/devtools/transformTunables.d.ts +3 -0
  127. package/dist/devtools/transformTunables.js +3 -0
  128. package/dist/devtools/tunableSchema.d.ts +31 -0
  129. package/dist/devtools/tunableSchema.js +31 -0
  130. package/dist/devtools/types.d.ts +212 -0
  131. package/dist/devtools/types.js +1 -0
  132. package/dist/economy/auctionBook.d.ts +122 -0
  133. package/dist/economy/auctionBook.js +213 -0
  134. package/dist/economy/currency.d.ts +12 -1
  135. package/dist/economy/currency.js +12 -1
  136. package/dist/economy/listingBook.d.ts +91 -0
  137. package/dist/economy/listingBook.js +144 -0
  138. package/dist/economy/priceHistory.d.ts +44 -0
  139. package/dist/economy/priceHistory.js +89 -0
  140. package/dist/economy/resourceLedger.d.ts +222 -0
  141. package/dist/economy/resourceLedger.js +353 -0
  142. package/dist/economy/sharedWallet.d.ts +14 -0
  143. package/dist/economy/sharedWallet.js +14 -0
  144. package/dist/economy/techTree.d.ts +12 -0
  145. package/dist/economy/techTree.js +12 -0
  146. package/dist/economy/unlockPoints.d.ts +92 -0
  147. package/dist/economy/unlockPoints.js +103 -0
  148. package/dist/economy/wallet.d.ts +26 -2
  149. package/dist/economy/wallet.js +35 -6
  150. package/dist/editor/commandApply.d.ts +5 -0
  151. package/dist/editor/commandApply.js +755 -0
  152. package/dist/editor/commands.d.ts +235 -7
  153. package/dist/editor/commands.js +82 -124
  154. package/dist/editor/directives.d.ts +94 -0
  155. package/dist/editor/directives.js +206 -0
  156. package/dist/editor/document.d.ts +194 -13
  157. package/dist/editor/document.js +1166 -19
  158. package/dist/editor/entityCatalog.d.ts +42 -0
  159. package/dist/editor/entityCatalog.js +101 -0
  160. package/dist/editor/environment.d.ts +74 -0
  161. package/dist/editor/environment.js +169 -0
  162. package/dist/editor/grid.d.ts +229 -0
  163. package/dist/editor/grid.js +366 -0
  164. package/dist/editor/gridAdapters.d.ts +80 -0
  165. package/dist/editor/gridAdapters.js +134 -0
  166. package/dist/editor/index.d.ts +98 -6
  167. package/dist/editor/index.js +13 -2
  168. package/dist/editor/liveSync.d.ts +127 -0
  169. package/dist/editor/liveSync.js +249 -0
  170. package/dist/editor/minimap.d.ts +31 -0
  171. package/dist/editor/minimap.js +73 -0
  172. package/dist/editor/runtimeInspector.d.ts +88 -0
  173. package/dist/editor/runtimeInspector.js +239 -0
  174. package/dist/editor/streamer.d.ts +66 -0
  175. package/dist/editor/streamer.js +68 -0
  176. package/dist/editor/types.d.ts +250 -1
  177. package/dist/editor/world.d.ts +136 -0
  178. package/dist/editor/world.js +303 -0
  179. package/dist/faction/reputation.d.ts +5 -0
  180. package/dist/faction/reputation.js +5 -0
  181. package/dist/format/distance.d.ts +17 -0
  182. package/dist/format/distance.js +18 -0
  183. package/dist/format/duration.d.ts +27 -0
  184. package/dist/format/duration.js +45 -0
  185. package/dist/format/speed.d.ts +17 -0
  186. package/dist/format/speed.js +25 -0
  187. package/dist/game/breeding.d.ts +161 -0
  188. package/dist/game/breeding.js +181 -0
  189. package/dist/game/cameraConfig.d.ts +451 -0
  190. package/dist/game/cameraConfig.js +1 -0
  191. package/dist/game/connectedPlayers.d.ts +6 -4
  192. package/dist/game/connectedPlayers.js +2 -2
  193. package/dist/game/cosmetics.d.ts +9 -0
  194. package/dist/game/cosmetics.js +16 -0
  195. package/dist/game/defineGame.d.ts +110 -5
  196. package/dist/game/defineGame.js +49 -4
  197. package/dist/game/defineSystem.d.ts +90 -0
  198. package/dist/game/defineSystem.js +47 -0
  199. package/dist/game/dialogue.d.ts +33 -0
  200. package/dist/game/dialogue.js +21 -0
  201. package/dist/game/events.d.ts +63 -13
  202. package/dist/game/events.js +5 -0
  203. package/dist/game/feed.d.ts +33 -0
  204. package/dist/game/feed.js +35 -2
  205. package/dist/game/gamePhase.d.ts +11 -0
  206. package/dist/game/gamePhase.js +16 -0
  207. package/dist/game/leaderboard.d.ts +5 -0
  208. package/dist/game/leaderboard.js +5 -0
  209. package/dist/game/loadout.d.ts +5 -0
  210. package/dist/game/loadout.js +5 -0
  211. package/dist/game/lootFilter.d.ts +2 -0
  212. package/dist/game/lootFilter.js +2 -0
  213. package/dist/game/lootPipeline.d.ts +164 -0
  214. package/dist/game/lootPipeline.js +216 -0
  215. package/dist/game/lootTable.d.ts +19 -2
  216. package/dist/game/lootTable.js +15 -5
  217. package/dist/game/objectives.d.ts +43 -0
  218. package/dist/game/objectives.js +36 -0
  219. package/dist/game/paramLayers.d.ts +148 -0
  220. package/dist/game/paramLayers.js +185 -0
  221. package/dist/game/ping.d.ts +5 -0
  222. package/dist/game/ping.js +5 -0
  223. package/dist/game/playableGame.d.ts +116 -432
  224. package/dist/game/playableGame.js +1 -1
  225. package/dist/game/progression.d.ts +35 -0
  226. package/dist/game/progression.js +19 -0
  227. package/dist/game/quest.d.ts +8 -0
  228. package/dist/game/quest.js +30 -3
  229. package/dist/game/race.d.ts +141 -0
  230. package/dist/game/race.js +169 -0
  231. package/dist/game/recordBook.d.ts +3 -1
  232. package/dist/game/recordBook.js +4 -1
  233. package/dist/game/ruleSelection.d.ts +75 -0
  234. package/dist/game/ruleSelection.js +127 -0
  235. package/dist/game/runDraft.d.ts +5 -0
  236. package/dist/game/runDraft.js +5 -0
  237. package/dist/game/saveStore.d.ts +111 -0
  238. package/dist/game/saveStore.js +312 -0
  239. package/dist/game/snapshotHistory.d.ts +67 -0
  240. package/dist/game/snapshotHistory.js +95 -0
  241. package/dist/game/social.d.ts +38 -1
  242. package/dist/game/social.js +71 -0
  243. package/dist/game/spawnPoints.d.ts +5 -0
  244. package/dist/game/spawnPoints.js +5 -0
  245. package/dist/game/systemRuntime.d.ts +50 -0
  246. package/dist/game/systemRuntime.js +157 -0
  247. package/dist/game/systemSchedule.d.ts +72 -0
  248. package/dist/game/systemSchedule.js +242 -0
  249. package/dist/game/toasts.d.ts +43 -0
  250. package/dist/game/toasts.js +44 -0
  251. package/dist/game/trade.d.ts +10 -0
  252. package/dist/game/trade.js +10 -0
  253. package/dist/game/tribe.d.ts +184 -0
  254. package/dist/game/tribe.js +432 -0
  255. package/dist/game/unlocks.d.ts +8 -0
  256. package/dist/game/unlocks.js +16 -0
  257. package/dist/game/vfxInstance.d.ts +138 -0
  258. package/dist/game/vfxInstance.js +96 -0
  259. package/dist/game/worldItem.d.ts +17 -4
  260. package/dist/game/worldItem.js +17 -4
  261. package/dist/gameplay.d.ts +93 -0
  262. package/dist/gameplay.js +93 -0
  263. package/dist/index.d.ts +5 -14
  264. package/dist/index.js +5 -14
  265. package/dist/input/actionBindings.d.ts +23 -6
  266. package/dist/input/actionBindings.js +23 -6
  267. package/dist/input/axisInput.d.ts +7 -2
  268. package/dist/input/axisInput.js +7 -2
  269. package/dist/input/controlGroups.d.ts +67 -0
  270. package/dist/input/controlGroups.js +41 -0
  271. package/dist/input/touchScheme.d.ts +82 -6
  272. package/dist/input/touchScheme.js +123 -10
  273. package/dist/interaction/lockpick.d.ts +61 -0
  274. package/dist/interaction/lockpick.js +168 -0
  275. package/dist/interaction/proximityPrompt.d.ts +2 -0
  276. package/dist/interaction/proximityPrompt.js +2 -0
  277. package/dist/interaction/qte.d.ts +5 -0
  278. package/dist/interaction/qte.js +5 -0
  279. package/dist/interaction/skillCheck.d.ts +5 -0
  280. package/dist/interaction/skillCheck.js +5 -0
  281. package/dist/inventory/encumbrance.d.ts +69 -0
  282. package/dist/inventory/encumbrance.js +68 -0
  283. package/dist/inventory/inventoryModel.d.ts +12 -0
  284. package/dist/inventory/inventoryModel.js +12 -0
  285. package/dist/inventory/shapedGrid.d.ts +16 -0
  286. package/dist/inventory/shapedGrid.js +16 -0
  287. package/dist/inventory/slotModel.d.ts +10 -0
  288. package/dist/inventory/slotModel.js +10 -0
  289. package/dist/item/durability.d.ts +5 -0
  290. package/dist/item/durability.js +6 -3
  291. package/dist/item/itemIdentity.d.ts +171 -0
  292. package/dist/item/itemIdentity.js +138 -0
  293. package/dist/item/itemInstanceRegistry.d.ts +32 -0
  294. package/dist/item/itemInstanceRegistry.js +34 -0
  295. package/dist/item/itemgen.d.ts +163 -0
  296. package/dist/item/itemgen.js +151 -0
  297. package/dist/item/modularItem.d.ts +5 -0
  298. package/dist/item/modularItem.js +5 -0
  299. package/dist/item/use.d.ts +5 -0
  300. package/dist/item/use.js +5 -0
  301. package/dist/item/useBehavior.d.ts +142 -0
  302. package/dist/item/useBehavior.js +105 -0
  303. package/dist/item/weapon.d.ts +5 -0
  304. package/dist/item/weapon.js +5 -0
  305. package/dist/math/scalar.d.ts +25 -0
  306. package/dist/math/scalar.js +47 -0
  307. package/dist/meta/changelog.d.ts +4 -1
  308. package/dist/meta/changelog.js +39 -2
  309. package/dist/movement/avoidance.d.ts +45 -0
  310. package/dist/movement/avoidance.js +123 -0
  311. package/dist/movement/cameraRig.d.ts +8 -0
  312. package/dist/movement/cameraRig.js +8 -0
  313. package/dist/movement/dash.d.ts +11 -0
  314. package/dist/movement/dash.js +11 -0
  315. package/dist/movement/formation.d.ts +135 -0
  316. package/dist/movement/formation.js +194 -0
  317. package/dist/movement/glideModel.d.ts +5 -0
  318. package/dist/movement/glideModel.js +5 -0
  319. package/dist/movement/grappleSwing.d.ts +5 -0
  320. package/dist/movement/grappleSwing.js +5 -0
  321. package/dist/movement/leaderTrail.d.ts +5 -0
  322. package/dist/movement/leaderTrail.js +5 -0
  323. package/dist/movement/movementModel.d.ts +50 -9
  324. package/dist/movement/movementModel.js +75 -29
  325. package/dist/movement/playerMovement.js +167 -12
  326. package/dist/movement/poseState.d.ts +13 -0
  327. package/dist/movement/poseState.js +16 -0
  328. package/dist/movement/steering.d.ts +8 -0
  329. package/dist/movement/steering.js +18 -0
  330. package/dist/multiplayer/combatSnapshot.d.ts +3 -0
  331. package/dist/multiplayer/combatSnapshot.js +16 -8
  332. package/dist/multiplayer/lagCompensation.d.ts +5 -0
  333. package/dist/multiplayer/lagCompensation.js +5 -0
  334. package/dist/multiplayer/presenceModel.d.ts +11 -1
  335. package/dist/multiplayer/presenceModel.js +17 -1
  336. package/dist/multiplayer/simultaneousCommit.d.ts +3 -0
  337. package/dist/multiplayer/simultaneousCommit.js +3 -0
  338. package/dist/multiplayer.d.ts +11 -0
  339. package/dist/multiplayer.js +11 -0
  340. package/dist/nav/pathFollow.d.ts +57 -0
  341. package/dist/nav/pathFollow.js +109 -0
  342. package/dist/orders/orderKinds.d.ts +156 -0
  343. package/dist/orders/orderKinds.js +197 -0
  344. package/dist/orders/orderQueue.d.ts +208 -0
  345. package/dist/orders/orderQueue.js +211 -0
  346. package/dist/physics/drivableVehicle.d.ts +31 -0
  347. package/dist/physics/drivableVehicle.js +16 -0
  348. package/dist/physics/flightDynamics.d.ts +82 -0
  349. package/dist/physics/flightDynamics.js +165 -0
  350. package/dist/physics/gravityField.d.ts +25 -0
  351. package/dist/physics/gravityField.js +41 -0
  352. package/dist/physics/kinematicVehicle.d.ts +108 -1
  353. package/dist/physics/kinematicVehicle.js +212 -15
  354. package/dist/physics/physicsWorld.d.ts +50 -12
  355. package/dist/physics/physicsWorld.js +120 -122
  356. package/dist/physics/radialImpulse.d.ts +25 -0
  357. package/dist/physics/radialImpulse.js +27 -0
  358. package/dist/physics/vehicleObstacles.d.ts +44 -0
  359. package/dist/physics/vehicleObstacles.js +115 -0
  360. package/dist/procedural.d.ts +3 -0
  361. package/dist/procedural.js +3 -0
  362. package/dist/progression/statGraph.d.ts +116 -0
  363. package/dist/progression/statGraph.js +318 -0
  364. package/dist/puzzle/cellGrid.d.ts +9 -0
  365. package/dist/puzzle/cellGrid.js +9 -0
  366. package/dist/puzzle/fallingPiece.d.ts +9 -0
  367. package/dist/puzzle/fallingPiece.js +9 -0
  368. package/dist/puzzle/nonogram.d.ts +39 -0
  369. package/dist/puzzle/nonogram.js +136 -0
  370. package/dist/random/nameGen.d.ts +5 -0
  371. package/dist/random/nameGen.js +5 -0
  372. package/dist/random/pick.d.ts +8 -0
  373. package/dist/random/pick.js +31 -0
  374. package/dist/random/rng.d.ts +26 -1
  375. package/dist/random/rng.js +32 -9
  376. package/dist/random/seedLink.d.ts +4 -0
  377. package/dist/random/seedLink.js +4 -0
  378. package/dist/relation/keyedValues.d.ts +54 -0
  379. package/dist/relation/keyedValues.js +115 -0
  380. package/dist/relation/thresholds.d.ts +62 -0
  381. package/dist/relation/thresholds.js +62 -0
  382. package/dist/render/color.d.ts +12 -0
  383. package/dist/render/color.js +26 -0
  384. package/dist/render/lookPreset.d.ts +41 -0
  385. package/dist/render/lookPreset.js +29 -0
  386. package/dist/render/postProcessing.d.ts +20 -0
  387. package/dist/render/postProcessing.js +21 -1
  388. package/dist/rules/predicate.d.ts +53 -0
  389. package/dist/rules/predicate.js +64 -0
  390. package/dist/rules/ruleEffects.d.ts +38 -0
  391. package/dist/rules/ruleEffects.js +37 -0
  392. package/dist/rules/triggeredRules.d.ts +160 -0
  393. package/dist/rules/triggeredRules.js +241 -0
  394. package/dist/runtime/adapter.d.ts +55 -3
  395. package/dist/runtime/adapter.js +57 -1
  396. package/dist/runtime/cameraDirector.d.ts +1 -0
  397. package/dist/runtime/cameraDirector.js +1 -0
  398. package/dist/runtime/commandRunner.d.ts +1 -0
  399. package/dist/runtime/commandRunner.js +1 -0
  400. package/dist/runtime/context/combat.d.ts +51 -0
  401. package/dist/runtime/context/combat.js +130 -0
  402. package/dist/runtime/context/combatFx.d.ts +23 -0
  403. package/dist/runtime/context/combatFx.js +161 -0
  404. package/dist/runtime/context/deathLoot.d.ts +30 -0
  405. package/dist/runtime/context/deathLoot.js +39 -0
  406. package/dist/runtime/context/player.d.ts +48 -0
  407. package/dist/runtime/context/player.js +125 -0
  408. package/dist/runtime/context/registries.d.ts +13 -0
  409. package/dist/runtime/context/registries.js +84 -0
  410. package/dist/runtime/context/scene.d.ts +59 -0
  411. package/dist/runtime/context/scene.js +291 -0
  412. package/dist/runtime/context/snapshotCodecs.d.ts +12 -0
  413. package/dist/runtime/context/snapshotCodecs.js +26 -0
  414. package/dist/runtime/context/worldItems.d.ts +21 -0
  415. package/dist/runtime/context/worldItems.js +37 -0
  416. package/dist/runtime/descriptors/baseline.d.ts +48 -0
  417. package/dist/runtime/descriptors/baseline.js +157 -0
  418. package/dist/runtime/descriptors/features.d.ts +79 -0
  419. package/dist/runtime/descriptors/features.js +299 -0
  420. package/dist/runtime/gameContext.d.ts +2 -327
  421. package/dist/runtime/gameContext.js +273 -778
  422. package/dist/runtime/gameContextTypes.d.ts +467 -0
  423. package/dist/runtime/gameContextTypes.js +1 -0
  424. package/dist/runtime/gameRuntime.d.ts +1 -0
  425. package/dist/runtime/gameRuntime.js +1 -0
  426. package/dist/runtime/headlessRunner.d.ts +62 -0
  427. package/dist/runtime/headlessRunner.js +45 -0
  428. package/dist/runtime/hostPersistence.d.ts +12 -0
  429. package/dist/runtime/hostPersistence.js +12 -0
  430. package/dist/runtime/hostPolicy.d.ts +51 -0
  431. package/dist/runtime/hostPolicy.js +68 -0
  432. package/dist/runtime/hostedGameRunner.d.ts +11 -4
  433. package/dist/runtime/hostedGameRunner.js +27 -3
  434. package/dist/runtime/hostedWorldSession.d.ts +15 -5
  435. package/dist/runtime/hostedWorldSession.js +12 -4
  436. package/dist/runtime/inputSnapshot.d.ts +8 -3
  437. package/dist/runtime/inputSnapshot.js +6 -2
  438. package/dist/runtime/motionIntents.d.ts +11 -2
  439. package/dist/runtime/motionIntents.js +16 -2
  440. package/dist/runtime/perContext.d.ts +15 -0
  441. package/dist/runtime/perContext.js +21 -0
  442. package/dist/runtime/runtimeSave.d.ts +79 -0
  443. package/dist/runtime/runtimeSave.js +105 -0
  444. package/dist/runtime/save.d.ts +4 -0
  445. package/dist/runtime/save.js +4 -0
  446. package/dist/runtime/snapshot.d.ts +7 -0
  447. package/dist/runtime/snapshot.js +7 -0
  448. package/dist/runtime/visibility.d.ts +2 -1
  449. package/dist/runtime/visibility.js +2 -1
  450. package/dist/runtime/worldChannel.d.ts +7 -3
  451. package/dist/runtime/worldChannel.js +51 -6
  452. package/dist/runtime/worldMirror.d.ts +14 -2
  453. package/dist/runtime/worldMirror.js +15 -2
  454. package/dist/runtime/worldProjection.d.ts +47 -0
  455. package/dist/runtime/worldProjection.js +52 -0
  456. package/dist/runtime/worldReplication.d.ts +30 -7
  457. package/dist/runtime/worldReplication.js +41 -9
  458. package/dist/runtime/worldSnapshot.d.ts +42 -3
  459. package/dist/runtime/worldSnapshot.js +34 -7
  460. package/dist/scene/assetCatalog.d.ts +26 -0
  461. package/dist/scene/assetCatalog.js +4 -0
  462. package/dist/scene/assetDiagnostics.d.ts +69 -0
  463. package/dist/scene/assetDiagnostics.js +110 -0
  464. package/dist/scene/assetGenerator.d.ts +65 -0
  465. package/dist/scene/assetGenerator.js +64 -0
  466. package/dist/scene/assetSpace.d.ts +137 -0
  467. package/dist/scene/assetSpace.js +257 -0
  468. package/dist/scene/authoredTriggers.d.ts +219 -0
  469. package/dist/scene/authoredTriggers.js +454 -0
  470. package/dist/scene/behaviorRuntime.d.ts +75 -0
  471. package/dist/scene/behaviorRuntime.js +217 -0
  472. package/dist/scene/behaviors.d.ts +14 -2
  473. package/dist/scene/behaviors.js +7 -2
  474. package/dist/scene/bodyBind.d.ts +60 -0
  475. package/dist/scene/bodyBind.js +51 -0
  476. package/dist/scene/builtinSceneKinds.d.ts +5 -0
  477. package/dist/scene/builtinSceneKinds.js +67 -0
  478. package/dist/scene/colliders.d.ts +71 -1
  479. package/dist/scene/colliders.js +145 -1
  480. package/dist/scene/collisionMesh.d.ts +94 -0
  481. package/dist/scene/collisionMesh.js +699 -0
  482. package/dist/scene/companion.d.ts +147 -0
  483. package/dist/scene/companion.js +193 -0
  484. package/dist/scene/entityStats.d.ts +18 -11
  485. package/dist/scene/entityStats.js +21 -16
  486. package/dist/scene/entityStore.d.ts +12 -1
  487. package/dist/scene/entityStore.js +15 -0
  488. package/dist/scene/facing.d.ts +18 -0
  489. package/dist/scene/facing.js +26 -0
  490. package/dist/scene/modelSockets.d.ts +33 -0
  491. package/dist/scene/modelSockets.js +29 -0
  492. package/dist/scene/objectQuery.d.ts +2 -0
  493. package/dist/scene/objectQuery.js +2 -0
  494. package/dist/scene/objectStore.d.ts +4 -0
  495. package/dist/scene/objectStore.js +6 -0
  496. package/dist/scene/possession.d.ts +8 -0
  497. package/dist/scene/possession.js +14 -0
  498. package/dist/scene/roster.d.ts +3 -0
  499. package/dist/scene/roster.js +12 -0
  500. package/dist/scene/sceneKinds.d.ts +256 -0
  501. package/dist/scene/sceneKinds.js +218 -0
  502. package/dist/scene/sceneOwnership.d.ts +169 -0
  503. package/dist/scene/sceneOwnership.js +179 -0
  504. package/dist/scene/sceneRaycast.js +15 -0
  505. package/dist/scene/selectionBookmarks.d.ts +93 -0
  506. package/dist/scene/selectionBookmarks.js +122 -0
  507. package/dist/scene/vehicleSeat.d.ts +68 -0
  508. package/dist/scene/vehicleSeat.js +59 -0
  509. package/dist/sensor/concealment.d.ts +3 -0
  510. package/dist/sensor/concealment.js +3 -0
  511. package/dist/sensor/freezeMonitor.d.ts +1 -0
  512. package/dist/sensor/freezeMonitor.js +1 -0
  513. package/dist/sensor/frustumSensor.d.ts +7 -3
  514. package/dist/sensor/frustumSensor.js +7 -3
  515. package/dist/sensor/hiddenStateProbe.d.ts +5 -2
  516. package/dist/sensor/hiddenStateProbe.js +5 -2
  517. package/dist/sensor/recordingBuffer.d.ts +2 -1
  518. package/dist/sensor/recordingBuffer.js +2 -1
  519. package/dist/sensor/replayLoop.d.ts +6 -2
  520. package/dist/sensor/replayLoop.js +6 -2
  521. package/dist/sensor/revealQuery.d.ts +2 -1
  522. package/dist/sensor/revealQuery.js +2 -1
  523. package/dist/sensor/visionCone.d.ts +10 -3
  524. package/dist/sensor/visionCone.js +10 -3
  525. package/dist/session/contestedChannel.d.ts +1 -0
  526. package/dist/session/contestedChannel.js +1 -0
  527. package/dist/session/extraction.d.ts +1 -0
  528. package/dist/session/extraction.js +1 -0
  529. package/dist/session/roles.d.ts +6 -0
  530. package/dist/session/roles.js +6 -0
  531. package/dist/session/roundState.d.ts +8 -0
  532. package/dist/session/roundState.js +2 -0
  533. package/dist/settings/settingsModel.d.ts +1 -0
  534. package/dist/settings/settingsModel.js +1 -0
  535. package/dist/stats/accumulatorMeter.d.ts +6 -0
  536. package/dist/stats/accumulatorMeter.js +6 -0
  537. package/dist/stats/eventMeter.d.ts +5 -0
  538. package/dist/stats/eventMeter.js +5 -0
  539. package/dist/stats/rollCheck.d.ts +5 -0
  540. package/dist/stats/rollCheck.js +5 -0
  541. package/dist/stats/spawnLevelStats.d.ts +110 -0
  542. package/dist/stats/spawnLevelStats.js +140 -0
  543. package/dist/stats/statModifiers.d.ts +5 -0
  544. package/dist/stats/statModifiers.js +5 -0
  545. package/dist/stats/statPool.d.ts +70 -0
  546. package/dist/stats/statPool.js +59 -0
  547. package/dist/store/changeSignal.d.ts +3 -0
  548. package/dist/store/changeSignal.js +2 -0
  549. package/dist/store/defineKeyedStore.d.ts +38 -0
  550. package/dist/store/defineKeyedStore.js +42 -0
  551. package/dist/store/defineStore.d.ts +33 -0
  552. package/dist/store/defineStore.js +35 -0
  553. package/dist/store/observableKeyedStore.d.ts +7 -0
  554. package/dist/store/observableKeyedStore.js +35 -2
  555. package/dist/survival/decayMeter.d.ts +55 -0
  556. package/dist/survival/decayMeter.js +130 -57
  557. package/dist/survival/moodle.d.ts +2 -0
  558. package/dist/survival/regionHealth.d.ts +6 -0
  559. package/dist/survival/regionHealth.js +6 -3
  560. package/dist/tactics/fallingGrid.d.ts +4 -2
  561. package/dist/tactics/fallingGrid.js +4 -2
  562. package/dist/tactics/predictiveQuery.d.ts +3 -0
  563. package/dist/tactics/predictiveQuery.js +3 -0
  564. package/dist/tactics/snapshot.d.ts +2 -0
  565. package/dist/tactics/snapshot.js +2 -0
  566. package/dist/tactics/surface.d.ts +1 -0
  567. package/dist/tactics/surface.js +1 -0
  568. package/dist/tactics/tacticalGrid.d.ts +1 -0
  569. package/dist/tactics/tacticalGrid.js +1 -0
  570. package/dist/time/beatClock.d.ts +14 -4
  571. package/dist/time/beatClock.js +14 -4
  572. package/dist/time/calendarClock.d.ts +3 -0
  573. package/dist/time/calendarClock.js +3 -0
  574. package/dist/time/idleProgress.d.ts +4 -0
  575. package/dist/time/idleProgress.js +4 -0
  576. package/dist/time/simClock.d.ts +2 -0
  577. package/dist/time/simClock.js +20 -5
  578. package/dist/ui/actionModel.d.ts +110 -0
  579. package/dist/ui/actionModel.js +159 -0
  580. package/dist/ui/gameLayout.d.ts +30 -11
  581. package/dist/ui/gameLayout.js +30 -11
  582. package/dist/ui/hudDocument.d.ts +114 -0
  583. package/dist/ui/hudDocument.js +220 -0
  584. package/dist/ui/hudLayout.d.ts +38 -1
  585. package/dist/ui/hudLayout.js +220 -17
  586. package/dist/ui/selectionModel.d.ts +92 -0
  587. package/dist/ui/selectionModel.js +88 -0
  588. package/dist/ui/tooltipModel.d.ts +63 -0
  589. package/dist/ui/tooltipModel.js +82 -0
  590. package/dist/ui.d.ts +15 -0
  591. package/dist/ui.js +15 -0
  592. package/dist/visibility/bounds.d.ts +8 -1
  593. package/dist/visibility/bounds.js +8 -1
  594. package/dist/visibility/frustum.d.ts +12 -3
  595. package/dist/visibility/frustum.js +12 -3
  596. package/dist/work/jobQueue.d.ts +201 -0
  597. package/dist/work/jobQueue.js +253 -0
  598. package/dist/work/unitTraining.d.ts +58 -0
  599. package/dist/work/unitTraining.js +52 -0
  600. package/dist/world/authoredEntities.d.ts +29 -0
  601. package/dist/world/authoredEntities.js +29 -0
  602. package/dist/world/authoredObjects.d.ts +72 -0
  603. package/dist/world/authoredObjects.js +81 -0
  604. package/dist/world/authoredSpawn.d.ts +39 -0
  605. package/dist/world/authoredSpawn.js +37 -0
  606. package/dist/world/buildSockets.d.ts +152 -0
  607. package/dist/world/buildSockets.js +188 -0
  608. package/dist/world/buildingGenerator.d.ts +18 -0
  609. package/dist/world/buildingGenerator.js +62 -0
  610. package/dist/world/buildings.d.ts +5 -0
  611. package/dist/world/buildings.js +5 -0
  612. package/dist/world/catenary.d.ts +22 -0
  613. package/dist/world/catenary.js +69 -0
  614. package/dist/world/cityBlocks.d.ts +152 -0
  615. package/dist/world/cityBlocks.js +670 -0
  616. package/dist/world/cityContent.d.ts +77 -0
  617. package/dist/world/cityContent.js +261 -0
  618. package/dist/world/cityGeometry.d.ts +114 -0
  619. package/dist/world/cityGeometry.js +573 -0
  620. package/dist/world/cityKind.d.ts +314 -0
  621. package/dist/world/cityKind.js +1578 -0
  622. package/dist/world/features.d.ts +133 -10
  623. package/dist/world/features.js +66 -6
  624. package/dist/world/footprintGrid.d.ts +59 -0
  625. package/dist/world/footprintGrid.js +141 -0
  626. package/dist/world/geometry.d.ts +64 -0
  627. package/dist/world/geometry.js +94 -0
  628. package/dist/world/grassKind.d.ts +51 -0
  629. package/dist/world/grassKind.js +101 -0
  630. package/dist/world/markers.d.ts +50 -4
  631. package/dist/world/markers.js +49 -0
  632. package/dist/world/massing.js +1 -1
  633. package/dist/world/minimapBake.d.ts +78 -0
  634. package/dist/world/minimapBake.js +208 -0
  635. package/dist/world/minimapTrack.d.ts +17 -0
  636. package/dist/world/minimapTrack.js +22 -0
  637. package/dist/world/pathInstances.d.ts +27 -0
  638. package/dist/world/pathInstances.js +27 -0
  639. package/dist/world/pathNetwork.d.ts +159 -0
  640. package/dist/world/pathNetwork.js +684 -0
  641. package/dist/world/pathTerrain.d.ts +80 -0
  642. package/dist/world/pathTerrain.js +142 -0
  643. package/dist/world/place.d.ts +166 -0
  644. package/dist/world/place.js +96 -0
  645. package/dist/world/placeAsset.d.ts +81 -0
  646. package/dist/world/placeAsset.js +79 -0
  647. package/dist/world/placement.d.ts +4 -0
  648. package/dist/world/placement.js +4 -0
  649. package/dist/world/placementController.d.ts +6 -0
  650. package/dist/world/placementController.js +6 -0
  651. package/dist/world/poleLineKind.d.ts +40 -0
  652. package/dist/world/poleLineKind.js +97 -0
  653. package/dist/world/polyline.d.ts +34 -0
  654. package/dist/world/polyline.js +88 -0
  655. package/dist/world/resourceNode.d.ts +109 -0
  656. package/dist/world/resourceNode.js +140 -0
  657. package/dist/world/roads.d.ts +8 -0
  658. package/dist/world/roads.js +38 -0
  659. package/dist/world/scatter.js +2 -20
  660. package/dist/world/scatterRegion.d.ts +164 -0
  661. package/dist/world/scatterRegion.js +409 -0
  662. package/dist/world/sceneShapes.d.ts +43 -0
  663. package/dist/world/sceneShapes.js +1 -0
  664. package/dist/world/segment.d.ts +27 -0
  665. package/dist/world/segment.js +43 -0
  666. package/dist/world/soilKind.d.ts +48 -0
  667. package/dist/world/soilKind.js +92 -0
  668. package/dist/world/spatialSample.d.ts +241 -0
  669. package/dist/world/spatialSample.js +465 -0
  670. package/dist/world/streets.d.ts +29 -0
  671. package/dist/world/streets.js +55 -0
  672. package/dist/world/terraform.d.ts +213 -1
  673. package/dist/world/terraform.js +627 -22
  674. package/dist/world/terrain.d.ts +164 -20
  675. package/dist/world/terrain.js +325 -41
  676. package/dist/world/terrainGuides.d.ts +182 -0
  677. package/dist/world/terrainGuides.js +343 -0
  678. package/dist/world/vec2.d.ts +81 -0
  679. package/dist/world/vec2.js +128 -0
  680. package/dist/world/vec3.d.ts +49 -0
  681. package/dist/world/vec3.js +76 -0
  682. package/dist/world/vegetation.d.ts +71 -0
  683. package/dist/world/vegetation.js +151 -0
  684. package/dist/world/visibilityField.d.ts +154 -0
  685. package/dist/world/visibilityField.js +271 -0
  686. package/dist/world/volumetricClouds.d.ts +52 -0
  687. package/dist/world/volumetricClouds.js +43 -0
  688. package/dist/world/walls.d.ts +9 -0
  689. package/dist/world/walls.js +9 -0
  690. package/dist/world/waterKind.d.ts +55 -0
  691. package/dist/world/waterKind.js +99 -0
  692. package/dist/world.d.ts +141 -0
  693. package/dist/world.js +141 -0
  694. package/package.json +32 -8
  695. package/skills/game-design/SKILL.md +28 -0
  696. package/skills/game-design/agents/openai.yaml +4 -0
  697. package/skills/game-design/references/application-playbook.md +170 -0
  698. package/skills/game-design/references/field-guide.md +288 -0
  699. package/skills/jgengine/SKILL.md +54 -0
  700. package/skills/jgengine/api.md +527 -0
  701. package/skills/jgengine/capabilities.md +131 -0
  702. package/skills/jgengine/recipes/minimal-game.md +88 -0
  703. package/skills/jgengine-combat/SKILL.md +38 -0
  704. package/skills/jgengine-combat/api.md +585 -0
  705. package/skills/jgengine-combat/capabilities.md +213 -0
  706. package/skills/jgengine-combat/recipes/portable-stat-pools.md +122 -0
  707. package/skills/jgengine-combat/reference.md +108 -0
  708. package/skills/jgengine-gameplay/SKILL.md +39 -0
  709. package/skills/jgengine-gameplay/api.md +1920 -0
  710. package/skills/jgengine-gameplay/capabilities.md +454 -0
  711. package/skills/jgengine-gameplay/reference-systems.md +56 -0
  712. package/skills/jgengine-world/SKILL.md +51 -0
  713. package/skills/jgengine-world/api.md +3056 -0
  714. package/skills/jgengine-world/capabilities.md +476 -0
  715. package/skills/jgengine-world/recipes/commanding-entities.md +128 -0
  716. package/skills/jgengine-world/reference.md +261 -0
  717. package/dist/cartridge/runtime.d.ts +0 -15
  718. package/dist/cartridge/runtime.js +0 -556
  719. package/dist/cartridge/spec.d.ts +0 -188
  720. package/dist/cartridge/spec.js +0 -19
  721. package/dist/cartridge/validate.d.ts +0 -2
  722. package/dist/cartridge/validate.js +0 -78
  723. package/dist/store/engineStore.d.ts +0 -22
  724. package/dist/store/engineStore.js +0 -50
  725. package/dist/store/features.d.ts +0 -10
  726. package/dist/store/features.js +0 -23
  727. package/llms.txt +0 -5389
@@ -0,0 +1,147 @@
1
+ import type { MobVec3 } from "../ai/mobBrain.js";
2
+ import type { StatCatalog, StatValue, StatValueMap } from "./entityStats.js";
3
+ /**
4
+ * A tamed companion's standing order. Genre-agnostic aggression + posture preset:
5
+ * - `follow` — heel to the owner and assist whatever the owner is fighting.
6
+ * - `stay` — hold at `home` and assist the owner's target from there.
7
+ * - `passive` — heel to the owner and never engage (a pacifist escort).
8
+ * - `neutral` — heel to the owner and only fight back nearby threats (defensive).
9
+ * - `aggressive` — heel to the owner and proactively engage nearby threats and the owner's target.
10
+ */
11
+ export type CompanionCommand = "follow" | "stay" | "passive" | "neutral" | "aggressive";
12
+ /**
13
+ * Serializable per-companion state: who owns it, its standing order, where it holds, its
14
+ * leash radius, and its levelled stat pool. Plain data — JSON round-trips without loss.
15
+ */
16
+ export interface CompanionRecord {
17
+ id: string;
18
+ /** Owning user/entity id — the roster ownership tie. */
19
+ ownerId: string;
20
+ /** The {@link RosterEntry.id} this companion was tamed from, or `null` when free-standing. */
21
+ sourceId: string | null;
22
+ command: CompanionCommand;
23
+ /** Hold/return anchor used by `stay`; `null` until the owner parks it somewhere. */
24
+ home: MobVec3 | null;
25
+ /** Radius the game keeps the companion within of its resolved anchor (feeds a brain's leash distance). */
26
+ leash: number;
27
+ level: number;
28
+ /** Stat points earned from levels and not yet spent via {@link CompanionRoster.spend}. */
29
+ unspentPoints: number;
30
+ /** Levelled stat pool, composed over `scene/entityStats`. */
31
+ stats: StatValueMap;
32
+ }
33
+ /** Per-tick world context the game supplies so a command resolves into a concrete intent. */
34
+ export interface CompanionIntentContext {
35
+ /** Owner's current world position — the anchor for every non-`stay` mode; `null` when absent. */
36
+ ownerPosition?: MobVec3 | null;
37
+ /** The owner's current attack target — the companion assists/aggros it per its command. */
38
+ ownerTargetId?: string | null;
39
+ /** Threat ids near the companion the game offers as engage candidates (already proximity-filtered upstream). */
40
+ threats?: readonly string[];
41
+ }
42
+ /**
43
+ * The companion's decision for one tick, shaped for `ai/mobBrain`: feed `candidates` into
44
+ * `MobBrainDeps.candidates()`, treat `leashTo` as the brain's `home`, and pass `leashDistance`
45
+ * as `leashDistance`. `kind` summarises the posture for HUD/animation.
46
+ */
47
+ export interface CompanionIntent {
48
+ /** `follow`/`hold` when idle at the anchor; `engage` a fresh threat; `assist` the owner's target. */
49
+ kind: "follow" | "hold" | "engage" | "assist";
50
+ /** Whether the companion leashes to the owner (follow modes) or its `home` (stay). */
51
+ anchor: "owner" | "home";
52
+ /** Resolved anchor world point — owner position or `home`; `null` when that point is unknown. */
53
+ leashTo: MobVec3 | null;
54
+ /** Leash radius (copied from the record) the game passes to the brain / clamps movement against. */
55
+ leashDistance: number;
56
+ /** Threat ids to expose as `MobBrainDeps.candidates()`; empty when the command forbids engaging. */
57
+ candidates: readonly string[];
58
+ /** The primary threat to engage/assist this tick — `candidates[0]`; `null` while following/holding. */
59
+ targetId: string | null;
60
+ }
61
+ /** Rule for turning one spent level-point into a stat gain. Absent from config ⇒ the stat can't be upgraded. */
62
+ export interface CompanionStatUpgrade {
63
+ /** Amount a single point adds to the stat's `max` (and heals into `current`). */
64
+ increment: number;
65
+ /** Hard ceiling for the stat's `max`; spends that would exceed it are rejected. */
66
+ maxCap?: number;
67
+ }
68
+ /** Outcome of {@link CompanionRoster.spend}: the updated record + stat, or a rejection reason. */
69
+ export type CompanionSpendResult = {
70
+ status: "ok";
71
+ record: CompanionRecord;
72
+ stat: StatValue;
73
+ } | {
74
+ status: "rejected";
75
+ reason: string;
76
+ };
77
+ /** Per-companion configuration shared by every companion the roster mints. */
78
+ export interface CompanionConfig {
79
+ /** Stat catalog seeded into each new companion's pool (via `entityStats.seedStatValues`). */
80
+ stats?: StatCatalog;
81
+ /** Per-stat upgrade rules consulted by {@link CompanionRoster.spend}. */
82
+ upgrades?: Record<string, CompanionStatUpgrade>;
83
+ /** Points granted on reaching a given level; default `1` per level. Inject `game/progression` curves here. */
84
+ pointsPerLevel?: (level: number) => number;
85
+ /** Level ceiling; `levelUp` past it is a no-op. Default `Infinity`. */
86
+ maxLevel?: number;
87
+ /** Level every companion starts at; default `1`. */
88
+ startLevel?: number;
89
+ /** Default leash radius for new companions; default `12`. */
90
+ leash?: number;
91
+ }
92
+ /** Options for {@link CompanionRoster.adopt}. */
93
+ export interface CompanionAdoptOptions {
94
+ id?: string;
95
+ /** The {@link RosterEntry.id} this companion springs from — the ownership/catalog tie. */
96
+ sourceId?: string;
97
+ command?: CompanionCommand;
98
+ home?: MobVec3 | null;
99
+ leash?: number;
100
+ level?: number;
101
+ /** Override the config stat catalog for this one companion. */
102
+ stats?: StatCatalog;
103
+ }
104
+ /**
105
+ * A set of tamed companions keyed by companion id, scoped to owners. Wraps allegiance/command
106
+ * state, per-companion levelled stats, and intent resolution behind create/command/level/
107
+ * snapshot/hydrate — the counterpart of `scene/roster` for creatures that fight beside you.
108
+ */
109
+ export interface CompanionRoster {
110
+ /** Mint a companion for an owner (optionally tied to a {@link RosterEntry}). */
111
+ adopt(ownerId: string, options?: CompanionAdoptOptions): CompanionRecord;
112
+ release(companionId: string): boolean;
113
+ get(companionId: string): CompanionRecord | null;
114
+ ownerOf(companionId: string): string | null;
115
+ list(ownerId: string): readonly CompanionRecord[];
116
+ /** Set a companion's standing order; `null` if the id is unknown. */
117
+ command(companionId: string, command: CompanionCommand): CompanionRecord | null;
118
+ /** Park/clear a companion's `stay` anchor. */
119
+ setHome(companionId: string, home: MobVec3 | null): CompanionRecord | null;
120
+ setLeash(companionId: string, leash: number): CompanionRecord | null;
121
+ /** Gain `levels` levels (bounded by `maxLevel`), accruing points from `pointsPerLevel`. */
122
+ levelUp(companionId: string, levels?: number): CompanionRecord | null;
123
+ /** Spend one earned point into a stat per its {@link CompanionStatUpgrade} rule. */
124
+ spend(companionId: string, statId: string): CompanionSpendResult;
125
+ /** Resolve the companion's per-tick {@link CompanionIntent}; `null` if the id is unknown. */
126
+ resolveIntent(companionId: string, context: CompanionIntentContext): CompanionIntent | null;
127
+ /** Whole-store serializable copy — the save/replication seam. */
128
+ snapshot(): Record<string, CompanionRecord>;
129
+ hydrate(data: Record<string, CompanionRecord>): void;
130
+ }
131
+ /**
132
+ * Pure command → intent resolver. Maps a companion's standing order plus this tick's owner
133
+ * position, owner target, and nearby threats into the {@link CompanionIntent} a game feeds into
134
+ * `ai/mobBrain` (or executes directly). Deterministic and allocation-light — no import of the
135
+ * `@internal` brain factory; the two interoperate purely by shape.
136
+ *
137
+ * @capability companion-intent resolve a companion's command + threat context into a per-tick follow/hold/engage/assist intent
138
+ */
139
+ export declare function resolveCompanionIntent(record: CompanionRecord, context: CompanionIntentContext): CompanionIntent;
140
+ /**
141
+ * Build a {@link CompanionRoster}. Composes `scene/roster` ownership (via `ownerId`/`sourceId`),
142
+ * `scene/entityStats` for the per-companion stat pool, and {@link resolveCompanionIntent} for
143
+ * `ai/mobBrain`-shaped behavior — turning a captured creature into a loyal, levelling ally.
144
+ *
145
+ * @capability companion-roster manage tamed companions — allegiance, commands, per-companion stats/leveling, and mobBrain-shaped intent
146
+ */
147
+ export declare function createCompanionRoster(config?: CompanionConfig): CompanionRoster;
@@ -0,0 +1,193 @@
1
+ import { seedStatValues, setStatValue } from "./entityStats.js";
2
+ function dedupePush(out, id) {
3
+ if (!out.includes(id))
4
+ out.push(id);
5
+ }
6
+ function candidatesFor(command, ownerTargetId, threats) {
7
+ switch (command) {
8
+ case "passive":
9
+ return [];
10
+ case "follow":
11
+ case "stay":
12
+ return ownerTargetId === null ? [] : [ownerTargetId];
13
+ case "neutral":
14
+ return [...threats];
15
+ case "aggressive": {
16
+ const out = [];
17
+ for (const threat of threats)
18
+ dedupePush(out, threat);
19
+ if (ownerTargetId !== null)
20
+ dedupePush(out, ownerTargetId);
21
+ return out;
22
+ }
23
+ }
24
+ }
25
+ /**
26
+ * Pure command → intent resolver. Maps a companion's standing order plus this tick's owner
27
+ * position, owner target, and nearby threats into the {@link CompanionIntent} a game feeds into
28
+ * `ai/mobBrain` (or executes directly). Deterministic and allocation-light — no import of the
29
+ * `@internal` brain factory; the two interoperate purely by shape.
30
+ *
31
+ * @capability companion-intent resolve a companion's command + threat context into a per-tick follow/hold/engage/assist intent
32
+ */
33
+ export function resolveCompanionIntent(record, context) {
34
+ const ownerTargetId = context.ownerTargetId ?? null;
35
+ const threats = context.threats ?? [];
36
+ const anchor = record.command === "stay" ? "home" : "owner";
37
+ const leashTo = anchor === "home" ? record.home : (context.ownerPosition ?? null);
38
+ const candidates = candidatesFor(record.command, ownerTargetId, threats);
39
+ const targetId = candidates.length > 0 ? candidates[0] : null;
40
+ let kind;
41
+ if (targetId === null) {
42
+ kind = anchor === "home" ? "hold" : "follow";
43
+ }
44
+ else if (targetId === ownerTargetId) {
45
+ kind = "assist";
46
+ }
47
+ else {
48
+ kind = "engage";
49
+ }
50
+ return { kind, anchor, leashTo, leashDistance: record.leash, candidates, targetId };
51
+ }
52
+ function cloneStats(stats) {
53
+ const out = {};
54
+ for (const [statId, value] of Object.entries(stats))
55
+ out[statId] = { ...value };
56
+ return out;
57
+ }
58
+ function cloneRecord(record) {
59
+ return {
60
+ id: record.id,
61
+ ownerId: record.ownerId,
62
+ sourceId: record.sourceId,
63
+ command: record.command,
64
+ home: record.home === null ? null : [record.home[0], record.home[1], record.home[2]],
65
+ leash: record.leash,
66
+ level: record.level,
67
+ unspentPoints: record.unspentPoints,
68
+ stats: cloneStats(record.stats),
69
+ };
70
+ }
71
+ /**
72
+ * Build a {@link CompanionRoster}. Composes `scene/roster` ownership (via `ownerId`/`sourceId`),
73
+ * `scene/entityStats` for the per-companion stat pool, and {@link resolveCompanionIntent} for
74
+ * `ai/mobBrain`-shaped behavior — turning a captured creature into a loyal, levelling ally.
75
+ *
76
+ * @capability companion-roster manage tamed companions — allegiance, commands, per-companion stats/leveling, and mobBrain-shaped intent
77
+ */
78
+ export function createCompanionRoster(config = {}) {
79
+ const records = new Map();
80
+ const pointsPerLevel = config.pointsPerLevel ?? (() => 1);
81
+ const maxLevel = config.maxLevel ?? Number.POSITIVE_INFINITY;
82
+ const startLevel = config.startLevel ?? 1;
83
+ const defaultLeash = config.leash ?? 12;
84
+ let counter = 0;
85
+ const write = (record) => {
86
+ records.set(record.id, record);
87
+ return record;
88
+ };
89
+ const patch = (companionId, fn) => {
90
+ const record = records.get(companionId);
91
+ if (record === undefined)
92
+ return null;
93
+ return write(fn(record));
94
+ };
95
+ return {
96
+ adopt(ownerId, options = {}) {
97
+ counter += 1;
98
+ const id = options.id ?? `companion_${counter}`;
99
+ const seed = options.stats ?? config.stats ?? {};
100
+ const record = {
101
+ id,
102
+ ownerId,
103
+ sourceId: options.sourceId ?? null,
104
+ command: options.command ?? "follow",
105
+ home: options.home ?? null,
106
+ leash: options.leash ?? defaultLeash,
107
+ level: options.level ?? startLevel,
108
+ unspentPoints: 0,
109
+ stats: seedStatValues(seed),
110
+ };
111
+ return write(record);
112
+ },
113
+ release(companionId) {
114
+ return records.delete(companionId);
115
+ },
116
+ get(companionId) {
117
+ return records.get(companionId) ?? null;
118
+ },
119
+ ownerOf(companionId) {
120
+ return records.get(companionId)?.ownerId ?? null;
121
+ },
122
+ list(ownerId) {
123
+ const out = [];
124
+ for (const record of records.values())
125
+ if (record.ownerId === ownerId)
126
+ out.push(record);
127
+ return out;
128
+ },
129
+ command(companionId, command) {
130
+ return patch(companionId, (record) => ({ ...record, command }));
131
+ },
132
+ setHome(companionId, home) {
133
+ return patch(companionId, (record) => ({
134
+ ...record,
135
+ home: home === null ? null : [home[0], home[1], home[2]],
136
+ }));
137
+ },
138
+ setLeash(companionId, leash) {
139
+ return patch(companionId, (record) => ({ ...record, leash }));
140
+ },
141
+ levelUp(companionId, levels = 1) {
142
+ return patch(companionId, (record) => {
143
+ let level = record.level;
144
+ let points = record.unspentPoints;
145
+ for (let i = 0; i < levels && level < maxLevel; i += 1) {
146
+ level += 1;
147
+ points += pointsPerLevel(level);
148
+ }
149
+ return { ...record, level, unspentPoints: points };
150
+ });
151
+ },
152
+ spend(companionId, statId) {
153
+ const record = records.get(companionId);
154
+ if (record === undefined)
155
+ return { status: "rejected", reason: `unknown companion "${companionId}"` };
156
+ if (record.unspentPoints <= 0)
157
+ return { status: "rejected", reason: "no unspent points" };
158
+ const upgrade = config.upgrades?.[statId];
159
+ if (upgrade === undefined)
160
+ return { status: "rejected", reason: `stat "${statId}" is not upgradable` };
161
+ const existing = record.stats[statId];
162
+ if (existing === undefined)
163
+ return { status: "rejected", reason: `unknown stat "${statId}"` };
164
+ const nextMax = existing.max + upgrade.increment;
165
+ if (upgrade.maxCap !== undefined && nextMax > upgrade.maxCap) {
166
+ return { status: "rejected", reason: `stat "${statId}" is at its cap` };
167
+ }
168
+ const stats = setStatValue(record.stats, statId, {
169
+ max: nextMax,
170
+ current: existing.current + upgrade.increment,
171
+ });
172
+ const updated = write({ ...record, unspentPoints: record.unspentPoints - 1, stats });
173
+ return { status: "ok", record: updated, stat: updated.stats[statId] };
174
+ },
175
+ resolveIntent(companionId, context) {
176
+ const record = records.get(companionId);
177
+ if (record === undefined)
178
+ return null;
179
+ return resolveCompanionIntent(record, context);
180
+ },
181
+ snapshot() {
182
+ const out = {};
183
+ for (const [id, record] of records)
184
+ out[id] = cloneRecord(record);
185
+ return out;
186
+ },
187
+ hydrate(data) {
188
+ records.clear();
189
+ for (const [id, record] of Object.entries(data))
190
+ records.set(id, cloneRecord(record));
191
+ },
192
+ };
193
+ }
@@ -1,12 +1,9 @@
1
- export interface StatValue {
2
- current: number;
3
- max: number;
4
- min: number;
1
+ import { type StatPool, type StatPoolAccess, type StatPoolPatch } from "../stats/statPool.js";
2
+ /** Native entity-stat name retained as a compatibility bridge to the portable pool model. */
3
+ export interface StatValue extends StatPool {
5
4
  }
6
- export interface StatValuePatch {
7
- current?: number;
8
- max?: number;
9
- min?: number;
5
+ /** Native entity-stat patch retained as a compatibility bridge. */
6
+ export interface StatValuePatch extends StatPoolPatch {
10
7
  }
11
8
  export type StatValueMap = Record<string, StatValue>;
12
9
  export type StatCatalog = Record<string, {
@@ -24,19 +21,29 @@ export type PoolDeltaResult = {
24
21
  status: "rejected";
25
22
  reason: string;
26
23
  };
24
+ /** @internal */
27
25
  export declare function getStatValue(map: StatValueMap, statId: string): StatValue | null;
26
+ /** @internal */
28
27
  export declare function setStatValue(map: StatValueMap, statId: string, patch: StatValuePatch): StatValueMap;
28
+ /** @internal */
29
29
  export declare function applyPoolDelta(map: StatValueMap, statId: string, amount: number): PoolDeltaResult;
30
+ /** @internal */
30
31
  export declare function seedStatValues(catalogStats: StatCatalog): StatValueMap;
31
- /** Deep-copy the per-entity stat maps into a serializable record — the transport counterpart of {@link hydrateEntityStats}. */
32
+ /** Deep-copy the per-entity stat maps into a serializable record — the transport counterpart of {@link hydrateEntityStats}.
33
+ * @internal
34
+ */
32
35
  export declare function snapshotEntityStats(store: ReadonlyMap<string, StatValueMap>): Record<string, StatValueMap>;
33
- /** Replace a live stat store with deep copies of a snapshot, clearing entities absent from it. */
36
+ /** Replace a live stat store with deep copies of a snapshot, clearing entities absent from it.
37
+ * @internal
38
+ */
34
39
  export declare function hydrateEntityStats(store: Map<string, StatValueMap>, data: Record<string, StatValueMap>): void;
35
- export interface EntityStatsApi {
40
+ /** Native entity-stat adapter over the portable {@link StatPoolAccess} contract. */
41
+ export interface EntityStatsApi extends StatPoolAccess {
36
42
  get(instanceId: string, statId: string): StatValue | null;
37
43
  set(instanceId: string, statId: string, patch: StatValuePatch): boolean;
38
44
  delta(instanceId: string, statId: string, amount: number): null | {
39
45
  reason: string;
40
46
  };
41
47
  }
48
+ /** @internal */
42
49
  export declare function createEntityStatsApi(resolve: (instanceId: string) => StatValueMap | undefined): EntityStatsApi;
@@ -1,41 +1,43 @@
1
- function clamp(value, min, max) {
2
- return Math.min(max, Math.max(min, value));
3
- }
1
+ import { changeStatPool, createStatPool, patchStatPool, } from "../stats/statPool.js";
2
+ /** @internal */
4
3
  export function getStatValue(map, statId) {
5
4
  return map[statId] ?? null;
6
5
  }
6
+ /** @internal */
7
7
  export function setStatValue(map, statId, patch) {
8
8
  const existing = map[statId];
9
- const max = patch.max ?? existing?.max ?? 0;
10
- const min = patch.min ?? existing?.min ?? 0;
11
- const current = clamp(patch.current ?? existing?.current ?? max, min, max);
12
- return { ...map, [statId]: { current, max, min } };
9
+ const next = existing === undefined
10
+ ? createStatPool({ max: patch.max ?? 0, min: patch.min, current: patch.current })
11
+ : patchStatPool(existing, patch);
12
+ return { ...map, [statId]: next };
13
13
  }
14
+ /** @internal */
14
15
  export function applyPoolDelta(map, statId, amount) {
15
16
  const existing = map[statId];
16
17
  if (existing === undefined) {
17
18
  return { status: "rejected", reason: `unknown stat "${statId}"` };
18
19
  }
19
- const current = clamp(existing.current + amount, existing.min, existing.max);
20
- const stat = { ...existing, current };
20
+ const change = changeStatPool(existing, amount);
21
+ const stat = change.pool;
21
22
  return {
22
23
  status: "ok",
23
24
  map: { ...map, [statId]: stat },
24
25
  stat,
25
- hitMin: current === existing.min,
26
- hitMax: current === existing.max,
26
+ hitMin: change.hitMin,
27
+ hitMax: change.hitMax,
27
28
  };
28
29
  }
30
+ /** @internal */
29
31
  export function seedStatValues(catalogStats) {
30
32
  const map = {};
31
33
  for (const [statId, declaration] of Object.entries(catalogStats)) {
32
- const min = declaration.min ?? 0;
33
- const current = clamp(declaration.current ?? declaration.max, min, declaration.max);
34
- map[statId] = { current, max: declaration.max, min };
34
+ map[statId] = createStatPool(declaration);
35
35
  }
36
36
  return map;
37
37
  }
38
- /** Deep-copy the per-entity stat maps into a serializable record — the transport counterpart of {@link hydrateEntityStats}. */
38
+ /** Deep-copy the per-entity stat maps into a serializable record — the transport counterpart of {@link hydrateEntityStats}.
39
+ * @internal
40
+ */
39
41
  export function snapshotEntityStats(store) {
40
42
  const out = {};
41
43
  for (const [instanceId, map] of store) {
@@ -46,7 +48,9 @@ export function snapshotEntityStats(store) {
46
48
  }
47
49
  return out;
48
50
  }
49
- /** Replace a live stat store with deep copies of a snapshot, clearing entities absent from it. */
51
+ /** Replace a live stat store with deep copies of a snapshot, clearing entities absent from it.
52
+ * @internal
53
+ */
50
54
  export function hydrateEntityStats(store, data) {
51
55
  store.clear();
52
56
  for (const [instanceId, map] of Object.entries(data)) {
@@ -56,6 +60,7 @@ export function hydrateEntityStats(store, data) {
56
60
  store.set(instanceId, copy);
57
61
  }
58
62
  }
63
+ /** @internal */
59
64
  export function createEntityStatsApi(resolve) {
60
65
  return {
61
66
  get(instanceId, statId) {
@@ -22,9 +22,16 @@ export interface SceneEntity<TMeta = unknown> {
22
22
  role: EntityRole;
23
23
  movement: EntityMovement;
24
24
  behaviors: readonly BehaviorDescriptor[];
25
- /** Game-defined per-instance data set at `spawn`/`update` and carried to `renderEntity`/queries — narrow with a cast or type guard on read (#286.1); never encode state in the id/name string. */
25
+ /** Game-defined per-instance data set at `spawn`/`update` and carried to `renderEntity`/queries — narrow with {@link entityMetaOf} (or a type guard) on read (#286.1); never encode state in the id/name string. */
26
26
  meta: TMeta;
27
27
  }
28
+ /**
29
+ * Narrow `entity.meta` with a type guard — prefer this over `entity.meta as T` so failed shapes return `null`
30
+ * instead of lying to the type checker.
31
+ *
32
+ * @capability entity-meta cast-free narrow of SceneEntity.meta via a type guard
33
+ */
34
+ export declare function entityMetaOf<T>(entity: SceneEntity<unknown>, isMeta: (value: unknown) => value is T): T | null;
28
35
  /** Ground speed (horizontal magnitude of velocity) in world units per second. Scale to km/h or mph in game code. */
29
36
  export declare function groundSpeed(entity: SceneEntity<unknown>): number;
30
37
  export declare function movedWhileFrozen(entity: SceneEntity<unknown>, threshold?: number): boolean;
@@ -96,8 +103,12 @@ export interface EntityStore<TMeta = unknown> {
96
103
  setPoseConstraint(id: string, constraint: PoseConstraint | null): void;
97
104
  get(id: string): SceneEntity<TMeta> | null;
98
105
  list(): readonly SceneEntity<TMeta>[];
106
+ /** Stable-identity list of live entity ids; identity changes only on spawn/despawn/hydrate, not on pose writes. Pair with {@link subscribeMembership} for membership-only React subscriptions that skip per-frame pose churn (#625). */
107
+ ids(): readonly string[];
99
108
  clear(): void;
100
109
  subscribe(listener: () => void): () => void;
110
+ /** Notified only when the entity set changes (spawn/despawn/hydrate), never on a pose or field update — the render tree re-reconciles on membership, individual markers read live poses imperatively. */
111
+ subscribeMembership(listener: () => void): () => void;
101
112
  snapshot(): readonly SceneEntity<TMeta>[];
102
113
  /**
103
114
  * Apply a `snapshot()` (e.g. from an authoritative host) to this store — the counterpart of `snapshot()`
@@ -1,4 +1,13 @@
1
1
  import { createObservableKeyedStore } from "../store/observableKeyedStore.js";
2
+ /**
3
+ * Narrow `entity.meta` with a type guard — prefer this over `entity.meta as T` so failed shapes return `null`
4
+ * instead of lying to the type checker.
5
+ *
6
+ * @capability entity-meta cast-free narrow of SceneEntity.meta via a type guard
7
+ */
8
+ export function entityMetaOf(entity, isMeta) {
9
+ return isMeta(entity.meta) ? entity.meta : null;
10
+ }
2
11
  /** Ground speed (horizontal magnitude of velocity) in world units per second. Scale to km/h or mph in game code. */
3
12
  export function groundSpeed(entity) {
4
13
  return Math.hypot(entity.velocity[0], entity.velocity[2]);
@@ -167,6 +176,9 @@ export function createEntityStore() {
167
176
  list() {
168
177
  return store.arraySnapshot();
169
178
  },
179
+ ids() {
180
+ return store.keysSnapshot();
181
+ },
170
182
  clear() {
171
183
  for (const entity of store.arraySnapshot()) {
172
184
  store.delete(entity.id);
@@ -177,6 +189,9 @@ export function createEntityStore() {
177
189
  subscribe(listener) {
178
190
  return store.subscribe(listener);
179
191
  },
192
+ subscribeMembership(listener) {
193
+ return store.subscribeMembership(listener);
194
+ },
180
195
  snapshot() {
181
196
  return store.arraySnapshot();
182
197
  },
@@ -0,0 +1,18 @@
1
+ /**
2
+ * The forward-axis convention: a generator or scene kind declares which way its "front" faces (a
3
+ * bookcase's open/book face, a building's entrance) once, as data, instead of leaving every placement
4
+ * to hand-tuned `rotationY` trial-and-error. `StudioStage`'s `faceCamera` (`@jgengine/shell/scene/
5
+ * StudioStage`) reads the declared axis to auto-orient a product shot; a placement tool can read the
6
+ * same field to face a freshly dropped asset toward the camera/path by default. `DEFAULT_FORWARD`
7
+ * (+Z) is what a generator/scene-kind gets when it omits `forward` — build your front toward it.
8
+ * @capability forward-axis declared front convention for parametric assets — auto-orient product shots
9
+ */
10
+ export declare const DEFAULT_FORWARD: readonly [number, number, number];
11
+ /**
12
+ * The yaw (radians, around Y) that rotates `forward` so it points from `origin` toward `target`, both
13
+ * XZ points. Pure — no three.js — so `StudioStage.faceCamera` and any future placement tool share one
14
+ * tested formula instead of re-deriving atan2 math per call site. Only `forward`'s X/Z components
15
+ * matter (yaw is a rotation about Y); returns 0 when `origin` and `target` coincide.
16
+ * @internal — consumed through `StudioStage`'s `faceCamera` prop, not called directly by game code.
17
+ */
18
+ export declare function yawToFace(forward: readonly [number, number, number], origin: readonly [number, number], target: readonly [number, number]): number;
@@ -0,0 +1,26 @@
1
+ /**
2
+ * The forward-axis convention: a generator or scene kind declares which way its "front" faces (a
3
+ * bookcase's open/book face, a building's entrance) once, as data, instead of leaving every placement
4
+ * to hand-tuned `rotationY` trial-and-error. `StudioStage`'s `faceCamera` (`@jgengine/shell/scene/
5
+ * StudioStage`) reads the declared axis to auto-orient a product shot; a placement tool can read the
6
+ * same field to face a freshly dropped asset toward the camera/path by default. `DEFAULT_FORWARD`
7
+ * (+Z) is what a generator/scene-kind gets when it omits `forward` — build your front toward it.
8
+ * @capability forward-axis declared front convention for parametric assets — auto-orient product shots
9
+ */
10
+ export const DEFAULT_FORWARD = [0, 0, 1];
11
+ /**
12
+ * The yaw (radians, around Y) that rotates `forward` so it points from `origin` toward `target`, both
13
+ * XZ points. Pure — no three.js — so `StudioStage.faceCamera` and any future placement tool share one
14
+ * tested formula instead of re-deriving atan2 math per call site. Only `forward`'s X/Z components
15
+ * matter (yaw is a rotation about Y); returns 0 when `origin` and `target` coincide.
16
+ * @internal — consumed through `StudioStage`'s `faceCamera` prop, not called directly by game code.
17
+ */
18
+ export function yawToFace(forward, origin, target) {
19
+ const dx = target[0] - origin[0];
20
+ const dz = target[1] - origin[1];
21
+ if (dx === 0 && dz === 0)
22
+ return 0;
23
+ const angleToTarget = Math.atan2(dx, dz);
24
+ const angleForward = Math.atan2(forward[0], forward[2]);
25
+ return angleToTarget - angleForward;
26
+ }
@@ -0,0 +1,33 @@
1
+ /**
2
+ * Generic named-socket reader for loaded 3D models. Walks a node tree (any object with `.name`,
3
+ * `.position`, and `.children` — structurally satisfied by `THREE.Object3D`) and collects the local
4
+ * offsets of nodes whose name marks an attachment point. Genre-agnostic: wire anchors on a pylon,
5
+ * muzzle/hand mounts on a character, hardpoints on a ship, seat/decal slots on furniture — anything
6
+ * an artist tags with an empty in the GLB. Pure data (no three.js import), so it lives in core.
7
+ *
8
+ * @capability model-sockets named attachment points read from a model
9
+ */
10
+ /** Minimal shape of a model node this reader walks — structurally satisfied by `THREE.Object3D`. */
11
+ export interface ModelNode {
12
+ name: string;
13
+ position: {
14
+ x: number;
15
+ y: number;
16
+ z: number;
17
+ };
18
+ children?: readonly ModelNode[];
19
+ }
20
+ /** One resolved socket: its node name and local-space offset from the model origin. */
21
+ export interface ModelSocket {
22
+ name: string;
23
+ offset: readonly [number, number, number];
24
+ }
25
+ /** Default socket-name matcher: "socket", "wire", "attach", "anchor", "mount", "hardpoint" (any case). */
26
+ export declare const SOCKET_PATTERN: RegExp;
27
+ /**
28
+ * Depth-first collect every socket-named node's local offset, sorted by descending Y then ascending X
29
+ * so socket indices are stable across loads (top first, left-to-right). Empty when the model tags
30
+ * none — callers then fall back to computed offsets. Pass a custom `pattern` for a bespoke naming
31
+ * convention.
32
+ */
33
+ export declare function readNamedSockets(root: ModelNode, pattern?: RegExp): ModelSocket[];
@@ -0,0 +1,29 @@
1
+ /**
2
+ * Generic named-socket reader for loaded 3D models. Walks a node tree (any object with `.name`,
3
+ * `.position`, and `.children` — structurally satisfied by `THREE.Object3D`) and collects the local
4
+ * offsets of nodes whose name marks an attachment point. Genre-agnostic: wire anchors on a pylon,
5
+ * muzzle/hand mounts on a character, hardpoints on a ship, seat/decal slots on furniture — anything
6
+ * an artist tags with an empty in the GLB. Pure data (no three.js import), so it lives in core.
7
+ *
8
+ * @capability model-sockets named attachment points read from a model
9
+ */
10
+ /** Default socket-name matcher: "socket", "wire", "attach", "anchor", "mount", "hardpoint" (any case). */
11
+ export const SOCKET_PATTERN = /socket|wire|attach|anchor|mount|hardpoint/i;
12
+ /**
13
+ * Depth-first collect every socket-named node's local offset, sorted by descending Y then ascending X
14
+ * so socket indices are stable across loads (top first, left-to-right). Empty when the model tags
15
+ * none — callers then fall back to computed offsets. Pass a custom `pattern` for a bespoke naming
16
+ * convention.
17
+ */
18
+ export function readNamedSockets(root, pattern = SOCKET_PATTERN) {
19
+ const found = [];
20
+ const walk = (node) => {
21
+ if (pattern.test(node.name))
22
+ found.push({ name: node.name, offset: [node.position.x, node.position.y, node.position.z] });
23
+ for (const child of node.children ?? [])
24
+ walk(child);
25
+ };
26
+ walk(root);
27
+ found.sort((a, b) => b.offset[1] - a.offset[1] || a.offset[0] - b.offset[0]);
28
+ return found;
29
+ }
@@ -24,6 +24,8 @@ declare function intersectAabb(origin: EntityPosition, direction: EntityPosition
24
24
  distance: number;
25
25
  normal: EntityPosition;
26
26
  } | null;
27
+ /** @internal */
27
28
  export declare function raycastObjects(source: ObjectRaycastSource, input: ObjectRaycastInput): ObjectRaycastHit | null;
29
+ /** @internal */
28
30
  export declare function raycastObjectsAll(source: ObjectRaycastSource, input: ObjectRaycastInput): ObjectRaycastHit[];
29
31
  export { intersectAabb, normalize as normalizeDirection };