@fps-games/vfx 0.3.2 → 0.3.4

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 (234) hide show
  1. package/CHANGELOG.md +16 -0
  2. package/README.md +5 -5
  3. package/dist/effects/treasure-attention/index.d.ts +1 -1
  4. package/package.json +6 -5
  5. package/tooling/vfx-cli.mjs +31 -22
  6. package/tooling/vfx-package-resolution.mjs +8 -8
  7. package/docs/AUTHORING_EFFECTS.md +0 -297
  8. package/docs/INTEGRATION.md +0 -194
  9. package/docs/VFX_LIBRARY_ARCHITECTURE_chatgpt.md +0 -1580
  10. package/docs/VFX_LIBRARY_EXECUTION_PLAN.md +0 -229
  11. package/docs/VFX_LIBRARY_PLAN.md +0 -546
  12. package/docs/hit-flash-red-method.md +0 -155
  13. package/docs/treasure_attention_fx_babylonjs_guide.md +0 -901
  14. package/docs/vfx-ab/RESULTS.md +0 -35
  15. package/docs/vfx-ab/lumber-order/vehicle-exhaust-smoke/after.png +0 -0
  16. package/docs/vfx-ab/lumber-order/vehicle-exhaust-smoke/before.png +0 -0
  17. package/docs/vfx-ab/lumber-truck/vehicle-exhaust-smoke/after.png +0 -0
  18. package/docs/vfx-ab/lumber-truck/vehicle-exhaust-smoke/before.png +0 -0
  19. package/docs/vfx-integration_chatgpt.md +0 -462
  20. package/docs/vfx-placement-design.md +0 -164
  21. package/docs/weapon-trail-visualization.html +0 -241
  22. package/packages/EffectPackageService.ts +0 -346
  23. package/packages/SceneVfxService.ts +0 -96
  24. package/packages/build.mesh.yellow_build_upgrade_indicator/assets/runtime/simpleMeshEffect.v1.js +0 -333
  25. package/packages/build.mesh.yellow_build_upgrade_indicator/assets/shaders/mesh-effect-preview.frag.glsl +0 -25
  26. package/packages/build.mesh.yellow_build_upgrade_indicator/assets/shaders/mesh-effect-preview.vert.glsl +0 -11
  27. package/packages/build.mesh.yellow_build_upgrade_indicator/assets/textures/effect_jianbian.png +0 -0
  28. package/packages/build.mesh.yellow_build_upgrade_indicator/effect.json +0 -927
  29. package/packages/build.mesh.yellow_build_upgrade_indicator/media/contact-sheet.png +0 -0
  30. package/packages/build.mesh.yellow_build_upgrade_indicator/media/preview.gif +0 -0
  31. package/packages/build.mesh.yellow_build_upgrade_indicator/media/preview.mp4 +0 -0
  32. package/packages/build.mesh.yellow_build_upgrade_indicator/media/preview.webm +0 -0
  33. package/packages/build.mesh.yellow_build_upgrade_indicator/media/thumbnail.png +0 -0
  34. package/packages/build.mesh.yellow_build_upgrade_indicator/metadata/description.json +0 -197
  35. package/packages/build.mesh.yellow_build_upgrade_indicator/provenance/03-effect.original.json +0 -895
  36. package/packages/build.mesh.yellow_build_upgrade_indicator/provenance/03-normalized-vfx-to-babylon-report.json +0 -241
  37. package/packages/build.mesh.yellow_build_upgrade_indicator/provenance/04-preview-overrides.json +0 -542
  38. package/packages/build.mesh.yellow_build_upgrade_indicator/provenance/04-preview-tuning-report.json +0 -69
  39. package/packages/build.mesh.yellow_build_upgrade_indicator/provenance/asset-map.json +0 -125
  40. package/packages/build.mesh.yellow_build_upgrade_indicator/provenance/lineage.json +0 -44
  41. package/packages/build.particle.golden_upgrade_starburst/assets/runtime/particleEmitter.v1.js +0 -210
  42. package/packages/build.particle.golden_upgrade_starburst/assets/textures/effect_guangdian.png +0 -0
  43. package/packages/build.particle.golden_upgrade_starburst/effect.json +0 -880
  44. package/packages/build.particle.golden_upgrade_starburst/media/contact-sheet.png +0 -0
  45. package/packages/build.particle.golden_upgrade_starburst/media/preview.gif +0 -0
  46. package/packages/build.particle.golden_upgrade_starburst/media/preview.mp4 +0 -0
  47. package/packages/build.particle.golden_upgrade_starburst/media/preview.webm +0 -0
  48. package/packages/build.particle.golden_upgrade_starburst/media/thumbnail.png +0 -0
  49. package/packages/build.particle.golden_upgrade_starburst/metadata/description.json +0 -161
  50. package/packages/build.particle.golden_upgrade_starburst/provenance/03-effect.original.json +0 -762
  51. package/packages/build.particle.golden_upgrade_starburst/provenance/03-normalized-vfx-to-babylon-report.json +0 -260
  52. package/packages/build.particle.golden_upgrade_starburst/provenance/04-preview-overrides.json +0 -436
  53. package/packages/build.particle.golden_upgrade_starburst/provenance/04-preview-tuning-report.json +0 -40
  54. package/packages/build.particle.golden_upgrade_starburst/provenance/asset-map.json +0 -115
  55. package/packages/build.particle.golden_upgrade_starburst/provenance/lineage.json +0 -40
  56. package/packages/build.particle.orange_upgrade_transform_sparks/assets/runtime/particleEmitter.v1.js +0 -210
  57. package/packages/build.particle.orange_upgrade_transform_sparks/assets/textures/b5b27ab1-e740-4398-b407-848fc2b2c897.png +0 -0
  58. package/packages/build.particle.orange_upgrade_transform_sparks/effect.json +0 -887
  59. package/packages/build.particle.orange_upgrade_transform_sparks/media/preview.gif +0 -0
  60. package/packages/build.particle.orange_upgrade_transform_sparks/media/preview.mp4 +0 -0
  61. package/packages/build.particle.orange_upgrade_transform_sparks/media/preview.webm +0 -0
  62. package/packages/build.particle.orange_upgrade_transform_sparks/media/thumbnail.png +0 -0
  63. package/packages/build.particle.orange_upgrade_transform_sparks/metadata/description.json +0 -179
  64. package/packages/build.particle.orange_upgrade_transform_sparks/provenance/03-effect.original.json +0 -859
  65. package/packages/build.particle.orange_upgrade_transform_sparks/provenance/03-normalized-vfx-to-babylon-report.json +0 -260
  66. package/packages/build.particle.orange_upgrade_transform_sparks/provenance/04-preview-overrides.json +0 -478
  67. package/packages/build.particle.orange_upgrade_transform_sparks/provenance/04-preview-tuning-report.json +0 -40
  68. package/packages/build.particle.orange_upgrade_transform_sparks/provenance/asset-map.json +0 -114
  69. package/packages/build.particle.orange_upgrade_transform_sparks/provenance/lineage.json +0 -41
  70. package/packages/build.particle.wood_chip_dust_burst/assets/runtime/particleEmitter.v1.js +0 -210
  71. package/packages/build.particle.wood_chip_dust_burst/assets/textures/effect_yanwu4.png +0 -0
  72. package/packages/build.particle.wood_chip_dust_burst/assets/textures/suipian3.png +0 -0
  73. package/packages/build.particle.wood_chip_dust_burst/effect.json +0 -1400
  74. package/packages/build.particle.wood_chip_dust_burst/media/contact-sheet.png +0 -0
  75. package/packages/build.particle.wood_chip_dust_burst/media/preview.gif +0 -0
  76. package/packages/build.particle.wood_chip_dust_burst/media/preview.mp4 +0 -0
  77. package/packages/build.particle.wood_chip_dust_burst/media/preview.webm +0 -0
  78. package/packages/build.particle.wood_chip_dust_burst/media/thumbnail.png +0 -0
  79. package/packages/build.particle.wood_chip_dust_burst/metadata/description.json +0 -173
  80. package/packages/build.particle.wood_chip_dust_burst/provenance/03-effect.original.json +0 -1277
  81. package/packages/build.particle.wood_chip_dust_burst/provenance/03-normalized-vfx-to-babylon-report.json +0 -329
  82. package/packages/build.particle.wood_chip_dust_burst/provenance/04-preview-overrides.json +0 -749
  83. package/packages/build.particle.wood_chip_dust_burst/provenance/04-preview-tuning-report.json +0 -60
  84. package/packages/build.particle.wood_chip_dust_burst/provenance/asset-map.json +0 -146
  85. package/packages/build.particle.wood_chip_dust_burst/provenance/lineage.json +0 -69
  86. package/packages/effects/building-upgrade/effect.json +0 -6
  87. package/packages/effects/building-upgrade/index.ts +0 -387
  88. package/packages/effects/character-entrance/effect.json +0 -6
  89. package/packages/effects/character-entrance/index.ts +0 -308
  90. package/packages/effects/coin-burst/index.ts +0 -48
  91. package/packages/effects/comet-trail-flame/assets/textures/trail_5x4.webp +0 -0
  92. package/packages/effects/comet-trail-flame/index.ts +0 -107
  93. package/packages/effects/conveyor-upgrade/effect.json +0 -6
  94. package/packages/effects/conveyor-upgrade/index.ts +0 -401
  95. package/packages/effects/debris-smoke/assets/models/rock_debris.glb +0 -0
  96. package/packages/effects/debris-smoke/assets/textures/smoke22.webp +0 -0
  97. package/packages/effects/debris-smoke/index.ts +0 -102
  98. package/packages/effects/door_open_gold_flakes/assets/runtime/goldFlakes.v1.js +0 -397
  99. package/packages/effects/door_open_gold_flakes/door_open_gold_flakes.json +0 -498
  100. package/packages/effects/door_open_gold_flakes/index.ts +0 -11
  101. package/packages/effects/electric-arc/assets/textures/spark_4x4.webp +0 -0
  102. package/packages/effects/electric-arc/index.ts +0 -63
  103. package/packages/effects/energy-shield/effect.json +0 -7
  104. package/packages/effects/energy-shield/index.ts +0 -432
  105. package/packages/effects/explosion/assets/textures/baozha29.webp +0 -0
  106. package/packages/effects/explosion/assets/textures/glow01.webp +0 -0
  107. package/packages/effects/explosion/assets/textures/lizi01.webp +0 -0
  108. package/packages/effects/explosion/assets/textures/xulie_lizibaozha02_5x5.webp +0 -0
  109. package/packages/effects/explosion/index.ts +0 -115
  110. package/packages/effects/ground-tile-upgrade/effect.json +0 -6
  111. package/packages/effects/ground-tile-upgrade/index.ts +0 -410
  112. package/packages/effects/hit-flash/index.ts +0 -77
  113. package/packages/effects/laser-beam/assets/textures/laser_glow.webp +0 -0
  114. package/packages/effects/laser-beam/assets/textures/laser_noise.webp +0 -0
  115. package/packages/effects/laser-beam/index.ts +0 -6
  116. package/packages/effects/laser-beam-factory.ts +0 -146
  117. package/packages/effects/lumber-cart-suction/effect.json +0 -6
  118. package/packages/effects/lumber-cart-suction/index.ts +0 -399
  119. package/packages/effects/lumber-debris-scatter/assets/models/lumber_prop_model.glb +0 -0
  120. package/packages/effects/lumber-debris-scatter/assets/models/lumber_prop_model.glb.versions/.active +0 -1
  121. package/packages/effects/lumber-debris-scatter/assets/models/lumber_prop_model.glb.versions/1781589063890_upload.glb +0 -0
  122. package/packages/effects/lumber-debris-scatter/assets/runtime/solidParticleScatter.v1.js +0 -236
  123. package/packages/effects/lumber-debris-scatter/effect.json +0 -228
  124. package/packages/effects/lumber-debris-scatter/index.ts +0 -780
  125. package/packages/effects/lumber_vehicle_gear_spin/assets/runtime/gearSpin.v1.js +0 -202
  126. package/packages/effects/lumber_vehicle_gear_spin/index.ts +0 -11
  127. package/packages/effects/lumber_vehicle_gear_spin/lumber_vehicle_gear_spin.json +0 -338
  128. package/packages/effects/lumber_vehicle_upgrade_aura/assets/runtime/upgradeAura.v1.js +0 -353
  129. package/packages/effects/lumber_vehicle_upgrade_aura/index.ts +0 -13
  130. package/packages/effects/lumber_vehicle_upgrade_aura/lumber_vehicle_upgrade_aura.json +0 -365
  131. package/packages/effects/lumber_vehicle_wood_chips/assets/runtime/solidParticleScatter.v1.js +0 -310
  132. package/packages/effects/lumber_vehicle_wood_chips/index.ts +0 -11
  133. package/packages/effects/lumber_vehicle_wood_chips/lumber_vehicle_wood_chips.json +0 -335
  134. package/packages/effects/monster-hit/index.ts +0 -129
  135. package/packages/effects/player-upgrade/effect.json +0 -6
  136. package/packages/effects/player-upgrade/index.ts +0 -640
  137. package/packages/effects/pulse-laser-volley/assets/textures/bolt_guangshu.webp +0 -0
  138. package/packages/effects/pulse-laser-volley/index.ts +0 -215
  139. package/packages/effects/resource-collect-sparkles/effect.json +0 -6
  140. package/packages/effects/resource-collect-sparkles/index.ts +0 -254
  141. package/packages/effects/run-footstep-dust/assets/runtime/runFootstepDust.v1.js +0 -215
  142. package/packages/effects/run-footstep-dust/effect.json +0 -183
  143. package/packages/effects/run-footstep-dust/index.ts +0 -377
  144. package/packages/effects/space-shared.ts +0 -120
  145. package/packages/effects/thruster-flame/index.ts +0 -306
  146. package/packages/effects/treasure-attention/effect.json +0 -7
  147. package/packages/effects/treasure-attention/index.ts +0 -630
  148. package/packages/effects/tree-chop-dust/assets/textures/tree_chop_dust_atlas.png +0 -0
  149. package/packages/effects/tree-chop-dust/effect.json +0 -8
  150. package/packages/effects/tree-chop-dust/index.ts +0 -202
  151. package/packages/effects/tree-leaf-chop-burst/assets/runtime/particleEmitter.v1.js +0 -303
  152. package/packages/effects/tree-leaf-chop-burst/assets/textures/tree_leaf_chop_burst_leaf_atlas.png +0 -0
  153. package/packages/effects/tree-leaf-chop-burst/effect.json +0 -498
  154. package/packages/effects/tree-leaf-chop-burst/index.ts +0 -294
  155. package/packages/effects/tree_chop_dust_burst/assets/runtime/particleEmitter.v1.js +0 -318
  156. package/packages/effects/tree_chop_dust_burst/assets/textures/tree_chop_dust_burst_dust.png +0 -0
  157. package/packages/effects/tree_chop_dust_burst/index.ts +0 -13
  158. package/packages/effects/tree_chop_dust_burst/tree_chop_dust_burst.json +0 -412
  159. package/packages/effects/ufo-thread-flame/assets/textures/flame_flow.webp +0 -0
  160. package/packages/effects/ufo-thread-flame/assets/textures/flame_spike.webp +0 -0
  161. package/packages/effects/ufo-thread-flame/index.ts +0 -153
  162. package/packages/effects/vehicle-exhaust-smoke/assets/textures/vehicle_exhaust_smoke_atlas.png +0 -0
  163. package/packages/effects/vehicle-exhaust-smoke/effect.json +0 -8
  164. package/packages/effects/vehicle-exhaust-smoke/index.ts +0 -298
  165. package/packages/effects/vehicle-upgrade/effect.json +0 -6
  166. package/packages/effects/vehicle-upgrade/index.ts +0 -404
  167. package/packages/effects/weapon-trail/assets/textures/trail_wedge.png +0 -0
  168. package/packages/effects/weapon-trail/index.ts +0 -317
  169. package/packages/effects/wood-crusher-sawdust/assets/runtime/particleEmitter.v1.js +0 -312
  170. package/packages/effects/wood-crusher-sawdust/assets/textures/wood_crusher_sawdust_dust.png +0 -0
  171. package/packages/effects/wood-crusher-sawdust/assets/textures/wood_crusher_sawdust_fiber.png +0 -0
  172. package/packages/effects/wood-crusher-sawdust/index.ts +0 -43
  173. package/packages/effects/wood-crusher-sawdust/wood_crusher_sawdust.json +0 -592
  174. package/packages/effects/wood-cutter-sawdust/assets/runtime/particleEmitter.v1.js +0 -312
  175. package/packages/effects/wood-cutter-sawdust/assets/textures/wood_cutter_sawdust_chip.png +0 -0
  176. package/packages/effects/wood-cutter-sawdust/assets/textures/wood_cutter_sawdust_dust.png +0 -0
  177. package/packages/effects/wood-cutter-sawdust/index.ts +0 -43
  178. package/packages/effects/wood-cutter-sawdust/wood_cutter_sawdust.json +0 -592
  179. package/packages/effects/wood-sawdust-effect-factory.ts +0 -194
  180. package/packages/effects/wood_crusher_sawdust/assets/runtime/particleEmitter.v1.js +0 -318
  181. package/packages/effects/wood_crusher_sawdust/assets/textures/wood_crusher_sawdust_dust.png +0 -0
  182. package/packages/effects/wood_crusher_sawdust/assets/textures/wood_crusher_sawdust_fiber.png +0 -0
  183. package/packages/effects/wood_crusher_sawdust/index.ts +0 -29
  184. package/packages/effects/wood_crusher_sawdust/wood_crusher_sawdust.json +0 -592
  185. package/packages/effects/wood_cutter_sawdust/assets/runtime/particleEmitter.v1.js +0 -318
  186. package/packages/effects/wood_cutter_sawdust/assets/textures/wood_cutter_sawdust_chip.png +0 -0
  187. package/packages/effects/wood_cutter_sawdust/assets/textures/wood_cutter_sawdust_dust.png +0 -0
  188. package/packages/effects/wood_cutter_sawdust/index.ts +0 -29
  189. package/packages/effects/wood_cutter_sawdust/wood_cutter_sawdust.json +0 -592
  190. package/packages/effects/wood_peel_material_test/assets/runtime/woodPeelMaterialTest.v1.js +0 -196
  191. package/packages/effects/wood_peel_material_test/index.ts +0 -11
  192. package/packages/effects/wood_peel_material_test/wood_peel_material_test.json +0 -136
  193. package/packages/env.particle.forest_edge_fog/assets/runtime/particleEmitter.v1.js +0 -210
  194. package/packages/env.particle.forest_edge_fog/assets/textures/f12a23c4-b924-4322-a260-3d982428f1e8.png +0 -0
  195. package/packages/env.particle.forest_edge_fog/assets/textures/yuan.png +0 -0
  196. package/packages/env.particle.forest_edge_fog/effect.json +0 -854
  197. package/packages/env.particle.forest_edge_fog/media/preview.gif +0 -0
  198. package/packages/env.particle.forest_edge_fog/media/preview.mp4 +0 -0
  199. package/packages/env.particle.forest_edge_fog/media/preview.webm +0 -0
  200. package/packages/env.particle.forest_edge_fog/media/thumbnail.png +0 -0
  201. package/packages/env.particle.forest_edge_fog/metadata/description.json +0 -148
  202. package/packages/env.particle.forest_edge_fog/provenance/03-effect.original.json +0 -827
  203. package/packages/env.particle.forest_edge_fog/provenance/03-normalized-vfx-to-babylon-report.json +0 -196
  204. package/packages/env.particle.forest_edge_fog/provenance/04-preview-overrides.json +0 -432
  205. package/packages/env.particle.forest_edge_fog/provenance/04-preview-tuning-report.json +0 -28
  206. package/packages/env.particle.forest_edge_fog/provenance/asset-map.json +0 -124
  207. package/packages/env.particle.forest_edge_fog/provenance/lineage.json +0 -41
  208. package/packages/generation.ts +0 -14
  209. package/packages/index.ts +0 -14
  210. package/packages/legacy-particle-runtime.ts +0 -113
  211. package/packages/manifestRuntimePackage.ts +0 -519
  212. package/packages/registry.ts +0 -85
  213. package/packages/rendering.ts +0 -13
  214. package/packages/resource.particle.viscous_oil_suction/assets/runtime/top_disk_suction/particleEmitter.v1.js +0 -424
  215. package/packages/resource.particle.viscous_oil_suction/assets/textures/Glow ad.png +0 -0
  216. package/packages/resource.particle.viscous_oil_suction/effect.json +0 -1254
  217. package/packages/resource.particle.viscous_oil_suction/media/preview.gif +0 -0
  218. package/packages/resource.particle.viscous_oil_suction/media/preview.mp4 +0 -0
  219. package/packages/resource.particle.viscous_oil_suction/media/preview.webm +0 -0
  220. package/packages/resource.particle.viscous_oil_suction/media/thumbnail.png +0 -0
  221. package/packages/resource.particle.viscous_oil_suction/metadata/description.json +0 -122
  222. package/packages/resource.particle.viscous_oil_suction/provenance/03-effect.original.json +0 -1051
  223. package/packages/resource.particle.viscous_oil_suction/provenance/03-normalized-vfx-to-babylon-report.json +0 -200
  224. package/packages/resource.particle.viscous_oil_suction/provenance/04-preview-overrides.json +0 -581
  225. package/packages/resource.particle.viscous_oil_suction/provenance/04-preview-tuning-report.json +0 -28
  226. package/packages/resource.particle.viscous_oil_suction/provenance/asset-map.json +0 -111
  227. package/packages/resource.particle.viscous_oil_suction/provenance/lineage.json +0 -45
  228. package/packages/types.ts +0 -195
  229. package/tooling/check-dist-runtime.mjs +0 -166
  230. package/tooling/generate-index.mjs +0 -55
  231. package/tooling/test-guardrails.mjs +0 -157
  232. package/tooling/validate-boundary.mjs +0 -92
  233. package/tooling/validate-effects.mjs +0 -304
  234. package/tooling/validate.mjs +0 -53
