πŸš€ ΠŸΡ€ΠΎΠΌΡ‚ для Ρ€Π°Π·Ρ€Π°Π±ΠΎΡ‚ΠΊΠΈ ΠΏΡ€Π΅Π·Π΅Π½Ρ‚Π°Ρ†ΠΈΠΎΠ½Π½ΠΎΠ³ΠΎ сайта (React + Anime.js + 3D)

Роль: Π’Ρ‹ β€” Senior Frontend Developer, ΡΠΏΠ΅Ρ†ΠΈΠ°Π»ΠΈΠ·ΠΈΡ€ΡƒΡŽΡ‰ΠΈΠΉΡΡ Π½Π° создании иммСрсивных Π²Π΅Π±-ΠΏΡ€Π΅Π·Π΅Π½Ρ‚Π°Ρ†ΠΈΠΉ с Π°ΠΊΡ†Π΅Π½Ρ‚ΠΎΠΌ Π½Π° ΠΌΠΈΠΊΡ€ΠΎ-Π°Π½ΠΈΠΌΠ°Ρ†ΠΈΠΈ ΠΈ ΠΏΡ€ΠΎΠΈΠ·Π²ΠΎΠ΄ΠΈΡ‚Π΅Π»ΡŒΠ½ΠΎΡΡ‚ΡŒ.

ЦСль: Π Π°Π·Ρ€Π°Π±ΠΎΡ‚Π°Ρ‚ΡŒ одностраничный (ΠΈΠ»ΠΈ многостраничный с ΠΏΠ»Π°Π²Π½Ρ‹ΠΌ скроллом) ΠΏΡ€Π΅Π·Π΅Π½Ρ‚Π°Ρ†ΠΈΠΎΠ½Π½Ρ‹ΠΉ сайт для Π²Ρ‹ΠΌΡ‹ΡˆΠ»Π΅Π½Π½ΠΎΠ³ΠΎ Π±Ρ€Π΅Π½Π΄Π° "NEXUS VISION". Основная Π·Π°Π΄Π°Ρ‡Π° β€” Π²Ρ‹Π·Π²Π°Ρ‚ΡŒ Π²Π°Ρƒ-эффСкт Π·Π° счСт ΠΏΠ»Π°Π²Π½ΠΎΠΉ Π°Π½ΠΈΠΌΠ°Ρ†ΠΈΠΈ ΠΈ соврСмСнного 3D-ΠΊΠΎΠ½Ρ‚Π΅Π½Ρ‚Π°.


1. ВСхнологичСский стСк (Stack)


2. АрхитСктура ΠΈ Навигация (Modern Navigation)

Π Π΅Π°Π»ΠΈΠ·ΡƒΠΉ ΡΠΎΠ²Ρ€Π΅ΠΌΠ΅Π½Π½ΡƒΡŽ Π½Π°Π²ΠΈΠ³Π°Ρ†ΠΈΡŽ с динамичСскими ΠΏΠ΅Ρ€Π΅Ρ…ΠΎΠ΄Π°ΠΌΠΈ:

ΠŸΠ»Π°Π²Π°ΡŽΡ‰Π΅Π΅ мСню

ЀиксированноС Π³ΠΎΡ€ΠΈΠ·ΠΎΠ½Ρ‚Π°Π»ΡŒΠ½ΠΎΠ΅ мСню Π² Π²Π΅Ρ€Ρ…Π½Π΅ΠΉ части экрана с эффСктом размытия стСкла (Glassmorphism).

ΠŸΡ€ΠΎΠ³Ρ€Π΅ΡΡ-Π±Π°Ρ€

Π˜Π½Π΄ΠΈΠΊΠ°Ρ‚ΠΎΡ€ прогрСсса ΠΏΡ€ΠΎΠΊΡ€ΡƒΡ‚ΠΊΠΈ страницы, синхронизированный с anime.js.

Π―ΠΊΠΎΡ€Π½Ρ‹Π΅ ссылки

