@fps-games/vfx 0.3.2 → 0.3.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (231) hide show
  1. package/CHANGELOG.md +8 -0
  2. package/package.json +5 -4
  3. package/tooling/vfx-cli.mjs +8 -1
  4. package/docs/AUTHORING_EFFECTS.md +0 -297
  5. package/docs/INTEGRATION.md +0 -194
  6. package/docs/VFX_LIBRARY_ARCHITECTURE_chatgpt.md +0 -1580
  7. package/docs/VFX_LIBRARY_EXECUTION_PLAN.md +0 -229
  8. package/docs/VFX_LIBRARY_PLAN.md +0 -546
  9. package/docs/hit-flash-red-method.md +0 -155
  10. package/docs/treasure_attention_fx_babylonjs_guide.md +0 -901
  11. package/docs/vfx-ab/RESULTS.md +0 -35
  12. package/docs/vfx-ab/lumber-order/vehicle-exhaust-smoke/after.png +0 -0
  13. package/docs/vfx-ab/lumber-order/vehicle-exhaust-smoke/before.png +0 -0
  14. package/docs/vfx-ab/lumber-truck/vehicle-exhaust-smoke/after.png +0 -0
  15. package/docs/vfx-ab/lumber-truck/vehicle-exhaust-smoke/before.png +0 -0
  16. package/docs/vfx-integration_chatgpt.md +0 -462
  17. package/docs/vfx-placement-design.md +0 -164
  18. package/docs/weapon-trail-visualization.html +0 -241
  19. package/packages/EffectPackageService.ts +0 -346
  20. package/packages/SceneVfxService.ts +0 -96
  21. package/packages/build.mesh.yellow_build_upgrade_indicator/assets/runtime/simpleMeshEffect.v1.js +0 -333
  22. package/packages/build.mesh.yellow_build_upgrade_indicator/assets/shaders/mesh-effect-preview.frag.glsl +0 -25
  23. package/packages/build.mesh.yellow_build_upgrade_indicator/assets/shaders/mesh-effect-preview.vert.glsl +0 -11
  24. package/packages/build.mesh.yellow_build_upgrade_indicator/assets/textures/effect_jianbian.png +0 -0
  25. package/packages/build.mesh.yellow_build_upgrade_indicator/effect.json +0 -927
  26. package/packages/build.mesh.yellow_build_upgrade_indicator/media/contact-sheet.png +0 -0
  27. package/packages/build.mesh.yellow_build_upgrade_indicator/media/preview.gif +0 -0
  28. package/packages/build.mesh.yellow_build_upgrade_indicator/media/preview.mp4 +0 -0
  29. package/packages/build.mesh.yellow_build_upgrade_indicator/media/preview.webm +0 -0
  30. package/packages/build.mesh.yellow_build_upgrade_indicator/media/thumbnail.png +0 -0
  31. package/packages/build.mesh.yellow_build_upgrade_indicator/metadata/description.json +0 -197
  32. package/packages/build.mesh.yellow_build_upgrade_indicator/provenance/03-effect.original.json +0 -895
  33. package/packages/build.mesh.yellow_build_upgrade_indicator/provenance/03-normalized-vfx-to-babylon-report.json +0 -241
  34. package/packages/build.mesh.yellow_build_upgrade_indicator/provenance/04-preview-overrides.json +0 -542
  35. package/packages/build.mesh.yellow_build_upgrade_indicator/provenance/04-preview-tuning-report.json +0 -69
  36. package/packages/build.mesh.yellow_build_upgrade_indicator/provenance/asset-map.json +0 -125
  37. package/packages/build.mesh.yellow_build_upgrade_indicator/provenance/lineage.json +0 -44
  38. package/packages/build.particle.golden_upgrade_starburst/assets/runtime/particleEmitter.v1.js +0 -210
  39. package/packages/build.particle.golden_upgrade_starburst/assets/textures/effect_guangdian.png +0 -0
  40. package/packages/build.particle.golden_upgrade_starburst/effect.json +0 -880
  41. package/packages/build.particle.golden_upgrade_starburst/media/contact-sheet.png +0 -0
  42. package/packages/build.particle.golden_upgrade_starburst/media/preview.gif +0 -0
  43. package/packages/build.particle.golden_upgrade_starburst/media/preview.mp4 +0 -0
  44. package/packages/build.particle.golden_upgrade_starburst/media/preview.webm +0 -0
  45. package/packages/build.particle.golden_upgrade_starburst/media/thumbnail.png +0 -0
  46. package/packages/build.particle.golden_upgrade_starburst/metadata/description.json +0 -161
  47. package/packages/build.particle.golden_upgrade_starburst/provenance/03-effect.original.json +0 -762
  48. package/packages/build.particle.golden_upgrade_starburst/provenance/03-normalized-vfx-to-babylon-report.json +0 -260
  49. package/packages/build.particle.golden_upgrade_starburst/provenance/04-preview-overrides.json +0 -436
  50. package/packages/build.particle.golden_upgrade_starburst/provenance/04-preview-tuning-report.json +0 -40
  51. package/packages/build.particle.golden_upgrade_starburst/provenance/asset-map.json +0 -115
  52. package/packages/build.particle.golden_upgrade_starburst/provenance/lineage.json +0 -40
  53. package/packages/build.particle.orange_upgrade_transform_sparks/assets/runtime/particleEmitter.v1.js +0 -210
  54. package/packages/build.particle.orange_upgrade_transform_sparks/assets/textures/b5b27ab1-e740-4398-b407-848fc2b2c897.png +0 -0
  55. package/packages/build.particle.orange_upgrade_transform_sparks/effect.json +0 -887
  56. package/packages/build.particle.orange_upgrade_transform_sparks/media/preview.gif +0 -0
  57. package/packages/build.particle.orange_upgrade_transform_sparks/media/preview.mp4 +0 -0
  58. package/packages/build.particle.orange_upgrade_transform_sparks/media/preview.webm +0 -0
  59. package/packages/build.particle.orange_upgrade_transform_sparks/media/thumbnail.png +0 -0
  60. package/packages/build.particle.orange_upgrade_transform_sparks/metadata/description.json +0 -179
  61. package/packages/build.particle.orange_upgrade_transform_sparks/provenance/03-effect.original.json +0 -859
  62. package/packages/build.particle.orange_upgrade_transform_sparks/provenance/03-normalized-vfx-to-babylon-report.json +0 -260
  63. package/packages/build.particle.orange_upgrade_transform_sparks/provenance/04-preview-overrides.json +0 -478
  64. package/packages/build.particle.orange_upgrade_transform_sparks/provenance/04-preview-tuning-report.json +0 -40
  65. package/packages/build.particle.orange_upgrade_transform_sparks/provenance/asset-map.json +0 -114
  66. package/packages/build.particle.orange_upgrade_transform_sparks/provenance/lineage.json +0 -41
  67. package/packages/build.particle.wood_chip_dust_burst/assets/runtime/particleEmitter.v1.js +0 -210
  68. package/packages/build.particle.wood_chip_dust_burst/assets/textures/effect_yanwu4.png +0 -0
  69. package/packages/build.particle.wood_chip_dust_burst/assets/textures/suipian3.png +0 -0
  70. package/packages/build.particle.wood_chip_dust_burst/effect.json +0 -1400
  71. package/packages/build.particle.wood_chip_dust_burst/media/contact-sheet.png +0 -0
  72. package/packages/build.particle.wood_chip_dust_burst/media/preview.gif +0 -0
  73. package/packages/build.particle.wood_chip_dust_burst/media/preview.mp4 +0 -0
  74. package/packages/build.particle.wood_chip_dust_burst/media/preview.webm +0 -0
  75. package/packages/build.particle.wood_chip_dust_burst/media/thumbnail.png +0 -0
  76. package/packages/build.particle.wood_chip_dust_burst/metadata/description.json +0 -173
  77. package/packages/build.particle.wood_chip_dust_burst/provenance/03-effect.original.json +0 -1277
  78. package/packages/build.particle.wood_chip_dust_burst/provenance/03-normalized-vfx-to-babylon-report.json +0 -329
  79. package/packages/build.particle.wood_chip_dust_burst/provenance/04-preview-overrides.json +0 -749
  80. package/packages/build.particle.wood_chip_dust_burst/provenance/04-preview-tuning-report.json +0 -60
  81. package/packages/build.particle.wood_chip_dust_burst/provenance/asset-map.json +0 -146
  82. package/packages/build.particle.wood_chip_dust_burst/provenance/lineage.json +0 -69
  83. package/packages/effects/building-upgrade/effect.json +0 -6
  84. package/packages/effects/building-upgrade/index.ts +0 -387
  85. package/packages/effects/character-entrance/effect.json +0 -6
  86. package/packages/effects/character-entrance/index.ts +0 -308
  87. package/packages/effects/coin-burst/index.ts +0 -48
  88. package/packages/effects/comet-trail-flame/assets/textures/trail_5x4.webp +0 -0
  89. package/packages/effects/comet-trail-flame/index.ts +0 -107
  90. package/packages/effects/conveyor-upgrade/effect.json +0 -6
  91. package/packages/effects/conveyor-upgrade/index.ts +0 -401
  92. package/packages/effects/debris-smoke/assets/models/rock_debris.glb +0 -0
  93. package/packages/effects/debris-smoke/assets/textures/smoke22.webp +0 -0
  94. package/packages/effects/debris-smoke/index.ts +0 -102
  95. package/packages/effects/door_open_gold_flakes/assets/runtime/goldFlakes.v1.js +0 -397
  96. package/packages/effects/door_open_gold_flakes/door_open_gold_flakes.json +0 -498
  97. package/packages/effects/door_open_gold_flakes/index.ts +0 -11
  98. package/packages/effects/electric-arc/assets/textures/spark_4x4.webp +0 -0
  99. package/packages/effects/electric-arc/index.ts +0 -63
  100. package/packages/effects/energy-shield/effect.json +0 -7
  101. package/packages/effects/energy-shield/index.ts +0 -432
  102. package/packages/effects/explosion/assets/textures/baozha29.webp +0 -0
  103. package/packages/effects/explosion/assets/textures/glow01.webp +0 -0
  104. package/packages/effects/explosion/assets/textures/lizi01.webp +0 -0
  105. package/packages/effects/explosion/assets/textures/xulie_lizibaozha02_5x5.webp +0 -0
  106. package/packages/effects/explosion/index.ts +0 -115
  107. package/packages/effects/ground-tile-upgrade/effect.json +0 -6
  108. package/packages/effects/ground-tile-upgrade/index.ts +0 -410
  109. package/packages/effects/hit-flash/index.ts +0 -77
  110. package/packages/effects/laser-beam/assets/textures/laser_glow.webp +0 -0
  111. package/packages/effects/laser-beam/assets/textures/laser_noise.webp +0 -0
  112. package/packages/effects/laser-beam/index.ts +0 -6
  113. package/packages/effects/laser-beam-factory.ts +0 -146
  114. package/packages/effects/lumber-cart-suction/effect.json +0 -6
  115. package/packages/effects/lumber-cart-suction/index.ts +0 -399
  116. package/packages/effects/lumber-debris-scatter/assets/models/lumber_prop_model.glb +0 -0
  117. package/packages/effects/lumber-debris-scatter/assets/models/lumber_prop_model.glb.versions/.active +0 -1
  118. package/packages/effects/lumber-debris-scatter/assets/models/lumber_prop_model.glb.versions/1781589063890_upload.glb +0 -0
  119. package/packages/effects/lumber-debris-scatter/assets/runtime/solidParticleScatter.v1.js +0 -236
  120. package/packages/effects/lumber-debris-scatter/effect.json +0 -228
  121. package/packages/effects/lumber-debris-scatter/index.ts +0 -780
  122. package/packages/effects/lumber_vehicle_gear_spin/assets/runtime/gearSpin.v1.js +0 -202
  123. package/packages/effects/lumber_vehicle_gear_spin/index.ts +0 -11
  124. package/packages/effects/lumber_vehicle_gear_spin/lumber_vehicle_gear_spin.json +0 -338
  125. package/packages/effects/lumber_vehicle_upgrade_aura/assets/runtime/upgradeAura.v1.js +0 -353
  126. package/packages/effects/lumber_vehicle_upgrade_aura/index.ts +0 -13
  127. package/packages/effects/lumber_vehicle_upgrade_aura/lumber_vehicle_upgrade_aura.json +0 -365
  128. package/packages/effects/lumber_vehicle_wood_chips/assets/runtime/solidParticleScatter.v1.js +0 -310
  129. package/packages/effects/lumber_vehicle_wood_chips/index.ts +0 -11
  130. package/packages/effects/lumber_vehicle_wood_chips/lumber_vehicle_wood_chips.json +0 -335
  131. package/packages/effects/monster-hit/index.ts +0 -129
  132. package/packages/effects/player-upgrade/effect.json +0 -6
  133. package/packages/effects/player-upgrade/index.ts +0 -640
  134. package/packages/effects/pulse-laser-volley/assets/textures/bolt_guangshu.webp +0 -0
  135. package/packages/effects/pulse-laser-volley/index.ts +0 -215
  136. package/packages/effects/resource-collect-sparkles/effect.json +0 -6
  137. package/packages/effects/resource-collect-sparkles/index.ts +0 -254
  138. package/packages/effects/run-footstep-dust/assets/runtime/runFootstepDust.v1.js +0 -215
  139. package/packages/effects/run-footstep-dust/effect.json +0 -183
  140. package/packages/effects/run-footstep-dust/index.ts +0 -377
  141. package/packages/effects/space-shared.ts +0 -120
  142. package/packages/effects/thruster-flame/index.ts +0 -306
  143. package/packages/effects/treasure-attention/effect.json +0 -7
  144. package/packages/effects/treasure-attention/index.ts +0 -630
  145. package/packages/effects/tree-chop-dust/assets/textures/tree_chop_dust_atlas.png +0 -0
  146. package/packages/effects/tree-chop-dust/effect.json +0 -8
  147. package/packages/effects/tree-chop-dust/index.ts +0 -202
  148. package/packages/effects/tree-leaf-chop-burst/assets/runtime/particleEmitter.v1.js +0 -303
  149. package/packages/effects/tree-leaf-chop-burst/assets/textures/tree_leaf_chop_burst_leaf_atlas.png +0 -0
  150. package/packages/effects/tree-leaf-chop-burst/effect.json +0 -498
  151. package/packages/effects/tree-leaf-chop-burst/index.ts +0 -294
  152. package/packages/effects/tree_chop_dust_burst/assets/runtime/particleEmitter.v1.js +0 -318
  153. package/packages/effects/tree_chop_dust_burst/assets/textures/tree_chop_dust_burst_dust.png +0 -0
  154. package/packages/effects/tree_chop_dust_burst/index.ts +0 -13
  155. package/packages/effects/tree_chop_dust_burst/tree_chop_dust_burst.json +0 -412
  156. package/packages/effects/ufo-thread-flame/assets/textures/flame_flow.webp +0 -0
  157. package/packages/effects/ufo-thread-flame/assets/textures/flame_spike.webp +0 -0
  158. package/packages/effects/ufo-thread-flame/index.ts +0 -153
  159. package/packages/effects/vehicle-exhaust-smoke/assets/textures/vehicle_exhaust_smoke_atlas.png +0 -0
  160. package/packages/effects/vehicle-exhaust-smoke/effect.json +0 -8
  161. package/packages/effects/vehicle-exhaust-smoke/index.ts +0 -298
  162. package/packages/effects/vehicle-upgrade/effect.json +0 -6
  163. package/packages/effects/vehicle-upgrade/index.ts +0 -404
  164. package/packages/effects/weapon-trail/assets/textures/trail_wedge.png +0 -0
  165. package/packages/effects/weapon-trail/index.ts +0 -317
  166. package/packages/effects/wood-crusher-sawdust/assets/runtime/particleEmitter.v1.js +0 -312
  167. package/packages/effects/wood-crusher-sawdust/assets/textures/wood_crusher_sawdust_dust.png +0 -0
  168. package/packages/effects/wood-crusher-sawdust/assets/textures/wood_crusher_sawdust_fiber.png +0 -0
  169. package/packages/effects/wood-crusher-sawdust/index.ts +0 -43
  170. package/packages/effects/wood-crusher-sawdust/wood_crusher_sawdust.json +0 -592
  171. package/packages/effects/wood-cutter-sawdust/assets/runtime/particleEmitter.v1.js +0 -312
  172. package/packages/effects/wood-cutter-sawdust/assets/textures/wood_cutter_sawdust_chip.png +0 -0
  173. package/packages/effects/wood-cutter-sawdust/assets/textures/wood_cutter_sawdust_dust.png +0 -0
  174. package/packages/effects/wood-cutter-sawdust/index.ts +0 -43
  175. package/packages/effects/wood-cutter-sawdust/wood_cutter_sawdust.json +0 -592
  176. package/packages/effects/wood-sawdust-effect-factory.ts +0 -194
  177. package/packages/effects/wood_crusher_sawdust/assets/runtime/particleEmitter.v1.js +0 -318
  178. package/packages/effects/wood_crusher_sawdust/assets/textures/wood_crusher_sawdust_dust.png +0 -0
  179. package/packages/effects/wood_crusher_sawdust/assets/textures/wood_crusher_sawdust_fiber.png +0 -0
  180. package/packages/effects/wood_crusher_sawdust/index.ts +0 -29
  181. package/packages/effects/wood_crusher_sawdust/wood_crusher_sawdust.json +0 -592
  182. package/packages/effects/wood_cutter_sawdust/assets/runtime/particleEmitter.v1.js +0 -318
  183. package/packages/effects/wood_cutter_sawdust/assets/textures/wood_cutter_sawdust_chip.png +0 -0
  184. package/packages/effects/wood_cutter_sawdust/assets/textures/wood_cutter_sawdust_dust.png +0 -0
  185. package/packages/effects/wood_cutter_sawdust/index.ts +0 -29
  186. package/packages/effects/wood_cutter_sawdust/wood_cutter_sawdust.json +0 -592
  187. package/packages/effects/wood_peel_material_test/assets/runtime/woodPeelMaterialTest.v1.js +0 -196
  188. package/packages/effects/wood_peel_material_test/index.ts +0 -11
  189. package/packages/effects/wood_peel_material_test/wood_peel_material_test.json +0 -136
  190. package/packages/env.particle.forest_edge_fog/assets/runtime/particleEmitter.v1.js +0 -210
  191. package/packages/env.particle.forest_edge_fog/assets/textures/f12a23c4-b924-4322-a260-3d982428f1e8.png +0 -0
  192. package/packages/env.particle.forest_edge_fog/assets/textures/yuan.png +0 -0
  193. package/packages/env.particle.forest_edge_fog/effect.json +0 -854
  194. package/packages/env.particle.forest_edge_fog/media/preview.gif +0 -0
  195. package/packages/env.particle.forest_edge_fog/media/preview.mp4 +0 -0
  196. package/packages/env.particle.forest_edge_fog/media/preview.webm +0 -0
  197. package/packages/env.particle.forest_edge_fog/media/thumbnail.png +0 -0
  198. package/packages/env.particle.forest_edge_fog/metadata/description.json +0 -148
  199. package/packages/env.particle.forest_edge_fog/provenance/03-effect.original.json +0 -827
  200. package/packages/env.particle.forest_edge_fog/provenance/03-normalized-vfx-to-babylon-report.json +0 -196
  201. package/packages/env.particle.forest_edge_fog/provenance/04-preview-overrides.json +0 -432
  202. package/packages/env.particle.forest_edge_fog/provenance/04-preview-tuning-report.json +0 -28
  203. package/packages/env.particle.forest_edge_fog/provenance/asset-map.json +0 -124
  204. package/packages/env.particle.forest_edge_fog/provenance/lineage.json +0 -41
  205. package/packages/generation.ts +0 -14
  206. package/packages/index.ts +0 -14
  207. package/packages/legacy-particle-runtime.ts +0 -113
  208. package/packages/manifestRuntimePackage.ts +0 -519
  209. package/packages/registry.ts +0 -85
  210. package/packages/rendering.ts +0 -13
  211. package/packages/resource.particle.viscous_oil_suction/assets/runtime/top_disk_suction/particleEmitter.v1.js +0 -424
  212. package/packages/resource.particle.viscous_oil_suction/assets/textures/Glow ad.png +0 -0
  213. package/packages/resource.particle.viscous_oil_suction/effect.json +0 -1254
  214. package/packages/resource.particle.viscous_oil_suction/media/preview.gif +0 -0
  215. package/packages/resource.particle.viscous_oil_suction/media/preview.mp4 +0 -0
  216. package/packages/resource.particle.viscous_oil_suction/media/preview.webm +0 -0
  217. package/packages/resource.particle.viscous_oil_suction/media/thumbnail.png +0 -0
  218. package/packages/resource.particle.viscous_oil_suction/metadata/description.json +0 -122
  219. package/packages/resource.particle.viscous_oil_suction/provenance/03-effect.original.json +0 -1051
  220. package/packages/resource.particle.viscous_oil_suction/provenance/03-normalized-vfx-to-babylon-report.json +0 -200
  221. package/packages/resource.particle.viscous_oil_suction/provenance/04-preview-overrides.json +0 -581
  222. package/packages/resource.particle.viscous_oil_suction/provenance/04-preview-tuning-report.json +0 -28
  223. package/packages/resource.particle.viscous_oil_suction/provenance/asset-map.json +0 -111
  224. package/packages/resource.particle.viscous_oil_suction/provenance/lineage.json +0 -45
  225. package/packages/types.ts +0 -195
  226. package/tooling/check-dist-runtime.mjs +0 -166
  227. package/tooling/generate-index.mjs +0 -55
  228. package/tooling/test-guardrails.mjs +0 -157
  229. package/tooling/validate-boundary.mjs +0 -92
  230. package/tooling/validate-effects.mjs +0 -304
  231. package/tooling/validate.mjs +0 -53
@@ -1,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
- }