@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,333 +0,0 @@
1
- export const runtimeId = "simpleMeshEffect/v1";
2
-
3
- export const runtimeContract = {
4
- runtimeId,
5
- kind: "meshEffect",
6
- meshEffectFields: {
7
- shape: "Mesh primitive to create. Supported values: box, cylinder.",
8
- size: "Absolute mesh dimensions in Babylon local x/y/z units.",
9
- offset: "Babylon TransformNode position offset in x/y/z units.",
10
- tintColor: "Base shader tint color in 0-1 RGBA space. RGB is multiplied by tintColorIntensity; alpha is not.",
11
- tintColorIntensity: "Brightness multiplier applied only to shader tintColor.rgb.",
12
- fadeSoftness: "Softness of the upward reveal edge in normalized local-Y space.",
13
- boundsAxis: "Axis used by the shader for height fade and reveal. simpleMeshEffect/v1 uses localY.",
14
- },
15
- shaderUniforms: {
16
- diffuseSampler: "Emitter texture sampled by UV.",
17
- tintColor: "Final vec4 tint passed to shader after runtime keyframe sampling.",
18
- globalAlpha: "Final alpha multiplier sampled from emitter.alphaKeys.",
19
- revealY: "Normalized upward reveal progress from 0 to 1.",
20
- fadeSoftness: "Soft reveal edge width.",
21
- meshMinY: "Minimum local mesh Y used to normalize vertical gradients.",
22
- meshMaxY: "Maximum local mesh Y used to normalize vertical gradients.",
23
- },
24
- runtimeBindings: {
25
- "shader.tintColor.rgb": "meshEffect.tintColor.rgb * meshEffect.tintColorIntensity * sample(colorKeys, t).rgb",
26
- "shader.tintColor.a": "meshEffect.tintColor.a * sample(colorKeys, t).a",
27
- "shader.globalAlpha": "sample(alphaKeys, t).alpha",
28
- "root.scaling.y": "sample(meshScaleKeys.y, t) / finalMeshScaleKeysY",
29
- "shader.revealY": "elapsed / duration",
30
- },
31
- };
32
-
33
- function num(value, fallback = 0) {
34
- const next = Number(value);
35
- return Number.isFinite(next) ? next : fallback;
36
- }
37
-
38
- function readColor(BABYLON, value, fallback = new BABYLON.Color4(1, 1, 1, 1)) {
39
- if (!value) return fallback;
40
- return new BABYLON.Color4(num(value.r, fallback.r), num(value.g, fallback.g), num(value.b, fallback.b), num(value.a, fallback.a));
41
- }
42
-
43
- function sampleKeyframes(keys, valueKey, t, fallback = 1) {
44
- if (!Array.isArray(keys) || keys.length === 0) return fallback;
45
- const points = keys
46
- .map((key) => ({ time: Math.min(1, Math.max(0, num(key.time, 0))), value: num(key[valueKey], fallback) }))
47
- .sort((a, b) => a.time - b.time);
48
- if (t <= points[0].time) return points[0].value;
49
- for (let index = 1; index < points.length; index += 1) {
50
- const prev = points[index - 1];
51
- const next = points[index];
52
- if (t <= next.time) {
53
- const span = Math.max(0.0001, next.time - prev.time);
54
- const local = (t - prev.time) / span;
55
- return prev.value + (next.value - prev.value) * local;
56
- }
57
- }
58
- return points.at(-1).value;
59
- }
60
-
61
- function sampleColorKeyframes(BABYLON, keys, t, fallback = new BABYLON.Color4(1, 1, 1, 1)) {
62
- if (!Array.isArray(keys) || keys.length === 0) return fallback;
63
- const points = keys
64
- .map((key) => ({
65
- time: Math.min(1, Math.max(0, num(key.time, 0))),
66
- color: readColor(BABYLON, key.color, fallback),
67
- }))
68
- .sort((a, b) => a.time - b.time);
69
- if (t <= points[0].time) return points[0].color;
70
- for (let index = 1; index < points.length; index += 1) {
71
- const prev = points[index - 1];
72
- const next = points[index];
73
- if (t <= next.time) {
74
- const span = Math.max(0.0001, next.time - prev.time);
75
- const local = (t - prev.time) / span;
76
- return new BABYLON.Color4(
77
- prev.color.r + (next.color.r - prev.color.r) * local,
78
- prev.color.g + (next.color.g - prev.color.g) * local,
79
- prev.color.b + (next.color.b - prev.color.b) * local,
80
- prev.color.a + (next.color.a - prev.color.a) * local,
81
- );
82
- }
83
- }
84
- return points.at(-1).color;
85
- }
86
-
87
- function shaderMaterialAlphaMode(BABYLON, value) {
88
- if (value === "STANDARD") return BABYLON.Engine.ALPHA_COMBINE;
89
- if (value === "MULTIPLY") return BABYLON.Engine.ALPHA_MULTIPLY ?? BABYLON.Engine.ALPHA_COMBINE;
90
- return BABYLON.Engine.ALPHA_ADD;
91
- }
92
-
93
- function shaderStoreName(emitter, index) {
94
- const id = String(emitter?.shader?.id || emitter?.meshEffect?.shaderId || `simpleMeshEffectV1_${index}`)
95
- .replace(/[^a-zA-Z0-9_]/g, "_")
96
- .replace(/^([^a-zA-Z_])/, "_$1");
97
- return id || `simpleMeshEffectV1_${index}`;
98
- }
99
-
100
- async function fetchShaderSource({ packagePath, label, urlForPackagePath }) {
101
- if (!packagePath) throw new Error(`Missing ${label} shader path.`);
102
- const url = urlForPackagePath ? urlForPackagePath(packagePath) : packagePath;
103
- const response = await fetch(url, { cache: "no-store" });
104
- if (!response.ok) throw new Error(`Failed to load ${label} shader ${packagePath}: HTTP ${response.status}.`);
105
- const source = await response.text();
106
- if (!source.trim()) throw new Error(`Loaded empty ${label} shader ${packagePath}.`);
107
- return source;
108
- }
109
-
110
- async function loadShaders({ BABYLON, emitter, index, urlForPackagePath }) {
111
- const name = shaderStoreName(emitter, index);
112
- const vertexSource = await fetchShaderSource({
113
- packagePath: emitter?.shader?.vertexShaderPath,
114
- label: "vertex",
115
- urlForPackagePath,
116
- });
117
- const fragmentSource = await fetchShaderSource({
118
- packagePath: emitter?.shader?.fragmentShaderPath,
119
- label: "fragment",
120
- urlForPackagePath,
121
- });
122
- BABYLON.Effect.ShadersStore[`${name}VertexShader`] = vertexSource;
123
- BABYLON.Effect.ShadersStore[`${name}FragmentShader`] = fragmentSource;
124
- return name;
125
- }
126
-
127
- function createMaterial({ BABYLON, scene, name, texture, alphaMode, shaderName }) {
128
- const material = new BABYLON.ShaderMaterial(name, scene, {
129
- vertex: shaderName,
130
- fragment: shaderName,
131
- }, {
132
- attributes: ["position", "uv"],
133
- uniforms: ["worldViewProjection", "tintColor", "meshMinY", "meshMaxY", "revealY", "fadeSoftness", "globalAlpha"],
134
- samplers: ["diffuseSampler"],
135
- needAlphaBlending: true,
136
- });
137
- material.setTexture("diffuseSampler", texture);
138
- material.setFloat("meshMinY", -1);
139
- material.setFloat("meshMaxY", 1);
140
- material.setFloat("revealY", 0);
141
- material.setFloat("fadeSoftness", 0.24);
142
- material.setFloat("globalAlpha", 1);
143
- material.backFaceCulling = false;
144
- material.alphaMode = shaderMaterialAlphaMode(BABYLON, alphaMode);
145
- return material;
146
- }
147
-
148
- function meshLocalYBounds(BABYLON, meshes) {
149
- let minY = Number.POSITIVE_INFINITY;
150
- let maxY = Number.NEGATIVE_INFINITY;
151
- for (const mesh of meshes) {
152
- const positions = mesh.getVerticesData?.(BABYLON.VertexBuffer.PositionKind) || [];
153
- for (let index = 1; index < positions.length; index += 3) {
154
- minY = Math.min(minY, positions[index]);
155
- maxY = Math.max(maxY, positions[index]);
156
- }
157
- }
158
- if (!Number.isFinite(minY) || !Number.isFinite(maxY)) return { minY: -1, maxY: 1 };
159
- return { minY, maxY: Math.max(maxY, minY + 0.0001) };
160
- }
161
-
162
- function shapeType(emitter) {
163
- const shape = emitter?.meshEffect?.shape || "box";
164
- return ["box", "cylinder"].includes(shape) ? shape : "box";
165
- }
166
-
167
- function createBoxMeshes({ BABYLON, scene, emitter, index, root, material, width, depth, height }) {
168
- const sides = [
169
- { name: "front", sideWidth: width, position: new BABYLON.Vector3(0, 0, depth * 0.5), rotationY: 0 },
170
- { name: "back", sideWidth: width, position: new BABYLON.Vector3(0, 0, -depth * 0.5), rotationY: Math.PI },
171
- { name: "right", sideWidth: depth, position: new BABYLON.Vector3(width * 0.5, 0, 0), rotationY: Math.PI * 0.5 },
172
- { name: "left", sideWidth: depth, position: new BABYLON.Vector3(-width * 0.5, 0, 0), rotationY: -Math.PI * 0.5 },
173
- ];
174
- return sides.map((side) => {
175
- const mesh = BABYLON.MeshBuilder.CreatePlane(`simple-mesh-effect-${emitter.name || index}-${side.name}`, { width: side.sideWidth, height }, scene);
176
- mesh.material = material;
177
- mesh.parent = root;
178
- mesh.position = side.position;
179
- mesh.rotation.y = side.rotationY;
180
- mesh.renderingGroupId = 2;
181
- mesh.metadata = { ...(mesh.metadata || {}), emitterIndex: index, meshEffectMode: "simple", meshEffectShape: "box" };
182
- return mesh;
183
- });
184
- }
185
-
186
- function createCylinderMeshes({ BABYLON, scene, emitter, index, root, material, width, depth, height }) {
187
- const mesh = BABYLON.MeshBuilder.CreateCylinder(`simple-mesh-effect-${emitter.name || index}-cylinder`, {
188
- height,
189
- diameter: 1,
190
- tessellation: 48,
191
- cap: BABYLON.Mesh.NO_CAP,
192
- }, scene);
193
- mesh.material = material;
194
- mesh.parent = root;
195
- mesh.scaling.x = width;
196
- mesh.scaling.z = depth;
197
- mesh.renderingGroupId = 2;
198
- mesh.metadata = { ...(mesh.metadata || {}), emitterIndex: index, meshEffectMode: "simple", meshEffectShape: "cylinder" };
199
- return [mesh];
200
- }
201
-
202
- function createMeshes({ BABYLON, scene, emitter, index, root, material, size }) {
203
- if (shapeType(emitter) === "cylinder") {
204
- return createCylinderMeshes({ BABYLON, scene, emitter, index, root, material, width: size.x, depth: size.z, height: size.y });
205
- }
206
- return createBoxMeshes({ BABYLON, scene, emitter, index, root, material, width: size.x, depth: size.z, height: size.y });
207
- }
208
-
209
- function defaultSize(emitter) {
210
- const finalMeshScaleY = Math.max(0.001, num(emitter.meshScaleKeys?.y?.at?.(-1)?.scale, 8));
211
- return {
212
- x: Math.max(0.1, num(emitter.meshScaleKeys?.x?.[0]?.scale, 7.125) * 1.016),
213
- y: Math.max(0.1, finalMeshScaleY * 1.016),
214
- z: Math.max(0.1, num(emitter.meshScaleKeys?.z?.[0]?.scale, 4.125) * 1.016),
215
- };
216
- }
217
-
218
- function meshEffectSize(emitter) {
219
- const fallback = defaultSize(emitter);
220
- return {
221
- x: Math.max(0.1, num(emitter.meshEffect?.size?.x, fallback.x)),
222
- y: Math.max(0.1, num(emitter.meshEffect?.size?.y, fallback.y)),
223
- z: Math.max(0.1, num(emitter.meshEffect?.size?.z, fallback.z)),
224
- };
225
- }
226
-
227
- function meshEffectOffset(emitter) {
228
- return {
229
- x: num(emitter.meshEffect?.offset?.x, 0),
230
- y: num(emitter.meshEffect?.offset?.y, 0.65),
231
- z: num(emitter.meshEffect?.offset?.z, 0),
232
- };
233
- }
234
-
235
- function playbackSpeed(emitter) {
236
- return Math.max(0.001, num(emitter.updateSpeed, 0.01) / 0.01);
237
- }
238
-
239
- function stopAfterSeconds(emitter, fallback = 1) {
240
- return num(emitter.runtime?.stopAfterSeconds, fallback);
241
- }
242
-
243
- export async function createSimpleMeshEffectRuntime({ BABYLON, scene, emitter, index = 0, urlForPackagePath, shouldStart = false }) {
244
- if (!BABYLON) throw new Error("createSimpleMeshEffectRuntime requires BABYLON.");
245
- if (!scene) throw new Error("createSimpleMeshEffectRuntime requires scene.");
246
- if (!emitter) throw new Error("createSimpleMeshEffectRuntime requires emitter.");
247
- const shaderName = await loadShaders({ BABYLON, emitter, index, urlForPackagePath });
248
- const textureUrl = urlForPackagePath ? urlForPackagePath(emitter.particleTexturePath) : emitter.particleTexturePath;
249
- const texture = new BABYLON.Texture(textureUrl, scene);
250
- texture.hasAlpha = true;
251
- texture.getAlphaFromRGB = true;
252
-
253
- const material = createMaterial({
254
- BABYLON,
255
- scene,
256
- name: `simple-mesh-effect-material-${emitter.name || index}`,
257
- texture,
258
- alphaMode: emitter.blendMode,
259
- shaderName,
260
- });
261
- const size = meshEffectSize(emitter);
262
- const offset = meshEffectOffset(emitter);
263
- const root = new BABYLON.TransformNode(`simple-mesh-effect-${emitter.name || index}`, scene);
264
- root.position = new BABYLON.Vector3(offset.x, offset.y, offset.z);
265
- root.metadata = { ...(root.metadata || {}), emitterIndex: index, meshEffectMode: "simple", meshEffectShape: shapeType(emitter) };
266
- const meshes = createMeshes({ BABYLON, scene, emitter, index, root, material, size });
267
- root.setEnabled(false);
268
-
269
- const bounds = meshLocalYBounds(BABYLON, meshes);
270
- material.setFloat("meshMinY", bounds.minY);
271
- material.setFloat("meshMaxY", bounds.maxY);
272
-
273
- const finalMeshScaleY = Math.max(0.001, num(emitter.meshScaleKeys?.y?.at?.(-1)?.scale, 1));
274
- const duration = Math.max(0.1, stopAfterSeconds(emitter) / playbackSpeed(emitter));
275
- const baseTint = readColor(BABYLON, emitter.meshEffect?.tintColor, new BABYLON.Color4(1, 1, 1, 1));
276
- const tintColorIntensity = Math.max(0, num(emitter.meshEffect?.tintColorIntensity, 1));
277
- const fadeSoftness = Math.max(0.03, num(emitter.meshEffect?.fadeSoftness, 0.24));
278
- const colorKeys = emitter.colorKeys || [];
279
- const meshScaleKeys = emitter.meshScaleKeys || null;
280
- let startedAt = 0;
281
- let observer = null;
282
- let running = false;
283
-
284
- const update = () => {
285
- const elapsed = (performance.now() - startedAt) / 1000;
286
- const t = Math.min(1, elapsed / duration);
287
- const sizeFactor = Math.max(0.001, sampleKeyframes(emitter.sizeKeys, "size", t, 1));
288
- const alphaFactor = Math.min(1, Math.max(0, sampleKeyframes(emitter.alphaKeys, "alpha", t, 1)));
289
- const colorFactor = sampleColorKeyframes(BABYLON, colorKeys, t);
290
- const rawScaleY = Math.max(0.001, sampleKeyframes(meshScaleKeys?.y, "scale", t, sizeFactor));
291
- const scaleY = Math.max(0.001, rawScaleY / finalMeshScaleY);
292
- root.scaling.set(1, scaleY, 1);
293
- root.position.set(offset.x, offset.y - bounds.minY * scaleY, offset.z);
294
- material.setFloat("revealY", Math.min(1, Math.max(0.001, t)));
295
- material.setFloat("fadeSoftness", fadeSoftness);
296
- material.setFloat("globalAlpha", alphaFactor);
297
- material.setVector4("tintColor", new BABYLON.Vector4(
298
- baseTint.r * tintColorIntensity * colorFactor.r,
299
- baseTint.g * tintColorIntensity * colorFactor.g,
300
- baseTint.b * tintColorIntensity * colorFactor.b,
301
- baseTint.a * colorFactor.a,
302
- ));
303
- if (t >= 1) stop();
304
- };
305
-
306
- function start() {
307
- stop();
308
- running = true;
309
- startedAt = performance.now();
310
- root.setEnabled(true);
311
- update();
312
- observer = scene.onBeforeRenderObservable.add(update);
313
- }
314
-
315
- function stop() {
316
- if (observer) scene.onBeforeRenderObservable.remove(observer);
317
- observer = null;
318
- running = false;
319
- root.setEnabled(false);
320
- }
321
-
322
- function dispose() {
323
- stop();
324
- for (const mesh of meshes) mesh.dispose();
325
- root.dispose();
326
- material.dispose();
327
- texture.dispose();
328
- }
329
-
330
- const preview = { start, stop, dispose, isStarted: () => running, root, meshes, material };
331
- if (shouldStart) preview.start();
332
- return preview;
333
- }
@@ -1,25 +0,0 @@
1
- precision highp float;
2
- varying vec2 vUV;
3
- varying float vLocalY;
4
- uniform sampler2D diffuseSampler;
5
- uniform vec4 tintColor;
6
- uniform float meshMinY;
7
- uniform float meshMaxY;
8
- uniform float revealY;
9
- uniform float fadeSoftness;
10
- uniform float globalAlpha;
11
- float saturate(float value) {
12
- return clamp(value, 0.0, 1.0);
13
- }
14
- void main(void) {
15
- vec4 tex = texture2D(diffuseSampler, vUV);
16
- float height = max(meshMaxY - meshMinY, 0.0001);
17
- float y01 = saturate((vLocalY - meshMinY) / height);
18
- float revealMask = saturate((revealY - y01) / max(fadeSoftness, 0.0001));
19
- float bottomSoft = smoothstep(0.0, 0.06, y01);
20
- float verticalFade = pow(saturate(1.0 - y01), 1.35);
21
- float textureGlow = mix(0.65, 1.15, max(max(tex.r, tex.g), tex.b));
22
- float alpha = tintColor.a * globalAlpha * revealMask * bottomSoft * verticalFade * textureGlow;
23
- vec3 color = tintColor.rgb * mix(vec3(0.72), vec3(1.18), tex.rgb);
24
- gl_FragColor = vec4(color, alpha);
25
- }
@@ -1,11 +0,0 @@
1
- precision highp float;
2
- attribute vec3 position;
3
- attribute vec2 uv;
4
- uniform mat4 worldViewProjection;
5
- varying vec2 vUV;
6
- varying float vLocalY;
7
- void main(void) {
8
- vUV = uv;
9
- vLocalY = position.y;
10
- gl_Position = worldViewProjection * vec4(position, 1.0);
11
- }