Points particle animation

i need a points animation like in this website website when scroll the particles change with animation. i would like to do that . if you guys know how to do like that please help.

code Editor

const group = new THREE.Group();
    scene.add(group);
    const color = new THREE.Color();
    const particlesGeometry = new THREE.BufferGeometry();
    const Ppositions = [];
    const Sposition = []
    const Pcolors = [];
    let particles;
    const globeRadius = 1.3;

    let sampler;
    let model;
    loader.load('/earth.glb', (gltf) => {
      model = gltf.scene;
      gltf.scene.traverse((obj) => {
        if (obj.isMesh) {
          obj.scale.set(0.4, 0.4, 0.4);
          sampler = new MeshSurfaceSampler(obj).build();
          for (let i = 0; i < 8000; i++) {
            const sample = new THREE.Vector3();
            sampler.sample(sample);
            sample.normalize();
            const phi = Math.atan2(sample.z, sample.x);
            const gradientPosition = (phi + Math.PI) / (2 * Math.PI);

            if (gradientPosition < 0.5) {
              color.lerpColors(new THREE.Color(0x006dff), new THREE.Color(0xfc0001), gradientPosition * 2);
            } else {
              color.lerpColors(new THREE.Color(0xfc0001), new THREE.Color(0xf2e300), (gradientPosition - 0.5) * 2);
            }

            sample.multiplyScalar(globeRadius);
            Ppositions.push(sample.x, sample.y, sample.z);
            Pcolors.push(color.r, color.g, color.b);
          }

          particlesGeometry.setAttribute('position', new THREE.Float32BufferAttribute(Ppositions, 3));
          particlesGeometry.setAttribute('color', new THREE.Float32BufferAttribute(Pcolors, 3));

          const material = new THREE.PointsMaterial({ size: 0.008, vertexColors: true, map: sprite });
          particles = new THREE.Points(particlesGeometry, material);
          group.add(particles);
          group.scale.set(0.36, 0.36, 0.36);
        }
      });
    });





    let secondModel;
    loader.load('/land.glb', (gltf) => {
      secondModel = gltf.scene;
      gltf.scene.traverse((obj) => {
        if (obj.isMesh) {
          obj.scale.set(0.4, 0.4, 0.4);
          sampler = new MeshSurfaceSampler(obj).build();
          for (let i = 0; i < 8000; i++) {
            const sample = new THREE.Vector3();
            sampler.sample(sample);
            Sposition.push(sample.x, sample.y, sample.z);
            Pcolors.push(color.r, color.g, color.b);
          }

          // particlesGeometry.setAttribute('position', new THREE.Float32BufferAttribute(Ppositions, 3));
          particlesGeometry.setAttribute('color', new THREE.Float32BufferAttribute(Pcolors, 3));
        }
      });
    });



tl.to({}, {
        ease: Power1.easeInOut,
        duration: 80,
        scrollTrigger: {
          trigger: "#page1",
          start: "bottom bottom",
          end: "bottom top",
          scrub: true,
          onUpdate: function (self) {
            var progress = self.progress;
            if (progress > 0.8) {
              particlesGeometry.setAttribute('position', new THREE.Float32BufferAttribute(Sposition, 3));
            }else{
              particlesGeometry.setAttribute('position', new THREE.Float32BufferAttribute(Ppositions, 3));
            }
          }
        }
      })


this is what i have right now

Can you explain, to yourself in the first place, what this code does? And what do you expect it to do?

update the position attribute of particlesGeometry.
If the scroll progress is greater than 0.8, it uses the positions from the Sposition array; otherwise, it uses positions from the Ppositions array.

Does it produce a smooth transition from one formation to another?

no it switch the positions fast