@fps-games/vfx 0.3.2 → 0.3.3

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 (231) hide show
  1. package/CHANGELOG.md +8 -0
  2. package/package.json +5 -4
  3. package/tooling/vfx-cli.mjs +8 -1
  4. package/docs/AUTHORING_EFFECTS.md +0 -297
  5. package/docs/INTEGRATION.md +0 -194
  6. package/docs/VFX_LIBRARY_ARCHITECTURE_chatgpt.md +0 -1580
  7. package/docs/VFX_LIBRARY_EXECUTION_PLAN.md +0 -229
  8. package/docs/VFX_LIBRARY_PLAN.md +0 -546
  9. package/docs/hit-flash-red-method.md +0 -155
  10. package/docs/treasure_attention_fx_babylonjs_guide.md +0 -901
  11. package/docs/vfx-ab/RESULTS.md +0 -35
  12. package/docs/vfx-ab/lumber-order/vehicle-exhaust-smoke/after.png +0 -0
  13. package/docs/vfx-ab/lumber-order/vehicle-exhaust-smoke/before.png +0 -0
  14. package/docs/vfx-ab/lumber-truck/vehicle-exhaust-smoke/after.png +0 -0
  15. package/docs/vfx-ab/lumber-truck/vehicle-exhaust-smoke/before.png +0 -0
  16. package/docs/vfx-integration_chatgpt.md +0 -462
  17. package/docs/vfx-placement-design.md +0 -164
  18. package/docs/weapon-trail-visualization.html +0 -241
  19. package/packages/EffectPackageService.ts +0 -346
  20. package/packages/SceneVfxService.ts +0 -96
  21. package/packages/build.mesh.yellow_build_upgrade_indicator/assets/runtime/simpleMeshEffect.v1.js +0 -333
  22. package/packages/build.mesh.yellow_build_upgrade_indicator/assets/shaders/mesh-effect-preview.frag.glsl +0 -25
  23. package/packages/build.mesh.yellow_build_upgrade_indicator/assets/shaders/mesh-effect-preview.vert.glsl +0 -11
  24. package/packages/build.mesh.yellow_build_upgrade_indicator/assets/textures/effect_jianbian.png +0 -0
  25. package/packages/build.mesh.yellow_build_upgrade_indicator/effect.json +0 -927
  26. package/packages/build.mesh.yellow_build_upgrade_indicator/media/contact-sheet.png +0 -0
  27. package/packages/build.mesh.yellow_build_upgrade_indicator/media/preview.gif +0 -0
  28. package/packages/build.mesh.yellow_build_upgrade_indicator/media/preview.mp4 +0 -0
  29. package/packages/build.mesh.yellow_build_upgrade_indicator/media/preview.webm +0 -0
  30. package/packages/build.mesh.yellow_build_upgrade_indicator/media/thumbnail.png +0 -0
  31. package/packages/build.mesh.yellow_build_upgrade_indicator/metadata/description.json +0 -197
  32. package/packages/build.mesh.yellow_build_upgrade_indicator/provenance/03-effect.original.json +0 -895
  33. package/packages/build.mesh.yellow_build_upgrade_indicator/provenance/03-normalized-vfx-to-babylon-report.json +0 -241
  34. package/packages/build.mesh.yellow_build_upgrade_indicator/provenance/04-preview-overrides.json +0 -542
  35. package/packages/build.mesh.yellow_build_upgrade_indicator/provenance/04-preview-tuning-report.json +0 -69
  36. package/packages/build.mesh.yellow_build_upgrade_indicator/provenance/asset-map.json +0 -125
  37. package/packages/build.mesh.yellow_build_upgrade_indicator/provenance/lineage.json +0 -44
  38. package/packages/build.particle.golden_upgrade_starburst/assets/runtime/particleEmitter.v1.js +0 -210
  39. package/packages/build.particle.golden_upgrade_starburst/assets/textures/effect_guangdian.png +0 -0
  40. package/packages/build.particle.golden_upgrade_starburst/effect.json +0 -880
  41. package/packages/build.particle.golden_upgrade_starburst/media/contact-sheet.png +0 -0
  42. package/packages/build.particle.golden_upgrade_starburst/media/preview.gif +0 -0
  43. package/packages/build.particle.golden_upgrade_starburst/media/preview.mp4 +0 -0
  44. package/packages/build.particle.golden_upgrade_starburst/media/preview.webm +0 -0
  45. package/packages/build.particle.golden_upgrade_starburst/media/thumbnail.png +0 -0
  46. package/packages/build.particle.golden_upgrade_starburst/metadata/description.json +0 -161
  47. package/packages/build.particle.golden_upgrade_starburst/provenance/03-effect.original.json +0 -762
  48. package/packages/build.particle.golden_upgrade_starburst/provenance/03-normalized-vfx-to-babylon-report.json +0 -260
  49. package/packages/build.particle.golden_upgrade_starburst/provenance/04-preview-overrides.json +0 -436
  50. package/packages/build.particle.golden_upgrade_starburst/provenance/04-preview-tuning-report.json +0 -40
  51. package/packages/build.particle.golden_upgrade_starburst/provenance/asset-map.json +0 -115
  52. package/packages/build.particle.golden_upgrade_starburst/provenance/lineage.json +0 -40
  53. package/packages/build.particle.orange_upgrade_transform_sparks/assets/runtime/particleEmitter.v1.js +0 -210
  54. package/packages/build.particle.orange_upgrade_transform_sparks/assets/textures/b5b27ab1-e740-4398-b407-848fc2b2c897.png +0 -0
  55. package/packages/build.particle.orange_upgrade_transform_sparks/effect.json +0 -887
  56. package/packages/build.particle.orange_upgrade_transform_sparks/media/preview.gif +0 -0
  57. package/packages/build.particle.orange_upgrade_transform_sparks/media/preview.mp4 +0 -0
  58. package/packages/build.particle.orange_upgrade_transform_sparks/media/preview.webm +0 -0
  59. package/packages/build.particle.orange_upgrade_transform_sparks/media/thumbnail.png +0 -0
  60. package/packages/build.particle.orange_upgrade_transform_sparks/metadata/description.json +0 -179
  61. package/packages/build.particle.orange_upgrade_transform_sparks/provenance/03-effect.original.json +0 -859
  62. package/packages/build.particle.orange_upgrade_transform_sparks/provenance/03-normalized-vfx-to-babylon-report.json +0 -260
  63. package/packages/build.particle.orange_upgrade_transform_sparks/provenance/04-preview-overrides.json +0 -478
  64. package/packages/build.particle.orange_upgrade_transform_sparks/provenance/04-preview-tuning-report.json +0 -40
  65. package/packages/build.particle.orange_upgrade_transform_sparks/provenance/asset-map.json +0 -114
  66. package/packages/build.particle.orange_upgrade_transform_sparks/provenance/lineage.json +0 -41
  67. package/packages/build.particle.wood_chip_dust_burst/assets/runtime/particleEmitter.v1.js +0 -210
  68. package/packages/build.particle.wood_chip_dust_burst/assets/textures/effect_yanwu4.png +0 -0
  69. package/packages/build.particle.wood_chip_dust_burst/assets/textures/suipian3.png +0 -0
  70. package/packages/build.particle.wood_chip_dust_burst/effect.json +0 -1400
  71. package/packages/build.particle.wood_chip_dust_burst/media/contact-sheet.png +0 -0
  72. package/packages/build.particle.wood_chip_dust_burst/media/preview.gif +0 -0
  73. package/packages/build.particle.wood_chip_dust_burst/media/preview.mp4 +0 -0
  74. package/packages/build.particle.wood_chip_dust_burst/media/preview.webm +0 -0
  75. package/packages/build.particle.wood_chip_dust_burst/media/thumbnail.png +0 -0
  76. package/packages/build.particle.wood_chip_dust_burst/metadata/description.json +0 -173
  77. package/packages/build.particle.wood_chip_dust_burst/provenance/03-effect.original.json +0 -1277
  78. package/packages/build.particle.wood_chip_dust_burst/provenance/03-normalized-vfx-to-babylon-report.json +0 -329
  79. package/packages/build.particle.wood_chip_dust_burst/provenance/04-preview-overrides.json +0 -749
  80. package/packages/build.particle.wood_chip_dust_burst/provenance/04-preview-tuning-report.json +0 -60
  81. package/packages/build.particle.wood_chip_dust_burst/provenance/asset-map.json +0 -146
  82. package/packages/build.particle.wood_chip_dust_burst/provenance/lineage.json +0 -69
  83. package/packages/effects/building-upgrade/effect.json +0 -6
  84. package/packages/effects/building-upgrade/index.ts +0 -387
  85. package/packages/effects/character-entrance/effect.json +0 -6
  86. package/packages/effects/character-entrance/index.ts +0 -308
  87. package/packages/effects/coin-burst/index.ts +0 -48
  88. package/packages/effects/comet-trail-flame/assets/textures/trail_5x4.webp +0 -0
  89. package/packages/effects/comet-trail-flame/index.ts +0 -107
  90. package/packages/effects/conveyor-upgrade/effect.json +0 -6
  91. package/packages/effects/conveyor-upgrade/index.ts +0 -401
  92. package/packages/effects/debris-smoke/assets/models/rock_debris.glb +0 -0
  93. package/packages/effects/debris-smoke/assets/textures/smoke22.webp +0 -0
  94. package/packages/effects/debris-smoke/index.ts +0 -102
  95. package/packages/effects/door_open_gold_flakes/assets/runtime/goldFlakes.v1.js +0 -397
  96. package/packages/effects/door_open_gold_flakes/door_open_gold_flakes.json +0 -498
  97. package/packages/effects/door_open_gold_flakes/index.ts +0 -11
  98. package/packages/effects/electric-arc/assets/textures/spark_4x4.webp +0 -0
  99. package/packages/effects/electric-arc/index.ts +0 -63
  100. package/packages/effects/energy-shield/effect.json +0 -7
  101. package/packages/effects/energy-shield/index.ts +0 -432
  102. package/packages/effects/explosion/assets/textures/baozha29.webp +0 -0
  103. package/packages/effects/explosion/assets/textures/glow01.webp +0 -0
  104. package/packages/effects/explosion/assets/textures/lizi01.webp +0 -0
  105. package/packages/effects/explosion/assets/textures/xulie_lizibaozha02_5x5.webp +0 -0
  106. package/packages/effects/explosion/index.ts +0 -115
  107. package/packages/effects/ground-tile-upgrade/effect.json +0 -6
  108. package/packages/effects/ground-tile-upgrade/index.ts +0 -410
  109. package/packages/effects/hit-flash/index.ts +0 -77
  110. package/packages/effects/laser-beam/assets/textures/laser_glow.webp +0 -0
  111. package/packages/effects/laser-beam/assets/textures/laser_noise.webp +0 -0
  112. package/packages/effects/laser-beam/index.ts +0 -6
  113. package/packages/effects/laser-beam-factory.ts +0 -146
  114. package/packages/effects/lumber-cart-suction/effect.json +0 -6
  115. package/packages/effects/lumber-cart-suction/index.ts +0 -399
  116. package/packages/effects/lumber-debris-scatter/assets/models/lumber_prop_model.glb +0 -0
  117. package/packages/effects/lumber-debris-scatter/assets/models/lumber_prop_model.glb.versions/.active +0 -1
  118. package/packages/effects/lumber-debris-scatter/assets/models/lumber_prop_model.glb.versions/1781589063890_upload.glb +0 -0
  119. package/packages/effects/lumber-debris-scatter/assets/runtime/solidParticleScatter.v1.js +0 -236
  120. package/packages/effects/lumber-debris-scatter/effect.json +0 -228
  121. package/packages/effects/lumber-debris-scatter/index.ts +0 -780
  122. package/packages/effects/lumber_vehicle_gear_spin/assets/runtime/gearSpin.v1.js +0 -202
  123. package/packages/effects/lumber_vehicle_gear_spin/index.ts +0 -11
  124. package/packages/effects/lumber_vehicle_gear_spin/lumber_vehicle_gear_spin.json +0 -338
  125. package/packages/effects/lumber_vehicle_upgrade_aura/assets/runtime/upgradeAura.v1.js +0 -353
  126. package/packages/effects/lumber_vehicle_upgrade_aura/index.ts +0 -13
  127. package/packages/effects/lumber_vehicle_upgrade_aura/lumber_vehicle_upgrade_aura.json +0 -365
  128. package/packages/effects/lumber_vehicle_wood_chips/assets/runtime/solidParticleScatter.v1.js +0 -310
  129. package/packages/effects/lumber_vehicle_wood_chips/index.ts +0 -11
  130. package/packages/effects/lumber_vehicle_wood_chips/lumber_vehicle_wood_chips.json +0 -335
  131. package/packages/effects/monster-hit/index.ts +0 -129
  132. package/packages/effects/player-upgrade/effect.json +0 -6
  133. package/packages/effects/player-upgrade/index.ts +0 -640
  134. package/packages/effects/pulse-laser-volley/assets/textures/bolt_guangshu.webp +0 -0
  135. package/packages/effects/pulse-laser-volley/index.ts +0 -215
  136. package/packages/effects/resource-collect-sparkles/effect.json +0 -6
  137. package/packages/effects/resource-collect-sparkles/index.ts +0 -254
  138. package/packages/effects/run-footstep-dust/assets/runtime/runFootstepDust.v1.js +0 -215
  139. package/packages/effects/run-footstep-dust/effect.json +0 -183
  140. package/packages/effects/run-footstep-dust/index.ts +0 -377
  141. package/packages/effects/space-shared.ts +0 -120
  142. package/packages/effects/thruster-flame/index.ts +0 -306
  143. package/packages/effects/treasure-attention/effect.json +0 -7
  144. package/packages/effects/treasure-attention/index.ts +0 -630
  145. package/packages/effects/tree-chop-dust/assets/textures/tree_chop_dust_atlas.png +0 -0
  146. package/packages/effects/tree-chop-dust/effect.json +0 -8
  147. package/packages/effects/tree-chop-dust/index.ts +0 -202
  148. package/packages/effects/tree-leaf-chop-burst/assets/runtime/particleEmitter.v1.js +0 -303
  149. package/packages/effects/tree-leaf-chop-burst/assets/textures/tree_leaf_chop_burst_leaf_atlas.png +0 -0
  150. package/packages/effects/tree-leaf-chop-burst/effect.json +0 -498
  151. package/packages/effects/tree-leaf-chop-burst/index.ts +0 -294
  152. package/packages/effects/tree_chop_dust_burst/assets/runtime/particleEmitter.v1.js +0 -318
  153. package/packages/effects/tree_chop_dust_burst/assets/textures/tree_chop_dust_burst_dust.png +0 -0
  154. package/packages/effects/tree_chop_dust_burst/index.ts +0 -13
  155. package/packages/effects/tree_chop_dust_burst/tree_chop_dust_burst.json +0 -412
  156. package/packages/effects/ufo-thread-flame/assets/textures/flame_flow.webp +0 -0
  157. package/packages/effects/ufo-thread-flame/assets/textures/flame_spike.webp +0 -0
  158. package/packages/effects/ufo-thread-flame/index.ts +0 -153
  159. package/packages/effects/vehicle-exhaust-smoke/assets/textures/vehicle_exhaust_smoke_atlas.png +0 -0
  160. package/packages/effects/vehicle-exhaust-smoke/effect.json +0 -8
  161. package/packages/effects/vehicle-exhaust-smoke/index.ts +0 -298
  162. package/packages/effects/vehicle-upgrade/effect.json +0 -6
  163. package/packages/effects/vehicle-upgrade/index.ts +0 -404
  164. package/packages/effects/weapon-trail/assets/textures/trail_wedge.png +0 -0
  165. package/packages/effects/weapon-trail/index.ts +0 -317
  166. package/packages/effects/wood-crusher-sawdust/assets/runtime/particleEmitter.v1.js +0 -312
  167. package/packages/effects/wood-crusher-sawdust/assets/textures/wood_crusher_sawdust_dust.png +0 -0
  168. package/packages/effects/wood-crusher-sawdust/assets/textures/wood_crusher_sawdust_fiber.png +0 -0
  169. package/packages/effects/wood-crusher-sawdust/index.ts +0 -43
  170. package/packages/effects/wood-crusher-sawdust/wood_crusher_sawdust.json +0 -592
  171. package/packages/effects/wood-cutter-sawdust/assets/runtime/particleEmitter.v1.js +0 -312
  172. package/packages/effects/wood-cutter-sawdust/assets/textures/wood_cutter_sawdust_chip.png +0 -0
  173. package/packages/effects/wood-cutter-sawdust/assets/textures/wood_cutter_sawdust_dust.png +0 -0
  174. package/packages/effects/wood-cutter-sawdust/index.ts +0 -43
  175. package/packages/effects/wood-cutter-sawdust/wood_cutter_sawdust.json +0 -592
  176. package/packages/effects/wood-sawdust-effect-factory.ts +0 -194
  177. package/packages/effects/wood_crusher_sawdust/assets/runtime/particleEmitter.v1.js +0 -318
  178. package/packages/effects/wood_crusher_sawdust/assets/textures/wood_crusher_sawdust_dust.png +0 -0
  179. package/packages/effects/wood_crusher_sawdust/assets/textures/wood_crusher_sawdust_fiber.png +0 -0
  180. package/packages/effects/wood_crusher_sawdust/index.ts +0 -29
  181. package/packages/effects/wood_crusher_sawdust/wood_crusher_sawdust.json +0 -592
  182. package/packages/effects/wood_cutter_sawdust/assets/runtime/particleEmitter.v1.js +0 -318
  183. package/packages/effects/wood_cutter_sawdust/assets/textures/wood_cutter_sawdust_chip.png +0 -0
  184. package/packages/effects/wood_cutter_sawdust/assets/textures/wood_cutter_sawdust_dust.png +0 -0
  185. package/packages/effects/wood_cutter_sawdust/index.ts +0 -29
  186. package/packages/effects/wood_cutter_sawdust/wood_cutter_sawdust.json +0 -592
  187. package/packages/effects/wood_peel_material_test/assets/runtime/woodPeelMaterialTest.v1.js +0 -196
  188. package/packages/effects/wood_peel_material_test/index.ts +0 -11
  189. package/packages/effects/wood_peel_material_test/wood_peel_material_test.json +0 -136
  190. package/packages/env.particle.forest_edge_fog/assets/runtime/particleEmitter.v1.js +0 -210
  191. package/packages/env.particle.forest_edge_fog/assets/textures/f12a23c4-b924-4322-a260-3d982428f1e8.png +0 -0
  192. package/packages/env.particle.forest_edge_fog/assets/textures/yuan.png +0 -0
  193. package/packages/env.particle.forest_edge_fog/effect.json +0 -854
  194. package/packages/env.particle.forest_edge_fog/media/preview.gif +0 -0
  195. package/packages/env.particle.forest_edge_fog/media/preview.mp4 +0 -0
  196. package/packages/env.particle.forest_edge_fog/media/preview.webm +0 -0
  197. package/packages/env.particle.forest_edge_fog/media/thumbnail.png +0 -0
  198. package/packages/env.particle.forest_edge_fog/metadata/description.json +0 -148
  199. package/packages/env.particle.forest_edge_fog/provenance/03-effect.original.json +0 -827
  200. package/packages/env.particle.forest_edge_fog/provenance/03-normalized-vfx-to-babylon-report.json +0 -196
  201. package/packages/env.particle.forest_edge_fog/provenance/04-preview-overrides.json +0 -432
  202. package/packages/env.particle.forest_edge_fog/provenance/04-preview-tuning-report.json +0 -28
  203. package/packages/env.particle.forest_edge_fog/provenance/asset-map.json +0 -124
  204. package/packages/env.particle.forest_edge_fog/provenance/lineage.json +0 -41
  205. package/packages/generation.ts +0 -14
  206. package/packages/index.ts +0 -14
  207. package/packages/legacy-particle-runtime.ts +0 -113
  208. package/packages/manifestRuntimePackage.ts +0 -519
  209. package/packages/registry.ts +0 -85
  210. package/packages/rendering.ts +0 -13
  211. package/packages/resource.particle.viscous_oil_suction/assets/runtime/top_disk_suction/particleEmitter.v1.js +0 -424
  212. package/packages/resource.particle.viscous_oil_suction/assets/textures/Glow ad.png +0 -0
  213. package/packages/resource.particle.viscous_oil_suction/effect.json +0 -1254
  214. package/packages/resource.particle.viscous_oil_suction/media/preview.gif +0 -0
  215. package/packages/resource.particle.viscous_oil_suction/media/preview.mp4 +0 -0
  216. package/packages/resource.particle.viscous_oil_suction/media/preview.webm +0 -0
  217. package/packages/resource.particle.viscous_oil_suction/media/thumbnail.png +0 -0
  218. package/packages/resource.particle.viscous_oil_suction/metadata/description.json +0 -122
  219. package/packages/resource.particle.viscous_oil_suction/provenance/03-effect.original.json +0 -1051
  220. package/packages/resource.particle.viscous_oil_suction/provenance/03-normalized-vfx-to-babylon-report.json +0 -200
  221. package/packages/resource.particle.viscous_oil_suction/provenance/04-preview-overrides.json +0 -581
  222. package/packages/resource.particle.viscous_oil_suction/provenance/04-preview-tuning-report.json +0 -28
  223. package/packages/resource.particle.viscous_oil_suction/provenance/asset-map.json +0 -111
  224. package/packages/resource.particle.viscous_oil_suction/provenance/lineage.json +0 -45
  225. package/packages/types.ts +0 -195
  226. package/tooling/check-dist-runtime.mjs +0 -166
  227. package/tooling/generate-index.mjs +0 -55
  228. package/tooling/test-guardrails.mjs +0 -157
  229. package/tooling/validate-boundary.mjs +0 -92
  230. package/tooling/validate-effects.mjs +0 -304
  231. package/tooling/validate.mjs +0 -53
