@fps-games/vfx 0.1.1

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 (375) hide show
  1. package/CHANGELOG.md +34 -0
  2. package/dist/EffectPackageService.d.ts +26 -0
  3. package/dist/SceneVfxService.d.ts +27 -0
  4. package/dist/chunks/legacy-particle-runtime-CbJYVxdd.js +75 -0
  5. package/dist/chunks/manifestRuntimePackage-CXQFSTo2.js +356 -0
  6. package/dist/chunks/rendering-CV3nhygX.js +13 -0
  7. package/dist/chunks/space-shared-BXV1hc0k.js +124 -0
  8. package/dist/chunks/wood-sawdust-effect-factory-DlETNaBn.js +129 -0
  9. package/dist/effects/building-upgrade/effect.json.d.ts +9 -0
  10. package/dist/effects/building-upgrade/index.d.ts +20 -0
  11. package/dist/effects/building-upgrade/index.js +337 -0
  12. package/dist/effects/character-entrance/effect.json.d.ts +9 -0
  13. package/dist/effects/character-entrance/index.d.ts +18 -0
  14. package/dist/effects/character-entrance/index.js +271 -0
  15. package/dist/effects/coin-burst/index.d.ts +6 -0
  16. package/dist/effects/coin-burst/index.js +45 -0
  17. package/dist/effects/comet-trail-flame/index.d.ts +11 -0
  18. package/dist/effects/comet-trail-flame/index.js +103 -0
  19. package/dist/effects/conveyor-upgrade/effect.json.d.ts +9 -0
  20. package/dist/effects/conveyor-upgrade/index.d.ts +20 -0
  21. package/dist/effects/conveyor-upgrade/index.js +349 -0
  22. package/dist/effects/debris-smoke/index.d.ts +10 -0
  23. package/dist/effects/debris-smoke/index.js +108 -0
  24. package/dist/effects/door_open_gold_flakes/door_open_gold_flakes.json.d.ts +501 -0
  25. package/dist/effects/door_open_gold_flakes/index.d.ts +1 -0
  26. package/dist/effects/door_open_gold_flakes/index.js +524 -0
  27. package/dist/effects/electric-arc/index.d.ts +8 -0
  28. package/dist/effects/electric-arc/index.js +71 -0
  29. package/dist/effects/energy-shield/index.d.ts +46 -0
  30. package/dist/effects/energy-shield/index.js +365 -0
  31. package/dist/effects/explosion/index.d.ts +11 -0
  32. package/dist/effects/explosion/index.js +129 -0
  33. package/dist/effects/ground-tile-upgrade/effect.json.d.ts +9 -0
  34. package/dist/effects/ground-tile-upgrade/index.d.ts +20 -0
  35. package/dist/effects/ground-tile-upgrade/index.js +357 -0
  36. package/dist/effects/hit-flash/index.d.ts +8 -0
  37. package/dist/effects/hit-flash/index.js +71 -0
  38. package/dist/effects/laser-beam/index.d.ts +1 -0
  39. package/dist/effects/laser-beam/index.js +152 -0
  40. package/dist/effects/laser-beam-factory.d.ts +12 -0
  41. package/dist/effects/lumber-cart-suction/effect.json.d.ts +9 -0
  42. package/dist/effects/lumber-cart-suction/index.d.ts +26 -0
  43. package/dist/effects/lumber-cart-suction/index.js +322 -0
  44. package/dist/effects/lumber-debris-scatter/effect.json.d.ts +231 -0
  45. package/dist/effects/lumber-debris-scatter/index.d.ts +20 -0
  46. package/dist/effects/lumber-debris-scatter/index.js +637 -0
  47. package/dist/effects/lumber_vehicle_gear_spin/index.d.ts +1 -0
  48. package/dist/effects/lumber_vehicle_gear_spin/index.js +363 -0
  49. package/dist/effects/lumber_vehicle_gear_spin/lumber_vehicle_gear_spin.json.d.ts +341 -0
  50. package/dist/effects/lumber_vehicle_upgrade_aura/index.d.ts +1 -0
  51. package/dist/effects/lumber_vehicle_upgrade_aura/index.js +391 -0
  52. package/dist/effects/lumber_vehicle_upgrade_aura/lumber_vehicle_upgrade_aura.json.d.ts +368 -0
  53. package/dist/effects/lumber_vehicle_wood_chips/index.d.ts +1 -0
  54. package/dist/effects/lumber_vehicle_wood_chips/index.js +360 -0
  55. package/dist/effects/lumber_vehicle_wood_chips/lumber_vehicle_wood_chips.json.d.ts +338 -0
  56. package/dist/effects/monster-hit/index.d.ts +15 -0
  57. package/dist/effects/monster-hit/index.js +156 -0
  58. package/dist/effects/player-upgrade/effect.json.d.ts +9 -0
  59. package/dist/effects/player-upgrade/index.d.ts +24 -0
  60. package/dist/effects/player-upgrade/index.js +539 -0
  61. package/dist/effects/pulse-laser-volley/index.d.ts +17 -0
  62. package/dist/effects/pulse-laser-volley/index.js +173 -0
  63. package/dist/effects/resource-collect-sparkles/effect.json.d.ts +9 -0
  64. package/dist/effects/resource-collect-sparkles/index.d.ts +21 -0
  65. package/dist/effects/resource-collect-sparkles/index.js +222 -0
  66. package/dist/effects/run-footstep-dust/effect.json.d.ts +186 -0
  67. package/dist/effects/run-footstep-dust/index.d.ts +23 -0
  68. package/dist/effects/run-footstep-dust/index.js +343 -0
  69. package/dist/effects/space-shared.d.ts +44 -0
  70. package/dist/effects/thruster-flame/index.d.ts +15 -0
  71. package/dist/effects/thruster-flame/index.js +301 -0
  72. package/dist/effects/tree-chop-dust/effect.json.d.ts +11 -0
  73. package/dist/effects/tree-chop-dust/index.d.ts +17 -0
  74. package/dist/effects/tree-chop-dust/index.js +165 -0
  75. package/dist/effects/tree-leaf-chop-burst/index.d.ts +19 -0
  76. package/dist/effects/tree-leaf-chop-burst/index.js +219 -0
  77. package/dist/effects/tree_chop_dust_burst/index.d.ts +1 -0
  78. package/dist/effects/tree_chop_dust_burst/index.js +443 -0
  79. package/dist/effects/tree_chop_dust_burst/tree_chop_dust_burst.json.d.ts +415 -0
  80. package/dist/effects/ufo-thread-flame/index.d.ts +21 -0
  81. package/dist/effects/ufo-thread-flame/index.js +140 -0
  82. package/dist/effects/vehicle-exhaust-smoke/effect.json.d.ts +11 -0
  83. package/dist/effects/vehicle-exhaust-smoke/index.d.ts +19 -0
  84. package/dist/effects/vehicle-exhaust-smoke/index.js +242 -0
  85. package/dist/effects/vehicle-upgrade/effect.json.d.ts +9 -0
  86. package/dist/effects/vehicle-upgrade/index.d.ts +20 -0
  87. package/dist/effects/vehicle-upgrade/index.js +349 -0
  88. package/dist/effects/weapon-trail/index.d.ts +26 -0
  89. package/dist/effects/weapon-trail/index.js +351 -0
  90. package/dist/effects/wood-crusher-sawdust/index.d.ts +2 -0
  91. package/dist/effects/wood-crusher-sawdust/index.js +648 -0
  92. package/dist/effects/wood-crusher-sawdust/wood_crusher_sawdust.json.d.ts +595 -0
  93. package/dist/effects/wood-cutter-sawdust/index.d.ts +2 -0
  94. package/dist/effects/wood-cutter-sawdust/index.js +648 -0
  95. package/dist/effects/wood-cutter-sawdust/wood_cutter_sawdust.json.d.ts +595 -0
  96. package/dist/effects/wood-sawdust-effect-factory.d.ts +36 -0
  97. package/dist/effects/wood_crusher_sawdust/index.d.ts +16 -0
  98. package/dist/effects/wood_crusher_sawdust/index.js +634 -0
  99. package/dist/effects/wood_crusher_sawdust/wood_crusher_sawdust.json.d.ts +595 -0
  100. package/dist/effects/wood_cutter_sawdust/index.d.ts +16 -0
  101. package/dist/effects/wood_cutter_sawdust/index.js +634 -0
  102. package/dist/effects/wood_cutter_sawdust/wood_cutter_sawdust.json.d.ts +595 -0
  103. package/dist/effects/wood_peel_material_test/index.d.ts +1 -0
  104. package/dist/effects/wood_peel_material_test/index.js +157 -0
  105. package/dist/effects/wood_peel_material_test/wood_peel_material_test.json.d.ts +139 -0
  106. package/dist/generation.d.ts +7 -0
  107. package/dist/index.d.ts +8 -0
  108. package/dist/index.js +309 -0
  109. package/dist/legacy-particle-runtime.d.ts +30 -0
  110. package/dist/manifestRuntimePackage.d.ts +68 -0
  111. package/dist/registry.d.ts +20 -0
  112. package/dist/rendering.d.ts +5 -0
  113. package/dist/types.d.ts +83 -0
  114. package/docs/AUTHORING_EFFECTS.md +297 -0
  115. package/docs/VFX_LIBRARY_ARCHITECTURE_chatgpt.md +1580 -0
  116. package/docs/VFX_LIBRARY_EXECUTION_PLAN.md +229 -0
  117. package/docs/VFX_LIBRARY_PLAN.md +546 -0
  118. package/docs/vfx-ab/RESULTS.md +35 -0
  119. package/docs/vfx-ab/lumber-order/vehicle-exhaust-smoke/after.png +0 -0
  120. package/docs/vfx-ab/lumber-order/vehicle-exhaust-smoke/before.png +0 -0
  121. package/docs/vfx-ab/lumber-truck/vehicle-exhaust-smoke/after.png +0 -0
  122. package/docs/vfx-ab/lumber-truck/vehicle-exhaust-smoke/before.png +0 -0
  123. package/docs/vfx-integration_chatgpt.md +462 -0
  124. package/docs/weapon-trail-visualization.html +241 -0
  125. package/index.json +381 -0
  126. package/package.json +51 -0
  127. package/packages/EffectPackageService.ts +240 -0
  128. package/packages/SceneVfxService.ts +96 -0
  129. package/packages/build.mesh.yellow_build_upgrade_indicator/assets/runtime/simpleMeshEffect.v1.js +333 -0
  130. package/packages/build.mesh.yellow_build_upgrade_indicator/assets/shaders/mesh-effect-preview.frag.glsl +25 -0
  131. package/packages/build.mesh.yellow_build_upgrade_indicator/assets/shaders/mesh-effect-preview.vert.glsl +11 -0
  132. package/packages/build.mesh.yellow_build_upgrade_indicator/assets/textures/effect_jianbian.png +0 -0
  133. package/packages/build.mesh.yellow_build_upgrade_indicator/effect.json +927 -0
  134. package/packages/build.mesh.yellow_build_upgrade_indicator/media/contact-sheet.png +0 -0
  135. package/packages/build.mesh.yellow_build_upgrade_indicator/media/preview.gif +0 -0
  136. package/packages/build.mesh.yellow_build_upgrade_indicator/media/preview.mp4 +0 -0
  137. package/packages/build.mesh.yellow_build_upgrade_indicator/media/preview.webm +0 -0
  138. package/packages/build.mesh.yellow_build_upgrade_indicator/media/thumbnail.png +0 -0
  139. package/packages/build.mesh.yellow_build_upgrade_indicator/metadata/description.json +197 -0
  140. package/packages/build.mesh.yellow_build_upgrade_indicator/provenance/03-effect.original.json +895 -0
  141. package/packages/build.mesh.yellow_build_upgrade_indicator/provenance/03-normalized-vfx-to-babylon-report.json +241 -0
  142. package/packages/build.mesh.yellow_build_upgrade_indicator/provenance/04-preview-overrides.json +542 -0
  143. package/packages/build.mesh.yellow_build_upgrade_indicator/provenance/04-preview-tuning-report.json +69 -0
  144. package/packages/build.mesh.yellow_build_upgrade_indicator/provenance/asset-map.json +125 -0
  145. package/packages/build.mesh.yellow_build_upgrade_indicator/provenance/lineage.json +44 -0
  146. package/packages/build.particle.golden_upgrade_starburst/assets/runtime/particleEmitter.v1.js +210 -0
  147. package/packages/build.particle.golden_upgrade_starburst/assets/textures/effect_guangdian.png +0 -0
  148. package/packages/build.particle.golden_upgrade_starburst/effect.json +880 -0
  149. package/packages/build.particle.golden_upgrade_starburst/media/contact-sheet.png +0 -0
  150. package/packages/build.particle.golden_upgrade_starburst/media/preview.gif +0 -0
  151. package/packages/build.particle.golden_upgrade_starburst/media/preview.mp4 +0 -0
  152. package/packages/build.particle.golden_upgrade_starburst/media/preview.webm +0 -0
  153. package/packages/build.particle.golden_upgrade_starburst/media/thumbnail.png +0 -0
  154. package/packages/build.particle.golden_upgrade_starburst/metadata/description.json +161 -0
  155. package/packages/build.particle.golden_upgrade_starburst/provenance/03-effect.original.json +762 -0
  156. package/packages/build.particle.golden_upgrade_starburst/provenance/03-normalized-vfx-to-babylon-report.json +260 -0
  157. package/packages/build.particle.golden_upgrade_starburst/provenance/04-preview-overrides.json +436 -0
  158. package/packages/build.particle.golden_upgrade_starburst/provenance/04-preview-tuning-report.json +40 -0
  159. package/packages/build.particle.golden_upgrade_starburst/provenance/asset-map.json +115 -0
  160. package/packages/build.particle.golden_upgrade_starburst/provenance/lineage.json +40 -0
  161. package/packages/build.particle.orange_upgrade_transform_sparks/assets/runtime/particleEmitter.v1.js +210 -0
  162. package/packages/build.particle.orange_upgrade_transform_sparks/assets/textures/b5b27ab1-e740-4398-b407-848fc2b2c897.png +0 -0
  163. package/packages/build.particle.orange_upgrade_transform_sparks/effect.json +887 -0
  164. package/packages/build.particle.orange_upgrade_transform_sparks/media/preview.gif +0 -0
  165. package/packages/build.particle.orange_upgrade_transform_sparks/media/preview.mp4 +0 -0
  166. package/packages/build.particle.orange_upgrade_transform_sparks/media/preview.webm +0 -0
  167. package/packages/build.particle.orange_upgrade_transform_sparks/media/thumbnail.png +0 -0
  168. package/packages/build.particle.orange_upgrade_transform_sparks/metadata/description.json +179 -0
  169. package/packages/build.particle.orange_upgrade_transform_sparks/provenance/03-effect.original.json +859 -0
  170. package/packages/build.particle.orange_upgrade_transform_sparks/provenance/03-normalized-vfx-to-babylon-report.json +260 -0
  171. package/packages/build.particle.orange_upgrade_transform_sparks/provenance/04-preview-overrides.json +478 -0
  172. package/packages/build.particle.orange_upgrade_transform_sparks/provenance/04-preview-tuning-report.json +40 -0
  173. package/packages/build.particle.orange_upgrade_transform_sparks/provenance/asset-map.json +114 -0
  174. package/packages/build.particle.orange_upgrade_transform_sparks/provenance/lineage.json +41 -0
  175. package/packages/build.particle.wood_chip_dust_burst/assets/runtime/particleEmitter.v1.js +210 -0
  176. package/packages/build.particle.wood_chip_dust_burst/assets/textures/effect_yanwu4.png +0 -0
  177. package/packages/build.particle.wood_chip_dust_burst/assets/textures/suipian3.png +0 -0
  178. package/packages/build.particle.wood_chip_dust_burst/effect.json +1400 -0
  179. package/packages/build.particle.wood_chip_dust_burst/media/contact-sheet.png +0 -0
  180. package/packages/build.particle.wood_chip_dust_burst/media/preview.gif +0 -0
  181. package/packages/build.particle.wood_chip_dust_burst/media/preview.mp4 +0 -0
  182. package/packages/build.particle.wood_chip_dust_burst/media/preview.webm +0 -0
  183. package/packages/build.particle.wood_chip_dust_burst/media/thumbnail.png +0 -0
  184. package/packages/build.particle.wood_chip_dust_burst/metadata/description.json +173 -0
  185. package/packages/build.particle.wood_chip_dust_burst/provenance/03-effect.original.json +1277 -0
  186. package/packages/build.particle.wood_chip_dust_burst/provenance/03-normalized-vfx-to-babylon-report.json +329 -0
  187. package/packages/build.particle.wood_chip_dust_burst/provenance/04-preview-overrides.json +749 -0
  188. package/packages/build.particle.wood_chip_dust_burst/provenance/04-preview-tuning-report.json +60 -0
  189. package/packages/build.particle.wood_chip_dust_burst/provenance/asset-map.json +146 -0
  190. package/packages/build.particle.wood_chip_dust_burst/provenance/lineage.json +69 -0
  191. package/packages/effects/building-upgrade/effect.json +6 -0
  192. package/packages/effects/building-upgrade/index.ts +387 -0
  193. package/packages/effects/building-upgrade/vfx-params.json +24 -0
  194. package/packages/effects/character-entrance/effect.json +6 -0
  195. package/packages/effects/character-entrance/index.ts +308 -0
  196. package/packages/effects/character-entrance/vfx-params.json +24 -0
  197. package/packages/effects/coin-burst/index.ts +43 -0
  198. package/packages/effects/coin-burst/vfx-params.json +5 -0
  199. package/packages/effects/comet-trail-flame/assets/textures/trail_5x4.webp +0 -0
  200. package/packages/effects/comet-trail-flame/index.ts +106 -0
  201. package/packages/effects/comet-trail-flame/vfx-params.json +5 -0
  202. package/packages/effects/conveyor-upgrade/effect.json +6 -0
  203. package/packages/effects/conveyor-upgrade/index.ts +401 -0
  204. package/packages/effects/conveyor-upgrade/vfx-params.json +21 -0
  205. package/packages/effects/debris-smoke/assets/models/rock_debris.glb +0 -0
  206. package/packages/effects/debris-smoke/assets/textures/smoke22.webp +0 -0
  207. package/packages/effects/debris-smoke/index.ts +101 -0
  208. package/packages/effects/debris-smoke/vfx-params.json +5 -0
  209. package/packages/effects/door_open_gold_flakes/assets/runtime/goldFlakes.v1.js +397 -0
  210. package/packages/effects/door_open_gold_flakes/door_open_gold_flakes.json +498 -0
  211. package/packages/effects/door_open_gold_flakes/index.ts +11 -0
  212. package/packages/effects/door_open_gold_flakes/vfx-params.json +23 -0
  213. package/packages/effects/electric-arc/assets/textures/spark_4x4.webp +0 -0
  214. package/packages/effects/electric-arc/index.ts +62 -0
  215. package/packages/effects/electric-arc/vfx-params.json +5 -0
  216. package/packages/effects/energy-shield/effect.json +7 -0
  217. package/packages/effects/energy-shield/index.ts +431 -0
  218. package/packages/effects/energy-shield/vfx-params.json +29 -0
  219. package/packages/effects/explosion/assets/textures/baozha29.webp +0 -0
  220. package/packages/effects/explosion/assets/textures/glow01.webp +0 -0
  221. package/packages/effects/explosion/assets/textures/lizi01.webp +0 -0
  222. package/packages/effects/explosion/assets/textures/xulie_lizibaozha02_5x5.webp +0 -0
  223. package/packages/effects/explosion/index.ts +114 -0
  224. package/packages/effects/explosion/vfx-params.json +5 -0
  225. package/packages/effects/ground-tile-upgrade/effect.json +6 -0
  226. package/packages/effects/ground-tile-upgrade/index.ts +410 -0
  227. package/packages/effects/ground-tile-upgrade/vfx-params.json +21 -0
  228. package/packages/effects/hit-flash/index.ts +69 -0
  229. package/packages/effects/hit-flash/vfx-params.json +5 -0
  230. package/packages/effects/laser-beam/assets/textures/laser_glow.webp +0 -0
  231. package/packages/effects/laser-beam/assets/textures/laser_noise.webp +0 -0
  232. package/packages/effects/laser-beam/index.ts +6 -0
  233. package/packages/effects/laser-beam/vfx-params.json +5 -0
  234. package/packages/effects/laser-beam-factory.ts +135 -0
  235. package/packages/effects/lumber-cart-suction/effect.json +6 -0
  236. package/packages/effects/lumber-cart-suction/index.ts +399 -0
  237. package/packages/effects/lumber-cart-suction/vfx-params.json +30 -0
  238. package/packages/effects/lumber-debris-scatter/assets/models/lumber_prop_model.glb +0 -0
  239. package/packages/effects/lumber-debris-scatter/assets/models/lumber_prop_model.glb.versions/.active +1 -0
  240. package/packages/effects/lumber-debris-scatter/assets/models/lumber_prop_model.glb.versions/1781589063890_upload.glb +0 -0
  241. package/packages/effects/lumber-debris-scatter/assets/runtime/solidParticleScatter.v1.js +236 -0
  242. package/packages/effects/lumber-debris-scatter/effect.json +228 -0
  243. package/packages/effects/lumber-debris-scatter/index.ts +780 -0
  244. package/packages/effects/lumber-debris-scatter/vfx-params.json +19 -0
  245. package/packages/effects/lumber_vehicle_gear_spin/assets/runtime/gearSpin.v1.js +202 -0
  246. package/packages/effects/lumber_vehicle_gear_spin/index.ts +11 -0
  247. package/packages/effects/lumber_vehicle_gear_spin/lumber_vehicle_gear_spin.json +338 -0
  248. package/packages/effects/lumber_vehicle_gear_spin/vfx-params.json +21 -0
  249. package/packages/effects/lumber_vehicle_upgrade_aura/assets/runtime/upgradeAura.v1.js +353 -0
  250. package/packages/effects/lumber_vehicle_upgrade_aura/index.ts +11 -0
  251. package/packages/effects/lumber_vehicle_upgrade_aura/lumber_vehicle_upgrade_aura.json +365 -0
  252. package/packages/effects/lumber_vehicle_upgrade_aura/vfx-params.json +15 -0
  253. package/packages/effects/lumber_vehicle_wood_chips/assets/runtime/solidParticleScatter.v1.js +310 -0
  254. package/packages/effects/lumber_vehicle_wood_chips/index.ts +11 -0
  255. package/packages/effects/lumber_vehicle_wood_chips/lumber_vehicle_wood_chips.json +335 -0
  256. package/packages/effects/lumber_vehicle_wood_chips/vfx-params.json +11 -0
  257. package/packages/effects/monster-hit/index.ts +128 -0
  258. package/packages/effects/monster-hit/vfx-params.json +5 -0
  259. package/packages/effects/player-upgrade/effect.json +6 -0
  260. package/packages/effects/player-upgrade/index.ts +635 -0
  261. package/packages/effects/player-upgrade/vfx-params.json +28 -0
  262. package/packages/effects/pulse-laser-volley/assets/textures/bolt_guangshu.webp +0 -0
  263. package/packages/effects/pulse-laser-volley/index.ts +204 -0
  264. package/packages/effects/pulse-laser-volley/vfx-params.json +5 -0
  265. package/packages/effects/resource-collect-sparkles/effect.json +6 -0
  266. package/packages/effects/resource-collect-sparkles/index.ts +254 -0
  267. package/packages/effects/resource-collect-sparkles/vfx-params.json +25 -0
  268. package/packages/effects/run-footstep-dust/assets/runtime/runFootstepDust.v1.js +215 -0
  269. package/packages/effects/run-footstep-dust/effect.json +183 -0
  270. package/packages/effects/run-footstep-dust/index.ts +377 -0
  271. package/packages/effects/run-footstep-dust/vfx-params.json +27 -0
  272. package/packages/effects/space-shared.ts +120 -0
  273. package/packages/effects/thruster-flame/index.ts +305 -0
  274. package/packages/effects/thruster-flame/vfx-params.json +5 -0
  275. package/packages/effects/tree-chop-dust/assets/textures/tree_chop_dust_atlas.png +0 -0
  276. package/packages/effects/tree-chop-dust/effect.json +8 -0
  277. package/packages/effects/tree-chop-dust/index.ts +202 -0
  278. package/packages/effects/tree-chop-dust/vfx-params.json +21 -0
  279. package/packages/effects/tree-leaf-chop-burst/assets/runtime/particleEmitter.v1.js +303 -0
  280. package/packages/effects/tree-leaf-chop-burst/assets/textures/tree_leaf_chop_burst_leaf_atlas.png +0 -0
  281. package/packages/effects/tree-leaf-chop-burst/effect.json +498 -0
  282. package/packages/effects/tree-leaf-chop-burst/index.ts +294 -0
  283. package/packages/effects/tree-leaf-chop-burst/vfx-params.json +27 -0
  284. package/packages/effects/tree_chop_dust_burst/assets/runtime/particleEmitter.v1.js +318 -0
  285. package/packages/effects/tree_chop_dust_burst/assets/textures/tree_chop_dust_burst_dust.png +0 -0
  286. package/packages/effects/tree_chop_dust_burst/index.ts +13 -0
  287. package/packages/effects/tree_chop_dust_burst/tree_chop_dust_burst.json +412 -0
  288. package/packages/effects/tree_chop_dust_burst/vfx-params.json +9 -0
  289. package/packages/effects/ufo-thread-flame/assets/textures/flame_flow.webp +0 -0
  290. package/packages/effects/ufo-thread-flame/assets/textures/flame_spike.webp +0 -0
  291. package/packages/effects/ufo-thread-flame/index.ts +152 -0
  292. package/packages/effects/ufo-thread-flame/vfx-params.json +5 -0
  293. package/packages/effects/vehicle-exhaust-smoke/assets/textures/vehicle_exhaust_smoke_atlas.png +0 -0
  294. package/packages/effects/vehicle-exhaust-smoke/effect.json +8 -0
  295. package/packages/effects/vehicle-exhaust-smoke/index.ts +298 -0
  296. package/packages/effects/vehicle-exhaust-smoke/vfx-params.json +23 -0
  297. package/packages/effects/vehicle-upgrade/effect.json +6 -0
  298. package/packages/effects/vehicle-upgrade/index.ts +401 -0
  299. package/packages/effects/vehicle-upgrade/vfx-params.json +21 -0
  300. package/packages/effects/weapon-trail/assets/textures/trail_wedge.png +0 -0
  301. package/packages/effects/weapon-trail/index.ts +313 -0
  302. package/packages/effects/weapon-trail/vfx-params.json +5 -0
  303. package/packages/effects/wood-crusher-sawdust/assets/runtime/particleEmitter.v1.js +312 -0
  304. package/packages/effects/wood-crusher-sawdust/assets/textures/wood_crusher_sawdust_dust.png +0 -0
  305. package/packages/effects/wood-crusher-sawdust/assets/textures/wood_crusher_sawdust_fiber.png +0 -0
  306. package/packages/effects/wood-crusher-sawdust/index.ts +43 -0
  307. package/packages/effects/wood-crusher-sawdust/vfx-params.json +24 -0
  308. package/packages/effects/wood-crusher-sawdust/wood_crusher_sawdust.json +592 -0
  309. package/packages/effects/wood-cutter-sawdust/assets/runtime/particleEmitter.v1.js +312 -0
  310. package/packages/effects/wood-cutter-sawdust/assets/textures/wood_cutter_sawdust_chip.png +0 -0
  311. package/packages/effects/wood-cutter-sawdust/assets/textures/wood_cutter_sawdust_dust.png +0 -0
  312. package/packages/effects/wood-cutter-sawdust/index.ts +43 -0
  313. package/packages/effects/wood-cutter-sawdust/vfx-params.json +24 -0
  314. package/packages/effects/wood-cutter-sawdust/wood_cutter_sawdust.json +592 -0
  315. package/packages/effects/wood-sawdust-effect-factory.ts +194 -0
  316. package/packages/effects/wood_crusher_sawdust/assets/runtime/particleEmitter.v1.js +318 -0
  317. package/packages/effects/wood_crusher_sawdust/assets/textures/wood_crusher_sawdust_dust.png +0 -0
  318. package/packages/effects/wood_crusher_sawdust/assets/textures/wood_crusher_sawdust_fiber.png +0 -0
  319. package/packages/effects/wood_crusher_sawdust/index.ts +29 -0
  320. package/packages/effects/wood_crusher_sawdust/vfx-params.json +14 -0
  321. package/packages/effects/wood_crusher_sawdust/wood_crusher_sawdust.json +592 -0
  322. package/packages/effects/wood_cutter_sawdust/assets/runtime/particleEmitter.v1.js +318 -0
  323. package/packages/effects/wood_cutter_sawdust/assets/textures/wood_cutter_sawdust_chip.png +0 -0
  324. package/packages/effects/wood_cutter_sawdust/assets/textures/wood_cutter_sawdust_dust.png +0 -0
  325. package/packages/effects/wood_cutter_sawdust/index.ts +29 -0
  326. package/packages/effects/wood_cutter_sawdust/vfx-params.json +14 -0
  327. package/packages/effects/wood_cutter_sawdust/wood_cutter_sawdust.json +592 -0
  328. package/packages/effects/wood_peel_material_test/assets/runtime/woodPeelMaterialTest.v1.js +196 -0
  329. package/packages/effects/wood_peel_material_test/index.ts +11 -0
  330. package/packages/effects/wood_peel_material_test/vfx-params.json +9 -0
  331. package/packages/effects/wood_peel_material_test/wood_peel_material_test.json +136 -0
  332. package/packages/env.particle.forest_edge_fog/assets/runtime/particleEmitter.v1.js +210 -0
  333. package/packages/env.particle.forest_edge_fog/assets/textures/f12a23c4-b924-4322-a260-3d982428f1e8.png +0 -0
  334. package/packages/env.particle.forest_edge_fog/assets/textures/yuan.png +0 -0
  335. package/packages/env.particle.forest_edge_fog/effect.json +854 -0
  336. package/packages/env.particle.forest_edge_fog/media/preview.gif +0 -0
  337. package/packages/env.particle.forest_edge_fog/media/preview.mp4 +0 -0
  338. package/packages/env.particle.forest_edge_fog/media/preview.webm +0 -0
  339. package/packages/env.particle.forest_edge_fog/media/thumbnail.png +0 -0
  340. package/packages/env.particle.forest_edge_fog/metadata/description.json +148 -0
  341. package/packages/env.particle.forest_edge_fog/provenance/03-effect.original.json +827 -0
  342. package/packages/env.particle.forest_edge_fog/provenance/03-normalized-vfx-to-babylon-report.json +196 -0
  343. package/packages/env.particle.forest_edge_fog/provenance/04-preview-overrides.json +432 -0
  344. package/packages/env.particle.forest_edge_fog/provenance/04-preview-tuning-report.json +28 -0
  345. package/packages/env.particle.forest_edge_fog/provenance/asset-map.json +124 -0
  346. package/packages/env.particle.forest_edge_fog/provenance/lineage.json +41 -0
  347. package/packages/generation.ts +14 -0
  348. package/packages/index.ts +14 -0
  349. package/packages/legacy-particle-runtime.ts +113 -0
  350. package/packages/manifestRuntimePackage.ts +519 -0
  351. package/packages/registry.ts +85 -0
  352. package/packages/rendering.ts +13 -0
  353. package/packages/resource.particle.viscous_oil_suction/assets/runtime/top_disk_suction/particleEmitter.v1.js +424 -0
  354. package/packages/resource.particle.viscous_oil_suction/assets/textures/Glow ad.png +0 -0
  355. package/packages/resource.particle.viscous_oil_suction/effect.json +1254 -0
  356. package/packages/resource.particle.viscous_oil_suction/media/preview.gif +0 -0
  357. package/packages/resource.particle.viscous_oil_suction/media/preview.mp4 +0 -0
  358. package/packages/resource.particle.viscous_oil_suction/media/preview.webm +0 -0
  359. package/packages/resource.particle.viscous_oil_suction/media/thumbnail.png +0 -0
  360. package/packages/resource.particle.viscous_oil_suction/metadata/description.json +122 -0
  361. package/packages/resource.particle.viscous_oil_suction/provenance/03-effect.original.json +1051 -0
  362. package/packages/resource.particle.viscous_oil_suction/provenance/03-normalized-vfx-to-babylon-report.json +200 -0
  363. package/packages/resource.particle.viscous_oil_suction/provenance/04-preview-overrides.json +581 -0
  364. package/packages/resource.particle.viscous_oil_suction/provenance/04-preview-tuning-report.json +28 -0
  365. package/packages/resource.particle.viscous_oil_suction/provenance/asset-map.json +111 -0
  366. package/packages/resource.particle.viscous_oil_suction/provenance/lineage.json +45 -0
  367. package/packages/types.ts +107 -0
  368. package/tooling/check-dist-runtime.mjs +166 -0
  369. package/tooling/generate-index.mjs +55 -0
  370. package/tooling/test-guardrails.mjs +157 -0
  371. package/tooling/validate-boundary.mjs +92 -0
  372. package/tooling/validate-effects.mjs +304 -0
  373. package/tooling/validate.mjs +53 -0
  374. package/tooling/vfx-cli.mjs +232 -0
  375. package/tooling/vfx-package-resolution.mjs +28 -0
