@fps-games/vfx 0.1.1 → 0.3.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +115 -0
- package/README.md +41 -0
- package/dist/effects/coin-burst/index.js +6 -2
- package/dist/effects/comet-trail-flame/index.js +3 -1
- package/dist/effects/debris-smoke/index.js +1 -0
- package/dist/effects/electric-arc/index.js +1 -0
- package/dist/effects/energy-shield/index.js +1 -0
- package/dist/effects/explosion/index.js +3 -2
- package/dist/effects/hit-flash/index.js +12 -4
- package/dist/effects/laser-beam/index.js +14 -2
- package/dist/effects/lumber_vehicle_upgrade_aura/index.js +1 -0
- package/dist/effects/monster-hit/index.js +2 -1
- package/dist/effects/player-upgrade/index.js +5 -3
- package/dist/effects/pulse-laser-volley/index.js +14 -4
- package/dist/effects/thruster-flame/index.js +3 -1
- package/dist/effects/treasure-attention/index.d.ts +54 -0
- package/dist/effects/treasure-attention/index.js +535 -0
- package/dist/effects/ufo-thread-flame/index.js +1 -0
- package/dist/effects/vehicle-upgrade/index.js +4 -1
- package/dist/effects/weapon-trail/index.js +8 -3
- package/dist/effects/wood_crusher_sawdust/index.d.ts +4 -0
- package/dist/effects/wood_cutter_sawdust/index.d.ts +4 -0
- package/dist/index.js +85 -17
- package/dist/types.d.ts +80 -0
- package/index.json +19 -1
- package/package.json +9 -4
- package/packages/effects/treasure-attention/vfx-params.json +49 -0
- package/tooling/vfx-cli.mjs +8 -1
- package/docs/AUTHORING_EFFECTS.md +0 -297
- package/docs/VFX_LIBRARY_ARCHITECTURE_chatgpt.md +0 -1580
- package/docs/VFX_LIBRARY_EXECUTION_PLAN.md +0 -229
- package/docs/VFX_LIBRARY_PLAN.md +0 -546
- package/docs/vfx-ab/RESULTS.md +0 -35
- package/docs/vfx-ab/lumber-order/vehicle-exhaust-smoke/after.png +0 -0
- package/docs/vfx-ab/lumber-order/vehicle-exhaust-smoke/before.png +0 -0
- package/docs/vfx-ab/lumber-truck/vehicle-exhaust-smoke/after.png +0 -0
- package/docs/vfx-ab/lumber-truck/vehicle-exhaust-smoke/before.png +0 -0
- package/docs/vfx-integration_chatgpt.md +0 -462
- package/docs/weapon-trail-visualization.html +0 -241
- package/packages/EffectPackageService.ts +0 -240
- package/packages/SceneVfxService.ts +0 -96
- package/packages/build.mesh.yellow_build_upgrade_indicator/assets/runtime/simpleMeshEffect.v1.js +0 -333
- package/packages/build.mesh.yellow_build_upgrade_indicator/assets/shaders/mesh-effect-preview.frag.glsl +0 -25
- package/packages/build.mesh.yellow_build_upgrade_indicator/assets/shaders/mesh-effect-preview.vert.glsl +0 -11
- package/packages/build.mesh.yellow_build_upgrade_indicator/assets/textures/effect_jianbian.png +0 -0
- package/packages/build.mesh.yellow_build_upgrade_indicator/effect.json +0 -927
- package/packages/build.mesh.yellow_build_upgrade_indicator/media/contact-sheet.png +0 -0
- package/packages/build.mesh.yellow_build_upgrade_indicator/media/preview.gif +0 -0
- package/packages/build.mesh.yellow_build_upgrade_indicator/media/preview.mp4 +0 -0
- package/packages/build.mesh.yellow_build_upgrade_indicator/media/preview.webm +0 -0
- package/packages/build.mesh.yellow_build_upgrade_indicator/media/thumbnail.png +0 -0
- package/packages/build.mesh.yellow_build_upgrade_indicator/metadata/description.json +0 -197
- package/packages/build.mesh.yellow_build_upgrade_indicator/provenance/03-effect.original.json +0 -895
- package/packages/build.mesh.yellow_build_upgrade_indicator/provenance/03-normalized-vfx-to-babylon-report.json +0 -241
- package/packages/build.mesh.yellow_build_upgrade_indicator/provenance/04-preview-overrides.json +0 -542
- package/packages/build.mesh.yellow_build_upgrade_indicator/provenance/04-preview-tuning-report.json +0 -69
- package/packages/build.mesh.yellow_build_upgrade_indicator/provenance/asset-map.json +0 -125
- package/packages/build.mesh.yellow_build_upgrade_indicator/provenance/lineage.json +0 -44
- package/packages/build.particle.golden_upgrade_starburst/assets/runtime/particleEmitter.v1.js +0 -210
- package/packages/build.particle.golden_upgrade_starburst/assets/textures/effect_guangdian.png +0 -0
- package/packages/build.particle.golden_upgrade_starburst/effect.json +0 -880
- package/packages/build.particle.golden_upgrade_starburst/media/contact-sheet.png +0 -0
- package/packages/build.particle.golden_upgrade_starburst/media/preview.gif +0 -0
- package/packages/build.particle.golden_upgrade_starburst/media/preview.mp4 +0 -0
- package/packages/build.particle.golden_upgrade_starburst/media/preview.webm +0 -0
- package/packages/build.particle.golden_upgrade_starburst/media/thumbnail.png +0 -0
- package/packages/build.particle.golden_upgrade_starburst/metadata/description.json +0 -161
- package/packages/build.particle.golden_upgrade_starburst/provenance/03-effect.original.json +0 -762
- package/packages/build.particle.golden_upgrade_starburst/provenance/03-normalized-vfx-to-babylon-report.json +0 -260
- package/packages/build.particle.golden_upgrade_starburst/provenance/04-preview-overrides.json +0 -436
- package/packages/build.particle.golden_upgrade_starburst/provenance/04-preview-tuning-report.json +0 -40
- package/packages/build.particle.golden_upgrade_starburst/provenance/asset-map.json +0 -115
- package/packages/build.particle.golden_upgrade_starburst/provenance/lineage.json +0 -40
- package/packages/build.particle.orange_upgrade_transform_sparks/assets/runtime/particleEmitter.v1.js +0 -210
- package/packages/build.particle.orange_upgrade_transform_sparks/assets/textures/b5b27ab1-e740-4398-b407-848fc2b2c897.png +0 -0
- package/packages/build.particle.orange_upgrade_transform_sparks/effect.json +0 -887
- package/packages/build.particle.orange_upgrade_transform_sparks/media/preview.gif +0 -0
- package/packages/build.particle.orange_upgrade_transform_sparks/media/preview.mp4 +0 -0
- package/packages/build.particle.orange_upgrade_transform_sparks/media/preview.webm +0 -0
- package/packages/build.particle.orange_upgrade_transform_sparks/media/thumbnail.png +0 -0
- package/packages/build.particle.orange_upgrade_transform_sparks/metadata/description.json +0 -179
- package/packages/build.particle.orange_upgrade_transform_sparks/provenance/03-effect.original.json +0 -859
- package/packages/build.particle.orange_upgrade_transform_sparks/provenance/03-normalized-vfx-to-babylon-report.json +0 -260
- package/packages/build.particle.orange_upgrade_transform_sparks/provenance/04-preview-overrides.json +0 -478
- package/packages/build.particle.orange_upgrade_transform_sparks/provenance/04-preview-tuning-report.json +0 -40
- package/packages/build.particle.orange_upgrade_transform_sparks/provenance/asset-map.json +0 -114
- package/packages/build.particle.orange_upgrade_transform_sparks/provenance/lineage.json +0 -41
- package/packages/build.particle.wood_chip_dust_burst/assets/runtime/particleEmitter.v1.js +0 -210
- package/packages/build.particle.wood_chip_dust_burst/assets/textures/effect_yanwu4.png +0 -0
- package/packages/build.particle.wood_chip_dust_burst/assets/textures/suipian3.png +0 -0
- package/packages/build.particle.wood_chip_dust_burst/effect.json +0 -1400
- package/packages/build.particle.wood_chip_dust_burst/media/contact-sheet.png +0 -0
- package/packages/build.particle.wood_chip_dust_burst/media/preview.gif +0 -0
- package/packages/build.particle.wood_chip_dust_burst/media/preview.mp4 +0 -0
- package/packages/build.particle.wood_chip_dust_burst/media/preview.webm +0 -0
- package/packages/build.particle.wood_chip_dust_burst/media/thumbnail.png +0 -0
- package/packages/build.particle.wood_chip_dust_burst/metadata/description.json +0 -173
- package/packages/build.particle.wood_chip_dust_burst/provenance/03-effect.original.json +0 -1277
- package/packages/build.particle.wood_chip_dust_burst/provenance/03-normalized-vfx-to-babylon-report.json +0 -329
- package/packages/build.particle.wood_chip_dust_burst/provenance/04-preview-overrides.json +0 -749
- package/packages/build.particle.wood_chip_dust_burst/provenance/04-preview-tuning-report.json +0 -60
- package/packages/build.particle.wood_chip_dust_burst/provenance/asset-map.json +0 -146
- package/packages/build.particle.wood_chip_dust_burst/provenance/lineage.json +0 -69
- package/packages/effects/building-upgrade/effect.json +0 -6
- package/packages/effects/building-upgrade/index.ts +0 -387
- package/packages/effects/character-entrance/effect.json +0 -6
- package/packages/effects/character-entrance/index.ts +0 -308
- package/packages/effects/coin-burst/index.ts +0 -43
- package/packages/effects/comet-trail-flame/assets/textures/trail_5x4.webp +0 -0
- package/packages/effects/comet-trail-flame/index.ts +0 -106
- package/packages/effects/conveyor-upgrade/effect.json +0 -6
- package/packages/effects/conveyor-upgrade/index.ts +0 -401
- package/packages/effects/debris-smoke/assets/models/rock_debris.glb +0 -0
- package/packages/effects/debris-smoke/assets/textures/smoke22.webp +0 -0
- package/packages/effects/debris-smoke/index.ts +0 -101
- package/packages/effects/door_open_gold_flakes/assets/runtime/goldFlakes.v1.js +0 -397
- package/packages/effects/door_open_gold_flakes/door_open_gold_flakes.json +0 -498
- package/packages/effects/door_open_gold_flakes/index.ts +0 -11
- package/packages/effects/electric-arc/assets/textures/spark_4x4.webp +0 -0
- package/packages/effects/electric-arc/index.ts +0 -62
- package/packages/effects/energy-shield/effect.json +0 -7
- package/packages/effects/energy-shield/index.ts +0 -431
- package/packages/effects/explosion/assets/textures/baozha29.webp +0 -0
- package/packages/effects/explosion/assets/textures/glow01.webp +0 -0
- package/packages/effects/explosion/assets/textures/lizi01.webp +0 -0
- package/packages/effects/explosion/assets/textures/xulie_lizibaozha02_5x5.webp +0 -0
- package/packages/effects/explosion/index.ts +0 -114
- package/packages/effects/ground-tile-upgrade/effect.json +0 -6
- package/packages/effects/ground-tile-upgrade/index.ts +0 -410
- package/packages/effects/hit-flash/index.ts +0 -69
- package/packages/effects/laser-beam/assets/textures/laser_glow.webp +0 -0
- package/packages/effects/laser-beam/assets/textures/laser_noise.webp +0 -0
- package/packages/effects/laser-beam/index.ts +0 -6
- package/packages/effects/laser-beam-factory.ts +0 -135
- package/packages/effects/lumber-cart-suction/effect.json +0 -6
- package/packages/effects/lumber-cart-suction/index.ts +0 -399
- package/packages/effects/lumber-debris-scatter/assets/models/lumber_prop_model.glb +0 -0
- package/packages/effects/lumber-debris-scatter/assets/models/lumber_prop_model.glb.versions/.active +0 -1
- package/packages/effects/lumber-debris-scatter/assets/models/lumber_prop_model.glb.versions/1781589063890_upload.glb +0 -0
- package/packages/effects/lumber-debris-scatter/assets/runtime/solidParticleScatter.v1.js +0 -236
- package/packages/effects/lumber-debris-scatter/effect.json +0 -228
- package/packages/effects/lumber-debris-scatter/index.ts +0 -780
- package/packages/effects/lumber_vehicle_gear_spin/assets/runtime/gearSpin.v1.js +0 -202
- package/packages/effects/lumber_vehicle_gear_spin/index.ts +0 -11
- package/packages/effects/lumber_vehicle_gear_spin/lumber_vehicle_gear_spin.json +0 -338
- package/packages/effects/lumber_vehicle_upgrade_aura/assets/runtime/upgradeAura.v1.js +0 -353
- package/packages/effects/lumber_vehicle_upgrade_aura/index.ts +0 -11
- package/packages/effects/lumber_vehicle_upgrade_aura/lumber_vehicle_upgrade_aura.json +0 -365
- package/packages/effects/lumber_vehicle_wood_chips/assets/runtime/solidParticleScatter.v1.js +0 -310
- package/packages/effects/lumber_vehicle_wood_chips/index.ts +0 -11
- package/packages/effects/lumber_vehicle_wood_chips/lumber_vehicle_wood_chips.json +0 -335
- package/packages/effects/monster-hit/index.ts +0 -128
- package/packages/effects/player-upgrade/effect.json +0 -6
- package/packages/effects/player-upgrade/index.ts +0 -635
- package/packages/effects/pulse-laser-volley/assets/textures/bolt_guangshu.webp +0 -0
- package/packages/effects/pulse-laser-volley/index.ts +0 -204
- package/packages/effects/resource-collect-sparkles/effect.json +0 -6
- package/packages/effects/resource-collect-sparkles/index.ts +0 -254
- package/packages/effects/run-footstep-dust/assets/runtime/runFootstepDust.v1.js +0 -215
- package/packages/effects/run-footstep-dust/effect.json +0 -183
- package/packages/effects/run-footstep-dust/index.ts +0 -377
- package/packages/effects/space-shared.ts +0 -120
- package/packages/effects/thruster-flame/index.ts +0 -305
- package/packages/effects/tree-chop-dust/assets/textures/tree_chop_dust_atlas.png +0 -0
- package/packages/effects/tree-chop-dust/effect.json +0 -8
- package/packages/effects/tree-chop-dust/index.ts +0 -202
- package/packages/effects/tree-leaf-chop-burst/assets/runtime/particleEmitter.v1.js +0 -303
- package/packages/effects/tree-leaf-chop-burst/assets/textures/tree_leaf_chop_burst_leaf_atlas.png +0 -0
- package/packages/effects/tree-leaf-chop-burst/effect.json +0 -498
- package/packages/effects/tree-leaf-chop-burst/index.ts +0 -294
- package/packages/effects/tree_chop_dust_burst/assets/runtime/particleEmitter.v1.js +0 -318
- package/packages/effects/tree_chop_dust_burst/assets/textures/tree_chop_dust_burst_dust.png +0 -0
- package/packages/effects/tree_chop_dust_burst/index.ts +0 -13
- package/packages/effects/tree_chop_dust_burst/tree_chop_dust_burst.json +0 -412
- package/packages/effects/ufo-thread-flame/assets/textures/flame_flow.webp +0 -0
- package/packages/effects/ufo-thread-flame/assets/textures/flame_spike.webp +0 -0
- package/packages/effects/ufo-thread-flame/index.ts +0 -152
- package/packages/effects/vehicle-exhaust-smoke/assets/textures/vehicle_exhaust_smoke_atlas.png +0 -0
- package/packages/effects/vehicle-exhaust-smoke/effect.json +0 -8
- package/packages/effects/vehicle-exhaust-smoke/index.ts +0 -298
- package/packages/effects/vehicle-upgrade/effect.json +0 -6
- package/packages/effects/vehicle-upgrade/index.ts +0 -401
- package/packages/effects/weapon-trail/assets/textures/trail_wedge.png +0 -0
- package/packages/effects/weapon-trail/index.ts +0 -313
- package/packages/effects/wood-crusher-sawdust/assets/runtime/particleEmitter.v1.js +0 -312
- package/packages/effects/wood-crusher-sawdust/assets/textures/wood_crusher_sawdust_dust.png +0 -0
- package/packages/effects/wood-crusher-sawdust/assets/textures/wood_crusher_sawdust_fiber.png +0 -0
- package/packages/effects/wood-crusher-sawdust/index.ts +0 -43
- package/packages/effects/wood-crusher-sawdust/wood_crusher_sawdust.json +0 -592
- package/packages/effects/wood-cutter-sawdust/assets/runtime/particleEmitter.v1.js +0 -312
- package/packages/effects/wood-cutter-sawdust/assets/textures/wood_cutter_sawdust_chip.png +0 -0
- package/packages/effects/wood-cutter-sawdust/assets/textures/wood_cutter_sawdust_dust.png +0 -0
- package/packages/effects/wood-cutter-sawdust/index.ts +0 -43
- package/packages/effects/wood-cutter-sawdust/wood_cutter_sawdust.json +0 -592
- package/packages/effects/wood-sawdust-effect-factory.ts +0 -194
- package/packages/effects/wood_crusher_sawdust/assets/runtime/particleEmitter.v1.js +0 -318
- package/packages/effects/wood_crusher_sawdust/assets/textures/wood_crusher_sawdust_dust.png +0 -0
- package/packages/effects/wood_crusher_sawdust/assets/textures/wood_crusher_sawdust_fiber.png +0 -0
- package/packages/effects/wood_crusher_sawdust/index.ts +0 -29
- package/packages/effects/wood_crusher_sawdust/wood_crusher_sawdust.json +0 -592
- package/packages/effects/wood_cutter_sawdust/assets/runtime/particleEmitter.v1.js +0 -318
- package/packages/effects/wood_cutter_sawdust/assets/textures/wood_cutter_sawdust_chip.png +0 -0
- package/packages/effects/wood_cutter_sawdust/assets/textures/wood_cutter_sawdust_dust.png +0 -0
- package/packages/effects/wood_cutter_sawdust/index.ts +0 -29
- package/packages/effects/wood_cutter_sawdust/wood_cutter_sawdust.json +0 -592
- package/packages/effects/wood_peel_material_test/assets/runtime/woodPeelMaterialTest.v1.js +0 -196
- package/packages/effects/wood_peel_material_test/index.ts +0 -11
- package/packages/effects/wood_peel_material_test/wood_peel_material_test.json +0 -136
- package/packages/env.particle.forest_edge_fog/assets/runtime/particleEmitter.v1.js +0 -210
- package/packages/env.particle.forest_edge_fog/assets/textures/f12a23c4-b924-4322-a260-3d982428f1e8.png +0 -0
- package/packages/env.particle.forest_edge_fog/assets/textures/yuan.png +0 -0
- package/packages/env.particle.forest_edge_fog/effect.json +0 -854
- package/packages/env.particle.forest_edge_fog/media/preview.gif +0 -0
- package/packages/env.particle.forest_edge_fog/media/preview.mp4 +0 -0
- package/packages/env.particle.forest_edge_fog/media/preview.webm +0 -0
- package/packages/env.particle.forest_edge_fog/media/thumbnail.png +0 -0
- package/packages/env.particle.forest_edge_fog/metadata/description.json +0 -148
- package/packages/env.particle.forest_edge_fog/provenance/03-effect.original.json +0 -827
- package/packages/env.particle.forest_edge_fog/provenance/03-normalized-vfx-to-babylon-report.json +0 -196
- package/packages/env.particle.forest_edge_fog/provenance/04-preview-overrides.json +0 -432
- package/packages/env.particle.forest_edge_fog/provenance/04-preview-tuning-report.json +0 -28
- package/packages/env.particle.forest_edge_fog/provenance/asset-map.json +0 -124
- package/packages/env.particle.forest_edge_fog/provenance/lineage.json +0 -41
- package/packages/generation.ts +0 -14
- package/packages/index.ts +0 -14
- package/packages/legacy-particle-runtime.ts +0 -113
- package/packages/manifestRuntimePackage.ts +0 -519
- package/packages/registry.ts +0 -85
- package/packages/rendering.ts +0 -13
- package/packages/resource.particle.viscous_oil_suction/assets/runtime/top_disk_suction/particleEmitter.v1.js +0 -424
- package/packages/resource.particle.viscous_oil_suction/assets/textures/Glow ad.png +0 -0
- package/packages/resource.particle.viscous_oil_suction/effect.json +0 -1254
- package/packages/resource.particle.viscous_oil_suction/media/preview.gif +0 -0
- package/packages/resource.particle.viscous_oil_suction/media/preview.mp4 +0 -0
- package/packages/resource.particle.viscous_oil_suction/media/preview.webm +0 -0
- package/packages/resource.particle.viscous_oil_suction/media/thumbnail.png +0 -0
- package/packages/resource.particle.viscous_oil_suction/metadata/description.json +0 -122
- package/packages/resource.particle.viscous_oil_suction/provenance/03-effect.original.json +0 -1051
- package/packages/resource.particle.viscous_oil_suction/provenance/03-normalized-vfx-to-babylon-report.json +0 -200
- package/packages/resource.particle.viscous_oil_suction/provenance/04-preview-overrides.json +0 -581
- package/packages/resource.particle.viscous_oil_suction/provenance/04-preview-tuning-report.json +0 -28
- package/packages/resource.particle.viscous_oil_suction/provenance/asset-map.json +0 -111
- package/packages/resource.particle.viscous_oil_suction/provenance/lineage.json +0 -45
- package/packages/types.ts +0 -107
- package/tooling/check-dist-runtime.mjs +0 -166
- package/tooling/generate-index.mjs +0 -55
- package/tooling/test-guardrails.mjs +0 -157
- package/tooling/validate-boundary.mjs +0 -92
- package/tooling/validate-effects.mjs +0 -304
- package/tooling/validate.mjs +0 -53
package/dist/index.js
CHANGED
|
@@ -111,20 +111,24 @@ class EffectPackageService {
|
|
|
111
111
|
const params = this.getMergedParams(effectId, explicitParams);
|
|
112
112
|
if (!params) return null;
|
|
113
113
|
const spawn = this.resolveSpawnTransform(effectPackage, params, spawnTransform);
|
|
114
|
+
warnMissingRequiredInputs(effectId, effectPackage.requiredInputs, spawn.inputs);
|
|
114
115
|
const runtimeParams = stripSpawnParams(params, effectPackage.spawnParams);
|
|
115
116
|
const root = new TransformNode(`vfx_package_${effectId}`, this.scene);
|
|
116
|
-
root
|
|
117
|
-
|
|
117
|
+
applySpawnToRoot(root, spawn);
|
|
118
|
+
const worldPosition = root.getAbsolutePosition().clone();
|
|
118
119
|
let handle;
|
|
119
120
|
try {
|
|
120
121
|
handle = effectPackage.create({
|
|
121
122
|
scene: this.scene,
|
|
122
123
|
root,
|
|
123
|
-
position:
|
|
124
|
+
position: worldPosition,
|
|
124
125
|
rotationY: spawn.rotationY,
|
|
125
126
|
renderingGroupId: spawn.renderingGroupId,
|
|
126
|
-
params: runtimeParams
|
|
127
|
+
params: runtimeParams,
|
|
128
|
+
scale: spawn.scale,
|
|
129
|
+
inputs: spawn.inputs
|
|
127
130
|
});
|
|
131
|
+
applySpawnToRoot(root, spawn);
|
|
128
132
|
} catch (error) {
|
|
129
133
|
console.warn(`[EffectPackageService] effect "${effectId}" create() failed; skipped.`, error);
|
|
130
134
|
try {
|
|
@@ -139,6 +143,9 @@ class EffectPackageService {
|
|
|
139
143
|
this.activeHandles.delete(handle);
|
|
140
144
|
originalDispose();
|
|
141
145
|
};
|
|
146
|
+
handle.root.onDisposeObservable.addOnce(() => {
|
|
147
|
+
this.activeHandles.delete(handle);
|
|
148
|
+
});
|
|
142
149
|
return handle;
|
|
143
150
|
}
|
|
144
151
|
dispose() {
|
|
@@ -157,26 +164,87 @@ class EffectPackageService {
|
|
|
157
164
|
}
|
|
158
165
|
resolveSpawnTransform(effectPackage, params, spawnTransform) {
|
|
159
166
|
const normalized = normalizeSpawnTransform(spawnTransform);
|
|
160
|
-
const
|
|
161
|
-
const
|
|
167
|
+
const parent = normalized.parent ?? null;
|
|
168
|
+
const basePosition = normalized.position?.clone() ?? (parent != null ? new Vector3(0, 0, 0) : this.resolveDebugPosition(effectPackage));
|
|
169
|
+
const rotation = resolveRotation(normalized.rotation, normalized.rotationY);
|
|
170
|
+
const scale = resolveScale(normalized.scale);
|
|
171
|
+
const offsetIsLocal = normalized.offsetIsLocal ?? parent != null;
|
|
162
172
|
const renderingGroupId = readOptionalFiniteNumber(normalized.renderingGroupId);
|
|
163
173
|
const offset = readSpawnOffset(params, effectPackage.spawnParams);
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
return {
|
|
170
|
-
position: basePosition.addInPlace(new Vector3(
|
|
174
|
+
let position = basePosition;
|
|
175
|
+
if (offset.lengthSquared() > 1e-7) {
|
|
176
|
+
const cos = Math.cos(rotation.y);
|
|
177
|
+
const sin = Math.sin(rotation.y);
|
|
178
|
+
position = basePosition.addInPlace(new Vector3(
|
|
171
179
|
offset.x * cos - offset.z * sin,
|
|
172
180
|
offset.y,
|
|
173
181
|
offset.x * sin + offset.z * cos
|
|
174
|
-
))
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
182
|
+
));
|
|
183
|
+
}
|
|
184
|
+
return { position, rotation, rotationY: rotation.y, scale, parent, offsetIsLocal, renderingGroupId, inputs: normalizeInputs(normalized.inputs) };
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
function normalizeInputs(inputs) {
|
|
188
|
+
if (!inputs) return void 0;
|
|
189
|
+
const asFn = (v) => v == null ? void 0 : typeof v === "function" ? v : () => v;
|
|
190
|
+
const out = {};
|
|
191
|
+
if (inputs.aim != null) out.aim = asFn(inputs.aim);
|
|
192
|
+
if (inputs.normal != null) out.normal = asFn(inputs.normal);
|
|
193
|
+
if (inputs.endpoints) out.endpoints = inputs.endpoints.map((e) => asFn(e)).filter(Boolean);
|
|
194
|
+
if (inputs.target) out.target = inputs.target;
|
|
195
|
+
if (inputs.scalars) {
|
|
196
|
+
out.scalars = {};
|
|
197
|
+
for (const [k, v] of Object.entries(inputs.scalars)) {
|
|
198
|
+
const fn = asFn(v);
|
|
199
|
+
if (fn) out.scalars[k] = fn;
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
return out;
|
|
203
|
+
}
|
|
204
|
+
function warnMissingRequiredInputs(effectId, required, inputs) {
|
|
205
|
+
if (!required || required.length === 0) return;
|
|
206
|
+
const missing = required.filter((k) => {
|
|
207
|
+
const v = inputs ? inputs[k] : void 0;
|
|
208
|
+
return v == null || k === "endpoints" && Array.isArray(v) && v.length < 2;
|
|
209
|
+
});
|
|
210
|
+
if (missing.length > 0) {
|
|
211
|
+
console.warn(`[EffectPackageService] effect "${effectId}" 声明 requiredInputs [${missing.join(", ")}] 但未提供 → 可能静默降级。`);
|
|
178
212
|
}
|
|
179
213
|
}
|
|
214
|
+
function applySpawnToRoot(root, spawn) {
|
|
215
|
+
if (spawn.parent) root.parent = spawn.parent;
|
|
216
|
+
root.rotation.copyFrom(spawn.rotation);
|
|
217
|
+
root.scaling.copyFrom(spawn.scale);
|
|
218
|
+
if (spawn.parent && !spawn.offsetIsLocal) {
|
|
219
|
+
root.computeWorldMatrix(true);
|
|
220
|
+
root.setAbsolutePosition(spawn.position);
|
|
221
|
+
} else {
|
|
222
|
+
root.position.copyFrom(spawn.position);
|
|
223
|
+
}
|
|
224
|
+
root.computeWorldMatrix(true);
|
|
225
|
+
}
|
|
226
|
+
function resolveRotation(rotation, rotationY) {
|
|
227
|
+
if (rotation) {
|
|
228
|
+
return new Vector3(
|
|
229
|
+
readFiniteNumber(rotation.x, 0),
|
|
230
|
+
readFiniteNumber(rotation.y, 0),
|
|
231
|
+
readFiniteNumber(rotation.z, 0)
|
|
232
|
+
);
|
|
233
|
+
}
|
|
234
|
+
return new Vector3(0, readFiniteNumber(rotationY, 0), 0);
|
|
235
|
+
}
|
|
236
|
+
function resolveScale(scale) {
|
|
237
|
+
if (scale == null) return new Vector3(1, 1, 1);
|
|
238
|
+
if (typeof scale === "number") {
|
|
239
|
+
const s2 = readFiniteNumber(scale, 1);
|
|
240
|
+
return new Vector3(s2, s2, s2);
|
|
241
|
+
}
|
|
242
|
+
return new Vector3(
|
|
243
|
+
readFiniteNumber(scale.x, 1),
|
|
244
|
+
readFiniteNumber(scale.y, 1),
|
|
245
|
+
readFiniteNumber(scale.z, 1)
|
|
246
|
+
);
|
|
247
|
+
}
|
|
180
248
|
function normalizeSpawnTransform(spawnTransform) {
|
|
181
249
|
if (!spawnTransform) return {};
|
|
182
250
|
if (spawnTransform instanceof Vector3) return { position: spawnTransform };
|
package/dist/types.d.ts
CHANGED
|
@@ -1,7 +1,27 @@
|
|
|
1
1
|
import { Scene } from '@babylonjs/core/scene';
|
|
2
2
|
import { Vector3 } from '@babylonjs/core/Maths/math.vector';
|
|
3
3
|
import { TransformNode } from '@babylonjs/core/Meshes/transformNode';
|
|
4
|
+
import { AbstractMesh } from '@babylonjs/core/Meshes/abstractMesh';
|
|
4
5
|
export type VfxDebugAnchor = 'playerRight' | 'player';
|
|
6
|
+
export type VfxInput<T> = T | (() => T);
|
|
7
|
+
export type VfxInputKey = 'aim' | 'normal' | 'endpoints' | 'target';
|
|
8
|
+
/** 调用方提供的 inputs(放在 VfxSpawnTransform.inputs)。 */
|
|
9
|
+
export interface VfxEffectInputs {
|
|
10
|
+
aim?: VfxInput<Vector3>;
|
|
11
|
+
normal?: VfxInput<Vector3>;
|
|
12
|
+
endpoints?: Array<VfxInput<Vector3>>;
|
|
13
|
+
target?: AbstractMesh;
|
|
14
|
+
/** 运行时标量(throttle/intensity 等),值可静态或 provider;特效每帧读取做活改(G5)。 */
|
|
15
|
+
scalars?: Record<string, VfxInput<number>>;
|
|
16
|
+
}
|
|
17
|
+
/** create() 收到的、已归一化为访问器的 inputs(provider 与静态值都变成可调用的函数)。 */
|
|
18
|
+
export interface VfxResolvedInputs {
|
|
19
|
+
aim?: () => Vector3;
|
|
20
|
+
normal?: () => Vector3;
|
|
21
|
+
endpoints?: Array<() => Vector3>;
|
|
22
|
+
target?: AbstractMesh;
|
|
23
|
+
scalars?: Record<string, () => number>;
|
|
24
|
+
}
|
|
5
25
|
export type VfxParamValue = number | string | VfxColorValue;
|
|
6
26
|
export type VfxParamValues = Record<string, VfxParamValue>;
|
|
7
27
|
export interface VfxColorValue {
|
|
@@ -41,11 +61,21 @@ export interface VfxEffectPackageContext<PParams extends VfxParamValues = VfxPar
|
|
|
41
61
|
rotationY: number;
|
|
42
62
|
renderingGroupId?: number;
|
|
43
63
|
params: PParams;
|
|
64
|
+
/**
|
|
65
|
+
* 解析后的三轴缩放(来自 spawnTransform.scale,默认 (1,1,1))。
|
|
66
|
+
* root 的缩放由 service 写好;但**几何不挂 root 的 world/detached 特效**(粒子/抛物池/世界坐标 emitter)
|
|
67
|
+
* root.scaling 作用不到,须自行把 ctx.scale 乘进几何尺寸/初速(G3)。
|
|
68
|
+
*/
|
|
69
|
+
scale: Vector3;
|
|
70
|
+
/** 运行时外部信息(已归一化为访问器)。link/target/定向武器/活改标量等按 required/optionalInputs 读取。 */
|
|
71
|
+
inputs?: VfxResolvedInputs;
|
|
44
72
|
}
|
|
45
73
|
export interface VfxEffectHandle {
|
|
46
74
|
root: TransformNode;
|
|
47
75
|
ready?: Promise<void>;
|
|
48
76
|
dispose(): void;
|
|
77
|
+
/** 可选:运行时活改 params(无须 dispose+replay,避免重置缓动/可见闪)。声明即纳入契约(G5)。 */
|
|
78
|
+
update?(params: Partial<VfxParamValues>): void;
|
|
49
79
|
}
|
|
50
80
|
export interface VfxEffectManifest {
|
|
51
81
|
id: string;
|
|
@@ -58,10 +88,34 @@ export interface VfxSpawnParamKeys {
|
|
|
58
88
|
offsetY?: string;
|
|
59
89
|
offsetZ?: string;
|
|
60
90
|
}
|
|
91
|
+
/** 欧拉角(弧度)/ 三轴缩放的纯数据三元组。 */
|
|
92
|
+
export interface VfxVector3Like {
|
|
93
|
+
x: number;
|
|
94
|
+
y: number;
|
|
95
|
+
z: number;
|
|
96
|
+
}
|
|
61
97
|
export interface VfxSpawnTransform {
|
|
62
98
|
position?: Vector3;
|
|
99
|
+
/**
|
|
100
|
+
* 兼容别名:绕 Y 轴旋转(弧度)。
|
|
101
|
+
* 若同时给了 `rotation`,以 `rotation` 为准;否则回退到 `rotationY`。
|
|
102
|
+
*/
|
|
63
103
|
rotationY?: number;
|
|
104
|
+
/** 完整欧拉角旋转(弧度);给了就覆盖 `rotationY`。 */
|
|
105
|
+
rotation?: VfxVector3Like;
|
|
106
|
+
/** 等比缩放(number)或三轴缩放;默认 1。 */
|
|
107
|
+
scale?: number | VfxVector3Like;
|
|
108
|
+
/** 挂载点节点;给了就把特效 root parent 到它(特效随之跟随)。 */
|
|
109
|
+
parent?: TransformNode;
|
|
110
|
+
/**
|
|
111
|
+
* position/rotation/scale 的坐标系解释:
|
|
112
|
+
* - 给了 `parent` 时默认 `true`:按相对 parent 的 **local** transform 解释;
|
|
113
|
+
* - 没给 `parent` 时默认 `false`:按 **世界坐标** 解释(保持现状行为)。
|
|
114
|
+
*/
|
|
115
|
+
offsetIsLocal?: boolean;
|
|
64
116
|
renderingGroupId?: number;
|
|
117
|
+
/** 运行时外部信息(瞄准点/法线/端点/目标 mesh);值可为静态或 provider(动态每帧取)。 */
|
|
118
|
+
inputs?: VfxEffectInputs;
|
|
65
119
|
}
|
|
66
120
|
export interface VfxParamsFile {
|
|
67
121
|
schemaVersion: string;
|
|
@@ -69,6 +123,15 @@ export interface VfxParamsFile {
|
|
|
69
123
|
updatedAt?: string | null;
|
|
70
124
|
params?: Partial<VfxParamValues>;
|
|
71
125
|
}
|
|
126
|
+
/**
|
|
127
|
+
* 特效的放置本质(内禀标记)。决定系统/binding/面板怎么放它,不靠猜。见 docs/vfx-placement-design.md。
|
|
128
|
+
* - 'socket' local:挂对象命名挂点、随它走(parent + follow)。
|
|
129
|
+
* - 'world' global:放世界某点、不跟随(fire-and-forget,可按法线定向)。
|
|
130
|
+
* - 'screen' global:屏幕/相机层(后处理/相机扰动/DOM 全屏),无 3D transform。
|
|
131
|
+
* - 'target' 改目标自身材质/渲染态,没有可 spawn 的 root。
|
|
132
|
+
* - 'link' 连 ≥2 个端点(每帧重建几何),单 parent 表达不了。
|
|
133
|
+
*/
|
|
134
|
+
export type VfxPlacement = 'socket' | 'world' | 'screen' | 'target' | 'link';
|
|
72
135
|
export interface VfxEffectPackage<PParams extends VfxParamValues = VfxParamValues> {
|
|
73
136
|
id: string;
|
|
74
137
|
nameZh: string;
|
|
@@ -78,6 +141,23 @@ export interface VfxEffectPackage<PParams extends VfxParamValues = VfxParamValue
|
|
|
78
141
|
spawnParams?: VfxSpawnParamKeys;
|
|
79
142
|
savedParams?: Partial<VfxParamValues>;
|
|
80
143
|
debugParams: VfxParamDefinition[];
|
|
144
|
+
/** 放置本质标记(默认 'world')。 */
|
|
145
|
+
placement?: VfxPlacement;
|
|
146
|
+
/** 声明**必需**的运行时 inputs(link 必须给 endpoints/aim、target 类必须给 target mesh);service 缺失时 warn。 */
|
|
147
|
+
requiredInputs?: VfxInputKey[];
|
|
148
|
+
/** 声明**可选**的运行时 inputs(给了就用、不给走默认,如定向武器的 aim:给了朝目标、不给走挂点朝向);不触发缺失 warn(G2)。 */
|
|
149
|
+
optionalInputs?: VfxInputKey[];
|
|
150
|
+
/**
|
|
151
|
+
* 几何空间:'local'=几何挂 root 子节点随它刚性变换;'world'=几何用世界坐标、root 仅作每帧采样源(拖尾)。
|
|
152
|
+
* 默认随 placement 推断('socket'→local,其余→world)。
|
|
153
|
+
*/
|
|
154
|
+
geometrySpace?: 'local' | 'world';
|
|
155
|
+
/**
|
|
156
|
+
* 构建特效。**约定(G6):root 的 transform(position/rotation/scaling/parent)归 service 独占** ——
|
|
157
|
+
* service 在 create() 后会二次 `applySpawnToRoot` 覆盖,create 内写 `root.position/rotation/scaling` 会被静默清掉。
|
|
158
|
+
* 需要内部局部偏移(如抬升)请用 root 下的**子 TransformNode** 承载,或声明 `spawnParams.offsetY` 走 service 存活通道。
|
|
159
|
+
* 几何挂 root 子树即随挂载跟随;world/拖尾类几何走世界坐标、读 ctx.scale 缩放。
|
|
160
|
+
*/
|
|
81
161
|
create(context: VfxEffectPackageContext<PParams>): VfxEffectHandle;
|
|
82
162
|
}
|
|
83
163
|
export type VfxDebugOverrides = Record<string, Partial<VfxParamValues>>;
|
package/index.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"schemaVersion": "vfx-index/1.0",
|
|
3
|
-
"count":
|
|
3
|
+
"count": 37,
|
|
4
4
|
"effects": [
|
|
5
5
|
{
|
|
6
6
|
"id": "build.particle.lumber_debris_scatter",
|
|
@@ -267,6 +267,24 @@
|
|
|
267
267
|
"media": {},
|
|
268
268
|
"path": "packages/effects/thruster-flame"
|
|
269
269
|
},
|
|
270
|
+
{
|
|
271
|
+
"id": "treasure-attention",
|
|
272
|
+
"dir": "treasure-attention",
|
|
273
|
+
"nameZh": "宝藏注意力光效",
|
|
274
|
+
"kind": "code",
|
|
275
|
+
"category": "treasure-attention",
|
|
276
|
+
"tags": [
|
|
277
|
+
"treasure",
|
|
278
|
+
"attention",
|
|
279
|
+
"pickup",
|
|
280
|
+
"gold",
|
|
281
|
+
"sparkle",
|
|
282
|
+
"aura",
|
|
283
|
+
"ring"
|
|
284
|
+
],
|
|
285
|
+
"media": {},
|
|
286
|
+
"path": "packages/effects/treasure-attention"
|
|
287
|
+
},
|
|
270
288
|
{
|
|
271
289
|
"id": "tree_chop_dust_burst",
|
|
272
290
|
"dir": "tree_chop_dust_burst",
|
package/package.json
CHANGED
|
@@ -1,8 +1,11 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@fps-games/vfx",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.3",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Shared VFX library for Playable projects: engine-injected effect packages + runtime. Project-pure (no imports of host project code).",
|
|
6
|
+
"publishConfig": {
|
|
7
|
+
"access": "public"
|
|
8
|
+
},
|
|
6
9
|
"types": "./dist/index.d.ts",
|
|
7
10
|
"module": "./dist/index.js",
|
|
8
11
|
"exports": {
|
|
@@ -18,9 +21,10 @@
|
|
|
18
21
|
},
|
|
19
22
|
"files": [
|
|
20
23
|
"dist",
|
|
21
|
-
"tooling",
|
|
22
|
-
"
|
|
23
|
-
"
|
|
24
|
+
"tooling/vfx-cli.mjs",
|
|
25
|
+
"tooling/vfx-package-resolution.mjs",
|
|
26
|
+
"packages/effects/*/vfx-params.json",
|
|
27
|
+
"README.md",
|
|
24
28
|
"CHANGELOG.md",
|
|
25
29
|
"index.json"
|
|
26
30
|
],
|
|
@@ -38,6 +42,7 @@
|
|
|
38
42
|
"test:guardrails": "node tooling/test-guardrails.mjs",
|
|
39
43
|
"generate:index": "node tooling/generate-index.mjs",
|
|
40
44
|
"demo:energy-shield": "vite demo/energy-shield --host 127.0.0.1",
|
|
45
|
+
"demo:treasure-attention": "vite demo/treasure-attention --host 127.0.0.1",
|
|
41
46
|
"release": "node scripts/release.mjs"
|
|
42
47
|
},
|
|
43
48
|
"//": "分发=git tag + 提交 dist(做法A):发版前 pnpm build → 提交 dist/ → git tag。消费端 import '@fps/vfx' 解析到 dist;本地开发可用 FPS_VFX_LIBRARY_REPO 切回源码 alias。",
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
{
|
|
2
|
+
"schemaVersion": "vfx-params/1.0",
|
|
3
|
+
"effectId": "treasure-attention",
|
|
4
|
+
"params": {
|
|
5
|
+
"radius": 1.15,
|
|
6
|
+
"yOffset": 0.05,
|
|
7
|
+
"height": 1.35,
|
|
8
|
+
"rays": 9,
|
|
9
|
+
"rayWidth": 0.34,
|
|
10
|
+
"spinSpeed": 0.85,
|
|
11
|
+
"color": {
|
|
12
|
+
"r": 1,
|
|
13
|
+
"g": 0.9,
|
|
14
|
+
"b": 0.22
|
|
15
|
+
},
|
|
16
|
+
"auraColor": {
|
|
17
|
+
"r": 1,
|
|
18
|
+
"g": 0.82,
|
|
19
|
+
"b": 0.18
|
|
20
|
+
},
|
|
21
|
+
"ringColor": {
|
|
22
|
+
"r": 1,
|
|
23
|
+
"g": 0.95,
|
|
24
|
+
"b": 0.38
|
|
25
|
+
},
|
|
26
|
+
"rayColor": {
|
|
27
|
+
"r": 1,
|
|
28
|
+
"g": 0.76,
|
|
29
|
+
"b": 0.12
|
|
30
|
+
},
|
|
31
|
+
"beamColor": {
|
|
32
|
+
"r": 1,
|
|
33
|
+
"g": 0.92,
|
|
34
|
+
"b": 0.32
|
|
35
|
+
},
|
|
36
|
+
"opacity": 1,
|
|
37
|
+
"auraOpacity": 0.82,
|
|
38
|
+
"ringOpacity": 0.95,
|
|
39
|
+
"beamOpacity": 0.68,
|
|
40
|
+
"particleRate": 42,
|
|
41
|
+
"particleLife": 0.82,
|
|
42
|
+
"sparkleMinSize": 0.045,
|
|
43
|
+
"sparkleMaxSize": 0.13,
|
|
44
|
+
"riseSpeed": 0.72,
|
|
45
|
+
"drift": 0.12,
|
|
46
|
+
"bloomIntensity": 0.55,
|
|
47
|
+
"bloomKernelSize": 32
|
|
48
|
+
}
|
|
49
|
+
}
|
package/tooling/vfx-cli.mjs
CHANGED
|
@@ -17,6 +17,9 @@ import { fileURLToPath } from 'node:url';
|
|
|
17
17
|
const LIB_ROOT = resolve(dirname(fileURLToPath(import.meta.url)), '..');
|
|
18
18
|
const LIB_EFFECTS = join(LIB_ROOT, 'packages', 'effects');
|
|
19
19
|
const LIB_VERSION = (() => { try { return JSON.parse(readFileSync(join(LIB_ROOT, 'package.json'), 'utf8')).version; } catch { return '0.0.0'; } })();
|
|
20
|
+
const LIB_INDEX = (() => {
|
|
21
|
+
try { return JSON.parse(readFileSync(join(LIB_ROOT, 'index.json'), 'utf8')); } catch { return null; }
|
|
22
|
+
})();
|
|
20
23
|
|
|
21
24
|
const [, , cmd, ...rest] = process.argv;
|
|
22
25
|
const VALUED_FLAGS = new Set(['--project', '--to']); // 这些 flag 后跟一个值,值不算 positional
|
|
@@ -33,10 +36,14 @@ const force = flags.has('--force');
|
|
|
33
36
|
|
|
34
37
|
// ── 通用 ──────────────────────────────────────────────────────────────────────
|
|
35
38
|
function libEffectIds() {
|
|
39
|
+
if (Array.isArray(LIB_INDEX?.effects)) return LIB_INDEX.effects.map((e) => e.id).filter(Boolean);
|
|
36
40
|
return readdirSync(LIB_EFFECTS).filter((e) => {
|
|
37
41
|
try { return statSync(join(LIB_EFFECTS, e)).isDirectory() && existsSync(join(LIB_EFFECTS, e, 'index.ts')); } catch { return false; }
|
|
38
42
|
});
|
|
39
43
|
}
|
|
44
|
+
function hasLibEffect(id) {
|
|
45
|
+
return libEffectIds().includes(id) || existsSync(join(LIB_EFFECTS, id, 'vfx-params.json'));
|
|
46
|
+
}
|
|
40
47
|
function stub(id) {
|
|
41
48
|
return `// @fps/vfx re-export 桩(代码/资源在包内;本地仅 vfx-params.json + 此桩)。\nexport * from '@fps/vfx/effects/${id}';\n`;
|
|
42
49
|
}
|
|
@@ -111,7 +118,7 @@ function changelogRange(fromVersion, toVersion) {
|
|
|
111
118
|
|
|
112
119
|
// ── add ───────────────────────────────────────────────────────────────────────
|
|
113
120
|
function add(id) {
|
|
114
|
-
if (!
|
|
121
|
+
if (!hasLibEffect(id)) { console.error(`✗ 库中无特效 "${id}"。可用:run "list"。`); process.exit(1); }
|
|
115
122
|
const destDir = join(effectsDestDir(), id);
|
|
116
123
|
const stubPath = join(destDir, 'index.ts');
|
|
117
124
|
const paramsPath = join(destDir, 'vfx-params.json');
|