@fps-games/vfx 0.1.1 → 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 (250) hide show
  1. package/CHANGELOG.md +115 -0
  2. package/README.md +41 -0
  3. package/dist/effects/coin-burst/index.js +6 -2
  4. package/dist/effects/comet-trail-flame/index.js +3 -1
  5. package/dist/effects/debris-smoke/index.js +1 -0
  6. package/dist/effects/electric-arc/index.js +1 -0
  7. package/dist/effects/energy-shield/index.js +1 -0
  8. package/dist/effects/explosion/index.js +3 -2
  9. package/dist/effects/hit-flash/index.js +12 -4
  10. package/dist/effects/laser-beam/index.js +14 -2
  11. package/dist/effects/lumber_vehicle_upgrade_aura/index.js +1 -0
  12. package/dist/effects/monster-hit/index.js +2 -1
  13. package/dist/effects/player-upgrade/index.js +5 -3
  14. package/dist/effects/pulse-laser-volley/index.js +14 -4
  15. package/dist/effects/thruster-flame/index.js +3 -1
  16. package/dist/effects/treasure-attention/index.d.ts +54 -0
  17. package/dist/effects/treasure-attention/index.js +535 -0
  18. package/dist/effects/ufo-thread-flame/index.js +1 -0
  19. package/dist/effects/vehicle-upgrade/index.js +4 -1
  20. package/dist/effects/weapon-trail/index.js +8 -3
  21. package/dist/effects/wood_crusher_sawdust/index.d.ts +4 -0
  22. package/dist/effects/wood_cutter_sawdust/index.d.ts +4 -0
  23. package/dist/index.js +85 -17
  24. package/dist/types.d.ts +80 -0
  25. package/index.json +19 -1
  26. package/package.json +9 -4
  27. package/packages/effects/treasure-attention/vfx-params.json +49 -0
  28. package/tooling/vfx-cli.mjs +8 -1
  29. package/docs/AUTHORING_EFFECTS.md +0 -297
  30. package/docs/VFX_LIBRARY_ARCHITECTURE_chatgpt.md +0 -1580
  31. package/docs/VFX_LIBRARY_EXECUTION_PLAN.md +0 -229
  32. package/docs/VFX_LIBRARY_PLAN.md +0 -546
  33. package/docs/vfx-ab/RESULTS.md +0 -35
  34. package/docs/vfx-ab/lumber-order/vehicle-exhaust-smoke/after.png +0 -0
  35. package/docs/vfx-ab/lumber-order/vehicle-exhaust-smoke/before.png +0 -0
  36. package/docs/vfx-ab/lumber-truck/vehicle-exhaust-smoke/after.png +0 -0
  37. package/docs/vfx-ab/lumber-truck/vehicle-exhaust-smoke/before.png +0 -0
  38. package/docs/vfx-integration_chatgpt.md +0 -462
  39. package/docs/weapon-trail-visualization.html +0 -241
  40. package/packages/EffectPackageService.ts +0 -240
  41. package/packages/SceneVfxService.ts +0 -96
  42. package/packages/build.mesh.yellow_build_upgrade_indicator/assets/runtime/simpleMeshEffect.v1.js +0 -333
  43. package/packages/build.mesh.yellow_build_upgrade_indicator/assets/shaders/mesh-effect-preview.frag.glsl +0 -25
  44. package/packages/build.mesh.yellow_build_upgrade_indicator/assets/shaders/mesh-effect-preview.vert.glsl +0 -11
  45. package/packages/build.mesh.yellow_build_upgrade_indicator/assets/textures/effect_jianbian.png +0 -0
  46. package/packages/build.mesh.yellow_build_upgrade_indicator/effect.json +0 -927
  47. package/packages/build.mesh.yellow_build_upgrade_indicator/media/contact-sheet.png +0 -0
  48. package/packages/build.mesh.yellow_build_upgrade_indicator/media/preview.gif +0 -0
  49. package/packages/build.mesh.yellow_build_upgrade_indicator/media/preview.mp4 +0 -0
  50. package/packages/build.mesh.yellow_build_upgrade_indicator/media/preview.webm +0 -0
  51. package/packages/build.mesh.yellow_build_upgrade_indicator/media/thumbnail.png +0 -0
  52. package/packages/build.mesh.yellow_build_upgrade_indicator/metadata/description.json +0 -197
  53. package/packages/build.mesh.yellow_build_upgrade_indicator/provenance/03-effect.original.json +0 -895
  54. package/packages/build.mesh.yellow_build_upgrade_indicator/provenance/03-normalized-vfx-to-babylon-report.json +0 -241
  55. package/packages/build.mesh.yellow_build_upgrade_indicator/provenance/04-preview-overrides.json +0 -542
  56. package/packages/build.mesh.yellow_build_upgrade_indicator/provenance/04-preview-tuning-report.json +0 -69
  57. package/packages/build.mesh.yellow_build_upgrade_indicator/provenance/asset-map.json +0 -125
  58. package/packages/build.mesh.yellow_build_upgrade_indicator/provenance/lineage.json +0 -44
  59. package/packages/build.particle.golden_upgrade_starburst/assets/runtime/particleEmitter.v1.js +0 -210
  60. package/packages/build.particle.golden_upgrade_starburst/assets/textures/effect_guangdian.png +0 -0
  61. package/packages/build.particle.golden_upgrade_starburst/effect.json +0 -880
  62. package/packages/build.particle.golden_upgrade_starburst/media/contact-sheet.png +0 -0
  63. package/packages/build.particle.golden_upgrade_starburst/media/preview.gif +0 -0
  64. package/packages/build.particle.golden_upgrade_starburst/media/preview.mp4 +0 -0
  65. package/packages/build.particle.golden_upgrade_starburst/media/preview.webm +0 -0
  66. package/packages/build.particle.golden_upgrade_starburst/media/thumbnail.png +0 -0
  67. package/packages/build.particle.golden_upgrade_starburst/metadata/description.json +0 -161
  68. package/packages/build.particle.golden_upgrade_starburst/provenance/03-effect.original.json +0 -762
  69. package/packages/build.particle.golden_upgrade_starburst/provenance/03-normalized-vfx-to-babylon-report.json +0 -260
  70. package/packages/build.particle.golden_upgrade_starburst/provenance/04-preview-overrides.json +0 -436
  71. package/packages/build.particle.golden_upgrade_starburst/provenance/04-preview-tuning-report.json +0 -40
  72. package/packages/build.particle.golden_upgrade_starburst/provenance/asset-map.json +0 -115
  73. package/packages/build.particle.golden_upgrade_starburst/provenance/lineage.json +0 -40
  74. package/packages/build.particle.orange_upgrade_transform_sparks/assets/runtime/particleEmitter.v1.js +0 -210
  75. package/packages/build.particle.orange_upgrade_transform_sparks/assets/textures/b5b27ab1-e740-4398-b407-848fc2b2c897.png +0 -0
  76. package/packages/build.particle.orange_upgrade_transform_sparks/effect.json +0 -887
  77. package/packages/build.particle.orange_upgrade_transform_sparks/media/preview.gif +0 -0
  78. package/packages/build.particle.orange_upgrade_transform_sparks/media/preview.mp4 +0 -0
  79. package/packages/build.particle.orange_upgrade_transform_sparks/media/preview.webm +0 -0
  80. package/packages/build.particle.orange_upgrade_transform_sparks/media/thumbnail.png +0 -0
  81. package/packages/build.particle.orange_upgrade_transform_sparks/metadata/description.json +0 -179
  82. package/packages/build.particle.orange_upgrade_transform_sparks/provenance/03-effect.original.json +0 -859
  83. package/packages/build.particle.orange_upgrade_transform_sparks/provenance/03-normalized-vfx-to-babylon-report.json +0 -260
  84. package/packages/build.particle.orange_upgrade_transform_sparks/provenance/04-preview-overrides.json +0 -478
  85. package/packages/build.particle.orange_upgrade_transform_sparks/provenance/04-preview-tuning-report.json +0 -40
  86. package/packages/build.particle.orange_upgrade_transform_sparks/provenance/asset-map.json +0 -114
  87. package/packages/build.particle.orange_upgrade_transform_sparks/provenance/lineage.json +0 -41
  88. package/packages/build.particle.wood_chip_dust_burst/assets/runtime/particleEmitter.v1.js +0 -210
  89. package/packages/build.particle.wood_chip_dust_burst/assets/textures/effect_yanwu4.png +0 -0
  90. package/packages/build.particle.wood_chip_dust_burst/assets/textures/suipian3.png +0 -0
  91. package/packages/build.particle.wood_chip_dust_burst/effect.json +0 -1400
  92. package/packages/build.particle.wood_chip_dust_burst/media/contact-sheet.png +0 -0
  93. package/packages/build.particle.wood_chip_dust_burst/media/preview.gif +0 -0
  94. package/packages/build.particle.wood_chip_dust_burst/media/preview.mp4 +0 -0
  95. package/packages/build.particle.wood_chip_dust_burst/media/preview.webm +0 -0
  96. package/packages/build.particle.wood_chip_dust_burst/media/thumbnail.png +0 -0
  97. package/packages/build.particle.wood_chip_dust_burst/metadata/description.json +0 -173
  98. package/packages/build.particle.wood_chip_dust_burst/provenance/03-effect.original.json +0 -1277
  99. package/packages/build.particle.wood_chip_dust_burst/provenance/03-normalized-vfx-to-babylon-report.json +0 -329
  100. package/packages/build.particle.wood_chip_dust_burst/provenance/04-preview-overrides.json +0 -749
  101. package/packages/build.particle.wood_chip_dust_burst/provenance/04-preview-tuning-report.json +0 -60
  102. package/packages/build.particle.wood_chip_dust_burst/provenance/asset-map.json +0 -146
  103. package/packages/build.particle.wood_chip_dust_burst/provenance/lineage.json +0 -69
  104. package/packages/effects/building-upgrade/effect.json +0 -6
  105. package/packages/effects/building-upgrade/index.ts +0 -387
  106. package/packages/effects/character-entrance/effect.json +0 -6
  107. package/packages/effects/character-entrance/index.ts +0 -308
  108. package/packages/effects/coin-burst/index.ts +0 -43
  109. package/packages/effects/comet-trail-flame/assets/textures/trail_5x4.webp +0 -0
  110. package/packages/effects/comet-trail-flame/index.ts +0 -106
  111. package/packages/effects/conveyor-upgrade/effect.json +0 -6
  112. package/packages/effects/conveyor-upgrade/index.ts +0 -401
  113. package/packages/effects/debris-smoke/assets/models/rock_debris.glb +0 -0
  114. package/packages/effects/debris-smoke/assets/textures/smoke22.webp +0 -0
  115. package/packages/effects/debris-smoke/index.ts +0 -101
  116. package/packages/effects/door_open_gold_flakes/assets/runtime/goldFlakes.v1.js +0 -397
  117. package/packages/effects/door_open_gold_flakes/door_open_gold_flakes.json +0 -498
  118. package/packages/effects/door_open_gold_flakes/index.ts +0 -11
  119. package/packages/effects/electric-arc/assets/textures/spark_4x4.webp +0 -0
  120. package/packages/effects/electric-arc/index.ts +0 -62
  121. package/packages/effects/energy-shield/effect.json +0 -7
  122. package/packages/effects/energy-shield/index.ts +0 -431
  123. package/packages/effects/explosion/assets/textures/baozha29.webp +0 -0
  124. package/packages/effects/explosion/assets/textures/glow01.webp +0 -0
  125. package/packages/effects/explosion/assets/textures/lizi01.webp +0 -0
  126. package/packages/effects/explosion/assets/textures/xulie_lizibaozha02_5x5.webp +0 -0
  127. package/packages/effects/explosion/index.ts +0 -114
  128. package/packages/effects/ground-tile-upgrade/effect.json +0 -6
  129. package/packages/effects/ground-tile-upgrade/index.ts +0 -410
  130. package/packages/effects/hit-flash/index.ts +0 -69
  131. package/packages/effects/laser-beam/assets/textures/laser_glow.webp +0 -0
  132. package/packages/effects/laser-beam/assets/textures/laser_noise.webp +0 -0
  133. package/packages/effects/laser-beam/index.ts +0 -6
  134. package/packages/effects/laser-beam-factory.ts +0 -135
  135. package/packages/effects/lumber-cart-suction/effect.json +0 -6
  136. package/packages/effects/lumber-cart-suction/index.ts +0 -399
  137. package/packages/effects/lumber-debris-scatter/assets/models/lumber_prop_model.glb +0 -0
  138. package/packages/effects/lumber-debris-scatter/assets/models/lumber_prop_model.glb.versions/.active +0 -1
  139. package/packages/effects/lumber-debris-scatter/assets/models/lumber_prop_model.glb.versions/1781589063890_upload.glb +0 -0
  140. package/packages/effects/lumber-debris-scatter/assets/runtime/solidParticleScatter.v1.js +0 -236
  141. package/packages/effects/lumber-debris-scatter/effect.json +0 -228
  142. package/packages/effects/lumber-debris-scatter/index.ts +0 -780
  143. package/packages/effects/lumber_vehicle_gear_spin/assets/runtime/gearSpin.v1.js +0 -202
  144. package/packages/effects/lumber_vehicle_gear_spin/index.ts +0 -11
  145. package/packages/effects/lumber_vehicle_gear_spin/lumber_vehicle_gear_spin.json +0 -338
  146. package/packages/effects/lumber_vehicle_upgrade_aura/assets/runtime/upgradeAura.v1.js +0 -353
  147. package/packages/effects/lumber_vehicle_upgrade_aura/index.ts +0 -11
  148. package/packages/effects/lumber_vehicle_upgrade_aura/lumber_vehicle_upgrade_aura.json +0 -365
  149. package/packages/effects/lumber_vehicle_wood_chips/assets/runtime/solidParticleScatter.v1.js +0 -310
  150. package/packages/effects/lumber_vehicle_wood_chips/index.ts +0 -11
  151. package/packages/effects/lumber_vehicle_wood_chips/lumber_vehicle_wood_chips.json +0 -335
  152. package/packages/effects/monster-hit/index.ts +0 -128
  153. package/packages/effects/player-upgrade/effect.json +0 -6
  154. package/packages/effects/player-upgrade/index.ts +0 -635
  155. package/packages/effects/pulse-laser-volley/assets/textures/bolt_guangshu.webp +0 -0
  156. package/packages/effects/pulse-laser-volley/index.ts +0 -204
  157. package/packages/effects/resource-collect-sparkles/effect.json +0 -6
  158. package/packages/effects/resource-collect-sparkles/index.ts +0 -254
  159. package/packages/effects/run-footstep-dust/assets/runtime/runFootstepDust.v1.js +0 -215
  160. package/packages/effects/run-footstep-dust/effect.json +0 -183
  161. package/packages/effects/run-footstep-dust/index.ts +0 -377
  162. package/packages/effects/space-shared.ts +0 -120
  163. package/packages/effects/thruster-flame/index.ts +0 -305
  164. package/packages/effects/tree-chop-dust/assets/textures/tree_chop_dust_atlas.png +0 -0
  165. package/packages/effects/tree-chop-dust/effect.json +0 -8
  166. package/packages/effects/tree-chop-dust/index.ts +0 -202
  167. package/packages/effects/tree-leaf-chop-burst/assets/runtime/particleEmitter.v1.js +0 -303
  168. package/packages/effects/tree-leaf-chop-burst/assets/textures/tree_leaf_chop_burst_leaf_atlas.png +0 -0
  169. package/packages/effects/tree-leaf-chop-burst/effect.json +0 -498
  170. package/packages/effects/tree-leaf-chop-burst/index.ts +0 -294
  171. package/packages/effects/tree_chop_dust_burst/assets/runtime/particleEmitter.v1.js +0 -318
  172. package/packages/effects/tree_chop_dust_burst/assets/textures/tree_chop_dust_burst_dust.png +0 -0
  173. package/packages/effects/tree_chop_dust_burst/index.ts +0 -13
  174. package/packages/effects/tree_chop_dust_burst/tree_chop_dust_burst.json +0 -412
  175. package/packages/effects/ufo-thread-flame/assets/textures/flame_flow.webp +0 -0
  176. package/packages/effects/ufo-thread-flame/assets/textures/flame_spike.webp +0 -0
  177. package/packages/effects/ufo-thread-flame/index.ts +0 -152
  178. package/packages/effects/vehicle-exhaust-smoke/assets/textures/vehicle_exhaust_smoke_atlas.png +0 -0
  179. package/packages/effects/vehicle-exhaust-smoke/effect.json +0 -8
  180. package/packages/effects/vehicle-exhaust-smoke/index.ts +0 -298
  181. package/packages/effects/vehicle-upgrade/effect.json +0 -6
  182. package/packages/effects/vehicle-upgrade/index.ts +0 -401
  183. package/packages/effects/weapon-trail/assets/textures/trail_wedge.png +0 -0
  184. package/packages/effects/weapon-trail/index.ts +0 -313
  185. package/packages/effects/wood-crusher-sawdust/assets/runtime/particleEmitter.v1.js +0 -312
  186. package/packages/effects/wood-crusher-sawdust/assets/textures/wood_crusher_sawdust_dust.png +0 -0
  187. package/packages/effects/wood-crusher-sawdust/assets/textures/wood_crusher_sawdust_fiber.png +0 -0
  188. package/packages/effects/wood-crusher-sawdust/index.ts +0 -43
  189. package/packages/effects/wood-crusher-sawdust/wood_crusher_sawdust.json +0 -592
  190. package/packages/effects/wood-cutter-sawdust/assets/runtime/particleEmitter.v1.js +0 -312
  191. package/packages/effects/wood-cutter-sawdust/assets/textures/wood_cutter_sawdust_chip.png +0 -0
  192. package/packages/effects/wood-cutter-sawdust/assets/textures/wood_cutter_sawdust_dust.png +0 -0
  193. package/packages/effects/wood-cutter-sawdust/index.ts +0 -43
  194. package/packages/effects/wood-cutter-sawdust/wood_cutter_sawdust.json +0 -592
  195. package/packages/effects/wood-sawdust-effect-factory.ts +0 -194
  196. package/packages/effects/wood_crusher_sawdust/assets/runtime/particleEmitter.v1.js +0 -318
  197. package/packages/effects/wood_crusher_sawdust/assets/textures/wood_crusher_sawdust_dust.png +0 -0
  198. package/packages/effects/wood_crusher_sawdust/assets/textures/wood_crusher_sawdust_fiber.png +0 -0
  199. package/packages/effects/wood_crusher_sawdust/index.ts +0 -29
  200. package/packages/effects/wood_crusher_sawdust/wood_crusher_sawdust.json +0 -592
  201. package/packages/effects/wood_cutter_sawdust/assets/runtime/particleEmitter.v1.js +0 -318
  202. package/packages/effects/wood_cutter_sawdust/assets/textures/wood_cutter_sawdust_chip.png +0 -0
  203. package/packages/effects/wood_cutter_sawdust/assets/textures/wood_cutter_sawdust_dust.png +0 -0
  204. package/packages/effects/wood_cutter_sawdust/index.ts +0 -29
  205. package/packages/effects/wood_cutter_sawdust/wood_cutter_sawdust.json +0 -592
  206. package/packages/effects/wood_peel_material_test/assets/runtime/woodPeelMaterialTest.v1.js +0 -196
  207. package/packages/effects/wood_peel_material_test/index.ts +0 -11
  208. package/packages/effects/wood_peel_material_test/wood_peel_material_test.json +0 -136
  209. package/packages/env.particle.forest_edge_fog/assets/runtime/particleEmitter.v1.js +0 -210
  210. package/packages/env.particle.forest_edge_fog/assets/textures/f12a23c4-b924-4322-a260-3d982428f1e8.png +0 -0
  211. package/packages/env.particle.forest_edge_fog/assets/textures/yuan.png +0 -0
  212. package/packages/env.particle.forest_edge_fog/effect.json +0 -854
  213. package/packages/env.particle.forest_edge_fog/media/preview.gif +0 -0
  214. package/packages/env.particle.forest_edge_fog/media/preview.mp4 +0 -0
  215. package/packages/env.particle.forest_edge_fog/media/preview.webm +0 -0
  216. package/packages/env.particle.forest_edge_fog/media/thumbnail.png +0 -0
  217. package/packages/env.particle.forest_edge_fog/metadata/description.json +0 -148
  218. package/packages/env.particle.forest_edge_fog/provenance/03-effect.original.json +0 -827
  219. package/packages/env.particle.forest_edge_fog/provenance/03-normalized-vfx-to-babylon-report.json +0 -196
  220. package/packages/env.particle.forest_edge_fog/provenance/04-preview-overrides.json +0 -432
  221. package/packages/env.particle.forest_edge_fog/provenance/04-preview-tuning-report.json +0 -28
  222. package/packages/env.particle.forest_edge_fog/provenance/asset-map.json +0 -124
  223. package/packages/env.particle.forest_edge_fog/provenance/lineage.json +0 -41
  224. package/packages/generation.ts +0 -14
  225. package/packages/index.ts +0 -14
  226. package/packages/legacy-particle-runtime.ts +0 -113
  227. package/packages/manifestRuntimePackage.ts +0 -519
  228. package/packages/registry.ts +0 -85
  229. package/packages/rendering.ts +0 -13
  230. package/packages/resource.particle.viscous_oil_suction/assets/runtime/top_disk_suction/particleEmitter.v1.js +0 -424
  231. package/packages/resource.particle.viscous_oil_suction/assets/textures/Glow ad.png +0 -0
  232. package/packages/resource.particle.viscous_oil_suction/effect.json +0 -1254
  233. package/packages/resource.particle.viscous_oil_suction/media/preview.gif +0 -0
  234. package/packages/resource.particle.viscous_oil_suction/media/preview.mp4 +0 -0
  235. package/packages/resource.particle.viscous_oil_suction/media/preview.webm +0 -0
  236. package/packages/resource.particle.viscous_oil_suction/media/thumbnail.png +0 -0
  237. package/packages/resource.particle.viscous_oil_suction/metadata/description.json +0 -122
  238. package/packages/resource.particle.viscous_oil_suction/provenance/03-effect.original.json +0 -1051
  239. package/packages/resource.particle.viscous_oil_suction/provenance/03-normalized-vfx-to-babylon-report.json +0 -200
  240. package/packages/resource.particle.viscous_oil_suction/provenance/04-preview-overrides.json +0 -581
  241. package/packages/resource.particle.viscous_oil_suction/provenance/04-preview-tuning-report.json +0 -28
  242. package/packages/resource.particle.viscous_oil_suction/provenance/asset-map.json +0 -111
  243. package/packages/resource.particle.viscous_oil_suction/provenance/lineage.json +0 -45
  244. package/packages/types.ts +0 -107
  245. package/tooling/check-dist-runtime.mjs +0 -166
  246. package/tooling/generate-index.mjs +0 -55
  247. package/tooling/test-guardrails.mjs +0 -157
  248. package/tooling/validate-boundary.mjs +0 -92
  249. package/tooling/validate-effects.mjs +0 -304
  250. package/tooling/validate.mjs +0 -53
