Use Cases (Atualizado: 02/06/2026)

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 3D com Claude Code: guia prático para Web UI

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

CasoPor que usar 3DO que pedir ao Claude Code
Viewer de produtoCliente vê cor, acabamento, profundidade e parte traseiraOrbitControls, variações de cor, luzes, teste móvel
Visualização de dadosGrupos, outliers e movimento temporal ficam visíveisnuvens de pontos, barras 3D, transições de câmera, legendas
Portfólio ou educaçãoUma estrutura pode ser manipulada e explicadalabels, 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

FalhaCausa provávelCorreção
Canvas em brancoaltura do pai é zero, câmera aponta errado ou não há luzdefina altura CSS, revise camera position e controls target
Cena distorcida após resizecamera.aspect e renderer size não são atualizados juntoschame camera.updateProjectionMatrix() e renderer.setSize()
Página fica lenta após navegaçãorecursos Three.js não foram liberadospercorra a scene no unmount e faça dispose
Celular esquentapixelRatio alto, sombras caras ou modelo densolimite pixelRatio, reduza sombras e segmentos
Erro em SSRacesso a window/document durante render do servidorinicialize 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.

#Claude Code #Three.js #3D #WebGL #frontend
Grátis

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.

Masa

Sobre o autor

Masa

Engenheiro focado em workflows práticos com Claude Code.