@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
@@ -1,297 +0,0 @@
1
- # 如何制作一个 VFX 特效(@fps/vfx 作者指南)
2
-
3
- 面向在 `fps-vfx-library` 里**新增/修改特效**的人(human 或 coding agent)。读完你能从零写出一个能被项目导入、能在 DEV 调试面板里调参的特效。
4
-
5
- 配套:运行手册见 `.claude/skills/vfx-library-maintenance/`;库总设计见 issue #1 / `docs/VFX_LIBRARY_PLAN.md`;参数运转的代码细节见本文 §5。
6
-
7
- ---
8
-
9
- ## 0. 核心概念:一个特效 = 一个 `VfxEffectPackage`
10
-
11
- 每个特效是 `packages/effects/<dir>/index.ts` 导出的一个对象,实现 `VfxEffectPackage`(定义在 `packages/types.ts`):
12
-
13
- ```ts
14
- interface VfxEffectPackage<P> {
15
- id: string; // 全局唯一 id
16
- nameZh: string; // 中文名(面板下拉显示)
17
- defaultParams: P; // 参数默认值(运行时真正用的数据)
18
- debugParams: VfxParamDefinition[]; // 参数的 UI 描述(面板照它建控件)
19
- create(ctx): VfxEffectHandle; // 唯一入口:用 ctx + params 在场景里建出特效
20
- debugAnchor?: 'playerRight' | 'player'; // 面板里默认 spawn 锚点
21
- manifest?: VfxEffectManifest; // 可选:检索元数据
22
- spawnParams?, savedParams?; // 可选:见 §5
23
- }
24
- ```
25
-
26
- 宿主(项目)只通过 `playEffectPackage(id, params, transform)` 触发它;特效拿到 `ctx`(scene/root/position/params)自给自足地建粒子/网格。**特效绝不 import 项目代码**(纯净契约,§7)。
27
-
28
- **两类实现**:
29
- - **code 类**(逃生舱):`index.ts` 手写 `create()`,直接用 Babylon `ParticleSystem`/`Sprite`/`Mesh`。适合复杂、跟随、mesh/GLB 特效。**本指南主讲这类。**
30
- - **data 类**(数据驱动):`index.ts` 是薄包装,调工厂 `createManifestRuntimeEffectPackage` 读 manifest JSON。适合标准粒子、AI 可生成。见 §6。
31
-
32
- ---
33
-
34
- ## 1. 五分钟:一个最小 code 特效
35
-
36
- 目录:`packages/effects/ember-sparks/`
37
-
38
- ```
39
- ember-sparks/
40
- ├── index.ts # 特效本体
41
- ├── vfx-params.json # 调参种子(项目会拷走并各自调)
42
- └── assets/textures/ember_spark.png # 贴图(经 ?url 打包内联)
43
- ```
44
-
45
- `index.ts`:
46
-
47
- ```ts
48
- import { Color4 } from '@babylonjs/core/Maths/math.color';
49
- import { ParticleSystem } from '@babylonjs/core/Particles/particleSystem';
50
- import { Texture } from '@babylonjs/core/Materials/Textures/texture';
51
- import type { VfxColorValue, VfxEffectPackage, VfxParamValues } from '../../types';
52
- import { VFX_RENDERING_GROUP_ID } from '../../rendering';
53
- import sparkTextureUrl from './assets/textures/ember_spark.png?url'; // ✅ 资源用 ?url
54
-
55
- // 1) 参数类型 + 默认值
56
- interface EmberSparksParams extends VfxParamValues {
57
- lifetime: number; // 特效整体存活秒数
58
- count: number; // 粒子数
59
- size: number; // 粒子大小
60
- speed: number; // 飞散速度
61
- color: VfxColorValue; // 颜色 {r,g,b}(0..1)
62
- }
63
-
64
- const DEFAULT_PARAMS: EmberSparksParams = {
65
- lifetime: 1.2, count: 60, size: 0.12, speed: 3, color: { r: 1, g: 0.6, b: 0.15 },
66
- };
67
-
68
- export const emberSparksEffectPackage: VfxEffectPackage<EmberSparksParams> = {
69
- id: 'ember-sparks',
70
- nameZh: '火星迸射',
71
- defaultParams: DEFAULT_PARAMS,
72
- debugAnchor: 'playerRight',
73
-
74
- // 2) 面板控件:每条 = 一个旋钮。key 必须与 defaultParams / create() 读取的 key 一致(见 §4)
75
- debugParams: [
76
- { key: 'lifetime', label: '存活时长', kind: 'lifetime', min: 0.2, max: 5, step: 0.1 },
77
- { key: 'count', label: '粒子数', kind: 'number', min: 1, max: 300, step: 1 },
78
- { key: 'size', label: '粒子大小', kind: 'scale', min: 0.01,max: 2, step: 0.01 },
79
- { key: 'speed', label: '飞散速度', kind: 'number', min: 0, max: 20, step: 0.1 },
80
- { key: 'color', label: '颜色', kind: 'color' },
81
- ],
82
-
83
- // 3) create:用 ctx + params 建特效。每个 params.<key> 来自五层合并后的最终值
84
- create({ scene, root, position, renderingGroupId, params }) {
85
- root.position.copyFrom(position);
86
- const ps = new ParticleSystem('ember_sparks', Math.ceil(params.count), scene);
87
- ps.particleTexture = new Texture(sparkTextureUrl, scene);
88
- ps.emitter = root; // 挂在 root 上 → 宿主 reparent root 即可跟随物体
89
- ps.minSize = ps.maxSize = params.size;
90
- ps.minEmitPower = params.speed * 0.5;
91
- ps.maxEmitPower = params.speed;
92
- ps.color1 = new Color4(params.color.r, params.color.g, params.color.b, 1);
93
- ps.emitRate = params.count / params.lifetime;
94
- ps.renderingGroupId = renderingGroupId ?? VFX_RENDERING_GROUP_ID; // ✅ 用库常量,别写 magic number
95
- ps.start();
96
-
97
- const stopTimer = window.setTimeout(() => ps.stop(), params.lifetime * 1000);
98
- // 4) 必须返回 handle:root + dispose(清理一切,别漏 timer/observer/system)
99
- return {
100
- root,
101
- dispose() { window.clearTimeout(stopTimer); ps.dispose(); root.dispose(); },
102
- };
103
- },
104
- };
105
- ```
106
-
107
- `vfx-params.json`(种子,项目会拷走并各自调;`params` 里只放想覆盖默认值的项,空也行):
108
-
109
- ```json
110
- { "schemaVersion": "vfx-params/1.0", "effectId": "ember-sparks", "params": {} }
111
- ```
112
-
113
- 校验 + 自测:
114
-
115
- ```bash
116
- node tooling/validate-effects.mjs --effect ember-sparks # 单个特效快速 lint
117
- pnpm validate # 全量(含 build + dist 扫描)
118
- ```
119
-
120
- 装进一个项目试调:`node node_modules/@fps/vfx/tooling/vfx-cli.mjs add ember-sparks --project .` → `pnpm dev` → 右下 **VFX** 按钮 → 选「火星迸射」→ 调参 → 播放/保存。
121
-
122
- ---
123
-
124
- ## 2. `create(ctx)` 契约
125
-
126
- `ctx`(`VfxEffectPackageContext`)给你:
127
-
128
- | 字段 | 含义 |
129
- |---|---|
130
- | `scene` | Babylon `Scene` |
131
- | `root` | 已建好的 `TransformNode`,已放到 spawn 位置;**把特效挂在它下面**,宿主 reparent 它即可跟随 |
132
- | `position` | spawn 世界坐标(= `root.position` 的副本) |
133
- | `rotationY` | spawn 朝向 |
134
- | `renderingGroupId` | 渲染组(可选;没有就用 `VFX_RENDERING_GROUP_ID`) |
135
- | `params` | **五层合并后的最终参数**(见 §5),按 key 读 |
136
-
137
- 返回 `VfxEffectHandle`:
138
-
139
- ```ts
140
- interface VfxEffectHandle {
141
- root: TransformNode;
142
- ready?: Promise<void>; // 异步加载(GLB/贴图)时返回它;宿主可 await(warmup 用),别漏
143
- dispose(): void; // 清理一切:粒子系统 / observer / setTimeout / mesh / root.dispose()
144
- }
145
- ```
146
-
147
- 规则:
148
- - **跟随型特效用 code 类**,把发射器挂 `root`,宿主 reparent root 即跟随(`root.getWorldMatrix()`)。data 类一次性定位、不跟随。
149
- - **异步加载**(GLB、贴图)→ 把加载 promise 放 `ready`,且 `dispose` 要能在加载未完成时也安全清理(置 `disposed` 标志)。参考 `lumber-debris-scatter`。
150
- - `create()` 内部抛错不会崩场景(service 有 try/catch 兜底),但**别把资源泄漏在错误路径**。
151
-
152
- ---
153
-
154
- ## 3. `debugParams` 是什么、面板怎么用它
155
-
156
- `debugParams` 是**参数的 UI 描述**;DEV 调试面板**照它自动生成控件**(`runtime-vfx-debug-panel.ts` 读 `effectPackage.debugParams`,一条 = 一个旋钮)。你不用写任何面板代码——声明即出控件。
157
-
158
- 每条是一个 `VfxParamDefinition`:
159
-
160
- | `kind` | 面板控件 | 额外字段 | 值类型 |
161
- |---|---|---|---|
162
- | `number` | 数字输入框 | `min` / `max` / `step` | `number` |
163
- | `lifetime` | 数字框(语义=时长) | `min` / `max` / `step` | `number` |
164
- | `scale` | 数字框(语义=缩放) | `min` / `max` / `step` | `number` |
165
- | `opacity` | 数字框(语义=透明度) | `min` / `max` / `step` | `number` |
166
- | `color` | 取色器 | — | `{ r, g, b }`(0..1) |
167
- | `enum` | 下拉 | `options: [{value,label}]` | `string` |
168
-
169
- 公共字段:`key`(必填,见 §4)、`label`(中文标签)、`description?`。
170
-
171
- ```ts
172
- { key: 'scatterShape', label: '散落形态', kind: 'enum',
173
- options: [ { value: 'radial', label: '中心外扩' }, { value: 'vertical', label: '垂直下落' } ] }
174
- ```
175
-
176
- > 不想暴露到面板的内部参数:放 `defaultParams` 但**不放** `debugParams` 即可(常见且允许)。反过来不行——见 §4。
177
-
178
- ---
179
-
180
- ## 4. ⭐ key 一致性:面板↔参数靠 `key` 字符串对齐
181
-
182
- 三处用**同一个 key 串**起来:
183
-
184
- ```
185
- debugParams[i].key ←→ defaultParams[key] ←→ create() 里读的 params[key]
186
- ```
187
-
188
- - 面板把旋钮的值写进 `params[key]`;`create()` 用 `params[key]` 去设粒子属性。key 对不上 → **旋钮调了没反应**。
189
- - 硬规则(guardrail 强制):**每个 `debugParams[].key` 必须在 `defaultParams` 里有默认值**。`validate-effects.mjs` 会静态检查;拼错 key(如 `partcileCount`)会被拦下:
190
- ```
191
- [参数] debugParams 旋钮 [partcileCount] 在 defaultParams 里没有对应默认值 → 面板调它不生效…
192
- ```
193
- - 反向(`defaultParams` 有、`debugParams` 没有)= 内部参数,允许(不强制每个值都给旋钮)。
194
- - 你在 `create()` 里读哪些 `params.<key>`,就应该在 `defaultParams` 给默认值;想让人调的,再加进 `debugParams`。
195
-
196
- ---
197
-
198
- ## 5. 参数怎么运转(五层合并)
199
-
200
- `playEffectPackage(id, explicitParams, transform)`(`EffectPackageService.ts`)按顺序合并 5 层,**后面的盖前面的**,得到最终 `params` 传给 `create()`:
201
-
202
- ```
203
- 1. 生成默认(spawn 位置偏移 offsetX/Y/Z)
204
- 2. defaultParams —— 你在库里写的默认值
205
- 3. savedParams —— 项目的 vfx-params.json(经 buildRegistry 注入)
206
- 4. 运行时 override —— 面板调参时 setDebugOverride 实时写的
207
- 5. explicitParams —— 调用方临时传的(gameplay 触发时算的动态值)
208
- ```
209
-
210
- 含义:
211
- - **面板调参 = 第 4 层**;点「保存」→ 写回项目 `effects/<id>/vfx-params.json`(第 3 层)→ 下次加载即新默认。
212
- - **库代码不被改**(模型 C:代码在 `@fps/vfx` 包,调参在项目的 `vfx-params.json`)。
213
- - **面板调好的值,游戏正式跑也生效**——gameplay 的 system 触发也走同一条合并。
214
-
215
- 调参面板的存盘端点(DEV):面板「保存」→ `POST /__debug_panel_config?file=effects/<id>/vfx-params.json`(vite 中间件落盘,只写 `params`)。
216
-
217
- ---
218
-
219
- ## 6. data 类特效(manifest + 工厂)
220
-
221
- 标准粒子可以不手写 `create()`,改用工厂读 manifest:
222
-
223
- ```ts
224
- // packages/effects/spark_puff/index.ts
225
- import manifest from './spark_puff.json'; // vfx-effect-package 格式(emitters + tunableParams)
226
- import runtimeUrl from './assets/runtime/particleEmitter.v1.js?url'; // 引擎适配器,?url 注入
227
- import texUrl from './assets/textures/spark.png?url';
228
- import { createManifestRuntimeEffectPackage } from '../../manifestRuntimePackage';
229
-
230
- export const sparkPuffEffectPackage = createManifestRuntimeEffectPackage({
231
- id: 'spark_puff',
232
- manifest,
233
- assetUrls: {
234
- 'assets/runtime/particleEmitter.v1.js': runtimeUrl,
235
- 'assets/textures/spark.png': texUrl,
236
- },
237
- });
238
- ```
239
-
240
- - `defaultParams` / `debugParams` / `nameZh` 由**工厂从 manifest 的 `tunableParams` 生成**(所以 data 类 index.ts 里看不到它们字面量,key 检查也跳过)。
241
- - 双发射器(dust + 碎屑)有专用工厂 `createWoodSawdustEffectPackage`(见 `wood-crusher-sawdust`)。
242
- - data 类**一次性定位、不跟随**;要跟随用 code 类。
243
-
244
- ---
245
-
246
- ## 7. 硬约束:库纯净契约(违反会被 guardrail 拦)
247
-
248
- 1. **不 import 任何项目代码**。只允许 `@babylonjs/*`、库内相对路径(`../../types`/`../../rendering`)、自身资源。特效↔宿主唯一通道 = `create(ctx)`。
249
- 2. **资源自带**:贴图/GLB/runtime-js 放包内,`import x from './assets/…?url'`。**禁 `new URL(…, import.meta.url)`**(库 build 不内联它)。
250
- 3. **glTF 只用核心 loader**:`import '@babylonjs/loaders/glTF/2.0/glTFLoader'`。**禁全量 barrel**(`@babylonjs/loaders` / `…/glTF`)——会把 `MeshoptDecoder` 拉进 consumer 包,违反 Playable 策略(#2 v0.1.1)。GLB 必须 plain(零扩展)。见 `lumber-debris-scatter`。
251
- 4. **配置参数化**:任何"配置值"做成 `defaultParams`/`debugParams`,经 `params` 传入。
252
- 5. **渲染组用常量** `VFX_RENDERING_GROUP_ID`,别写 magic number。
253
-
254
- ---
255
-
256
- ## 8. 工作流:校验 → 安装 → 发版
257
-
258
- ```bash
259
- # 作者本地(改完特效):
260
- node tooling/validate-effects.mjs --effect <id> # 单特效快速 lint
261
- pnpm validate # 全量 guardrail(boundary+lint+typecheck+build+dist)
262
- pnpm test:guardrails # guardrail 回归
263
-
264
- # 在某项目里调试:
265
- node node_modules/@fps/vfx/tooling/vfx-cli.mjs add <id> --project . # 装桩+种子params
266
- pnpm dev # → VFX 面板调参/保存
267
-
268
- # 发版(让消费方拿到新特效):
269
- pnpm release -- minor --dry-run # 预演(新增特效=minor)
270
- pnpm release -- minor # gate→bump→index/CHANGELOG→提交dist→tag→push
271
- ```
272
-
273
- ---
274
-
275
- ## 9. 常见坑
276
-
277
- | 坑 | 现象 | 修 |
278
- |---|---|---|
279
- | 全量 glTF loader | prod 构建被 meshopt 检查卡住 | 用 `@babylonjs/loaders/glTF/2.0/glTFLoader` |
280
- | `new URL(...)` 引资源 | 库 build 后资源丢失 | 改 `import x from './…?url'` |
281
- | debugParams key 拼错 | 面板旋钮调了没反应 | key 对齐 defaultParams(guardrail 会拦) |
282
- | 想跟随却用了 data 类 | 特效不跟物体 | 用 code 类,挂 `root`,宿主 reparent |
283
- | `dispose` 漏清理 | 切场景/重复播泄漏 | dispose 清 system/observer/timer/mesh/root |
284
- | 异步加载没给 `ready` | warmup 时机错乱 | 返回 handle 时带 `ready: Promise` |
285
- | 引用项目模块 | boundary 报错 | 改成 ctx 注入 / 自带资源 |
286
-
287
- ---
288
-
289
- ## 10. 提交前 checklist
290
-
291
- - [ ] `packages/effects/<dir>/index.ts` 导出 `VfxEffectPackage`(`id`/`nameZh`/`defaultParams`/`debugParams`/`create`)。
292
- - [ ] 资源在 `assets/` 下,经 `?url` 引;GLB 用核心 loader。
293
- - [ ] `debugParams` 每个 `key` 都在 `defaultParams`(面板↔参数对齐)。
294
- - [ ] `create()` 用 `ctx` + `params`,不 import 项目;`dispose()` 清理彻底。
295
- - [ ] 有 `vfx-params.json` 种子(合法 JSON)。
296
- - [ ] `pnpm validate` + `pnpm test:guardrails` 全绿。
297
- - [ ] DEV 面板里能选到、能调、能播、能存。