3Dポートフォリオ

Starter pack

インターフェース

3Dシーンがほぼ完成したので、HTMLインターフェースの作業を開始できます。

3Dシーンと同じ4つのセクションを持つInterface.jsxコンポーネントを作成しましょう:

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

section--bottomsection--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;
}

Google FontsからRoboto Slabフォントをインポートし、いくつかのカラー変数を定義しました。

セクションコンテナは中央に配置されており、大画面での可読性を保つためにmax-width1200pxに設定されています。

セクションのheight100vh (全高) でデフォルトでは中央に配置されています。section--topsection--bottomsection--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.divvariantsオブジェクトを追加して、アニメーションスクロールインジケーターを作成します:

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

framer motionを使用して、opacityとwheelの位置をアニメーションします。wheelを上下に動かすために、repeatrepeatTypeプロパティを使用します。

End of lesson preview

To get access to the entire lesson, you need to purchase the course.