@jgengine/core 0.10.0 → 0.11.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (607) hide show
  1. package/CHANGELOG.md +13 -2
  2. package/LICENSE +203 -661
  3. package/README.md +1 -1
  4. package/dist/ai/crowd.d.ts +55 -0
  5. package/dist/ai/crowd.js +114 -0
  6. package/dist/ai/flock.d.ts +5 -2
  7. package/dist/ai/flock.js +5 -2
  8. package/dist/ai/groupAssist.d.ts +1 -0
  9. package/dist/ai/groupAssist.js +1 -0
  10. package/dist/ai/heatSystem.d.ts +76 -0
  11. package/dist/ai/heatSystem.js +97 -0
  12. package/dist/ai/interestScheduler.d.ts +107 -0
  13. package/dist/ai/interestScheduler.js +118 -0
  14. package/dist/ai/jobBoard.d.ts +1 -0
  15. package/dist/ai/jobBoard.js +1 -0
  16. package/dist/ai/laneSelect.d.ts +5 -2
  17. package/dist/ai/laneSelect.js +5 -2
  18. package/dist/ai/mobBrain.d.ts +1 -0
  19. package/dist/ai/mobBrain.js +1 -0
  20. package/dist/ai/spawnDirector.d.ts +7 -2
  21. package/dist/ai/spawnDirector.js +18 -15
  22. package/dist/ai/spawnPoint.d.ts +3 -1
  23. package/dist/ai/spawnPoint.js +3 -1
  24. package/dist/ai/targetAcquisition.d.ts +84 -0
  25. package/dist/ai/targetAcquisition.js +92 -0
  26. package/dist/anim/easing.d.ts +19 -0
  27. package/dist/anim/easing.js +19 -0
  28. package/dist/anim/oscillator.d.ts +12 -0
  29. package/dist/anim/oscillator.js +25 -0
  30. package/dist/area/areaEffectField.d.ts +127 -0
  31. package/dist/area/areaEffectField.js +175 -0
  32. package/dist/area/stackPolicy.d.ts +47 -0
  33. package/dist/area/stackPolicy.js +99 -0
  34. package/dist/authoring.d.ts +1 -0
  35. package/dist/authoring.js +1 -0
  36. package/dist/board/laneBoard.d.ts +13 -0
  37. package/dist/board/laneBoard.js +13 -0
  38. package/dist/board/timelineBoard.d.ts +10 -0
  39. package/dist/board/timelineBoard.js +10 -0
  40. package/dist/combat/abilityKit.d.ts +18 -0
  41. package/dist/combat/abilityKit.js +24 -9
  42. package/dist/combat/animationState.d.ts +5 -0
  43. package/dist/combat/animationState.js +5 -0
  44. package/dist/combat/breakMeters.d.ts +10 -0
  45. package/dist/combat/breakMeters.js +10 -0
  46. package/dist/combat/castRunner.d.ts +5 -0
  47. package/dist/combat/castRunner.js +5 -0
  48. package/dist/combat/comboPoints.d.ts +5 -0
  49. package/dist/combat/comboPoints.js +5 -0
  50. package/dist/combat/comboString.d.ts +5 -0
  51. package/dist/combat/comboString.js +5 -0
  52. package/dist/combat/damageInterceptors.d.ts +192 -0
  53. package/dist/combat/damageInterceptors.js +251 -0
  54. package/dist/combat/damageMatchup.d.ts +68 -0
  55. package/dist/combat/damageMatchup.js +42 -0
  56. package/dist/combat/damageResolution.d.ts +63 -0
  57. package/dist/combat/damageResolution.js +50 -0
  58. package/dist/combat/death.d.ts +7 -1
  59. package/dist/combat/death.js +5 -0
  60. package/dist/combat/deathReason.d.ts +14 -0
  61. package/dist/combat/deathReason.js +1 -0
  62. package/dist/combat/defensiveWindow.d.ts +5 -0
  63. package/dist/combat/defensiveWindow.js +5 -0
  64. package/dist/combat/dotField.d.ts +5 -1
  65. package/dist/combat/dotField.js +5 -1
  66. package/dist/combat/downed.d.ts +5 -0
  67. package/dist/combat/downed.js +5 -0
  68. package/dist/combat/effects.d.ts +5 -0
  69. package/dist/combat/effects.js +5 -0
  70. package/dist/combat/encounterSequence.d.ts +258 -0
  71. package/dist/combat/encounterSequence.js +426 -0
  72. package/dist/combat/hitReaction.d.ts +57 -1
  73. package/dist/combat/hitReaction.js +45 -5
  74. package/dist/combat/magazine.d.ts +54 -0
  75. package/dist/combat/magazine.js +96 -0
  76. package/dist/combat/projectiles.d.ts +5 -0
  77. package/dist/combat/projectiles.js +32 -14
  78. package/dist/combat/receivedDamage.d.ts +117 -0
  79. package/dist/combat/receivedDamage.js +92 -0
  80. package/dist/combat/regenShield.d.ts +5 -1
  81. package/dist/combat/regenShield.js +5 -1
  82. package/dist/combat/renderCues.d.ts +51 -0
  83. package/dist/combat/renderCues.js +44 -0
  84. package/dist/combat/resourcePool.d.ts +5 -0
  85. package/dist/combat/resourcePool.js +5 -0
  86. package/dist/combat/rewardAllocation.d.ts +121 -0
  87. package/dist/combat/rewardAllocation.js +251 -0
  88. package/dist/combat/shotOrigin.d.ts +18 -1
  89. package/dist/combat/shotOrigin.js +39 -0
  90. package/dist/combat/statusApplication.d.ts +96 -0
  91. package/dist/combat/statusApplication.js +81 -0
  92. package/dist/combat/telegraph.d.ts +11 -2
  93. package/dist/combat/telegraph.js +11 -2
  94. package/dist/combat/thresholdCrossings.d.ts +85 -0
  95. package/dist/combat/thresholdCrossings.js +116 -0
  96. package/dist/combat.d.ts +34 -0
  97. package/dist/combat.js +34 -0
  98. package/dist/commands/commandRegistry.d.ts +11 -0
  99. package/dist/commands/commandRegistry.js +9 -2
  100. package/dist/crafting/crop.d.ts +18 -0
  101. package/dist/crafting/crop.js +18 -0
  102. package/dist/crafting/production.d.ts +5 -0
  103. package/dist/crafting/production.js +5 -0
  104. package/dist/devtools/rewriteTunables.d.ts +17 -0
  105. package/dist/devtools/rewriteTunables.js +276 -0
  106. package/dist/devtools/saveEndpoint.d.ts +46 -0
  107. package/dist/devtools/saveEndpoint.js +48 -0
  108. package/dist/devtools/transformTunables.d.ts +3 -0
  109. package/dist/devtools/transformTunables.js +3 -0
  110. package/dist/devtools/tunableSchema.d.ts +31 -0
  111. package/dist/devtools/tunableSchema.js +31 -0
  112. package/dist/economy/currency.d.ts +12 -1
  113. package/dist/economy/currency.js +12 -1
  114. package/dist/economy/listingBook.d.ts +91 -0
  115. package/dist/economy/listingBook.js +144 -0
  116. package/dist/economy/resourceLedger.d.ts +222 -0
  117. package/dist/economy/resourceLedger.js +353 -0
  118. package/dist/economy/sharedWallet.d.ts +14 -0
  119. package/dist/economy/sharedWallet.js +14 -0
  120. package/dist/economy/techTree.d.ts +12 -0
  121. package/dist/economy/techTree.js +12 -0
  122. package/dist/economy/wallet.d.ts +26 -2
  123. package/dist/economy/wallet.js +35 -6
  124. package/dist/editor/commands.d.ts +190 -7
  125. package/dist/editor/commands.js +727 -55
  126. package/dist/editor/document.d.ts +159 -13
  127. package/dist/editor/document.js +750 -19
  128. package/dist/editor/grid.d.ts +229 -0
  129. package/dist/editor/grid.js +366 -0
  130. package/dist/editor/gridAdapters.d.ts +80 -0
  131. package/dist/editor/gridAdapters.js +134 -0
  132. package/dist/editor/index.d.ts +73 -6
  133. package/dist/editor/index.js +6 -2
  134. package/dist/editor/liveSync.d.ts +127 -0
  135. package/dist/editor/liveSync.js +249 -0
  136. package/dist/editor/runtimeInspector.d.ts +88 -0
  137. package/dist/editor/runtimeInspector.js +239 -0
  138. package/dist/editor/types.d.ts +107 -1
  139. package/dist/faction/reputation.d.ts +5 -0
  140. package/dist/faction/reputation.js +5 -0
  141. package/dist/format/distance.d.ts +17 -0
  142. package/dist/format/distance.js +18 -0
  143. package/dist/format/duration.d.ts +27 -0
  144. package/dist/format/duration.js +45 -0
  145. package/dist/format/speed.d.ts +17 -0
  146. package/dist/format/speed.js +25 -0
  147. package/dist/game/connectedPlayers.d.ts +6 -4
  148. package/dist/game/connectedPlayers.js +2 -2
  149. package/dist/game/cosmetics.d.ts +9 -0
  150. package/dist/game/cosmetics.js +16 -0
  151. package/dist/game/defineGame.d.ts +100 -2
  152. package/dist/game/defineGame.js +39 -2
  153. package/dist/game/defineSystem.d.ts +88 -0
  154. package/dist/game/defineSystem.js +45 -0
  155. package/dist/game/dialogue.d.ts +33 -0
  156. package/dist/game/dialogue.js +21 -0
  157. package/dist/game/events.d.ts +35 -13
  158. package/dist/game/events.js +5 -0
  159. package/dist/game/feed.d.ts +33 -0
  160. package/dist/game/feed.js +35 -2
  161. package/dist/game/gamePhase.d.ts +11 -0
  162. package/dist/game/gamePhase.js +16 -0
  163. package/dist/game/leaderboard.d.ts +5 -0
  164. package/dist/game/leaderboard.js +5 -0
  165. package/dist/game/loadout.d.ts +5 -0
  166. package/dist/game/loadout.js +5 -0
  167. package/dist/game/lootFilter.d.ts +2 -0
  168. package/dist/game/lootFilter.js +2 -0
  169. package/dist/game/lootPipeline.d.ts +164 -0
  170. package/dist/game/lootPipeline.js +216 -0
  171. package/dist/game/lootTable.d.ts +19 -2
  172. package/dist/game/lootTable.js +15 -5
  173. package/dist/game/objectives.d.ts +43 -0
  174. package/dist/game/objectives.js +36 -0
  175. package/dist/game/paramLayers.d.ts +148 -0
  176. package/dist/game/paramLayers.js +185 -0
  177. package/dist/game/ping.d.ts +5 -0
  178. package/dist/game/ping.js +5 -0
  179. package/dist/game/playableGame.d.ts +92 -7
  180. package/dist/game/quest.d.ts +8 -0
  181. package/dist/game/quest.js +29 -0
  182. package/dist/game/race.d.ts +141 -0
  183. package/dist/game/race.js +169 -0
  184. package/dist/game/recordBook.d.ts +3 -1
  185. package/dist/game/recordBook.js +4 -1
  186. package/dist/game/ruleSelection.d.ts +75 -0
  187. package/dist/game/ruleSelection.js +127 -0
  188. package/dist/game/runDraft.d.ts +5 -0
  189. package/dist/game/runDraft.js +5 -0
  190. package/dist/game/saveStore.d.ts +111 -0
  191. package/dist/game/saveStore.js +312 -0
  192. package/dist/game/snapshotHistory.d.ts +67 -0
  193. package/dist/game/snapshotHistory.js +95 -0
  194. package/dist/game/social.d.ts +38 -1
  195. package/dist/game/social.js +71 -0
  196. package/dist/game/spawnPoints.d.ts +5 -0
  197. package/dist/game/spawnPoints.js +5 -0
  198. package/dist/game/systemRuntime.d.ts +50 -0
  199. package/dist/game/systemRuntime.js +157 -0
  200. package/dist/game/systemSchedule.d.ts +72 -0
  201. package/dist/game/systemSchedule.js +242 -0
  202. package/dist/game/toasts.d.ts +43 -0
  203. package/dist/game/toasts.js +44 -0
  204. package/dist/game/trade.d.ts +10 -0
  205. package/dist/game/trade.js +10 -0
  206. package/dist/game/unlocks.d.ts +8 -0
  207. package/dist/game/unlocks.js +16 -0
  208. package/dist/game/vfxInstance.d.ts +138 -0
  209. package/dist/game/vfxInstance.js +96 -0
  210. package/dist/game/worldItem.d.ts +17 -4
  211. package/dist/game/worldItem.js +17 -4
  212. package/dist/gameplay.d.ts +91 -0
  213. package/dist/gameplay.js +91 -0
  214. package/dist/index.d.ts +5 -14
  215. package/dist/index.js +5 -14
  216. package/dist/input/actionBindings.d.ts +23 -6
  217. package/dist/input/actionBindings.js +23 -6
  218. package/dist/input/axisInput.d.ts +7 -2
  219. package/dist/input/axisInput.js +7 -2
  220. package/dist/input/controlGroups.d.ts +67 -0
  221. package/dist/input/controlGroups.js +41 -0
  222. package/dist/input/touchScheme.d.ts +82 -6
  223. package/dist/input/touchScheme.js +123 -10
  224. package/dist/interaction/lockpick.d.ts +61 -0
  225. package/dist/interaction/lockpick.js +168 -0
  226. package/dist/interaction/proximityPrompt.d.ts +2 -0
  227. package/dist/interaction/proximityPrompt.js +2 -0
  228. package/dist/interaction/qte.d.ts +5 -0
  229. package/dist/interaction/qte.js +5 -0
  230. package/dist/interaction/skillCheck.d.ts +5 -0
  231. package/dist/interaction/skillCheck.js +5 -0
  232. package/dist/inventory/inventoryModel.d.ts +12 -0
  233. package/dist/inventory/inventoryModel.js +12 -0
  234. package/dist/inventory/shapedGrid.d.ts +16 -0
  235. package/dist/inventory/shapedGrid.js +16 -0
  236. package/dist/inventory/slotModel.d.ts +10 -0
  237. package/dist/inventory/slotModel.js +10 -0
  238. package/dist/item/durability.d.ts +5 -0
  239. package/dist/item/durability.js +5 -0
  240. package/dist/item/itemIdentity.d.ts +171 -0
  241. package/dist/item/itemIdentity.js +138 -0
  242. package/dist/item/itemInstanceRegistry.d.ts +32 -0
  243. package/dist/item/itemInstanceRegistry.js +34 -0
  244. package/dist/item/itemgen.d.ts +163 -0
  245. package/dist/item/itemgen.js +151 -0
  246. package/dist/item/modularItem.d.ts +5 -0
  247. package/dist/item/modularItem.js +5 -0
  248. package/dist/item/use.d.ts +5 -0
  249. package/dist/item/use.js +5 -0
  250. package/dist/item/useBehavior.d.ts +142 -0
  251. package/dist/item/useBehavior.js +105 -0
  252. package/dist/item/weapon.d.ts +5 -0
  253. package/dist/item/weapon.js +5 -0
  254. package/dist/math/scalar.d.ts +25 -0
  255. package/dist/math/scalar.js +47 -0
  256. package/dist/meta/changelog.d.ts +4 -1
  257. package/dist/meta/changelog.js +16 -2
  258. package/dist/movement/avoidance.d.ts +45 -0
  259. package/dist/movement/avoidance.js +123 -0
  260. package/dist/movement/cameraRig.d.ts +8 -0
  261. package/dist/movement/cameraRig.js +8 -0
  262. package/dist/movement/dash.d.ts +11 -0
  263. package/dist/movement/dash.js +11 -0
  264. package/dist/movement/formation.d.ts +135 -0
  265. package/dist/movement/formation.js +194 -0
  266. package/dist/movement/glideModel.d.ts +5 -0
  267. package/dist/movement/glideModel.js +5 -0
  268. package/dist/movement/grappleSwing.d.ts +5 -0
  269. package/dist/movement/grappleSwing.js +5 -0
  270. package/dist/movement/leaderTrail.d.ts +5 -0
  271. package/dist/movement/leaderTrail.js +5 -0
  272. package/dist/movement/movementModel.d.ts +35 -8
  273. package/dist/movement/movementModel.js +42 -14
  274. package/dist/movement/playerMovement.js +65 -10
  275. package/dist/movement/poseState.d.ts +13 -0
  276. package/dist/movement/poseState.js +16 -0
  277. package/dist/movement/steering.d.ts +8 -0
  278. package/dist/movement/steering.js +18 -0
  279. package/dist/multiplayer/combatSnapshot.d.ts +3 -0
  280. package/dist/multiplayer/combatSnapshot.js +3 -0
  281. package/dist/multiplayer/lagCompensation.d.ts +5 -0
  282. package/dist/multiplayer/lagCompensation.js +5 -0
  283. package/dist/multiplayer/presenceModel.d.ts +9 -1
  284. package/dist/multiplayer/presenceModel.js +9 -1
  285. package/dist/multiplayer/simultaneousCommit.d.ts +3 -0
  286. package/dist/multiplayer/simultaneousCommit.js +3 -0
  287. package/dist/multiplayer.d.ts +11 -0
  288. package/dist/multiplayer.js +11 -0
  289. package/dist/nav/pathFollow.d.ts +57 -0
  290. package/dist/nav/pathFollow.js +109 -0
  291. package/dist/orders/orderKinds.d.ts +156 -0
  292. package/dist/orders/orderKinds.js +197 -0
  293. package/dist/orders/orderQueue.d.ts +208 -0
  294. package/dist/orders/orderQueue.js +211 -0
  295. package/dist/physics/drivableVehicle.d.ts +29 -0
  296. package/dist/physics/drivableVehicle.js +16 -0
  297. package/dist/physics/kinematicVehicle.d.ts +21 -1
  298. package/dist/physics/kinematicVehicle.js +23 -8
  299. package/dist/physics/physicsWorld.d.ts +24 -12
  300. package/dist/physics/physicsWorld.js +11 -5
  301. package/dist/physics/radialImpulse.d.ts +25 -0
  302. package/dist/physics/radialImpulse.js +27 -0
  303. package/dist/procedural.d.ts +3 -0
  304. package/dist/procedural.js +3 -0
  305. package/dist/progression/statGraph.d.ts +116 -0
  306. package/dist/progression/statGraph.js +318 -0
  307. package/dist/puzzle/cellGrid.d.ts +9 -0
  308. package/dist/puzzle/cellGrid.js +9 -0
  309. package/dist/puzzle/fallingPiece.d.ts +9 -0
  310. package/dist/puzzle/fallingPiece.js +9 -0
  311. package/dist/puzzle/nonogram.d.ts +39 -0
  312. package/dist/puzzle/nonogram.js +136 -0
  313. package/dist/random/nameGen.d.ts +5 -0
  314. package/dist/random/nameGen.js +5 -0
  315. package/dist/random/pick.d.ts +8 -0
  316. package/dist/random/pick.js +31 -0
  317. package/dist/random/rng.d.ts +22 -0
  318. package/dist/random/rng.js +28 -8
  319. package/dist/random/seedLink.d.ts +4 -0
  320. package/dist/random/seedLink.js +4 -0
  321. package/dist/relation/keyedValues.d.ts +54 -0
  322. package/dist/relation/keyedValues.js +115 -0
  323. package/dist/relation/thresholds.d.ts +62 -0
  324. package/dist/relation/thresholds.js +62 -0
  325. package/dist/render/color.d.ts +12 -0
  326. package/dist/render/color.js +26 -0
  327. package/dist/render/lookPreset.d.ts +41 -0
  328. package/dist/render/lookPreset.js +29 -0
  329. package/dist/render/postProcessing.d.ts +20 -0
  330. package/dist/render/postProcessing.js +21 -1
  331. package/dist/rules/predicate.d.ts +53 -0
  332. package/dist/rules/predicate.js +64 -0
  333. package/dist/rules/ruleEffects.d.ts +38 -0
  334. package/dist/rules/ruleEffects.js +37 -0
  335. package/dist/rules/triggeredRules.d.ts +160 -0
  336. package/dist/rules/triggeredRules.js +241 -0
  337. package/dist/runtime/adapter.d.ts +42 -3
  338. package/dist/runtime/adapter.js +44 -1
  339. package/dist/runtime/cameraDirector.d.ts +1 -0
  340. package/dist/runtime/cameraDirector.js +1 -0
  341. package/dist/runtime/commandRunner.d.ts +1 -0
  342. package/dist/runtime/commandRunner.js +1 -0
  343. package/dist/runtime/context/combatFx.d.ts +23 -0
  344. package/dist/runtime/context/combatFx.js +161 -0
  345. package/dist/runtime/context/registries.d.ts +13 -0
  346. package/dist/runtime/context/registries.js +84 -0
  347. package/dist/runtime/context/worldItems.d.ts +21 -0
  348. package/dist/runtime/context/worldItems.js +37 -0
  349. package/dist/runtime/descriptors/baseline.d.ts +48 -0
  350. package/dist/runtime/descriptors/baseline.js +134 -0
  351. package/dist/runtime/descriptors/features.d.ts +74 -0
  352. package/dist/runtime/descriptors/features.js +281 -0
  353. package/dist/runtime/gameContext.d.ts +114 -13
  354. package/dist/runtime/gameContext.js +303 -395
  355. package/dist/runtime/gameRuntime.d.ts +1 -0
  356. package/dist/runtime/gameRuntime.js +1 -0
  357. package/dist/runtime/headlessRunner.d.ts +60 -0
  358. package/dist/runtime/headlessRunner.js +44 -0
  359. package/dist/runtime/hostPersistence.d.ts +12 -0
  360. package/dist/runtime/hostPersistence.js +12 -0
  361. package/dist/runtime/hostedGameRunner.d.ts +8 -3
  362. package/dist/runtime/hostedGameRunner.js +26 -3
  363. package/dist/runtime/hostedWorldSession.d.ts +12 -4
  364. package/dist/runtime/hostedWorldSession.js +11 -4
  365. package/dist/runtime/inputSnapshot.d.ts +8 -3
  366. package/dist/runtime/inputSnapshot.js +6 -2
  367. package/dist/runtime/motionIntents.d.ts +11 -2
  368. package/dist/runtime/motionIntents.js +16 -2
  369. package/dist/runtime/perContext.d.ts +15 -0
  370. package/dist/runtime/perContext.js +21 -0
  371. package/dist/runtime/runtimeSave.d.ts +79 -0
  372. package/dist/runtime/runtimeSave.js +105 -0
  373. package/dist/runtime/save.d.ts +4 -0
  374. package/dist/runtime/save.js +4 -0
  375. package/dist/runtime/snapshot.d.ts +7 -0
  376. package/dist/runtime/snapshot.js +7 -0
  377. package/dist/runtime/visibility.d.ts +2 -1
  378. package/dist/runtime/visibility.js +2 -1
  379. package/dist/runtime/worldChannel.d.ts +7 -3
  380. package/dist/runtime/worldChannel.js +51 -6
  381. package/dist/runtime/worldMirror.d.ts +14 -2
  382. package/dist/runtime/worldMirror.js +15 -2
  383. package/dist/runtime/worldProjection.d.ts +47 -0
  384. package/dist/runtime/worldProjection.js +52 -0
  385. package/dist/runtime/worldReplication.d.ts +30 -7
  386. package/dist/runtime/worldReplication.js +41 -9
  387. package/dist/runtime/worldSnapshot.d.ts +30 -3
  388. package/dist/runtime/worldSnapshot.js +20 -5
  389. package/dist/scene/assetCatalog.d.ts +21 -0
  390. package/dist/scene/assetCatalog.js +4 -0
  391. package/dist/scene/assetDiagnostics.d.ts +69 -0
  392. package/dist/scene/assetDiagnostics.js +110 -0
  393. package/dist/scene/assetGenerator.d.ts +65 -0
  394. package/dist/scene/assetGenerator.js +64 -0
  395. package/dist/scene/assetSpace.d.ts +137 -0
  396. package/dist/scene/assetSpace.js +259 -0
  397. package/dist/scene/authoredTriggers.d.ts +169 -0
  398. package/dist/scene/authoredTriggers.js +340 -0
  399. package/dist/scene/behaviorRuntime.d.ts +75 -0
  400. package/dist/scene/behaviorRuntime.js +217 -0
  401. package/dist/scene/behaviors.d.ts +14 -2
  402. package/dist/scene/behaviors.js +7 -2
  403. package/dist/scene/bodyBind.d.ts +60 -0
  404. package/dist/scene/bodyBind.js +51 -0
  405. package/dist/scene/builtinSceneKinds.d.ts +5 -0
  406. package/dist/scene/builtinSceneKinds.js +62 -0
  407. package/dist/scene/colliders.d.ts +13 -1
  408. package/dist/scene/colliders.js +37 -1
  409. package/dist/scene/entityStats.d.ts +11 -2
  410. package/dist/scene/entityStats.js +11 -2
  411. package/dist/scene/entityStore.d.ts +12 -1
  412. package/dist/scene/entityStore.js +15 -0
  413. package/dist/scene/facing.d.ts +18 -0
  414. package/dist/scene/facing.js +26 -0
  415. package/dist/scene/modelSockets.d.ts +33 -0
  416. package/dist/scene/modelSockets.js +29 -0
  417. package/dist/scene/objectQuery.d.ts +2 -0
  418. package/dist/scene/objectQuery.js +2 -0
  419. package/dist/scene/objectStore.d.ts +4 -0
  420. package/dist/scene/objectStore.js +6 -0
  421. package/dist/scene/possession.d.ts +8 -0
  422. package/dist/scene/possession.js +14 -0
  423. package/dist/scene/roster.d.ts +3 -0
  424. package/dist/scene/roster.js +12 -0
  425. package/dist/scene/sceneKinds.d.ts +240 -0
  426. package/dist/scene/sceneKinds.js +214 -0
  427. package/dist/scene/sceneOwnership.d.ts +169 -0
  428. package/dist/scene/sceneOwnership.js +179 -0
  429. package/dist/scene/selectionBookmarks.d.ts +93 -0
  430. package/dist/scene/selectionBookmarks.js +122 -0
  431. package/dist/scene/vehicleSeat.d.ts +68 -0
  432. package/dist/scene/vehicleSeat.js +59 -0
  433. package/dist/sensor/concealment.d.ts +3 -0
  434. package/dist/sensor/concealment.js +3 -0
  435. package/dist/sensor/freezeMonitor.d.ts +1 -0
  436. package/dist/sensor/freezeMonitor.js +1 -0
  437. package/dist/sensor/frustumSensor.d.ts +7 -3
  438. package/dist/sensor/frustumSensor.js +7 -3
  439. package/dist/sensor/hiddenStateProbe.d.ts +5 -2
  440. package/dist/sensor/hiddenStateProbe.js +5 -2
  441. package/dist/sensor/recordingBuffer.d.ts +2 -1
  442. package/dist/sensor/recordingBuffer.js +2 -1
  443. package/dist/sensor/replayLoop.d.ts +6 -2
  444. package/dist/sensor/replayLoop.js +6 -2
  445. package/dist/sensor/revealQuery.d.ts +2 -1
  446. package/dist/sensor/revealQuery.js +2 -1
  447. package/dist/sensor/visionCone.d.ts +10 -3
  448. package/dist/sensor/visionCone.js +10 -3
  449. package/dist/session/contestedChannel.d.ts +1 -0
  450. package/dist/session/contestedChannel.js +1 -0
  451. package/dist/session/extraction.d.ts +1 -0
  452. package/dist/session/extraction.js +1 -0
  453. package/dist/session/roles.d.ts +6 -0
  454. package/dist/session/roles.js +6 -0
  455. package/dist/session/roundState.d.ts +8 -0
  456. package/dist/session/roundState.js +2 -0
  457. package/dist/settings/settingsModel.d.ts +1 -0
  458. package/dist/settings/settingsModel.js +1 -0
  459. package/dist/stats/accumulatorMeter.d.ts +6 -0
  460. package/dist/stats/accumulatorMeter.js +6 -0
  461. package/dist/stats/eventMeter.d.ts +5 -0
  462. package/dist/stats/eventMeter.js +5 -0
  463. package/dist/stats/rollCheck.d.ts +5 -0
  464. package/dist/stats/rollCheck.js +5 -0
  465. package/dist/stats/statModifiers.d.ts +5 -0
  466. package/dist/stats/statModifiers.js +5 -0
  467. package/dist/store/defineKeyedStore.d.ts +38 -0
  468. package/dist/store/defineKeyedStore.js +42 -0
  469. package/dist/store/defineStore.d.ts +33 -0
  470. package/dist/store/defineStore.js +35 -0
  471. package/dist/store/observableKeyedStore.d.ts +5 -0
  472. package/dist/store/observableKeyedStore.js +34 -2
  473. package/dist/survival/decayMeter.d.ts +55 -0
  474. package/dist/survival/decayMeter.js +130 -55
  475. package/dist/survival/moodle.d.ts +2 -0
  476. package/dist/survival/regionHealth.d.ts +6 -0
  477. package/dist/survival/regionHealth.js +5 -0
  478. package/dist/tactics/fallingGrid.d.ts +4 -2
  479. package/dist/tactics/fallingGrid.js +4 -2
  480. package/dist/tactics/predictiveQuery.d.ts +3 -0
  481. package/dist/tactics/predictiveQuery.js +3 -0
  482. package/dist/tactics/snapshot.d.ts +2 -0
  483. package/dist/tactics/snapshot.js +2 -0
  484. package/dist/tactics/surface.d.ts +1 -0
  485. package/dist/tactics/surface.js +1 -0
  486. package/dist/tactics/tacticalGrid.d.ts +1 -0
  487. package/dist/tactics/tacticalGrid.js +1 -0
  488. package/dist/time/beatClock.d.ts +14 -4
  489. package/dist/time/beatClock.js +14 -4
  490. package/dist/time/calendarClock.d.ts +3 -0
  491. package/dist/time/calendarClock.js +3 -0
  492. package/dist/time/idleProgress.d.ts +4 -0
  493. package/dist/time/idleProgress.js +4 -0
  494. package/dist/time/simClock.d.ts +2 -0
  495. package/dist/time/simClock.js +20 -5
  496. package/dist/ui/actionModel.d.ts +110 -0
  497. package/dist/ui/actionModel.js +159 -0
  498. package/dist/ui/gameLayout.d.ts +30 -11
  499. package/dist/ui/gameLayout.js +30 -11
  500. package/dist/ui/hudDocument.d.ts +114 -0
  501. package/dist/ui/hudDocument.js +220 -0
  502. package/dist/ui/hudLayout.d.ts +33 -1
  503. package/dist/ui/hudLayout.js +204 -17
  504. package/dist/ui/selectionModel.d.ts +92 -0
  505. package/dist/ui/selectionModel.js +88 -0
  506. package/dist/ui/tooltipModel.d.ts +63 -0
  507. package/dist/ui/tooltipModel.js +82 -0
  508. package/dist/ui.d.ts +15 -0
  509. package/dist/ui.js +15 -0
  510. package/dist/visibility/bounds.d.ts +8 -1
  511. package/dist/visibility/bounds.js +8 -1
  512. package/dist/visibility/frustum.d.ts +12 -3
  513. package/dist/visibility/frustum.js +12 -3
  514. package/dist/work/jobQueue.d.ts +201 -0
  515. package/dist/work/jobQueue.js +253 -0
  516. package/dist/work/unitTraining.d.ts +58 -0
  517. package/dist/work/unitTraining.js +52 -0
  518. package/dist/world/authoredObjects.d.ts +58 -0
  519. package/dist/world/authoredObjects.js +69 -0
  520. package/dist/world/buildingGenerator.d.ts +18 -0
  521. package/dist/world/buildingGenerator.js +62 -0
  522. package/dist/world/buildings.d.ts +5 -0
  523. package/dist/world/buildings.js +5 -0
  524. package/dist/world/catenary.d.ts +22 -0
  525. package/dist/world/catenary.js +69 -0
  526. package/dist/world/features.d.ts +115 -7
  527. package/dist/world/features.js +56 -5
  528. package/dist/world/footprintGrid.d.ts +59 -0
  529. package/dist/world/footprintGrid.js +141 -0
  530. package/dist/world/geometry.d.ts +64 -0
  531. package/dist/world/geometry.js +94 -0
  532. package/dist/world/grassKind.d.ts +51 -0
  533. package/dist/world/grassKind.js +101 -0
  534. package/dist/world/pathInstances.d.ts +27 -0
  535. package/dist/world/pathInstances.js +27 -0
  536. package/dist/world/pathTerrain.d.ts +80 -0
  537. package/dist/world/pathTerrain.js +142 -0
  538. package/dist/world/placeAsset.d.ts +81 -0
  539. package/dist/world/placeAsset.js +77 -0
  540. package/dist/world/placement.d.ts +4 -0
  541. package/dist/world/placement.js +4 -0
  542. package/dist/world/placementController.d.ts +6 -0
  543. package/dist/world/placementController.js +6 -0
  544. package/dist/world/polyline.d.ts +34 -0
  545. package/dist/world/polyline.js +81 -0
  546. package/dist/world/roads.d.ts +8 -0
  547. package/dist/world/roads.js +38 -0
  548. package/dist/world/scatterRegion.d.ts +164 -0
  549. package/dist/world/scatterRegion.js +409 -0
  550. package/dist/world/sceneShapes.d.ts +43 -0
  551. package/dist/world/sceneShapes.js +1 -0
  552. package/dist/world/segment.d.ts +27 -0
  553. package/dist/world/segment.js +43 -0
  554. package/dist/world/soilKind.d.ts +48 -0
  555. package/dist/world/soilKind.js +92 -0
  556. package/dist/world/spatialSample.d.ts +241 -0
  557. package/dist/world/spatialSample.js +465 -0
  558. package/dist/world/terraform.d.ts +213 -1
  559. package/dist/world/terraform.js +655 -20
  560. package/dist/world/terrain.d.ts +119 -20
  561. package/dist/world/terrain.js +247 -41
  562. package/dist/world/terrainGuides.d.ts +182 -0
  563. package/dist/world/terrainGuides.js +343 -0
  564. package/dist/world/vec2.d.ts +81 -0
  565. package/dist/world/vec2.js +128 -0
  566. package/dist/world/vec3.d.ts +49 -0
  567. package/dist/world/vec3.js +76 -0
  568. package/dist/world/vegetation.d.ts +71 -0
  569. package/dist/world/vegetation.js +151 -0
  570. package/dist/world/visibilityField.d.ts +154 -0
  571. package/dist/world/visibilityField.js +271 -0
  572. package/dist/world/volumetricClouds.d.ts +52 -0
  573. package/dist/world/volumetricClouds.js +43 -0
  574. package/dist/world/walls.d.ts +9 -0
  575. package/dist/world/walls.js +9 -0
  576. package/dist/world/waterKind.d.ts +55 -0
  577. package/dist/world/waterKind.js +99 -0
  578. package/dist/world.d.ts +132 -0
  579. package/dist/world.js +132 -0
  580. package/package.json +32 -8
  581. package/skills/jgengine/SKILL.md +51 -0
  582. package/skills/jgengine/api.md +434 -0
  583. package/skills/jgengine/capabilities.md +29 -0
  584. package/skills/jgengine/reference-cartridge.md +72 -0
  585. package/skills/jgengine-combat/SKILL.md +34 -0
  586. package/skills/jgengine-combat/api.md +549 -0
  587. package/skills/jgengine-combat/capabilities.md +169 -0
  588. package/skills/jgengine-combat/reference.md +98 -0
  589. package/skills/jgengine-gameplay/SKILL.md +39 -0
  590. package/skills/jgengine-gameplay/api.md +1794 -0
  591. package/skills/jgengine-gameplay/capabilities.md +378 -0
  592. package/skills/jgengine-gameplay/reference-systems.md +60 -0
  593. package/skills/jgengine-world/SKILL.md +38 -0
  594. package/skills/jgengine-world/api.md +2652 -0
  595. package/skills/jgengine-world/capabilities.md +370 -0
  596. package/skills/jgengine-world/reference.md +222 -0
  597. package/dist/cartridge/runtime.d.ts +0 -15
  598. package/dist/cartridge/runtime.js +0 -556
  599. package/dist/cartridge/spec.d.ts +0 -188
  600. package/dist/cartridge/spec.js +0 -19
  601. package/dist/cartridge/validate.d.ts +0 -2
  602. package/dist/cartridge/validate.js +0 -78
  603. package/dist/store/engineStore.d.ts +0 -22
  604. package/dist/store/engineStore.js +0 -50
  605. package/dist/store/features.d.ts +0 -10
  606. package/dist/store/features.js +0 -23
  607. package/llms.txt +0 -5389
