@fps-games/vfx 0.1.1
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 +34 -0
- package/dist/EffectPackageService.d.ts +26 -0
- package/dist/SceneVfxService.d.ts +27 -0
- package/dist/chunks/legacy-particle-runtime-CbJYVxdd.js +75 -0
- package/dist/chunks/manifestRuntimePackage-CXQFSTo2.js +356 -0
- package/dist/chunks/rendering-CV3nhygX.js +13 -0
- package/dist/chunks/space-shared-BXV1hc0k.js +124 -0
- package/dist/chunks/wood-sawdust-effect-factory-DlETNaBn.js +129 -0
- package/dist/effects/building-upgrade/effect.json.d.ts +9 -0
- package/dist/effects/building-upgrade/index.d.ts +20 -0
- package/dist/effects/building-upgrade/index.js +337 -0
- package/dist/effects/character-entrance/effect.json.d.ts +9 -0
- package/dist/effects/character-entrance/index.d.ts +18 -0
- package/dist/effects/character-entrance/index.js +271 -0
- package/dist/effects/coin-burst/index.d.ts +6 -0
- package/dist/effects/coin-burst/index.js +45 -0
- package/dist/effects/comet-trail-flame/index.d.ts +11 -0
- package/dist/effects/comet-trail-flame/index.js +103 -0
- package/dist/effects/conveyor-upgrade/effect.json.d.ts +9 -0
- package/dist/effects/conveyor-upgrade/index.d.ts +20 -0
- package/dist/effects/conveyor-upgrade/index.js +349 -0
- package/dist/effects/debris-smoke/index.d.ts +10 -0
- package/dist/effects/debris-smoke/index.js +108 -0
- package/dist/effects/door_open_gold_flakes/door_open_gold_flakes.json.d.ts +501 -0
- package/dist/effects/door_open_gold_flakes/index.d.ts +1 -0
- package/dist/effects/door_open_gold_flakes/index.js +524 -0
- package/dist/effects/electric-arc/index.d.ts +8 -0
- package/dist/effects/electric-arc/index.js +71 -0
- package/dist/effects/energy-shield/index.d.ts +46 -0
- package/dist/effects/energy-shield/index.js +365 -0
- package/dist/effects/explosion/index.d.ts +11 -0
- package/dist/effects/explosion/index.js +129 -0
- package/dist/effects/ground-tile-upgrade/effect.json.d.ts +9 -0
- package/dist/effects/ground-tile-upgrade/index.d.ts +20 -0
- package/dist/effects/ground-tile-upgrade/index.js +357 -0
- package/dist/effects/hit-flash/index.d.ts +8 -0
- package/dist/effects/hit-flash/index.js +71 -0
- package/dist/effects/laser-beam/index.d.ts +1 -0
- package/dist/effects/laser-beam/index.js +152 -0
- package/dist/effects/laser-beam-factory.d.ts +12 -0
- package/dist/effects/lumber-cart-suction/effect.json.d.ts +9 -0
- package/dist/effects/lumber-cart-suction/index.d.ts +26 -0
- package/dist/effects/lumber-cart-suction/index.js +322 -0
- package/dist/effects/lumber-debris-scatter/effect.json.d.ts +231 -0
- package/dist/effects/lumber-debris-scatter/index.d.ts +20 -0
- package/dist/effects/lumber-debris-scatter/index.js +637 -0
- package/dist/effects/lumber_vehicle_gear_spin/index.d.ts +1 -0
- package/dist/effects/lumber_vehicle_gear_spin/index.js +363 -0
- package/dist/effects/lumber_vehicle_gear_spin/lumber_vehicle_gear_spin.json.d.ts +341 -0
- package/dist/effects/lumber_vehicle_upgrade_aura/index.d.ts +1 -0
- package/dist/effects/lumber_vehicle_upgrade_aura/index.js +391 -0
- package/dist/effects/lumber_vehicle_upgrade_aura/lumber_vehicle_upgrade_aura.json.d.ts +368 -0
- package/dist/effects/lumber_vehicle_wood_chips/index.d.ts +1 -0
- package/dist/effects/lumber_vehicle_wood_chips/index.js +360 -0
- package/dist/effects/lumber_vehicle_wood_chips/lumber_vehicle_wood_chips.json.d.ts +338 -0
- package/dist/effects/monster-hit/index.d.ts +15 -0
- package/dist/effects/monster-hit/index.js +156 -0
- package/dist/effects/player-upgrade/effect.json.d.ts +9 -0
- package/dist/effects/player-upgrade/index.d.ts +24 -0
- package/dist/effects/player-upgrade/index.js +539 -0
- package/dist/effects/pulse-laser-volley/index.d.ts +17 -0
- package/dist/effects/pulse-laser-volley/index.js +173 -0
- package/dist/effects/resource-collect-sparkles/effect.json.d.ts +9 -0
- package/dist/effects/resource-collect-sparkles/index.d.ts +21 -0
- package/dist/effects/resource-collect-sparkles/index.js +222 -0
- package/dist/effects/run-footstep-dust/effect.json.d.ts +186 -0
- package/dist/effects/run-footstep-dust/index.d.ts +23 -0
- package/dist/effects/run-footstep-dust/index.js +343 -0
- package/dist/effects/space-shared.d.ts +44 -0
- package/dist/effects/thruster-flame/index.d.ts +15 -0
- package/dist/effects/thruster-flame/index.js +301 -0
- package/dist/effects/tree-chop-dust/effect.json.d.ts +11 -0
- package/dist/effects/tree-chop-dust/index.d.ts +17 -0
- package/dist/effects/tree-chop-dust/index.js +165 -0
- package/dist/effects/tree-leaf-chop-burst/index.d.ts +19 -0
- package/dist/effects/tree-leaf-chop-burst/index.js +219 -0
- package/dist/effects/tree_chop_dust_burst/index.d.ts +1 -0
- package/dist/effects/tree_chop_dust_burst/index.js +443 -0
- package/dist/effects/tree_chop_dust_burst/tree_chop_dust_burst.json.d.ts +415 -0
- package/dist/effects/ufo-thread-flame/index.d.ts +21 -0
- package/dist/effects/ufo-thread-flame/index.js +140 -0
- package/dist/effects/vehicle-exhaust-smoke/effect.json.d.ts +11 -0
- package/dist/effects/vehicle-exhaust-smoke/index.d.ts +19 -0
- package/dist/effects/vehicle-exhaust-smoke/index.js +242 -0
- package/dist/effects/vehicle-upgrade/effect.json.d.ts +9 -0
- package/dist/effects/vehicle-upgrade/index.d.ts +20 -0
- package/dist/effects/vehicle-upgrade/index.js +349 -0
- package/dist/effects/weapon-trail/index.d.ts +26 -0
- package/dist/effects/weapon-trail/index.js +351 -0
- package/dist/effects/wood-crusher-sawdust/index.d.ts +2 -0
- package/dist/effects/wood-crusher-sawdust/index.js +648 -0
- package/dist/effects/wood-crusher-sawdust/wood_crusher_sawdust.json.d.ts +595 -0
- package/dist/effects/wood-cutter-sawdust/index.d.ts +2 -0
- package/dist/effects/wood-cutter-sawdust/index.js +648 -0
- package/dist/effects/wood-cutter-sawdust/wood_cutter_sawdust.json.d.ts +595 -0
- package/dist/effects/wood-sawdust-effect-factory.d.ts +36 -0
- package/dist/effects/wood_crusher_sawdust/index.d.ts +16 -0
- package/dist/effects/wood_crusher_sawdust/index.js +634 -0
- package/dist/effects/wood_crusher_sawdust/wood_crusher_sawdust.json.d.ts +595 -0
- package/dist/effects/wood_cutter_sawdust/index.d.ts +16 -0
- package/dist/effects/wood_cutter_sawdust/index.js +634 -0
- package/dist/effects/wood_cutter_sawdust/wood_cutter_sawdust.json.d.ts +595 -0
- package/dist/effects/wood_peel_material_test/index.d.ts +1 -0
- package/dist/effects/wood_peel_material_test/index.js +157 -0
- package/dist/effects/wood_peel_material_test/wood_peel_material_test.json.d.ts +139 -0
- package/dist/generation.d.ts +7 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.js +309 -0
- package/dist/legacy-particle-runtime.d.ts +30 -0
- package/dist/manifestRuntimePackage.d.ts +68 -0
- package/dist/registry.d.ts +20 -0
- package/dist/rendering.d.ts +5 -0
- package/dist/types.d.ts +83 -0
- package/docs/AUTHORING_EFFECTS.md +297 -0
- package/docs/VFX_LIBRARY_ARCHITECTURE_chatgpt.md +1580 -0
- package/docs/VFX_LIBRARY_EXECUTION_PLAN.md +229 -0
- package/docs/VFX_LIBRARY_PLAN.md +546 -0
- package/docs/vfx-ab/RESULTS.md +35 -0
- 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 +462 -0
- package/docs/weapon-trail-visualization.html +241 -0
- package/index.json +381 -0
- package/package.json +51 -0
- package/packages/EffectPackageService.ts +240 -0
- package/packages/SceneVfxService.ts +96 -0
- package/packages/build.mesh.yellow_build_upgrade_indicator/assets/runtime/simpleMeshEffect.v1.js +333 -0
- package/packages/build.mesh.yellow_build_upgrade_indicator/assets/shaders/mesh-effect-preview.frag.glsl +25 -0
- package/packages/build.mesh.yellow_build_upgrade_indicator/assets/shaders/mesh-effect-preview.vert.glsl +11 -0
- 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 +927 -0
- 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 +197 -0
- package/packages/build.mesh.yellow_build_upgrade_indicator/provenance/03-effect.original.json +895 -0
- package/packages/build.mesh.yellow_build_upgrade_indicator/provenance/03-normalized-vfx-to-babylon-report.json +241 -0
- package/packages/build.mesh.yellow_build_upgrade_indicator/provenance/04-preview-overrides.json +542 -0
- package/packages/build.mesh.yellow_build_upgrade_indicator/provenance/04-preview-tuning-report.json +69 -0
- package/packages/build.mesh.yellow_build_upgrade_indicator/provenance/asset-map.json +125 -0
- package/packages/build.mesh.yellow_build_upgrade_indicator/provenance/lineage.json +44 -0
- package/packages/build.particle.golden_upgrade_starburst/assets/runtime/particleEmitter.v1.js +210 -0
- package/packages/build.particle.golden_upgrade_starburst/assets/textures/effect_guangdian.png +0 -0
- package/packages/build.particle.golden_upgrade_starburst/effect.json +880 -0
- 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 +161 -0
- package/packages/build.particle.golden_upgrade_starburst/provenance/03-effect.original.json +762 -0
- package/packages/build.particle.golden_upgrade_starburst/provenance/03-normalized-vfx-to-babylon-report.json +260 -0
- package/packages/build.particle.golden_upgrade_starburst/provenance/04-preview-overrides.json +436 -0
- package/packages/build.particle.golden_upgrade_starburst/provenance/04-preview-tuning-report.json +40 -0
- package/packages/build.particle.golden_upgrade_starburst/provenance/asset-map.json +115 -0
- package/packages/build.particle.golden_upgrade_starburst/provenance/lineage.json +40 -0
- package/packages/build.particle.orange_upgrade_transform_sparks/assets/runtime/particleEmitter.v1.js +210 -0
- 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 +887 -0
- 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 +179 -0
- package/packages/build.particle.orange_upgrade_transform_sparks/provenance/03-effect.original.json +859 -0
- package/packages/build.particle.orange_upgrade_transform_sparks/provenance/03-normalized-vfx-to-babylon-report.json +260 -0
- package/packages/build.particle.orange_upgrade_transform_sparks/provenance/04-preview-overrides.json +478 -0
- package/packages/build.particle.orange_upgrade_transform_sparks/provenance/04-preview-tuning-report.json +40 -0
- package/packages/build.particle.orange_upgrade_transform_sparks/provenance/asset-map.json +114 -0
- package/packages/build.particle.orange_upgrade_transform_sparks/provenance/lineage.json +41 -0
- package/packages/build.particle.wood_chip_dust_burst/assets/runtime/particleEmitter.v1.js +210 -0
- 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 +1400 -0
- 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 +173 -0
- package/packages/build.particle.wood_chip_dust_burst/provenance/03-effect.original.json +1277 -0
- package/packages/build.particle.wood_chip_dust_burst/provenance/03-normalized-vfx-to-babylon-report.json +329 -0
- package/packages/build.particle.wood_chip_dust_burst/provenance/04-preview-overrides.json +749 -0
- package/packages/build.particle.wood_chip_dust_burst/provenance/04-preview-tuning-report.json +60 -0
- package/packages/build.particle.wood_chip_dust_burst/provenance/asset-map.json +146 -0
- package/packages/build.particle.wood_chip_dust_burst/provenance/lineage.json +69 -0
- package/packages/effects/building-upgrade/effect.json +6 -0
- package/packages/effects/building-upgrade/index.ts +387 -0
- package/packages/effects/building-upgrade/vfx-params.json +24 -0
- package/packages/effects/character-entrance/effect.json +6 -0
- package/packages/effects/character-entrance/index.ts +308 -0
- package/packages/effects/character-entrance/vfx-params.json +24 -0
- package/packages/effects/coin-burst/index.ts +43 -0
- package/packages/effects/coin-burst/vfx-params.json +5 -0
- package/packages/effects/comet-trail-flame/assets/textures/trail_5x4.webp +0 -0
- package/packages/effects/comet-trail-flame/index.ts +106 -0
- package/packages/effects/comet-trail-flame/vfx-params.json +5 -0
- package/packages/effects/conveyor-upgrade/effect.json +6 -0
- package/packages/effects/conveyor-upgrade/index.ts +401 -0
- package/packages/effects/conveyor-upgrade/vfx-params.json +21 -0
- 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 +101 -0
- package/packages/effects/debris-smoke/vfx-params.json +5 -0
- package/packages/effects/door_open_gold_flakes/assets/runtime/goldFlakes.v1.js +397 -0
- package/packages/effects/door_open_gold_flakes/door_open_gold_flakes.json +498 -0
- package/packages/effects/door_open_gold_flakes/index.ts +11 -0
- package/packages/effects/door_open_gold_flakes/vfx-params.json +23 -0
- package/packages/effects/electric-arc/assets/textures/spark_4x4.webp +0 -0
- package/packages/effects/electric-arc/index.ts +62 -0
- package/packages/effects/electric-arc/vfx-params.json +5 -0
- package/packages/effects/energy-shield/effect.json +7 -0
- package/packages/effects/energy-shield/index.ts +431 -0
- package/packages/effects/energy-shield/vfx-params.json +29 -0
- 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 +114 -0
- package/packages/effects/explosion/vfx-params.json +5 -0
- package/packages/effects/ground-tile-upgrade/effect.json +6 -0
- package/packages/effects/ground-tile-upgrade/index.ts +410 -0
- package/packages/effects/ground-tile-upgrade/vfx-params.json +21 -0
- package/packages/effects/hit-flash/index.ts +69 -0
- package/packages/effects/hit-flash/vfx-params.json +5 -0
- 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 +6 -0
- package/packages/effects/laser-beam/vfx-params.json +5 -0
- package/packages/effects/laser-beam-factory.ts +135 -0
- package/packages/effects/lumber-cart-suction/effect.json +6 -0
- package/packages/effects/lumber-cart-suction/index.ts +399 -0
- package/packages/effects/lumber-cart-suction/vfx-params.json +30 -0
- 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 +1 -0
- 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 +236 -0
- package/packages/effects/lumber-debris-scatter/effect.json +228 -0
- package/packages/effects/lumber-debris-scatter/index.ts +780 -0
- package/packages/effects/lumber-debris-scatter/vfx-params.json +19 -0
- package/packages/effects/lumber_vehicle_gear_spin/assets/runtime/gearSpin.v1.js +202 -0
- package/packages/effects/lumber_vehicle_gear_spin/index.ts +11 -0
- package/packages/effects/lumber_vehicle_gear_spin/lumber_vehicle_gear_spin.json +338 -0
- package/packages/effects/lumber_vehicle_gear_spin/vfx-params.json +21 -0
- package/packages/effects/lumber_vehicle_upgrade_aura/assets/runtime/upgradeAura.v1.js +353 -0
- package/packages/effects/lumber_vehicle_upgrade_aura/index.ts +11 -0
- package/packages/effects/lumber_vehicle_upgrade_aura/lumber_vehicle_upgrade_aura.json +365 -0
- package/packages/effects/lumber_vehicle_upgrade_aura/vfx-params.json +15 -0
- package/packages/effects/lumber_vehicle_wood_chips/assets/runtime/solidParticleScatter.v1.js +310 -0
- package/packages/effects/lumber_vehicle_wood_chips/index.ts +11 -0
- package/packages/effects/lumber_vehicle_wood_chips/lumber_vehicle_wood_chips.json +335 -0
- package/packages/effects/lumber_vehicle_wood_chips/vfx-params.json +11 -0
- package/packages/effects/monster-hit/index.ts +128 -0
- package/packages/effects/monster-hit/vfx-params.json +5 -0
- package/packages/effects/player-upgrade/effect.json +6 -0
- package/packages/effects/player-upgrade/index.ts +635 -0
- package/packages/effects/player-upgrade/vfx-params.json +28 -0
- package/packages/effects/pulse-laser-volley/assets/textures/bolt_guangshu.webp +0 -0
- package/packages/effects/pulse-laser-volley/index.ts +204 -0
- package/packages/effects/pulse-laser-volley/vfx-params.json +5 -0
- package/packages/effects/resource-collect-sparkles/effect.json +6 -0
- package/packages/effects/resource-collect-sparkles/index.ts +254 -0
- package/packages/effects/resource-collect-sparkles/vfx-params.json +25 -0
- package/packages/effects/run-footstep-dust/assets/runtime/runFootstepDust.v1.js +215 -0
- package/packages/effects/run-footstep-dust/effect.json +183 -0
- package/packages/effects/run-footstep-dust/index.ts +377 -0
- package/packages/effects/run-footstep-dust/vfx-params.json +27 -0
- package/packages/effects/space-shared.ts +120 -0
- package/packages/effects/thruster-flame/index.ts +305 -0
- package/packages/effects/thruster-flame/vfx-params.json +5 -0
- package/packages/effects/tree-chop-dust/assets/textures/tree_chop_dust_atlas.png +0 -0
- package/packages/effects/tree-chop-dust/effect.json +8 -0
- package/packages/effects/tree-chop-dust/index.ts +202 -0
- package/packages/effects/tree-chop-dust/vfx-params.json +21 -0
- package/packages/effects/tree-leaf-chop-burst/assets/runtime/particleEmitter.v1.js +303 -0
- 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 +498 -0
- package/packages/effects/tree-leaf-chop-burst/index.ts +294 -0
- package/packages/effects/tree-leaf-chop-burst/vfx-params.json +27 -0
- package/packages/effects/tree_chop_dust_burst/assets/runtime/particleEmitter.v1.js +318 -0
- 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 +13 -0
- package/packages/effects/tree_chop_dust_burst/tree_chop_dust_burst.json +412 -0
- package/packages/effects/tree_chop_dust_burst/vfx-params.json +9 -0
- 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 +152 -0
- package/packages/effects/ufo-thread-flame/vfx-params.json +5 -0
- package/packages/effects/vehicle-exhaust-smoke/assets/textures/vehicle_exhaust_smoke_atlas.png +0 -0
- package/packages/effects/vehicle-exhaust-smoke/effect.json +8 -0
- package/packages/effects/vehicle-exhaust-smoke/index.ts +298 -0
- package/packages/effects/vehicle-exhaust-smoke/vfx-params.json +23 -0
- package/packages/effects/vehicle-upgrade/effect.json +6 -0
- package/packages/effects/vehicle-upgrade/index.ts +401 -0
- package/packages/effects/vehicle-upgrade/vfx-params.json +21 -0
- package/packages/effects/weapon-trail/assets/textures/trail_wedge.png +0 -0
- package/packages/effects/weapon-trail/index.ts +313 -0
- package/packages/effects/weapon-trail/vfx-params.json +5 -0
- package/packages/effects/wood-crusher-sawdust/assets/runtime/particleEmitter.v1.js +312 -0
- 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 +43 -0
- package/packages/effects/wood-crusher-sawdust/vfx-params.json +24 -0
- package/packages/effects/wood-crusher-sawdust/wood_crusher_sawdust.json +592 -0
- package/packages/effects/wood-cutter-sawdust/assets/runtime/particleEmitter.v1.js +312 -0
- 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 +43 -0
- package/packages/effects/wood-cutter-sawdust/vfx-params.json +24 -0
- package/packages/effects/wood-cutter-sawdust/wood_cutter_sawdust.json +592 -0
- package/packages/effects/wood-sawdust-effect-factory.ts +194 -0
- package/packages/effects/wood_crusher_sawdust/assets/runtime/particleEmitter.v1.js +318 -0
- 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 +29 -0
- package/packages/effects/wood_crusher_sawdust/vfx-params.json +14 -0
- package/packages/effects/wood_crusher_sawdust/wood_crusher_sawdust.json +592 -0
- package/packages/effects/wood_cutter_sawdust/assets/runtime/particleEmitter.v1.js +318 -0
- 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 +29 -0
- package/packages/effects/wood_cutter_sawdust/vfx-params.json +14 -0
- package/packages/effects/wood_cutter_sawdust/wood_cutter_sawdust.json +592 -0
- package/packages/effects/wood_peel_material_test/assets/runtime/woodPeelMaterialTest.v1.js +196 -0
- package/packages/effects/wood_peel_material_test/index.ts +11 -0
- package/packages/effects/wood_peel_material_test/vfx-params.json +9 -0
- package/packages/effects/wood_peel_material_test/wood_peel_material_test.json +136 -0
- package/packages/env.particle.forest_edge_fog/assets/runtime/particleEmitter.v1.js +210 -0
- 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 +854 -0
- 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 +148 -0
- package/packages/env.particle.forest_edge_fog/provenance/03-effect.original.json +827 -0
- package/packages/env.particle.forest_edge_fog/provenance/03-normalized-vfx-to-babylon-report.json +196 -0
- package/packages/env.particle.forest_edge_fog/provenance/04-preview-overrides.json +432 -0
- package/packages/env.particle.forest_edge_fog/provenance/04-preview-tuning-report.json +28 -0
- package/packages/env.particle.forest_edge_fog/provenance/asset-map.json +124 -0
- package/packages/env.particle.forest_edge_fog/provenance/lineage.json +41 -0
- package/packages/generation.ts +14 -0
- package/packages/index.ts +14 -0
- package/packages/legacy-particle-runtime.ts +113 -0
- package/packages/manifestRuntimePackage.ts +519 -0
- package/packages/registry.ts +85 -0
- package/packages/rendering.ts +13 -0
- package/packages/resource.particle.viscous_oil_suction/assets/runtime/top_disk_suction/particleEmitter.v1.js +424 -0
- package/packages/resource.particle.viscous_oil_suction/assets/textures/Glow ad.png +0 -0
- package/packages/resource.particle.viscous_oil_suction/effect.json +1254 -0
- 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 +122 -0
- package/packages/resource.particle.viscous_oil_suction/provenance/03-effect.original.json +1051 -0
- package/packages/resource.particle.viscous_oil_suction/provenance/03-normalized-vfx-to-babylon-report.json +200 -0
- package/packages/resource.particle.viscous_oil_suction/provenance/04-preview-overrides.json +581 -0
- package/packages/resource.particle.viscous_oil_suction/provenance/04-preview-tuning-report.json +28 -0
- package/packages/resource.particle.viscous_oil_suction/provenance/asset-map.json +111 -0
- package/packages/resource.particle.viscous_oil_suction/provenance/lineage.json +45 -0
- package/packages/types.ts +107 -0
- package/tooling/check-dist-runtime.mjs +166 -0
- package/tooling/generate-index.mjs +55 -0
- package/tooling/test-guardrails.mjs +157 -0
- package/tooling/validate-boundary.mjs +92 -0
- package/tooling/validate-effects.mjs +304 -0
- package/tooling/validate.mjs +53 -0
- package/tooling/vfx-cli.mjs +232 -0
- package/tooling/vfx-package-resolution.mjs +28 -0
|
@@ -0,0 +1,241 @@
|
|
|
1
|
+
<!doctype html>
|
|
2
|
+
<html lang="zh">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="utf-8" />
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
6
|
+
<title>武器拖尾 weapon-trail · 贴图 / 颜色 / 形状 可视化</title>
|
|
7
|
+
<style>
|
|
8
|
+
:root { --bg:#0a0e17; --panel:#121826; --ink:#cfe1ff; --dim:#7e93b8; --line:#22304d; --accent:#6cc0ff; }
|
|
9
|
+
* { box-sizing:border-box; }
|
|
10
|
+
body { margin:0; background:var(--bg); color:var(--ink); font:14px/1.6 -apple-system,system-ui,"PingFang SC",sans-serif; }
|
|
11
|
+
h1 { font-size:18px; margin:0 0 4px; }
|
|
12
|
+
h2 { font-size:14px; color:var(--accent); margin:0 0 8px; letter-spacing:.5px; }
|
|
13
|
+
.sub { color:var(--dim); font-size:12px; margin-bottom:18px; }
|
|
14
|
+
.wrap { max-width:1080px; margin:0 auto; padding:22px 18px 60px; }
|
|
15
|
+
.grid { display:grid; grid-template-columns:1fr 1fr; gap:16px; }
|
|
16
|
+
.card { background:var(--panel); border:1px solid var(--line); border-radius:12px; padding:14px 16px; }
|
|
17
|
+
.full { grid-column:1 / -1; }
|
|
18
|
+
canvas { display:block; width:100%; border-radius:8px; background:
|
|
19
|
+
conic-gradient(#1a2233 0 25%, #141a28 0 50%, #1a2233 0 75%, #141a28 0) 0 0 / 16px 16px; }
|
|
20
|
+
.row { display:flex; align-items:center; gap:10px; margin:7px 0; }
|
|
21
|
+
.row label { flex:0 0 120px; color:var(--dim); font-size:12px; }
|
|
22
|
+
.row input[type=range] { flex:1; }
|
|
23
|
+
.row .val { flex:0 0 48px; text-align:right; color:var(--accent); font-variant-numeric:tabular-nums; }
|
|
24
|
+
.row input[type=color] { width:40px; height:24px; border:1px solid var(--line); border-radius:5px; background:#0c1322; padding:0; }
|
|
25
|
+
code { background:#0c1322; border:1px solid var(--line); border-radius:4px; padding:1px 5px; color:#9fd0ff; font-size:12px; }
|
|
26
|
+
.legend { font-size:12px; color:var(--dim); margin-top:8px; }
|
|
27
|
+
.legend b { color:var(--ink); }
|
|
28
|
+
.pipe { font-size:12.5px; line-height:1.9; }
|
|
29
|
+
.pipe .step { color:var(--ink); } .pipe .op { color:var(--accent); }
|
|
30
|
+
.tag { display:inline-block; font-size:11px; padding:1px 6px; border:1px solid var(--line); border-radius:999px; color:var(--dim); margin-left:6px; }
|
|
31
|
+
.axis { font-size:11px; color:var(--dim); }
|
|
32
|
+
</style>
|
|
33
|
+
</head>
|
|
34
|
+
<body>
|
|
35
|
+
<div class="wrap">
|
|
36
|
+
<h1>武器拖尾 <code>weapon-trail</code> — 贴图 / 颜色 / 形状</h1>
|
|
37
|
+
<div class="sub">贴图 <b>trail_wedge.png</b> 254×77 RGBA · 下面用 canvas 实时复刻片元着色器,拖滑块即时看每个参数的影响。背景棋盘格 = 透明区。</div>
|
|
38
|
+
|
|
39
|
+
<div class="grid">
|
|
40
|
+
<!-- 1. 原始贴图 -->
|
|
41
|
+
<div class="card">
|
|
42
|
+
<h2>① 原始贴图 trail_wedge.png</h2>
|
|
43
|
+
<canvas id="texCanvas" height="120"></canvas>
|
|
44
|
+
<div class="legend">
|
|
45
|
+
左 = 拖尾<b>头部</b>(u≈0),右 = <b>尾端</b>(u≈1);上下 = 拖尾<b>宽度</b>方向(v 0→1)。<br>
|
|
46
|
+
这是一个<b>楔形 + alpha 渐变</b>:RGB 蓝白,alpha 决定可见形状(头宽尾窄/边缘羽化)。
|
|
47
|
+
</div>
|
|
48
|
+
</div>
|
|
49
|
+
|
|
50
|
+
<!-- 2. alpha 通道 -->
|
|
51
|
+
<div class="card">
|
|
52
|
+
<h2>② 贴图通道拆解</h2>
|
|
53
|
+
<canvas id="chanCanvas" height="120"></canvas>
|
|
54
|
+
<div class="legend">上 = <b>RGB</b>(颜色)· 下 = <b>Alpha</b>(白=不透明,黑=透明)。拖尾的「形状」几乎全在 alpha 里。</div>
|
|
55
|
+
</div>
|
|
56
|
+
|
|
57
|
+
<!-- 3. 颜色管线 -->
|
|
58
|
+
<div class="card full">
|
|
59
|
+
<h2>③ 片元颜色管线(逐步)</h2>
|
|
60
|
+
<div class="pipe">
|
|
61
|
+
<span class="step">base = texture(uv)</span> <span class="op">→</span>
|
|
62
|
+
<span class="step">color = base.rgb × <b style="color:#6cc0ff">uTint</b></span> <span class="op">→</span>
|
|
63
|
+
<span class="step">饱和度 mix(灰, color, <b style="color:#6cc0ff">uSaturation</b>)</span> <span class="op">→</span>
|
|
64
|
+
<span class="step">对比度 (color−0.5)×<b style="color:#6cc0ff">uContrast</b>+0.5</span> <span class="op">→</span>
|
|
65
|
+
<span class="step">alpha = base.a<sup><b style="color:#6cc0ff">uAlphaPower</b></sup> × 顶点α(尾部淡出) × <b style="color:#6cc0ff">uAlphaScale</b></span>
|
|
66
|
+
<span class="tag">ALPHA_COMBINE</span>
|
|
67
|
+
</div>
|
|
68
|
+
<canvas id="stripCanvas" height="120" style="margin-top:10px"></canvas>
|
|
69
|
+
<div class="legend">↑ <b>展开的 ribbon</b>:贴图经上面整条管线 + <b>尾部 alpha 衰减</b>(<code>1 − u^淡出曲线 × 淡出强度</code>,沿长度从头到尾越来越透)后的最终样子。</div>
|
|
70
|
+
</div>
|
|
71
|
+
|
|
72
|
+
<!-- 4. 拖尾形状 -->
|
|
73
|
+
<div class="card full">
|
|
74
|
+
<h2>④ 拖尾形状(几何)</h2>
|
|
75
|
+
<canvas id="arcCanvas" height="300"></canvas>
|
|
76
|
+
<div class="legend">
|
|
77
|
+
每个采样点出 <b>2 个顶点</b> = 中心点 ± (宽度/2) × <b>宽度轴</b>,连成三角带 = ribbon。<br>
|
|
78
|
+
采样点是 emitter 绕圈路径按<b>弧长均匀重采样</b>到固定段数的结果;<b>水平面</b>朝向时宽度轴=径向(平躺),<b>竖直</b>时=上方向(立着)。
|
|
79
|
+
<span class="axis">— 虚线 = 采样中心线(emitter 轨迹弧段),短线 = 各点宽度轴。</span>
|
|
80
|
+
</div>
|
|
81
|
+
</div>
|
|
82
|
+
</div>
|
|
83
|
+
|
|
84
|
+
<!-- 控制 -->
|
|
85
|
+
<div class="card full" style="margin-top:16px">
|
|
86
|
+
<h2>参数(对应 weapon-trail debugParams)</h2>
|
|
87
|
+
<div class="grid" style="gap:4px 28px">
|
|
88
|
+
<div>
|
|
89
|
+
<div class="row"><label>颜色 uTint</label><input type="color" id="tint" value="#ffffff"><span class="val" id="tintv">#fff</span></div>
|
|
90
|
+
<div class="row"><label>透明度 opacity</label><input type="range" id="opacity" min="0" max="3" step="0.01" value="1.35"><span class="val" id="opacityv"></span></div>
|
|
91
|
+
<div class="row"><label>饱和度 saturation</label><input type="range" id="saturation" min="0" max="3" step="0.01" value="1.45"><span class="val" id="saturationv"></span></div>
|
|
92
|
+
<div class="row"><label>对比度 contrast</label><input type="range" id="contrast" min="0" max="3" step="0.01" value="1.32"><span class="val" id="contrastv"></span></div>
|
|
93
|
+
<div class="row"><label>alphaPower</label><input type="range" id="alphaPower" min="0.1" max="3" step="0.01" value="0.82"><span class="val" id="alphaPowerv"></span></div>
|
|
94
|
+
</div>
|
|
95
|
+
<div>
|
|
96
|
+
<div class="row"><label>尾部淡出强度</label><input type="range" id="fadeStrength" min="0" max="1" step="0.01" value="0.58"><span class="val" id="fadeStrengthv"></span></div>
|
|
97
|
+
<div class="row"><label>尾部淡出曲线</label><input type="range" id="fadeExp" min="0.2" max="4" step="0.05" value="1.35"><span class="val" id="fadeExpv"></span></div>
|
|
98
|
+
<div class="row"><label>拖尾宽度 width</label><input type="range" id="width" min="0.1" max="4" step="0.01" value="1.2"><span class="val" id="widthv"></span></div>
|
|
99
|
+
<div class="row"><label>拖尾弧度</label><input type="range" id="arcSpan" min="20" max="300" step="5" value="150"><span class="val" id="arcSpanv"></span></div>
|
|
100
|
+
<div class="row"><label>朝向</label>
|
|
101
|
+
<select id="orient" style="flex:1;background:#0c1322;color:var(--ink);border:1px solid var(--line);border-radius:5px;padding:3px 6px;">
|
|
102
|
+
<option value="horizontal">水平面</option><option value="vertical">竖直</option>
|
|
103
|
+
</select><span class="val"></span></div>
|
|
104
|
+
</div>
|
|
105
|
+
</div>
|
|
106
|
+
</div>
|
|
107
|
+
</div>
|
|
108
|
+
|
|
109
|
+
<script>
|
|
110
|
+
const TEX_DATA_URI = "data:image/png;base64,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";
|
|
111
|
+
const P = {};
|
|
112
|
+
const ids = ['opacity','saturation','contrast','alphaPower','fadeStrength','fadeExp','width','arcSpan'];
|
|
113
|
+
function readParams(){
|
|
114
|
+
for (const id of ids){ P[id]=parseFloat(document.getElementById(id).value); document.getElementById(id+'v').textContent = P[id]; }
|
|
115
|
+
const t = document.getElementById('tint').value;
|
|
116
|
+
P.tint = [parseInt(t.substr(1,2),16)/255, parseInt(t.substr(3,2),16)/255, parseInt(t.substr(5,2),16)/255];
|
|
117
|
+
document.getElementById('tintv').textContent = t;
|
|
118
|
+
P.orient = document.getElementById('orient').value;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
// 读贴图像素
|
|
122
|
+
const img = new Image();
|
|
123
|
+
let texW=0, texH=0, texData=null;
|
|
124
|
+
function sampleTex(u, v){ // u,v in 0..1 → {r,g,b,a} 0..1 (nearest)
|
|
125
|
+
const x = Math.min(texW-1, Math.max(0, Math.floor(u*texW)));
|
|
126
|
+
const y = Math.min(texH-1, Math.max(0, Math.floor(v*texH)));
|
|
127
|
+
const i = (y*texW + x)*4;
|
|
128
|
+
return [texData[i]/255, texData[i+1]/255, texData[i+2]/255, texData[i+3]/255];
|
|
129
|
+
}
|
|
130
|
+
// 复刻片元:base + tint + sat + contrast + alpha(含尾部衰减 vertexAlpha(u))
|
|
131
|
+
function shade(u, v){
|
|
132
|
+
const b = sampleTex(u*0.97+0.015, v);
|
|
133
|
+
let c = [b[0]*P.tint[0], b[1]*P.tint[1], b[2]*P.tint[2]];
|
|
134
|
+
const lum = c[0]*0.299 + c[1]*0.587 + c[2]*0.114;
|
|
135
|
+
c = c.map(x => lum + (x-lum)*P.saturation);
|
|
136
|
+
c = c.map(x => (x-0.5)*P.contrast + 0.5);
|
|
137
|
+
c = c.map(x => Math.min(1, Math.max(0, x)));
|
|
138
|
+
const vertexAlpha = Math.max(0, 1 - Math.pow(u, P.fadeExp) * P.fadeStrength);
|
|
139
|
+
let a = Math.pow(Math.min(1,Math.max(0,b[3])), P.alphaPower) * vertexAlpha * P.opacity;
|
|
140
|
+
a = Math.min(1, Math.max(0, a));
|
|
141
|
+
return [c[0]*255, c[1]*255, c[2]*255, a];
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
function fitCanvas(cv){ const w = cv.clientWidth; cv.width = w; return cv.getContext('2d'); }
|
|
145
|
+
|
|
146
|
+
function drawTex(){ // 原始贴图(直接画 img,棋盘格背景透出 alpha)
|
|
147
|
+
const cv = document.getElementById('texCanvas'); const ctx = fitCanvas(cv);
|
|
148
|
+
ctx.clearRect(0,0,cv.width,cv.height);
|
|
149
|
+
ctx.imageSmoothingEnabled = false;
|
|
150
|
+
ctx.drawImage(img, 0, 0, cv.width, cv.height);
|
|
151
|
+
}
|
|
152
|
+
function drawChannels(){
|
|
153
|
+
const cv = document.getElementById('chanCanvas'); const ctx = fitCanvas(cv);
|
|
154
|
+
ctx.clearRect(0,0,cv.width,cv.height);
|
|
155
|
+
const h = cv.height/2, w = cv.width;
|
|
156
|
+
const out = ctx.createImageData(w, cv.height);
|
|
157
|
+
for (let y=0;y<cv.height;y++) for (let x=0;x<w;x++){
|
|
158
|
+
const u=x/w, top = y<h;
|
|
159
|
+
const v = top ? y/h : (y-h)/h;
|
|
160
|
+
const b = sampleTex(u, v); const o=(y*w+x)*4;
|
|
161
|
+
if (top){ out.data[o]=b[0]*255; out.data[o+1]=b[1]*255; out.data[o+2]=b[2]*255; out.data[o+3]=255; }
|
|
162
|
+
else { const g=b[3]*255; out.data[o]=g; out.data[o+1]=g; out.data[o+2]=g; out.data[o+3]=255; }
|
|
163
|
+
}
|
|
164
|
+
ctx.putImageData(out,0,0);
|
|
165
|
+
ctx.fillStyle='#0008'; ctx.fillRect(0,h-9,42,18); ctx.fillStyle='#cfe1ff'; ctx.font='11px monospace';
|
|
166
|
+
ctx.fillText('RGB', 6, h-12); ctx.fillText('Alpha', 6, cv.height-6);
|
|
167
|
+
}
|
|
168
|
+
function drawStrip(){ // 展开 ribbon:整条管线后的最终像素
|
|
169
|
+
const cv = document.getElementById('stripCanvas'); const ctx = fitCanvas(cv);
|
|
170
|
+
ctx.clearRect(0,0,cv.width,cv.height);
|
|
171
|
+
const w=cv.width, h=cv.height;
|
|
172
|
+
const out = ctx.createImageData(w,h);
|
|
173
|
+
for (let y=0;y<h;y++) for (let x=0;x<w;x++){
|
|
174
|
+
const u=x/w, v=y/h; const s=shade(u,v); const o=(y*w+x)*4;
|
|
175
|
+
// 在棋盘格上做 alpha 合成
|
|
176
|
+
const checker = (((x>>4)+(y>>4))&1) ? [26,34,51] : [20,26,40];
|
|
177
|
+
out.data[o] = s[0]*s[3] + checker[0]*(1-s[3]);
|
|
178
|
+
out.data[o+1] = s[1]*s[3] + checker[1]*(1-s[3]);
|
|
179
|
+
out.data[o+2] = s[2]*s[3] + checker[2]*(1-s[3]);
|
|
180
|
+
out.data[o+3] = 255;
|
|
181
|
+
}
|
|
182
|
+
ctx.putImageData(out,0,0);
|
|
183
|
+
ctx.fillStyle='#cfe1ff'; ctx.font='11px monospace';
|
|
184
|
+
ctx.fillText('头 u=0', 4, 14); ctx.textAlign='right'; ctx.fillText('尾 u=1', w-4, 14); ctx.textAlign='left';
|
|
185
|
+
}
|
|
186
|
+
function drawArc(){ // 弯成弧的实际形状 + 几何标注
|
|
187
|
+
const cv = document.getElementById('arcCanvas'); const ctx = fitCanvas(cv);
|
|
188
|
+
const w=cv.width, h=cv.height; ctx.clearRect(0,0,w,h);
|
|
189
|
+
const cx=w*0.5, cy=h*0.62, R=Math.min(w*0.32, h*0.7);
|
|
190
|
+
const span = P.arcSpan * Math.PI/180;
|
|
191
|
+
const a0 = -span/2 - Math.PI/2; // 起始角
|
|
192
|
+
const SEG=140, VW=18; // u 段数 / v 行数
|
|
193
|
+
const halfW = (P.width*0.5) * (R*0.34);// 屏幕上的半宽(可视化缩放)
|
|
194
|
+
// 逐格 quad 画 ribbon
|
|
195
|
+
for (let i=0;i<SEG;i++){
|
|
196
|
+
const u0=i/SEG, u1=(i+1)/SEG;
|
|
197
|
+
const ang0=a0+span*u0, ang1=a0+span*u1;
|
|
198
|
+
for (let j=0;j<VW;j++){
|
|
199
|
+
const v0=j/VW, v1=(j+1)/VW, vm=(v0+v1)/2, um=(u0+u1)/2;
|
|
200
|
+
const s=shade(um,vm); if (s[3]<0.02) continue;
|
|
201
|
+
// 中心线点
|
|
202
|
+
const p0x=cx+Math.cos(ang0)*R, p0y=cy+Math.sin(ang0)*R*0.55; // *0.55 模拟俯视压扁(水平面)
|
|
203
|
+
const p1x=cx+Math.cos(ang1)*R, p1y=cy+Math.sin(ang1)*R*0.55;
|
|
204
|
+
// 宽度方向:水平=径向(在压扁平面里),竖直=屏幕上下
|
|
205
|
+
let wx0,wy0,wx1,wy1;
|
|
206
|
+
if (P.orient==='vertical'){ wx0=0; wy0=-1; wx1=0; wy1=-1; }
|
|
207
|
+
else { wx0=Math.cos(ang0); wy0=Math.sin(ang0)*0.55; const l0=Math.hypot(wx0,wy0); wx0/=l0; wy0/=l0; wx1=Math.cos(ang1); wy1=Math.sin(ang1)*0.55; const l1=Math.hypot(wx1,wy1); wx1/=l1; wy1/=l1; }
|
|
208
|
+
const oy = P.orient==='vertical' ? halfW : halfW; // 屏幕半宽
|
|
209
|
+
const A=[p0x+wx0*oy*(0.5-v0)*2, p0y+wy0*oy*(0.5-v0)*2];
|
|
210
|
+
const B=[p0x+wx0*oy*(0.5-v1)*2, p0y+wy0*oy*(0.5-v1)*2];
|
|
211
|
+
const C=[p1x+wx1*oy*(0.5-v1)*2, p1y+wy1*oy*(0.5-v1)*2];
|
|
212
|
+
const D=[p1x+wx1*oy*(0.5-v0)*2, p1y+wy1*oy*(0.5-v0)*2];
|
|
213
|
+
ctx.fillStyle=`rgba(${s[0]|0},${s[1]|0},${s[2]|0},${s[3]})`;
|
|
214
|
+
ctx.beginPath(); ctx.moveTo(A[0],A[1]); ctx.lineTo(B[0],B[1]); ctx.lineTo(C[0],C[1]); ctx.lineTo(D[0],D[1]); ctx.closePath(); ctx.fill();
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
// 标注:中心线 + 几个宽度轴
|
|
218
|
+
ctx.setLineDash([4,4]); ctx.strokeStyle='#6cc0ff88'; ctx.beginPath();
|
|
219
|
+
for (let i=0;i<=SEG;i++){ const ang=a0+span*(i/SEG); const x=cx+Math.cos(ang)*R, y=cy+Math.sin(ang)*R*0.55; i?ctx.lineTo(x,y):ctx.moveTo(x,y); }
|
|
220
|
+
ctx.stroke(); ctx.setLineDash([]);
|
|
221
|
+
ctx.strokeStyle='#ffd36c'; ctx.lineWidth=1.5;
|
|
222
|
+
for (let k=0;k<=6;k++){ const u=k/6; const ang=a0+span*u; const px=cx+Math.cos(ang)*R, py=cy+Math.sin(ang)*R*0.55;
|
|
223
|
+
let wx,wy; if(P.orient==='vertical'){wx=0;wy=-1;} else {wx=Math.cos(ang); wy=Math.sin(ang)*0.55; const l=Math.hypot(wx,wy); wx/=l; wy/=l;}
|
|
224
|
+
const hw=(P.width*0.5)*(R*0.34); ctx.beginPath(); ctx.moveTo(px-wx*hw,py-wy*hw); ctx.lineTo(px+wx*hw,py+wy*hw); ctx.stroke(); }
|
|
225
|
+
ctx.fillStyle='#cfe1ff'; ctx.font='12px monospace'; ctx.fillText('头(u=0)', cx+Math.cos(a0)*R-10, cy+Math.sin(a0)*R*0.55-8);
|
|
226
|
+
ctx.fillText('尾(u=1)', cx+Math.cos(a0+span)*R-10, cy+Math.sin(a0+span)*R*0.55+16);
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
function redraw(){ readParams(); drawTex(); drawChannels(); drawStrip(); drawArc(); }
|
|
230
|
+
img.onload = () => {
|
|
231
|
+
const off = document.createElement('canvas'); off.width=img.width; off.height=img.height;
|
|
232
|
+
const octx = off.getContext('2d'); octx.drawImage(img,0,0);
|
|
233
|
+
texW=img.width; texH=img.height; texData=octx.getImageData(0,0,texW,texH).data;
|
|
234
|
+
redraw();
|
|
235
|
+
};
|
|
236
|
+
img.src = TEX_DATA_URI;
|
|
237
|
+
document.querySelectorAll('input,select').forEach(el => el.addEventListener('input', redraw));
|
|
238
|
+
window.addEventListener('resize', redraw);
|
|
239
|
+
</script>
|
|
240
|
+
</body>
|
|
241
|
+
</html>
|