Fundamentals
Core
Master
Shaders
VFX
Portafolio 3D
Interfaz
Ahora que tenemos nuestra escena 3D principalmente terminada, podemos empezar a trabajar en la interfaz HTML.
Vamos a crear un componente Interface.jsx
con las mismas 4 secciones que nuestra escena 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 las clases section--bottom
, section--right
y section--left
para posicionar el contenido dentro de las secciones.
Por el momento, solo hemos añadido los nombres de las secciones, agregaremos el contenido más tarde.
Vamos a agregar nuestro componente Interface
en el 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 nuestra interfaz HTML, usaremos CSS puro para ser lo más genéricos posible. Puedes usar tu framework de CSS favorito si lo deseas. (Yo usé TailwindCSS en la mayoría de mis proyectos)
Vamos a agregar los estilos predeterminados a nuestro archivo 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 la fuente Roboto Slab de Google Fonts y definimos algunas variables de colores.
El contenedor de las secciones está centrado y tiene un max-width
de 1200px
para mantener una buena legibilidad en pantallas grandes.
Las secciones tienen una height
de 100vh
(altura completa) y están centradas por defecto. Usaremos las clases section--top
, section--bottom
, section--right
y section--left
para posicionar el contenido dentro de las secciones.
¡Nuestra interfaz está lista, vamos a agregar el contenido!
Indicador de desplazamiento en la página de inicio
En la sección de inicio, añadiremos un indicador de desplazamiento para decirle al usuario que puede desplazarse para ver las otras secciones.
Primero, vamos a crear un estado para saber si el usuario ha hecho scroll:
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); }); // ... };
Luego, en la sección de inicio, podemos agregar un motion.div
con un objeto variants
para crear un indicador de desplazamiento animado:
// ... import { motion } from "framer-motion"; export const Interface = () => { // ... return ( <div className="interface"> <div className="sections"> {/* INICIO */} <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 la opacidad y la posición de la rueda. Para hacer que la rueda se mueva hacia arriba y hacia abajo, usamos las propiedades repeat
y repeatType
.
End of lesson preview
To get access to the entire lesson, you need to purchase the course.