Fundamentals
Core
Master
Shaders
Portfólio 3D
Interface
Agora que temos a nossa cena 3D principalmente concluída, podemos começar a trabalhar na interface HTML.
Vamos criar um componente Interface.jsx
com as mesmas 4 seções da nossa cena 3D:
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> ); };
Usaremos as classes section--bottom
, section--right
e section--left
para posicionar o conteúdo dentro das seções.
Por enquanto, apenas adicionamos os nomes das seções, adicionaremos o conteúdo mais tarde.
Vamos adicionar o nosso componente Interface
no componente 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;
Para estilizar nossa interface HTML, usaremos vanilla CSS para ser o mais genérico possível. Você pode usar seu framework CSS favorito, se preferir. (Utilizei TailwindCSS na maioria dos meus projetos)
Vamos adicionar os estilos padrão ao nosso arquivo 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; }
Importamos a fonte Roboto Slab do Google Fonts e definimos algumas variáveis de cores.
O contêiner das seções é centralizado e tem uma max-width
de 1200px
para manter uma boa legibilidade em telas grandes.
As seções têm uma height
de 100vh
(altura total) e são centralizadas por padrão. Usaremos as classes section--top
, section--bottom
, section--right
e section--left
para posicionar o conteúdo dentro das seções.
Nossa interface está pronta, vamos adicionar o conteúdo!
Indicador de rolagem na home
Na seção inicial, vamos adicionar um indicador de rolagem para informar ao usuário que ele pode rolar a página para ver as outras seções.
Primeiro, vamos criar um estado para saber se o usuário rolou a página:
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); }); // ... };
Em seguida, na seção inicial, podemos adicionar um motion.div
com um objeto variants
para criar um indicador de rolagem animado:
// ... import { motion } from "framer-motion"; export const Interface = () => { // ... return ( <div className="interface"> <div className="sections"> {/* INÍCIO */} <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> ); };
Estamos usando framer motion para animar a opacidade e a posição da roda. Para fazer a roda mover para cima e para baixo, usamos as propriedades repeat
e repeatType
.
End of lesson preview
To get access to the entire lesson, you need to purchase the course.