@@ -0,0 +1,535 @@
1
+ import { Constants } from "@babylonjs/core/Engines/constants";
2
+ import { GlowLayer } from "@babylonjs/core/Layers/glowLayer";
3
+ import { Material } from "@babylonjs/core/Materials/material";
4
+ import { StandardMaterial } from "@babylonjs/core/Materials/standardMaterial";
5
+ import { DynamicTexture } from "@babylonjs/core/Materials/Textures/dynamicTexture";
6
+ import { Texture } from "@babylonjs/core/Materials/Textures/texture";
7
+ import { Color3, Color4 } from "@babylonjs/core/Maths/math.color";
8
+ import { Vector3 } from "@babylonjs/core/Maths/math.vector";
9
+ import { Mesh } from "@babylonjs/core/Meshes/mesh";
10
+ import { VertexData } from "@babylonjs/core/Meshes/mesh.vertexData";
11
+ import { MeshBuilder } from "@babylonjs/core/Meshes/meshBuilder";
12
+ import { TransformNode } from "@babylonjs/core/Meshes/transformNode";
13
+ import { ParticleSystem } from "@babylonjs/core/Particles/particleSystem";
14
+ import { V as VFX_RENDERING_GROUP_ID, c as configureVfxParticleSystem } from "../../chunks/rendering-CV3nhygX.js";
15
+ const DEFAULT_PARAMS = {
16
+ radius: 1.15,
17
+ yOffset: 0.05,
18
+ height: 1.35,
19
+ rays: 9,
20
+ rayWidth: 0.34,
21
+ spinSpeed: 0.85,
22
+ color: { r: 1, g: 0.9, b: 0.22 },
23
+ auraColor: { r: 1, g: 0.82, b: 0.18 },
24
+ ringColor: { r: 1, g: 0.95, b: 0.38 },
25
+ rayColor: { r: 1, g: 0.76, b: 0.12 },
26
+ beamColor: { r: 1, g: 0.92, b: 0.32 },
27
+ opacity: 1,
28
+ auraOpacity: 0.82,
29
+ ringOpacity: 0.95,
30
+ beamOpacity: 0.68,
31
+ particleRate: 42,
32
+ particleLife: 0.82,
33
+ sparkleMinSize: 0.045,
34
+ sparkleMaxSize: 0.13,
35
+ riseSpeed: 0.72,
36
+ drift: 0.12,
37
+ bloomIntensity: 0.55,
38
+ bloomKernelSize: 32
39
+ };
40
+ const treasureAttentionEffectPackage = {
41
+ id: "treasure-attention",
42
+ nameZh: "宝藏注意力光效",
43
+ placement: "socket",
44
+ // 附着在宝藏上的注意力标记:geometry 挂 fxRoot 子节点承 yOffset,root 交给 service(挂载/位置由 service 管)
45
+ defaultParams: DEFAULT_PARAMS,
46
+ debugAnchor: "playerRight",
47
+ manifest: {
48
+ id: "treasure-attention",
49
+ nameZh: "宝藏注意力光效",
50
+ source: "docs/treasure_attention_fx_babylonjs_guide.md"
51
+ },
52
+ debugParams: [
53
+ { key: "radius", label: "光效半径", kind: "scale", min: 0.35, max: 3.5, step: 0.01 },
54
+ { key: "yOffset", label: "离地高度", kind: "number", min: -0.1, max: 0.4, step: 5e-3 },
55
+ { key: "height", label: "竖光高度", kind: "scale", min: 0.2, max: 3.5, step: 0.01 },
56
+ { key: "rays", label: "星芒数量", kind: "number", min: 0, max: 18, step: 1 },
57
+ { key: "rayWidth", label: "星芒宽度", kind: "scale", min: 0.05, max: 1, step: 0.01 },
58
+ { key: "spinSpeed", label: "旋转速度", kind: "number", min: -3, max: 3, step: 0.01 },
59
+ { key: "color", label: "上浮星星颜色", kind: "color" },
60
+ { key: "auraColor", label: "地面柔光颜色", kind: "color" },
61
+ { key: "ringColor", label: "光环颜色", kind: "color" },
62
+ { key: "rayColor", label: "旋转星芒颜色", kind: "color" },
63
+ { key: "beamColor", label: "竖向光柱颜色", kind: "color" },
64
+ { key: "opacity", label: "整体透明度", kind: "opacity", min: 0, max: 1.5, step: 0.01 },
65
+ { key: "auraOpacity", label: "地面柔光", kind: "opacity", min: 0, max: 1.5, step: 0.01 },
66
+ { key: "ringOpacity", label: "光环亮度", kind: "opacity", min: 0, max: 1.5, step: 0.01 },
67
+ { key: "beamOpacity", label: "竖光亮度", kind: "opacity", min: 0, max: 1.5, step: 0.01 },
68
+ { key: "particleRate", label: "闪片频率", kind: "number", min: 0, max: 120, step: 1 },
69
+ { key: "particleLife", label: "闪片寿命", kind: "lifetime", min: 0.2, max: 2.5, step: 0.01 },
70
+ { key: "sparkleMinSize", label: "闪片最小", kind: "scale", min: 0.01, max: 0.5, step: 5e-3 },
71
+ { key: "sparkleMaxSize", label: "闪片最大", kind: "scale", min: 0.01, max: 0.8, step: 5e-3 },
72
+ { key: "riseSpeed", label: "上浮速度", kind: "number", min: 0, max: 2.5, step: 0.01 },
73
+ { key: "drift", label: "横向漂移", kind: "number", min: 0, max: 1.2, step: 0.01 },
74
+ { key: "bloomIntensity", label: "Bloom 强度", kind: "number", min: 0, max: 2.5, step: 0.01 },
75
+ { key: "bloomKernelSize", label: "Bloom 半径", kind: "number", min: 8, max: 96, step: 1 }
76
+ ],
77
+ create({ scene, root, position, renderingGroupId, params }) {
78
+ return createTreasureAttentionFx(scene, { root, position, renderingGroupId, params, serviceOwnedRoot: true });
79
+ }
80
+ };
81
+ function createTreasureAttentionFx(scene, options = {}) {
82
+ let params = mergeParams(options.params);
83
+ const root = options.root ?? new TransformNode("vfx_treasureAttention_root", scene);
84
+ const disposeRoot = options.disposeRoot ?? true;
85
+ const renderingGroupId = options.renderingGroupId ?? VFX_RENDERING_GROUP_ID;
86
+ const sharedGlowLayer = options.glowLayer ?? null;
87
+ let target = options.target ?? null;
88
+ const serviceOwnedRoot = options.serviceOwnedRoot ?? false;
89
+ const basePosition = (options.position ?? root.position).clone();
90
+ const fxRoot = new TransformNode("vfx_treasureAttention_fxRoot", scene);
91
+ fxRoot.parent = root;
92
+ let enabled = true;
93
+ let disposed = false;
94
+ let elapsed = 0;
95
+ let raySignature = "";
96
+ const textures = /* @__PURE__ */ new Set();
97
+ const materials = /* @__PURE__ */ new Set();
98
+ const meshes = /* @__PURE__ */ new Set();
99
+ let rayMeshes = [];
100
+ let glowLayer = null;
101
+ let ownsGlowLayer = false;
102
+ const raysRoot = new TransformNode("vfx_treasureAttention_raysRoot", scene);
103
+ raysRoot.parent = fxRoot;
104
+ const auraTex = makeTexture(scene, textures, "vfx_treasureAttention_auraTex", 256, (ctx, size) => {
105
+ drawAuraTexture(ctx, size, DEFAULT_PARAMS.auraColor);
106
+ });
107
+ const ringTex = makeTexture(scene, textures, "vfx_treasureAttention_ringTex", 256, (ctx, size) => {
108
+ drawRingTexture(ctx, size, DEFAULT_PARAMS.ringColor);
109
+ });
110
+ const rayTex = makeTexture(scene, textures, "vfx_treasureAttention_rayTex", 256, (ctx, size) => {
111
+ drawRayTexture(ctx, size, DEFAULT_PARAMS.rayColor);
112
+ });
113
+ const beamTex = makeTexture(scene, textures, "vfx_treasureAttention_beamTex", 256, (ctx, size) => {
114
+ drawBeamTexture(ctx, size, DEFAULT_PARAMS.beamColor);
115
+ });
116
+ const sparkleTex = makeTexture(scene, textures, "vfx_treasureAttention_sparkleTex", 128, drawSparkleTexture);
117
+ const auraMat = makeAdditiveMaterial(scene, materials, "vfx_treasureAttention_auraMat", auraTex);
118
+ const ringMat = makeAdditiveMaterial(scene, materials, "vfx_treasureAttention_ringMat", ringTex);
119
+ const rayMat = makeAdditiveMaterial(scene, materials, "vfx_treasureAttention_rayMat", rayTex);
120
+ const beamMat = makeAdditiveMaterial(scene, materials, "vfx_treasureAttention_beamMat", beamTex);
121
+ const aura = addMesh(MeshBuilder.CreatePlane("vfx_treasureAttention_aura", { size: 1 }, scene));
122
+ aura.rotation.x = Math.PI / 2;
123
+ aura.position.y = 0.025;
124
+ aura.material = auraMat;
125
+ aura.parent = fxRoot;
126
+ aura.alphaIndex = 0;
127
+ const ring = addMesh(MeshBuilder.CreatePlane("vfx_treasureAttention_ring", { size: 1 }, scene));
128
+ ring.rotation.x = Math.PI / 2;
129
+ ring.position.y = 0.04;
130
+ ring.material = ringMat;
131
+ ring.parent = fxRoot;
132
+ ring.alphaIndex = 1;
133
+ const beam = addMesh(MeshBuilder.CreatePlane("vfx_treasureAttention_beam", { size: 1 }, scene));
134
+ beam.position.y = params.height * 0.52;
135
+ beam.billboardMode = Mesh.BILLBOARDMODE_Y;
136
+ beam.material = beamMat;
137
+ beam.parent = fxRoot;
138
+ beam.alphaIndex = 3;
139
+ const particleEmitter = addMesh(new Mesh("vfx_treasureAttention_particleEmitter", scene), false);
140
+ particleEmitter.isVisible = false;
141
+ particleEmitter.parent = fxRoot;
142
+ const particleSystem = new ParticleSystem("vfx_treasureAttention_sparkles", 180, scene);
143
+ configureVfxParticleSystem(particleSystem);
144
+ particleSystem.particleTexture = sparkleTex;
145
+ particleSystem.emitter = particleEmitter;
146
+ particleSystem.blendMode = ParticleSystem.BLENDMODE_ADD;
147
+ particleSystem.updateSpeed = 1 / 60;
148
+ particleSystem.minAngularSpeed = -4;
149
+ particleSystem.maxAngularSpeed = 4;
150
+ particleSystem.gravity = new Vector3(0, -0.04, 0);
151
+ particleSystem.start();
152
+ applyParams();
153
+ syncRoot();
154
+ const observer = scene.onBeforeRenderObservable.add(() => {
155
+ if (disposed || !enabled) return;
156
+ const dt = Math.min(scene.getEngine().getDeltaTime() / 1e3, 0.05);
157
+ elapsed += dt;
158
+ syncRoot();
159
+ animate(dt);
160
+ });
161
+ return {
162
+ root,
163
+ particleSystem,
164
+ update(partial) {
165
+ if (disposed) return;
166
+ params = mergeParams(partial, params);
167
+ applyParams();
168
+ syncRoot();
169
+ },
170
+ setEnabled(nextEnabled) {
171
+ enabled = nextEnabled;
172
+ root.setEnabled(nextEnabled);
173
+ if (nextEnabled) {
174
+ particleSystem.start();
175
+ } else {
176
+ particleSystem.stop();
177
+ }
178
+ },
179
+ setTarget(nextTarget) {
180
+ target = nextTarget;
181
+ syncRoot();
182
+ },
183
+ setPosition(position) {
184
+ basePosition.copyFrom(position);
185
+ syncRoot();
186
+ },
187
+ dispose() {
188
+ disposeAll();
189
+ }
190
+ };
191
+ function addMesh(mesh, includeInGlow = true) {
192
+ mesh.isPickable = false;
193
+ mesh.alwaysSelectAsActiveMesh = true;
194
+ mesh.renderingGroupId = renderingGroupId;
195
+ meshes.add(mesh);
196
+ if (includeInGlow) addGlowMesh(mesh);
197
+ return mesh;
198
+ }
199
+ function addGlowMesh(mesh) {
200
+ if (!glowLayer || !mesh.material) return;
201
+ glowLayer.addIncludedOnlyMesh(mesh);
202
+ glowLayer.referenceMeshToUseItsOwnMaterial(mesh);
203
+ }
204
+ function removeGlowMesh(mesh) {
205
+ glowLayer?.removeIncludedOnlyMesh(mesh);
206
+ }
207
+ function applyParams() {
208
+ redrawTexture(auraTex, 256, (ctx, size) => drawAuraTexture(ctx, size, params.auraColor));
209
+ redrawTexture(ringTex, 256, (ctx, size) => drawRingTexture(ctx, size, params.ringColor));
210
+ redrawTexture(rayTex, 256, (ctx, size) => drawRayTexture(ctx, size, params.rayColor));
211
+ redrawTexture(beamTex, 256, (ctx, size) => drawBeamTexture(ctx, size, params.beamColor));
212
+ auraMat.alpha = clamp(params.opacity * params.auraOpacity, 0, 1);
213
+ ringMat.alpha = clamp(params.opacity * params.ringOpacity, 0, 1);
214
+ rayMat.alpha = clamp(params.opacity * 0.9, 0, 1);
215
+ beamMat.alpha = clamp(params.opacity * params.beamOpacity, 0, 1);
216
+ fxRoot.position.y = params.yOffset;
217
+ aura.position.y = 0.015;
218
+ ring.position.y = aura.position.y + 0.018;
219
+ beam.position.y = params.height * 0.52;
220
+ beam.scaling.set(Math.max(0.02, params.radius * 1.05), Math.max(0.02, params.height), 1);
221
+ const particleLife = Math.max(0.04, params.particleLife);
222
+ const minSize = Math.max(1e-3, Math.min(params.sparkleMinSize, params.sparkleMaxSize));
223
+ const maxSize = Math.max(minSize, Math.max(params.sparkleMinSize, params.sparkleMaxSize));
224
+ particleSystem.emitRate = Math.max(0, params.particleRate);
225
+ particleSystem.minLifeTime = particleLife * 0.75;
226
+ particleSystem.maxLifeTime = particleLife * 1.2;
227
+ particleSystem.minSize = minSize;
228
+ particleSystem.maxSize = maxSize;
229
+ particleSystem.minEmitBox = new Vector3(-params.radius * 0.45, 0.15, -params.radius * 0.45);
230
+ particleSystem.maxEmitBox = new Vector3(params.radius * 0.45, 0.55, params.radius * 0.45);
231
+ particleSystem.direction1 = new Vector3(-params.drift, params.riseSpeed * 0.76, -params.drift);
232
+ particleSystem.direction2 = new Vector3(params.drift, params.riseSpeed * 1.24, params.drift);
233
+ particleSystem.minEmitPower = Math.max(0.01, params.riseSpeed * 0.28);
234
+ particleSystem.maxEmitPower = Math.max(particleSystem.minEmitPower, params.riseSpeed * 0.58);
235
+ particleSystem.color1 = tintColor(params.color, 1.15, 0.9 * params.opacity);
236
+ particleSystem.color2 = tintColor(params.color, 1.55, 0.76 * params.opacity);
237
+ particleSystem.colorDead = tintColor(params.color, 0.8, 0);
238
+ rebuildRaysIfNeeded();
239
+ syncGlowLayer();
240
+ }
241
+ function rebuildRaysIfNeeded() {
242
+ const rayCount = clamp(Math.round(params.rays), 0, 32);
243
+ const signature = `${rayCount}:${params.radius.toFixed(3)}:${params.rayWidth.toFixed(3)}`;
244
+ if (signature === raySignature) return;
245
+ raySignature = signature;
246
+ for (const ray of rayMeshes) {
247
+ removeGlowMesh(ray);
248
+ meshes.delete(ray);
249
+ ray.dispose(false, false);
250
+ }
251
+ rayMeshes = [];
252
+ for (let i = 0; i < rayCount; i += 1) {
253
+ const angle = i / Math.max(1, rayCount) * Math.PI * 2;
254
+ const length = params.radius * (0.95 + i % 3 * 0.13);
255
+ const width = params.rayWidth * (0.8 + i % 2 * 0.22);
256
+ const ray = createRayMesh(scene, `vfx_treasureAttention_ray_${i}`, length, width);
257
+ ray.parent = raysRoot;
258
+ ray.rotation.y = angle;
259
+ ray.position.y = ring.position.y + 0.014 + i * 1e-3;
260
+ ray.material = rayMat;
261
+ ray.alphaIndex = 2;
262
+ addMesh(ray);
263
+ rayMeshes.push(ray);
264
+ }
265
+ }
266
+ function syncGlowLayer() {
267
+ const shouldGlow = params.bloomIntensity > 0;
268
+ if (!shouldGlow) {
269
+ if (glowLayer) {
270
+ for (const mesh of meshes) removeGlowMesh(mesh);
271
+ }
272
+ if (ownsGlowLayer) glowLayer?.dispose();
273
+ glowLayer = null;
274
+ ownsGlowLayer = false;
275
+ return;
276
+ }
277
+ if (!glowLayer) {
278
+ if (sharedGlowLayer) {
279
+ glowLayer = sharedGlowLayer;
280
+ } else {
281
+ glowLayer = new GlowLayer(`vfx_treasureAttention_glow_${root.uniqueId}`, scene, {
282
+ blurKernelSize: params.bloomKernelSize,
283
+ mainTextureRatio: 0.4
284
+ });
285
+ ownsGlowLayer = true;
286
+ }
287
+ for (const mesh of meshes) addGlowMesh(mesh);
288
+ }
289
+ if (ownsGlowLayer && glowLayer) {
290
+ glowLayer.intensity = params.bloomIntensity;
291
+ glowLayer.blurKernelSize = params.bloomKernelSize;
292
+ }
293
+ }
294
+ function syncRoot() {
295
+ if (serviceOwnedRoot) return;
296
+ if (target) {
297
+ root.position.copyFrom(target.getAbsolutePosition());
298
+ return;
299
+ }
300
+ root.position.copyFrom(basePosition);
301
+ }
302
+ function animate(dt) {
303
+ const pulse = 0.5 + 0.5 * Math.sin(elapsed * 5.2);
304
+ const auraSize = params.radius * 2.55 * (0.96 + pulse * 0.11);
305
+ const ringSize = params.radius * 2.15 * (0.94 + pulse * 0.08);
306
+ aura.scaling.set(auraSize, auraSize, 1);
307
+ aura.visibility = clamp((0.72 + pulse * 0.24) * params.opacity * params.auraOpacity, 0, 1);
308
+ ring.rotation.z += dt * 0.65;
309
+ ring.scaling.set(ringSize, ringSize, 1);
310
+ ring.visibility = clamp((0.55 + pulse * 0.36) * params.opacity * params.ringOpacity, 0, 1);
311
+ beam.scaling.x = Math.max(0.02, params.radius * 1.05) * (0.85 + pulse * 0.28);
312
+ beam.scaling.y = Math.max(0.02, params.height);
313
+ beam.visibility = clamp((0.35 + pulse * 0.28) * params.opacity * params.beamOpacity, 0, 1);
314
+ raysRoot.rotation.y += dt * params.spinSpeed;
315
+ for (let i = 0; i < rayMeshes.length; i += 1) {
316
+ const q = 0.5 + 0.5 * Math.sin(elapsed * 4.4 + i * 0.9);
317
+ const ray = rayMeshes[i];
318
+ ray.visibility = clamp((0.42 + q * 0.42) * params.opacity, 0, 1);
319
+ ray.scaling.x = 0.92 + q * 0.18;
320
+ ray.scaling.z = 0.82 + q * 0.35;
321
+ }
322
+ if (ownsGlowLayer && glowLayer) {
323
+ glowLayer.intensity = params.bloomIntensity * (0.75 + pulse * 0.35);
324
+ }
325
+ }
326
+ function disposeAll() {
327
+ if (disposed) return;
328
+ disposed = true;
329
+ scene.onBeforeRenderObservable.remove(observer);
330
+ particleSystem.stop();
331
+ particleSystem.dispose(false);
332
+ if (glowLayer) {
333
+ for (const mesh of meshes) removeGlowMesh(mesh);
334
+ }
335
+ if (ownsGlowLayer) glowLayer?.dispose();
336
+ for (const mesh of meshes) {
337
+ mesh.dispose(false, false);
338
+ }
339
+ raysRoot.dispose();
340
+ for (const material of materials) material.dispose();
341
+ for (const texture of textures) texture.dispose();
342
+ if (disposeRoot) root.dispose();
343
+ }
344
+ }
345
+ function makeTexture(scene, textures, name, size, draw) {
346
+ const texture = new DynamicTexture(name, { width: size, height: size }, scene, false);
347
+ texture.hasAlpha = true;
348
+ texture.wrapU = Texture.CLAMP_ADDRESSMODE;
349
+ texture.wrapV = Texture.CLAMP_ADDRESSMODE;
350
+ const context = texture.getContext();
351
+ context.clearRect(0, 0, size, size);
352
+ draw(context, size);
353
+ texture.update(false);
354
+ textures.add(texture);
355
+ return texture;
356
+ }
357
+ function makeAdditiveMaterial(scene, materials, name, texture) {
358
+ const material = new StandardMaterial(name, scene);
359
+ material.diffuseTexture = texture;
360
+ material.emissiveTexture = texture;
361
+ material.diffuseColor = Color3.White();
362
+ material.emissiveColor = Color3.White();
363
+ material.specularColor = Color3.Black();
364
+ material.disableLighting = true;
365
+ material.backFaceCulling = false;
366
+ material.useAlphaFromDiffuseTexture = true;
367
+ material.transparencyMode = Material.MATERIAL_ALPHABLEND;
368
+ material.alphaMode = Constants.ALPHA_ADD;
369
+ material.disableDepthWrite = true;
370
+ materials.add(material);
371
+ return material;
372
+ }
373
+ function createRayMesh(scene, name, length, width) {
374
+ const mesh = new Mesh(name, scene);
375
+ const positions = [
376
+ 0,
377
+ 0,
378
+ -width * 0.5,
379
+ length,
380
+ 0,
381
+ -width * 0.12,
382
+ length,
383
+ 0,
384
+ width * 0.12,
385
+ 0,
386
+ 0,
387
+ width * 0.5
388
+ ];
389
+ const vertexData = new VertexData();
390
+ vertexData.positions = positions;
391
+ vertexData.indices = [0, 1, 2, 0, 2, 3];
392
+ vertexData.normals = [
393
+ 0,
394
+ 1,
395
+ 0,
396
+ 0,
397
+ 1,
398
+ 0,
399
+ 0,
400
+ 1,
401
+ 0,
402
+ 0,
403
+ 1,
404
+ 0
405
+ ];
406
+ vertexData.uvs = [0, 0, 1, 0, 1, 1, 0, 1];
407
+ vertexData.applyToMesh(mesh, false);
408
+ return mesh;
409
+ }
410
+ function redrawTexture(texture, size, draw) {
411
+ const context = texture.getContext();
412
+ context.clearRect(0, 0, size, size);
413
+ draw(context, size);
414
+ texture.update(false);
415
+ }
416
+ function drawAuraTexture(ctx, size, color) {
417
+ const center = size / 2;
418
+ const gradient = ctx.createRadialGradient(center, center, 0, center, center, center);
419
+ gradient.addColorStop(0, colorRgba(color, 0.86));
420
+ gradient.addColorStop(0.25, colorRgba(color, 0.46));
421
+ gradient.addColorStop(0.55, colorRgba(color, 0.16));
422
+ gradient.addColorStop(1, colorRgba(color, 0));
423
+ ctx.fillStyle = gradient;
424
+ ctx.fillRect(0, 0, size, size);
425
+ }
426
+ function drawRingTexture(ctx, size, color) {
427
+ const center = size / 2;
428
+ ctx.shadowColor = colorRgba(color, 0.9);
429
+ ctx.shadowBlur = size * 0.05;
430
+ ctx.strokeStyle = colorRgba(color, 0.78);
431
+ ctx.lineWidth = size * 0.035;
432
+ ctx.beginPath();
433
+ ctx.arc(center, center, size * 0.31, 0, Math.PI * 2);
434
+ ctx.stroke();
435
+ ctx.lineWidth = size * 0.012;
436
+ ctx.strokeStyle = colorRgba(lightenColor(color, 0.58), 0.85);
437
+ ctx.beginPath();
438
+ ctx.arc(center, center, size * 0.42, 0, Math.PI * 2);
439
+ ctx.stroke();
440
+ }
441
+ function drawRayTexture(ctx, size, color) {
442
+ const gradient = ctx.createLinearGradient(0, 0, size, 0);
443
+ gradient.addColorStop(0, colorRgba(color, 0));
444
+ gradient.addColorStop(0.18, colorRgba(lightenColor(color, 0.35), 0.72));
445
+ gradient.addColorStop(0.55, colorRgba(color, 0.34));
446
+ gradient.addColorStop(1, colorRgba(color, 0));
447
+ ctx.fillStyle = gradient;
448
+ ctx.beginPath();
449
+ ctx.moveTo(0, size * 0.5);
450
+ ctx.quadraticCurveTo(size * 0.45, size * 0.1, size, size * 0.18);
451
+ ctx.lineTo(size, size * 0.82);
452
+ ctx.quadraticCurveTo(size * 0.45, size * 0.9, 0, size * 0.5);
453
+ ctx.closePath();
454
+ ctx.fill();
455
+ }
456
+ function drawBeamTexture(ctx, size, color) {
457
+ const center = size / 2;
458
+ const radial = ctx.createRadialGradient(center, center, 0, center, center, center * 0.55);
459
+ radial.addColorStop(0, colorRgba(lightenColor(color, 0.65), 0.75));
460
+ radial.addColorStop(0.28, colorRgba(color, 0.35));
461
+ radial.addColorStop(1, colorRgba(color, 0));
462
+ ctx.fillStyle = radial;
463
+ ctx.fillRect(0, 0, size, size);
464
+ const vertical = ctx.createLinearGradient(0, 0, 0, size);
465
+ vertical.addColorStop(0, colorRgba(color, 0));
466
+ vertical.addColorStop(0.42, colorRgba(lightenColor(color, 0.42), 0.42));
467
+ vertical.addColorStop(0.62, colorRgba(lightenColor(color, 0.42), 0.42));
468
+ vertical.addColorStop(1, colorRgba(color, 0));
469
+ ctx.fillStyle = vertical;
470
+ ctx.fillRect(size * 0.43, 0, size * 0.14, size);
471
+ }
472
+ function drawSparkleTexture(ctx, size) {
473
+ const center = size / 2;
474
+ ctx.save();
475
+ ctx.translate(center, center);
476
+ ctx.shadowColor = "rgba(255,255,255,1)";
477
+ ctx.shadowBlur = size * 0.12;
478
+ ctx.fillStyle = "rgba(255,255,255,0.95)";
479
+ ctx.beginPath();
480
+ for (let i = 0; i < 8; i += 1) {
481
+ const angle = i * Math.PI / 4;
482
+ const radius = i % 2 === 0 ? size * 0.42 : size * 0.12;
483
+ const x = Math.cos(angle) * radius;
484
+ const y = Math.sin(angle) * radius;
485
+ if (i === 0) ctx.moveTo(x, y);
486
+ else ctx.lineTo(x, y);
487
+ }
488
+ ctx.closePath();
489
+ ctx.fill();
490
+ ctx.restore();
491
+ }
492
+ function mergeParams(patch, base = DEFAULT_PARAMS) {
493
+ return {
494
+ ...base,
495
+ ...patch,
496
+ color: copyColor(patch?.color, base.color),
497
+ auraColor: copyColor(patch?.auraColor, base.auraColor),
498
+ ringColor: copyColor(patch?.ringColor, base.ringColor),
499
+ rayColor: copyColor(patch?.rayColor, base.rayColor),
500
+ beamColor: copyColor(patch?.beamColor, base.beamColor)
501
+ };
502
+ }
503
+ function copyColor(value, fallback) {
504
+ return value ? { ...value } : { ...fallback };
505
+ }
506
+ function tintColor(color, brightness, alpha) {
507
+ return new Color4(
508
+ Math.max(0, color.r * brightness),
509
+ Math.max(0, color.g * brightness),
510
+ Math.max(0, color.b * brightness),
511
+ clamp(alpha, 0, 1)
512
+ );
513
+ }
514
+ function colorRgba(color, alpha) {
515
+ const r = Math.round(clamp(color.r, 0, 1) * 255);
516
+ const g = Math.round(clamp(color.g, 0, 1) * 255);
517
+ const b = Math.round(clamp(color.b, 0, 1) * 255);
518
+ return `rgba(${r},${g},${b},${clamp(alpha, 0, 1)})`;
519
+ }
520
+ function lightenColor(color, amount) {
521
+ const t = clamp(amount, 0, 1);
522
+ return {
523
+ r: color.r + (1 - color.r) * t,
524
+ g: color.g + (1 - color.g) * t,
525
+ b: color.b + (1 - color.b) * t
526
+ };
527
+ }
528
+ function clamp(value, min, max) {
529
+ return Math.min(max, Math.max(min, value));
530
+ }
531
+ export {
532
+ createTreasureAttentionFx,
533
+ treasureAttentionEffectPackage as default,
534
+ treasureAttentionEffectPackage
535
+ };
@@ -39,6 +39,7 @@ function excludeFromGlow(scene, mesh) {
39
39
  const ufoThreadFlameEffectPackage = {
40
40
  id: "ufo-thread-flame",
41
41
  nameZh: "UFO丝束尾焰",
42
+ placement: "socket",
42
43
  debugAnchor: "player",
43
44
  defaultParams: DEFAULT_PARAMS,
44
45
  debugParams: [
@@ -38,8 +38,11 @@ const DEFAULT_PARAMS = {
38
38
  const vehicleUpgradeEffectPackage = {
39
39
  id: "vehicle-upgrade",
40
40
  nameZh: "建筑&地块&设备升级",
41
+ placement: "socket",
41
42
  manifest,
42
43
  defaultParams: DEFAULT_PARAMS,
44
+ // initialHeight 走 service 存活的 Y 偏移通道(G6/M12)。
45
+ spawnParams: { offsetY: "initialHeight" },
43
46
  debugAnchor: "playerRight",
44
47
  debugParams: [
45
48
  { key: "lifetime", label: "生命周期", kind: "lifetime", min: 0.2, max: 6, step: 0.01 },
@@ -59,7 +62,7 @@ const vehicleUpgradeEffectPackage = {
59
62
  { key: "glowOpacity", label: "光幕强度", kind: "opacity", min: 0, max: 1, step: 0.01 }
60
63
  ],
61
64
  create({ scene, root, position, params }) {
62
- root.position.copyFrom(position).addInPlace(new Vector3(0, params.initialHeight, 0));
65
+ root.position.copyFrom(position);
63
66
  const centerStrands = createStrandSystem(scene, root, params, "center");
64
67
  const outlineStrands = createStrandSystem(scene, root, params, "outline");
65
68
  const glow = createOutlineGlow(scene, root, params);
@@ -14,9 +14,10 @@ const trailTextureUrl = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAP4AAABNC
14
14
  const DEFAULT_PARAMS = {
15
15
  ...LIFETIME_DEFAULTS,
16
16
  orientation: "horizontal",
17
- orbitRadius: 1.6,
17
+ orbitRadius: 0,
18
18
  orbitSpeed: 7,
19
19
  height: 0,
20
+ // 默认 0:真实跟随挂点(orbit>0 是演示用的幻影圆周轨道)
20
21
  trailLength: 16,
21
22
  worldLength: 4,
22
23
  width: 1.01,
@@ -90,6 +91,8 @@ function lerpSample(a, b, t, dst) {
90
91
  const weaponTrailEffectPackage = {
91
92
  id: "weapon-trail",
92
93
  nameZh: "武器拖尾",
94
+ placement: "socket",
95
+ geometrySpace: "world",
93
96
  debugAnchor: "player",
94
97
  defaultParams: DEFAULT_PARAMS,
95
98
  debugParams: [
@@ -120,8 +123,9 @@ const weaponTrailEffectPackage = {
120
123
  { key: "sparkRate", label: "刃头火花/秒", kind: "number", min: 0, max: 80, step: 1 },
121
124
  { key: "tint", label: "颜色", kind: "color" }
122
125
  ],
123
- create({ scene, root, position, params }) {
126
+ create({ scene, root, position, params, renderingGroupId }) {
124
127
  root.position.copyFrom(position);
128
+ const rgid = renderingGroupId ?? 0;
125
129
  registerShaders();
126
130
  const blend = params.blendMode === "combine" ? Constants.ALPHA_COMBINE : Constants.ALPHA_ADD;
127
131
  const tex = new Texture(trailTextureUrl, scene, true, false);
@@ -162,7 +166,7 @@ const weaponTrailEffectPackage = {
162
166
  m.alwaysSelectAsActiveMesh = true;
163
167
  m.useVertexColors = true;
164
168
  m.hasVertexAlpha = true;
165
- m.renderingGroupId = 0;
169
+ m.renderingGroupId = rgid;
166
170
  m.alphaIndex = ai;
167
171
  return m;
168
172
  }
@@ -185,6 +189,7 @@ const weaponTrailEffectPackage = {
185
189
  const c255 = `${Math.round(params.tint.r * 255)},${Math.round(params.tint.g * 255)},${Math.round(params.tint.b * 255)}`;
186
190
  const flare = makeFlareTexture(scene, "vfx_weaponTrail_sparkTex", "255,255,255", c255);
187
191
  sparkPs = new ParticleSystem("vfx_weaponTrail_sparks", 160, scene);
192
+ sparkPs.renderingGroupId = rgid;
188
193
  sparkPs.particleTexture = flare;
189
194
  sparkPs.emitter = sparkEmitter;
190
195
  sparkPs.minSize = 0.07;
@@ -12,5 +12,9 @@ export declare const woodCrusherSawdustEffectPackage: {
12
12
  spawnParams?: import('../..').VfxSpawnParamKeys;
13
13
  savedParams?: Partial<import('../..').VfxParamValues>;
14
14
  debugParams: import('../..').VfxParamDefinition[];
15
+ placement?: import('../..').VfxPlacement;
16
+ requiredInputs?: import('../..').VfxInputKey[];
17
+ optionalInputs?: import('../..').VfxInputKey[];
18
+ geometrySpace?: "local" | "world";
15
19
  create(context: import('../..').VfxEffectPackageContext<import('../..').VfxParamValues>): import('../..').VfxEffectHandle;
16
20
  };
@@ -12,5 +12,9 @@ export declare const woodCutterSawdustEffectPackage: {
12
12
  spawnParams?: import('../..').VfxSpawnParamKeys;
13
13
  savedParams?: Partial<import('../..').VfxParamValues>;
14
14
  debugParams: import('../..').VfxParamDefinition[];
15
+ placement?: import('../..').VfxPlacement;
16
+ requiredInputs?: import('../..').VfxInputKey[];
17
+ optionalInputs?: import('../..').VfxInputKey[];
18
+ geometrySpace?: "local" | "world";
15
19
  create(context: import('../..').VfxEffectPackageContext<import('../..').VfxParamValues>): import('../..').VfxEffectHandle;
16
20
  };