ΠŸΡ€ΠΈ ΠΊΠ»ΠΈΠΊΠ΅ Π½Π° ΠΏΡƒΠ½ΠΊΡ‚ мСню происходит ΠΏΠ»Π°Π²Π½Ρ‹ΠΉ скролл ΠΊ сСкции с использованиСм anime.js (easing: easeInOutQuad) вмСсто стандартного scrollIntoView.

ДинамичСскиС страницы (ΠΎΠΏΡ†ΠΈΠΎΠ½Π°Π»ΡŒΠ½ΠΎ)

Если ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠ΅Ρ‚ΡΡ React Router, Ρ€Π΅Π°Π»ΠΈΠ·ΡƒΠΉ Π°Π½ΠΈΠΌΠ°Ρ†ΠΈΡŽ появлСния/исчСзновСния страниц (AnimatePresence-ΠΏΠΎΠ΄ΠΎΠ±Π½Ρ‹ΠΉ ΠΏΠΎΠ΄Ρ…ΠΎΠ΄, Π½ΠΎ Π½Π° anime.js).


3. Π Π°Π±ΠΎΡ‚Π° с 3D Π³Ρ€Π°Ρ„ΠΈΠΊΠΎΠΉ

Π˜Π½Ρ‚Π΅Π³Ρ€ΠΈΡ€ΡƒΠΉ 3D-сцСну Π² качСствС Ρ„ΠΎΠ½Π° ΠΈΠ»ΠΈ Ρ†Π΅Π½Ρ‚Ρ€Π°Π»ΡŒΠ½ΠΎΠ³ΠΎ элСмСнта:

Π‘Ρ†Π΅Π½Π°

Π˜ΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠΉ Canvas ΠΎΡ‚ @react-three/fiber, растянутый Π½Π° всю ΡˆΠΈΡ€ΠΈΠ½Ρƒ экрана (с pointer-events: none для Ρ„ΠΎΠ½Π° ΠΈΠ»ΠΈ auto для ΠΈΠ½Ρ‚Π΅Ρ€Π°ΠΊΡ‚ΠΈΠ²Π°).

ΠžΠ±ΡŠΠ΅ΠΊΡ‚Ρ‹

ВзаимодСйствиС

ΠŸΠ°Ρ€Π°Π»Π»Π°ΠΊΡ-эффСкт β€” ΠΏΡ€ΠΈ Π΄Π²ΠΈΠΆΠ΅Π½ΠΈΠΈ ΠΌΡ‹ΡˆΠΈ 3D-ΠΎΠ±ΡŠΠ΅ΠΊΡ‚Ρ‹ слСгка ΡΠΌΠ΅Ρ‰Π°ΡŽΡ‚ΡΡ ΠΎΡ‚Π½ΠΎΡΠΈΡ‚Π΅Π»ΡŒΠ½ΠΎ курсора (ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚ΡŒ useFrame для обновлСния ΠΏΠΎΠ²ΠΎΡ€ΠΎΡ‚Π°).


4. Анимации с anime.js (ΠšΠ»ΡŽΡ‡Π΅Π²Ρ‹Π΅ ΠΌΠ΅Ρ…Π°Π½ΠΈΠΊΠΈ)

Π Π°Π·Π΄Π΅Π»ΠΈ Π°Π½ΠΈΠΌΠ°Ρ†ΠΈΠΈ Π½Π° нСсколько ΡƒΡ€ΠΎΠ²Π½Π΅ΠΉ:

Бтартовая Π·Π°Π³Ρ€ΡƒΠ·ΠΊΠ°

Π‘ΠΊΡ€ΠΎΠ»Π»-Π°Π½ΠΈΠΌΠ°Ρ†ΠΈΠΈ (Scroll-triggered)

ΠœΠΈΠΊΡ€ΠΎ-взаимодСйствия


5. Π˜Π½Ρ‚Π΅Π³Ρ€Π°Ρ†ΠΈΡ PNG-пСрсонаТа (РСфСрСнс)