@@ -0,0 +1,69 @@
1
+ function metaString(meta, key) {
2
+ const value = meta?.[key];
3
+ return typeof value === "string" && value.length > 0 ? value : null;
4
+ }
5
+ function metaNumber(meta, key) {
6
+ const value = meta?.[key];
7
+ return typeof value === "number" && Number.isFinite(value) ? value : null;
8
+ }
9
+ /**
10
+ * Catalog id for a marker: first-class `catalogId` field, else `meta.catalogId` migration alias.
11
+ * Returns null when the marker is not an authored catalog prop (spawn, mob, generator, …).
12
+ * @capability authored-objects place catalog mesh props from an editor document
13
+ */
14
+ export function markerCatalogId(marker) {
15
+ if (typeof marker.catalogId === "string" && marker.catalogId.length > 0)
16
+ return marker.catalogId;
17
+ return metaString(marker.meta, "catalogId");
18
+ }
19
+ function markerVerticalOffset(marker) {
20
+ const fromMeta = metaNumber(marker.meta, "verticalOffset") ??
21
+ metaNumber(marker.meta, "offsetY") ??
22
+ metaNumber(marker.meta, "yOffset");
23
+ return fromMeta ?? 0;
24
+ }
25
+ /**
26
+ * Every marker carrying a catalog id, as placeable props — pure, no terrain sample. Parallel to
27
+ * {@link resolveScatter}: games and headless tests read the same list `<AuthoredObjects>` places.
28
+ * @capability authored-objects place catalog mesh props from an editor document
29
+ */
30
+ export function resolveAuthoredObjects(document) {
31
+ const out = [];
32
+ for (const marker of document.markers) {
33
+ const catalogId = markerCatalogId(marker);
34
+ if (catalogId === null)
35
+ continue;
36
+ out.push({
37
+ catalogId,
38
+ x: marker.position.x,
39
+ z: marker.position.z,
40
+ rotationY: marker.rotationY ?? 0,
41
+ instanceId: marker.id,
42
+ verticalOffset: markerVerticalOffset(marker),
43
+ });
44
+ }
45
+ return out;
46
+ }
47
+ /**
48
+ * Places resolved authored objects into an object store, grounding each on `sampleHeight(x,z)` plus
49
+ * per-object and options vertical offsets. Returns the instance ids that were placed (or kept).
50
+ * @capability authored-objects place catalog mesh props from an editor document
51
+ */
52
+ export function placeAuthoredObjects(store, objects, sampleHeight, options = {}) {
53
+ const lift = options.verticalOffset ?? 0;
54
+ const onExisting = options.onExisting;
55
+ const ids = [];
56
+ for (const object of objects) {
57
+ const y = sampleHeight(object.x, object.z) + object.verticalOffset + lift;
58
+ ids.push(store.place(object.catalogId, object.x, y, object.z, {
59
+ instanceId: object.instanceId,
60
+ rotation: object.rotationY,
61
+ ...(onExisting === undefined ? {} : { onExisting }),
62
+ }));
63
+ }
64
+ return ids;
65
+ }
66
+ /** Convenience: resolve a document then place every authored catalog prop. */
67
+ export function placeAuthoredObjectsFromDocument(store, document, sampleHeight, options = {}) {
68
+ return placeAuthoredObjects(store, resolveAuthoredObjects(document), sampleHeight, options);
69
+ }
@@ -0,0 +1,18 @@
1
+ /**
2
+ * The building generator registered against the {@link registerAssetGenerator} seam — the one engine
3
+ * adopter, proving the seeded config→parts building generator ({@link generateBuilding}) drops into
4
+ * the parametric-asset catalog with a slider schema and nothing bespoke. Domain generators (bookcase,
5
+ * …) register the same way from example/game code.
6
+ *
7
+ * @capability building-generator seeded building as a placeable parametric asset
8
+ */
9
+ import { type GeneratedAsset } from "../scene/assetGenerator.js";
10
+ import type { ParamSchema, ParsedParams } from "../scene/sceneKinds.js";
11
+ /** The generator id a catalog entry / placed marker references. */
12
+ export declare const BUILDING_GENERATOR_ID = "building";
13
+ /** The building generator's slider schema — drives the inspector via #809. */
14
+ export declare const BUILDING_GENERATOR_SCHEMA: ParamSchema;
15
+ /** Generate a building's parts from validated params + seed — the {@link registerAssetGenerator} hook. @internal */
16
+ export declare function generateBuildingAsset(params: ParsedParams, seed: string): GeneratedAsset;
17
+ /** Register the building generator asset. Called by {@link registerBuiltinSceneKinds}. @internal */
18
+ export declare function registerBuildingGenerator(): void;
@@ -0,0 +1,62 @@
1
+ /**
2
+ * The building generator registered against the {@link registerAssetGenerator} seam — the one engine
3
+ * adopter, proving the seeded config→parts building generator ({@link generateBuilding}) drops into
4
+ * the parametric-asset catalog with a slider schema and nothing bespoke. Domain generators (bookcase,
5
+ * …) register the same way from example/game code.
6
+ *
7
+ * @capability building-generator seeded building as a placeable parametric asset
8
+ */
9
+ import { registerAssetGenerator, partsBounds } from "../scene/assetGenerator.js";
10
+ import { BUILDING_STYLE_PALETTES, DEFAULT_BUILDING_CONFIG, generateBuilding, resolveBuildingPalette } from "./buildings.js";
11
+ /** The generator id a catalog entry / placed marker references. */
12
+ export const BUILDING_GENERATOR_ID = "building";
13
+ /** The building generator's slider schema — drives the inspector via #809. */
14
+ export const BUILDING_GENERATOR_SCHEMA = {
15
+ fields: [
16
+ { type: "range", key: "floors", label: "floors", min: 1, max: 20, step: 1, default: DEFAULT_BUILDING_CONFIG.floors },
17
+ { type: "range", key: "baysWide", label: "bays wide", min: 1, max: 12, step: 1, default: DEFAULT_BUILDING_CONFIG.baysWide },
18
+ { type: "range", key: "baysDeep", label: "bays deep", min: 1, max: 12, step: 1, default: DEFAULT_BUILDING_CONFIG.baysDeep },
19
+ { type: "range", key: "bayWidth", label: "bay width", min: 1, max: 5, step: 0.1, default: DEFAULT_BUILDING_CONFIG.bayWidth, unit: "m" },
20
+ { type: "range", key: "floorHeight", label: "floor height", min: 2, max: 5, step: 0.1, default: DEFAULT_BUILDING_CONFIG.floorHeight, unit: "m" },
21
+ {
22
+ type: "select",
23
+ key: "style",
24
+ label: "style",
25
+ default: "generic",
26
+ options: Object.keys(BUILDING_STYLE_PALETTES).map((style) => ({ value: style })),
27
+ },
28
+ { type: "seed", key: "seed", label: "seed", default: "" },
29
+ ],
30
+ };
31
+ /** Generate a building's parts from validated params + seed — the {@link registerAssetGenerator} hook. @internal */
32
+ export function generateBuildingAsset(params, seed) {
33
+ const style = params["style"];
34
+ const palette = resolveBuildingPalette(style);
35
+ const building = generateBuilding({
36
+ seed,
37
+ center: [0, 0],
38
+ floors: params["floors"],
39
+ baysWide: params["baysWide"],
40
+ baysDeep: params["baysDeep"],
41
+ bayWidth: params["bayWidth"],
42
+ floorHeight: params["floorHeight"],
43
+ });
44
+ const parts = building.parts.map((part) => ({
45
+ id: part.id,
46
+ kind: part.kind,
47
+ position: part.position,
48
+ size: part.scale,
49
+ rotationY: part.rotationY,
50
+ color: palette[part.kind],
51
+ }));
52
+ return { parts, bounds: partsBounds(parts) };
53
+ }
54
+ /** Register the building generator asset. Called by {@link registerBuiltinSceneKinds}. @internal */
55
+ export function registerBuildingGenerator() {
56
+ registerAssetGenerator({
57
+ id: BUILDING_GENERATOR_ID,
58
+ label: "Building",
59
+ schema: BUILDING_GENERATOR_SCHEMA,
60
+ generate: generateBuildingAsset,
61
+ });
62
+ }
@@ -97,8 +97,13 @@ export type BuildingPaletteOverrides = Partial<BuildingPalette>;
97
97
  export type BuildingStyle = "generic" | "capital" | "village" | "desert" | "industrial" | "coastal" | "neon" | "ruin" | "frontier" | "aerial";
