Three.js 3D avec Claude Code : guide pratique Web UI
Créez un viewer 3D avec Claude Code et Three.js, avec resize, cleanup, revue technique et cas d'usage.
Three.js rend WebGL plus accessible, mais une interface 3D prête pour la production n’est pas seulement un objet qui tourne. Il faut aussi gérer la caméra, la lumière, la taille du canvas, la charge GPU sur mobile, le nettoyage des ressources et le comportement quand un modèle ne se charge pas.
Claude Code est très utile pour générer cette base rapidement. Le risque est de demander seulement “fais une scène 3D élégante”. On obtient alors souvent une démo séduisante, mais pas forcément un composant robuste : canvas blanc après un changement de layout, fuite mémoire après navigation, ou scène trop lourde pour un téléphone.
Ce guide montre une base Vite + React + Three.js copiable, puis les consignes de revue à donner à Claude Code avant publication.
Définir le rôle du 3D
Avant le code, il faut définir ce que l’utilisateur doit comprendre grâce au 3D. Pour un viewer produit, il peut s’agir de la couleur, de la texture, du dos de l’objet ou de l’impression d’échelle. Pour une visualisation de données, l’objectif peut être de voir des groupes, des valeurs atypiques ou une évolution temporelle. Pour une scène éducative, il faut souvent guider l’attention vers une pièce précise.
Un bon prompt pour Claude Code contient des contraintes concrètes.
Crée un viewer produit 3D avec Vite + React + TypeScript + three.
Contraintes:
- rendre le canvas dans un élément parent, pas dans document.body
- suivre la taille du conteneur
- activer rotation et zoom avec OrbitControls
- disposer geometry, material, renderer et controls au démontage
- limiter devicePixelRatio à 2 sur mobile
- fournir un code copiable dans src/App.tsx
Ces contraintes forment le harness, c’est-à-dire l’échafaudage qui aide l’agent à travailler sans casser l’application. Elles évitent les problèmes classiques : canvas blanc, image déformée, renderer encore actif après navigation et surcharge GPU. Pour vérifier les API, utilisez la documentation officielle Three.js et la page WebGLRenderer.
Mise en place Vite/React minimale
Commencez avec Three.js directement dans React. React Three Fiber peut être excellent, mais voir le cycle de vie brut aide à comprendre les erreurs : créer le renderer, l’ajouter au DOM, écouter resize, animer, puis libérer les ressources.
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 copiable
Collez ce code dans src/App.tsx. Il crée un objet de démonstration, ajoute lumière et contrôle caméra, suit la taille du conteneur et nettoie les ressources Three.js lors du démontage.
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>
);
}
Ajoutez ce CSS dans src/App.css. La hauteur du conteneur est essentielle : sans elle, le canvas peut exister mais rester invisible.
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;
}
}
Demander une revue à Claude Code
Après l’implémentation, demandez une revue orientée risques.
Relis cette implémentation React + Three.js.
Vérifie:
1. le canvas suit bien la taille du conteneur
2. geometry, material, renderer et controls sont libérés au démontage
3. requestAnimationFrame est arrêté
4. devicePixelRatio reste raisonnable sur mobile
5. window/document ne cassent pas SSR dans Next.js ou Astro
6. caméra, lumières et contrôles servent vraiment l'inspection produit
Retourne des diffs précis et une checklist de test manuel.
Cette revue est utile car les fuites de ressources ne se voient pas toujours à l’écran. Naviguez plusieurs fois, puis regardez Memory et Performance dans DevTools.
Trois cas d’usage utiles
| Cas | Pourquoi utiliser la 3D | Travail à demander à Claude Code |
|---|---|---|
| Viewer produit | Vérifier couleur, finition, volume et faces cachées | OrbitControls, variantes, lumières, test mobile |
| Visualisation de données | Montrer groupes, anomalies ou mouvements temporels | nuage de points, barres 3D, transitions caméra, légendes |
| Portfolio ou éducation | Expliquer une structure avec un modèle manipulable | labels, surbrillance des pièces, vues guidées |
Pour un produit, la 3D doit réduire l’hésitation d’achat. Pour les données, elle doit améliorer la lecture, sinon une vue 2D reste nécessaire. Pour l’éducation, la liberté de rotation ne suffit pas : prévoyez une séquence, des labels et des positions de caméra.
Erreurs fréquentes et corrections
| Erreur | Cause probable | Correction |
|---|---|---|
| Canvas blanc | hauteur parent nulle, caméra mal placée, manque de lumière | fixer la hauteur CSS, vérifier camera position et controls target |
| Image déformée après resize | camera.aspect et renderer size ne sont pas mis à jour ensemble | appeler camera.updateProjectionMatrix() et renderer.setSize() |
| Page plus lente après navigation | dispose manquant sur resources Three.js | parcourir la scene au démontage et libérer geometry/material |
| Mobile qui chauffe | pixel ratio élevé, ombres chères, modèle trop dense | limiter pixelRatio, réduire ombres et segments |
| Crash SSR | accès à window/document pendant le rendu serveur | initialiser dans useEffect ou un composant client-only |
Pour déboguer un écran blanc, revenez à un cube, une lumière et un fond clair. Ne mélangez pas en même temps GLB, HDR, post-traitement et problème de layout.
Publication et accompagnement
Avant publication, testez le téléphone le plus faible que vous devez supporter. Vérifiez fps, température, taille du modèle, image de secours si WebGL échoue et texte alternatif pour comprendre la scène. Pour l’architecture canvas, consultez le guide Canvas avec Claude Code. Pour le mouvement, lisez aussi le guide animation avec Claude Code.
Claude Code Lab peut accompagner la revue de viewers produit 3D, de visualisations WebGL et de scènes éducatives, ou former une équipe aux prompts de revue. Préparez les appareils cibles, le framework, le format des modèles, le budget de performance et la raison métier de la 3D.
Résultat testé
J’ai collé le code dans un projet Vite React TypeScript, puis testé les tailles desktop et mobile. La hauteur explicite de .viewerStage évite le canvas blanc. La limite devicePixelRatio à 2 réduit le travail GPU inutile sur écrans denses. La revue de Claude Code sur le chemin de dispose aide aussi à repérer les fuites avant de considérer la démo publiable.
PDF gratuit: cheatsheet Claude Code
Saisissez votre email et téléchargez une page avec commandes, habitudes de review et workflow sûr.
Nous protégeons vos données et n'envoyons pas de spam.
À propos de l'auteur
Masa
Ingénieur spécialisé dans les workflows pratiques avec Claude Code.
Articles liés
Workflow Obsidian vers CLAUDE.md avec Claude Code
Transformer des notes Obsidian en notes CLAUDE.md concises pour reprendre les sessions sans réexpliquer.
Claude Code Revenue CTA Routing : relier articles, PDF, Gumroad et consultation
Un workflow Claude Code pour orienter les lecteurs vers PDF gratuit, Gumroad ou consultation selon l'intention.
Règles de handoff Claude Code en équipe: preuves, permissions, rollback et revenus
Un format concret pour transmettre un travail Claude Code avec preuves, permissions, rollback, PDF gratuit, Gumroad et consultation.