@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,111 +0,0 @@
1
- {
2
- "schemaVersion": "vfx-asset-map/1.0",
3
- "generatedAt": "2026-05-21T13:04:29.644Z",
4
- "sourcePackage": "vfx-intermediate/cocos-babylon-packages/gas_town_oil_suction",
5
- "policy": {
6
- "runtimeAssetsRoot": "assets/",
7
- "sourceAssetsRoot": "source/",
8
- "note": "assets/ contains files loaded by Babylon runtime. source/cocos/assets/ preserves the original Cocos asset tree for traceability and reconversion."
9
- },
10
- "entries": [
11
- {
12
- "id": "glow_ad",
13
- "kind": "texture",
14
- "group": "textures",
15
- "role": "babylon-runtime",
16
- "runtimeUse": true,
17
- "packagePath": "assets/textures/Glow ad.png",
18
- "sourcePackagePath": "assets/textures/Glow ad.png",
19
- "sourceArchivePath": "source/cocos/assets/ArtResources/Effect/GasTown_OilSuction/Glow ad.png",
20
- "sourcePath": "gs://fps-vfx-library/packages/resource.particle.viscous_oil_suction/source/cocos/assets/ArtResources/Effect/GasTown_OilSuction/Glow ad.png",
21
- "sourceId": "dd44b0a9-0998-4c24-ba2e-d6ac9d1bebb7@6c48a",
22
- "usedBy": [],
23
- "originalProjectPath": "assets/ArtResources/Effect/GasTown_OilSuction/Glow ad.png"
24
- },
25
- {
26
- "id": "asset",
27
- "kind": "material",
28
- "group": "materials",
29
- "role": "source-evidence",
30
- "runtimeUse": false,
31
- "packagePath": "source/cocos/assets/ArtResources/Effect/GasTown_OilSuction/石油.mtl",
32
- "sourcePackagePath": "assets/materials/石油.mtl",
33
- "sourceArchivePath": "source/cocos/assets/ArtResources/Effect/GasTown_OilSuction/石油.mtl",
34
- "sourcePath": "gs://fps-vfx-library/packages/resource.particle.viscous_oil_suction/source/cocos/assets/ArtResources/Effect/GasTown_OilSuction/石油.mtl",
35
- "sourceId": "4aabf2b0-1d20-4e13-9384-ae47eb8522aa",
36
- "usedBy": [],
37
- "originalProjectPath": "assets/ArtResources/Effect/GasTown_OilSuction/石油.mtl"
38
- },
39
- {
40
- "id": "particle_emitter_oil_suction_v1",
41
- "kind": "script",
42
- "group": "scripts",
43
- "role": "babylon-runtime",
44
- "runtimeUse": true,
45
- "packagePath": "assets/runtime/gas_town_oil_suction/particleEmitter.v1.js",
46
- "sourcePackagePath": "assets/runtime/gas_town_oil_suction/particleEmitter.v1.js",
47
- "sourceArchivePath": null,
48
- "sourcePath": null,
49
- "sourceId": null,
50
- "usedBy": []
51
- },
52
- {
53
- "id": "02-normalized-vfx",
54
- "kind": "raw",
55
- "group": "raw",
56
- "role": "source-evidence",
57
- "runtimeUse": false,
58
- "packagePath": "source/02-normalized-vfx.json",
59
- "sourcePackagePath": "source/02-normalized-vfx.json",
60
- "sourceArchivePath": null,
61
- "sourcePath": "gs://fps-vfx-library/packages/resource.particle.viscous_oil_suction/source/02-normalized-vfx.json",
62
- "sourceId": null,
63
- "usedBy": []
64
- },
65
- {
66
- "id": "01-source-dump",
67
- "kind": "raw",
68
- "group": "raw",
69
- "role": "source-evidence",
70
- "runtimeUse": false,
71
- "packagePath": "source/01-source-dump.json",
72
- "sourcePackagePath": "source/01-source-dump.json",
73
- "sourceArchivePath": null,
74
- "sourcePath": "gs://fps-vfx-library/packages/resource.particle.viscous_oil_suction/source/01-source-dump.json",
75
- "sourceId": null,
76
- "usedBy": []
77
- },
78
- {
79
- "id": "asset",
80
- "kind": "raw",
81
- "group": "raw",
82
- "role": "source-evidence",
83
- "runtimeUse": false,
84
- "packagePath": "source/raw/吸石油.prefab",
85
- "sourcePackagePath": "source/raw/吸石油.prefab",
86
- "sourceArchivePath": "source/cocos/assets/ArtResources/Effect/GasTown_OilSuction/吸石油.prefab",
87
- "sourcePath": "gs://fps-vfx-library/packages/resource.particle.viscous_oil_suction/source/cocos/assets/ArtResources/Effect/GasTown_OilSuction/吸石油.prefab",
88
- "sourceId": "29954e7e-d137-4c8b-a730-4f0320cbece8",
89
- "usedBy": [],
90
- "originalProjectPath": "assets/ArtResources/Effect/GasTown_OilSuction/吸石油.prefab"
91
- },
92
- {
93
- "id": "asset.meta",
94
- "kind": "raw",
95
- "group": "raw",
96
- "role": "source-evidence",
97
- "runtimeUse": false,
98
- "packagePath": "source/raw/吸石油.prefab.meta",
99
- "sourcePackagePath": "source/raw/吸石油.prefab.meta",
100
- "sourceArchivePath": "source/cocos/assets/ArtResources/Effect/GasTown_OilSuction/吸石油.prefab.meta",
101
- "sourcePath": "gs://fps-vfx-library/packages/resource.particle.viscous_oil_suction/source/cocos/assets/ArtResources/Effect/GasTown_OilSuction/吸石油.prefab.meta",
102
- "sourceId": "29954e7e-d137-4c8b-a730-4f0320cbece8",
103
- "usedBy": [],
104
- "originalProjectPath": "assets/ArtResources/Effect/GasTown_OilSuction/吸石油.prefab.meta"
105
- }
106
- ],
107
- "gcsPrefix": "gs://fps-vfx-library/packages/resource.particle.viscous_oil_suction",
108
- "sourceArchivePrefix": "gs://fps-vfx-library/packages/resource.particle.viscous_oil_suction/source",
109
- "fullProvenancePrefix": "gs://fps-vfx-library/packages/resource.particle.viscous_oil_suction/provenance",
110
- "canonicalSource": "gcs"
111
- }
@@ -1,45 +0,0 @@
1
- {
2
- "schemaVersion": "vfx-library-lineage/1.0",
3
- "savedAt": "2026-05-21T13:04:29.665Z",
4
- "sourcePackage": "vfx-intermediate/cocos-babylon-packages/gas_town_oil_suction",
5
- "sourceEffect": "03-effect.json",
6
- "libraryPackage": "packages/resource.particle.viscous_oil_suction",
7
- "effectId": "resource.particle.viscous_oil_suction",
8
- "media": {
9
- "previewVideo": "media/preview.webm",
10
- "previewWebm": "media/preview.webm",
11
- "previewMp4": "media/preview.mp4",
12
- "previewGif": "media/preview.gif",
13
- "thumbnail": "media/thumbnail.png",
14
- "gcsUri": null
15
- },
16
- "recording": {
17
- "provider": "browser-mediarecorder",
18
- "recordedAt": "2026-05-21T13:04:30.575Z",
19
- "mimeType": "video/webm;codecs=vp9",
20
- "durationSec": 10,
21
- "fps": 30,
22
- "media": {
23
- "previewVideo": "media/preview.webm",
24
- "previewWebm": "media/preview.webm",
25
- "previewMp4": "media/preview.mp4",
26
- "previewGif": "media/preview.gif",
27
- "thumbnail": "media/thumbnail.png",
28
- "gcsUri": null
29
- }
30
- },
31
- "description": {
32
- "provider": "litellm",
33
- "status": "described",
34
- "model": "gemini-3.1-pro-preview",
35
- "generatedAt": "2026-05-21T13:30:34.263Z"
36
- },
37
- "gcsPrefix": "gs://fps-vfx-library/packages/resource.particle.viscous_oil_suction",
38
- "sourceArchivePrefix": "gs://fps-vfx-library/packages/resource.particle.viscous_oil_suction/source",
39
- "fullProvenancePrefix": "gs://fps-vfx-library/packages/resource.particle.viscous_oil_suction/provenance",
40
- "previousIds": [
41
- "world.particle.gas_town_oil_suction",
42
- "world.particle.viscous_oil_suction"
43
- ],
44
- "renamedAt": "2026-05-21T13:39:08.485Z"
45
- }
package/packages/types.ts DELETED
@@ -1,195 +0,0 @@
1
- import type { Scene } from '@babylonjs/core/scene';
2
- import type { Vector3 } from '@babylonjs/core/Maths/math.vector';
3
- import type { TransformNode } from '@babylonjs/core/Meshes/transformNode';
4
- import type { AbstractMesh } from '@babylonjs/core/Meshes/abstractMesh';
5
-
6
- export type VfxDebugAnchor = 'playerRight' | 'player';
7
-
8
- // ── 运行时外部信息(inputs)──────────────────────────────────────────────
9
- // 与 params(设计期可调、保存)区分:inputs 是运行时由游戏逻辑提供的外部上下文,常动态。
10
- // 值可为静态值或 provider(() => 值);动态目标(移动)用 provider 每帧取。见 docs/vfx-placement-design.md。
11
- export type VfxInput<T> = T | (() => T);
12
- export type VfxInputKey = 'aim' | 'normal' | 'endpoints' | 'target';
13
-
14
- /** 调用方提供的 inputs(放在 VfxSpawnTransform.inputs)。 */
15
- export interface VfxEffectInputs {
16
- aim?: VfxInput<Vector3>; // 瞄准点(激光/定向武器)
17
- normal?: VfxInput<Vector3>; // 表面法线(贴花/冲击)
18
- endpoints?: Array<VfxInput<Vector3>>; // link/链式(≥2 端点)
19
- target?: AbstractMesh; // target-material 类(改目标自身材质)
20
- /** 运行时标量(throttle/intensity 等),值可静态或 provider;特效每帧读取做活改(G5)。 */
21
- scalars?: Record<string, VfxInput<number>>;
22
- }
23
-
24
- /** create() 收到的、已归一化为访问器的 inputs(provider 与静态值都变成可调用的函数)。 */
25
- export interface VfxResolvedInputs {
26
- aim?: () => Vector3;
27
- normal?: () => Vector3;
28
- endpoints?: Array<() => Vector3>;
29
- target?: AbstractMesh;
30
- scalars?: Record<string, () => number>;
31
- }
32
-
33
- export type VfxParamValue = number | string | VfxColorValue;
34
- export type VfxParamValues = Record<string, VfxParamValue>;
35
-
36
- export interface VfxColorValue {
37
- r: number;
38
- g: number;
39
- b: number;
40
- }
41
-
42
- export type VfxParamKind =
43
- | 'number'
44
- | 'color'
45
- | 'enum'
46
- | 'opacity'
47
- | 'lifetime'
48
- | 'scale';
49
-
50
- export interface VfxParamDefinitionBase {
51
- key: string;
52
- label: string;
53
- kind: VfxParamKind;
54
- description?: string;
55
- }
56
-
57
- export interface VfxNumberParamDefinition extends VfxParamDefinitionBase {
58
- kind: 'number' | 'opacity' | 'lifetime' | 'scale';
59
- min?: number;
60
- max?: number;
61
- step?: number;
62
- }
63
-
64
- export interface VfxColorParamDefinition extends VfxParamDefinitionBase {
65
- kind: 'color';
66
- }
67
-
68
- export interface VfxEnumParamOption {
69
- value: string;
70
- label: string;
71
- }
72
-
73
- export interface VfxEnumParamDefinition extends VfxParamDefinitionBase {
74
- kind: 'enum';
75
- options: VfxEnumParamOption[];
76
- }
77
-
78
- export type VfxParamDefinition = VfxNumberParamDefinition | VfxColorParamDefinition | VfxEnumParamDefinition;
79
-
80
- export interface VfxEffectPackageContext<PParams extends VfxParamValues = VfxParamValues> {
81
- scene: Scene;
82
- root: TransformNode;
83
- position: Vector3;
84
- rotationY: number;
85
- renderingGroupId?: number;
86
- params: PParams;
87
- /**
88
- * 解析后的三轴缩放(来自 spawnTransform.scale,默认 (1,1,1))。
89
- * root 的缩放由 service 写好;但**几何不挂 root 的 world/detached 特效**(粒子/抛物池/世界坐标 emitter)
90
- * root.scaling 作用不到,须自行把 ctx.scale 乘进几何尺寸/初速(G3)。
91
- */
92
- scale: Vector3;
93
- /** 运行时外部信息(已归一化为访问器)。link/target/定向武器/活改标量等按 required/optionalInputs 读取。 */
94
- inputs?: VfxResolvedInputs;
95
- }
96
-
97
- export interface VfxEffectHandle {
98
- root: TransformNode;
99
- ready?: Promise<void>;
100
- dispose(): void;
101
- /** 可选:运行时活改 params(无须 dispose+replay,避免重置缓动/可见闪)。声明即纳入契约(G5)。 */
102
- update?(params: Partial<VfxParamValues>): void;
103
- }
104
-
105
- export interface VfxEffectManifest {
106
- id: string;
107
- nameZh: string;
108
- assets?: string[];
109
- source?: string;
110
- }
111
-
112
- export interface VfxSpawnParamKeys {
113
- offsetX?: string;
114
- offsetY?: string;
115
- offsetZ?: string;
116
- }
117
-
118
- /** 欧拉角(弧度)/ 三轴缩放的纯数据三元组。 */
119
- export interface VfxVector3Like {
120
- x: number;
121
- y: number;
122
- z: number;
123
- }
124
-
125
- export interface VfxSpawnTransform {
126
- position?: Vector3;
127
- /**
128
- * 兼容别名:绕 Y 轴旋转(弧度)。
129
- * 若同时给了 `rotation`,以 `rotation` 为准;否则回退到 `rotationY`。
130
- */
131
- rotationY?: number;
132
- /** 完整欧拉角旋转(弧度);给了就覆盖 `rotationY`。 */
133
- rotation?: VfxVector3Like;
134
- /** 等比缩放(number)或三轴缩放;默认 1。 */
135
- scale?: number | VfxVector3Like;
136
- /** 挂载点节点;给了就把特效 root parent 到它(特效随之跟随)。 */
137
- parent?: TransformNode;
138
- /**
139
- * position/rotation/scale 的坐标系解释:
140
- * - 给了 `parent` 时默认 `true`:按相对 parent 的 **local** transform 解释;
141
- * - 没给 `parent` 时默认 `false`:按 **世界坐标** 解释(保持现状行为)。
142
- */
143
- offsetIsLocal?: boolean;
144
- renderingGroupId?: number;
145
- /** 运行时外部信息(瞄准点/法线/端点/目标 mesh);值可为静态或 provider(动态每帧取)。 */
146
- inputs?: VfxEffectInputs;
147
- }
148
-
149
- export interface VfxParamsFile {
150
- schemaVersion: string;
151
- effectId?: string;
152
- updatedAt?: string | null;
153
- params?: Partial<VfxParamValues>;
154
- }
155
-
156
- /**
157
- * 特效的放置本质(内禀标记)。决定系统/binding/面板怎么放它,不靠猜。见 docs/vfx-placement-design.md。
158
- * - 'socket' local:挂对象命名挂点、随它走(parent + follow)。
159
- * - 'world' global:放世界某点、不跟随(fire-and-forget,可按法线定向)。
160
- * - 'screen' global:屏幕/相机层(后处理/相机扰动/DOM 全屏),无 3D transform。
161
- * - 'target' 改目标自身材质/渲染态,没有可 spawn 的 root。
162
- * - 'link' 连 ≥2 个端点(每帧重建几何),单 parent 表达不了。
163
- */
164
- export type VfxPlacement = 'socket' | 'world' | 'screen' | 'target' | 'link';
165
-
166
- export interface VfxEffectPackage<PParams extends VfxParamValues = VfxParamValues> {
167
- id: string;
168
- nameZh: string;
169
- manifest?: VfxEffectManifest;
170
- defaultParams: PParams;
171
- debugAnchor?: VfxDebugAnchor;
172
- spawnParams?: VfxSpawnParamKeys;
173
- savedParams?: Partial<VfxParamValues>;
174
- debugParams: VfxParamDefinition[];
175
- /** 放置本质标记(默认 'world')。 */
176
- placement?: VfxPlacement;
177
- /** 声明**必需**的运行时 inputs(link 必须给 endpoints/aim、target 类必须给 target mesh);service 缺失时 warn。 */
178
- requiredInputs?: VfxInputKey[];
179
- /** 声明**可选**的运行时 inputs(给了就用、不给走默认,如定向武器的 aim:给了朝目标、不给走挂点朝向);不触发缺失 warn(G2)。 */
180
- optionalInputs?: VfxInputKey[];
181
- /**
182
- * 几何空间:'local'=几何挂 root 子节点随它刚性变换;'world'=几何用世界坐标、root 仅作每帧采样源(拖尾)。
183
- * 默认随 placement 推断('socket'→local,其余→world)。
184
- */
185
- geometrySpace?: 'local' | 'world';
186
- /**
187
- * 构建特效。**约定(G6):root 的 transform(position/rotation/scaling/parent)归 service 独占** ——
188
- * service 在 create() 后会二次 `applySpawnToRoot` 覆盖,create 内写 `root.position/rotation/scaling` 会被静默清掉。
189
- * 需要内部局部偏移(如抬升)请用 root 下的**子 TransformNode** 承载,或声明 `spawnParams.offsetY` 走 service 存活通道。
190
- * 几何挂 root 子树即随挂载跟随;world/拖尾类几何走世界坐标、读 ctx.scale 缩放。
191
- */
192
- create(context: VfxEffectPackageContext<PParams>): VfxEffectHandle;
193
- }
194
-
195
- export type VfxDebugOverrides = Record<string, Partial<VfxParamValues>>;
@@ -1,166 +0,0 @@
1
- #!/usr/bin/env node
2
- // 新增特效 guardrail · Layer 2(构建产物禁运行时扫描,见 issue #3,最强一层)。
3
- // `pnpm build` 之后扫 dist/,镜像消费方 Playable bundle 策略(lumber-order
4
- // scripts/check-playable-asset-bundle.mjs 的 forbiddenTokens),把"会坑消费方"的重运行时
5
- // 提前到库侧拦住 —— 即便它是被某个特效"间接"拉进来的(顺着 dist 的 chunk import 图归因到特效)。
6
- //
7
- // 用法:
8
- // node tooling/check-dist-runtime.mjs # 扫 dist/
9
- // node tooling/check-dist-runtime.mjs --dist <dir> # 换扫描目录(回归 fixture 用)
10
- // 退出码:命中 → 1;干净 → 0。
11
- import { readdirSync, statSync, readFileSync, existsSync } from 'node:fs';
12
- import { resolve, dirname, join, relative } from 'node:path';
13
- import { fileURLToPath } from 'node:url';
14
-
15
- const LIB_ROOT = resolve(dirname(fileURLToPath(import.meta.url)), '..');
16
- const argv = process.argv.slice(2);
17
- const distArg = argv.indexOf('--dist') >= 0 ? argv[argv.indexOf('--dist') + 1] : undefined;
18
- const DIST = resolve(distArg ?? join(LIB_ROOT, 'dist'));
19
-
20
- // 精确 token —— 类名/扩展名/MIME,绝不用宽松子串(如 `basis` 会误报 RingBasis 变量)。
21
- // 与 lumber-order check-playable-asset-bundle.mjs 的 forbiddenTokens 对齐 + 补 draco/ktx2。
22
- const SUBSTRING_TOKENS = [
23
- 'EXT_meshopt_compression', 'MeshoptDecoder', 'meshopt_decoder',
24
- 'KHR_draco_mesh_compression', 'DracoCompression', 'DracoDecoder', 'draco_decoder', 'draco_wasm_wrapper',
25
- 'KHR_texture_basisu', 'KhronosTextureContainer2', '_KTX2Decoder', 'MSCTranscoder', 'basis_transcoder',
26
- 'application/x-glb-brotli', 'brotli-dec-wasm',
27
- 'application/wasm', 'data:application/wasm',
28
- 'WebAssembly.Module', 'WebAssembly.instantiate',
29
- ];
30
- // `.wasm` 资源 URL:要求路径分隔符(/),只拦真资源路径如 "./decoder.wasm"/"chunks/x.wasm",
31
- // 不误报纯文件名字符串(错误消息 "physics.wasm" / debug 标签 "ringBurst.wasm" 无 /)。
32
- const WASM_URL_RE = /['"][^'"]*\/[^'"/]*\.wasm(\?[^'"]*)?['"]/;
33
-
34
- // 与 Layer 1 一致:扫描前剥注释(避免 dist 里残留的解释性注释/banner 误报)。
35
- function stripComments(src) {
36
- return src.replace(/\/\*[\s\S]*?\*\//g, '').replace(/(?<!:)\/\/[^\n]*/g, '');
37
- }
38
-
39
- function tokensIn(rawContent) {
40
- const content = stripComments(rawContent);
41
- const hits = [];
42
- for (const t of SUBSTRING_TOKENS) if (content.includes(t)) hits.push(t);
43
- const m = content.match(WASM_URL_RE);
44
- if (m) hits.push(m[0]);
45
- return hits;
46
- }
47
-
48
- // dist 模块文件:.js + .mjs/.cjs(防止重运行时藏在非 .js chunk 里绕过)。
49
- const DIST_MODULE_EXT = /\.(js|mjs|cjs)$/;
50
- function jsFilesIn(dir, out = []) {
51
- if (!existsSync(dir)) return out;
52
- for (const e of readdirSync(dir)) {
53
- const p = join(dir, e);
54
- const s = statSync(p);
55
- if (s.isDirectory()) jsFilesIn(p, out);
56
- else if (DIST_MODULE_EXT.test(e)) out.push(p);
57
- }
58
- return out;
59
- }
60
-
61
- // 解析一个 dist 模块的相对 import(构 chunk 依赖图;裸包如 @babylonjs/* 不进图)。
62
- function relImports(file) {
63
- const src = readFileSync(file, 'utf8');
64
- const specs = new Set();
65
- let m;
66
- const re = /\bfrom\s*['"]([^'"]+)['"]/g;
67
- while ((m = re.exec(src))) specs.add(m[1]);
68
- const side = /\bimport\s*['"]([^'"]+)['"]/g;
69
- while ((m = side.exec(src))) specs.add(m[1]);
70
- const dyn = /\bimport\(\s*['"]([^'"]+)['"]\s*\)/g;
71
- while ((m = dyn.exec(src))) specs.add(m[1]);
72
- const resolved = [];
73
- for (const spec of specs) {
74
- if (!spec.startsWith('.')) continue;
75
- const target = resolve(dirname(file), spec);
76
- const cands = [target, target + '.js', target + '.mjs', target + '.cjs',
77
- join(target, 'index.js'), join(target, 'index.mjs'), join(target, 'index.cjs')];
78
- for (const cand of cands) {
79
- if (existsSync(cand) && statSync(cand).isFile()) { resolved.push(cand); break; }
80
- }
81
- }
82
- return resolved;
83
- }
84
-
85
- // dist/<dir>/index.{js,mjs,cjs} 取第一个存在的入口。
86
- function indexEntry(dir) {
87
- for (const ext of ['js', 'mjs', 'cjs']) {
88
- const p = join(dir, `index.${ext}`);
89
- if (existsSync(p)) return p;
90
- }
91
- return null;
92
- }
93
-
94
- function reachableFrom(entry, importGraph) {
95
- const seen = new Set();
96
- const stack = [entry];
97
- while (stack.length) {
98
- const f = stack.pop();
99
- if (seen.has(f)) continue;
100
- seen.add(f);
101
- for (const dep of importGraph.get(f) ?? []) if (!seen.has(dep)) stack.push(dep);
102
- }
103
- return seen;
104
- }
105
-
106
- // ── 主流程 ────────────────────────────────────────────────────────────────────
107
- if (!existsSync(DIST)) {
108
- console.error(`✗ dist 不存在:${DIST}(先 \`pnpm build\`)。`);
109
- process.exit(1);
110
- }
111
-
112
- const allJs = jsFilesIn(DIST);
113
- const importGraph = new Map(allJs.map((f) => [f, relImports(f)]));
114
- const tokenByFile = new Map();
115
- for (const f of allJs) {
116
- const hits = tokensIn(readFileSync(f, 'utf8'));
117
- if (hits.length) tokenByFile.set(f, [...new Set(hits)]);
118
- }
119
-
120
- // 入口 = dist/index.{js,mjs,cjs}(runtime 核心)+ 每个 dist/effects/<id>/index.{js,mjs,cjs}。
121
- const entries = [];
122
- const rootIndex = indexEntry(DIST);
123
- if (rootIndex) entries.push({ label: 'runtime (index)', entry: rootIndex });
124
- const effectsDist = join(DIST, 'effects');
125
- if (existsSync(effectsDist)) {
126
- for (const id of readdirSync(effectsDist)) {
127
- const idx = indexEntry(join(effectsDist, id));
128
- if (idx) entries.push({ label: id, entry: idx });
129
- }
130
- }
131
-
132
- // 归因:每个入口 → 它可达的、命中 token 的文件。
133
- const findings = []; // {label, file, tokens}
134
- const attributedFiles = new Set();
135
- for (const { label, entry } of entries) {
136
- const reach = reachableFrom(entry, importGraph);
137
- for (const f of reach) {
138
- if (tokenByFile.has(f)) {
139
- attributedFiles.add(f);
140
- findings.push({ label, file: f, tokens: tokenByFile.get(f) });
141
- }
142
- }
143
- }
144
- // 没被任何入口可达但仍命中的文件(孤儿,理论上不该有)。
145
- for (const [f, tokens] of tokenByFile) {
146
- if (!attributedFiles.has(f)) findings.push({ label: '(未归因/孤儿 chunk)', file: f, tokens });
147
- }
148
-
149
- if (findings.length === 0) {
150
- console.log(`✅ Layer 2 dist 禁运行时扫描通过:${allJs.length} 个 js,0 命中(无 meshopt/draco/ktx2/brotli/wasm 运行时)。`);
151
- process.exit(0);
152
- }
153
-
154
- console.log(`❌ Layer 2 dist 禁运行时扫描:发现 ${findings.length} 处命中。\n`);
155
- // 按特效聚合展示
156
- const byLabel = {};
157
- for (const f of findings) (byLabel[f.label] ??= []).push(f);
158
- for (const [label, items] of Object.entries(byLabel)) {
159
- console.log(` 特效/入口:${label}`);
160
- for (const it of items) {
161
- console.log(` ✗ ${relative(DIST, it.file)} ← ${it.tokens.join(', ')}`);
162
- }
163
- }
164
- console.log('\n修复:定位拉入该运行时的特效(多半是全量 glTF loader / 含 meshopt|draco|ktx2 的 GLB)。');
165
- console.log(' 改用核心 loader、把 GLB 预解压成 plain、或用 ?url 内联的轻量资源。详见 Layer 1 提示与 #2 v0.1.1。');
166
- process.exit(1);
@@ -1,55 +0,0 @@
1
- #!/usr/bin/env node
2
- // 生成顶层 index.json:扫 packages/effects/<id>/,汇总 id/nameZh/kind/category/tags/media。
3
- // 富检索字段(category/tags/media)优先取 description.json,避免与 manifest 双源。
4
- import { readdirSync, statSync, readFileSync, writeFileSync, existsSync } from 'node:fs';
5
- import { resolve, dirname, join } from 'node:path';
6
- import { fileURLToPath } from 'node:url';
7
-
8
- const LIB_ROOT = resolve(dirname(fileURLToPath(import.meta.url)), '..');
9
- const EFFECTS_DIR = join(LIB_ROOT, 'packages', 'effects');
10
-
11
- function readJsonSafe(p) {
12
- try { return JSON.parse(readFileSync(p, 'utf8')); } catch { return null; }
13
- }
14
-
15
- const effects = [];
16
- for (const entry of readdirSync(EFFECTS_DIR)) {
17
- const dir = join(EFFECTS_DIR, entry);
18
- if (!statSync(dir).isDirectory()) continue;
19
- const indexPath = join(dir, 'index.ts');
20
- if (!existsSync(indexPath)) continue;
21
-
22
- const effectJson = readJsonSafe(join(dir, 'effect.json')) ?? {};
23
- const desc = readJsonSafe(join(dir, 'description.json')) ?? {};
24
- const indexSrc = readFileSync(indexPath, 'utf8');
25
- const kind = /createManifestRuntimeEffectPackage|createDataDrivenEffectPackage/.test(indexSrc) ? 'data' : 'code';
26
-
27
- const mediaDir = join(dir, 'media');
28
- const media = {};
29
- if (existsSync(mediaDir)) {
30
- for (const f of readdirSync(mediaDir)) {
31
- if (/thumbnail/.test(f)) media.thumbnail = `packages/effects/${entry}/media/${f}`;
32
- else if (/preview\.(mp4|webm|gif)$/.test(f)) media.preview = `packages/effects/${entry}/media/${f}`;
33
- }
34
- }
35
-
36
- effects.push({
37
- id: effectJson.id || entry,
38
- dir: entry,
39
- nameZh: effectJson.nameZh || desc.searchTitleZh || entry,
40
- kind,
41
- category: desc.semanticTags?.[0] || (effectJson.id?.split('.')[0]) || null,
42
- tags: desc.searchKeywordsEn || desc.visualTags || effectJson.search?.tags || [],
43
- media,
44
- path: `packages/effects/${entry}`,
45
- });
46
- }
47
- effects.sort((a, b) => a.id.localeCompare(b.id));
48
-
49
- const out = {
50
- schemaVersion: 'vfx-index/1.0',
51
- count: effects.length,
52
- effects,
53
- };
54
- writeFileSync(join(LIB_ROOT, 'index.json'), JSON.stringify(out, null, 2) + '\n');
55
- console.log(`✅ index.json 生成:${effects.length} 个特效。`);