Π£ мСня Π΅ΡΡ‚ΡŒ PNG-ΠΈΠ·ΠΎΠ±Ρ€Π°ΠΆΠ΅Π½ΠΈΠ΅ пСрсонаТа с ΠΏΡ€ΠΎΠ·Ρ€Π°Ρ‡Π½Ρ‹ΠΌ Ρ„ΠΎΠ½ΠΎΠΌ. Ввоя Π·Π°Π΄Π°Ρ‡Π°:

ΠŸΠΎΠ·ΠΈΡ†ΠΈΠΎΠ½ΠΈΡ€ΠΎΠ²Π°Π½ΠΈΠ΅

РазмСсти пСрсонаТа Π² ΠΏΡ€Π°Π²ΠΎΠΉ Π½ΠΈΠΆΠ½Π΅ΠΉ части экрана ΠΏΠΎΠ²Π΅Ρ€Ρ… 3D-Ρ„ΠΎΠ½Π°, Π½ΠΎ ΠΏΠΎΠ·Π°Π΄ΠΈ тСкстовых слоСв (z-index: 10).

Анимация (Idle)

Π‘Π΄Π΅Π»Π°ΠΉ Ρ‚Π°ΠΊ, Ρ‡Ρ‚ΠΎΠ±Ρ‹ пСрсонаТ ΠΏΠ»Π°Π²Π½ΠΎ покачивался (Π»Π΅Π³ΠΊΠΈΠΉ Π½Π°ΠΊΠ»ΠΎΠ½ Π²Π»Π΅Π²ΠΎ-Π²ΠΏΡ€Π°Π²ΠΎ) ΠΈ слСгка ΠΌΠ°ΡΡˆΡ‚Π°Π±ΠΈΡ€ΠΎΠ²Π°Π»ΡΡ ΠΏΡ€ΠΈ "Π΄Ρ‹Ρ…Π°Π½ΠΈΠΈ" (ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠΉ anime.js Ρ†ΠΈΠΊΠ»Ρ‹ loop: true).

РСакция Π½Π° курсор

ΠŸΡ€ΠΈ Π½Π°Π²Π΅Π΄Π΅Π½ΠΈΠΈ Π½Π° пСрсонаТа, ΠΎΠ½ Π΄ΠΎΠ»ΠΆΠ΅Π½ "ΡΠΌΠΎΡ‚Ρ€Π΅Ρ‚ΡŒ" Π½Π° курсор (ΠΏΠΎΠ²ΠΎΡ€Π°Ρ‡ΠΈΠ²Π°Ρ‚ΡŒΡΡ) ΠΈΠ»ΠΈ ΠΌΠ΅Π½ΡΡ‚ΡŒ ΡΠΌΠΎΡ†ΠΈΡŽ (Π·Π°ΠΌΠ΅Π½ΠΈΡ‚ΡŒ PNG Π½Π° Π΄Ρ€ΡƒΠ³ΠΎΠΉ Π²Π°Ρ€ΠΈΠ°Π½Ρ‚, Ссли ΠΈΡ… нСсколько).

Parallax

ΠŸΡ€ΠΈ скроллС, пСрсонаТ Π΄ΠΎΠ»ΠΆΠ΅Π½ ΠΏΠ΅Ρ€Π΅ΠΌΠ΅Ρ‰Π°Ρ‚ΡŒΡΡ ΠΏΠΎ оси Y ΠΌΠ΅Π΄Π»Π΅Π½Π½Π΅Π΅, Ρ‡Π΅ΠΌ основной ΠΊΠΎΠ½Ρ‚Π΅Π½Ρ‚ (эффСкт Π³Π»ΡƒΠ±ΠΈΠ½Ρ‹).


6. Π‘Ρ‚Ρ€ΡƒΠΊΡ‚ΡƒΡ€Π° сСкций (UI/UX)