98
98
  export declare const DEFAULT_BUILDING_STYLE: BuildingStyle;
99
99
  export declare const BUILDING_STYLE_PALETTES: Record<BuildingStyle, BuildingPalette>;
100
+ /** @internal */
100
101
  export declare function resolveBuildingPalette(style?: BuildingStyle, overrides?: BuildingPaletteOverrides): BuildingPalette;
102
+ /** @internal */
101
103
  export declare function createBuildingConfig(input?: BuildingConfigInput): BuildingConfig;
104
+ /** @internal */
102
105
  export declare function generateBuilding(input?: BuildingConfigInput): GeneratedBuilding;
106
+ /** @internal */
103
107
  export declare function createBuildingGrid(config: BuildingGridConfig): BuildingLot[];
108
+ /** @internal */
104
109
  export declare function generateBuildingDistrict(config: BuildingGridConfig): GeneratedBuilding[];
@@ -176,6 +176,7 @@ export const BUILDING_STYLE_PALETTES = {
176
176
  corner: "#c3d0d7",
177
177
  },
178
178
  };
179
+ /** @internal */
179
180
  export function resolveBuildingPalette(style = DEFAULT_BUILDING_STYLE, overrides) {
180
181
  const preset = BUILDING_STYLE_PALETTES[style];
181
182
  if (preset === undefined) {
@@ -228,6 +229,7 @@ function rangeInt(seed, key, min, max) {
228
229
  const hi = Math.max(min, max);
229
230
  return lo + Math.floor(hash01(seed, key) * (hi - lo + 1));
230
231
  }
232
+ /** @internal */
231
233
  export function createBuildingConfig(input = {}) {
232
234
  return {
233
235
  id: input.id ?? DEFAULT_BUILDING_CONFIG.id,
@@ -406,6 +408,7 @@ function pushCorners(parts, config, width, depth) {
406
408
  parts.push(part(config, "corner", index < 2 ? "back" : "front", position, [config.facadeDepth * 1.35, height, config.facadeDepth * 1.35], `corner:${index}`, undefined, ["structure"]));
407
409
  });
408
410
  }
411
+ /** @internal */
409
412
  export function generateBuilding(input = {}) {
410
413
  const config = createBuildingConfig(input);
411
414
  const width = config.baysWide * config.bayWidth;
@@ -429,6 +432,7 @@ export function generateBuilding(input = {}) {
429
432
  parts,
430
433
  };
431
434
  }
435
+ /** @internal */
432
436
  export function createBuildingGrid(config) {
433
437
  const rows = positiveInt(config.rows, 1);
434
438
  const columns = positiveInt(config.columns, 1);
@@ -467,6 +471,7 @@ export function createBuildingGrid(config) {
467
471
  }
468
472
  return lots;
469
473
  }
474
+ /** @internal */
470
475
  export function generateBuildingDistrict(config) {
471
476
  return createBuildingGrid(config).map((lot) => generateBuilding(lot.config));
472
477
  }
@@ -0,0 +1,22 @@
1
+ /**
2
+ * Generic sag/catenary curve → point string, ready to loft into a tube. Genre-agnostic — power lines,
3
+ * suspension-bridge cables, ziplines, ropes, hanging chains, festoon lights all hang the same way.
4
+ * `sagCurve` is a cheap quadratic-Bézier droop; `catenaryCurve` is the true cosh hyperbolic cable.
5
+ *
6
+ * @capability catenary sagging cable curve between two anchors
7
+ */
8
+ export type { Vec3 } from "./geometry.js";
9
+ import type { Vec3 } from "./geometry.js";
10
+ /**
11
+ * Quadratic-Bézier sag between two anchors: the control point is pulled straight down so the mid-span
12
+ * lowest point droops by exactly `sag` meters below the chord. Cheap and stable; the go-to for cables
13
+ * where exact catenary physics don't matter. Returns `segments + 1` points.
14
+ */
15
+ export declare function sagCurve(a: Vec3, b: Vec3, sag: number, segments: number): Vec3[];
16
+ /**
17
+ * True hyperbolic catenary between two anchors — the shape a uniform cable actually takes under
18
+ * gravity. `slack` is the extra length beyond the straight-line distance, as a fraction (0.1 = 10%
19
+ * longer than taut); larger slack droops deeper. Falls back to {@link sagCurve} for a near-taut cable.
20
+ * Returns `segments + 1` points. Anchors may differ in height; the curve interpolates the chord.
21
+ */
22
+ export declare function catenaryCurve(a: Vec3, b: Vec3, slack: number, segments: number): Vec3[];
@@ -0,0 +1,69 @@
1
+ /**
2
+ * Generic sag/catenary curve → point string, ready to loft into a tube. Genre-agnostic — power lines,
3
+ * suspension-bridge cables, ziplines, ropes, hanging chains, festoon lights all hang the same way.
4
+ * `sagCurve` is a cheap quadratic-Bézier droop; `catenaryCurve` is the true cosh hyperbolic cable.
5
+ *
6
+ * @capability catenary sagging cable curve between two anchors
7
+ */
8
+ /**
9
+ * Quadratic-Bézier sag between two anchors: the control point is pulled straight down so the mid-span
10
+ * lowest point droops by exactly `sag` meters below the chord. Cheap and stable; the go-to for cables
11
+ * where exact catenary physics don't matter. Returns `segments + 1` points.
12
+ */
13
+ export function sagCurve(a, b, sag, segments) {
14
+ const steps = Math.max(2, Math.round(segments));
15
+ const cx = (a[0] + b[0]) / 2;
16
+ const cy = (a[1] + b[1]) / 2 - 2 * sag;
17
+ const cz = (a[2] + b[2]) / 2;
18
+ const points = [];
19
+ for (let i = 0; i <= steps; i += 1) {
20
+ const t = i / steps;
21
+ const u = 1 - t;
22
+ const w0 = u * u;
23
+ const w1 = 2 * u * t;
24
+ const w2 = t * t;
25
+ points.push([w0 * a[0] + w1 * cx + w2 * b[0], w0 * a[1] + w1 * cy + w2 * b[1], w0 * a[2] + w1 * cz + w2 * b[2]]);
26
+ }
27
+ return points;
28
+ }
29
+ /**
30
+ * True hyperbolic catenary between two anchors — the shape a uniform cable actually takes under
31
+ * gravity. `slack` is the extra length beyond the straight-line distance, as a fraction (0.1 = 10%
32
+ * longer than taut); larger slack droops deeper. Falls back to {@link sagCurve} for a near-taut cable.
33
+ * Returns `segments + 1` points. Anchors may differ in height; the curve interpolates the chord.
34
+ */
35
+ export function catenaryCurve(a, b, slack, segments) {
36
+ const steps = Math.max(2, Math.round(segments));
37
+ const dx = b[0] - a[0];
38
+ const dz = b[2] - a[2];
39
+ const horizontal = Math.hypot(dx, dz);
40
+ if (horizontal < 1e-4 || slack <= 0)
41
+ return sagCurve(a, b, Math.max(0, slack) * horizontal * 0.5, steps);
42
+ const length = horizontal * (1 + slack);
43
+ // Solve the catenary parameter `p` (= a in y=p·cosh(x/p)) for the required arc length via bisection.
44
+ const targetRatio = length / horizontal;
45
+ let lo = 1e-3;
46
+ let hi = 1e6;
47
+ for (let i = 0; i < 48; i += 1) {
48
+ const mid = (lo + hi) / 2;
49
+ const ratio = (2 * mid * Math.sinh(horizontal / (2 * mid))) / horizontal;
50
+ if (ratio > targetRatio)
51
+ lo = mid;
52
+ else
53
+ hi = mid;
54
+ }
55
+ const p = (lo + hi) / 2;
56
+ const edge = p * Math.cosh(horizontal / (2 * p));
57
+ const points = [];
58
+ for (let i = 0; i <= steps; i += 1) {
59
+ const t = i / steps;
60
+ const x = a[0] + dx * t;
61
+ const z = a[2] + dz * t;
62
+ // Local horizontal coordinate centered at mid-span → catenary drop below the chord (0 at ends).
63
+ const local = (t - 0.5) * horizontal;
64
+ const drop = p * Math.cosh(local / p) - edge;
65
+ const chordY = a[1] + (b[1] - a[1]) * t;
66
+ points.push([x, chordY + drop, z]);
67
+ }
68
+ return points;
69
+ }
@@ -1,4 +1,8 @@
1
1
  import type { BuildingPaletteOverrides, BuildingStyle } from "./buildings.js";
2
+ import type { AvoidZone } from "./geometry.js";
3
+ import type { TerrainPathProfile } from "./pathTerrain.js";
4
+ import type { TerraformSnapshot } from "./terraform.js";
5
+ import type { VolumetricCloudsConfig } from "./volumetricClouds.js";
2
6
  export interface WorldBounds {
3
7
  w: number;
4
8
  d: number;
@@ -42,6 +46,35 @@ export interface TerrainDetailConfig {
42
46
  roughness?: number;
43
47
  /** Overall detail intensity 0..1. Default 1. */
44
48
  strength?: number;
49
+ /** Real PBR texture maps blended over the procedural detail — the seam for `@jgengine/assets` `buildMaterialCatalog` output. Omit to keep the procedural-only look. */
50
+ material?: TerrainDetailMaterialConfig;
51
+ }
52
+ /**
53
+ * PBR map URLs for a real ground texture — the same shape
54
+ * `buildMaterialCatalog({ basePath }).resolve(id)!.maps` from `@jgengine/assets` returns. Kept
55
+ * dependency-free here so `core` never imports the assets package; any URLs (pulled maps, a CDN, a
56
+ * data URI) satisfy it.
57
+ */
58
+ export interface TerrainMaterialMaps {
59
+ color: string;
60
+ normal: string;
61
+ roughness: string;
62
+ ao: string;
63
+ displacement: string;
64
+ }
65
+ /**
66
+ * Real PBR texture applied over the ground surface — the seam that lets a game put a
67
+ * `buildMaterialCatalog` material on terrain. Blends with, never replaces, the procedural detail
68
+ * shader: color/roughness/ao tile the maps by world position, `strength` fades them over the
69
+ * existing vertex-colour + noise look.
70
+ */
71
+ export interface TerrainDetailMaterialConfig {
72
+ /** e.g. `buildMaterialCatalog({ basePath: "/materials" }).resolve("material/grass")!.maps`. */
73
+ maps: TerrainMaterialMaps;
74
+ /** World units per texture tile; smaller tiles the texture more densely. Default 4. */
75
+ repeat?: number;
76
+ /** Blend strength of the texture over the procedural/vertex-colour base, 0..1. Default 1. */
77
+ strength?: number;
45
78
  }
46
79
  export interface TerrainFlattenMask {
47
80
  center: EnvironmentVec2;
@@ -88,11 +121,26 @@ export interface TerrainRectRegion extends TerrainRegionStyle {
88
121
  * and blend back across `falloff`; later regions in the list win overlaps.
89
122
  */
90
123
  export type TerrainMaterialRegion = TerrainCircleRegion | TerrainPolylineRegion | TerrainRectRegion;
124
+ /** Per-band fog override cross-faded along z by `createBiomeFogSampler`; unset fields fall through to the base sky fog. */
125
+ export interface BiomeFog {
126
+ color?: string;
127
+ near?: number;
128
+ far?: number;
129
+ density?: number;
130
+ }
131
+ /** Per-band sky/light override cross-faded along z by `createBiomeSkySampler`; unset fields fall through to the base sky. */
132
+ export interface BiomeSky {
133
+ horizonColor?: string;
134
+ zenithColor?: string;
135
+ sunIntensity?: number;
136
+ ambientIntensity?: number;
137
+ }
91
138
  /**
92
139
  * A z-ordered ground palette zone — the linear-boundary counterpart to the radial `materialRegions`.
93
140
  * Adjacent bands cross-fade into each other across a `fade`-wide window centered on the midpoint z
94
141
  * between their centers, so a multi-biome world (vale → marsh → peaks along z) blends its ground
95
- * color instead of hard-switching. Order the list by ascending `z`.
142
+ * color instead of hard-switching. Bands may also carry per-zone `fog`, `sky`, and `weather`. Order
143
+ * the list by ascending `z`.
96
144
  */
97
145
  export interface BiomeBand {
98
146
  /** World-space center z of the zone. */
@@ -103,6 +151,12 @@ export interface BiomeBand {
103
151
  material?: TerrainMaterial;
104
152
  /** Explicit low/high/waterline hex colors for the zone. */
105
153
  colors?: TerrainColors;
154
+ /** Fog color/near/far/density for the zone, cross-faded per camera z; unset fields keep the base sky fog. */
155
+ fog?: BiomeFog;
156
+ /** Sky horizon/zenith colors and sun/ambient intensity for the zone, cross-faded per camera z; unset fields keep the base sky. */
157
+ sky?: BiomeSky;
158
+ /** Precipitation covering the zone — expands into a full-width weather strip centered at `[0, z]`, `fade`-deep. */
159
+ weather?: "rain" | "snow";
106
160
  }
107
161
  export interface TerrainEnvironmentConfig {
108
162
  bounds?: WorldBounds;
@@ -131,22 +185,50 @@ export interface TerrainEnvironmentConfig {
131
185
  waterLevel?: number;
132
186
  /** Flat pads carved into the noise field, e.g. for building pads or spawn circles. */
133
187
  flatten?: readonly TerrainFlattenMask[];
188
+ /** Authored path profiles that flatten/grade/carve the heightfield along a centerline (roads, rivers, ramps) with optional retaining walls. Applied after `flatten`. */
189
+ pathProfiles?: readonly TerrainPathProfile[];
134
190
  /** Procedural detail surface (noise-driven rock/sand/snow over the biome base). Omit for the flat vertex-colour ground. */
135
191
  detail?: TerrainDetailConfig;
136
192
  }
137
193
  export interface RainEnvironmentConfig {
194
+ /**
195
+ * `w`/`d`/`h` size a wrap-volume of raindrops **anchored to and re-centered on the camera every
196
+ * frame** — not a world-space region. `area.position` (and the `position` sugar below) has **no
197
+ * visual effect** on rain/snow: the shell's `RainField`/`SnowField` always run `followCamera` and
198
+ * never apply the mesh's transform, only `camera.position`. Keep `w`/`d`/`h` near camera scale
199
+ * (roughly 50-120 per axis) so drops stay a visible size at normal view distance — sizing the
200
+ * volume to a world region (e.g. matching a district's footprint) spreads the same drop count
201
+ * across that much more space until they're sub-pixel and the storm reads as empty sky, even
202
+ * though `summarizeEnvironment` shows the layer exists. Reach for `density`, `width`, and `opacity`
203
+ * to make a storm read heavier/taller instead of enlarging `area`.
204
+ */
138
205
  area?: EnvironmentArea;
139
- /** World-space center `[x, z]` of the band, matching `building()`/`ocean()` — sugar for `area.position`, letting a biome zone site its own weather away from the origin. */
206
+ /** World-space center `[x, z]` of the band, matching `building()`/`ocean()` — sugar for `area.position`. No visual effect on rain/snow (see `area`); kept for API symmetry with other weather-adjacent features. */
140
207
  position?: EnvironmentVec2;
141
208
  density?: number;
142
209
  speed?: number;
143
210
  dropLength?: number;
144
211
  wind?: EnvironmentVec2;
145
212
  color?: string;
213
+ /** Streak width of each raindrop quad, in world units. Default 0.018 — raise for a heavier-reading storm without enlarging `area`. */
214
+ width?: number;
215
+ /** Drop opacity, 0-1. Default 0.48 — raise for a denser-reading storm without enlarging `area`. */
216
+ opacity?: number;
146
217
  }
147
218
  export interface SnowEnvironmentConfig {
219
+ /**
220
+ * `w`/`d`/`h` size a wrap-volume of snowflakes **anchored to and re-centered on the camera every
221
+ * frame** — not a world-space region. `area.position` (and the `position` sugar below) has **no
222
+ * visual effect** on rain/snow: the shell's `RainField`/`SnowField` always run `followCamera` and
223
+ * never apply the mesh's transform, only `camera.position`. Keep `w`/`d`/`h` near camera scale
224
+ * (roughly 50-120 per axis) so flakes stay a visible size at normal view distance — sizing the
225
+ * volume to a world region (e.g. matching a district's footprint) spreads the same flake count
226
+ * across that much more space until they're sub-pixel and the storm reads as empty sky, even
227
+ * though `summarizeEnvironment` shows the layer exists. Reach for `density`, `flakeSize`, and
228
+ * `opacity` to make a storm read heavier instead of enlarging `area`.
229
+ */
148
230
  area?: EnvironmentArea;
149
- /** World-space center `[x, z]` of the band, matching `building()`/`ocean()` — sugar for `area.position`, letting a biome zone site its own weather away from the origin. */
231
+ /** World-space center `[x, z]` of the band, matching `building()`/`ocean()` — sugar for `area.position`. No visual effect on rain/snow (see `area`); kept for API symmetry with other weather-adjacent features. */
150
232
  position?: EnvironmentVec2;
151
233
  density?: number;
152
234
  speed?: number;
@@ -154,6 +236,8 @@ export interface SnowEnvironmentConfig {
154
236
  drift?: number;
155
237
  wind?: EnvironmentVec2;
156
238
  color?: string;
239
+ /** Flake opacity, 0-1. Default 0.86 — raise for a denser-reading storm without enlarging `area`. */
240
+ opacity?: number;
157
241
  }
158
242
  export interface GrassEnvironmentConfig {
159
243
  area?: EnvironmentArea;
@@ -192,11 +276,19 @@ export interface SkyEnvironmentConfig {
192
276
  zenithColor?: string;
193
277
  sunIntensity?: number;
194
278
  ambientIntensity?: number;
279
+ /** Sky-dome sphere radius in world units. Enlarge for a playfield sited far from the origin so the viewer never exits the dome. Default 260. */
280
+ radius?: number;
281
+ /** Horizon haze-band strength: 0 removes the dusty band, ~1 makes it heavy. Default 0.5. */
282
+ hazeStrength?: number;
283
+ /** Sun-glow brightness multiplier around the sun disc. Default 1. */
284
+ sunGlowStrength?: number;
195
285
  fog?: {
196
286
  color?: string;
197
287
  near?: number;
198
288
  far?: number;
199
289
  };
290
+ /** Raymarched volumetric cloud layer over the sky dome. Off by default — omit for no clouds. */
291
+ volumetricClouds?: VolumetricCloudsConfig;
200
292
  }
201
293
  export interface BuildingEnvironmentConfig {
202
294
  count?: number;
@@ -239,10 +331,10 @@ export type TerrainIslandDescriptor = Omit<TerrainEnvironmentDescriptor, "kind">
239
331
  };
240
332
  export type RainEnvironmentDescriptor = {
241
333
  kind: "rain";
242
- } & Required<Pick<RainEnvironmentConfig, "area" | "density" | "speed" | "dropLength" | "wind" | "color">>;
334
+ } & Required<Pick<RainEnvironmentConfig, "area" | "density" | "speed" | "dropLength" | "wind" | "color" | "width" | "opacity">>;
243
335
  export type SnowEnvironmentDescriptor = {
244
336
  kind: "snow";
245
- } & Required<Pick<SnowEnvironmentConfig, "area" | "density" | "speed" | "flakeSize" | "drift" | "wind" | "color">>;
337
+ } & Required<Pick<SnowEnvironmentConfig, "area" | "density" | "speed" | "flakeSize" | "drift" | "wind" | "color" | "opacity">>;
246
338
  export type GrassEnvironmentDescriptor = {
247
339
  kind: "grass";
248
340
  } & Required<Pick<GrassEnvironmentConfig, "area" | "density" | "bladeHeight" | "bladeWidth" | "windStrength" | "colors">> & Pick<GrassEnvironmentConfig, "seed">;
@@ -306,6 +398,18 @@ export interface EnvironmentWorldConfig {
306
398
  roads?: EnvironmentDescriptorList<RoadEnvironmentDescriptor>;
307
399
  /** Ground pads, e.g. platforms or paved patches; each implicitly flattens the terrain beneath it. */
308
400
  pads?: readonly PadEnvironmentDescriptor[];
401
+ /**
402
+ * An authored editor {@link TerraformSnapshot} whose offsets layer over the base terrain — the
403
+ * editor-to-runtime ground seam. The same snapshot in a game's `editorLayers.terrain` renders and
404
+ * collides identically at runtime.
405
+ */
406
+ sculpt?: TerraformSnapshot;
407
+ /**
408
+ * Clearance discs flattened into the ground (spawns, plots, paths) — the terrain half of a
409
+ * clearance zone whose foliage half is scatter's `avoid`. Derive them from a document with
410
+ * `clearanceZonesFrom`.
411
+ */
412
+ clearings?: readonly AvoidZone[];
309
413
  }
310
414
  export interface EnvironmentWorldFeature {
311
415
  kind: "environment";
@@ -318,6 +422,10 @@ export interface EnvironmentWorldFeature {
318
422
  structures?: readonly StructureEnvironmentDescriptor[];
319
423
  roads?: readonly RoadEnvironmentDescriptor[];
320
424
  pads?: readonly PadEnvironmentDescriptor[];
425
+ /** Authored sculpt snapshot layered over the base terrain — see {@link EnvironmentWorldConfig.sculpt}. */
426
+ sculpt?: TerraformSnapshot;
427
+ /** Clearance discs flattened into the ground — see {@link EnvironmentWorldConfig.clearings}. */
428
+ clearings?: readonly AvoidZone[];
321
429
  }
322
430
  export interface WorldGridCell {
323
431
  x: number;
@@ -375,9 +483,9 @@ export declare function environment(config?: EnvironmentWorldConfig): Environmen
375
483
  /** Declares a heightfield terrain patch for `environment()` — bounds, noise, materials, and flatten masks. */
376
484
  export declare function terrain(config?: TerrainEnvironmentConfig): TerrainEnvironmentDescriptor;
377
485
  export declare function sky(config?: SkyEnvironmentConfig): SkyEnvironmentDescriptor;
378
- /** Declares a rainfall weather effect for `environment()` — area, density, speed, and wind. */
486
+ /** Declares a rainfall weather effect for `environment()` — area, density, speed, wind, and drop width/opacity. */
379
487
  export declare function rain(config?: RainEnvironmentConfig): RainEnvironmentDescriptor;
380
- /** Declares a snowfall weather effect for `environment()` — area, density, drift, and wind. */
488
+ /** Declares a snowfall weather effect for `environment()` — area, density, drift, wind, and flake opacity. */
381
489
  export declare function snow(config?: SnowEnvironmentConfig): SnowEnvironmentDescriptor;
382
490
  /** Declares a grass vegetation patch for `environment()` — area, blade sizing, density, and colors. */
383
491
  export declare function grass(config?: GrassEnvironmentConfig): GrassEnvironmentDescriptor;
@@ -27,9 +27,28 @@ function withPadFlatten(terrainDescriptor, pads) {
27
27
  flatten: [...(terrainDescriptor.flatten ?? []), ...padFlattenMasks(pads)],
28
28
  };
29
29
  }
30
+ /** Expands each `biomeBand.weather` into a full-width precipitation strip centered on the band's z, `fade`-deep. */
31
+ function bandWeatherDescriptors(terrainDescriptor) {
32
+ const bands = terrainDescriptor?.biomeBands;
33
+ if (bands === undefined || bands.length === 0)
34
+ return [];
35
+ const width = terrainDescriptor.bounds.w;
36
+ const out = [];
37
+ for (const band of bands) {
38
+ if (band.weather === undefined)
39
+ continue;
40
+ const area = { w: width, d: band.fade ?? 64, h: 80 };
41
+ const position = [0, band.z];
42
+ out.push(band.weather === "rain" ? rain({ area, position }) : snow({ area, position }));
43
+ }
44
+ return out;
45
+ }
30
46
  /** Composes an `environment()` world feature from terrain, sky, weather, vegetation, water, structures, roads, and pads. */
31
47
  export function environment(config = {}) {
32
- const weather = list(config.weather);
48
+ const explicitWeather = list(config.weather);
49
+ const bandWeather = bandWeatherDescriptors(config.terrain);
50
+ const weatherAll = [...(explicitWeather ?? []), ...bandWeather];
51
+ const weather = weatherAll.length === 0 ? undefined : weatherAll;
33
52
  const vegetation = list(config.vegetation);
34
53
  const water = list(config.water);
35
54
  const structures = list(config.structures);
@@ -46,6 +65,8 @@ export function environment(config = {}) {
46
65
  ...(structures === undefined ? {} : { structures }),
47
66
  ...(roads === undefined ? {} : { roads }),
48
67
  ...(config.pads === undefined ? {} : { pads: config.pads }),
68
+ ...(config.sculpt === undefined ? {} : { sculpt: config.sculpt }),
69
+ ...(config.clearings === undefined || config.clearings.length === 0 ? {} : { clearings: config.clearings }),
49
70
  };
50
71
  }
51
72
  /** Declares a heightfield terrain patch for `environment()` — bounds, noise, materials, and flatten masks. */
@@ -75,6 +96,7 @@ export function terrain(config = {}) {
75
96
  ...(config.baseHeight === undefined ? {} : { baseHeight: config.baseHeight }),
76
97
  ...(config.waterLevel === undefined ? {} : { waterLevel: config.waterLevel }),
77
98
  ...(config.flatten === undefined ? {} : { flatten: config.flatten }),
99
+ ...(config.pathProfiles === undefined ? {} : { pathProfiles: config.pathProfiles }),
78
100
  ...(config.detail === undefined ? {} : { detail: config.detail }),
79
101
  });
80
102
  }
@@ -88,35 +110,64 @@ export function sky(config = {}) {
88
110
  ...(config.zenithColor === undefined ? {} : { zenithColor: config.zenithColor }),
89
111
  ...(config.sunIntensity === undefined ? {} : { sunIntensity: config.sunIntensity }),
90
112
  ...(config.ambientIntensity === undefined ? {} : { ambientIntensity: config.ambientIntensity }),
113
+ ...(config.radius === undefined ? {} : { radius: config.radius }),
114
+ ...(config.hazeStrength === undefined ? {} : { hazeStrength: config.hazeStrength }),
115
+ ...(config.sunGlowStrength === undefined ? {} : { sunGlowStrength: config.sunGlowStrength }),
91
116
  ...(config.fog === undefined ? {} : { fog: config.fog }),
117
+ ...(config.volumetricClouds === undefined ? {} : { volumetricClouds: config.volumetricClouds }),
92
118
  });
93
119
  }
94
120
  function withAreaPosition(area, position) {
95
121
  return position !== undefined && area.position === undefined ? { ...area, position } : area;
96
122
  }
97
- /** Declares a rainfall weather effect for `environment()` — area, density, speed, and wind. */
123
+ /**
124
+ * Practical ceiling (world units per axis) past which an author-specified rain/snow `area` is almost
125
+ * certainly a world-region size mistakenly handed to the camera-anchored wrap-volume — see the
126
+ * `area` doc on `RainEnvironmentConfig`/`SnowEnvironmentConfig`.
127
+ */
128
+ const WEATHER_AREA_CAMERA_SCALE_HINT = 120;
129
+ function warnIfOversizedWeatherArea(kind, area) {
130
+ if (typeof console === "undefined")
131
+ return;
132
+ if (area.w <= WEATHER_AREA_CAMERA_SCALE_HINT &&
133
+ area.d <= WEATHER_AREA_CAMERA_SCALE_HINT &&
134
+ (area.h ?? 0) <= WEATHER_AREA_CAMERA_SCALE_HINT) {
135
+ return;
136
+ }
137
+ console.warn(`[jgengine:${kind}] area ${area.w}x${area.d}x${area.h ?? "default"} is far larger than the camera-anchored wrap-volume ${kind}() actually renders — area.position is ignored, and an oversized area.w/d/h just spreads drops/flakes thinner until they're sub-pixel at normal view distance, not wider visible coverage. Keep area near camera scale (~50-120 per axis); use density/width/opacity (or flakeSize for snow) to make a storm read heavier instead.`);
138
+ }
139
+ /** Declares a rainfall weather effect for `environment()` — area, density, speed, wind, and drop width/opacity. */
98
140
  export function rain(config = {}) {
141
+ const area = withAreaPosition(config.area ?? { w: 256, d: 256, h: 80 }, config.position);
142
+ if (config.area !== undefined)
143
+ warnIfOversizedWeatherArea("rain", area);
99
144
  return {
100
145
  kind: "rain",
101
- area: withAreaPosition(config.area ?? { w: 256, d: 256, h: 80 }, config.position),
146
+ area,
102
147
  density: config.density ?? 0.65,
103
148
  speed: config.speed ?? 18,
104
149
  dropLength: config.dropLength ?? 0.8,
105
150
  wind: config.wind ?? [0, 0],
106
151
  color: config.color ?? "#9ec8ff",
152
+ width: config.width ?? 0.018,
153
+ opacity: config.opacity ?? 0.48,
107
154
  };
108
155
  }
109
- /** Declares a snowfall weather effect for `environment()` — area, density, drift, and wind. */
156
+ /** Declares a snowfall weather effect for `environment()` — area, density, drift, wind, and flake opacity. */
110
157
  export function snow(config = {}) {
158
+ const area = withAreaPosition(config.area ?? { w: 256, d: 256, h: 80 }, config.position);
159
+ if (config.area !== undefined)
160
+ warnIfOversizedWeatherArea("snow", area);
111
161
  return {
112
162
  kind: "snow",
113
- area: withAreaPosition(config.area ?? { w: 256, d: 256, h: 80 }, config.position),
163
+ area,
114
164
  density: config.density ?? 0.35,
115
165
  speed: config.speed ?? 2.4,
116
166
  flakeSize: config.flakeSize ?? 0.08,
117
167
  drift: config.drift ?? 0.4,
118
168
  wind: config.wind ?? [0, 0],
119
169
  color: config.color ?? "#ffffff",
170
+ opacity: config.opacity ?? 0.86,
120
171
  };
121
172
  }
122
173
  /** Declares a grass vegetation patch for `environment()` — area, blade sizing, density, and colors. */