Three js responsive chess app

Hello guys this is my code Chessboard.tsx and my app is completely no responsive i was watching
guides to fix this but nothing helped me.

import React, { useEffect, useRef, useState } from "react";
import * as THREE from "three";
import { GLTFLoader } from "three/examples/jsm/loaders/GLTFLoader.js";
import { OrbitControls } from "three/examples/jsm/controls/OrbitControls.js";
import { RGBELoader } from "three/examples/jsm/loaders/RGBELoader.js";
import Button from "@/components/landing-page/button";


const Chessboard: React.FC = () => {
  const mountRef = useRef<HTMLDivElement | null>(null);
  const [lastPosition, setLastPosition] = useState(5);
  const [showButton, setShowButton] = useState(false);
  const cameraPositions = useRef<{ position: THREE.Vector3; lookAt: THREE.Vector3 }[]>([
    {
      position: new THREE.Vector3(0, 8, 15), // Widok z przodu
      lookAt: new THREE.Vector3(0, 0, 0),
    },
    {
      position: new THREE.Vector3(0, 10, 0), // Widok z góry
      lookAt: new THREE.Vector3(0, 0, 0),
    },
    {
      position: new THREE.Vector3(0, 8, 10), // Powrót do widoku z przodu
      lookAt: new THREE.Vector3(0, 0, 0),
    },
    {
      position: new THREE.Vector3(-8, 3, 0), // Widok z boku
      lookAt: new THREE.Vector3(0, 0, 0),
    },
    {
      position: new THREE.Vector3(-2, 3, 0), // Przybliżenie do szachownicy
      lookAt: new THREE.Vector3(0, 0, 0),
    },
    {
      position: new THREE.Vector3(-8, 3, 0), // Widok oddalony
      lookAt: new THREE.Vector3(0, 0, 0),
    },
  ]);
  const currentPositionIndex = useRef(0);
  const transitioning = useRef(false);
  const startTransitionTime = useRef<number | null>(null);
  const animationDuration = 3000; // 3 sekundy
  const startPosition = useRef(new THREE.Vector3());
  const targetPosition = useRef(new THREE.Vector3());
  const startRotation = useRef(0); // Startowa rotacja szachownicy
  const targetRotation = useRef(0); // Docelowa rotacja szachownicy
  const chessModel = useRef<THREE.Group | null>(null); // Referencja do modelu szachownicy



  const renderButton = () => {
    if(showButton) {
      return (
        
          <Button />
    
      );
    }
  }

  useEffect(() => {
    if (!mountRef.current) return;

    const scene = new THREE.Scene();
    const camera = new THREE.PerspectiveCamera(
      50,
      window.innerWidth / window.innerHeight,
      0.1,
      1000
    );

    // Ustaw początkową pozycję kamery
    if (cameraPositions.current[0]) {
      camera.position.copy(cameraPositions.current[0].position);
      camera.lookAt(cameraPositions.current[0].lookAt);
    }

    const renderer = new THREE.WebGLRenderer({ antialias: true });
    renderer.setSize(window.innerWidth, window.innerHeight);
    renderer.shadowMap.enabled = true;
    mountRef.current.appendChild(renderer.domElement);

    const textureLoader = new RGBELoader();
    textureLoader.load("/backgrounds/finalBackground.hdr", (texture: THREE.Texture) => { 
      texture.mapping = THREE.EquirectangularReflectionMapping;
      const backgroundGeometry = new THREE.SphereGeometry(500, 32, 32);
      const backgroundMaterial = new THREE.MeshBasicMaterial({
        map: texture,
        side: THREE.BackSide
      });

      const backgroundMesh = new THREE.Mesh(backgroundGeometry, backgroundMaterial);
      scene.add(backgroundMesh);


      scene.environment = texture;
    });

    const controls = new OrbitControls(camera, renderer.domElement);
    controls.enableDamping = true;
    controls.dampingFactor = 0.05;
    controls.enableRotate = false;
    controls.enablePan = false;
    controls.enableZoom = false;

    const ambientLight = new THREE.AmbientLight(0x808080, 0.7); // Jaśniejsze światło otoczenia
    scene.add(ambientLight);
    
    // Wyraźniejsze światło punktowe skierowane na szachownicę
    const pointLight = new THREE.PointLight(0xffffff, 2.0, 150); // Jeszcze mocniejsze światło punktowe
    pointLight.position.set(0, 20, 10); // Wyższe ustawienie nad szachownicą
    pointLight.castShadow = true;
    pointLight.shadow.mapSize.width = 2048; // Wyższa rozdzielczość cieni
    pointLight.shadow.mapSize.height = 2048;
    scene.add(pointLight);
    
    // Jaśniejsze światło kierunkowe dla głębi
    const directionalLight = new THREE.DirectionalLight(0xffffff, 1.0); // Jeszcze bardziej widoczne
    directionalLight.position.set(10, 20, 15); // Wyżej i bardziej z boku dla lepszej głębi
    directionalLight.castShadow = true;
    directionalLight.shadow.mapSize.width = 2048; // Szczegółowe cienie
    directionalLight.shadow.mapSize.height = 2048;
    scene.add(directionalLight);

    const loader = new GLTFLoader();
    loader.load(
      "/models/chess_set_1k.glb",
      (gltf) => {
        const model = gltf.scene;
        model.scale.set(11, 11, 11);
        model.traverse((node) => {
          if ((node as THREE.Mesh).isMesh) {
            const mesh = node as THREE.Mesh;
            mesh.castShadow = true;
            mesh.receiveShadow = true;
          }
        });

        chessModel.current = model; // Zachowaj referencję do szachownicy
        scene.add(model);
      },
      undefined,
      (error) => {
        console.error("Błąd ładowania modelu:", error);
      }
    );

    const handleScroll = (event: WheelEvent) => {
      if(currentPositionIndex.current === lastPosition) {
        setShowButton(true);
      }else{
        if (transitioning.current || !cameraPositions.current.length) return;

      const direction = event.deltaY > 0 ? 1 : -1;
      const newIndex =
        (currentPositionIndex.current + direction + cameraPositions.current.length) %
        cameraPositions.current.length;

      const newPosition = cameraPositions.current[newIndex];
      if (!newPosition) return;

      // Ustawienia pozycji kamery
      startPosition.current.copy(camera.position);
      targetPosition.current.copy(newPosition.position);

      // Ustawienia rotacji szachownicy
      startRotation.current = chessModel.current?.rotation.y || 0;
      if (newIndex === 3) {
        // Obrót szachownicy o 90 stopni dla widoku z boku (4)
        targetRotation.current = startRotation.current + Math.PI / 2;
      } else if (newIndex === 2) {
        // Cofnij obrót do pierwotnej rotacji
        targetRotation.current = 0;
      } else {
        targetRotation.current = startRotation.current; // Nie obracaj w innych przypadkach
      }

      currentPositionIndex.current = newIndex;
      transitioning.current = true;
      startTransitionTime.current = performance.now();

      if (newIndex === lastPosition) {
        setShowButton(true);
      }
      }
    };

    window.addEventListener("wheel", handleScroll);

    const animate = () => {
      requestAnimationFrame(animate);

      if (transitioning.current && startTransitionTime.current !== null) {
        const elapsedTime = performance.now() - startTransitionTime.current;
        const progress = Math.min(elapsedTime / animationDuration, 1); // Ogranicz progress do 0-1

        // Interpolacja pozycji kamery
        camera.position.lerpVectors(
          startPosition.current,
          targetPosition.current,
          progress
        );

        // Rotacja szachownicy
        if (chessModel.current) {
          chessModel.current.rotation.y =
            startRotation.current +
            (targetRotation.current - startRotation.current) * progress;
        }

        // Ustaw `lookAt` kamery
        const currentLookAt = cameraPositions.current[currentPositionIndex.current]?.lookAt;
        if (currentLookAt) camera.lookAt(currentLookAt);

        if (progress === 1) {
          transitioning.current = false; // Zakończ animację
          startTransitionTime.current = null;
        }
      }

      controls.update();
      renderer.render(scene, camera);
    };

    animate();

    return () => {
      window.removeEventListener("wheel", handleScroll);
      mountRef.current?.removeChild(renderer.domElement);
    };
  }, []);

  return (
    <>
    <div
      ref={mountRef}
      style={{
        zIndex: -1,
        width: "100vw",
        height: "100vh",
        margin: 0,
        padding: 0,
        overflow: "hidden",
      }}
    />
    {renderButton()}
    </>
  );
};

export default Chessboard;

It will be easier for others to help you if you can put your code in a codesandbox / jsfiddle or similar so it can be run.

Can you also explain more clearly what your issue is?

I’m not sure if:

  • the app is not responsive, as in its size doesn’t change when you resize your browser
  • or if it’s not responsive, as in it can’t be interacted with and seems frozen
1 Like