БвСрстай 5 основных Π±Π»ΠΎΠΊΠΎΠ²:

  1. Hero: Π‘ΠΎΠ»ΡŒΡˆΠΎΠΉ Π·Π°Π³ΠΎΠ»ΠΎΠ²ΠΎΠΊ, ΠΏΠΎΠ΄Π·Π°Π³ΠΎΠ»ΠΎΠ²ΠΎΠΊ, CTA-ΠΊΠ½ΠΎΠΏΠΊΠ°
  2. О нас: Π‘Π΅Ρ‚ΠΊΠ° с ΠΈΠΊΠΎΠ½ΠΊΠ°ΠΌΠΈ ΠΈ тСкстом (анимация появлСния ΠΏΠΎ ΠΎΡ‡Π΅Ρ€Π΅Π΄ΠΈ)
  3. ΠŸΠΎΡ€Ρ‚Ρ„ΠΎΠ»ΠΈΠΎ / 3D Π¨ΠΎΡƒΡ€ΡƒΠΌ: Π—Π΄Π΅ΡΡŒ 3D-сцСна становится ΠΈΠ½Ρ‚Π΅Ρ€Π°ΠΊΡ‚ΠΈΠ²Π½ΠΎΠΉ (ΠΌΠΎΠΆΠ½ΠΎ ΠΊΡ€ΡƒΡ‚ΠΈΡ‚ΡŒ ΠΎΠ±ΡŠΠ΅ΠΊΡ‚ ΠΌΡ‹ΡˆΡŒΡŽ)
  4. Команда: ΠšΠ°Ρ€Ρ‚ΠΎΡ‡ΠΊΠΈ участников с ΠΈΡ… Ρ„ΠΎΡ‚ΠΎ (ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠΉ маски)
  5. ΠšΠΎΠ½Ρ‚Π°ΠΊΡ‚Ρ‹: Π€ΠΎΡ€ΠΌΠ° ΠΎΠ±Ρ€Π°Ρ‚Π½ΠΎΠΉ связи с Π°Π½ΠΈΠΌΠΈΡ€ΠΎΠ²Π°Π½Π½Ρ‹ΠΌΠΈ полями Π²Π²ΠΎΠ΄Π° (ΠΏΡ€ΠΈ фокусС ΠΏΠΎΠ»Π΅ Ρ€Π°ΡΡˆΠΈΡ€ΡΠ΅Ρ‚ΡΡ)

7. ВрСбования ΠΊ ΠΊΠΎΠ΄Ρƒ (Quality Gates)

  1. ΠžΠΏΡ‚ΠΈΠΌΠΈΠ·Π°Ρ†ΠΈΡ: Π˜ΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠΉ React.memo для тяТСлых ΠΊΠΎΠΌΠΏΠΎΠ½Π΅Π½Ρ‚ΠΎΠ² ΠΈ lazy + Suspense для Π·Π°Π³Ρ€ΡƒΠ·ΠΊΠΈ 3D-ΠΌΠΎΠ΄ΡƒΠ»Π΅ΠΉ
  2. ΠΠ΄Π°ΠΏΡ‚ΠΈΠ²Π½ΠΎΡΡ‚ΡŒ: Мобильная вСрсия Π΄ΠΎΠ»ΠΆΠ½Π° ΠΊΠΎΡ€Ρ€Π΅ΠΊΡ‚Π½ΠΎ ΠΎΡ‚ΠΎΠ±Ρ€Π°ΠΆΠ°Ρ‚ΡŒ 3D-сцСну (ΡƒΠΌΠ΅Π½ΡŒΡˆΠ΅Π½Π½Ρ‹ΠΉ Ρ€Π°Π·ΠΌΠ΅Ρ€), Π° пСрсонаТ Π΄ΠΎΠ»ΠΆΠ΅Π½ ΡΠΌΠ΅Ρ‰Π°Ρ‚ΡŒΡΡ Π² Ρ†Π΅Π½Ρ‚Ρ€ ΠΈΠ»ΠΈ ΠΈΡΡ‡Π΅Π·Π°Ρ‚ΡŒ Π½Π° ΠΌΠ°Π»Π΅Π½ΡŒΠΊΠΈΡ… экранах
  3. Чистота: Π’Π΅ΡΡŒ ΠΊΠΎΠ΄ Π°Π½ΠΈΠΌΠ°Ρ†ΠΈΠΉ вынСси Π² ΠΎΡ‚Π΄Π΅Π»ΡŒΠ½Ρ‹Π΅ Ρ…ΡƒΠΊΠΈ (Π½Π°ΠΏΡ€ΠΈΠΌΠ΅Ρ€, useHeroAnimation, useParallax)