@@ -1,401 +0,0 @@
1
- import { Color4 } from '@babylonjs/core/Maths/math.color';
2
- import { Matrix, Vector3 } from '@babylonjs/core/Maths/math.vector';
3
- import { DynamicTexture } from '@babylonjs/core/Materials/Textures/dynamicTexture';
4
- import type { TransformNode } from '@babylonjs/core/Meshes/transformNode';
5
- import type { Particle } from '@babylonjs/core/Particles/particle';
6
- import { ParticleSystem } from '@babylonjs/core/Particles/particleSystem';
7
- import type { Scene } from '@babylonjs/core/scene';
8
- import type { VfxColorValue, VfxEffectPackage, VfxParamValues } from '../../types';
9
- import { configureVfxParticleSystem } from '../../rendering';
10
- import manifest from './effect.json';
11
-
12
- interface ConveyorUpgradeParams extends VfxParamValues {
13
- lifetime: number;
14
- scale: number;
15
- initialHeight: number;
16
- color: VfxColorValue;
17
- opacity: number;
18
- scaleX: number;
19
- scaleY: number;
20
- scaleZ: number;
21
- centerCount: number;
22
- outlineCount: number;
23
- strandWidth: number;
24
- riseSpeed: number;
25
- centerSpread: number;
26
- outlineThickness: number;
27
- glowOpacity: number;
28
- }
29
-
30
- const BASE_FOOTPRINT_X = 3.2;
31
- const BASE_FOOTPRINT_Z = 2.6;
32
- const BASE_CENTER_HEIGHT = 2.2;
33
- const BASE_OUTLINE_HEIGHT = 3.1;
34
- const BASE_GLOW_THICKNESS = 0.38;
35
-
36
- const DEFAULT_PARAMS: ConveyorUpgradeParams = {
37
- lifetime: 1.8,
38
- scale: 1,
39
- initialHeight: 0.02,
40
- color: { r: 1, g: 0.84, b: 0.12 },
41
- opacity: 1,
42
- scaleX: 1.35,
43
- scaleY: 0.35,
44
- scaleZ: 0.55,
45
- centerCount: 46,
46
- outlineCount: 150,
47
- strandWidth: 0.035,
48
- riseSpeed: 1.15,
49
- centerSpread: 0.92,
50
- outlineThickness: 0.18,
51
- glowOpacity: 0.62,
52
- };
53
-
54
- export const conveyorUpgradeEffectPackage: VfxEffectPackage<ConveyorUpgradeParams> = {
55
- id: 'conveyor-upgrade',
56
- nameZh: '传送带升级光效',
57
- manifest,
58
- defaultParams: DEFAULT_PARAMS,
59
- debugAnchor: 'playerRight',
60
- debugParams: [
61
- { key: 'lifetime', label: '生命周期', kind: 'lifetime', min: 0.2, max: 6, step: 0.01 },
62
- { key: 'scale', label: '整体缩放', kind: 'scale', min: 0.1, max: 6, step: 0.01 },
63
- { key: 'initialHeight', label: '初始高度', kind: 'number', min: -1, max: 3, step: 0.01 },
64
- { key: 'color', label: '光效颜色', kind: 'color' },
65
- { key: 'opacity', label: '透明度', kind: 'opacity', min: 0, max: 1, step: 0.01 },
66
- { key: 'scaleX', label: 'X 轴缩放', kind: 'number', min: 0.1, max: 6, step: 0.01 },
67
- { key: 'scaleY', label: 'Y 轴缩放', kind: 'number', min: 0.1, max: 6, step: 0.01 },
68
- { key: 'scaleZ', label: 'Z 轴缩放', kind: 'number', min: 0.1, max: 6, step: 0.01 },
69
- { key: 'centerCount', label: '中心光丝数量', kind: 'number', min: 0, max: 240, step: 1 },
70
- { key: 'outlineCount', label: '轮廓光丝数量', kind: 'number', min: 0, max: 420, step: 1 },
71
- { key: 'strandWidth', label: '光丝粗细', kind: 'number', min: 0.005, max: 0.2, step: 0.001 },
72
- { key: 'riseSpeed', label: '上升速度', kind: 'number', min: 0, max: 5, step: 0.01 },
73
- { key: 'centerSpread', label: '中心散布', kind: 'number', min: 0, max: 1.5, step: 0.01 },
74
- { key: 'outlineThickness', label: '轮廓厚度', kind: 'number', min: 0, max: 1, step: 0.01 },
75
- { key: 'glowOpacity', label: '光幕强度', kind: 'opacity', min: 0, max: 1, step: 0.01 },
76
- ],
77
- create({ scene, root, position, params }) {
78
- root.position.copyFrom(position).addInPlace(new Vector3(0, params.initialHeight, 0));
79
-
80
- const centerStrands = createStrandSystem(scene, root, params, 'center');
81
- const outlineStrands = createStrandSystem(scene, root, params, 'outline');
82
- const glow = createOutlineGlow(scene, root, params);
83
- let disposed = false;
84
- const disposeTimer = window.setTimeout(
85
- () => disposeAll(),
86
- Math.max(0.05, params.lifetime + getMaxStrandHeight(params) / Math.max(0.1, params.riseSpeed) * 0.18 + 0.45) * 1000,
87
- );
88
-
89
- centerStrands.start();
90
- outlineStrands.start();
91
- glow.start();
92
-
93
- return {
94
- root,
95
- dispose() {
96
- disposeAll();
97
- },
98
- };
99
-
100
- function disposeAll(): void {
101
- if (disposed) return;
102
- disposed = true;
103
- window.clearTimeout(disposeTimer);
104
- centerStrands.dispose(false);
105
- outlineStrands.dispose(false);
106
- glow.dispose(false);
107
- root.dispose();
108
- }
109
- },
110
- };
111
-
112
- function createStrandSystem(
113
- scene: Scene,
114
- root: TransformNode,
115
- params: ConveyorUpgradeParams,
116
- mode: 'center' | 'outline',
117
- ): ParticleSystem {
118
- const count = Math.max(0, Math.round(mode === 'center' ? params.centerCount : params.outlineCount));
119
- const system = new ParticleSystem(`conveyor-upgrade.${mode}-strands`, Math.max(1, count), scene);
120
- const color = params.color;
121
- const brightColor = getBrightColor(color);
122
- const height = mode === 'center' ? getCenterHeight(params) : getOutlineHeight(params);
123
- const width = params.strandWidth * getHorizontalScale(params) * (mode === 'center' ? 1.35 : 0.92);
124
-
125
- configureVfxParticleSystem(system);
126
- system.particleTexture = getStrandTexture(scene);
127
- system.emitter = root as any;
128
- system.manualEmitCount = count;
129
- system.emitRate = count * 60;
130
- system.targetStopDuration = 0.04;
131
- system.disposeOnStop = false;
132
- system.updateSpeed = 1 / 60;
133
- system.minLifeTime = Math.max(0.12, params.lifetime * (mode === 'center' ? 0.48 : 0.62));
134
- system.maxLifeTime = Math.max(system.minLifeTime + 0.01, params.lifetime * (mode === 'center' ? 0.86 : 1.08));
135
- system.minSize = Math.max(0.01, height * 0.34);
136
- system.maxSize = Math.max(system.minSize, height * (mode === 'center' ? 0.72 : 0.98));
137
- system.minScaleX = Math.max(0.02, width);
138
- system.maxScaleX = Math.max(system.minScaleX, width * 1.8);
139
- system.minScaleY = 1;
140
- system.maxScaleY = mode === 'center' ? 1.45 : 1.75;
141
- system.minEmitPower = Math.max(0.01, params.riseSpeed * getVerticalScale(params) * (mode === 'center' ? 0.5 : 0.7));
142
- system.maxEmitPower = Math.max(system.minEmitPower, params.riseSpeed * getVerticalScale(params) * (mode === 'center' ? 1.15 : 1.65));
143
- system.gravity = new Vector3(0, 0.38 * getVerticalScale(params), 0);
144
- system.blendMode = ParticleSystem.BLENDMODE_ADD;
145
- system.color1 = toColor4(color, params.opacity * (mode === 'center' ? 0.72 : 0.86));
146
- system.color2 = toColor4(brightColor, params.opacity);
147
- system.colorDead = toColor4(color, 0);
148
- system.addColorGradient(0, toColor4(color, 0));
149
- system.addColorGradient(0.12, toColor4(brightColor, params.opacity));
150
- system.addColorGradient(0.72, toColor4(color, params.opacity * 0.62));
151
- system.addColorGradient(1, toColor4(color, 0));
152
- system.addVelocityGradient(0, 1);
153
- system.addVelocityGradient(0.65, 0.55);
154
- system.addVelocityGradient(1, 0.12);
155
-
156
- let positionIndex = 0;
157
- let directionIndex = 0;
158
- system.startPositionFunction = (worldMatrix: Matrix, positionToUpdate: Vector3, particle: Particle, isLocal: boolean) => {
159
- const index = particle.id + positionIndex;
160
- positionIndex += 1;
161
- const local = mode === 'center'
162
- ? sampleCenterPosition(index, params)
163
- : sampleOutlinePosition(index, params);
164
- if (isLocal) positionToUpdate.copyFrom(local);
165
- else Vector3.TransformCoordinatesToRef(local, worldMatrix, positionToUpdate);
166
- };
167
- system.startDirectionFunction = (worldMatrix: Matrix, directionToUpdate: Vector3, particle: Particle, isLocal: boolean) => {
168
- const index = particle.id + directionIndex;
169
- directionIndex += 1;
170
- const sway = (mode === 'center' ? 0.22 : 0.12) * getHorizontalScale(params);
171
- const local = new Vector3(
172
- (sequence01(index, 4) - 0.5) * sway,
173
- 0.8 + sequence01(index, 5) * 0.65,
174
- (sequence01(index, 6) - 0.5) * sway,
175
- );
176
- if (isLocal) directionToUpdate.copyFrom(local);
177
- else Vector3.TransformNormalToRef(local, worldMatrix, directionToUpdate);
178
- };
179
-
180
- return system;
181
- }
182
-
183
- function createOutlineGlow(scene: Scene, root: TransformNode, params: ConveyorUpgradeParams): ParticleSystem {
184
- const count = Math.max(1, Math.round(params.outlineCount * 0.82));
185
- const system = new ParticleSystem('conveyor-upgrade.outline-glow-rays', count, scene);
186
- const height = getOutlineHeight(params) * 1.06;
187
- const glowWidth = Math.max(0.04, BASE_GLOW_THICKNESS * getHorizontalScale(params));
188
- const alpha = params.glowOpacity * params.opacity;
189
- const brightColor = getBrightColor(params.color);
190
-
191
- configureVfxParticleSystem(system);
192
- system.particleTexture = getOutlineGlowTexture(scene);
193
- system.emitter = root as any;
194
- system.manualEmitCount = count;
195
- system.emitRate = count * 60;
196
- system.targetStopDuration = 0.04;
197
- system.disposeOnStop = false;
198
- system.updateSpeed = 1 / 60;
199
- system.minLifeTime = Math.max(0.12, params.lifetime * 0.62);
200
- system.maxLifeTime = Math.max(system.minLifeTime + 0.01, params.lifetime * 1.08);
201
- system.minSize = Math.max(0.01, height * 0.42);
202
- system.maxSize = Math.max(system.minSize, height * 1.08);
203
- system.minScaleX = glowWidth * 0.42;
204
- system.maxScaleX = glowWidth * 1.18;
205
- system.minScaleY = 1.05;
206
- system.maxScaleY = 1.75;
207
- system.minEmitPower = Math.max(0.01, params.riseSpeed * getVerticalScale(params) * 0.58);
208
- system.maxEmitPower = Math.max(system.minEmitPower, params.riseSpeed * getVerticalScale(params) * 1.38);
209
- system.gravity = new Vector3(0, 0.3 * getVerticalScale(params), 0);
210
- system.blendMode = ParticleSystem.BLENDMODE_ADD;
211
- system.color1 = toColor4(params.color, alpha * 0.62);
212
- system.color2 = toColor4(brightColor, alpha * 0.86);
213
- system.colorDead = toColor4(params.color, 0);
214
- system.addColorGradient(0, toColor4(params.color, 0));
215
- system.addColorGradient(0.1, toColor4(brightColor, alpha * 0.82));
216
- system.addColorGradient(0.56, toColor4(params.color, alpha * 0.52));
217
- system.addColorGradient(1, toColor4(params.color, 0));
218
- system.addVelocityGradient(0, 1);
219
- system.addVelocityGradient(0.65, 0.52);
220
- system.addVelocityGradient(1, 0.12);
221
-
222
- let positionIndex = 0;
223
- let directionIndex = 0;
224
- system.startPositionFunction = (worldMatrix: Matrix, positionToUpdate: Vector3, particle: Particle, isLocal: boolean) => {
225
- const index = particle.id + positionIndex + 31;
226
- positionIndex += 1;
227
- const local = sampleOutlinePosition(index, params);
228
- if (isLocal) positionToUpdate.copyFrom(local);
229
- else Vector3.TransformCoordinatesToRef(local, worldMatrix, positionToUpdate);
230
- };
231
- system.startDirectionFunction = (worldMatrix: Matrix, directionToUpdate: Vector3, particle: Particle, isLocal: boolean) => {
232
- const index = particle.id + directionIndex + 31;
233
- directionIndex += 1;
234
- const sway = 0.08 * getHorizontalScale(params);
235
- const local = new Vector3(
236
- (sequence01(index, 4) - 0.5) * sway,
237
- 0.82 + sequence01(index, 5) * 0.58,
238
- (sequence01(index, 6) - 0.5) * sway,
239
- );
240
- if (isLocal) directionToUpdate.copyFrom(local);
241
- else Vector3.TransformNormalToRef(local, worldMatrix, directionToUpdate);
242
- };
243
-
244
- return system;
245
- }
246
-
247
- function sampleCenterPosition(index: number, params: ConveyorUpgradeParams): Vector3 {
248
- const angle = sequence01(index, 0) * Math.PI * 2;
249
- const radius = Math.sqrt(0.16 + sequence01(index, 1) * 0.84);
250
- const xRadius = getFootprintX(params) * 0.5 * params.centerSpread;
251
- const zRadius = getFootprintZ(params) * 0.5 * params.centerSpread;
252
- const jitterX = (sequence01(index, 7) - 0.5) * xRadius * 0.18;
253
- const jitterZ = (sequence01(index, 8) - 0.5) * zRadius * 0.18;
254
- const x = Math.cos(angle) * radius * xRadius + jitterX;
255
- const z = Math.sin(angle) * radius * zRadius + jitterZ;
256
- const y = sequence01(index, 2) * 0.12 * getVerticalScale(params);
257
- return new Vector3(x, y, z);
258
- }
259
-
260
- function sampleOutlinePosition(index: number, params: ConveyorUpgradeParams): Vector3 {
261
- const width = getFootprintX(params);
262
- const depth = getFootprintZ(params);
263
- const perimeter = Math.max(0.001, width * 2 + depth * 2);
264
- const distance = sequence01(index, 0) * perimeter;
265
- const jitter = (sequence01(index, 1) - 0.5) * params.outlineThickness * getHorizontalScale(params);
266
- const y = sequence01(index, 2) * 0.16 * getVerticalScale(params);
267
-
268
- if (distance < width) return new Vector3(-width * 0.5 + distance, y, -depth * 0.5 + jitter);
269
- if (distance < width + depth) return new Vector3(width * 0.5 + jitter, y, -depth * 0.5 + distance - width);
270
- if (distance < width * 2 + depth) return new Vector3(width * 0.5 - (distance - width - depth), y, depth * 0.5 + jitter);
271
- return new Vector3(-width * 0.5 + jitter, y, depth * 0.5 - (distance - width * 2 - depth));
272
- }
273
-
274
- function getFootprintX(params: ConveyorUpgradeParams): number {
275
- return BASE_FOOTPRINT_X * Math.max(0.05, params.scale) * Math.max(0.05, params.scaleX);
276
- }
277
-
278
- function getFootprintZ(params: ConveyorUpgradeParams): number {
279
- return BASE_FOOTPRINT_Z * Math.max(0.05, params.scale) * Math.max(0.05, params.scaleZ);
280
- }
281
-
282
- function getVerticalScale(params: ConveyorUpgradeParams): number {
283
- return Math.max(0.05, params.scale) * Math.max(0.05, params.scaleY);
284
- }
285
-
286
- function getHorizontalScale(params: ConveyorUpgradeParams): number {
287
- return Math.max(0.05, params.scale) * Math.max(0.05, (params.scaleX + params.scaleZ) * 0.5);
288
- }
289
-
290
- function getCenterHeight(params: ConveyorUpgradeParams): number {
291
- return BASE_CENTER_HEIGHT * getVerticalScale(params);
292
- }
293
-
294
- function getOutlineHeight(params: ConveyorUpgradeParams): number {
295
- return BASE_OUTLINE_HEIGHT * getVerticalScale(params);
296
- }
297
-
298
- function getMaxStrandHeight(params: ConveyorUpgradeParams): number {
299
- return Math.max(getCenterHeight(params), getOutlineHeight(params));
300
- }
301
-
302
- function getStrandTexture(scene: Scene): DynamicTexture {
303
- const key = '__vfx_conveyor_upgrade_strand_texture';
304
- const metadata = scene.metadata && typeof scene.metadata === 'object' ? scene.metadata as Record<string, unknown> : {};
305
- scene.metadata = metadata;
306
- const existing = metadata[key] as DynamicTexture | undefined;
307
- if (existing) return existing;
308
-
309
- const texture = new DynamicTexture('conveyor_upgrade_strand_texture', { width: 48, height: 192 }, scene, true);
310
- const context = texture.getContext();
311
- context.clearRect(0, 0, 48, 192);
312
- const glow = context.createLinearGradient(0, 0, 0, 192);
313
- glow.addColorStop(0, 'rgba(255, 255, 255, 0)');
314
- glow.addColorStop(0.18, 'rgba(255, 255, 255, 0.92)');
315
- glow.addColorStop(0.62, 'rgba(255, 255, 255, 0.52)');
316
- glow.addColorStop(1, 'rgba(255, 255, 255, 0)');
317
- context.fillStyle = glow;
318
- context.fillRect(19, 0, 10, 192);
319
- context.fillStyle = 'rgba(255, 255, 255, 0.95)';
320
- context.fillRect(23, 8, 2, 168);
321
- const halo = context.createRadialGradient(24, 64, 0, 24, 64, 24);
322
- halo.addColorStop(0, 'rgba(255, 255, 255, 0.5)');
323
- halo.addColorStop(1, 'rgba(255, 255, 255, 0)');
324
- context.fillStyle = halo;
325
- context.fillRect(0, 16, 48, 96);
326
- texture.hasAlpha = true;
327
- texture.update(false);
328
- metadata[key] = texture;
329
- return texture;
330
- }
331
-
332
- function getOutlineGlowTexture(scene: Scene): DynamicTexture {
333
- const key = '__vfx_conveyor_upgrade_outline_glow_texture';
334
- const metadata = scene.metadata && typeof scene.metadata === 'object' ? scene.metadata as Record<string, unknown> : {};
335
- scene.metadata = metadata;
336
- const existing = metadata[key] as DynamicTexture | undefined;
337
- if (existing) return existing;
338
-
339
- const texture = new DynamicTexture('conveyor_upgrade_outline_glow_texture', { width: 96, height: 192 }, scene, true);
340
- const context = texture.getContext();
341
- const compositeContext = context as unknown as CanvasRenderingContext2D;
342
- context.clearRect(0, 0, 96, 192);
343
- const sideFade = context.createLinearGradient(0, 0, 96, 0);
344
- sideFade.addColorStop(0, 'rgba(255, 255, 255, 0)');
345
- sideFade.addColorStop(0.28, 'rgba(255, 255, 255, 0.36)');
346
- sideFade.addColorStop(0.5, 'rgba(255, 255, 255, 0.78)');
347
- sideFade.addColorStop(0.72, 'rgba(255, 255, 255, 0.36)');
348
- sideFade.addColorStop(1, 'rgba(255, 255, 255, 0)');
349
- const verticalFade = context.createLinearGradient(0, 0, 0, 192);
350
- verticalFade.addColorStop(0, 'rgba(255, 255, 255, 0)');
351
- verticalFade.addColorStop(0.16, 'rgba(255, 255, 255, 0.65)');
352
- verticalFade.addColorStop(0.55, 'rgba(255, 255, 255, 0.46)');
353
- verticalFade.addColorStop(1, 'rgba(255, 255, 255, 0)');
354
- context.fillStyle = sideFade;
355
- context.fillRect(0, 0, 96, 192);
356
- compositeContext.globalCompositeOperation = 'source-in';
357
- context.fillStyle = verticalFade;
358
- context.fillRect(0, 0, 96, 192);
359
- compositeContext.globalCompositeOperation = 'source-over';
360
- const core = context.createLinearGradient(0, 0, 0, 192);
361
- core.addColorStop(0, 'rgba(255, 255, 255, 0)');
362
- core.addColorStop(0.22, 'rgba(255, 255, 255, 0.64)');
363
- core.addColorStop(0.66, 'rgba(255, 255, 255, 0.28)');
364
- core.addColorStop(1, 'rgba(255, 255, 255, 0)');
365
- context.fillStyle = core;
366
- context.fillRect(44, 8, 8, 166);
367
- texture.hasAlpha = true;
368
- texture.update(false);
369
- metadata[key] = texture;
370
- return texture;
371
- }
372
-
373
- function getBrightColor(color: VfxColorValue): VfxColorValue {
374
- return {
375
- r: lerp(color.r, 1, 0.68),
376
- g: lerp(color.g, 1, 0.68),
377
- b: lerp(color.b, 1, 0.68),
378
- };
379
- }
380
-
381
- function toColor4(color: VfxColorValue, alpha: number): Color4 {
382
- return new Color4(clamp01(color.r), clamp01(color.g), clamp01(color.b), clamp01(alpha));
383
- }
384
-
385
- function lerp(min: number, max: number, t: number): number {
386
- return min + (max - min) * t;
387
- }
388
-
389
- function clamp01(value: number): number {
390
- return Math.min(1, Math.max(0, value));
391
- }
392
-
393
- function fract(value: number): number {
394
- return value - Math.floor(value);
395
- }
396
-
397
- function sequence01(index: number, axis: number): number {
398
- if (index === 0) return 0.5;
399
- const strides = [0.618033988749895, 0.414213562373095, 0.732050807568877, 0.324717957244746, 0.754877666246693, 0.569840290998053];
400
- return fract(0.5 + index * strides[axis % strides.length] + axis * 0.173205080756888);
401
- }
@@ -1,102 +0,0 @@
1
- // 碎石烟雾(组合:碎石飞溅 #10 + 爆炸烟雾 #8)。一次性爆点,参数分两段独立调。
2
- // 碎石段:rock_debris.glb 克隆抛物池;烟雾段:smoke22 STANDARD 上飘粒子。
3
- import { Mesh } from '@babylonjs/core/Meshes/mesh';
4
- import { Vector3, Matrix } from '@babylonjs/core/Maths/math.vector';
5
- import { Color4 } from '@babylonjs/core/Maths/math.color';
6
- import { ParticleSystem } from '@babylonjs/core/Particles/particleSystem';
7
- import { SceneLoader } from '@babylonjs/core/Loading/sceneLoader';
8
- import '@babylonjs/loaders/glTF/2.0/glTFLoader';
9
- import type { Scene } from '@babylonjs/core/scene';
10
- import type { VfxEffectPackage, VfxParamValues } from '../../types';
11
- import { FlyerPool, makeBurstPS } from '../space-shared';
12
- import rockModelUrl from './assets/models/rock_debris.glb?url';
13
- import smokeUrl from './assets/textures/smoke22.webp?url';
14
-
15
- interface DebrisSmokeParams extends VfxParamValues {
16
- // 段1 碎石
17
- debrisCount: number; debrisSize: number; debrisRadius: number;
18
- // 段2 烟雾
19
- smokeCount: number; smokeSize: number;
20
- }
21
-
22
- const DEFAULT_PARAMS: DebrisSmokeParams = {
23
- debrisCount: 14, debrisSize: 0.35, debrisRadius: 1.8,
24
- smokeCount: 10, smokeSize: 1,
25
- };
26
-
27
- const cachedRockTpls = new WeakMap<Scene, Promise<Mesh[]>>();
28
- function loadRockTemplates(scene: Scene): Promise<Mesh[]> {
29
- const existing = cachedRockTpls.get(scene);
30
- if (existing) return existing;
31
- const isDataUri = rockModelUrl.startsWith('data:');
32
- const lastSlash = isDataUri ? -1 : rockModelUrl.lastIndexOf('/');
33
- const rootUrl = lastSlash >= 0 ? rockModelUrl.slice(0, lastSlash + 1) : '';
34
- const fileName = lastSlash >= 0 ? rockModelUrl.slice(lastSlash + 1) : rockModelUrl;
35
- const promise = SceneLoader.ImportMeshAsync('', rootUrl, fileName, scene, undefined, '.glb').then((res) => {
36
- const tpls = res.meshes.filter((m): m is Mesh => m instanceof Mesh && m.getTotalVertices() > 0);
37
- for (const r of tpls) {
38
- r.setParent(null);
39
- const c = r.getBoundingInfo().boundingBox.centerWorld.clone();
40
- r.bakeTransformIntoVertices(Matrix.Translation(-c.x, -c.y, -c.z));
41
- r.position.set(0, 0, 0); r.setEnabled(false); r.isPickable = false;
42
- }
43
- return tpls;
44
- }).catch((e) => { cachedRockTpls.delete(scene); throw e; });
45
- cachedRockTpls.set(scene, promise);
46
- return promise;
47
- }
48
-
49
- export const debrisSmokeEffectPackage: VfxEffectPackage<DebrisSmokeParams> = {
50
- id: 'debris-smoke',
51
- nameZh: '碎石烟雾',
52
- placement: 'world',
53
- debugAnchor: 'playerRight',
54
- defaultParams: DEFAULT_PARAMS,
55
- debugParams: [
56
- // 段1 · 碎石
57
- { key: 'debrisCount', label: '碎石·数量', kind: 'number', min: 0, max: 30, step: 1 },
58
- { key: 'debrisSize', label: '碎石·大小', kind: 'number', min: 0.1, max: 1, step: 0.01 },
59
- { key: 'debrisRadius', label: '碎石·范围', kind: 'scale', min: 0.5, max: 5, step: 0.1 },
60
- // 段2 · 烟雾
61
- { key: 'smokeCount', label: '烟雾·数量', kind: 'number', min: 0, max: 40, step: 1 },
62
- { key: 'smokeSize', label: '烟雾·尺寸', kind: 'scale', min: 0.2, max: 3, step: 0.05 },
63
- ],
64
-
65
- create({ scene, root, position, params }) {
66
- root.position.copyFrom(position);
67
-
68
- // ── 段2 烟雾(立即发)──────────────────────────────────────────────────────
69
- const smokePs = makeBurstPS('vfx_ds_smoke', scene, smokeUrl, {
70
- cap: 120, size: [2.2, 4.5], life: [0.9, 1.6], power: [1.5, 4], gravity: new Vector3(0, 1.2, 0),
71
- blend: ParticleSystem.BLENDMODE_STANDARD, c1: new Color4(0.5, 0.45, 0.42, 0.65), c2: new Color4(0.32, 0.3, 0.3, 0.5), cd: new Color4(0.2, 0.2, 0.2, 0),
72
- });
73
- smokePs.minSize *= params.smokeSize; smokePs.maxSize *= params.smokeSize;
74
- (smokePs.emitter as Vector3).copyFrom(position);
75
- smokePs.manualEmitCount += Math.round(params.smokeCount);
76
-
77
- // ── 段1 碎石(glb 异步加载后抛撒)──────────────────────────────────────────
78
- const pool = new FlyerPool(scene);
79
- const r = params.debrisRadius;
80
- let disposed = false;
81
- const ready = (params.debrisCount > 0 ? loadRockTemplates(scene) : Promise.resolve([] as Mesh[])).then((tpls) => {
82
- if (disposed || !tpls.length) return;
83
- for (let i = 0; i < Math.round(params.debrisCount); i++) {
84
- const tpl = tpls[(Math.random() * tpls.length) | 0];
85
- const d = tpl.clone('vfx_ds_debris', null, false);
86
- if (!d) continue;
87
- d.setEnabled(true); d.isPickable = false;
88
- d.normalizeToUnitCube();
89
- d.scaling.scaleInPlace(r * params.debrisSize * (0.5 + Math.random() * 0.8));
90
- pool.spawn(d, position, new Vector3((Math.random() - 0.5) * 13, Math.random() * 6.75 + 2.25, (Math.random() - 0.5) * 13), 7, 1.2);
91
- }
92
- }).catch((e) => { console.warn('[VFX] debris-smoke load failed', e); });
93
-
94
- const disposeTimer = window.setTimeout(() => disposeAll(), 2200);
95
- function disposeAll(): void {
96
- if (disposed) return; disposed = true;
97
- window.clearTimeout(disposeTimer);
98
- pool.dispose(); smokePs.dispose(); root.dispose();
99
- }
100
- return { root, ready, dispose() { disposeAll(); } };
101
- },
102
- };