@@ -1,519 +0,0 @@
1
- import { Engine } from '@babylonjs/core/Engines/engine';
2
- import { Color3, Color4 } from '@babylonjs/core/Maths/math.color';
3
- import { Vector3 } from '@babylonjs/core/Maths/math.vector';
4
- import { Material } from '@babylonjs/core/Materials/material';
5
- import { MaterialPluginBase } from '@babylonjs/core/Materials/materialPluginBase';
6
- import { PBRMaterial } from '@babylonjs/core/Materials/PBR/pbrMaterial';
7
- import { DynamicTexture } from '@babylonjs/core/Materials/Textures/dynamicTexture';
8
- import { Texture } from '@babylonjs/core/Materials/Textures/texture';
9
- import { StandardMaterial } from '@babylonjs/core/Materials/standardMaterial';
10
- import { CreateBox } from '@babylonjs/core/Meshes/Builders/boxBuilder';
11
- import { CreateCylinder } from '@babylonjs/core/Meshes/Builders/cylinderBuilder';
12
- import { CreateDisc } from '@babylonjs/core/Meshes/Builders/discBuilder';
13
- import { CreatePlane } from '@babylonjs/core/Meshes/Builders/planeBuilder';
14
- import { CreateTube } from '@babylonjs/core/Meshes/Builders/tubeBuilder';
15
- import { Mesh } from '@babylonjs/core/Meshes/mesh';
16
- import { VertexData } from '@babylonjs/core/Meshes/mesh.vertexData';
17
- import { TransformNode } from '@babylonjs/core/Meshes/transformNode';
18
- import { ParticleSystem } from '@babylonjs/core/Particles/particleSystem';
19
- import { SolidParticleSystem } from '@babylonjs/core/Particles/solidParticleSystem';
20
- import { SceneLoader } from '@babylonjs/core/Loading/sceneLoader';
21
- import type { Scene } from '@babylonjs/core/scene';
22
-
23
- import type {
24
- VfxColorValue,
25
- VfxDebugAnchor,
26
- VfxEffectHandle,
27
- VfxEffectPackage,
28
- VfxEffectPackageContext,
29
- VfxParamDefinition,
30
- VfxParamValue,
31
- VfxParamValues,
32
- } from './types';
33
-
34
- type LegacyTunableParamType = 'number' | 'color' | 'enum' | string;
35
-
36
- interface LegacyTunableTarget {
37
- emitter: string;
38
- property: string;
39
- operator?: string;
40
- defaultValue?: unknown;
41
- }
42
-
43
- interface LegacyTunableParam {
44
- key: string;
45
- label?: string;
46
- labelEn?: string;
47
- labelZh?: string;
48
- type: LegacyTunableParamType;
49
- default?: unknown;
50
- min?: number;
51
- max?: number;
52
- step?: number;
53
- options?: Array<{ value: string; label?: string }>;
54
- target?: LegacyTunableTarget;
55
- targets?: LegacyTunableTarget[];
56
- }
57
-
58
- interface LegacyEmitterConfig {
59
- name: string;
60
- enabled?: boolean;
61
- runtime?: {
62
- adapter?: string;
63
- stopAfterSeconds?: number;
64
- disposeOnComplete?: boolean;
65
- };
66
- [key: string]: unknown;
67
- }
68
-
69
- interface LegacyRuntimeAdapterConfig {
70
- id: string;
71
- entry: string;
72
- moduleFormat?: string;
73
- exports?: string[];
74
- }
75
-
76
- interface LegacyEffectManifest {
77
- id?: string;
78
- name?: {
79
- en?: string;
80
- zh?: string;
81
- };
82
- assets?: Record<string, unknown> | unknown[];
83
- source?: unknown;
84
- emitters?: LegacyEmitterConfig[];
85
- runtime?: {
86
- driver?: string;
87
- adapters?: LegacyRuntimeAdapterConfig[];
88
- };
89
- tunableParams?: LegacyTunableParam[];
90
- defaultParams?: Record<string, unknown>;
91
- debug?: {
92
- playAnchor?: string;
93
- livePreview?: boolean;
94
- };
95
- }
96
-
97
- type RuntimePreview = {
98
- start?: () => void;
99
- stop?: () => void;
100
- dispose?: () => void;
101
- isStarted?: () => boolean;
102
- setPosition?: (position: Vector3) => void;
103
- setScaling?: (scaling: Vector3) => void;
104
- };
105
-
106
- const BABYLON_RUNTIME_API = {
107
- Color3,
108
- Color4,
109
- DynamicTexture,
110
- Engine,
111
- Material,
112
- MaterialPluginBase,
113
- Mesh,
114
- MeshBuilder: {
115
- CreateBox,
116
- CreateCylinder,
117
- CreateDisc,
118
- CreatePlane,
119
- CreateTube,
120
- },
121
- PBRMaterial,
122
- ParticleSystem,
123
- SceneLoader,
124
- SolidParticleSystem,
125
- StandardMaterial,
126
- Texture,
127
- TransformNode,
128
- Vector3,
129
- VertexData,
130
- } as const;
131
-
132
- export interface ManifestRuntimeEffectPackageOptions {
133
- id: string;
134
- manifest: LegacyEffectManifest;
135
- assetUrls: Record<string, string>;
136
- }
137
-
138
- export function createManifestRuntimeEffectPackage(options: ManifestRuntimeEffectPackageOptions): VfxEffectPackage {
139
- const { id, manifest, assetUrls } = options;
140
- return {
141
- id,
142
- nameZh: manifest.name?.zh ?? manifest.name?.en ?? id,
143
- manifest: {
144
- id: manifest.id ?? id,
145
- nameZh: manifest.name?.zh ?? manifest.name?.en ?? id,
146
- assets: collectManifestAssetPaths(manifest),
147
- source: readManifestSource(manifest),
148
- },
149
- defaultParams: buildDefaultParams(manifest),
150
- debugAnchor: normalizeDebugAnchor(manifest.debug?.playAnchor),
151
- debugParams: buildDebugParams(manifest),
152
- create(context) {
153
- return createManifestRuntimeHandle(context, manifest, assetUrls, id);
154
- },
155
- };
156
- }
157
-
158
- function createManifestRuntimeHandle(
159
- context: VfxEffectPackageContext,
160
- manifest: LegacyEffectManifest,
161
- assetUrls: Record<string, string>,
162
- effectId: string,
163
- ): VfxEffectHandle {
164
- const root = context.root;
165
- const previews: RuntimePreview[] = [];
166
- const cleanupCallbacks: Array<() => void> = [];
167
- let disposed = false;
168
-
169
- const ready = startRuntimePreviews().catch((error) => {
170
- console.warn(`[VFX] Failed to play effect package "${effectId}".`, error);
171
- });
172
-
173
- return {
174
- root,
175
- ready,
176
- dispose() {
177
- disposed = true;
178
- for (const cleanup of cleanupCallbacks.splice(0)) cleanup();
179
- for (const preview of previews.splice(0)) {
180
- preview.stop?.();
181
- preview.dispose?.();
182
- }
183
- disposeRoot(root);
184
- },
185
- };
186
-
187
- async function startRuntimePreviews(): Promise<void> {
188
- const emitters = (manifest.emitters ?? [])
189
- .filter((emitter) => emitter.enabled !== false)
190
- .map(cloneEmitter);
191
-
192
- for (const [index, emitter] of emitters.entries()) {
193
- if (disposed) return;
194
- applyTunableValues(emitter, manifest.tunableParams ?? [], context.params);
195
- emitter.origin = {
196
- x: context.position.x,
197
- y: context.position.y,
198
- z: context.position.z,
199
- };
200
- emitter.rotationY = root.rotation.y;
201
- const preview = await playEmitter(manifest, emitter, assetUrls, index, effectId, context.scene);
202
- if (!preview) continue;
203
- if (disposed) {
204
- preview.stop?.();
205
- preview.dispose?.();
206
- continue;
207
- }
208
- syncPreviewPosition(context, preview, cleanupCallbacks);
209
- previews.push(preview);
210
- }
211
- }
212
- }
213
-
214
- function syncPreviewPosition(
215
- context: VfxEffectPackageContext,
216
- preview: RuntimePreview,
217
- cleanupCallbacks: Array<() => void>,
218
- ): void {
219
- if (typeof preview.setPosition !== 'function') return;
220
- preview.setPosition(context.root.getAbsolutePosition());
221
- const observer = context.scene.onBeforeRenderObservable.add(() => {
222
- preview.setPosition?.(context.root.getAbsolutePosition());
223
- preview.setScaling?.(context.root.scaling);
224
- });
225
- cleanupCallbacks.push(() => {
226
- context.scene.onBeforeRenderObservable.remove(observer);
227
- });
228
- }
229
-
230
- async function playEmitter(
231
- manifest: LegacyEffectManifest,
232
- emitter: LegacyEmitterConfig,
233
- assetUrls: Record<string, string>,
234
- index: number,
235
- effectId: string,
236
- scene: Scene,
237
- ): Promise<RuntimePreview | null> {
238
- const adapterId = resolveEmitterAdapterId(manifest, emitter);
239
- if (!adapterId) {
240
- console.warn(`[VFX] Missing runtime adapter for ${effectId}/${emitter.name}`);
241
- return null;
242
- }
243
-
244
- const adapter = manifest.runtime?.adapters?.find((item) => item.id === adapterId)
245
- ?? manifest.runtime?.adapters?.[0];
246
- if (!adapter) {
247
- console.warn(`[VFX] Adapter "${adapterId}" is not registered in ${effectId}`);
248
- return null;
249
- }
250
-
251
- const adapterUrl = assetUrls[adapter.entry];
252
- if (!adapterUrl) {
253
- console.warn(`[VFX] Missing runtime asset "${adapter.entry}" for ${effectId}`);
254
- return null;
255
- }
256
-
257
- const runtimeModule = await import(/* @vite-ignore */ adapterUrl) as Record<string, unknown>;
258
- const createRuntimeName = adapter.exports?.find((name) => name.startsWith('create'))
259
- ?? getRuntimeFactoryName(adapter.id);
260
- const createRuntime = runtimeModule[createRuntimeName];
261
- if (typeof createRuntime !== 'function') {
262
- console.warn(`[VFX] Runtime "${adapter.id}" does not export "${createRuntimeName}"`);
263
- return null;
264
- }
265
-
266
- return await createRuntime({
267
- BABYLON: BABYLON_RUNTIME_API,
268
- scene,
269
- emitter,
270
- index,
271
- shouldStart: true,
272
- urlForPackagePath: (packagePath: string) => assetUrls[packagePath] ?? packagePath,
273
- }) as RuntimePreview;
274
- }
275
-
276
- function resolveEmitterAdapterId(manifest: LegacyEffectManifest, emitter: LegacyEmitterConfig): string | undefined {
277
- const runtimeAdapter = emitter.runtime?.adapter;
278
- if (runtimeAdapter) return runtimeAdapter;
279
- const adapters = manifest.runtime?.adapters ?? [];
280
- if (adapters.length === 1) return adapters[0].id;
281
- if (manifest.runtime?.driver === 'solidParticleScatter') return 'solidParticleScatter/v1';
282
- if (manifest.runtime?.driver === 'particle') return 'particleEmitter/v1';
283
- return adapters[0]?.id;
284
- }
285
-
286
- function getRuntimeFactoryName(adapterId: string): string {
287
- if (adapterId === 'solidParticleScatter/v1') return 'createSolidParticleScatterRuntime';
288
- if (adapterId === 'particleEmitter/v1') return 'createParticleEmitterRuntime';
289
- if (adapterId === 'gearSpin/v1') return 'createGearSpinRuntime';
290
- if (adapterId === 'goldFlakes/v1') return 'createGoldFlakesRuntime';
291
- if (adapterId === 'upgradeAura/v1') return 'createUpgradeAuraRuntime';
292
- if (adapterId === 'woodPeelMaterialTest/v1') return 'createWoodPeelMaterialTestRuntime';
293
- if (adapterId === 'simpleMeshEffect/v1') return 'createSimpleMeshEffectRuntime';
294
- return 'createVfxRuntime';
295
- }
296
-
297
- function applyTunableValues(
298
- emitter: LegacyEmitterConfig,
299
- params: LegacyTunableParam[],
300
- values: VfxParamValues,
301
- ): void {
302
- for (const param of params) {
303
- if (!(param.key in values)) continue;
304
- const targets = param.targets ?? (param.target ? [param.target] : []);
305
- for (const target of targets) {
306
- if (target.emitter !== emitter.name) continue;
307
- applyTunableTarget(emitter, target, values[param.key]);
308
- }
309
- }
310
- }
311
-
312
- function applyTunableTarget(emitter: LegacyEmitterConfig, target: LegacyTunableTarget, value: VfxParamValue): void {
313
- const operator = target.operator ?? 'set';
314
- if (operator === 'set') {
315
- setNestedValue(emitter, target.property, normalizeTunableValue(emitter, target.property, value));
316
- return;
317
- }
318
-
319
- if (operator === 'scaleDefault') {
320
- const multiplier = Number(value);
321
- const baseValue = Number(target.defaultValue ?? getNestedValue(emitter, target.property));
322
- if (!Number.isFinite(multiplier) || !Number.isFinite(baseValue)) return;
323
- setNestedValue(emitter, target.property, baseValue * multiplier);
324
- return;
325
- }
326
-
327
- if (operator === 'scaleVectorDefault') {
328
- const multiplier = Number(value);
329
- if (!Number.isFinite(multiplier)) return;
330
- setNestedValue(emitter, target.property, scaleVectorDefaultValue(target.defaultValue, multiplier));
331
- }
332
- }
333
-
334
- function scaleVectorDefaultValue(defaultValue: unknown, multiplier: number): unknown {
335
- if (!defaultValue || typeof defaultValue !== 'object' || Array.isArray(defaultValue)) return defaultValue;
336
-
337
- const source = defaultValue as { x?: unknown; y?: unknown; z?: unknown; scaleAxes?: unknown };
338
- const scaleAxes = source.scaleAxes && typeof source.scaleAxes === 'object' && !Array.isArray(source.scaleAxes)
339
- ? source.scaleAxes as Record<string, unknown>
340
- : { x: true, y: true, z: true };
341
-
342
- const scaleComponent = (axis: 'x' | 'y' | 'z') => {
343
- const base = Number(source[axis] ?? 0);
344
- if (!Number.isFinite(base)) return 0;
345
- return scaleAxes[axis] === false ? base : base * multiplier;
346
- };
347
-
348
- return {
349
- x: scaleComponent('x'),
350
- y: scaleComponent('y'),
351
- z: scaleComponent('z'),
352
- };
353
- }
354
-
355
- function setNestedValue(target: Record<string, unknown>, path: string, value: unknown): void {
356
- const parts = path.split('.').filter(Boolean);
357
- if (parts.length === 0) return;
358
-
359
- let cursor: Record<string, unknown> = target;
360
- for (const part of parts.slice(0, -1)) {
361
- const next = cursor[part];
362
- if (!next || typeof next !== 'object' || Array.isArray(next)) {
363
- cursor[part] = {};
364
- }
365
- cursor = cursor[part] as Record<string, unknown>;
366
- }
367
-
368
- cursor[parts[parts.length - 1]] = value;
369
- }
370
-
371
- function normalizeTunableValue(emitter: LegacyEmitterConfig, path: string, value: VfxParamValue): unknown {
372
- if (isColorValue(value)) {
373
- return {
374
- r: value.r,
375
- g: value.g,
376
- b: value.b,
377
- a: readExistingAlpha(emitter, path),
378
- };
379
- }
380
-
381
- if (typeof value !== 'string' || !/^#[0-9a-f]{6}$/i.test(value)) return value;
382
-
383
- const alpha = readExistingAlpha(emitter, path);
384
-
385
- return {
386
- r: parseInt(value.slice(1, 3), 16) / 255,
387
- g: parseInt(value.slice(3, 5), 16) / 255,
388
- b: parseInt(value.slice(5, 7), 16) / 255,
389
- a: alpha,
390
- };
391
- }
392
-
393
- function readExistingAlpha(emitter: LegacyEmitterConfig, path: string): number {
394
- const existing = getNestedValue(emitter, path);
395
- const alpha = existing && typeof existing === 'object' && 'a' in existing
396
- ? Number((existing as { a?: unknown }).a)
397
- : 1;
398
- return Number.isFinite(alpha) ? alpha : 1;
399
- }
400
-
401
- function getNestedValue(target: Record<string, unknown>, path: string): unknown {
402
- let cursor: unknown = target;
403
- for (const part of path.split('.').filter(Boolean)) {
404
- if (!cursor || typeof cursor !== 'object' || Array.isArray(cursor)) return undefined;
405
- cursor = (cursor as Record<string, unknown>)[part];
406
- }
407
- return cursor;
408
- }
409
-
410
- function buildDefaultParams(manifest: LegacyEffectManifest): VfxParamValues {
411
- const params: VfxParamValues = {};
412
- for (const [key, value] of Object.entries(manifest.defaultParams ?? {})) {
413
- if (isVfxParamValue(value)) params[key] = value;
414
- }
415
- for (const param of manifest.tunableParams ?? []) {
416
- if (param.default !== undefined && isVfxParamValue(param.default)) {
417
- params[param.key] = param.default;
418
- }
419
- }
420
- return params;
421
- }
422
-
423
- function buildDebugParams(manifest: LegacyEffectManifest): VfxParamDefinition[] {
424
- const result: VfxParamDefinition[] = [];
425
- for (const param of manifest.tunableParams ?? []) {
426
- const label = param.labelZh ?? param.label ?? param.labelEn ?? param.key;
427
- if (param.type === 'number') {
428
- result.push({
429
- key: param.key,
430
- label,
431
- kind: 'number',
432
- min: param.min,
433
- max: param.max,
434
- step: param.step,
435
- });
436
- continue;
437
- }
438
- if (param.type === 'color') {
439
- result.push({
440
- key: param.key,
441
- label,
442
- kind: 'color',
443
- });
444
- continue;
445
- }
446
- if (param.type === 'enum' && Array.isArray(param.options)) {
447
- result.push({
448
- key: param.key,
449
- label,
450
- kind: 'enum',
451
- options: param.options.map((option) => ({
452
- value: option.value,
453
- label: option.label ?? option.value,
454
- })),
455
- });
456
- }
457
- }
458
- return result;
459
- }
460
-
461
- function isVfxParamValue(value: unknown): value is VfxParamValue {
462
- if (typeof value === 'number') return Number.isFinite(value);
463
- if (typeof value === 'string') return true;
464
- if (!value || typeof value !== 'object' || Array.isArray(value)) return false;
465
- const color = value as Record<string, unknown>;
466
- return typeof color.r === 'number'
467
- && Number.isFinite(color.r)
468
- && typeof color.g === 'number'
469
- && Number.isFinite(color.g)
470
- && typeof color.b === 'number'
471
- && Number.isFinite(color.b);
472
- }
473
-
474
- function isColorValue(value: unknown): value is VfxColorValue {
475
- if (!value || typeof value !== 'object' || Array.isArray(value)) return false;
476
- const color = value as Record<string, unknown>;
477
- return typeof color.r === 'number'
478
- && Number.isFinite(color.r)
479
- && typeof color.g === 'number'
480
- && Number.isFinite(color.g)
481
- && typeof color.b === 'number'
482
- && Number.isFinite(color.b);
483
- }
484
-
485
- function normalizeDebugAnchor(value: string | undefined): VfxDebugAnchor | undefined {
486
- return value === 'player' || value === 'playerRight' ? value : undefined;
487
- }
488
-
489
- function collectManifestAssetPaths(manifest: LegacyEffectManifest): string[] {
490
- const paths: string[] = [];
491
- const collect = (value: unknown): void => {
492
- if (Array.isArray(value)) {
493
- for (const item of value) collect(item);
494
- return;
495
- }
496
- if (!value || typeof value !== 'object') return;
497
- const record = value as Record<string, unknown>;
498
- if (typeof record.packagePath === 'string') paths.push(record.packagePath);
499
- for (const child of Object.values(record)) collect(child);
500
- };
501
- collect(manifest.assets);
502
- return Array.from(new Set(paths));
503
- }
504
-
505
- function readManifestSource(manifest: LegacyEffectManifest): string | undefined {
506
- if (typeof manifest.source === 'string') return manifest.source;
507
- if (!manifest.source || typeof manifest.source !== 'object') return undefined;
508
- const source = manifest.source as Record<string, unknown>;
509
- return typeof source.sourceId === 'string' ? source.sourceId : undefined;
510
- }
511
-
512
- function cloneEmitter(emitter: LegacyEmitterConfig): LegacyEmitterConfig {
513
- return JSON.parse(JSON.stringify(emitter)) as LegacyEmitterConfig;
514
- }
515
-
516
- function disposeRoot(root: TransformNode): void {
517
- if (typeof root.isDisposed === 'function' && root.isDisposed()) return;
518
- root.dispose(false, true);
519
- }
@@ -1,85 +0,0 @@
1
- // 注册表:库提供 buildRegistry(纯函数);glob 调用在「项目侧」(Vite 编译期相对解析),
2
- // 项目把 glob 结果传进来 → 得到一个 VfxRegistry,注入给 EffectPackageService。
3
- import type { VfxEffectPackage, VfxParamValues } from './types';
4
-
5
- export interface VfxRegistry {
6
- getEffectPackage(effectId: string): VfxEffectPackage | undefined;
7
- getEffectPackages(): VfxEffectPackage[];
8
- savedParams: Record<string, Partial<VfxParamValues>>;
9
- }
10
-
11
- export interface BuildRegistryInput {
12
- /** import.meta.glob('./effects/*\/index.ts', { eager: true }) 的结果 */
13
- modules: Record<string, Record<string, unknown>>;
14
- /** import.meta.glob('./effects/*\/vfx-params.json', { eager: true }) 的结果(可选) */
15
- params?: Record<string, { default: unknown } | unknown>;
16
- /** 可选:判定某目录是否仅调试用(prod 构建剔除) */
17
- isDebugOnly?: (dir: string) => boolean;
18
- /** 可选:prod 标志,配合 isDebugOnly 过滤 */
19
- prod?: boolean;
20
- }
21
-
22
- export function isVfxEffectPackage(value: unknown): value is VfxEffectPackage {
23
- return (
24
- !!value &&
25
- typeof value === 'object' &&
26
- typeof (value as VfxEffectPackage).id === 'string' &&
27
- typeof (value as VfxEffectPackage).create === 'function'
28
- );
29
- }
30
-
31
- function pickPackage(mod: Record<string, unknown>): VfxEffectPackage | null {
32
- if (isVfxEffectPackage((mod as { default?: unknown }).default)) {
33
- return (mod as { default: VfxEffectPackage }).default;
34
- }
35
- for (const value of Object.values(mod)) if (isVfxEffectPackage(value)) return value;
36
- return null;
37
- }
38
-
39
- function dirOf(path: string): string {
40
- const m = path.match(/\/effects\/([^/]+)\//) ?? path.match(/^\.\/effects\/([^/]+)\//);
41
- return m ? m[1] : path;
42
- }
43
-
44
- function sanitizeParamsFile(value: unknown): Partial<VfxParamValues> {
45
- const v = value && typeof value === 'object' && 'default' in (value as object)
46
- ? (value as { default: unknown }).default
47
- : value;
48
- if (!v || typeof v !== 'object' || Array.isArray(v)) return {};
49
- const params = (v as { params?: unknown }).params;
50
- if (params && typeof params === 'object' && !Array.isArray(params)) return params as Partial<VfxParamValues>;
51
- return v as Partial<VfxParamValues>;
52
- }
53
-
54
- export function buildRegistry(input: BuildRegistryInput): VfxRegistry {
55
- const paramsByDir: Record<string, Partial<VfxParamValues>> = {};
56
- for (const [path, mod] of Object.entries(input.params ?? {})) {
57
- paramsByDir[dirOf(path)] = sanitizeParamsFile(mod);
58
- }
59
-
60
- const map = new Map<string, VfxEffectPackage>();
61
- const savedParams: Record<string, Partial<VfxParamValues>> = {};
62
- for (const [path, mod] of Object.entries(input.modules)) {
63
- const dir = dirOf(path);
64
- if (input.prod && input.isDebugOnly?.(dir)) continue;
65
- const pkg = pickPackage(mod);
66
- if (!pkg) {
67
- console.warn('[vfx] no VfxEffectPackage export found in', path);
68
- continue;
69
- }
70
- if (map.has(pkg.id)) {
71
- throw new Error(`[vfx] duplicate effect id "${pkg.id}" (dir: ${dir})`);
72
- }
73
- const saved = paramsByDir[dir] ?? {};
74
- pkg.savedParams = saved;
75
- savedParams[pkg.id] = saved;
76
- map.set(pkg.id, pkg);
77
- }
78
-
79
- const list = [...map.values()].sort((a, b) => a.id.localeCompare(b.id));
80
- return {
81
- getEffectPackage: (id) => map.get(id),
82
- getEffectPackages: () => list,
83
- savedParams,
84
- };
85
- }
@@ -1,13 +0,0 @@
1
- import type { ParticleSystem } from '@babylonjs/core/Particles/particleSystem';
2
- import type { SpriteManager } from '@babylonjs/core/Sprites/spriteManager';
3
-
4
- export const VFX_RENDERING_GROUP_ID = 2;
5
-
6
- export function configureVfxSpriteManager(manager: SpriteManager): void {
7
- manager.renderingGroupId = VFX_RENDERING_GROUP_ID;
8
- manager.disableDepthWrite = true;
9
- }
10
-
11
- export function configureVfxParticleSystem(system: ParticleSystem): void {
12
- system.renderingGroupId = VFX_RENDERING_GROUP_ID;
13
- }