8. РСфСрСнсы (ΠŸΡ€ΠΈΠΌΠ΅Ρ€Π½Π°Ρ рСализация Π°Π½ΠΈΠΌΠ°Ρ†ΠΈΠΈ пСрсонаТа)

// ΠŸΡ€ΠΈΠΌΠ΅Ρ€Π½Ρ‹ΠΉ ΠΊΠΎΠ΄ для Π°Π½ΠΈΠΌΠ°Ρ†ΠΈΠΈ "дыхания" пСрсонаТа
useEffect(() => {
  const animation = anime({
    targets: '.character-img',
    translateY: ['-5px', '5px'],
    scale: ['1', '1.02'],
    direction: 'alternate',
    loop: true,
    easing: 'easeInOutSine',
    duration: 1500
  });
  return () => animation.pause();
}, []);

ΠŸΡ€ΠΈΠΌΠ΅Ρ€ 3D сцСны с частицами
javascript
import { Canvas } from '@react-three/fiber';
import { OrbitControls, Stars } from '@react-three/drei';

function Scene3D() {
  return (
    <Canvas camera={{ position: [0, 0, 5] }}>
      <ambientLight intensity={0.5} />
      <pointLight position={[10, 10, 10]} />
      <Stars radius={10} depth={50} count={2000} factor={4} />
      <mesh rotation={[0.5, 0.5, 0]}>
        <torusGeometry args={[1.5, 0.3, 16, 100]} />
        <meshStandardMaterial color="#6c63ff" wireframe />
      </mesh>
      <OrbitControls enableZoom={false} />
    </Canvas>
  );
}
ΠŸΡ€ΠΈΠΌΠ΅Ρ€ Π½Π°Π²ΠΈΠ³Π°Ρ†ΠΈΠΈ с React Router ΠΈ anime.js
javascript
import { BrowserRouter as Router, Routes, Route, Link } from 'react-router-dom';
import { useEffect, useRef } from 'react';
import anime from 'animejs';

function Navigation() {
  const menuRef = useRef(null);

  useEffect(() => {
    anime({
      targets: menuRef.current,
      translateY: [-50, 0],
      opacity: [0, 1],
      easing: 'easeOutQuad',
      duration: 800
    });
  }, []);

  return (
    <nav ref={menuRef} className="fixed top-0 w-full z-50 bg-white/80 backdrop-blur-md">
      <ul className="flex justify-center space-x-8 p-4">
        <li><Link to="/" className="hover:text-indigo-600 transition">Главная</Link></li>
        <li><Link to="/about" className="hover:text-indigo-600 transition">О нас</Link></li>
        <li><Link to="/portfolio" className="hover:text-indigo-600 transition">ΠŸΠΎΡ€Ρ‚Ρ„ΠΎΠ»ΠΈΠΎ</Link></li>
        <li><Link to="/contact" className="hover:text-indigo-600 transition">ΠšΠΎΠ½Ρ‚Π°ΠΊΡ‚Ρ‹</Link></li>
      </ul>
    </nav>
  );
}
ΠŸΡ€ΠΈΠΌΠ΅Ρ€ использования Intersection Observer с anime.js
javascript
import { useEffect, useRef } from 'react';
import anime from 'animejs';

