Portofolio 3D

Starter pack

Antarmuka

Sekarang setelah kita menyelesaikan sebagian besar adegan 3D kita, kita bisa mulai mengerjakan antarmuka HTML.

Mari kita buat komponen Interface.jsx dengan 4 bagian yang sama seperti adegan 3D kita:

export const Interface = () => {
  return (
    <div className="interface">
      <div className="sections">
        {/* HOME */}
        <section className="section section--bottom">HOME</section>
        {/* SKILLS */}
        <section className="section section--right">SKILLS</section>
        {/* PROJECTS */}
        <section className="section section--left">PROJECTS</section>
        {/* CONTACT */}
        <section className="section section--left">CONTACT</section>
      </div>
    </div>
  );
};

Kita akan menggunakan kelas section--bottom, section--right, dan section--left untuk memposisikan konten di dalam bagian-bagian tersebut.

Untuk saat ini kita hanya menambahkan nama bagian-bagiannya, kita akan menambahkan konten nanti.

Mari tambahkan komponen Interface kita ke dalam komponen 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;

Untuk menata antarmuka HTML kita, kita akan menggunakan vanilla CSS agar lebih umum. Anda dapat menggunakan framework CSS favorit Anda jika Anda mau. (Saya menggunakan TailwindCSS pada sebagian besar proyek saya)

Mari tambahkan gaya default ke file index.css kita:

@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;
}

Kami mengimpor font Roboto Slab dari Google Fonts dan mendefinisikan beberapa variabel warna.

Kontainer bagian-bagian berada di tengah dan memiliki max-width sebesar 1200px untuk menjaga keterbacaan yang baik pada layar besar.

Bagian-bagian memiliki height sebesar 100vh (tinggi penuh) dan berada di tengah secara default. Kita akan menggunakan kelas section--top, section--bottom, section--right, dan section--left untuk memposisikan konten di dalam bagian-bagian tersebut.

Antarmuka kita sudah siap, mari tambahkan kontennya!

Indikator Gulir Home

Pada bagian home, kita akan menambahkan indikator gulir untuk memberitahu pengguna bahwa mereka dapat menggulir untuk melihat bagian lainnya.

Pertama, mari kita buat state untuk mengetahui apakah pengguna sudah menggulir:

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);
  });
  // ...
};

Kemudian di bagian home, kita dapat menambahkan motion.div dengan objek variants untuk membuat indikator gulir yang animatif:

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

export const Interface = () => {
  // ...
  return (
    <div className="interface">
      <div className="sections">
        {/* HOME */}
        <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>
  );
};

Kami menggunakan framer motion untuk menganimasikan opasitas dan posisi roda. Untuk membuat roda bergerak ke atas dan ke bawah, kami menggunakan properti repeat dan 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.