﻿{"id":646,"date":"2026-02-28T19:12:31","date_gmt":"2026-02-28T18:12:31","guid":{"rendered":"https:\/\/lmspro.fr\/premiers-pas-avec-three-js-2\/"},"modified":"2026-02-28T19:12:31","modified_gmt":"2026-02-28T18:12:31","slug":"premiers-pas-avec-three-js-2","status":"publish","type":"post","link":"https:\/\/lmspro.fr\/en\/premiers-pas-avec-three-js-2\/","title":{"rendered":"premiers pas avec three js"},"content":{"rendered":"<article class=\"lms-video-card\"><div class=\"lms-content\"><div class=\"lms-meta\"><span class=\"lms-pill lms-pill--provider\">YouTube<\/span><span class=\"lms-pill lms-pill--muted\">three js<\/span><span class=\"lms-pill lms-pill--muted\">three js tutorial<\/span><span class=\"lms-pill lms-pill--muted\">what is three js<\/span><span class=\"lms-pill lms-pill--muted\">three js in 100 seconds<\/span><\/div><div class=\"lms-media\"><iframe class=\"lms-iframe\" src=\"https:\/\/www.youtube-nocookie.com\/embed\/ZHZh6S9b6DY?rel=0\" allowfullscreen><\/iframe><\/div><\/div><\/article>\n<h2>Premiers pas avec Three.js<\/h2>\n<p class=\"wpa-text\">Three.js est une biblioth\u00e8que JavaScript r\u00e9volutionnaire qui permet de cr\u00e9er facilement des graphiques 3D dans le navigateur web. Cette fiche vous accompagne dans la d\u00e9couverte de cette technologie passionnante \u00e0 travers une s\u00e9rie d&rsquo;exemples graphiques et interactifs adapt\u00e9s aux d\u00e9butants.<\/p>\n<div class=\"article-meta\">\n<p><strong>Module :<\/strong> Module 6 : Module Bonus<\/p>\n<p><strong>Niveau :<\/strong> D\u00e9butant<\/p>\n<p><strong>Dur\u00e9e :<\/strong> 20 minutes<\/p>\n<p><strong>Pr\u00e9requis :<\/strong> Aucun<\/p>\n<\/div>\n<h2>Objectifs p\u00e9dagogiques<\/h2>\n<ul>\n<li>Comprendre les concepts fondamentaux de Three.js et de la 3D dans le web<\/li>\n<li>Cr\u00e9er votre premi\u00e8re sc\u00e8ne 3D avec des objets g\u00e9om\u00e9triques simples<\/li>\n<li>Manipuler les cam\u00e9ras, l&rsquo;\u00e9clairage et les mat\u00e9riaux de base<\/li>\n<li>Ajouter de l&rsquo;interactivit\u00e9 \u00e0 vos cr\u00e9ations 3D<\/li>\n<li>Int\u00e9grer Three.js dans vos projets web et architecturaux<\/li>\n<\/ul>\n<div class=\"wpa-accordion wpa-accordion-flush\" id=\"accordion-premiers-pas-avec-three-js\">\n<div class=\"wpa-accordion-item\">\n<button class=\"wpa-accordion-header\" data-wpa-target=\"#accordion-premiers-pas-avec-three-js-item-1\" aria-expanded=\"false\"><span class=\"wpa-accordion-title\"><span class=\"wpa-accordion-number\">01<\/span> Introduction \u00e0 Three.js<\/span><span class=\"wpa-accordion-icon\"><\/span><\/button><\/p>\n<div id=\"accordion-premiers-pas-avec-three-js-item-1\" class=\"wpa-accordion-body\">\n<div class=\"wpa-accordion-content\">\n<h4>Qu&rsquo;est-ce que Three.js ?<\/h4>\n<p>Three.js est une biblioth\u00e8que JavaScript open-source qui simplifie \u00e9norm\u00e9ment la cr\u00e9ation de contenu 3D dans les navigateurs web. Imaginez-la comme un traducteur universel : alors que votre navigateur ne comprend que le langage WebGL (tr\u00e8s complexe), Three.js vous permet d&rsquo;\u00e9crire du JavaScript simple pour cr\u00e9er des sc\u00e8nes 3D \u00e9poustouflantes. C&rsquo;est comme utiliser une t\u00e9l\u00e9commande simple au lieu de devoir programmer directement les circuits \u00e9lectroniques de votre t\u00e9l\u00e9vision.<\/p>\n<h4>Pourquoi Three.js est r\u00e9volutionnaire ?<\/h4>\n<p>Avant Three.js, cr\u00e9er de la 3D pour le web n\u00e9cessitait des connaissances approfondies en WebGL et en math\u00e9matiques 3D. Three.js a d\u00e9mocratis\u00e9 cette technologie en proposant une API intuitive et bien document\u00e9e. Pour les architectes et designers, c&rsquo;est un outil pr\u00e9cieux qui permet de pr\u00e9senter des projets de mani\u00e8re immersive, de cr\u00e9er des visites virtuelles ou de d\u00e9velopper des configurateurs 3D interactifs sans avoir besoin d&rsquo;un dipl\u00f4me en informatique graphique.<\/p>\n<div class=\"info-box\">\n<p><strong>Point cl\u00e9<\/strong> : Three.js fonctionne directement dans le navigateur, sans plugin ni installation suppl\u00e9mentaire pour l&rsquo;utilisateur final.<\/p>\n<\/div>\n<div class=\"tuto-objectif\" style=\"background: #f5f5f5; border-left: 4px solid #667eea; padding: 16px 20px; margin-top: 24px; border-radius: 0 8px 8px 0;\">\n<h3 style=\"color: #667eea; margin: 0 0 8px 0; font-size: 16px;\">\u00c0 retenir<\/h3>\n<p style=\"margin: 0; color: #333;\">Three.js est un pont entre le JavaScript simple et la 3D complexe, permettant de cr\u00e9er facilement des exp\u00e9riences visuelles immersives dans le navigateur web.<\/p>\n<\/div>\n<div class=\"tuto-exercise\" style=\"background: #fff3e0; border-left: 4px solid #ff9800; padding: 16px 20px; margin-top: 20px; border-radius: 0 8px 8px 0;\">\n<h4 style=\"color: #ff9800; margin: 0 0 8px 0; font-size: 15px;\">\ud83c\udfaf Mini-exercice : Votre premi\u00e8re sc\u00e8ne 3D<\/h4>\n<p style=\"margin: 0; color: #333; font-size: 14px;\">Cr\u00e9ez une sc\u00e8ne 3D basique avec un cube color\u00e9 qui tourne automatiquement pour d\u00e9couvrir les fondamentaux de Three.js.<\/p>\n<\/div>\n<div class=\"codepen-block\" data-block-id=\"exercise-1\">\n<p class=\"codepen-block-label\">Code de r\u00e9f\u00e9rence :<\/p>\n<div class=\"codepen-header\">\n<div class=\"codepen-tabs\">\n<button class=\"codepen-tab active\" data-tab=\"html\">HTML<\/button><br \/>\n<button class=\"codepen-tab\" data-tab=\"javascript\">JS (3D)<\/button>\n<\/div>\n<p><button class=\"codepen-copy-btn\">Copier<\/button>\n<\/div>\n<div class=\"codepen-code-container\">\n<pre class=\"codepen-code active\" data-lang=\"html\">&lt;!DOCTYPE html&gt;\n&lt;html&gt;\n&lt;head&gt;\n    &lt;title&gt;Ma premi\u00e8re sc\u00e8ne Three.js&lt;\/title&gt;\n    &lt;style&gt;\n        body { margin: 0; padding: 0; overflow: hidden; background: #000; }\n        canvas { display: block; }\n    &lt;\/style&gt;\n&lt;\/head&gt;\n&lt;body&gt;\n    &lt;script src=\"https:\/\/cdn.jsdelivr.net\/npm\/three@0.150\/build\/three.min.js\"&gt;&lt;\/script&gt;\n&lt;\/body&gt;\n&lt;\/html&gt;<\/pre>\n<pre class=\"codepen-code\" data-lang=\"javascript\">\/\/ Cr\u00e9ation de la sc\u00e8ne, cam\u00e9ra et rendu\nconst scene = new THREE.Scene();\nconst camera = new THREE.PerspectiveCamera(75, window.innerWidth \/ window.innerHeight, 0.1, 1000);\nconst renderer = new THREE.WebGLRenderer();\n\n\/\/ Configuration du rendu\nrenderer.setSize(window.innerWidth, window.innerHeight);\nrenderer.setClearColor(0x222222);\ndocument.body.appendChild(renderer.domElement);\n\n\/\/ Cr\u00e9ation d'un cube color\u00e9\nconst geometry = new THREE.BoxGeometry(2, 2, 2);\nconst material = new THREE.MeshBasicMaterial({ \n    color: 0x00ff88,\n    wireframe: false \n});\nconst cube = new THREE.Mesh(geometry, material);\n\n\/\/ Ajout du cube \u00e0 la sc\u00e8ne\nscene.add(cube);\n\n\/\/ Position de la cam\u00e9ra\ncamera.position.z = 5;\n\n\/\/ Fonction d'animation\nfunction animate() {\n    requestAnimationFrame(animate);\n    \n    \/\/ Rotation du cube\n    cube.rotation.x += 0.01;\n    cube.rotation.y += 0.01;\n    \n    \/\/ Rendu de la sc\u00e8ne\n    renderer.render(scene, camera);\n}\n\n\/\/ D\u00e9marrage de l'animation\nanimate();<\/pre>\n<\/div>\n<\/div>\n<div class=\"monaco-sandbox\" data-block-id=\"exercise-1\">\n<div class=\"monaco-header\">\n<div class=\"monaco-tabs\">\n<button class=\"monaco-tab active\" data-lang=\"html\">HTML<\/button><br \/>\n<button class=\"monaco-tab\" data-lang=\"javascript\">JS (3D)<\/button>\n<\/div>\n<div class=\"monaco-actions\">\n<button class=\"monaco-btn monaco-btn-run\">\u25b6 Ex\u00e9cuter<\/button><br \/>\n<button class=\"monaco-btn monaco-btn-reset\">\u21ba Reset<\/button>\n<\/div>\n<\/div>\n<div class=\"monaco-container\">\n<div class=\"monaco-editor-wrapper\">\n<div class=\"monaco-editor-pane active\" data-lang=\"html\"><\/div>\n<div class=\"monaco-editor-pane\" data-lang=\"javascript\"><\/div>\n<\/div>\n<div class=\"monaco-preview-wrapper\">\n<div class=\"monaco-preview-header\">Result<\/div>\n<\/div>\n<\/div>\n<div class=\"monaco-status\">\n<span class=\"monaco-status-left\">\u25cf Pr\u00eat<\/span><br \/>\n<span class=\"monaco-status-right\">Monaco Editor v0.45<\/span>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n<div class=\"wpa-accordion-item\">\n<button class=\"wpa-accordion-header\" data-wpa-target=\"#accordion-premiers-pas-avec-three-js-item-2\" aria-expanded=\"false\"><span class=\"wpa-accordion-title\"><span class=\"wpa-accordion-number\">02<\/span> Les composants essentiels d&rsquo;une sc\u00e8ne 3D<\/span><span class=\"wpa-accordion-icon\"><\/span><\/button><\/p>\n<div id=\"accordion-premiers-pas-avec-three-js-item-2\" class=\"wpa-accordion-body\">\n<div class=\"wpa-accordion-content\">\n<h4>La trinit\u00e9 de Three.js : Sc\u00e8ne, Cam\u00e9ra, Rendu<\/h4>\n<p>Chaque cr\u00e9ation Three.js repose sur trois piliers fondamentaux, comme les trois pieds d&rsquo;un tr\u00e9pied. La <strong>sc\u00e8ne<\/strong> (Scene) est votre monde virtuel, un conteneur invisible qui accueille tous vos objets 3D. Imaginez-la comme un plateau de th\u00e9\u00e2tre o\u00f9 vous placez d\u00e9cors, acteurs et \u00e9clairages. La <strong>cam\u00e9ra<\/strong> (Camera) est votre \u0153il num\u00e9rique, d\u00e9terminant ce que voit le spectateur et sous quel angle. Enfin, le <strong>rendu<\/strong> (Renderer) est le projecteur qui transforme votre sc\u00e8ne 3D en image 2D sur l&rsquo;\u00e9cran, comme un appareil photo qui capture un instant.<\/p>\n<h4>Les types de cam\u00e9ras et leurs usages<\/h4>\n<p>Three.js propose principalement deux types de cam\u00e9ras. La <strong>PerspectiveCamera<\/strong> simule la vision humaine avec un effet de perspective naturel : les objets proches paraissent plus grands que ceux \u00e9loign\u00e9s. C&rsquo;est parfait pour des sc\u00e8nes r\u00e9alistes ou des visites architecturales virtuelles. L&rsquo;<strong>OrthographicCamera<\/strong> offre une vue sans perspective, id\u00e9ale pour des plans techniques ou des vues isom\u00e9triques d&rsquo;architecte o\u00f9 les dimensions doivent rester proportionnelles quelle que soit la distance.<\/p>\n<div class=\"info-box\">\n<p><strong>Point cl\u00e9<\/strong> : Le ratio d&rsquo;aspect de la cam\u00e9ra (largeur\/hauteur) doit correspondre aux dimensions de votre canvas pour \u00e9viter les d\u00e9formations.<\/p>\n<\/div>\n<div class=\"tuto-objectif\" style=\"background: #f5f5f5; border-left: 4px solid #667eea; padding: 16px 20px; margin-top: 24px; border-radius: 0 8px 8px 0;\">\n<h3 style=\"color: #667eea; margin: 0 0 8px 0; font-size: 16px;\">\u00c0 retenir<\/h3>\n<p style=\"margin: 0; color: #333;\">Sc\u00e8ne = conteneur, Cam\u00e9ra = point de vue, Rendu = transformation en image. Ces trois \u00e9l\u00e9ments forment la base obligatoire de toute cr\u00e9ation Three.js.<\/p>\n<\/div>\n<div class=\"tuto-exercise\" style=\"background: #fff3e0; border-left: 4px solid #ff9800; padding: 16px 20px; margin-top: 20px; border-radius: 0 8px 8px 0;\">\n<h4 style=\"color: #ff9800; margin: 0 0 8px 0; font-size: 15px;\">\ud83c\udfaf Mini-exercice : Comparer les types de cam\u00e9ras<\/h4>\n<p style=\"margin: 0; color: #333; font-size: 14px;\">Cr\u00e9ez une sc\u00e8ne avec plusieurs cubes et basculez entre cam\u00e9ra perspective et orthographique pour comprendre leur diff\u00e9rence visuelle.<\/p>\n<\/div>\n<div class=\"codepen-block\" data-block-id=\"exercise-2\">\n<p class=\"codepen-block-label\">Code de r\u00e9f\u00e9rence :<\/p>\n<div class=\"codepen-header\">\n<div class=\"codepen-tabs\">\n<button class=\"codepen-tab active\" data-tab=\"html\">HTML<\/button><br \/>\n<button class=\"codepen-tab\" data-tab=\"javascript\">JS (3D)<\/button>\n<\/div>\n<p><button class=\"codepen-copy-btn\">Copier<\/button>\n<\/div>\n<div class=\"codepen-code-container\">\n<pre class=\"codepen-code active\" data-lang=\"html\">&lt;!DOCTYPE html&gt;\n&lt;html&gt;\n&lt;head&gt;\n    &lt;title&gt;Comparaison des cam\u00e9ras&lt;\/title&gt;\n    &lt;style&gt;\n        body { margin: 0; padding: 0; overflow: hidden; background: #111; font-family: Arial; }\n        canvas { display: block; }\n        .controls { position: absolute; top: 20px; left: 20px; z-index: 100; }\n        button { background: #0066cc; color: white; border: none; padding: 10px 20px; margin: 5px; border-radius: 5px; cursor: pointer; }\n        button:hover { background: #0088ff; }\n    &lt;\/style&gt;\n&lt;\/head&gt;\n&lt;body&gt;\n    &lt;div class=\"controls\"&gt;\n        &lt;button onclick=\"switchToPerspective()\"&gt;Cam\u00e9ra Perspective&lt;\/button&gt;\n        &lt;button onclick=\"switchToOrthographic()\"&gt;Cam\u00e9ra Orthographique&lt;\/button&gt;\n    &lt;\/div&gt;\n    &lt;script src=\"https:\/\/cdn.jsdelivr.net\/npm\/three@0.150\/build\/three.min.js\"&gt;&lt;\/script&gt;\n&lt;\/body&gt;\n&lt;\/html&gt;<\/pre>\n<pre class=\"codepen-code\" data-lang=\"javascript\">\/\/ Configuration de base\nconst scene = new THREE.Scene();\nconst renderer = new THREE.WebGLRenderer();\nrenderer.setSize(window.innerWidth, window.innerHeight);\nrenderer.setClearColor(0x111111);\ndocument.body.appendChild(renderer.domElement);\n\n\/\/ Cr\u00e9ation des deux types de cam\u00e9ras\nconst perspectiveCamera = new THREE.PerspectiveCamera(75, window.innerWidth \/ window.innerHeight, 0.1, 1000);\nconst orthographicCamera = new THREE.OrthographicCamera(\n    window.innerWidth \/ -100, window.innerWidth \/ 100,\n    window.innerHeight \/ 100, window.innerHeight \/ -100,\n    0.1, 1000\n);\n\n\/\/ Cam\u00e9ra active (par d\u00e9faut perspective)\nlet activeCamera = perspectiveCamera;\n\n\/\/ Position des cam\u00e9ras\nperspectiveCamera.position.set(8, 6, 10);\northographicCamera.position.set(8, 6, 10);\n\n\/\/ Cr\u00e9ation de plusieurs cubes \u00e0 diff\u00e9rentes distances\nconst cubes = [];\nconst colors = [0xff6b6b, 0x4ecdc4, 0x45b7d1, 0xf9ca24, 0xf0932b];\n\nfor (let i = 0; i < 5; i++) {\n    const geometry = new THREE.BoxGeometry(1.5, 1.5, 1.5);\n    const material = new THREE.MeshBasicMaterial({ color: colors[i] });\n    const cube = new THREE.Mesh(geometry, material);\n    \n    cube.position.set(i * 2 - 4, 0, -i * 2);\n    cubes.push(cube);\n    scene.add(cube);\n}\n\n\/\/ Fonctions de basculement des cam\u00e9ras\nfunction switchToPerspective() {\n    activeCamera = perspectiveCamera;\n}\n\nfunction switchToOrthographic() {\n    activeCamera = orthographicCamera;\n}\n\n\/\/ Animation\nfunction animate() {\n    requestAnimationFrame(animate);\n    \n    \/\/ Rotation de tous les cubes\n    cubes.forEach((cube, index) => {\n        cube.rotation.x += 0.01;\n        cube.rotation.y += 0.01 * (index + 1);\n    });\n    \n    \/\/ Rendu avec la cam\u00e9ra active\n    renderer.render(scene, activeCamera);\n}\n\nanimate();<\/pre>\n<\/div>\n<\/div>\n<div class=\"monaco-sandbox\" data-block-id=\"exercise-2\">\n<div class=\"monaco-header\">\n<div class=\"monaco-tabs\">\n<button class=\"monaco-tab active\" data-lang=\"html\">HTML<\/button><br \/>\n<button class=\"monaco-tab\" data-lang=\"javascript\">JS (3D)<\/button>\n<\/div>\n<div class=\"monaco-actions\">\n<button class=\"monaco-btn monaco-btn-run\">\u25b6 Ex\u00e9cuter<\/button><br \/>\n<button class=\"monaco-btn monaco-btn-reset\">\u21ba Reset<\/button>\n<\/div>\n<\/div>\n<div class=\"monaco-container\">\n<div class=\"monaco-editor-wrapper\">\n<div class=\"monaco-editor-pane active\" data-lang=\"html\"><\/div>\n<div class=\"monaco-editor-pane\" data-lang=\"javascript\"><\/div>\n<\/div>\n<div class=\"monaco-preview-wrapper\">\n<div class=\"monaco-preview-header\">Result<\/div>\n<\/div>\n<\/div>\n<div class=\"monaco-status\">\n<span class=\"monaco-status-left\">\u25cf Pr\u00eat<\/span><br \/>\n<span class=\"monaco-status-right\">Monaco Editor v0.45<\/span>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n<div class=\"wpa-accordion-item\">\n<button class=\"wpa-accordion-header\" data-wpa-target=\"#accordion-premiers-pas-avec-three-js-item-3\" aria-expanded=\"false\"><span class=\"wpa-accordion-title\"><span class=\"wpa-accordion-number\">03<\/span> G\u00e9om\u00e9tries et mat\u00e9riaux de base<\/span><span class=\"wpa-accordion-icon\"><\/span><\/button><\/p>\n<div id=\"accordion-premiers-pas-avec-three-js-item-3\" class=\"wpa-accordion-body\">\n<div class=\"wpa-accordion-content\">\n<h4>Les formes g\u00e9om\u00e9triques fondamentales<\/h4>\n<p>Three.js offre une riche biblioth\u00e8que de formes pr\u00e9con\u00e7ues appel\u00e9es g\u00e9om\u00e9tries. Les plus utilis\u00e9es sont BoxGeometry (cubes\/parall\u00e9l\u00e9pip\u00e8des), SphereGeometry (sph\u00e8res), CylinderGeometry (cylindres), et PlaneGeometry (surfaces planes). Chaque g\u00e9om\u00e9trie se personnalise avec des param\u00e8tres : un BoxGeometry(2, 3, 1) cr\u00e9e un parall\u00e9l\u00e9pip\u00e8de de 2 unit\u00e9s de large, 3 de haut, et 1 de profondeur. Pour l&rsquo;architecture, ces formes constituent les briques \u00e9l\u00e9mentaires pour mod\u00e9liser des b\u00e2timents, meubles ou \u00e9l\u00e9ments d\u00e9coratifs.<\/p>\n<h4>Les types de mat\u00e9riaux et leurs applications<\/h4>\n<p>Un mat\u00e9riau d\u00e9termine l&rsquo;apparence de surface de vos objets 3D. Le MeshBasicMaterial est le plus simple : il affiche une couleur unie sans r\u00e9agir \u00e0 l&rsquo;\u00e9clairage, parfait pour d\u00e9buter. Le MeshStandardMaterial simule des surfaces r\u00e9alistes en r\u00e9agissant \u00e0 la lumi\u00e8re, id\u00e9al pour des mat\u00e9riaux architecturaux comme le bois, m\u00e9tal ou b\u00e9ton. Vous pouvez contr\u00f4ler la rugosit\u00e9 (roughness) pour des effets mat ou brillant, et la m\u00e9tallicit\u00e9 (metalness) pour simuler des surfaces m\u00e9talliques.<\/p>\n<div class=\"info-box\">\n<p><strong>Point cl\u00e9<\/strong> : Un Mesh = G\u00e9om\u00e9trie + Mat\u00e9riau. C&rsquo;est l&rsquo;objet final visible que vous ajoutez \u00e0 votre sc\u00e8ne.<\/p>\n<\/div>\n<div class=\"tuto-objectif\" style=\"background: #f5f5f5; border-left: 4px solid #667eea; padding: 16px 20px; margin-top: 24px; border-radius: 0 8px 8px 0;\">\n<h3 style=\"color: #667eea; margin: 0 0 8px 0; font-size: 16px;\">\u00c0 retenir<\/h3>\n<p style=\"margin: 0; color: #333;\">G\u00e9om\u00e9trie = forme 3D, Mat\u00e9riau = apparence de surface. Leur combinaison forme un Mesh, l&rsquo;objet visible dans votre sc\u00e8ne.<\/p>\n<\/div>\n<div class=\"tuto-exercise\" style=\"background: #fff3e0; border-left: 4px solid #ff9800; padding: 16px 20px; margin-top: 20px; border-radius: 0 8px 8px 0;\">\n<h4 style=\"color: #ff9800; margin: 0 0 8px 0; font-size: 15px;\">\ud83c\udfaf Mini-exercice : Collection de formes architecturales<\/h4>\n<p style=\"margin: 0; color: #333; font-size: 14px;\">Cr\u00e9ez une composition avec diff\u00e9rentes g\u00e9om\u00e9tries et mat\u00e9riaux pour simuler des \u00e9l\u00e9ments architecturaux simples.<\/p>\n<\/div>\n<div class=\"codepen-block\" data-block-id=\"exercise-3\">\n<p class=\"codepen-block-label\">Code de r\u00e9f\u00e9rence :<\/p>\n<div class=\"codepen-header\">\n<div class=\"codepen-tabs\">\n<button class=\"codepen-tab active\" data-tab=\"html\">HTML<\/button><br \/>\n<button class=\"codepen-tab\" data-tab=\"javascript\">JS (3D)<\/button>\n<\/div>\n<p><button class=\"codepen-copy-btn\">Copier<\/button>\n<\/div>\n<div class=\"codepen-code-container\">\n<pre class=\"codepen-code active\" data-lang=\"html\">&lt;!DOCTYPE html&gt;\n&lt;html&gt;\n&lt;head&gt;\n    &lt;title&gt;\u00c9l\u00e9ments architecturaux 3D&lt;\/title&gt;\n    &lt;style&gt;\n        body { margin: 0; padding: 0; overflow: hidden; background: #87CEEB; font-family: Arial; }\n        canvas { display: block; }\n        .info { position: absolute; bottom: 20px; left: 20px; color: white; background: rgba(0,0,0,0.7); padding: 15px; border-radius: 10px; }\n    &lt;\/style&gt;\n&lt;\/head&gt;\n&lt;body&gt;\n    &lt;div class=\"info\"&gt;\n        &lt;h3 style=\"margin: 0 0 10px 0;\"&gt;\u00c9l\u00e9ments architecturaux&lt;\/h3&gt;\n        &lt;p style=\"margin: 0; font-size: 14px;\"&gt;Fondation (cube) \u2022 Colonne (cylindre) \u2022 D\u00f4me (sph\u00e8re) \u2022 Sol (plan)&lt;\/p&gt;\n    &lt;\/div&gt;\n    &lt;script src=\"https:\/\/cdn.jsdelivr.net\/npm\/three@0.150\/build\/three.min.js\"&gt;&lt;\/script&gt;\n&lt;\/body&gt;\n&lt;\/html&gt;<\/pre>\n<pre class=\"codepen-code\" data-lang=\"javascript\">\/\/ Configuration de la sc\u00e8ne\nconst scene = new THREE.Scene();\nconst camera = new THREE.PerspectiveCamera(75, window.innerWidth \/ window.innerHeight, 0.1, 1000);\nconst renderer = new THREE.WebGLRenderer({ antialias: true });\nrenderer.setSize(window.innerWidth, window.innerHeight);\nrenderer.setClearColor(0x87CEEB); \/\/ Bleu ciel\ndocument.body.appendChild(renderer.domElement);\n\n\/\/ \u00c9clairage ambiant pour voir les mat\u00e9riaux\nconst ambientLight = new THREE.AmbientLight(0xffffff, 0.6);\nscene.add(ambientLight);\n\nconst directionalLight = new THREE.DirectionalLight(0xffffff, 0.8);\ndirectionalLight.position.set(10, 10, 5);\nscene.add(directionalLight);\n\n\/\/ 1. Fondation en b\u00e9ton (cube)\nconst foundationGeometry = new THREE.BoxGeometry(6, 0.5, 6);\nconst foundationMaterial = new THREE.MeshStandardMaterial({ \n    color: 0x888888,\n    roughness: 0.8 \n});\nconst foundation = new THREE.Mesh(foundationGeometry, foundationMaterial);\nfoundation.position.y = -0.25;\nscene.add(foundation);\n\n\/\/ 2. Sol en pierre (plan)\nconst floorGeometry = new THREE.PlaneGeometry(12, 12);\nconst floorMaterial = new THREE.MeshStandardMaterial({ \n    color: 0x654321,\n    roughness: 0.9 \n});\nconst floor = new THREE.Mesh(floorGeometry, floorMaterial);\nfloor.rotation.x = -Math.PI \/ 2;\nfloor.position.y = -1;\nscene.add(floor);\n\n\/\/ 3. Colonnes en marbre (cylindres)\nconst columnGeometry = new THREE.CylinderGeometry(0.3, 0.3, 4, 8);\nconst columnMaterial = new THREE.MeshStandardMaterial({ \n    color: 0xF5F5DC,\n    roughness: 0.3 \n});\n\nconst positions = [\n    { x: -2, z: -2 },\n    { x: 2, z: -2 },\n    { x: -2, z: 2 },\n    { x: 2, z: 2 }\n];\n\npositions.forEach(pos => {\n    const column = new THREE.Mesh(columnGeometry, columnMaterial);\n    column.position.set(pos.x, 1.75, pos.z);\n    scene.add(column);\n});\n\n\/\/ 4. D\u00f4me central (sph\u00e8re)\nconst domeGeometry = new THREE.SphereGeometry(1.2, 16, 8, 0, Math.PI * 2, 0, Math.PI \/ 2);\nconst domeMaterial = new THREE.MeshStandardMaterial({ \n    color: 0xCD853F,\n    roughness: 0.4 \n});\nconst dome = new THREE.Mesh(domeGeometry, domeMaterial);\ndome.position.y = 4;\nscene.add(dome);\n\n\/\/ Position de la cam\u00e9ra\ncamera.position.set(8, 6, 8);\ncamera.lookAt(0, 2, 0);\n\n\/\/ Animation douce\nfunction animate() {\n    requestAnimationFrame(animate);\n    \n    \/\/ Rotation lente de la sc\u00e8ne pour admirer sous tous les angles\n    scene.rotation.y += 0.005;\n    \n    renderer.render(scene, camera);\n}\n\nanimate();<\/pre>\n<\/div>\n<\/div>\n<div class=\"monaco-sandbox\" data-block-id=\"exercise-3\">\n<div class=\"monaco-header\">\n<div class=\"monaco-tabs\">\n<button class=\"monaco-tab active\" data-lang=\"html\">HTML<\/button><br \/>\n<button class=\"monaco-tab\" data-lang=\"javascript\">JS (3D)<\/button>\n<\/div>\n<div class=\"monaco-actions\">\n<button class=\"monaco-btn monaco-btn-run\">\u25b6 Ex\u00e9cuter<\/button><br \/>\n<button class=\"monaco-btn monaco-btn-reset\">\u21ba Reset<\/button>\n<\/div>\n<\/div>\n<div class=\"monaco-container\">\n<div class=\"monaco-editor-wrapper\">\n<div class=\"monaco-editor-pane active\" data-lang=\"html\"><\/div>\n<div class=\"monaco-editor-pane\" data-lang=\"javascript\"><\/div>\n<\/div>\n<div class=\"monaco-preview-wrapper\">\n<div class=\"monaco-preview-header\">Result<\/div>\n<\/div>\n<\/div>\n<div class=\"monaco-status\">\n<span class=\"monaco-status-left\">\u25cf Pr\u00eat<\/span><br \/>\n<span class=\"monaco-status-right\">Monaco Editor v0.45<\/span>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n<div class=\"wpa-accordion-item\">\n<button class=\"wpa-accordion-header\" data-wpa-target=\"#accordion-premiers-pas-avec-three-js-item-4\" aria-expanded=\"false\"><span class=\"wpa-accordion-title\"><span class=\"wpa-accordion-number\">04<\/span> \u00c9clairage et atmosph\u00e8re<\/span><span class=\"wpa-accordion-icon\"><\/span><\/button><\/p>\n<div id=\"accordion-premiers-pas-avec-three-js-item-4\" class=\"wpa-accordion-body\">\n<div class=\"wpa-accordion-content\">\n<h4>Les diff\u00e9rents types d&rsquo;\u00e9clairage<\/h4>\n<p>L&rsquo;\u00e9clairage transforme radicalement l&rsquo;atmosph\u00e8re de vos sc\u00e8nes 3D. L&rsquo;<strong>AmbientLight<\/strong> \u00e9claire uniform\u00e9ment tous les objets, comme la lumi\u00e8re diffuse d&rsquo;un jour nuageux, sans cr\u00e9er d&rsquo;ombres. La <strong>DirectionalLight<\/strong> simule le soleil avec des rayons parall\u00e8les venant d&rsquo;une direction, parfaite pour l&rsquo;\u00e9clairage naturel ext\u00e9rieur. La <strong>PointLight<\/strong> rayonne dans toutes les directions depuis un point, comme une ampoule, cr\u00e9ant des ombres r\u00e9alistes. Enfin, la <strong>SpotLight<\/strong> projette un c\u00f4ne de lumi\u00e8re, id\u00e9ale pour mettre en valeur des \u00e9l\u00e9ments architecturaux sp\u00e9cifiques.<\/p>\n<h4>Cr\u00e9er des ambiances avec la couleur et l&rsquo;intensit\u00e9<\/h4>\n<p>Chaque source lumineuse accepte deux param\u00e8tres cruciaux : la couleur et l&rsquo;intensit\u00e9. Une lumi\u00e8re blanche (0xffffff) \u00e0 intensit\u00e9 1 simule un \u00e9clairage neutre. Une teinte dor\u00e9e (0xffd700) avec intensit\u00e9 0.8 \u00e9voque un coucher de soleil chaleureux. Pour l&rsquo;architecture d&rsquo;int\u00e9rieur, combinez plusieurs sources : une AmbientLight bleut\u00e9e faible (0.2) pour simuler la lumi\u00e8re du ciel, plus des PointLights jaunes (0.6) pour les luminaires artificiels. Cette stratification cr\u00e9e une hi\u00e9rarchie visuelle et guide naturellement l&rsquo;\u0153il.<\/p>\n<div class=\"info-box\">\n<p><strong>Point cl\u00e9<\/strong> : Les mat\u00e9riaux MeshBasicMaterial ignorent l&rsquo;\u00e9clairage. Utilisez MeshStandardMaterial ou MeshPhongMaterial pour voir les effets lumineux.<\/p>\n<\/div>\n<div class=\"tuto-objectif\" style=\"background: #f5f5f5; border-left: 4px solid #667eea; padding: 16px 20px; margin-top: 24px; border-radius: 0 8px 8px 0;\">\n<h3 style=\"color: #667eea; margin: 0 0 8px 0; font-size: 16px;\">\u00c0 retenir<\/h3>\n<p style=\"margin: 0; color: #333;\">L&rsquo;\u00e9clairage d\u00e9finit l&rsquo;ambiance de votre sc\u00e8ne. Combinez plusieurs sources lumineuses pour cr\u00e9er des atmosph\u00e8res r\u00e9alistes et \u00e9motionnellement engageantes.<\/p>\n<\/div>\n<div class=\"tuto-exercise\" style=\"background: #fff3e0; border-left: 4px solid #ff9800; padding: 16px 20px; margin-top: 20px; border-radius: 0 8px 8px 0;\">\n<h4 style=\"color: #ff9800; margin: 0 0 8px 0; font-size: 15px;\">\ud83c\udfaf Mini-exercice : \u00c9volution de l&rsquo;\u00e9clairage naturel<\/h4>\n<p style=\"margin: 0; color: #333; font-size: 14px;\">Simulez le passage du jour \u00e0 la nuit en animant couleur et position d&rsquo;une DirectionalLight sur une sc\u00e8ne architecturale.<\/p>\n<\/div>\n<div class=\"codepen-block\" data-block-id=\"exercise-4\">\n<p class=\"codepen-block-label\">Code de r\u00e9f\u00e9rence :<\/p>\n<div class=\"codepen-header\">\n<div class=\"codepen-tabs\">\n<button class=\"codepen-tab active\" data-tab=\"html\">HTML<\/button><br \/>\n<button class=\"codepen-tab\" data-tab=\"javascript\">JS (3D)<\/button>\n<\/div>\n<p><button class=\"codepen-copy-btn\">Copier<\/button>\n<\/div>\n<div class=\"codepen-code-container\">\n<pre class=\"codepen-code active\" data-lang=\"html\">&lt;!DOCTYPE html&gt;\n&lt;html&gt;\n&lt;head&gt;\n    &lt;title&gt;Cycle jour\/nuit architectural&lt;\/title&gt;\n    &lt;style&gt;\n        body { margin: 0; padding: 0; overflow: hidden; font-family: Arial; }\n        canvas { display: block; }\n        .time-info { position: absolute; top: 20px; right: 20px; color: white; background: rgba(0,0,0,0.7); padding: 15px; border-radius: 10px; text-align: center; }\n        .controls { position: absolute; bottom: 20px; left: 20px; }\n        button { background: #4CAF50; color: white; border: none; padding: 10px 20px; margin: 5px; border-radius: 5px; cursor: pointer; }\n        button:hover { background: #45a049; }\n    &lt;\/style&gt;\n&lt;\/head&gt;\n&lt;body&gt;\n    &lt;div class=\"time-info\"&gt;\n        &lt;div id=\"time-display\"&gt;06:00 - Aube&lt;\/div&gt;\n        &lt;div style=\"font-size: 12px; margin-top: 5px;\"&gt;Simulation temporelle&lt;\/div&gt;\n    &lt;\/div&gt;\n    &lt;div class=\"controls\"&gt;\n        &lt;button onclick=\"toggleAnimation()\"&gt;\u23ef Pause\/Play&lt;\/button&gt;\n        &lt;button onclick=\"resetTime()\"&gt;\ud83c\udf05 Reset&lt;\/button&gt;\n    &lt;\/div&gt;\n    &lt;script src=\"https:\/\/cdn.jsdelivr.net\/npm\/three@0.150\/build\/three.min.js\"&gt;&lt;\/script&gt;\n&lt;\/body&gt;\n&lt;\/html&gt;<\/pre>\n<pre class=\"codepen-code\" data-lang=\"javascript\">\/\/ Configuration de base\nconst scene = new THREE.Scene();\nconst camera = new THREE.PerspectiveCamera(75, window.innerWidth \/ window.innerHeight, 0.1, 1000);\nconst renderer = new THREE.WebGLRenderer({ antialias: true });\nrenderer.setSize(window.innerWidth, window.innerHeight);\ndocument.body.appendChild(renderer.domElement);\n\n\/\/ Variables temporelles\nlet timeOfDay = 0; \/\/ 0 = minuit, 12 = midi, 24 = minuit suivant\nlet animationActive = true;\n\n\/\/ Construction simple (maison)\nconst houseGroup = new THREE.Group();\n\n\/\/ Base de la maison\nconst wallsGeometry = new THREE.BoxGeometry(4, 3, 4);\nconst wallsMaterial = new THREE.MeshStandardMaterial({ color: 0xDEB887 });\nconst walls = new THREE.Mesh(wallsGeometry, wallsMaterial);\nwalls.position.y = 1.5;\nhouseGroup.add(walls);\n\n\/\/ Toit\nconst roofGeometry = new THREE.ConeGeometry(3, 2, 4);\nconst roofMaterial = new THREE.MeshStandardMaterial({ color: 0x8B4513 });\nconst roof = new THREE.Mesh(roofGeometry, roofMaterial);\nroof.position.y = 4;\nroof.rotation.y = Math.PI \/ 4;\nhouseGroup.add(roof);\n\n\/\/ Sol\nconst groundGeometry = new THREE.PlaneGeometry(20, 20);\nconst groundMaterial = new THREE.MeshStandardMaterial({ color: 0x228B22 });\nconst ground = new THREE.Mesh(groundGeometry, groundMaterial);\nground.rotation.x = -Math.PI \/ 2;\nhouseGroup.add(ground);\n\nscene.add(houseGroup);\n\n\/\/ Syst\u00e8me d'\u00e9clairage dynamique\nconst ambientLight = new THREE.AmbientLight(0x404040, 0.2);\nscene.add(ambientLight);\n\nconst sunLight = new THREE.DirectionalLight(0xffffff, 1);\nscene.add(sunLight);\n\n\/\/ Lumi\u00e8res artificielles (fen\u00eatres)\nconst windowLight = new THREE.PointLight(0xffeb3b, 0, 10);\nwindowLight.position.set(0, 2, 2.1);\nscene.add(windowLight);\n\n\/\/ Position cam\u00e9ra\ncamera.position.set(8, 6, 8);\ncamera.lookAt(0, 2, 0);\n\n\/\/ Fonctions de contr\u00f4le\nfunction toggleAnimation() {\n    animationActive = !animationActive;\n}\n\nfunction resetTime() {\n    timeOfDay = 6; \/\/ Aube\n}\n\n\/\/ Fonction de mise \u00e0 jour de l'\u00e9clairage\nfunction updateLighting() {\n    \/\/ Position du soleil (arc de cercle)\n    const sunAngle = (timeOfDay - 6) * Math.PI \/ 12; \/\/ 6h = lever, 18h = coucher\n    sunLight.position.set(\n        Math.cos(sunAngle) * 15,\n        Math.sin(sunAngle) * 10,\n        5\n    );\n\n    \/\/ Couleur et intensit\u00e9 du soleil selon l'heure\n    let sunColor, sunIntensity, skyColor, ambientIntensity;\n    \n    if (timeOfDay >= 5 && timeOfDay < 7) { \/\/ Aube\n        sunColor = 0xffa500;\n        sunIntensity = 0.6;\n        skyColor = 0x4169e1;\n        ambientIntensity = 0.3;\n    } else if (timeOfDay >= 7 && timeOfDay < 18) { \/\/ Jour\n        sunColor = 0xffffff;\n        sunIntensity = 1;\n        skyColor = 0x87ceeb;\n        ambientIntensity = 0.4;\n    } else if (timeOfDay >= 18 && timeOfDay < 20) { \/\/ Cr\u00e9puscule\n        sunColor = 0xff6347;\n        sunIntensity = 0.4;\n        skyColor = 0x191970;\n        ambientIntensity = 0.2;\n    } else { \/\/ Nuit\n        sunColor = 0x4169e1;\n        sunIntensity = 0.1;\n        skyColor = 0x000000;\n        ambientIntensity = 0.1;\n    }\n\n    sunLight.color.setHex(sunColor);\n    sunLight.intensity = sunIntensity;\n    renderer.setClearColor(skyColor);\n    ambientLight.intensity = ambientIntensity;\n    \n    \/\/ \u00c9clairage artificiel (actif la nuit)\n    windowLight.intensity = timeOfDay < 6 || timeOfDay > 20 ? 0.8 : 0;\n\n    \/\/ Mise \u00e0 jour de l'affichage du temps\n    const hour = Math.floor(timeOfDay);\n    const minute = Math.floor((timeOfDay - hour) * 60);\n    const timeString = `${hour.toString().padStart(2, '0')}:${minute.toString().padStart(2, '0')}`;\n    \n    let period;\n    if (timeOfDay >= 5 && timeOfDay < 7) period = \"Aube\";\n    else if (timeOfDay >= 7 && timeOfDay < 18) period = \"Jour\";\n    else if (timeOfDay >= 18 && timeOfDay < 20) period = \"Cr\u00e9puscule\";\n    else period = \"Nuit\";\n    \n    document.getElementById('time-display').textContent = `${timeString} - ${period}`;\n}\n\n\/\/ Animation\nfunction animate() {\n    requestAnimationFrame(animate);\n    \n    if (animationActive) {\n        timeOfDay += 0.02; \/\/ Vitesse du cycle\n        if (timeOfDay >= 24) timeOfDay = 0;\n    }\n    \n    updateLighting();\n    \n    renderer.render(scene, camera);\n}\n\n\/\/ Initialisation\nupdateLighting();\nanimate();<\/pre>\n<\/div>\n<\/div>\n<div class=\"monaco-sandbox\" data-block-id=\"exercise-4\">\n<div class=\"monaco-header\">\n<div class=\"monaco-tabs\">\n<button class=\"monaco-tab active\" data-lang=\"html\">HTML<\/button><br \/>\n<button class=\"monaco-tab\" data-lang=\"javascript\">JS (3D)<\/button>\n<\/div>\n<div class=\"monaco-actions\">\n<button class=\"monaco-btn monaco-btn-run\">\u25b6 Ex\u00e9cuter<\/button><br \/>\n<button class=\"monaco-btn monaco-btn-reset\">\u21ba Reset<\/button>\n<\/div>\n<\/div>\n<div class=\"monaco-container\">\n<div class=\"monaco-editor-wrapper\">\n<div class=\"monaco-editor-pane active\" data-lang=\"html\"><\/div>\n<div class=\"monaco-editor-pane\" data-lang=\"javascript\"><\/div>\n<\/div>\n<div class=\"monaco-preview-wrapper\">\n<div class=\"monaco-preview-header\">Result<\/div>\n<\/div>\n<\/div>\n<div class=\"monaco-status\">\n<span class=\"monaco-status-left\">\u25cf Pr\u00eat<\/span><br \/>\n<span class=\"monaco-status-right\">Monaco Editor v0.45<\/span>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n<div class=\"wpa-accordion-item\">\n<button class=\"wpa-accordion-header\" data-wpa-target=\"#accordion-premiers-pas-avec-three-js-item-5\" aria-expanded=\"false\"><span class=\"wpa-accordion-title\"><span class=\"wpa-accordion-number\">05<\/span> Interactivit\u00e9 et contr\u00f4les utilisateur<\/span><span class=\"wpa-accordion-icon\"><\/span><\/button><\/p>\n<div id=\"accordion-premiers-pas-avec-three-js-item-5\" class=\"wpa-accordion-body\">\n<div class=\"wpa-accordion-content\">\n<h4>Les contr\u00f4les de cam\u00e9ra OrbitControls<\/h4>\n<p>L&rsquo;interactivit\u00e9 transforme une simple d\u00e9monstration 3D en exp\u00e9rience immersive. Les OrbitControls constituent l&rsquo;outil le plus populaire pour permettre \u00e0 l&rsquo;utilisateur d&rsquo;explorer librement votre sc\u00e8ne. Ils autorisent la rotation autour d&rsquo;un point central (orbite), le zoom avant\/arri\u00e8re avec la molette, et le d\u00e9placement lat\u00e9ral (pan) en maintenant le clic droit. Pour des projets architecturaux, c&rsquo;est parfait pour des visites virtuelles o\u00f9 le client peut examiner un b\u00e2timent sous tous les angles, zoomer sur les d\u00e9tails, et se d\u00e9placer intuitivement.<\/p>\n<h4>D\u00e9tection de clics et interactions avec les objets<\/h4>\n<p>Three.js propose un syst\u00e8me appel\u00e9 Raycasting pour d\u00e9tecter les clics sur les objets 3D. Imaginez un rayon invisible partant de la souris vers la sc\u00e8ne : le Raycaster calcule quels objets ce rayon traverse. Cela permet de cr\u00e9er des interactions sophistiqu\u00e9es : cliquer sur une porte pour l&rsquo;ouvrir, s\u00e9lectionner une pi\u00e8ce pour afficher ses informations, ou modifier la couleur d&rsquo;un mat\u00e9riau au survol. Pour l&rsquo;architecture, c&rsquo;est essentiel pour cr\u00e9er des configurations interactives ou des visites guid\u00e9es avec points d&rsquo;int\u00e9r\u00eat cliquables.<\/p>\n<div class=\"info-box\">\n<p><strong>Point cl\u00e9<\/strong> : Les OrbitControls n\u00e9cessitent un import s\u00e9par\u00e9 depuis les exemples Three.js. Pensez \u00e0 inclure le bon fichier CDN.<\/p>\n<\/div>\n<div class=\"tuto-objectif\" style=\"background: #f5f5f5; border-left: 4px solid #667eea; padding: 16px 20px; margin-top: 24px; border-radius: 0 8px 8px 0;\">\n<h3 style=\"color: #667eea; margin: 0 0 8px 0; font-size: 16px;\">\u00c0 retenir<\/h3>\n<p style=\"margin: 0; color: #333;\">L&rsquo;interactivit\u00e9 rend vos cr\u00e9ations 3D vivantes. OrbitControls pour l&rsquo;exploration libre, Raycasting pour les interactions pr\u00e9cises avec les objets.<\/p>\n<\/div>\n<div class=\"tuto-exercise\" style=\"background: #fff3e0; border-left: 4px solid #ff9800; padding: 16px 20px; margin-top: 20px; border-radius: 0 8px 8px 0;\">\n<h4 style=\"color: #ff9800; margin: 0 0 8px 0; font-size: 15px;\">\ud83c\udfaf Mini-exercice : Configurateur architectural interactif<\/h4>\n<p style=\"margin: 0; color: #333; font-size: 14px;\">Cr\u00e9ez une sc\u00e8ne o\u00f9 l&rsquo;utilisateur peut cliquer sur diff\u00e9rents \u00e9l\u00e9ments architecturaux pour changer leurs couleurs et naviguer librement avec OrbitControls.<\/p>\n<\/div>\n<div class=\"codepen-block\" data-block-id=\"exercise-5\">\n<p class=\"codepen-block-label\">Code de r\u00e9f\u00e9rence :<\/p>\n<div class=\"codepen-header\">\n<div class=\"codepen-tabs\">\n<button class=\"codepen-tab active\" data-tab=\"html\">HTML<\/button><br \/>\n<button class=\"codepen-tab\" data-tab=\"javascript\">JS (3D)<\/button>\n<\/div>\n<p><button class=\"codepen-copy-btn\">Copier<\/button>\n<\/div>\n<div class=\"codepen-code-container\">\n<pre class=\"codepen-code active\" data-lang=\"html\">&lt;!DOCTYPE html&gt;\n&lt;html&gt;\n&lt;head&gt;\n    &lt;title&gt;Configurateur architectural interactif&lt;\/title&gt;\n    &lt;style&gt;\n        body { margin: 0; padding: 0; overflow: hidden; font-family: Arial; background: #f0f0f0; }\n        canvas { display: block; cursor: crosshair; }\n        .ui-panel { position: absolute; top: 20px; left: 20px; background: rgba(255,255,255,0.95); padding: 20px; border-radius: 10px; box-shadow: 0 4px 15px rgba(0,0,0,0.2); }\n        .ui-panel h3 { margin: 0 0 15px 0; color: #333; }\n        .instructions { position: absolute; bottom: 20px; right: 20px; background: rgba(0,0,0,0.8); color: white; padding: 15px; border-radius: 10px; max-width: 300px; }\n        .color-palette { display: flex; gap: 10px; margin-top: 10px; }\n        .color-swatch { width: 30px; height: 30px; border-radius: 50%; cursor: pointer; border: 3px solid transparent; transition: border-color 0.3s; }\n        .color-swatch:hover { border-color: #333; }\n        .selected-info { background: rgba(76, 175, 80, 0.9); color: white; padding: 10px; border-radius: 5px; margin-top: 10px; }\n    &lt;\/style&gt;\n&lt;\/head&gt;\n&lt;body&gt;\n    &lt;div class=\"ui-panel\"&gt;\n        &lt;h3&gt;\ud83c\udfe0 Configurateur&lt;\/h3&gt;\n        &lt;div&gt;Cliquez sur un \u00e9l\u00e9ment pour le personnaliser&lt;\/div&gt;\n        &lt;div class=\"color-palette\"&gt;\n            &lt;div class=\"color-swatch\" style=\"background: #ff6b6b;\" onclick=\"applyColor(0xff6b6b)\"&gt;&lt;\/div&gt;\n            &lt;div class=\"color-swatch\" style=\"background: #4ecdc4;\" onclick=\"applyColor(0x4ecdc4)\"&gt;&lt;\/div&gt;\n            &lt;div class=\"color-swatch\" style=\"background: #45b7d1;\" onclick=\"applyColor(0x45b7d1)\"&gt;&lt;\/div&gt;\n            &lt;div class=\"color-swatch\" style=\"background: #f9ca24;\" onclick=\"applyColor(0xf9ca24)\"&gt;&lt;\/div&gt;\n            &lt;div class=\"color-swatch\" style=\"background: #f0932b;\" onclick=\"applyColor(0xf0932b)\"&gt;&lt;\/div&gt;\n        &lt;\/div&gt;\n        &lt;div id=\"selected-element\"&gt;&lt;\/div&gt;\n    &lt;\/div&gt;\n    \n    &lt;div class=\"instructions\"&gt;\n        &lt;strong&gt;Instructions:&lt;\/strong&gt;&lt;br&gt;\n        \u2022 Clic gauche: s\u00e9lectionner un \u00e9l\u00e9ment&lt;br&gt;\n        \u2022 Clic droit + glisser: d\u00e9placer la vue&lt;br&gt;\n        \u2022 Molette: zoomer\/d\u00e9zoomer&lt;br&gt;\n        \u2022 Clic gauche + glisser: tourner autour\n    &lt;\/div&gt;\n    \n    &lt;script src=\"https:\/\/cdn.jsdelivr.net\/npm\/three@0.150\/build\/three.min.js\"&gt;&lt;\/script&gt;\n    &lt;script src=\"https:\/\/cdn.jsdelivr.net\/npm\/three@0.150\/examples\/js\/controls\/OrbitControls.js\"&gt;&lt;\/script&gt;\n&lt;\/body&gt;\n&lt;\/html&gt;<\/pre>\n<pre class=\"codepen-code\" data-lang=\"javascript\">\/\/ Configuration de base\nconst scene = new THREE.Scene();\nconst camera = new THREE.PerspectiveCamera(75, window.innerWidth \/ window.innerHeight, 0.1, 1000);\nconst renderer = new THREE.WebGLRenderer({ antialias: true });\nrenderer.setSize(window.innerWidth, window.innerHeight);\nrenderer.setClearColor(0x87CEEB);\nrenderer.shadowMap.enabled = true;\nrenderer.shadowMap.type = THREE.PCFSoftShadowMap;\ndocument.body.appendChild(renderer.domElement);\n\n\/\/ Contr\u00f4les OrbitControls\nconst controls = new THREE.OrbitControls(camera, renderer.domElement);\ncontrols.enableDamping = true;\ncontrols.dampingFactor = 0.05;\n\n\/\/ \u00c9clairage\nconst ambientLight = new THREE.AmbientLight(0xffffff, 0.6);\nscene.add(ambientLight);\n\nconst directionalLight = new THREE.DirectionalLight(0xffffff, 0.8);\ndirectionalLight.position.set(10, 10, 5);\ndirectionalLight.castShadow = true;\nscene.add(directionalLight);\n\n\/\/ Variables pour l'interactivit\u00e9\nconst raycaster = new THREE.Raycaster();\nconst mouse = new THREE.Vector2();\nlet selectedObject = null;\nconst interactiveObjects = [];\n\n\/\/ Construction de la maison modulaire\nconst houseGroup = new THREE.Group();\n\n\/\/ Murs\nconst wallsGeometry = new THREE.BoxGeometry(6, 4, 6);\nconst wallsMaterial = new THREE.MeshStandardMaterial({ color: 0xDEB887 });\nconst walls = new THREE.Mesh(wallsGeometry, wallsMaterial);\nwalls.position.y = 2;\nwalls.userData = { name: \"Murs\", type: \"walls\" };\nwalls.castShadow = true;\nwalls.receiveShadow = true;\ninteractiveObjects.push(walls);\nhouseGroup.add(walls);\n\n\/\/ Toit\nconst roofGeometry = new THREE.ConeGeometry(4.5, 3, 8);\nconst roofMaterial = new THREE.MeshStandardMaterial({ color: 0x8B4513 });\nconst roof = new THREE.Mesh(roofGeometry, roofMaterial);\nroof.position.y = 6.5;\nroof.userData = { name: \"Toit\", type: \"roof\" };\nroof.castShadow = true;\ninteractiveObjects.push(roof);\nhouseGroup.add(roof);\n\n\/\/ Porte\nconst doorGeometry = new THREE.BoxGeometry(1.5, 3, 0.2);\nconst doorMaterial = new THREE.MeshStandardMaterial({ color: 0x654321 });\nconst door = new THREE.Mesh(doorGeometry, doorMaterial);\ndoor.position.set(0, 1.5, 3.1);\ndoor.userData = { name: \"Porte\", type: \"door\" };\ndoor.castShadow = true;\ninteractiveObjects.push(door);\nhouseGroup.add(door);\n\n\/\/ Fen\u00eatres\nconst windowGeometry = new THREE.BoxGeometry(1.2, 1.2, 0.1);\nconst windowMaterial = new THREE.MeshStandardMaterial({ color: 0x87CEEB });\n\n\/\/ Fen\u00eatre gauche\nconst windowLeft = new THREE.Mesh(windowGeometry, windowMaterial.clone());\nwindowLeft.position.set(-1.5, 2.5, 3.05);\nwindowLeft.userData = { name: \"Fen\u00eatre gauche\", type: \"window\" };\ninteractiveObjects.push(windowLeft);\nhouseGroup.add(windowLeft);\n\n\/\/ Fen\u00eatre droite\nconst windowRight = new THREE.Mesh(windowGeometry, windowMaterial.clone());\nwindowRight.position.set(1.5, 2.5, 3.05);\nwindowRight.userData = { name: \"Fen\u00eatre droite\", type: \"window\" };\ninteractiveObjects.push(windowRight);\nhouseGroup.add(windowRight);\n\n\/\/ Sol\nconst groundGeometry = new THREE.PlaneGeometry(20, 20);\nconst groundMaterial = new THREE.MeshStandardMaterial({ color: 0x228B22 });\nconst ground = new THREE.Mesh(groundGeometry, groundMaterial);\nground.rotation.x = -Math.PI \/ 2;\nground.receiveShadow = true;\nground.userData = { name: \"Pelouse\", type: \"ground\" };\ninteractiveObjects.push(ground);\nscene.add(ground);\n\nscene.add(houseGroup);\n\n\/\/ Position de la cam\u00e9ra\ncamera.position.set(10, 8, 10);\ncontrols.target.set(0, 3, 0);\n\n\/\/ Gestion des clics\nfunction onMouseClick(event) {\n    \/\/ Calcul des coordonn\u00e9es de la souris normalis\u00e9es\n    mouse.x = (event.clientX \/ window.innerWidth) * 2 - 1;\n    mouse.y = -(event.clientY \/ window.innerHeight) * 2 + 1;\n\n    \/\/ Lancement du rayon\n    raycaster.setFromCamera(mouse, camera);\n    const intersects = raycaster.intersectObjects(interactiveObjects);\n\n    if (intersects.length > 0) {\n        const clickedObject = intersects[0].object;\n        \n        \/\/ D\u00e9s\u00e9lection de l'objet pr\u00e9c\u00e9dent\n        if (selectedObject && selectedObject !== clickedObject) {\n            selectedObject.material.emissive.setHex(0x000000);\n        }\n        \n        \/\/ S\u00e9lection du nouvel objet\n        selectedObject = clickedObject;\n        selectedObject.material.emissive.setHex(0x444444);\n        \n        \/\/ Mise \u00e0 jour de l'interface\n        document.getElementById('selected-element').innerHTML = \n            `&lt;div class=\"selected-info\"&gt;&lt;strong&gt;S\u00e9lectionn\u00e9:&lt;\/strong&gt; ${selectedObject.userData.name}&lt;\/div&gt;`;\n    }\n}\n\n\/\/ Fonction pour appliquer une couleur\nfunction applyColor(color) {\n    if (selectedObject) {\n        selectedObject.material.color.setHex(color);\n    }\n}\n\n\/\/ \u00c9couteurs d'\u00e9v\u00e9nements\nrenderer.domElement.addEventListener('click', onMouseClick, false);\n\n\/\/ Gestion du redimensionnement\nwindow.addEventListener('resize', () => {\n    camera.aspect = window.innerWidth \/ window.innerHeight;\n    camera.updateProjectionMatrix();\n    renderer.setSize(window.innerWidth, window.innerHeight);\n});\n\n\/\/ Boucle d'animation\nfunction animate() {\n    requestAnimationFrame(animate);\n    \n    controls.update();\n    renderer.render(scene, camera);\n}\n\nanimate();<\/pre>\n<\/div>\n<\/div>\n<div class=\"monaco-sandbox\" data-block-id=\"exercise-5\">\n<div class=\"monaco-header\">\n<div class=\"monaco-tabs\">\n<button class=\"monaco-tab active\" data-lang=\"html\">HTML<\/button><br \/>\n<button class=\"monaco-tab\" data-lang=\"javascript\">JS (3D)<\/button>\n<\/div>\n<div class=\"monaco-actions\">\n<button class=\"monaco-btn monaco-btn-run\">\u25b6 Ex\u00e9cuter<\/button><br \/>\n<button class=\"monaco-btn monaco-btn-reset\">\u21ba Reset<\/button>\n<\/div>\n<\/div>\n<div class=\"monaco-container\">\n<div class=\"monaco-editor-wrapper\">\n<div class=\"monaco-editor-pane active\" data-lang=\"html\"><\/div>\n<div class=\"monaco-editor-pane\" data-lang=\"javascript\"><\/div>\n<\/div>\n<div class=\"monaco-preview-wrapper\">\n<div class=\"monaco-preview-header\">Result<\/div>\n<\/div>\n<\/div>\n<div class=\"monaco-status\">\n<span class=\"monaco-status-left\">\u25cf Pr\u00eat<\/span><br \/>\n<span class=\"monaco-status-right\">Monaco Editor v0.45<\/span>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n<h2>R\u00e9capitulatif<\/h2>\n<div class=\"tuto-recap\" style=\"background: #f5f5f5; border-left: 4px solid #9c27b0; padding: 16px 20px; border-radius: 0 8px 8px 0;\">\n<h3 style=\"color: #9c27b0; margin: 0 0 12px 0; font-size: 16px;\">Points essentiels \u00e0 retenir<\/h3>\n<ul style=\"margin: 0; padding-left: 20px; color: #333;\">\n<li><strong>Three.js simplifie la 3D web<\/strong> : Cette biblioth\u00e8que traduit le JavaScript simple en WebGL complexe pour cr\u00e9er des exp\u00e9riences 3D accessibles<\/li>\n<li><strong>Trinit\u00e9 Scene-Camera-Renderer<\/strong> : Ces trois composants forment la base obligatoire de toute cr\u00e9ation Three.js<\/li>\n<li><strong>G\u00e9om\u00e9tries + Mat\u00e9riaux = Mesh<\/strong> : La combinaison de formes 3D et d&rsquo;apparences de surface cr\u00e9e les objets visibles<\/li>\n<li><strong>L&rsquo;\u00e9clairage d\u00e9finit l&rsquo;atmosph\u00e8re<\/strong> : Combiner plusieurs sources lumineuses cr\u00e9e des ambiances r\u00e9alistes et \u00e9motionnellement engageantes<\/li>\n<li><strong>Interactivit\u00e9 avec OrbitControls et Raycasting<\/strong> : Navigation libre et interactions pr\u00e9cises transforment une d\u00e9monstration en exp\u00e9rience immersive<\/li>\n<\/ul>\n<\/div>\n<h2>Sources<\/h2>\n<div class=\"sources-box\" style=\"background: linear-gradient(135deg, #f8fafc 0%, #e2e8f0 100%); border: 1px solid #cbd5e1; border-radius: 12px; padding: 16px; margin-bottom: 24px;\">\n<p style=\"color: #64748b; margin: 0 0 12px 0; font-size: 13px;\">Pour approfondir vos connaissances :<\/p>\n<ul style=\"margin: 0; padding-left: 0; list-style: none;\">\n<li style=\"margin-bottom: 8px;\">\n<a href=\"#\" style=\"display: flex; align-items: center; gap: 10px; padding: 10px 14px; background: white; border-radius: 8px; text-decoration: none; color: #1e293b; border: 1px solid #e2e8f0;\"><br \/>\n<span style=\"color: #94a3b8;\">\ud83d\udd17<\/span><br \/>\n<span style=\"flex: 1; font-weight: 500; color: #0f172a;\">Documentation officielle Three.js<\/span><br \/>\n<span style=\"color: #94a3b8;\">\u2192<\/span><br \/>\n<\/a>\n<\/li>\n<li style=\"margin-bottom: 0;\">\n<a href=\"#\" style=\"display: flex; align-items: center; gap: 10px; padding: 10px 14px; background: white; border-radius: 8px; text-decoration: none; color: #1e293b; border: 1px solid #e2e8f0;\"><br \/>\n<span style=\"color: #94a3b8;\">\ud83d\udd17<\/span><br \/>\n<span style=\"flex: 1; font-weight: 500; color: #0f172a;\">Three.js Journey &#8211; Tutoriels avanc\u00e9s<\/span><br \/>\n<span style=\"color: #94a3b8;\">\u2192<\/span><br \/>\n<\/a>\n<\/li>\n<\/ul>\n<\/div>\n<h2>Validez vos connaissances<\/h2>\n<p>Testez votre compr\u00e9hension avec ce quiz de 10 questions :<\/p>\n<div id=\"quiz-block-1\" class=\"quiz-container\" data-quiz-json=\"https:\/\/lmspro.fr\/wp-content\/plugins\/generate-article-endpoint\/quiz-data\/quiz-premiers-pas-avec-three-js.json\" aria-label=\"Interactive Quiz\"><div class=\"quiz-loading\" role=\"status\" aria-live=\"polite\"><span class=\"quiz-sr-only\">Loading quiz...<\/span><\/div><\/div>\n","protected":false},"excerpt":{"rendered":"<p>Premiers pas avec Three.js Three.js est une biblioth\u00e8que JavaScript r\u00e9volutionnaire qui permet de cr\u00e9er facilement des graphiques 3D dans le navigateur web. Cette fiche vous accompagne dans la d\u00e9couverte de cette technologie passionnante \u00e0 travers une s\u00e9rie d&rsquo;exemples graphiques et interactifs adapt\u00e9s aux d\u00e9butants. Module : Module 6 : Module Bonus Niveau : D\u00e9butant Dur\u00e9e &#8230; <a href=\"https:\/\/lmspro.fr\/en\/premiers-pas-avec-three-js-2\/\" class=\"more-link\">Read More<span class=\"screen-reader-text\"> \u00ab\u00a0premiers pas avec three js\u00a0\u00bb<\/span> &raquo;<\/a><\/p>","protected":false},"author":1,"featured_media":647,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[183],"tags":[185,5],"class_list":["post-646","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-module-bonus","tag-bonus","tag-design"],"_links":{"self":[{"href":"https:\/\/lmspro.fr\/en\/wp-json\/wp\/v2\/posts\/646","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/lmspro.fr\/en\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/lmspro.fr\/en\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/lmspro.fr\/en\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/lmspro.fr\/en\/wp-json\/wp\/v2\/comments?post=646"}],"version-history":[{"count":0,"href":"https:\/\/lmspro.fr\/en\/wp-json\/wp\/v2\/posts\/646\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/lmspro.fr\/en\/wp-json\/wp\/v2\/media\/647"}],"wp:attachment":[{"href":"https:\/\/lmspro.fr\/en\/wp-json\/wp\/v2\/media?parent=646"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/lmspro.fr\/en\/wp-json\/wp\/v2\/categories?post=646"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/lmspro.fr\/en\/wp-json\/wp\/v2\/tags?post=646"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}