function AnimatedSection({ children }) {
  const sectionRef = useRef(null);
  const animated = useRef(false);

  useEffect(() => {
    const observer = new IntersectionObserver((entries) => {
      entries.forEach(entry => {
        if (entry.isIntersecting && !animated.current) {
          animated.current = true;
          anime({
            targets: sectionRef.current,
            translateY: [50, 0],
            opacity: [0, 1],
            easing: 'easeOutElastic',
            duration: 1200,
            elasticity: 400
          });
        }
      });
    }, { threshold: 0.3 });

    if (sectionRef.current) {
      observer.observe(sectionRef.current);
    }

    return () => observer.disconnect();
  }, []);

  return <div ref={sectionRef} className="opacity-0">{children}</div>;
}
Полная структура ΠΊΠΎΠΌΠΏΠΎΠ½Π΅Π½Ρ‚Π° Hero с ΠΈΠ½Ρ‚Π΅Π³Ρ€Π°Ρ†ΠΈΠ΅ΠΉ
javascript
import React, { useEffect, useRef } from 'react';
import anime from 'animejs';
import { Scene3D } from './Scene3D';
import characterPNG from './assets/character.png';

function Hero() {
  const titleRef = useRef(null);
  const subtitleRef = useRef(null);
  const ctaRef = useRef(null);
  const characterRef = useRef(null);

  useEffect(() => {
    // Анимация Π·Π°Π³ΠΎΠ»ΠΎΠ²ΠΊΠ°
    anime({
      targets: titleRef.current,
      translateY: [100, 0],
      opacity: [0, 1],
      easing: 'easeOutQuad',
      duration: 1000,
      delay: 200
    });

    // Анимация ΠΏΠΎΠ΄Π·Π°Π³ΠΎΠ»ΠΎΠ²ΠΊΠ°
    anime({
      targets: subtitleRef.current,
      translateY: [80, 0],
      opacity: [0, 1],
      easing: 'easeOutQuad',
      duration: 1000,
      delay: 400
    });

    // Анимация ΠΊΠ½ΠΎΠΏΠΊΠΈ
    anime({
      targets: ctaRef.current,
      scale: [0.8, 1],
      opacity: [0, 1],
      easing: 'easeOutElastic',
      duration: 1200,
      delay: 600,
      elasticity: 500
    });

    // Анимация "дыхания" пСрсонаТа
    anime({
      targets: characterRef.current,
      translateY: ['-8px', '8px'],
      scale: ['1', '1.03'],
      direction: 'alternate',
      loop: true,
      easing: 'easeInOutSine',
      duration: 2000
    });

    // ΠŸΠ°Ρ€Π°Π»Π»Π°ΠΊΡ ΠΏΡ€ΠΈ скроллС
    const handleScroll = () => {
      const scrollY = window.scrollY;
      if (characterRef.current) {
        characterRef.current.style.transform = `translateY(${scrollY * 0.1}px)`;
      }
    };

    window.addEventListener('scroll', handleScroll);
    return () => window.removeEventListener('scroll', handleScroll);
  }, []);

  return (
    <section className="relative h-screen flex items-center overflow-hidden">
      {/* 3D Π€ΠΎΠ½ */}
      <div className="absolute inset-0 z-0">
        <Scene3D />
      </div>

      {/* ΠšΠΎΠ½Ρ‚Π΅Π½Ρ‚ */}
      <div className="relative z-10 container mx-auto px-6">
        <h1 ref={titleRef} className="text-6xl md:text-8xl font-bold text-white opacity-0">
          NEXUS VISION
        </h1>
        <p ref={subtitleRef} className="text-xl md:text-2xl text-gray-200 mt-4 opacity-0">
          Π‘ΡƒΠ΄ΡƒΡ‰Π΅Π΅ ΡƒΠΆΠ΅ здСсь
        </p>
        <button ref={ctaRef} className="mt-8 px-8 py-4 bg-indigo-600 text-white rounded-full hover:bg-indigo-700 transition transform hover:scale-105 opacity-0">
          ΠΠ°Ρ‡Π°Ρ‚ΡŒ
        </button>
      </div>

      {/* PNG ΠŸΠ΅Ρ€ΡΠΎΠ½Π°ΠΆ */}
      <img
        ref={characterRef}
        src={characterPNG}
        alt="ΠŸΠ΅Ρ€ΡΠΎΠ½Π°ΠΆ"
        className="absolute bottom-10 right-10 z-10 w-48 md:w-64 h-auto pointer-events-none select-none"
        style={{ filter: 'drop-shadow(0 10px 30px rgba(0,0,0,0.5))' }}
      />
    </section>
  );
}

