Fundamentals
Core
Master
Shaders
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.