Sommaire
- Pourquoi le 3D web a basculé en 2026
- Three.js r184 : le moteur historique
- React Three Fiber v9 : le 3D déclaratif
- WebGPU : la nouvelle API graphique standard
- TSL : un seul langage de shader pour deux mondes
- La stack moderne d’une scène 3D web
- Architecture type d’une application R3F
- Concepts mathématiques à maîtriser
- Les tutoriels de cette série
- Erreurs fréquentes à éviter
- FAQ
- Ressources officielles
Pourquoi le 3D web a basculé en 2026
En septembre 2025, Apple a livré WebGPU dans Safari 26 sur macOS Tahoe 26, iOS 26, iPadOS 26 et visionOS 26. Cette annonce, faite à la WWDC 25 puis confirmée dans les notes WebKit officielles, fait tomber le dernier verrou : Chrome, Edge, Firefox et Safari activent désormais WebGPU par défaut sur leurs canaux stables. La page Implementation Status du groupe de travail W3C confirme le statut « shipped » pour les quatre moteurs. C’est un événement comparable au déploiement de WebGL en 2011, à ceci près qu’aujourd’hui il n’y a plus de moteur retardataire à attendre.
Pour un développeur frontend, le calcul a changé. Pendant dix ans, faire du 3D performant sur le web supposait de composer avec WebGL 2, hérité d’OpenGL ES 3.0, et de subir ses limitations : pas de compute shader, gestion d’état globale fragile, parallélisme CPU/GPU médiocre. WebGPU, conçu pour exposer Vulkan, Metal et Direct3D 12 sous une API unique, lève ces verrous. Compute shaders, command encoders explicites, ressources liées par groupes : on parle enfin au GPU comme une console le fait depuis quinze ans.
L’autre événement de 2026 est la maturation de l’écosystème Three.js. La série de releases a livré r171 en septembre 2025 avec un WebGPURenderer prêt pour la production, puis r181, r182, r183 et r184 (16 avril 2026) avec à chaque fois des améliorations TSL, des correctifs WebGPU et un nettoyage progressif des API héritées de WebGL. La bibliothèque React Three Fiber a suivi avec sa version 9, dont le guide de migration formalise le passage à un Canvas asynchrone, indispensable pour initialiser un WebGPURenderer.
Concrètement, en 2026 vous pouvez livrer une scène 3D qui exploite la GPU moderne, fonctionne sur iPhone et MacBook, et continue de tourner sur un Chrome 2023 grâce au repli automatique vers WebGL 2. C’est le scénario que cette série explore pas à pas.
Three.js r184 : le moteur historique
Three.js, créé par Ricardo Cabello (mrdoob) en 2010, reste le moteur 3D web de référence. Il abstrait WebGL et WebGPU derrière des concepts familiers — Scene, Camera, Mesh, Material, Geometry — et fournit tout l’arsenal nécessaire à une production graphique sérieuse : chargement glTF, animation skeletale, post-processing, shadow mapping, environnement HDRI, raycasting.
La rupture technique de Three.js depuis r171 est la coexistence des deux renderers. Le WebGLRenderer historique reste là, parfaitement maintenu. Le WebGPURenderer vit en parallèle, avec une initialisation asynchrone explicite qui se fait via la méthode renderer.init(). La documentation officielle WebGPURenderer détaille la procédure : on instancie, on attend l’initialisation, puis on l’utilise comme un renderer classique. Le détail intéressant est que les notes communautaires de migration rapportent qu’à partir de r171 il n’y a plus besoin de configuration bundler particulière, plus de polyfill : le moteur détecte le contexte disponible et fait son travail.
Côté matériaux, la grande nouveauté est l’arrivée des node materials. Plutôt que d’écrire un fragment shader GLSL à la main, on compose un graphe de nœuds en JavaScript. Ce graphe peut être compilé en WGSL pour WebGPU, ou en GLSL pour WebGL 2. C’est la base de TSL.
React Three Fiber v9 : le 3D déclaratif
React Three Fiber, maintenu par Poimandres (pmndrs), est un renderer React qui mappe l’arbre Three.js sur du JSX. La version 9, sortie début 2026, introduit plusieurs ruptures qu’il faut connaître avant de démarrer.
D’abord, le Canvas accepte désormais une fonction gl asynchrone qui retourne une promesse. C’est la conséquence directe de WebGPU, dont l’initialisation passe par navigator.gpu.requestAdapter() puis adapter.requestDevice() — deux promesses successives. Sans support asynchrone du Canvas, impossible d’instancier proprement un WebGPURenderer. Cette capacité est documentée explicitement dans le guide de migration v9 et reste la rupture principale à connaître.
Ensuite, R3F v9 a clarifié son contrat de types : les exports historiques comme MeshProps ont été retirés et fusionnés dans ThreeElement, et la prop Props a été renommée CanvasProps. Le StrictMode de React 18 et 19 est maintenant pleinement supporté, ce qui révèle au passage les fuites de ressources Three.js qui pouvaient passer inaperçues en v8.
La branche v10, en alpha au moment de la rédaction, va plus loin et introduit la propriété state.renderer en remplacement de state.gl ainsi qu’une famille de hooks dédiés à TSL. Tant que vous restez en v9 stable — ce que recommande la documentation pour la production en 2026 —, la propriété s’appelle toujours state.gl, et les hooks TSL ne sont pas encore disponibles. Vous trouverez les détails de la pré-version v10 dans les notes v10.0.0-alpha du dépôt pmndrs.
WebGPU : la nouvelle API graphique standard
WebGPU est défini par le W3C WebGPU Specification publié comme Candidate Recommendation en 2024 puis affiné depuis. L’API expose, côté JavaScript, des objets qui correspondent directement aux concepts modernes des GPU : adapter (la carte physique), device (la session logique), command encoder (la file de commandes), bind group (le regroupement de ressources), pipeline (l’état complet d’un rendu).
Ce qui change pour le développeur web est triple. D’abord, les compute shaders sont disponibles. On peut faire du calcul GPU général : simulation de particules, post-processing avancé, inférence de modèles ML directement dans le navigateur via web-llm ou des bibliothèques équivalentes. Ensuite, les performances sont meilleures : moins d’overhead côté JS, parallélisme accru, meilleur usage de la mémoire vidéo. Enfin, l’API est explicite : on déclare ses ressources, on les binde, on les exécute. Plus de magie globale comme en OpenGL/WebGL.
Le langage de shader natif de WebGPU est WGSL (WebGPU Shading Language). C’est un langage récent, inspiré de Rust et du HLSL Microsoft, conçu pour être compilé efficacement vers SPIR-V (Vulkan), MSL (Metal) et HLSL (D3D12). Il est documenté dans la spécification WGSL du W3C. WGSL est puissant mais verbeux ; c’est précisément pourquoi TSL existe.
TSL : un seul langage de shader pour deux mondes
TSL signifie Three Shading Language. Ce n’est pas un nouveau langage compilé : c’est une API JavaScript dans laquelle on compose des nœuds (positions, uniforms, opérations mathématiques, textures), et le compilateur Three.js produit soit du WGSL pour WebGPU, soit du GLSL ES 3.0 pour WebGL 2 selon le renderer actif.
L’intérêt est massif. Vous écrivez votre shader une fois, en JavaScript, avec autocomplete, typage et debugging dans votre IDE. Trois lignes de TSL remplacent un fichier .glsl séparé, avec sa boilerplate, ses includes et son pipeline de build. La documentation TSL officielle recense la centaine de nœuds disponibles : positionLocal, normalLocal, uv, time, texture, mix, step, etc.
Un point crucial pour qui démarre : les noms de méthodes évoluent encore d’une release à l’autre. La release r178, par exemple, a renommé label() en setName(), et r183 a renommé PostProcessing en RenderPipeline. Avant de copier un snippet trouvé sur un blog, vérifier la version Three.js de l’auteur et confronter aux notes de migration officielles.
La stack moderne d’une scène 3D web
Une stack typique en 2026 pour un projet sérieux ressemble à ceci. Le bundler est Vite 5 ou 6, qui gère ESM natif et le HMR rapide indispensable au shader work. Le runtime est Node.js 22 LTS (codename Jod), supporté jusqu’en avril 2027 selon la page de support Node.js. Le moteur 3D est Three.js r184 ou supérieur. Le binding React est @react-three/fiber v9.x. Les helpers viennent de @react-three/drei et, pour le post-processing, on bascule sur les nœuds TSL natifs de Three.js plutôt que sur @react-three/postprocessing dès qu’on cible WebGPU — c’est ce que confirme la checklist de migration utsubo.com.
Pour les modèles 3D, le format est glTF 2.0 (spécification Khronos), idéalement compressé via Draco pour la géométrie ou Meshopt pour le streaming. Pour les textures, on privilégie le format KTX2 avec compression Basis Universal, qui se transcode à la volée vers le format supporté par le GPU cible (BC7, ASTC, ETC2). C’est plus léger que du PNG et plus rapide à uploader sur le GPU.
Pour les animations, deux écoles cohabitent. react-spring/three reste excellent pour les transitions physiques courtes. Theatre.js excelle dans les animations cinématiques scénarisées avec son éditeur visuel intégré. Les deux fonctionnent en R3F v9.
Architecture type d’une application R3F
Au-delà des outils, une scène 3D web qui passe en production a besoin d’une architecture lisible. La pratique convergente, observable dans les projets Poimandres et dans les démos officielles, distingue trois couches dans le code React.
La première couche est la scène statique. C’est la déclaration JSX des objets 3D, importée depuis des fichiers .tsx dédiés (un fichier par sous-scène ou par modèle complexe). Ces fichiers ne contiennent pas de logique d’animation : juste les <mesh>, <light>, <Environment> et leurs props. L’avantage est qu’on peut composer la scène par sous-arbres réutilisables, et que le diff React se limite à ce qui change vraiment au niveau de l’arbre Three.js.
La deuxième couche est la logique d’animation. Elle vit dans des hooks personnalisés (useFloat, useOrbit, useCameraPath) qui prennent une ref et appellent useFrame pour muter directement le position, le rotation, ou la scale de l’objet. La règle absolue est de ne jamais déclencher de re-render React pour de l’animation continue : on mute la propriété native Three.js sur la ref, ce qui contourne entièrement la reconciliation. C’est ce point qui fait la différence entre un projet qui tourne à 60 fps et un projet qui rame à 20 fps.
La troisième couche est la configuration de rendu : le Canvas, le choix du renderer, les paramètres de pixel ratio, le post-processing, le shadow mapping. Cette couche change peu et mérite son propre composant racine. C’est typiquement là qu’on gère la détection WebGPU/WebGL, le repli, et l’orchestration des passes TSL.
Cette séparation permet, le moment venu, de remplacer R3F par du Three.js vanilla ou inversement sans réécrire la logique métier. Elle facilite aussi le test : la logique des hooks d’animation peut se tester avec Vitest et un mock de ref, indépendamment du rendu.
Concepts mathématiques à maîtriser
Le 3D web temps réel manipule en permanence quatre concepts mathématiques. Les ignorer conduit à des bugs visuels difficiles à diagnostiquer.
Le premier est l’espace. Un point dans une scène 3D existe successivement dans l’espace objet (relatif à son mesh d’origine), l’espace monde (relatif à la scène), l’espace vue (relatif à la caméra) et l’espace clip (projeté sur l’écran). Chaque transition est une multiplication par une matrice 4×4. Quand un shader produit un effet bizarre, la première question est presque toujours : « dans quel espace travaille cette variable ? ». TSL expose positionLocal, positionWorld, positionView précisément pour rendre cette distinction explicite.
Le deuxième est la normale. C’est un vecteur perpendiculaire à la surface, utilisé pour le calcul de l’éclairage. Une normale doit être normalisée (longueur 1) et transformée par la matrice normale (l’inverse transposée de la matrice de modèle, sauf transformations uniformes). Une scène où l’éclairage paraît « sale » ou inversé est presque toujours un bug de normales.
Le troisième est le quaternion. Three.js utilise des quaternions pour les rotations afin d’éviter le gimbal lock. Pour un développeur, l’API Euler reste pratique pour des rotations simples (degrés sur trois axes), mais dès qu’on interpole entre deux orientations ou qu’on compose plusieurs rotations, le quaternion via Quaternion.slerp() est la voie correcte.
Le quatrième est l’espace colorimétrique. Three.js r152 a basculé par défaut en sRGB output et linear working space, ce qui change le rendu par rapport aux versions antérieures. Une texture albedo doit être déclarée en SRGBColorSpace, une normal map en NoColorSpace. Mélanger les deux produit des matériaux pâles ou trop saturés. La page Color management de la documentation officielle est lecture obligatoire.
Les tutoriels de cette série
Pour chaque sujet ci-dessous, un tutoriel pas-à-pas est disponible. Ils sont conçus pour être lus dans l’ordre, mais chacun est autonome.
- Démarrer React Three Fiber v9 avec Vite et TypeScript — créer un projet propre, premier rendu, structure de dossiers conseillée.
- Activer WebGPU en R3F avec fallback WebGL 2 — Canvas asynchrone, détection capabilities, bascule transparente entre WebGPURenderer et WebGLRenderer.
- Premier shader TSL : Three Shading Language pas à pas — composer un graphe de nœuds, animer une couleur, lire une texture, debugger.
- Charger un modèle glTF avec Draco et Meshopt en R3F — préparer son fichier dans Blender, compresser, charger avec
useGLTF, vérifier la taille réseau. - Post-processing en WebGPU avec TSL : bloom, DoF, vignette — composer une chaîne de passes en nœuds, mesurer le coût GPU.
- Animer en R3F : useFrame, react-spring/three et Theatre.js — comparer les approches, choisir selon le besoin.
- Performance R3F : instancing, LOD et frustum culling — passer de 200 à 50 000 mesh sans saturer la frame budget.
- Déployer une scène 3D : KTX2, glTF compressé et CDN statique — pipeline de build, headers HTTP, cache, mesure du Time To First Mesh.
Lus ensemble, ces tutoriels couvrent la chaîne complète : initialisation, écriture de shaders, ingestion d’assets, rendu avancé, animation, optimisation et livraison. Le seul prérequis est une connaissance de React et un peu de mathématiques de transformation 3D (translation, rotation, échelle, espaces objet/monde/vue).
Erreurs fréquentes à éviter
| Erreur | Cause | Solution |
|---|---|---|
| Écran noir au démarrage avec WebGPU | Canvas synchrone qui essaie de monter le renderer avant que renderer.init() soit résolu |
Passer une fonction gl async retournant la promesse du renderer initialisé (R3F v9) |
state.gl is undefined après mise à jour R3F v10-alpha |
Renommage en state.renderer introduit dans la v10 alpha |
Migrer useThree(s => s.gl) en s.renderer uniquement si l’on cible v10 ; sinon rester sur s.gl |
| Shader TSL qui marche en WebGPU mais pas en WebGL | Usage d’une fonctionnalité compute-only ou d’un nœud non transpilable | Vérifier la matrice de compatibilité TSL ; isoler la logique compute dans un fallback CPU |
| Modèle glTF lent à charger | Fichier non compressé, textures PNG 4096² | Convertir en KTX2 + Draco/Meshopt, viser < 2 Mo total pour la première scène |
| Frame rate qui chute à 30 fps avec 500 cubes | Un mesh par cube → 500 draw calls | Utiliser InstancedMesh ou le helper <Instances> de Drei : un seul draw call |
| Post-processing pmndrs cassé en WebGPU | @react-three/postprocessing ne supporte pas tous les effets sur le WebGPURenderer |
Basculer sur les passes TSL natives via postProcessing de Three.js |
| Memory leak après navigation SPA | Géométries et textures non disposées | Utiliser les helpers Drei qui gèrent le dispose, ou appeler geometry.dispose() et material.dispose() explicitement |
FAQ
Three.js et React Three Fiber, faut-il choisir ?
Non, R3F est une couche au-dessus de Three.js, pas un concurrent. Vous écrivez du JSX, R3F instancie et orchestre les objets Three.js sous-jacents. Les performances sont équivalentes à un projet Three.js vanilla bien écrit, à condition d’éviter les re-renders React intempestifs (mémoïsation des props, refs pour les animations).
WebGPU est-il obligatoire en 2026 ?
Non, mais il est recommandé pour tout nouveau projet visant un public récent. Avec le repli automatique de Three.js vers WebGL 2, vous ne perdez aucun utilisateur : ceux qui ont une plateforme moderne profitent des compute shaders et de la meilleure performance, les autres conservent un rendu acceptable.
Quelle différence entre WGSL et TSL ?
WGSL est le langage de shader bas niveau de WebGPU, équivalent moderne du GLSL. TSL est une API JavaScript haut niveau qui génère du WGSL ou du GLSL selon le renderer cible. TSL n’est pas un remplaçant de WGSL — sous le capot, il y a toujours du WGSL exécuté. C’est l’expérience de développement qui change.
Faut-il maîtriser GLSL avant TSL ?
Pas obligatoire. La pratique montre cependant qu’une compréhension des concepts shader (vertex, fragment, varyings, uniforms, espaces) reste indispensable, quel que soit le langage. Le livre The Book of Shaders de Patricio Gonzalez Vivo et le tutoriel thebookofshaders.com restent d’excellents points d’entrée.
Comment debugger un shader TSL ?
Trois techniques complémentaires. D’abord, le compilateur TSL expose le code généré : on peut imprimer le WGSL ou le GLSL produit pour comprendre ce que la machine voit. Ensuite, Spector.js (extension Chrome) inspecte les frames WebGL/WebGPU. Enfin, l’écriture de la valeur intermédiaire dans la couleur du fragment (output = vec4(myValue, 0, 0, 1)) reste la méthode universelle.
Quelle taille maximale pour une scène 3D web ?
La règle empirique est qu’un premier rendu doit tenir sous 2 Mo de payload réseau pour une expérience fluide sur connexion 4G typique. Au-delà, on segmente : un loader animé pendant le téléchargement progressif des assets, ou un streaming par chunks via Meshopt. Le format KTX2 et la compression Draco sont essentiels pour rester sous ce seuil.
R3F est-il compatible avec Next.js ou Remix ?
Oui, à condition de désactiver le SSR pour le composant Canvas. Three.js et R3F dépendent de l’API DOM/Canvas, indisponibles côté serveur. La pratique courante en 2026 est 'use client' en tête du composant, ou un dynamic(() => import('./Scene'), { ssr: false }) en Next.js.
Comment mesurer les performances d’une scène ?
Trois outils se complètent. Le panneau Performance de Chrome DevTools montre la frame timeline et identifie le coût CPU. L’onglet GPU de Safari (Web Inspector) et les onglets équivalents de Firefox exposent le temps GPU réel par passe. Enfin, le helper <Stats> de Drei affiche un overlay en temps réel avec FPS, MS et MB. Pour un audit sérieux, il faut viser un budget de 16,6 ms par frame à 60 fps, dont moins de 8 ms côté CPU pour laisser au GPU le temps de finir son travail. Au-delà de 33 ms, la sensation de lag devient perceptible même pour un utilisateur non technique.
Quelle place pour Babylon.js, PlayCanvas ou Unity WebGL ?
Three.js domine l’écosystème JavaScript ouvert et bénéficie de la communauté la plus large. Babylon.js, soutenu par Microsoft, reste un excellent choix pour des cas plus orientés moteur de jeu, avec un éditeur visuel et un support WebGPU avancé. PlayCanvas et Unity WebGL ciblent davantage la production de jeux finis avec un pipeline d’éditeur. Pour une intégration React-first dans une application web classique, R3F + Three.js reste la voie de moindre friction, et c’est sur ce couple que cette série se concentre.
Ressources officielles
- Three.js — site officiel et documentation
- TSL — documentation Three Shading Language
- WebGPURenderer — documentation API
- Three.js — guide de migration officiel
- React Three Fiber — documentation officielle
- React Three Fiber — guide de migration v9
- Drei — bibliothèque de helpers R3F
- WebGPU — spécification W3C
- WGSL — spécification W3C
- WebGPU — statut d’implémentation par moteur
- WebKit — annonce WebGPU Safari 26
- glTF 2.0 — spécification Khronos