export default Hero;
Π‘Ρ‚Ρ€ΡƒΠΊΡ‚ΡƒΡ€Π° ΠΏΡ€ΠΎΠ΅ΠΊΡ‚Π°
text
src/
β”œβ”€β”€ components/
β”‚   β”œβ”€β”€ Navigation.jsx
β”‚   β”œβ”€β”€ Hero.jsx
β”‚   β”œβ”€β”€ About.jsx
β”‚   β”œβ”€β”€ Portfolio.jsx
β”‚   β”œβ”€β”€ Team.jsx
β”‚   β”œβ”€β”€ Contact.jsx
β”‚   └── Footer.jsx
β”œβ”€β”€ components/3D/
β”‚   β”œβ”€β”€ Scene3D.jsx
β”‚   β”œβ”€β”€ Particles.jsx
β”‚   └── AnimatedObject.jsx
β”œβ”€β”€ hooks/
β”‚   β”œβ”€β”€ useScrollAnimation.js
β”‚   β”œβ”€β”€ useParallax.js
β”‚   └── useCharacterAnimation.js
β”œβ”€β”€ assets/
β”‚   └── character.png
β”œβ”€β”€ styles/
β”‚   └── index.css
β”œβ”€β”€ App.jsx
└── index.js
9. Π˜Ρ‚ΠΎΠ³ΠΎΠ²Ρ‹ΠΉ запрос ΠΊ ΠΌΠΎΠ΄Π΅Π»ΠΈ
Π‘Π³Π΅Π½Π΅Ρ€ΠΈΡ€ΡƒΠΉ ΠΊΠΎΠ΄ для этого ΠΏΡ€ΠΎΠ΅ΠΊΡ‚Π°, начиная с Ρ„Π°ΠΉΠ»Π° App.js, настройки Ρ€ΠΎΡƒΡ‚ΠΈΠ½Π³Π°, ΠΈ основного ΠΊΠΎΠΌΠΏΠΎΠ½Π΅Π½Ρ‚Π° Hero с ΠΈΠ½Ρ‚Π΅Π³Ρ€Π°Ρ†ΠΈΠ΅ΠΉ 3D-Ρ„ΠΎΠ½Π° ΠΈ PNG-пСрсонаТа, ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΡ Π²Ρ‹ΡˆΠ΅ΠΎΠΏΠΈΡΠ°Π½Π½Ρ‹Π΅ ΠΏΡ€Π°Π²ΠΈΠ»Π° Π°Π½ΠΈΠΌΠ°Ρ†ΠΈΠΈ. УбСдись, Ρ‡Ρ‚ΠΎ:

ВсС зависимости ΠΏΡ€Π°Π²ΠΈΠ»ΡŒΠ½ΠΎ ΠΈΠΌΠΏΠΎΡ€Ρ‚ΠΈΡ€ΠΎΠ²Π°Π½Ρ‹

Анимации Ρ€Π°Π±ΠΎΡ‚Π°ΡŽΡ‚ синхронно ΠΈ Π½Π΅ ΠΊΠΎΠ½Ρ„Π»ΠΈΠΊΡ‚ΡƒΡŽΡ‚

3D-сцСна ΠΎΠΏΡ‚ΠΈΠΌΠΈΠ·ΠΈΡ€ΠΎΠ²Π°Π½Π° для ΠΏΡ€ΠΎΠΈΠ·Π²ΠΎΠ΄ΠΈΡ‚Π΅Π»ΡŒΠ½ΠΎΡΡ‚ΠΈ

ΠŸΠ΅Ρ€ΡΠΎΠ½Π°ΠΆ ΠΏΡ€Π°Π²ΠΈΠ»ΡŒΠ½ΠΎ Ρ€Π΅Π°Π³ΠΈΡ€ΡƒΠ΅Ρ‚ Π½Π° скролл ΠΈ ΠΈΠΌΠ΅Π΅Ρ‚ "Π΄Ρ‹Ρ…Π°Π½ΠΈΠ΅"

