Um hero 3D com React Three Fiber
Um hero 3D girando, em metal escovado, numa página escura, com o seu nome de marca. Levou minutos, não a tarde inteira que eu tinha reservado. A surpresa não é que fica bonito. É que o 3D na web deixou de ser o suplício de um especialista, e quase ninguém reparou.
Sentei para aprender Three.js esperando perder uma tarde nisso. Eu tinha um hero renderizado e girando, com meu nome, antes de o café esfriar. Essa distância, entre o que o 3D custava e o que custa agora, é a história inteira. A matemática do WebGL não ficou mais fácil. O suplício em volta dela foi apagado.
A ideia que destrava tudo: um set de filmagem
Toda cena de Three.js são as mesmas seis coisas. Quando elas encaixam na cabeça, todo tutorial e todo trecho que o Claude te entrega ficam fáceis de ler, e um render quebrado vira um conserto de dez segundos em vez de um mistério.
- Scene — o contêiner que segura tudo. O set.
- Mesh — uma coisa visível, feita de uma Geometry (a forma) mais um Material (a superfície). O ator: corpo mais figurino.
- Light — sem ela, um material padrão é só preto. As luzes do estúdio.
- Camera — seu ponto de vista e a lente. De onde você olha.
- Renderer — desenha a cena e a câmera num
<canvas>. O filme. - O loop — redesenha a cada quadro para que as coisas se mexam. Rodando a câmera.
1. A menor coisa que renderiza
Aqui está o modelo inteiro num arquivo só, sem etapa de build. O Three.js vem direto de uma CDN, então isso roda só abrindo a página. Repare nos seis substantivos passando em ordem:
import * as THREE from 'three';
import { OrbitControls } from 'three/addons/controls/OrbitControls.js';
const scene = new THREE.Scene(); // 1. o cenário
const camera = new THREE.PerspectiveCamera(
50, innerWidth / innerHeight, 0.1, 100);
camera.position.set(0, 0, 4.5); // 2. onde você fica Mostrar a cena completaMostrar menos
const renderer = new THREE.WebGLRenderer({ antialias: true, alpha: true });
renderer.setSize(innerWidth, innerHeight); // 3. o filme
document.body.appendChild(renderer.domElement);
const knot = new THREE.Mesh( // 4. o ator
new THREE.TorusKnotGeometry(1, 0.32, 240, 32), // forma (geometria)
new THREE.MeshStandardMaterial({ // superfície (material)
color: 0x9aa0a6, metalness: 0.9, roughness: 0.22 })
);
scene.add(knot);
scene.add(new THREE.AmbientLight(0xffffff, 0.25)); // 5. luzes
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. o loop
controls.update();
renderer.render(scene, camera);
}); É isso. Monte o set, posicione o ator e as luzes, coloque a câmera, rode o loop. Uma tela preta quase sempre quer dizer uma de duas coisas: um material que precisa de luz, sem luz nenhuma na cena, ou a câmera parada dentro do objeto. Adicione uma luz, puxe a câmera para trás e olhe de novo.
2. A mesma cena em React Three Fiber
A versão vanilla é ótima para entender o modelo. Para um site de verdade num stack
React ou Astro, você quer React Three Fiber (R3F): o mesmo Three.js por
baixo, mas a cena escrita como componentes em vez de configuração imperativa. A
biblioteca auxiliar drei te entrega câmeras, controles e loaders de
graça. Instale tudo:
npx astro add react
npm i three @react-three/fiber @react-three/drei Aí a cena exata de cima vira isto:
// 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>
);
} Mostrar o componente completoMostrar 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>
);
}
Leia lado a lado com o arquivo vanilla e a troca fica óbvia: o JSX é o
grafo da cena. <mesh> envolve uma geometria e um material, as
luzes são tags, e não há loop manual para conectar. Esse é o argumento inteiro a
favor do R3F quando você já está em React.
3. Coloque no seu site
No Astro, um canvas 3D tem que rodar no navegador, então renderize o componente como uma ilha de cliente. Um import, uma tag:
---
import Hero3D from '../components/Hero3D.jsx';
---
<Hero3D client:only="react" /> client:only="react" diz ao Astro para pular a renderização no servidor
e iniciar o componente no cliente, que é o que um canvas WebGL ao vivo precisa.
Estilize o <Canvas> para preencher o contêiner, jogue um título
por cima e você tem um hero.
O que mudou, e por que isso levou minutos
Reservei uma tarde porque era o que o 3D na web custava: brigar com boilerplate, perda de contexto e erros crípticos antes de qualquer coisa aparecer. Nada disso é mais a parte difícil.
- O boilerplate acabou. O Claude já conhece toda a superfície do Three.js e do R3F. Você descreve a cena, ele escreve a configuração, você ajusta conversando. A habilidade que sobra é o modelo dos seis substantivos, para você conseguir depurar o que volta.
- O WebGPU chegou, e dá para ignorar por enquanto. Desde o Three.js r171 o renderer WebGPU, mais rápido, vem com um fallback automático para WebGL, então ~95% dos navegadores estão cobertos. Importa para cenas pesadas, partículas, milhares de objetos. Para um hero, WebGL puro está ótimo. Saiba que a palavra existe, mas não comece por ela.
O fosso em volta do 3D nunca foram os conceitos. Era o suplício, e o suplício é justamente a parte que foi automatizada.
Quando algo quebra
- Tela preta. Falta de luz com um
MeshStandardMaterial, ou a câmera está dentro do objeto. Adicione umambientLighte afaste a câmera antes de mexer em qualquer outra coisa. - "Failed to resolve module three". A versão vanilla precisa de um import map, ou você pulou o npm install na versão R3F. Use um caminho ou o outro, não metade de cada.
- O canvas fica em branco no Astro mas funciona sozinho. Você esqueceu o
client:only="react", então ele tentou renderizar WebGL no servidor. Adicione. - Renderiza e depois congela. Algo dispara um erro dentro do loop. Abra o console do navegador; o erro e a linha estão ali. Cole no Claude.
Agora tente isto
O hero gira. Algumas formas de deixar a sua cara, cada uma uma frase para o Claude:
- Troque a forma. Peça um icosaedro, um modelo
.glbcarregado, ou seu logo extrudado em 3D. - Combine com sua marca. Mude a cor do material e as cores das luzes para a sua paleta; uma luz de contorno fria passa uma sensação de algo caro.
- Reaja ao mouse. Faça a forma inclinar em direção ao cursor em vez de girar sozinha.
- Mantenha leve. Um mesh e duas luzes ficam leves em qualquer laptop. Guarde o renderer WebGPU para o dia em que você de fato tiver milhares de objetos.
O que você acabou de fazer
Um elemento 3D de verdade, numa página de verdade, no tempo que leva para ler isto. O que importa não é Three.js nem R3F. É que a coisa que fazia do 3D uma especialidade, o suplício da configuração, é a coisa que a IA removeu. Os conceitos são pequenos. A barreira era o trabalho braçal, e o trabalho braçal acabou.
Deixe seu email e eu te aviso quando o próximo build sair, com o código e os prompts que usei. Sem spam.
Mais tutoriais ↗