@@ -0,0 +1,152 @@
1
+ import { TransformNode } from "@babylonjs/core/Meshes/transformNode";
2
+ import { Mesh } from "@babylonjs/core/Meshes/mesh";
3
+ import { VertexData } from "@babylonjs/core/Meshes/mesh.vertexData";
4
+ import { CreatePlane } from "@babylonjs/core/Meshes/Builders/planeBuilder";
5
+ import { StandardMaterial } from "@babylonjs/core/Materials/standardMaterial";
6
+ import { Texture } from "@babylonjs/core/Materials/Textures/texture";
7
+ import { Color3 } from "@babylonjs/core/Maths/math.color";
8
+ import { Constants } from "@babylonjs/core/Engines/constants";
9
+ import { L as LIFETIME_DEBUG_PARAMS, a as LIFETIME_DEFAULTS, b as makeFlareTexture, s as scheduleLifetime } from "../../chunks/space-shared-BXV1hc0k.js";
10
+ const arcTextureUrl = "data:image/webp;base64,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";
11
+ const noiseTextureUrl = "data:image/webp;base64,UklGRgwSAABXRUJQVlA4IAASAAAwjwCdASoAAQABPlEij0WjoaElo/CMeLAKCWltKoDEakinDLChYXM/vp1V/PuGaojxG/pNgDPVf/HmH/ev/lwPDP3HWA9/cz+cYhGGLIM7k+k6AubAi8fS2X3thc3/i5V5Lu6Fh5H7wm1s76asUseSl50PV7VM2G0YnHdmPG0cTbZSi0ekVDsrAgGI/Fe4A6cFfVKHVBnop8knXCJscEnNMCOqbZJWheqdcwLJK4IwYRh7tU0jJB1ASfT8PCyPjnzmjXrk+DGVM2lDaWLBZmoobYCtTCuVmsAe0ZhS4e3AL+yal7gcgy/n66gF82TjXLS3AM9dFFzMCzUexDonKPAR4SRKxpdLqxlc92tuvjYbVEaObjj9Dsut0yiJyMZnsKHaY0e3WHYGZrnAIKpyTxtkNIXJneVPYz9C2LPHDDQB2718NpJdzD8Xn7KWUBBpEA4oSfLWBCPbpGB6ybKZP5d1HHFc/dj481vhln+QJGXhgZ3sybavcU8EXXgnFcp7pIfWmYTnRJlmW+vhssZKkCB1fJ/BplSN99dZvnyOLGR5mPvqZWDwdXBp1SYdD9IcoRpOUHIXKM5mXtahKIR8U6/TAF8un9PU7ls9yIduZ8qdBOLgiWnU2hsi/QWZrErzRHYLoJULlzR0/pSlMZf3zPa4sRWViLp9Eabl/cIJrP08zlDm1/kuiDRLrJrBwFYpA687yWYgXC/cKoGvwh068dVSwMkLsBTyijLbefB6i47Ba6/wGtVJpZRrkRVpJblUDurLyOeQktqfgiIPNcSAD04qV71Ie2KD0snh7p3YzLkvYUHB0TU1g7IXc7Kuarr73DAzBvD2HKuIut+Vmn8s+OTHkXjdq2QUs5gTTFGPbmf5CD8RT5Ge6QIzycfym5Y1pLHQt5nhxACj0SG4rInOkgwmc0Ya0lb8hqNZvPZEw2iYN76FNwBhJQunFSUEG4vFAPsuHnq5W05rNIuFrrs5HGtBi2Aj5Vt1ENidqTeYVQizkS4+Bfp0B+4HBYT1yFi+cPgeLqPOxoCq7DJSyVbJhX75nE3T5MoFmW5c3D28uJMMEBfOns3qK+/9jjtamu/gzrpb9/10svlP9tCsjg/twlIy9aD0F8vXhZsP6750IAzUL5fmE23DeLnK4QrnUaiHQrhIaQ2EpNmimD72EeoOn1vhDYP5VQIwYumfP2878d76QHqRp0E4SdqIxioX75QCWHqqnV8FsYfuuo4zGVbkGvdUFd64wC33bFwZvIyU1i0NAiobwJLRrM0JTSnZc7CpXUyvi5xJteFciIrs/jKp9uOzDstjqAVH8d64C3o4F6ljs3P1Po0Cm0qv69MiJd78YFJrPYz73fPY8vBDZijKCBO06d9QbaAhpC/ZsxzcNXgSuhYBLHtMHCv/rndNDmCdefEpdbKfzBDmwaaiDhZrKGyfafaNFj+emNzyBUgrO8OmZkg1LBSov+oRmJX8QcYIofriOzS1lP80J/rFbXYByGKGs0HzW69HFdLJu7125asXWSePSZJ4DUZaefzZXEBark6YQAD+82yD7qA8+NLSkrHAU8GOeWvSttZJXiDl++MUPBzt7q7robk10d1spP6FRB6W8xois2NJCpuu4UdAjKVfnkLHwJBid/7GmhUF14l2eXGNPNdA7TGiT4M72T6J42PrrP3y8vtqMMv1v4Re73IkPUvUAsGXhJjFciTcTrVCWfaXi5RUuE8AU2LXZsrcfpt678KSc8V4Xab58lddNzvMKPWgLxvwN5ZL/25jnLtwDH4r7HV2rPraGmup6XPpX0rX/YpRj2pvPZqK9c0dArBQUeHGpS+TfCJlIgQxBzJNCFBqbe8KiV3N26iJe7KfQ0CvAfmmZEF1IpBiNaK4FSDsNG8jbDtaRT3+JPLit1eK0KFnnD+L61GuVJN36QeAoddaMHcxPanY9GqGvUq7wZHZB0V6hJLqmiJcZamD80ZdWwu1uwE7B838K3ylOQ6uSWmzzHg1unzS40z4fJVNSgLK21jU0rzTvoXn+G2Eu0FVEE5QI0KG9FvN/sXjlJNAw4V5viy9yF9hlPWtuSUUIyDADQKjm5paM5XThyjkRMd9k9JuEwv7J5iy1onxZ8VwxutdmyUJ5OImNsi9F5HI351x95OpEXF0kb3eT6dEI0icp/4iuMBLWQZyVDBOLIiEjwef3w/ok88w2KMKMJ0oSAemrJT3tFsoRgPe6H946RyDgHRvb9EllzfktGFzbJFYielWH/7EvCOrW6KqtbJzw7vKXzkJEYP3JXI+FtCtRXLMN4m5Zu8KbwgZgWhuxDeRnWZ1SqSmkhPoJle8ybMGBw1cdb3Z5jSN+60jBaJ2qc0J0PMekaLmJF4Okb3QfSSFo0sDwpK1kb79PXrInvZr9hrtDcbqZwsPzfhZZZ510CV4uH0Kozd9zo+MgPdfuXQHwbIdJKwtWPeli2LhvZJlfKpyYfaCtnudslo6mBP8CLTGZNmHXlJzbXSxLhYos6vT65IW+TtgOkbPacDgWoJU/Firvlsk3wtyI3twsdCMUXwKLbaPE6uSUznEMpID/IhxVRioGtEjCBLVTO4EpIXePeRC2tB6tGwKP2MAD+9yb/HZ+WtfuWAk33qwwVeAv6ibKzzhU51TBbtXoX87E5v23piL6z53PRF0TNLsW0OlRivwdN6CXE0pXVNZrYwhVwEEhAOj+YS7a0zt1yixeUrPyB+t+OaFKPpTYhIC2zR/t2/k+UvvYAavQ9ngvosyDivyk0mHGkQymJNR54aeUGzB1NdTJBVe0jAgwNk3PyzqT4IA8KyRb09M30LK04j/+PTyZZsBZ4sUMd2IOv/PezUcfobMWwscZQrn9i3/xh5JyItfJM6q7dYs3v1ywDpt30Or16Zg6aGdxH9/kwJlo8HAssmZ9prlJnWEXzlR/dHfF2g2qjNBaYqLltZhONP3+piPsrMc6vxR+oSLWI7ghg7f21hBkgJGgaA8LoPUpAkY/DfyOfAzQCkPpm7KQXu4Z0liXHG/Ba7q1Lku/6z8P7I9qbpqOMIOKi0a/PtSUJzH+A+HUbB8Av9Hcz0QtOPBztAnSZFVU898UFZQNoy24QzDWbqYYHdfzikTFmcm8Y/RUTHe+BFx26ZKZU4Y8tnJpdxIgRyOYeQvX/qNGuOJMTTk8Orft/gajkyLTuP5gPDz1C8sL2pB2n9ayJ2lR6kHqbQG95WBq/QCbVAPQVPxJj0QsNnHPu9c/vbB/TZBBnDl/FuaFjBceJM0Fd2cEU3iy4rVr559CdnRXUubGluY0jjqay5RzEj16Chv/rsnx5JayRviD/ggV8xLLy41f/HPSSU1wY5OpIlkG3DA1HF6F1Tu7Iu4FmUB/FMbFda0U8+pUAXT0TJ6HiBc2GuDaicYmkbxeW5vQKkHn60xTxsBhADDlYlZPufzGhC6zbml1d2mACbZDAUk2Xdh9Qfcnb2EBAK83I8HYxb3ZAh8oiu0BVYnJ97ppv00myKeQniHxSalBlQ9meX3V9d6ePXFDzmNwbGSjgfD5/+rK5hkZUMAwbnIdum+VFiIUXSxlip7b6KhEHFxM524/GIqwENgm7LnhrudeJ4joNdYwYl6dNKxNNP9oOa9M6xVuZ/ygvSJ9KoH3wk89ShIFEzRJIY0BtKjiGSjE1oXJxder3AuyrdQsw1ah84Y4MojRLO95wiXm2mW9jI7YBmsaf39w6R0K1qrfiRT0Q208eNVCZ7KEgtL+/N1/pD8t5Za2x9YZSLV2f46cwx+UCmhkDAU6gFjPZ8JIFnNKulZTglSb7ww1qkUZyYI6oAUy+1n+W09/15CD6MrE6HH4wapcViywiXiCRmxTREX51G6AZrGt5yBTIVxGJk97EyYeAXx4fnMSztUTSDOtybw3mTpOxpKk9Qi6go4yp8ADZdEde76aS/fZ4WnhQI9Ewq0HVIi0TU5ERpNZED7NcF9ckcNfotyTFYd+6RyTAhn2yKpyPNAorJOSYgv/HOnxFzAOUj2Autmn1qJ05Ydterf2W/neD7rN/WGUmbA2/aZrwmAHzktLNTQmEBf8N1iwK5J6xdh3uvSiZOCza54JUuavQt5PiqwUogF1O8pJBYAA5a4uIBSqVAYrgBXEvU6Df7wYbbJd6MsqbCzHCU3Wf4NoEDpUKSwa27vgbvuGogctV9LN2VN6icxfA8+yZo3oFEHC+tOenMLSRDOR7KJ76X7TzZmBh+mwmHzXXuWvclBftLRE+CNf2sL0hdPvu0Oc3zYAZ5bonPwMrEJSnhrfNrQ19piAa4LTvaRfSOrcPE1a18Gyo8gqR/mCUeFXw9tp+881HqQIuBWps267+QuXFw1mYhfC8Y8uRajSi3AYW9/Xrl+P3SplF2k1qH6ZWoL2Katy0BRZLtnKaBk69yGXJNkcGMQVuDWM54R0Yow6e5gnMPlcAeiEc15BMluSXVe7v6YZAAEv9YENr3UrvXRal7BVNw6bMQnprP/B7BVOSThRZ9fB4Iaa5mCsc1JZZmREedhFsJKyJ6wsrl5atDYoLa3w4OFdR+Qe/wBZ8f3GnyZP7AoyTldJlmrA8eF/PVbBpZtZ0TaDDiGBED5lB/0cdjbFDGBTxDrCc3Isbm7hNpPyNzXKCl7ivDiRi6qvq40TS+V9d8bF93husZopD9UqcZ21q3aE/eEFdA9/YQNbt/q41wOU+a3gqGZ2jsD7TqvBYMkoUWaNN0MeXUXpNseWmSeX4f7NNwq7WqrHkzV2AvcZIQylGEI173GljgMJ/4GVy2Qw1iNhrOu6FxURJbANU8gJW3kOS0QFuQFqSybbx/2EyQlNSs2PqZrNcHROfTqkknVGnPaQWr959jFtcOt7u0okzKIn5TD5z1Sro+hwwX6KiJ8LoQDFUlt66/LNGIapTVkQEZZj/rVFrFyHj1PF2MuptF0a1gigAk1yIv8aFzd9zcJ5WSPbe20C/hejSwK3+ltgl+MuJTn4VMvJIoiDh0QejMa9F6ZRp5yI+0Wl76XgPNIv85aZ/M3getXU5aG7oDwyLY5qTPNv6t4yclynjqDjLlnjPkreANRkUR2wLPkYQaonSolW3jrnyrCU9NRC8U75AfBCOtc3GWPN4BObVLtOKZ75AnwHmE9eXF3intsv0NMd7JriLsz64SV6C1UvRZQfMLUsddmSfmUVicwjHVovOKyysvaEqL2dW1L0mrPR14f8jlePwfaBZWq/MAcbNfu7oNV0DjyoOro8ffoiyPsgAJWNFsvrg053ydIzmq7TLj7d3R3cd28BJjq6zck2hgeiPnZ/f6LTVbKKmAyPR8e4ergTcXcqCm2rPo1EIvS1nnSwpI9wr/36XWpKwimZO7bjJK1kTI4o17fiJuTCK8F/QMop6fCjpwOoK2nSz7VypQX5Bsp+GpEyFWMIUIpARuYTEgvNv/tSOBUK9aOmp+E3kQz0NKqyqpzeBm+4fNeSIIIpsdR6I0RwuQg9TJt8f6WMK5P9NemqBpGhqqnQr4oN2FXYSsCxmY9N7MU0Rbu9fIaKvIzeiv7kl41q/AACNn6JS6TgiXTpu6XKpH7KMiglNdwHQ6/MdJNSiPzf56XO9Slq/leUe45HinVW0OWdLlWPrizoUt0wifkNmAFt/5KBi7582NEX3ycr7C5RlLfod3O/FosQUEoJG6AOLQL9fil69AnCztJsid4YfI/7gV4gFzdSq2YMQ9RAdezxO90XK6UfCtnWHiy18hQ1UaYZxeBj7k5zbRcFbNvwGtK3NokwP6lBFcMfD43VcNJkRGpJ2Fm2wbPJrhGYdaD49LkubohNSu5F7xG9o0vMafuino6PbiH540e95x2Wal5cq+39HA0miAKi7RnLGFPfUpIgbnAlIHs1OALW89zOoIebvrZkkxSAylNlmkh+BcnJVHdu97VztHZ5YuKnVMfC1a2kRtc2+YBhgU03Ahu7JXP9esU35oJurLzssGXDf4DrHAlZtWWf2eE383nBBxMMcwlYDcWtE0K+82FQmC1GYjFB6zwLOz7CR4LC6pbcANlnuKP1G8/1N68gu5AyKGQYg8AvBZhJLuP+FtkTO0QYyaPA/VPTlFa3zcXvkc8HejGDKBtND0oN+pmseogsZcfDzgqBhuTdWtSedcLSsH7vI483XubQ+/w9kOvjYxAaXpDnwAAAAA=";
12
+ function createBeamPlaneGeo(name, width, axis, scene) {
13
+ const h = width / 2;
14
+ const positions = axis === "x" ? [-h, 0, 0, h, 0, 0, h, 0, 1, -h, 0, 1] : [0, -h, 0, 0, h, 0, 0, h, 1, 0, -h, 1];
15
+ const normals = axis === "x" ? [0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0] : [1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0];
16
+ const uvs = [0, 0, 0, 1, 1, 1, 1, 0];
17
+ const indices = [0, 1, 2, 0, 2, 3];
18
+ const mesh = new Mesh(name, scene);
19
+ const vd = new VertexData();
20
+ vd.positions = positions;
21
+ vd.normals = normals;
22
+ vd.uvs = uvs;
23
+ vd.indices = indices;
24
+ vd.applyToMesh(mesh);
25
+ return mesh;
26
+ }
27
+ function createLaserBeamEffectPackage(id, nameZh, core) {
28
+ const defaultParams = { ...LIFETIME_DEFAULTS, ...core };
29
+ return {
30
+ id,
31
+ nameZh,
32
+ defaultParams,
33
+ debugAnchor: "playerRight",
34
+ debugParams: [
35
+ ...LIFETIME_DEBUG_PARAMS,
36
+ { key: "width", label: "束宽", kind: "scale", min: 0.05, max: 2, step: 0.01 },
37
+ { key: "intensity", label: "强度", kind: "number", min: 0.1, max: 3, step: 0.05 },
38
+ { key: "laserSpeed", label: "纹理流速", kind: "number", min: 0, max: 20, step: 0.5 },
39
+ { key: "targetDistance", label: "目标距离", kind: "number", min: 2, max: 40, step: 0.5 }
40
+ ],
41
+ create({ scene, root, position, rotationY, params }) {
42
+ root.position.copyFrom(position);
43
+ root.rotation.y = rotationY;
44
+ const { width, intensity } = params;
45
+ const segLen = width * 5;
46
+ const arcTex = new Texture(arcTextureUrl, scene);
47
+ arcTex.wrapU = Texture.WRAP_ADDRESSMODE;
48
+ const arcMat = new StandardMaterial("vfx_laser_arcMat", scene);
49
+ arcMat.emissiveTexture = arcTex;
50
+ arcMat.opacityTexture = arcTex;
51
+ arcMat.emissiveColor = new Color3(0.45 * intensity, 0.62 * intensity, 1.35 * intensity);
52
+ arcMat.disableLighting = true;
53
+ arcMat.backFaceCulling = false;
54
+ arcMat.alphaMode = Constants.ALPHA_ADD;
55
+ const noiseTex = new Texture(noiseTextureUrl, scene);
56
+ noiseTex.wrapU = Texture.WRAP_ADDRESSMODE;
57
+ const noiseMat = new StandardMaterial("vfx_laser_noiseMat", scene);
58
+ noiseMat.emissiveTexture = noiseTex;
59
+ noiseMat.opacityTexture = noiseTex;
60
+ noiseMat.opacityTexture.getAlphaFromRGB = true;
61
+ noiseMat.emissiveColor = new Color3(0.2 * intensity, 0.35 * intensity, 0.9 * intensity);
62
+ noiseMat.disableLighting = true;
63
+ noiseMat.backFaceCulling = false;
64
+ noiseMat.alphaMode = Constants.ALPHA_ADD;
65
+ const beamRoot = new TransformNode("vfx_laser_beamRoot", scene);
66
+ beamRoot.parent = root;
67
+ const planes = [];
68
+ const layout = [
69
+ ["x", arcMat, width],
70
+ ["y", arcMat, width],
71
+ ["x", noiseMat, width * 1.9],
72
+ ["y", noiseMat, width * 1.9]
73
+ ];
74
+ for (const [axis, mat, w] of layout) {
75
+ const p = createBeamPlaneGeo(`vfx_laser_p${planes.length}`, w, axis, scene);
76
+ p.material = mat;
77
+ p.parent = beamRoot;
78
+ p.isPickable = false;
79
+ planes.push(p);
80
+ }
81
+ const flareTex = makeFlareTexture(scene, "vfx_laser_flare");
82
+ function makeFlare(name, size) {
83
+ const f = CreatePlane(name, { size }, scene);
84
+ f.billboardMode = Mesh.BILLBOARDMODE_ALL;
85
+ const m = new StandardMaterial(name + "Mat", scene);
86
+ m.emissiveTexture = flareTex;
87
+ m.opacityTexture = flareTex;
88
+ m.emissiveColor = new Color3(0.7, 0.85, 1.6);
89
+ m.disableLighting = true;
90
+ m.alphaMode = Constants.ALPHA_ADD;
91
+ f.material = m;
92
+ f.isPickable = false;
93
+ f.parent = root;
94
+ return f;
95
+ }
96
+ const muzzleFlare = makeFlare("vfx_laser_muzzle", width * 3.2);
97
+ const hitFlare = makeFlare("vfx_laser_hit", width * 3.2);
98
+ let time = 0;
99
+ const observer = scene.onBeforeRenderObservable.add(() => {
100
+ const dt = Math.min(scene.getEngine().getDeltaTime() / 1e3, 0.05);
101
+ time += dt;
102
+ const dist = params.targetDistance;
103
+ beamRoot.scaling.z = dist;
104
+ const tiles = Math.max(1, dist / segLen);
105
+ arcMat.emissiveTexture.uScale = tiles;
106
+ arcMat.opacityTexture.uScale = tiles;
107
+ arcMat.emissiveTexture.uOffset -= params.laserSpeed * dt;
108
+ arcMat.opacityTexture.uOffset = arcMat.emissiveTexture.uOffset;
109
+ noiseMat.emissiveTexture.uScale = tiles * 0.6;
110
+ noiseMat.emissiveTexture.uOffset -= params.laserSpeed * 0.31 * dt;
111
+ noiseMat.opacityTexture.uScale = tiles * 0.6;
112
+ noiseMat.opacityTexture.uOffset = noiseMat.emissiveTexture.uOffset;
113
+ const pulse = 1 + Math.sin(time * 24) * 0.18;
114
+ muzzleFlare.position.set(0, 0, 0);
115
+ muzzleFlare.scaling.setAll(pulse);
116
+ hitFlare.position.set(0, 0, dist);
117
+ hitFlare.scaling.setAll(pulse * 1.4);
118
+ });
119
+ let disposed = false;
120
+ let ltTimer = 0;
121
+ const dispose = () => {
122
+ if (disposed) return;
123
+ disposed = true;
124
+ if (ltTimer) window.clearTimeout(ltTimer);
125
+ scene.onBeforeRenderObservable.remove(observer);
126
+ for (const p of planes) p.dispose();
127
+ muzzleFlare.material?.dispose();
128
+ muzzleFlare.dispose();
129
+ hitFlare.material?.dispose();
130
+ hitFlare.dispose();
131
+ beamRoot.dispose();
132
+ arcMat.dispose();
133
+ arcTex.dispose();
134
+ noiseMat.dispose();
135
+ noiseTex.dispose();
136
+ flareTex.dispose();
137
+ root.dispose();
138
+ };
139
+ ltTimer = scheduleLifetime(params, dispose);
140
+ return { root, dispose };
141
+ }
142
+ };
143
+ }
144
+ const laserBeamEffectPackage = createLaserBeamEffectPackage("laser-beam", "激光束", {
145
+ width: 0.55,
146
+ intensity: 1,
147
+ laserSpeed: 7,
148
+ targetDistance: 12
149
+ });
150
+ export {
151
+ laserBeamEffectPackage
152
+ };
@@ -0,0 +1,12 @@
1
+ import { VfxEffectPackage, VfxParamValues } from '../types';
2
+ export interface LaserBeamParams extends VfxParamValues {
3
+ lifetimeMode: string;
4
+ lifetime: number;
5
+ width: number;
6
+ intensity: number;
7
+ laserSpeed: number;
8
+ targetDistance: number;
9
+ }
10
+ type LaserCoreDefaults = Omit<LaserBeamParams, 'lifetimeMode' | 'lifetime'>;
11
+ export declare function createLaserBeamEffectPackage(id: string, nameZh: string, core: LaserCoreDefaults): VfxEffectPackage<LaserBeamParams>;
12
+ export {};
@@ -0,0 +1,9 @@
1
+ declare const _default: {
2
+ "id": "lumber-cart-suction",
3
+ "nameZh": "收集车吸入圆环",
4
+ "assets": [],
5
+ "source": "procedural"
6
+ }
7
+ ;
8
+
9
+ export default _default;
@@ -0,0 +1,26 @@
1
+ import { VfxColorValue, VfxEffectPackage, VfxParamValues } from '../../types';
2
+ interface LumberCartSuctionParams extends VfxParamValues {
3
+ lifetime: number;
4
+ scale: number;
5
+ initialHeight: number;
6
+ color: VfxColorValue;
7
+ opacity: number;
8
+ ringCount: number;
9
+ forwardOffset: number;
10
+ suctionLength: number;
11
+ startRadius: number;
12
+ endRadius: number;
13
+ ringWidth: number;
14
+ suctionSpeed: number;
15
+ pulse: number;
16
+ flyingParticleCount: number;
17
+ flyingParticleSize: number;
18
+ flyingParticleSpeed: number;
19
+ flyingParticleDrift: number;
20
+ flyingParticleOuterOffset: number;
21
+ flyingParticleOpacity: number;
22
+ directionX: number;
23
+ directionZ: number;
24
+ }
25
+ export declare const lumberCartSuctionEffectPackage: VfxEffectPackage<LumberCartSuctionParams>;
26
+ export {};
@@ -0,0 +1,322 @@
1
+ import { Color3, Color4 } from "@babylonjs/core/Maths/math.color";
2
+ import { Vector3 } from "@babylonjs/core/Maths/math.vector";
3
+ import { Constants } from "@babylonjs/core/Engines/constants";
4
+ import { DynamicTexture } from "@babylonjs/core/Materials/Textures/dynamicTexture";
5
+ import { StandardMaterial } from "@babylonjs/core/Materials/standardMaterial";
6
+ import { CreateTube } from "@babylonjs/core/Meshes/Builders/tubeBuilder";
7
+ import { ParticleSystem } from "@babylonjs/core/Particles/particleSystem";
8
+ const id = "lumber-cart-suction";
9
+ const nameZh = "收集车吸入圆环";
10
+ const assets = [];
11
+ const source = "procedural";
12
+ const manifest = {
13
+ id,
14
+ nameZh,
15
+ assets,
16
+ source
17
+ };
18
+ const LUMBER_CART_SUCTION_RENDERING_GROUP_ID = 0;
19
+ const DEFAULT_PARAMS = {
20
+ lifetime: 1.8,
21
+ scale: 1,
22
+ initialHeight: 0.18,
23
+ color: { r: 1, g: 0.86, b: 0.42 },
24
+ opacity: 0.95,
25
+ ringCount: 5,
26
+ forwardOffset: 0.4,
27
+ suctionLength: 2.1,
28
+ startRadius: 0.62,
29
+ endRadius: 0.08,
30
+ ringWidth: 0.035,
31
+ suctionSpeed: 1.45,
32
+ pulse: 0.18,
33
+ flyingParticleCount: 42,
34
+ flyingParticleSize: 0.045,
35
+ flyingParticleSpeed: 4.2,
36
+ flyingParticleDrift: 0.22,
37
+ flyingParticleOuterOffset: 0.28,
38
+ flyingParticleOpacity: 0.74,
39
+ directionX: 1,
40
+ directionZ: 0
41
+ };
42
+ const lumberCartSuctionEffectPackage = {
43
+ id: "lumber-cart-suction",
44
+ nameZh: "收集车吸入圆环",
45
+ manifest,
46
+ defaultParams: DEFAULT_PARAMS,
47
+ debugAnchor: "playerRight",
48
+ debugParams: [
49
+ { key: "lifetime", label: "生命周期", kind: "lifetime", min: 0.08, step: 0.01 },
50
+ { key: "scale", label: "整体缩放", kind: "scale", min: 0.05, max: 6, step: 0.01 },
51
+ { key: "initialHeight", label: "初始高度", kind: "number", min: -0.5, max: 3, step: 0.01 },
52
+ { key: "color", label: "圆环颜色", kind: "color" },
53
+ { key: "opacity", label: "透明度", kind: "opacity", min: 0, max: 1, step: 0.01 },
54
+ { key: "ringCount", label: "圆环数量", kind: "number", min: 1, max: 16, step: 1 },
55
+ { key: "forwardOffset", label: "车前偏移", kind: "number", min: -1, max: 4, step: 0.01 },
56
+ { key: "suctionLength", label: "吸入长度", kind: "number", min: 0.1, max: 8, step: 0.01 },
57
+ { key: "startRadius", label: "外圈半径", kind: "number", min: 0.02, max: 4, step: 0.01 },
58
+ { key: "endRadius", label: "入口半径", kind: "number", min: 0.01, max: 2, step: 0.01 },
59
+ { key: "ringWidth", label: "圆环粗细", kind: "number", min: 5e-3, max: 0.25, step: 1e-3 },
60
+ { key: "suctionSpeed", label: "吸入速度", kind: "number", min: 0, max: 8, step: 0.01 },
61
+ { key: "pulse", label: "收缩脉冲", kind: "number", min: 0, max: 1, step: 0.01 },
62
+ { key: "flyingParticleCount", label: "飞行粒子数量", kind: "number", min: 0, max: 180, step: 1 },
63
+ { key: "flyingParticleSize", label: "飞行粒子大小", kind: "number", min: 5e-3, max: 0.3, step: 1e-3 },
64
+ { key: "flyingParticleSpeed", label: "飞行粒子速度", kind: "number", min: 0, max: 16, step: 0.01 },
65
+ { key: "flyingParticleDrift", label: "飞行粒子散布", kind: "number", min: 0, max: 1.5, step: 0.01 },
66
+ { key: "flyingParticleOuterOffset", label: "飞行粒子外偏移", kind: "number", min: -1, max: 2, step: 0.01 },
67
+ { key: "flyingParticleOpacity", label: "飞行粒子透明度", kind: "opacity", min: 0, max: 1, step: 0.01 },
68
+ { key: "directionX", label: "方向 X", kind: "number", min: -1, max: 1, step: 0.01 },
69
+ { key: "directionZ", label: "方向 Z", kind: "number", min: -1, max: 1, step: 0.01 }
70
+ ],
71
+ create({ scene, root, position, params }) {
72
+ root.position.copyFrom(position).addInPlace(new Vector3(0, params.initialHeight, 0));
73
+ const rings = createSuctionRings(scene, root, params);
74
+ let disposed = false;
75
+ rings.start();
76
+ return {
77
+ root,
78
+ dispose() {
79
+ disposeAll();
80
+ }
81
+ };
82
+ function disposeAll() {
83
+ if (disposed) return;
84
+ disposed = true;
85
+ rings.dispose();
86
+ root.dispose();
87
+ }
88
+ }
89
+ };
90
+ function createSuctionRings(scene, root, params) {
91
+ const basis = createRingBasis(params);
92
+ const ringCount = Math.max(1, Math.round(params.ringCount));
93
+ const material = createRingMaterial(scene, params);
94
+ const particles = createFlyingParticleSystem(scene, root, params, basis);
95
+ const rings = [];
96
+ let age = 0;
97
+ let observer = null;
98
+ let disposed = false;
99
+ for (let index = 0; index < ringCount; index += 1) {
100
+ const progress = index / ringCount;
101
+ const ring = CreateTube(`lumber-cart-suction.ring.${index}`, {
102
+ path: buildRingPath(basis, progress, params.pulse),
103
+ radius: basis.ringWidth,
104
+ tessellation: 8,
105
+ updatable: true
106
+ }, scene);
107
+ ring.parent = root;
108
+ ring.material = material;
109
+ ring.renderingGroupId = LUMBER_CART_SUCTION_RENDERING_GROUP_ID;
110
+ ring.isPickable = false;
111
+ rings.push(ring);
112
+ }
113
+ return { start, dispose };
114
+ function start() {
115
+ if (observer) return;
116
+ particles.start();
117
+ observer = scene.onBeforeRenderObservable.add(() => {
118
+ if (disposed) return;
119
+ const deltaSeconds = Math.min(0.05, scene.getEngine().getDeltaTime() / 1e3);
120
+ age += deltaSeconds;
121
+ for (let index = 0; index < rings.length; index += 1) {
122
+ const progress = fract(age * Math.max(0, params.suctionSpeed) + index / rings.length);
123
+ CreateTube(`lumber-cart-suction.ring.${index}`, {
124
+ path: buildRingPath(basis, progress, params.pulse),
125
+ radius: basis.ringWidth,
126
+ tessellation: 8,
127
+ instance: rings[index]
128
+ }, scene);
129
+ }
130
+ const pulse = Math.sin(age * Math.max(0.1, params.suctionSpeed) * Math.PI * 2) * Math.max(0, params.pulse);
131
+ material.alpha = clamp01(params.opacity * (0.88 + pulse * 0.12));
132
+ });
133
+ }
134
+ function dispose() {
135
+ if (disposed) return;
136
+ disposed = true;
137
+ if (observer) scene.onBeforeRenderObservable.remove(observer);
138
+ observer = null;
139
+ for (const ring of rings) ring.dispose();
140
+ particles.stop();
141
+ particles.dispose(false);
142
+ material.dispose();
143
+ }
144
+ }
145
+ function createRingBasis(params) {
146
+ const scale = Math.max(0.01, params.scale);
147
+ const forward = new Vector3(params.directionX, 0, params.directionZ);
148
+ if (forward.lengthSquared() < 1e-4) forward.set(1, 0, 0);
149
+ forward.normalize();
150
+ return {
151
+ forward,
152
+ side: new Vector3(-forward.z, 0, forward.x),
153
+ up: Vector3.Up(),
154
+ mouth: forward.scale(params.forwardOffset * scale),
155
+ length: Math.max(0.01, params.suctionLength * scale),
156
+ startRadius: Math.max(1e-3, params.startRadius * scale),
157
+ endRadius: Math.max(1e-3, params.endRadius * scale),
158
+ ringWidth: Math.max(2e-3, params.ringWidth * scale)
159
+ };
160
+ }
161
+ function buildRingPath(basis, progress, pulse) {
162
+ const points = [];
163
+ const segments = 72;
164
+ const eased = easeInCubic(clamp01(progress));
165
+ const distance = basis.length * (1 - eased);
166
+ const pulseScale = 1 + Math.sin(progress * Math.PI * 2) * Math.max(0, pulse) * 0.12;
167
+ const radius = lerp(basis.endRadius, basis.startRadius, 1 - eased) * pulseScale;
168
+ const center = basis.mouth.add(basis.forward.scale(distance));
169
+ for (let index = 0; index <= segments; index += 1) {
170
+ const angle = index / segments * Math.PI * 2;
171
+ points.push(
172
+ center.add(basis.side.scale(Math.cos(angle) * radius)).add(basis.up.scale(Math.sin(angle) * radius))
173
+ );
174
+ }
175
+ return points;
176
+ }
177
+ function createRingMaterial(scene, params) {
178
+ const material = new StandardMaterial("lumber-cart-suction.ring.material", scene);
179
+ const color = toColor3(params.color);
180
+ material.diffuseColor = color;
181
+ material.emissiveColor = color.scale(1.35);
182
+ material.alpha = params.opacity;
183
+ material.disableLighting = true;
184
+ material.backFaceCulling = false;
185
+ material.alphaMode = Constants.ALPHA_ADD;
186
+ return material;
187
+ }
188
+ function createFlyingParticleSystem(scene, root, params, basis) {
189
+ const scale = Math.max(0.01, params.scale);
190
+ const count = Math.max(0, Math.round(params.flyingParticleCount));
191
+ const speed = Math.max(0.01, params.flyingParticleSpeed * scale);
192
+ const particleLife = clampNumber(basis.length / speed, 0.18, 0.85);
193
+ const system = new ParticleSystem("lumber-cart-suction.flying-particles", Math.max(8, count * 2), scene);
194
+ const size = Math.max(1e-3, params.flyingParticleSize * scale);
195
+ const color = params.color;
196
+ const opacity = clamp01(params.flyingParticleOpacity * params.opacity);
197
+ system.isLocal = false;
198
+ system.renderingGroupId = LUMBER_CART_SUCTION_RENDERING_GROUP_ID;
199
+ system.particleTexture = getFlyingParticleTexture(scene);
200
+ system.emitter = root;
201
+ system.emitRate = count / particleLife;
202
+ system.updateSpeed = 1 / 60;
203
+ system.minLifeTime = particleLife * 0.72;
204
+ system.maxLifeTime = particleLife * 1.12;
205
+ system.minSize = size * 0.72;
206
+ system.maxSize = size * 1.28;
207
+ system.minAngularSpeed = -4;
208
+ system.maxAngularSpeed = 4;
209
+ system.minEmitPower = 1;
210
+ system.maxEmitPower = 1;
211
+ system.gravity = Vector3.Zero();
212
+ system.blendMode = ParticleSystem.BLENDMODE_ADD;
213
+ system.color1 = tintColor(color, 1.5, opacity * 0.78);
214
+ system.color2 = tintColor(color, 2.1, opacity);
215
+ system.colorDead = tintColor(color, 0.8, 0);
216
+ system.addColorGradient(0, tintColor(color, 1.1, 0));
217
+ system.addColorGradient(0.2, tintColor(color, 2.2, opacity));
218
+ system.addColorGradient(0.72, tintColor(color, 1.55, opacity * 0.68));
219
+ system.addColorGradient(1, tintColor(color, 0.8, 0));
220
+ system.addSizeGradient(0, size * 0.46, size * 0.72);
221
+ system.addSizeGradient(0.22, size * 0.9, size * 1.28);
222
+ system.addSizeGradient(1, size * 0.18, size * 0.36);
223
+ system.startPositionFunction = (worldMatrix, positionToUpdate, _particle, isLocal) => {
224
+ const local = sampleFlyingParticlePosition(basis, params);
225
+ if (isLocal) positionToUpdate.copyFrom(local);
226
+ else Vector3.TransformCoordinatesToRef(local, worldMatrix, positionToUpdate);
227
+ };
228
+ system.startDirectionFunction = (worldMatrix, directionToUpdate, particle, isLocal) => {
229
+ const id2 = flyingParticleDirectionSequenceIndex;
230
+ flyingParticleDirectionSequenceIndex += 1;
231
+ const localPosition = particle.position.clone();
232
+ const localTarget = basis.mouth.add(
233
+ basis.side.scale((sequence01(id2, 3) - 0.5) * basis.endRadius * 0.6)
234
+ ).addInPlace(
235
+ basis.up.scale((sequence01(id2, 4) - 0.5) * basis.endRadius * 0.5)
236
+ );
237
+ const target = isLocal ? localTarget : Vector3.TransformCoordinates(localTarget, worldMatrix);
238
+ const direction = target.subtract(localPosition);
239
+ if (direction.lengthSquared() < 1e-4) {
240
+ const fallback = basis.forward.scale(-1);
241
+ if (isLocal) direction.copyFrom(fallback);
242
+ else Vector3.TransformNormalToRef(fallback, worldMatrix, direction);
243
+ } else direction.normalize();
244
+ const drift = Math.max(0, params.flyingParticleDrift) * scale;
245
+ const localTangent = basis.side.scale((sequence01(id2, 5) - 0.5) * drift).addInPlace(basis.up.scale((sequence01(id2, 6) - 0.5) * drift * 0.65));
246
+ const tangent = isLocal ? localTangent : Vector3.TransformNormal(localTangent, worldMatrix);
247
+ direction.scaleInPlace(speed * lerp(0.78, 1.28, sequence01(id2, 7))).addInPlace(tangent);
248
+ directionToUpdate.copyFrom(direction);
249
+ };
250
+ return system;
251
+ }
252
+ function sampleFlyingParticlePosition(basis, params) {
253
+ const id2 = flyingParticleSequenceIndex;
254
+ flyingParticleSequenceIndex += 1;
255
+ const scale = Math.max(0.01, params.scale);
256
+ const outerOffset = params.flyingParticleOuterOffset * scale;
257
+ const distanceRatio = lerp(0.68, 1.02, sequence01(id2, 0));
258
+ const radiusRatio = lerp(0.38, 0.92, Math.sqrt(sequence01(id2, 1)));
259
+ const angle = sequence01(id2, 2) * Math.PI * 2;
260
+ const radius = lerp(basis.endRadius, basis.startRadius, clamp01(distanceRatio)) * radiusRatio;
261
+ return basis.mouth.add(basis.forward.scale(basis.length * distanceRatio + outerOffset)).addInPlace(basis.side.scale(Math.cos(angle) * radius)).addInPlace(basis.up.scale(Math.sin(angle) * radius));
262
+ }
263
+ function getFlyingParticleTexture(scene) {
264
+ const key = "__vfx_lumber_cart_suction_particle_texture";
265
+ const metadata = scene.metadata && typeof scene.metadata === "object" ? scene.metadata : {};
266
+ scene.metadata = metadata;
267
+ const existing = metadata[key];
268
+ if (existing) return existing;
269
+ const texture = new DynamicTexture("lumber_cart_suction_particle_texture", { width: 64, height: 64 }, scene, true);
270
+ const context = texture.getContext();
271
+ context.clearRect(0, 0, 64, 64);
272
+ const dot = context.createRadialGradient(32, 32, 1, 32, 32, 30);
273
+ dot.addColorStop(0, "rgba(255, 255, 255, 1)");
274
+ dot.addColorStop(0.48, "rgba(255, 255, 255, 0.92)");
275
+ dot.addColorStop(0.78, "rgba(255, 255, 255, 0.42)");
276
+ dot.addColorStop(1, "rgba(255, 255, 255, 0)");
277
+ context.fillStyle = dot;
278
+ context.beginPath();
279
+ context.arc(32, 32, 30, 0, Math.PI * 2);
280
+ context.fill();
281
+ texture.hasAlpha = true;
282
+ texture.update(false);
283
+ metadata[key] = texture;
284
+ return texture;
285
+ }
286
+ function toColor3(color) {
287
+ return new Color3(clamp01(color.r), clamp01(color.g), clamp01(color.b));
288
+ }
289
+ function tintColor(color, brightness, alpha) {
290
+ return new Color4(
291
+ Math.max(0, color.r * brightness),
292
+ Math.max(0, color.g * brightness),
293
+ Math.max(0, color.b * brightness),
294
+ clamp01(alpha)
295
+ );
296
+ }
297
+ function lerp(min, max, t) {
298
+ return min + (max - min) * t;
299
+ }
300
+ function clamp01(value) {
301
+ return Math.min(1, Math.max(0, value));
302
+ }
303
+ function clampNumber(value, min, max) {
304
+ return Math.min(max, Math.max(min, value));
305
+ }
306
+ function fract(value) {
307
+ return value - Math.floor(value);
308
+ }
309
+ function easeInCubic(value) {
310
+ const t = clamp01(value);
311
+ return t * t * t;
312
+ }
313
+ function sequence01(index, axis) {
314
+ if (index === 0) return 0.5;
315
+ const strides = [0.618033988749895, 0.414213562373095, 0.732050807568877, 0.324717957244746, 0.754877666246693, 0.569840290998053];
316
+ return fract(0.5 + index * strides[axis % strides.length] + axis * 0.173205080756888);
317
+ }
318
+ let flyingParticleSequenceIndex = 0;
319
+ let flyingParticleDirectionSequenceIndex = 2048;
320
+ export {
321
+ lumberCartSuctionEffectPackage
322
+ };