Навигация ΠΏΠ»Π°Π²Π½ΠΎ скроллит ΠΊ сСкциям

Код чистый, Ρ…ΠΎΡ€ΠΎΡˆΠΎ структурированный ΠΈ Π·Π°Π΄ΠΎΠΊΡƒΠΌΠ΅Π½Ρ‚ΠΈΡ€ΠΎΠ²Π°Π½Π½Ρ‹ΠΉ

10. Π”ΠΎΠΏΠΎΠ»Π½ΠΈΡ‚Π΅Π»ΡŒΠ½Ρ‹Π΅ Ρ€Π΅ΠΊΠΎΠΌΠ΅Π½Π΄Π°Ρ†ΠΈΠΈ
Для ΡƒΠ»ΡƒΡ‡ΡˆΠ΅Π½ΠΈΡ ΠΏΡ€ΠΎΠΈΠ·Π²ΠΎΠ΄ΠΈΡ‚Π΅Π»ΡŒΠ½ΠΎΡΡ‚ΠΈ:
Π˜ΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠΉ useMemo для слоТных вычислСний Π² 3D-сцСнС

Π’ΠΊΠ»ΡŽΡ‡ΠΈ shallow Ρ€Π΅Π½Π΄Π΅Ρ€ΠΈΠ½Π³ для ΠΊΠΎΠΌΠΏΠΎΠ½Π΅Π½Ρ‚ΠΎΠ², ΠΊΠΎΡ‚ΠΎΡ€Ρ‹Π΅ часто ΠΎΠ±Π½ΠΎΠ²Π»ΡΡŽΡ‚ΡΡ

ΠžΠΏΡ‚ΠΈΠΌΠΈΠ·ΠΈΡ€ΡƒΠΉ изобраТСния с ΠΏΠΎΠΌΠΎΡ‰ΡŒΡŽ next/image ΠΈΠ»ΠΈ vite-plugin-imagemin

Π˜ΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠΉ React.lazy для ΠΊΠΎΠ΄-сплиттинга страниц

Для ΡƒΠ»ΡƒΡ‡ΡˆΠ΅Π½ΠΈΡ UX:
Π”ΠΎΠ±Π°Π²ΡŒ ΠΈΠ½Π΄ΠΈΠΊΠ°Ρ‚ΠΎΡ€ Π·Π°Π³Ρ€ΡƒΠ·ΠΊΠΈ для 3D-сцСны

Π Π΅Π°Π»ΠΈΠ·ΡƒΠΉ ΠΏΠ»Π°Π²Π½Ρ‹Π΅ ΠΏΠ΅Ρ€Π΅Ρ…ΠΎΠ΄Ρ‹ ΠΌΠ΅ΠΆΠ΄Ρƒ страницами

Π”ΠΎΠ±Π°Π²ΡŒ ΠΏΠΎΠ΄Π΄Π΅Ρ€ΠΆΠΊΡƒ prefers-reduced-motion для ΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚Π΅Π»Π΅ΠΉ с Ρ‡ΡƒΠ²ΡΡ‚Π²ΠΈΡ‚Π΅Π»ΡŒΠ½ΠΎΡΡ‚ΡŒΡŽ ΠΊ Π°Π½ΠΈΠΌΠ°Ρ†ΠΈΠΈ

Π’ΠΊΠ»ΡŽΡ‡ΠΈ ΠΊΠ΅ΡˆΠΈΡ€ΠΎΠ²Π°Π½ΠΈΠ΅ статичСских рСсурсов

Для SEO:
Π˜ΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠΉ react-helmet для управлСния ΠΌΠ΅Ρ‚Π°-Ρ‚Π΅Π³Π°ΠΌΠΈ

Π”ΠΎΠ±Π°Π²ΡŒ структурированныС Π΄Π°Π½Π½Ρ‹Π΅ (JSON-LD)

УбСдись, Ρ‡Ρ‚ΠΎ ΠΊΠΎΠ½Ρ‚Π΅Π½Ρ‚ доступСн Π±Π΅Π· JavaScript