Un hero 3D con React Three Fiber
Un hero 3D girando, en metal cepillado, sobre una página oscura y con tu nombre. Tardé minutos, no la tarde que había reservado. Lo sorprendente no es que se vea bien. Es que el 3D en la web dejó de ser cosa de especialistas y casi nadie se enteró.
Me senté a aprender Three.js contando con perder la tarde. Tenía un hero girando con mi nombre antes de que se enfriara el café. Esa distancia, entre lo que costaba el 3D y lo que cuesta ahora, es toda la historia. Las matemáticas de WebGL no se volvieron más fáciles. El andamiaje de alrededor desapareció.
La idea que lo desbloquea: un set de cine
Toda escena de Three.js son las mismas seis cosas. Cuando encajan, cualquier tutorial y cualquier fragmento que te dé Claude se leen claros, y un render roto pasa a ser un arreglo de diez segundos en vez de un misterio.
- Scene — el contenedor que sostiene todo. El set.
- Mesh — algo visible, hecho de una Geometry (la forma) más un Material (la superficie). El actor: cuerpo más vestuario.
- Light — sin luz, un material estándar es solo negro. Las luces del estudio.
- Camera — tu punto de vista y tu lente. Dónde te paras a mirar.
- Renderer — dibuja la escena y la cámara sobre un
<canvas>. La película. - El loop — redibuja cada cuadro para que las cosas se muevan. Hacer correr la cámara.
1. Lo mínimo que renderiza
Aquí está todo el modelo en un archivo, sin paso de build. Three.js viene directo de un CDN, así que esto corre con solo abrir la página. Fíjate en los seis sustantivos pasando en orden:
import * as THREE from 'three';
import { OrbitControls } from 'three/addons/controls/OrbitControls.js';
const scene = new THREE.Scene(); // 1. el set
const camera = new THREE.PerspectiveCamera(
50, innerWidth / innerHeight, 0.1, 100);
camera.position.set(0, 0, 4.5); // 2. dónde te paras Ver la escena completaVer menos
const renderer = new THREE.WebGLRenderer({ antialias: true, alpha: true });
renderer.setSize(innerWidth, innerHeight); // 3. la película
document.body.appendChild(renderer.domElement);
const knot = new THREE.Mesh( // 4. el actor
new THREE.TorusKnotGeometry(1, 0.32, 240, 32), // forma (geometry)
new THREE.MeshStandardMaterial({ // superficie (material)
color: 0x9aa0a6, metalness: 0.9, roughness: 0.22 })
);
scene.add(knot);
scene.add(new THREE.AmbientLight(0xffffff, 0.25)); // 5. las luces
const key = new THREE.DirectionalLight(0xffffff, 2.4);
key.position.set(3, 3, 4);
scene.add(key);
const controls = new OrbitControls(camera, renderer.domElement);
controls.autoRotate = true;
renderer.setAnimationLoop(() => { // 6. el loop
controls.update();
renderer.render(scene, camera);
}); Eso es. Monta el set, coloca al actor y las luces, para la cámara, corre el loop. Una pantalla en negro casi siempre es una de dos cosas: un material que necesita luz sin ninguna luz en la escena, o la cámara metida dentro del objeto. Agrega una luz, aleja la cámara y vuelve a mirar.
2. La misma escena en React Three Fiber
La versión vanilla es ideal para entender el modelo. Para una web real sobre
React o Astro, quieres React Three Fiber (R3F): el mismo Three.js por
debajo, pero la escena se escribe como componentes en vez de configuración
imperativa. La librería de ayudas drei te da cámaras, controles y
loaders gratis. Instálalos:
npx astro add react
npm i three @react-three/fiber @react-three/drei Y la escena de arriba se vuelve esto:
// Hero3D.jsx
import { Canvas } from '@react-three/fiber';
import { OrbitControls } from '@react-three/drei';
function Knot() {
return (
<mesh>
<torusKnotGeometry args={[1, 0.32, 240, 32]} />
<meshStandardMaterial color="#9aa0a6" metalness={0.9} roughness={0.22} />
</mesh>
);
} Ver el componente completoVer menos
export default function Hero3D() {
return (
<Canvas camera={{ position: [0, 0, 4.5], fov: 50 }}>
<ambientLight intensity={0.25} />
<directionalLight position={[3, 3, 4]} intensity={2.4} />
<Knot />
<OrbitControls autoRotate enablePan={false} />
</Canvas>
);
}
Léelo al lado del archivo vanilla y el cambio es obvio: el JSX es el
grafo de la escena. <mesh> envuelve una geometría y un material,
las luces son etiquetas, y no hay loop que cablear a mano. Ese es todo el
argumento para R3F una vez que estás en React.
3. Llévalo a tu web
En Astro, un canvas 3D tiene que correr en el navegador, así que renderiza el componente como una isla de cliente. Un import, una etiqueta:
---
import Hero3D from '../components/Hero3D.jsx';
---
<Hero3D client:only="react" /> client:only="react" le dice a Astro que se salte el render en el
servidor y lo arranque en el cliente, que es lo que necesita un canvas WebGL en
vivo. Estira el <Canvas> para que llene su contenedor, pon un
titular encima, y tienes un hero.
Qué cambió, y por qué esto tardó minutos
Reservé una tarde porque eso costaba antes el 3D en la web: pelear con el andamiaje, la pérdida de contexto y errores crípticos antes de ver nada. Nada de eso es ya la parte difícil.
- El andamiaje desapareció. Claude ya conoce toda la superficie de Three.js y R3F. Tú describes la escena, él escribe la configuración, ajustas hablando. La habilidad que queda es el modelo de seis sustantivos, para depurar lo que vuelve.
- WebGPU llegó, y por ahora puedes ignorarlo. Desde Three.js r171 el renderer WebGPU (más rápido) viene con fallback automático a WebGL, así que ~95% de los navegadores están cubiertos. Importa para escenas pesadas, partículas, miles de objetos. Para un hero, WebGL normal sobra. Que sepas que la palabra existe; no empieces por ahí.
La barrera del 3D nunca fueron los conceptos. Fue el andamiaje, y el andamiaje es justo lo que se automatizó.
Cuando algo se rompe
- Pantalla en negro. Sin luz más un
MeshStandardMaterial, o la cámara está dentro del objeto. Agrega unambientLighty aleja la cámara antes de tocar otra cosa. - "Failed to resolve module three". La versión vanilla necesita un import map, o te saltaste el npm install en la de R3F. Usa un camino o el otro, no la mitad de cada uno.
- El canvas sale en blanco en Astro pero bien suelto. Te faltó
client:only="react", así que intentó renderizar WebGL en el servidor. Agrégalo. - Renderiza y se congela. Algo lanza un error dentro del loop. Abre la consola del navegador; el error y la línea están ahí. Pégalo en Claude.
Ahora prueba esto
El hero gira. Unas formas de hacerlo tuyo, cada una una frase a Claude:
- Cambia la forma. Pide un icosaedro, un modelo
.glbcargado, o tu logo extruido en 3D. - Pon tu marca. Cambia el color del material y de las luces a tu paleta; una luz de contra fría se ve cara.
- Que reaccione al ratón. Haz que la forma se incline hacia el cursor en vez de girar sola.
- Mantenlo barato. Un mesh y dos luces va ligero en cualquier portátil. Guarda el renderer WebGPU para el día en que de verdad tengas miles de objetos.
Lo que acabas de hacer
Un elemento 3D real, en una página real, en lo que tardas en leer esto. Lo que importa no es Three.js ni R3F. Es que lo que hacía del 3D una especialidad, el andamiaje, es justo lo que la IA quitó. Los conceptos son pocos. La barrera era el trabajo, y el trabajo ya no está.
Déjame tu email y te aviso cuando salga el próximo build, con el código y los prompts que usé. Sin spam.
Más tutoriales ↗