الحافظة ثلاثية الأبعاد

Starter pack

الواجهة

الآن بعد أن أنجزنا مشهدنا ثلاثي الأبعاد بشكل رئيسي، يمكننا البدء في العمل على واجهة HTML.

دعونا ننشئ مكون Interface.jsx مع نفس الأقسام الأربعة كمشهد ثلاثي الأبعاد لدينا:

export const Interface = () => {
  return (
    <div className="interface">
      <div className="sections">
        {/* الصفحة الرئيسية */}
        <section className="section section--bottom">HOME</section>
        {/* المهارات */}
        <section className="section section--right">SKILLS</section>
        {/* المشاريع */}
        <section className="section section--left">PROJECTS</section>
        {/* الاتصال */}
        <section className="section section--left">CONTACT</section>
      </div>
    </div>
  );
};

سنستخدم الفئات section--bottom و section--right و section--left لتحديد موقع المحتوى داخل الأقسام.

في الوقت الحالي أضفنا فقط أسماء الأقسام، وسنضيف المحتوى لاحقًا.

دعونا نضيف مكون Interface إلى مكون App:

import { Scroll, ScrollControls } from "@react-three/drei";
import { Canvas } from "@react-three/fiber";
import { MotionConfig } from "framer-motion";
import { Experience } from "./components/Experience";
import { config } from "./config";
import { Interface } from "./components/Interface";

function App() {
  return (
    <>
      <Canvas camera={{ position: [0, 0.5, 5], fov: 42 }}>
        <color attach="background" args={["#f5f3ee"]} />
        <fog attach="fog" args={["#f5f3ee", 10, 50]} />
        <ScrollControls
          pages={config.sections.length}
          damping={0.1}
          maxSpeed={0.2}
        >
          <group position-y={-1}>
            <MotionConfig
              transition={{
                duration: 0.6,
              }}
            >
              <Experience />
            </MotionConfig>
          </group>
          <Scroll html>
            <Interface />
          </Scroll>
        </ScrollControls>
      </Canvas>
    </>
  );
}

export default App;

لتنسيق واجهة HTML الخاصة بنا، سنستخدم vanilla CSS لنكون أكثر عمومية ممكنة. يمكنك استخدام إطار عمل CSS المفضل لديك إذا كنت ترغب في ذلك. (لقد استخدمت TailwindCSS في معظم مشاريعي)

دعونا نضيف الأنماط الافتراضية إلى ملف index.css الخاص بنا:

@import url("https://fonts.googleapis.com/css2?family=Roboto+Slab:wght@400;700&display=swap");

:root {
  --primary-color: #4668ee;
  --text-color: #1a202c;
  --text-light-color: #555;
}

#root {
  width: 100vw;
  height: 100vh;
}

body {
  margin: 0;
  font-family: "Roboto Slab", serif;
}

/* ... */
.interface {
  width: 100vw;
  display: flex;
  flex-direction: column;
  align-items: center;
}

.sections {
  max-width: 1200px;
  width: 100%;
}

.section {
  height: 100vh;
  display: flex;
  justify-content: center;
  align-items: center;
}

.section--top {
  align-items: flex-start;
}

.section--bottom {
  align-items: flex-end;
}

.section--right {
  justify-content: flex-end;
}

.section--left {
  justify-content: flex-start;
}

لقد قمنا باستيراد خط Roboto Slab من Google Fonts وقمنا بتعريف بعض متغيرات الألوان.

يتم توسيط حاوية الأقسام وتحتوي على max-width بـ 1200px للحفاظ على قراءة جيدة على الشاشات الكبيرة.

الأقسام لها height بـ 100vh (ارتفاع كامل) ويتم توسيطها افتراضياً. سنستخدم الفئات section--top، section--bottom، section--right و section--left لتحديد موقع المحتوى داخل الأقسام.

واجهتنا جاهزة، دعونا نضيف المحتوى!

مؤشر التمرير للصفحة الرئيسية

في قسم الصفحة الرئيسية، سنضيف مؤشر تمرير لإخبار المستخدم بأنه يمكنه التمرير لرؤية الأقسام الأخرى.

أولاً، لنقم بإنشاء حالة لمعرفة ما إذا كان المستخدم قد قام بالتمرير:

import { useScroll } from "@react-three/drei";
import { useFrame } from "@react-three/fiber";
import { useState } from "react";

export const Interface = () => {
  const scrollData = useScroll();
  const [hasScrolled, setHasScrolled] = useState(false);
  useFrame(() => {
    setHasScrolled(scrollData.offset > 0);
  });
  // ...
};

ثم في قسم الصفحة الرئيسية، يمكننا إضافة motion.div مع كائن variants لإنشاء مؤشر تمرير متحرك:

// ...
import { motion } from "framer-motion";

export const Interface = () => {
  // ...
  return (
    <div className="interface">
      <div className="sections">
        {/* الصفحة الرئيسية */}
        <section className="section section--bottom">
          <motion.div
            className="scroll-down"
            initial={{
              opacity: 0,
            }}
            animate={{
              opacity: hasScrolled ? 0 : 1,
            }}
          >
            <motion.div
              className="scroll-down__wheel"
              initial={{
                translateY: 0,
              }}
              animate={{
                translateY: 4,
              }}
              transition={{
                duration: 0.4,
                repeatDelay: 0.5,
                repeatType: "reverse",
                repeat: Infinity,
              }}
            ></motion.div>
          </motion.div>
        </section>
        {/* ... */}
      </div>
    </div>
  );
};

نحن نستخدم framer motion لتحريك العتامة وموضع العجلة. لجعل العجلة تتحرك صعودًا وهبوطًا، نستخدم خصائص repeat وrepeatType.

Three.js logoReact logo

React Three Fiber: The Ultimate Guide to 3D Web Development

✨ You have reached the end of the preview ✨

Go to the next level with Three.js and React Three Fiber!

Get full access to this lesson and the complete course when you enroll:

  • 🔓 Full lesson videos with no limits
  • 💻 Access to the final source code
  • 🎓 Course progress tracking & completion
  • 💬 Invite to our private Discord community
Unlock the Full Course – Just $85

One-time payment. Lifetime updates included.