Mouse Hover on particles

hello, i am unable to add mouse hover effect like we have in this spline design - Interactive spark letter with particle effect
open and run this and try mouse hover, i tried but its not done
here is my code

import { useEffect, useMemo, useRef, useState } from "react";
import { Canvas, useFrame, useLoader } from "@react-three/fiber";
import { OrbitControls, Center } from "@react-three/drei";
import * as THREE from "three";
import { FontLoader } from "three/examples/jsm/loaders/FontLoader.js";
import { TextGeometry } from "three/examples/jsm/geometries/TextGeometry.js";
import { MeshSurfaceSampler } from "three/examples/jsm/math/MeshSurfaceSampler.js";

const ParticleText = ({ text = "BALL AI" }) => {
  const particleCount = 10000;
  const particlesRef = useRef();
  const [ready, setReady] = useState(false);
  const mousePos = useRef(new THREE.Vector2(0, 0)); // Normalized screen space
  const mouseWorldPos = useRef(new THREE.Vector3()); // World space

  // Assuming BlauerNueRegular.json is in public/assets/fonts
  const font = useLoader(FontLoader, "/fonts/helvetiker_regular.typeface.json");

  const { positions, initialPositions, lifetimes } = useMemo(() => {
    if (!font)
      return {
        positions: new Float32Array(particleCount * 3),
        initialPositions: new Float32Array(particleCount * 3),
        lifetimes: new Float32Array(particleCount),
      };

    const textGeometry = new TextGeometry(text, {
      font: font,
      size: 1.2,
      height: 0.2,
      curveSegments: 12,
      bevelEnabled: false,
    });

    textGeometry.computeBoundingBox();
    const centerOffset = new THREE.Vector3();
    textGeometry.boundingBox.getCenter(centerOffset).negate();
    textGeometry.translate(centerOffset.x, centerOffset.y, centerOffset.z);

    const textMaterial = new THREE.MeshBasicMaterial();
    const textMesh = new THREE.Mesh(textGeometry, textMaterial);
    const sampler = new MeshSurfaceSampler(textMesh).build();

    const positions = new Float32Array(particleCount * 3);
    const initialPositions = new Float32Array(particleCount * 3);
    const lifetimes = new Float32Array(particleCount);

    const tempPosition = new THREE.Vector3();

    for (let i = 0; i < particleCount; i++) {
      sampler.sample(tempPosition);

      const i3 = i * 3;
      positions[i3] = tempPosition.x;
      positions[i3 + 1] = tempPosition.y;
      positions[i3 + 2] = tempPosition.z;

      initialPositions[i3] = tempPosition.x;
      initialPositions[i3 + 1] = tempPosition.y;
      initialPositions[i3 + 2] = tempPosition.z;

      lifetimes[i] = Math.random() * 8.0; // Match cycleTime
    }

    setReady(true);
    return { positions, initialPositions, lifetimes };
  }, [font, text, particleCount]);
  

  const shader = useMemo(
    () => ({
      uniforms: {
        time: { value: 0 },
        gravity: { value: 0.02 },
        cycleTime: { value: 8.0 },
        colorStart: { value: new THREE.Color("#E1e1e1") },
        colorEnd: { value: new THREE.Color("#C77518") },
        mousePos: { value: new THREE.Vector3(0, 0, 0) },
        attractionStrength: { value: 10.0 },
        attractionRadius: { value: 0.3 },
        mouseCycleTime: { value: 2.0 }, // Short cycle for mouse attraction
      },
      vertexShader: `uniform float time;
      uniform float gravity;
      uniform float cycleTime;
      uniform vec3 colorStart;
      uniform vec3 colorEnd;
      uniform vec3 mousePos;
      uniform float attractionStrength;
      uniform float attractionRadius;
      uniform float mouseCycleTime;

      attribute vec3 initialPosition;
      attribute float lifetime;

      varying float vAlpha;
      varying vec3 vColor;

      void main() {
        float particleTime = mod(time + lifetime, cycleTime);
        vec3 pos = initialPosition;
        
        // Base rise and fall motion for all particles
        float upwardVelocity = 0.09;
        float t = particleTime;
        float verticalOffset = upwardVelocity * t - 0.5 * gravity * t * t;
        
        // Mouse attraction calculation
        // Mouse attraction calculation
vec3 directionToMouse = mousePos - pos; // Changed from initialPosition to use current pos
float distanceToMouse = length(directionToMouse);

if (distanceToMouse < attractionRadius) {
  // Normalize the direction vector for proper 3D attraction
  vec3 normalizedDirection = normalize(directionToMouse);
  
  // Calculate attraction strength based on distance
  float attractionFactor = smoothstep(attractionRadius, 0.0, distanceToMouse) * attractionStrength;
  
  // Calculate how much the particle should stick to the mouse
  float stickFactor = min(1.0, attractionFactor * 2.0);
  
  // Create the normal position with vertical offset
  vec3 normalPos = initialPosition + vec3(0.0, verticalOffset, 0.0);
  
  // The mouse position to attract to (full 3D position)
  vec3 attractedPos = mousePos;
  
  // Mix between normal position and mouse position based on stickFactor
  pos = mix(normalPos, attractedPos, stickFactor);
} else {
  // Normal motion when outside attraction radius
  pos = initialPosition + vec3(0.0, verticalOffset, 0.0);
}
        
        // Fade calculation (uniform for all particles)
        float peakTime = upwardVelocity / gravity;
        float peakHeight = (upwardVelocity * upwardVelocity) / (2.0 * gravity);
        float halfHeight = peakHeight * 0.5;
        float fallTimeToHalf = sqrt(2.0 * (peakHeight - halfHeight) / gravity);
        float fadeStartTime = peakTime + fallTimeToHalf;
        
        vAlpha = 1.0;
        if (particleTime < 0.1) {
          vAlpha = particleTime / 0.1;
        }
        if (particleTime > fadeStartTime) {
          float fadeProgress = (particleTime - fadeStartTime) / (cycleTime - fadeStartTime);
          vAlpha = max(0.0, 1.0 - fadeProgress);
        }
        
        // Color transition over full cycle
        float colorProgress = particleTime / cycleTime;
        vColor = mix(colorStart, colorEnd, colorProgress);
        
        vec4 mvPosition = modelViewMatrix * vec4(pos, 1.0);
        gl_Position = projectionMatrix * mvPosition;
        float baseSize = 3.0;
        gl_PointSize = baseSize * (3.0 / -mvPosition.z);
      }`,
      fragmentShader: `
      varying float vAlpha;
      varying vec3 vColor;
      
      void main() {
        if (vAlpha <= 0.01) discard;
        
        vec2 coord = gl_PointCoord - vec2(0.5);
        float dist = length(coord);
        float alpha = smoothstep(0.5, 0.3, dist) * vAlpha;
        
        gl_FragColor = vec4(vColor, alpha);
      }
    `,
    }),
    []
  );

  // Mouse movement handler
  useEffect(() => {
    const handleMouseMove = (event) => {
      const canvas = document.querySelector("canvas");
      if (!canvas) return;

      const rect = canvas.getBoundingClientRect();
      mousePos.current.x = ((event.clientX - rect.left) / rect.width) * 2 - 1;
      mousePos.current.y = -((event.clientY - rect.top) / rect.height) * 2 + 1;
    };

    window.addEventListener("mousemove", handleMouseMove);
    return () => window.removeEventListener("mousemove", handleMouseMove);
  }, []);

  const raycaster = new THREE.Raycaster();
const mouse = new THREE.Vector2();


  // Update loop
  useFrame((state) => {
    if (!particlesRef.current || !ready) return;

    const { camera } = state;
    particlesRef.current.material.uniforms.time.value = state.clock.getElapsedTime();

    // Update mouse position in world space
    const raycaster = new THREE.Raycaster();
    raycaster.setFromCamera(mousePos.current, camera);
    const plane = new THREE.Plane(new THREE.Vector3(0, 0, -1), 0);
    raycaster.ray.intersectPlane(plane, mouseWorldPos.current);
    if (mouseWorldPos.current) {
      particlesRef.current.material.uniforms.mousePos.value.copy(mouseWorldPos.current);
    }
  });

  return (
    <group>
      {ready && (
        <points ref={particlesRef}>
          <bufferGeometry>
            <bufferAttribute
              attach="attributes-position"
              count={particleCount}
              itemSize={3}
              array={positions}
            />
            <bufferAttribute
              attach="attributes-initialPosition"
              count={particleCount}
              itemSize={3}
              array={initialPositions}
            />
            <bufferAttribute
              attach="attributes-lifetime"
              count={particleCount}
              itemSize={1}
              array={lifetimes}
            />
          </bufferGeometry>
          <shaderMaterial
            args={[shader]}
            transparent
            depthWrite={false}
            blending={THREE.AdditiveBlending}
          />
        </points>
      )}
    </group>
  );
};

const BallAi = () => (
  <Canvas camera={{ position: [0, 0, 2.5] }} dpr={[1, 2]}>
    <color attach="background" args={["#000"]} />
    <ambientLight intensity={0.5} />
    <pointLight position={[10, 10, 10]} />
    <Center>
      <ParticleText text="BroAI" />
    </Center>
    <OrbitControls />
  </Canvas>
);

export default BallAi;

can anyone help me with this??

why threejs community doesnt reply? or they dont know anything!

just a reminder, if anyone can help me with this!?