этот код нужно изменить так, чтобы камера поворачивалась в зависимости от положения курсора на экране
код:

import * as THREE from 'three';
import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader';
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls'

const scene = new THREE.Scene();

const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
const renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);

const controls = new OrbitControls( camera, renderer.domElement );
controls.enableZoom = false;

controls.enableDamping = true; 
controls.dampingFactor = 0.05; 


let prevMouseX, prevMouseY;

function onMouseMove(event) {
  const mouseX = event.clientX;
  const mouseY = event.clientY;
  
  if (prevMouseX && prevMouseY) {
    const deltaX = mouseX - prevMouseX;
    const deltaY = mouseY - prevMouseY;
  
    controls.rotateLeftRight(deltaX * 0.01); // угол поворота по горизонтали
    controls.rotateUpDown(-deltaY * 0.01); // угол поворота по вертикали
  }
  
  prevMouseX = mouseX;
  prevMouseY = mouseY;
}

window.addEventListener('mousemove', onMouseMove);








const loader = new GLTFLoader();
const url = 'particlesThree.glb';

loader.load(url, function (gltf) {
  const model = gltf.scene;

  model.traverse((child) => {
    if (child.isMesh) {
      const geometry = child.geometry;
      const material = new THREE.PointsMaterial({
        size: 0.01,
        vertexColors: true // включаем использование цветов вершин
      });
      const points = new THREE.Points(geometry, material);
      
      // получаем массив вершин из объекта geometry
      const positions = geometry.getAttribute('position').array;

      // создаем массив цветов для вершин
      const colors = [];
      for (let i = 0; i < positions.length; i += 3) {
        let sin = Math.sin(Math.random());
        colors.push(0.8 * sin, 0.8 * sin, 0.5 * sin + sin); // создаем случайный цвет (почти) для каждой вершины
      }

      const randomPosition = [];
      for (let i = 0; i < positions.length; i += 3) {
        randomPosition.push(6.0*Math.random()-3.0, 6.0*Math.random()-3.0, 6.0*Math.random()-3.0);
      }
      const randomPositionCopy = [...randomPosition];

      let increment = 0.0005;


      // Анимация по таймеру
      // setInterval( () => {
      //   for(let i = 0; i<randomPosition.length; i++) {
      //     if (randomPosition[i] < positions[i]) {
      //       randomPosition[i] = randomPosition[i] + increment;
      //     } else if(randomPosition[i] > positions[i]) {
      //       randomPosition[i] = randomPosition[i] - increment;
      //     }
      //   }
      //   geometry.setAttribute('position', new THREE.BufferAttribute(new Float32Array(randomPosition), 3));
      // }, 1);



      // Анимация при прокрутке колесика
      geometry.setAttribute('position', new THREE.BufferAttribute(new Float32Array(randomPosition), 3));
      function updateArray(increment) {
        for(let j = 0; j < 75; j++) {
          for(let i = 0; i<randomPosition.length; i++) {
            if (randomPosition[i] < positions[i]) {
              randomPosition[i] = randomPosition[i] + increment;
            } else if(randomPosition[i] > positions[i]) {
              randomPosition[i] = randomPosition[i] - increment;
            } else if((randomPosition[i] - positions[i]) < 0.002) {
              randomPosition[i] = positions[i];
            }
          }
        }
        geometry.setAttribute('position', new THREE.BufferAttribute(new Float32Array(randomPosition), 3));
      }
      function reverseUpdateArray(increment) {
        for(let j = 0; j < 75; j++) {
          for(let i = 0; i<randomPosition.length; i++) {
            if (randomPosition[i] < randomPositionCopy[i]) {
              randomPosition[i] = randomPosition[i] + increment;
            } else if(randomPosition[i] > randomPositionCopy[i]) {
              randomPosition[i] = randomPosition[i] - increment;
            } else if((randomPosition[i] - randomPositionCopy[i]) < 0.002) {
              randomPosition[i] = randomPositionCopy[i];
            }
          }
        }
        geometry.setAttribute('position', new THREE.BufferAttribute(new Float32Array(randomPosition), 3));
      }

      window.addEventListener('wheel', function(event) {
        if (event.deltaY > 0) {
          updateArray(increment);
        } else {
          reverseUpdateArray(increment);
        }
      });

      
      // задаем массив цветов в объекте geometry
      geometry.setAttribute('color', new THREE.BufferAttribute(new Float32Array(colors), 3));
      child.parent.add(points);
      child.parent.remove(child);
    }
  });
  

  model.scale.set(1.0, 1.0, 1.0);
  model.rotateX(Math.PI/2.0);
  scene.add(model);

 
  camera.position.z = 3;
    

  animate();  
  function animate() {
    requestAnimationFrame(animate);
    controls.update();
    renderer.render(scene, camera);
  }
});