Three.js 3D com Claude Code: guia prático para Web UI
Crie um viewer 3D com Claude Code e Three.js, incluindo resize, cleanup, revisão e casos reais.
Three.js torna o WebGL mais acessível, mas uma interface 3D pronta para produção não é apenas um objeto girando. Você também precisa cuidar de câmera, iluminação, tamanho do canvas, carga de GPU em celulares, limpeza de recursos e comportamento quando o modelo não carrega.
Claude Code ajuda porque consegue gerar rapidamente a base repetitiva de Three.js. O risco está em pedir algo vago, como “faça uma experiência 3D bonita”. Isso pode virar uma demo visualmente boa, mas sem resize correto, sem dispose ao desmontar ou pesada demais para dispositivos móveis.
Este guia mostra uma base Vite + React + Three.js que pode ser copiada e executada, além de prompts de revisão para usar Claude Code como revisor técnico antes de publicar.
Defina o objetivo do3D
Antes do código, defina o que o usuário precisa entender com a cena 3D. Em um viewer de produto, o objetivo pode ser conferir cor, material, parte traseira e sensação de escala. Em visualização de dados, pode ser enxergar agrupamentos, outliers ou movimento no tempo. Em uma cena educacional, o importante pode ser guiar a atenção para uma peça específica.
Um bom prompt para Claude Code contém restrições práticas.
Crie um viewer de produto 3D com Vite + React + TypeScript + three.
Requisitos:
- renderizar o canvas dentro de um elemento pai
- acompanhar o resize do contêiner
- permitir rotação e zoom com OrbitControls
- fazer dispose de geometry, material, renderer e controls no unmount
- limitar devicePixelRatio a 2 em celulares
- entregar código copiável em src/App.tsx
Essas restrições formam o harness, ou seja, a estrutura de apoio para o agente trabalhar com segurança. Elas evitam canvas em branco, cena esticada, renderer ativo após navegação e uso excessivo de GPU. Para conferir APIs, use a documentação oficial do Three.js e a página de WebGLRenderer.
Configuração mínima com Vite e React
Comece com Three.js direto dentro do React. React Three Fiber pode ser útil depois, mas a versão direta deixa claro o ciclo de vida: criar renderer, anexar ao DOM, escutar resize, animar e liberar recursos.
npm create vite@latest three-claude-demo -- --template react-ts
cd three-claude-demo
npm i three
npm run dev
flowchart LR
A["React component"] --> B["mount div"]
B --> C["WebGLRenderer canvas"]
C --> D["Scene"]
D --> E["Camera and lights"]
D --> F["Mesh and material"]
C --> G["OrbitControls"]
G --> H["resize and dispose"]
Viewer 3D copiável
Cole o código abaixo em src/App.tsx. Ele cria um objeto simples parecido com produto, adiciona luz e controles, acompanha o tamanho do contêiner e libera recursos do Three.js ao desmontar.
import { useEffect, useRef } from "react";
import * as THREE from "three";
import { OrbitControls } from "three/examples/jsm/controls/OrbitControls.js";
import "./App.css";
export default function App() {
const mountRef = useRef<HTMLDivElement | null>(null);
useEffect(() => {
const mount = mountRef.current;
if (!mount) return;
const scene = new THREE.Scene();
scene.background = new THREE.Color(0xf6f7fb);
const camera = new THREE.PerspectiveCamera(45, 1, 0.1, 100);
camera.position.set(3.5, 2.2, 4.5);
const renderer = new THREE.WebGLRenderer({ antialias: true });
renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2));
renderer.outputColorSpace = THREE.SRGBColorSpace;
renderer.shadowMap.enabled = true;
mount.appendChild(renderer.domElement);
const controls = new OrbitControls(camera, renderer.domElement);
controls.enableDamping = true;
controls.minDistance = 2.5;
controls.maxDistance = 8;
controls.target.set(0, 0.4, 0);
scene.add(new THREE.HemisphereLight(0xffffff, 0x7c8594, 1.6));
const keyLight = new THREE.DirectionalLight(0xffffff, 2.4);
keyLight.position.set(3, 5, 4);
keyLight.castShadow = true;
scene.add(keyLight);
const productGeometry = new THREE.BoxGeometry(1.8, 1.2, 1.1, 4, 4, 4);
const productMaterial = new THREE.MeshStandardMaterial({
color: 0x2f6f73,
roughness: 0.42,
metalness: 0.08,
});
const product = new THREE.Mesh(productGeometry, productMaterial);
product.castShadow = true;
product.position.y = 0.75;
scene.add(product);
const floorGeometry = new THREE.CircleGeometry(2.2, 64);
const floorMaterial = new THREE.MeshStandardMaterial({
color: 0xd9dee8,
roughness: 0.7,
});
const floor = new THREE.Mesh(floorGeometry, floorMaterial);
floor.rotation.x = -Math.PI / 2;
floor.receiveShadow = true;
scene.add(floor);
const resize = () => {
const width = mount.clientWidth;
const height = mount.clientHeight;
if (width === 0 || height === 0) return;
camera.aspect = width / height;
camera.updateProjectionMatrix();
renderer.setSize(width, height, false);
};
let frameId = 0;
const clock = new THREE.Clock();
const animate = () => {
const elapsed = clock.getElapsedTime();
product.rotation.y = elapsed * 0.45;
product.rotation.x = Math.sin(elapsed * 0.8) * 0.08;
controls.update();
renderer.render(scene, camera);
frameId = window.requestAnimationFrame(animate);
};
resize();
animate();
window.addEventListener("resize", resize);
return () => {
window.removeEventListener("resize", resize);
window.cancelAnimationFrame(frameId);
controls.dispose();
scene.traverse((object) => {
if (object instanceof THREE.Mesh) {
object.geometry.dispose();
const materials = Array.isArray(object.material)
? object.material
: [object.material];
materials.forEach((material) => material.dispose());
}
});
renderer.dispose();
renderer.domElement.remove();
};
}, []);
return (
<main className="viewerShell">
<div className="copy">
<p className="eyebrow">Three.js + Claude Code</p>
<h1>3D product viewer</h1>
<p>
Drag to rotate, scroll to zoom, and resize the window to verify that
the canvas follows its container.
</p>
</div>
<div ref={mountRef} className="viewerStage" />
</main>
);
}
Adicione este CSS em src/App.css. A altura de .viewerStage é essencial; sem ela, o canvas pode existir, mas parecer uma tela branca.
body {
margin: 0;
font-family: Inter, system-ui, sans-serif;
background: #eef2f7;
color: #17202a;
}
.viewerShell {
min-height: 100vh;
display: grid;
grid-template-columns: minmax(260px, 0.8fr) minmax(320px, 1.2fr);
gap: 32px;
align-items: center;
padding: 40px;
box-sizing: border-box;
}
.copy {
max-width: 520px;
}
.viewerStage {
height: min(62vh, 560px);
min-height: 360px;
border: 1px solid #ccd5df;
background: #f6f7fb;
}
.viewerStage canvas {
display: block;
}
@media (max-width: 760px) {
.viewerShell {
grid-template-columns: 1fr;
padding: 24px;
}
.viewerStage {
min-height: 300px;
}
}
Use Claude Code como revisor
Depois da primeira versão, peça uma revisão de risco, não apenas um refinamento visual.
Revise esta implementação React + Three.js.
Verifique:
1. se o canvas acompanha o tamanho do contêiner
2. se geometry, material, renderer e controls são liberados no unmount
3. se requestAnimationFrame é interrompido
4. se devicePixelRatio é seguro para telas móveis densas
5. se window/document quebrariam SSR em Next.js ou Astro
6. se câmera, luzes e controles ajudam a inspecionar o produto
Retorne diffs concretos e uma checklist de teste manual.
Esse prompt transforma Claude Code em revisor técnico. Vazamentos de recursos não aparecem em uma captura de tela, então navegue algumas vezes e observe Memory e Performance no DevTools.
Três casos de uso práticos
| Caso | Por que usar 3D | O que pedir ao Claude Code |
|---|---|---|
| Viewer de produto | Cliente vê cor, acabamento, profundidade e parte traseira | OrbitControls, variações de cor, luzes, teste móvel |
| Visualização de dados | Grupos, outliers e movimento temporal ficam visíveis | nuvens de pontos, barras 3D, transições de câmera, legendas |
| Portfólio ou educação | Uma estrutura pode ser manipulada e explicada | labels, destaque de partes, posições guiadas de câmera |
No produto, o 3D deve reduzir dúvidas de compra. Nos dados, ele deve ajudar a comparar; se a perspectiva atrapalhar, mantenha uma visão 2D. Em educação, não basta rotação livre: use sequência, rótulos e pausas na animação.
Falhas comuns e correções
| Falha | Causa provável | Correção |
|---|---|---|
| Canvas em branco | altura do pai é zero, câmera aponta errado ou não há luz | defina altura CSS, revise camera position e controls target |
| Cena distorcida após resize | camera.aspect e renderer size não são atualizados juntos | chame camera.updateProjectionMatrix() e renderer.setSize() |
| Página fica lenta após navegação | recursos Three.js não foram liberados | percorra a scene no unmount e faça dispose |
| Celular esquenta | pixelRatio alto, sombras caras ou modelo denso | limite pixelRatio, reduza sombras e segmentos |
| Erro em SSR | acesso a window/document durante render do servidor | inicialize dentro de useEffect ou componente client-only |
Para depurar canvas em branco, simplifique: fundo claro, cubo, uma luz e câmera conhecida. Não investigue GLB, HDR, pós-processamento e layout ao mesmo tempo.
Checklist de publicação e CTA
Antes de publicar, teste no celular mais fraco que você precisa suportar. Confira fps, temperatura, tamanho do modelo, fallback se WebGL falhar e explicação alternativa para quem não interage com o canvas. Para arquitetura de canvas, veja o guia de Canvas com Claude Code. Para movimento, leia o guia de animação com Claude Code.
Claude Code Lab pode ajudar na revisão de viewers 3D de produto, visualizações WebGL e cenas educacionais, além de treinar equipes em prompts de revisão. Leve para a conversa os dispositivos alvo, framework, formato do modelo, orçamento de performance e motivo de negócio para usar 3D.
Resultado testado
Colei o código em um projeto Vite React TypeScript e testei larguras de desktop e celular. A altura explícita de .viewerStage evitou o canvas em branco. O limite de devicePixelRatio em 2 reduziu trabalho desnecessário da GPU em telas densas, e a revisão de dispose com Claude Code ajudou a encontrar riscos antes da publicação.
PDF grátis: cheatsheet do Claude Code
Informe seu e-mail e baixe uma página com comandos, hábitos de revisão e workflows seguros.
Cuidamos dos seus dados e não enviamos spam.
Sobre o autor
Masa
Engenheiro focado em workflows práticos com Claude Code.
Artigos relacionados
Workflow Obsidian para CLAUDE.md com Claude Code
Transforme notas de trabalho do Obsidian em notas operacionais CLAUDE.md para preservar contexto.
Claude Code Revenue CTA Routing: artigos para PDF, Gumroad e consultoria
Um fluxo com Claude Code para levar leitores ao PDF grátis, Gumroad ou consultoria conforme intenção.
Regras de handoff para equipes com Claude Code: evidências, permissões, rollback e receita
Formato prático para entregar trabalho do Claude Code com prova, permissões, rollback, PDF grátis, Gumroad e consultoria.