﻿{"id":644,"date":"2026-02-28T19:08:52","date_gmt":"2026-02-28T18:08:52","guid":{"rendered":"https:\/\/lmspro.fr\/premiers-pas-avec-three-js\/"},"modified":"2026-02-28T19:08:52","modified_gmt":"2026-02-28T18:08:52","slug":"premiers-pas-avec-three-js","status":"publish","type":"post","link":"https:\/\/lmspro.fr\/en\/premiers-pas-avec-three-js\/","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 d\u00e9mocratise la cr\u00e9ation d&rsquo;exp\u00e9riences 3D interactives dans le navigateur. \u00c0 travers une s\u00e9rie d&rsquo;exemples graphiques progressifs, d\u00e9couvrez comment donner vie \u00e0 vos projets architecturaux et cr\u00e9er des visualisations immersives qui captivent vos utilisateurs.<\/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 navigateur<\/li>\n<li>Cr\u00e9er une sc\u00e8ne 3D basique avec des objets g\u00e9om\u00e9triques simples<\/li>\n<li>Ma\u00eetriser l&rsquo;ajout d&rsquo;\u00e9clairage et de mat\u00e9riaux r\u00e9alistes<\/li>\n<li>Impl\u00e9menter des interactions utilisateur et des animations fluides<\/li>\n<li>D\u00e9velopper des visualisations architecturales interactives<\/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 qui simplifie \u00e9norm\u00e9ment la cr\u00e9ation d&rsquo;applications 3D dans le navigateur web. Imaginez que vous vouliez construire une maison : sans Three.js, vous devriez fabriquer chaque brique \u00e0 la main (c&rsquo;est ce qu&rsquo;on appelle WebGL natif), tandis qu&rsquo;avec Three.js, vous disposez d\u00e9j\u00e0 de briques pr\u00eates \u00e0 l&#8217;emploi et d&rsquo;outils pour les assembler facilement.<\/p>\n<h4>Les trois piliers fondamentaux<\/h4>\n<p>Toute application Three.js repose sur trois \u00e9l\u00e9ments essentiels, comme les trois pieds d&rsquo;un tabouret : la <strong>sc\u00e8ne<\/strong> (l&rsquo;espace 3D o\u00f9 tout se passe), la <strong>cam\u00e9ra<\/strong> (votre point de vue sur cette sc\u00e8ne), et le <strong>renderer<\/strong> (le moteur qui dessine tout \u00e0 l&rsquo;\u00e9cran). Sans l&rsquo;un de ces \u00e9l\u00e9ments, votre application 3D ne peut pas fonctionner.<\/p>\n<div class=\"info-box\">\n<p><strong>Point cl\u00e9<\/strong> : Three.js utilise WebGL en arri\u00e8re-plan, mais vous cache toute la complexit\u00e9 technique pour vous permettre de vous concentrer sur la cr\u00e9ativit\u00e9.<\/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 une biblioth\u00e8que qui simplifie la 3D web en s&rsquo;appuyant sur trois \u00e9l\u00e9ments essentiels : sc\u00e8ne, cam\u00e9ra et renderer.<\/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 : Premi\u00e8re sc\u00e8ne 3D<\/h4>\n<p style=\"margin: 0; color: #333; font-size: 14px;\">Cr\u00e9ez votre premi\u00e8re sc\u00e8ne 3D avec un cube color\u00e9 qui tourne lentement sur lui-m\u00eame.<\/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;script&gt;\n        \/\/ Le code JavaScript sera ici\n    &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, de la cam\u00e9ra et du renderer\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 });\n\n\/\/ Configuration du renderer\nrenderer.setSize(window.innerWidth, window.innerHeight);\nrenderer.setClearColor(0x2c3e50);\ndocument.body.appendChild(renderer.domElement);\n\n\/\/ Cr\u00e9ation d'un cube\nconst geometry = new THREE.BoxGeometry(2, 2, 2);\nconst material = new THREE.MeshBasicMaterial({ color: 0x3498db });\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\/\/ Lancement 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> G\u00e9om\u00e9tries et formes 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>Les g\u00e9om\u00e9tries de base<\/h4>\n<p>Dans Three.js, une g\u00e9om\u00e9trie d\u00e9finit la forme d&rsquo;un objet 3D, comme le moule d\u00e9finit la forme d&rsquo;un g\u00e2teau. Three.js propose une riche collection de g\u00e9om\u00e9tries pr\u00eates \u00e0 l&#8217;emploi : des formes simples comme les cubes (BoxGeometry) et les sph\u00e8res (SphereGeometry), jusqu&rsquo;aux formes plus complexes comme les tores ou les cylindres. Chaque g\u00e9om\u00e9trie peut \u00eatre personnalis\u00e9e avec des param\u00e8tres sp\u00e9cifiques.<\/p>\n<h4>Applications en architecture<\/h4>\n<p>Pour un architecte ou un designer, ces g\u00e9om\u00e9tries sont des outils pr\u00e9cieux. Un BoxGeometry peut repr\u00e9senter un b\u00e2timent ou une pi\u00e8ce, un CylinderGeometry peut mod\u00e9liser une colonne ou un pilier, tandis qu&rsquo;un PlaneGeometry est parfait pour cr\u00e9er des murs, des sols ou des toitures plates. La combinaison de plusieurs g\u00e9om\u00e9tries permet de construire des structures architecturales complexes.<\/p>\n<div class=\"info-box\">\n<p><strong>Point cl\u00e9<\/strong> : Une g\u00e9om\u00e9trie seule n&rsquo;est pas visible ; elle doit \u00eatre associ\u00e9e \u00e0 un mat\u00e9riau pour cr\u00e9er un \u00ab\u00a0Mesh\u00a0\u00bb (objet 3D complet).<\/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;\">Les g\u00e9om\u00e9tries d\u00e9finissent les formes 3D et doivent \u00eatre combin\u00e9es avec des mat\u00e9riaux pour devenir des objets visibles dans la 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 : Composition architecturale<\/h4>\n<p style=\"margin: 0; color: #333; font-size: 14px;\">Cr\u00e9ez une composition avec diff\u00e9rentes formes g\u00e9om\u00e9triques pour repr\u00e9senter un b\u00e2timent moderne simple.<\/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;Composition architecturale&lt;\/title&gt;\n    &lt;style&gt;\n        body { margin: 0; padding: 0; overflow: hidden; background: #87CEEB; }\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;script&gt;\n        \/\/ Le code JavaScript sera ici\n    &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 });\n\nrenderer.setSize(window.innerWidth, window.innerHeight);\nrenderer.setClearColor(0x87CEEB); \/\/ Bleu ciel\ndocument.body.appendChild(renderer.domElement);\n\n\/\/ Groupe pour contenir le b\u00e2timent\nconst building = new THREE.Group();\n\n\/\/ Sol\/fondation (plan rectangulaire)\nconst groundGeometry = new THREE.PlaneGeometry(8, 6);\nconst groundMaterial = new THREE.MeshBasicMaterial({ color: 0x8FBC8F, side: THREE.DoubleSide });\nconst ground = new THREE.Mesh(groundGeometry, groundMaterial);\nground.rotation.x = -Math.PI \/ 2;\nground.position.y = -2;\nbuilding.add(ground);\n\n\/\/ Corps principal du b\u00e2timent (cube)\nconst mainGeometry = new THREE.BoxGeometry(4, 3, 3);\nconst mainMaterial = new THREE.MeshBasicMaterial({ color: 0xDEB887 });\nconst mainBuilding = new THREE.Mesh(mainGeometry, mainMaterial);\nmainBuilding.position.y = 0;\nbuilding.add(mainBuilding);\n\n\/\/ Tour\/extension (cylindre)\nconst towerGeometry = new THREE.CylinderGeometry(0.8, 0.8, 4, 8);\nconst towerMaterial = new THREE.MeshBasicMaterial({ color: 0x696969 });\nconst tower = new THREE.Mesh(towerGeometry, towerMaterial);\ntower.position.set(2.5, 0.5, 0);\nbuilding.add(tower);\n\n\/\/ Toit (c\u00f4ne)\nconst roofGeometry = new THREE.ConeGeometry(1.2, 1.5, 8);\nconst roofMaterial = new THREE.MeshBasicMaterial({ color: 0x8B4513 });\nconst roof = new THREE.Mesh(roofGeometry, roofMaterial);\nroof.position.set(2.5, 2.75, 0);\nbuilding.add(roof);\n\n\/\/ Ajout du b\u00e2timent \u00e0 la sc\u00e8ne\nscene.add(building);\n\n\/\/ Position de la cam\u00e9ra\ncamera.position.set(6, 4, 8);\ncamera.lookAt(0, 0, 0);\n\n\/\/ Animation douce\nfunction animate() {\n    requestAnimationFrame(animate);\n    \n    \/\/ Rotation lente du b\u00e2timent\n    building.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-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> Mat\u00e9riaux et \u00e9clairage<\/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>Types de mat\u00e9riaux<\/h4>\n<p>Les mat\u00e9riaux dans Three.js d\u00e9finissent l&rsquo;apparence visuelle des objets, comme la peinture d\u00e9finit l&rsquo;aspect d&rsquo;un mur. Il existe plusieurs types principaux : MeshBasicMaterial (couleur unie, non affect\u00e9 par l&rsquo;\u00e9clairage), MeshLambertMaterial (surface mate qui r\u00e9agit \u00e0 la lumi\u00e8re), MeshPhongMaterial (surface brillante avec reflets), et MeshStandardMaterial (rendu r\u00e9aliste bas\u00e9 sur la physique). Chaque mat\u00e9riau a ses propres propri\u00e9t\u00e9s et cas d&rsquo;usage.<\/p>\n<h4>L&rsquo;importance de l&rsquo;\u00e9clairage<\/h4>\n<p>L&rsquo;\u00e9clairage transforme compl\u00e8tement l&rsquo;atmosph\u00e8re d&rsquo;une sc\u00e8ne 3D, exactement comme l&rsquo;\u00e9clairage naturel ou artificiel transforme un espace architectural. Three.js propose diff\u00e9rents types de lumi\u00e8res : AmbientLight (\u00e9clairage global uniforme), DirectionalLight (comme le soleil, rayons parall\u00e8les), PointLight (comme une ampoule, rayonne dans toutes les directions), et SpotLight (projecteur directionnel). Sans \u00e9clairage appropri\u00e9, m\u00eame les plus beaux mat\u00e9riaux perdent leur impact visuel.<\/p>\n<div class=\"info-box\">\n<p><strong>Point cl\u00e9<\/strong> : Les mat\u00e9riaux comme MeshBasicMaterial ne r\u00e9agissent pas \u00e0 l&rsquo;\u00e9clairage, tandis que MeshLambertMaterial et MeshPhongMaterial en ont besoin pour r\u00e9v\u00e9ler leurs propri\u00e9t\u00e9s.<\/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;\">Les mat\u00e9riaux d\u00e9finissent l&rsquo;apparence des objets et certains n\u00e9cessitent un \u00e9clairage appropri\u00e9 pour r\u00e9v\u00e9ler leurs propri\u00e9t\u00e9s visuelles.<\/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 : \u00c9clairage architectural<\/h4>\n<p style=\"margin: 0; color: #333; font-size: 14px;\">Cr\u00e9ez une sc\u00e8ne avec diff\u00e9rents mat\u00e9riaux et sources lumineuses pour simuler l&rsquo;\u00e9clairage d&rsquo;un espace architectural.<\/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;\u00c9clairage architectural&lt;\/title&gt;\n    &lt;style&gt;\n        body { margin: 0; padding: 0; overflow: hidden; background: #1a1a2e; }\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;script&gt;\n        \/\/ Le code JavaScript sera ici\n    &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 });\n\nrenderer.setSize(window.innerWidth, window.innerHeight);\nrenderer.setClearColor(0x1a1a2e);\nrenderer.shadowMap.enabled = true;\nrenderer.shadowMap.type = THREE.PCFSoftShadowMap;\ndocument.body.appendChild(renderer.domElement);\n\n\/\/ \u00c9clairage ambiant (\u00e9clairage global doux)\nconst ambientLight = new THREE.AmbientLight(0x404040, 0.3);\nscene.add(ambientLight);\n\n\/\/ Lumi\u00e8re directionnelle (simule le soleil)\nconst directionalLight = new THREE.DirectionalLight(0xffffff, 0.8);\ndirectionalLight.position.set(5, 10, 5);\ndirectionalLight.castShadow = true;\ndirectionalLight.shadow.mapSize.width = 2048;\ndirectionalLight.shadow.mapSize.height = 2048;\nscene.add(directionalLight);\n\n\/\/ Lumi\u00e8re ponctuelle (lampe d'int\u00e9rieur)\nconst pointLight = new THREE.PointLight(0xffaa00, 1, 100);\npointLight.position.set(-3, 3, 2);\nscene.add(pointLight);\n\n\/\/ Sol avec mat\u00e9riau r\u00e9fl\u00e9chissant\nconst floorGeometry = new THREE.PlaneGeometry(20, 20);\nconst floorMaterial = new THREE.MeshLambertMaterial({ color: 0x808080 });\nconst floor = new THREE.Mesh(floorGeometry, floorMaterial);\nfloor.rotation.x = -Math.PI \/ 2;\nfloor.position.y = -2;\nfloor.receiveShadow = true;\nscene.add(floor);\n\n\/\/ Mur avec mat\u00e9riau mat\nconst wallGeometry = new THREE.PlaneGeometry(15, 8);\nconst wallMaterial = new THREE.MeshLambertMaterial({ color: 0xe6e6e6 });\nconst wall = new THREE.Mesh(wallGeometry, wallMaterial);\nwall.position.set(0, 2, -7);\nwall.receiveShadow = true;\nscene.add(wall);\n\n\/\/ Colonne avec mat\u00e9riau brillant\nconst columnGeometry = new THREE.CylinderGeometry(0.5, 0.5, 6, 16);\nconst columnMaterial = new THREE.MeshPhongMaterial({ \n    color: 0xffffff, \n    shininess: 100 \n});\nconst column = new THREE.Mesh(columnGeometry, columnMaterial);\ncolumn.position.set(3, 1, 0);\ncolumn.castShadow = true;\ncolumn.receiveShadow = true;\nscene.add(column);\n\n\/\/ Objet avec mat\u00e9riau standard (PBR)\nconst sphereGeometry = new THREE.SphereGeometry(1, 32, 16);\nconst sphereMaterial = new THREE.MeshStandardMaterial({ \n    color: 0x3498db,\n    metalness: 0.7,\n    roughness: 0.2 \n});\nconst sphere = new THREE.Mesh(sphereGeometry, sphereMaterial);\nsphere.position.set(-2, 0, 2);\nsphere.castShadow = true;\nsphere.receiveShadow = true;\nscene.add(sphere);\n\n\/\/ Position de la cam\u00e9ra\ncamera.position.set(8, 5, 10);\ncamera.lookAt(0, 0, 0);\n\n\/\/ Animation\nfunction animate() {\n    requestAnimationFrame(animate);\n    \n    \/\/ Animation de la lumi\u00e8re ponctuelle\n    const time = Date.now() * 0.001;\n    pointLight.position.x = Math.cos(time) * 4;\n    pointLight.position.z = Math.sin(time) * 4;\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> Animations et interactions<\/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>Principe des animations<\/h4>\n<p>Les animations dans Three.js fonctionnent selon le m\u00eame principe que le cin\u00e9ma : en affichant une succession rapide d&rsquo;images l\u00e9g\u00e8rement diff\u00e9rentes, on cr\u00e9e l&rsquo;illusion du mouvement. La fonction requestAnimationFrame est votre projecteur personnel, elle s&rsquo;assure que chaque \u00ab\u00a0image\u00a0\u00bb (frame) est affich\u00e9e au bon moment, g\u00e9n\u00e9ralement 60 fois par seconde. Vous pouvez animer n&rsquo;importe quelle propri\u00e9t\u00e9 d&rsquo;un objet : position, rotation, \u00e9chelle, couleur, ou m\u00eame la g\u00e9om\u00e9trie elle-m\u00eame.<\/p>\n<h4>Interactivit\u00e9 avec l&rsquo;utilisateur<\/h4>\n<p>Rendre vos sc\u00e8nes interactives transforme une simple visualisation en exp\u00e9rience immersive. Three.js permet de d\u00e9tecter les clics de souris sur les objets 3D gr\u00e2ce au syst\u00e8me de \u00ab\u00a0raycasting\u00a0\u00bb (lancer de rayons), d&rsquo;\u00e9couter les mouvements de souris pour contr\u00f4ler la cam\u00e9ra, ou de r\u00e9agir aux touches du clavier. Ces interactions sont essentielles pour cr\u00e9er des visites virtuelles d&rsquo;architectures, des configurateurs de produits, ou des pr\u00e9sentations interactives.<\/p>\n<div class=\"info-box\">\n<p><strong>Point cl\u00e9<\/strong> : Utilisez requestAnimationFrame plut\u00f4t que setInterval pour des animations fluides synchronis\u00e9es avec le taux de rafra\u00eechissement de l&rsquo;\u00e9cran.<\/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;\">Les animations utilisent requestAnimationFrame pour cr\u00e9er des mouvements fluides, tandis que l&rsquo;interactivit\u00e9 repose sur la d\u00e9tection d&rsquo;\u00e9v\u00e9nements et le raycasting.<\/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 : Visite interactive<\/h4>\n<p style=\"margin: 0; color: #333; font-size: 14px;\">Cr\u00e9ez une sc\u00e8ne architecturale avec des objets anim\u00e9s et des interactions au clic pour simuler une visite virtuelle.<\/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;Visite interactive&lt;\/title&gt;\n    &lt;style&gt;\n        body { margin: 0; padding: 0; overflow: hidden; background: #000; }\n        canvas { display: block; cursor: crosshair; }\n        #info {\n            position: absolute;\n            top: 10px;\n            left: 10px;\n            color: white;\n            font-family: Arial;\n            background: rgba(0,0,0,0.7);\n            padding: 10px;\n            border-radius: 5px;\n        }\n    &lt;\/style&gt;\n&lt;\/head&gt;\n&lt;body&gt;\n    &lt;div id=\"info\"&gt;Cliquez sur les objets pour les activer !&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;script&gt;\n        \/\/ Le code JavaScript sera ici\n    &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 });\n\nrenderer.setSize(window.innerWidth, window.innerHeight);\nrenderer.setClearColor(0x000020);\ndocument.body.appendChild(renderer.domElement);\n\n\/\/ \u00c9clairage\nconst ambientLight = new THREE.AmbientLight(0x404040, 0.4);\nscene.add(ambientLight);\n\nconst directionalLight = new THREE.DirectionalLight(0xffffff, 0.8);\ndirectionalLight.position.set(10, 10, 5);\nscene.add(directionalLight);\n\n\/\/ Variables pour l'interaction\nconst raycaster = new THREE.Raycaster();\nconst mouse = new THREE.Vector2();\nconst interactiveObjects = [];\n\n\/\/ Cr\u00e9ation d'objets interactifs\nconst objects = [];\n\n\/\/ Porte (rectangle qui s'ouvre)\nconst doorGeometry = new THREE.BoxGeometry(2, 4, 0.2);\nconst doorMaterial = new THREE.MeshLambertMaterial({ color: 0x8B4513 });\nconst door = new THREE.Mesh(doorGeometry, doorMaterial);\ndoor.position.set(-4, 0, 0);\ndoor.userData = { type: 'door', isOpen: false, originalRotation: 0 };\nscene.add(door);\ninteractiveObjects.push(door);\nobjects.push(door);\n\n\/\/ Fen\u00eatre (change de couleur)\nconst windowGeometry = new THREE.BoxGeometry(3, 2, 0.1);\nconst windowMaterial = new THREE.MeshLambertMaterial({ color: 0x87CEEB });\nconst window = new THREE.Mesh(windowGeometry, windowMaterial);\nwindow.position.set(0, 2, -5);\nwindow.userData = { type: 'window', isLit: false };\nscene.add(window);\ninteractiveObjects.push(window);\nobjects.push(window);\n\n\/\/ Lampe (sph\u00e8re qui clignote)\nconst lampGeometry = new THREE.SphereGeometry(0.5, 16, 8);\nconst lampMaterial = new THREE.MeshPhongMaterial({ \n    color: 0xffff00,\n    emissive: 0x222200\n});\nconst lamp = new THREE.Mesh(lampGeometry, lampMaterial);\nlamp.position.set(4, 3, 2);\nlamp.userData = { type: 'lamp', isOn: false, originalEmissive: 0x222200 };\nscene.add(lamp);\ninteractiveObjects.push(lamp);\nobjects.push(lamp);\n\n\/\/ Sol\nconst floorGeometry = new THREE.PlaneGeometry(20, 20);\nconst floorMaterial = new THREE.MeshLambertMaterial({ color: 0x666666 });\nconst floor = new THREE.Mesh(floorGeometry, floorMaterial);\nfloor.rotation.x = -Math.PI \/ 2;\nfloor.position.y = -2;\nscene.add(floor);\n\n\/\/ Position de la cam\u00e9ra\ncamera.position.set(0, 5, 10);\ncamera.lookAt(0, 0, 0);\n\n\/\/ Gestionnaire de clic\nfunction onMouseClick(event) {\n    mouse.x = (event.clientX \/ window.innerWidth) * 2 - 1;\n    mouse.y = -(event.clientY \/ window.innerHeight) * 2 + 1;\n\n    raycaster.setFromCamera(mouse, camera);\n    const intersects = raycaster.intersectObjects(interactiveObjects);\n\n    if (intersects.length > 0) {\n        const object = intersects[0].object;\n        \n        switch(object.userData.type) {\n            case 'door':\n                object.userData.isOpen = !object.userData.isOpen;\n                break;\n            case 'window':\n                object.userData.isLit = !object.userData.isLit;\n                object.material.color.setHex(object.userData.isLit ? 0xFFFFAA : 0x87CEEB);\n                break;\n            case 'lamp':\n                object.userData.isOn = !object.userData.isOn;\n                object.material.emissive.setHex(object.userData.isOn ? 0xffff00 : 0x222200);\n                break;\n        }\n    }\n}\n\nwindow.addEventListener('click', onMouseClick, false);\n\n\/\/ Variables d'animation\nlet time = 0;\n\n\/\/ Boucle d'animation\nfunction animate() {\n    requestAnimationFrame(animate);\n    time += 0.01;\n\n    \/\/ Animation de la porte\n    objects.forEach(object => {\n        if (object.userData.type === 'door') {\n            const targetRotation = object.userData.isOpen ? -Math.PI \/ 2 : 0;\n            object.rotation.y += (targetRotation - object.rotation.y) * 0.1;\n        }\n    });\n\n    \/\/ Rotation lente de la cam\u00e9ra\n    camera.position.x = Math.cos(time * 0.1) * 10;\n    camera.position.z = Math.sin(time * 0.1) * 10;\n    camera.lookAt(0, 0, 0);\n\n    renderer.render(scene, camera);\n}\n\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> Projet complet : Visualisation architecturale<\/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>Int\u00e9gration des concepts<\/h4>\n<p>Un projet complet en Three.js combine tous les \u00e9l\u00e9ments que nous avons d\u00e9couverts : g\u00e9om\u00e9tries vari\u00e9es, mat\u00e9riaux r\u00e9alistes, \u00e9clairage soign\u00e9, animations fluides et interactions intuitives. Pour cr\u00e9er une visualisation architecturale convaincante, il faut penser comme un architecte ET comme un d\u00e9veloppeur. Chaque \u00e9l\u00e9ment doit avoir un but : les textures doivent \u00eatre coh\u00e9rentes, l&rsquo;\u00e9clairage doit cr\u00e9er l&rsquo;ambiance d\u00e9sir\u00e9e, et les interactions doivent guider naturellement l&rsquo;utilisateur dans l&rsquo;exploration de l&rsquo;espace.<\/p>\n<h4>Optimisation et performance<\/h4>\n<p>Une visualisation architecturale complexe peut rapidement devenir gourmande en ressources. Il est crucial d&rsquo;optimiser votre sc\u00e8ne : utilisez des g\u00e9om\u00e9tries simples quand c&rsquo;est possible, r\u00e9duisez le nombre de sources lumineuses, optimisez les textures, et employez des techniques comme le \u00ab\u00a0level of detail\u00a0\u00bb (LOD) qui affiche moins de d\u00e9tails pour les objets \u00e9loign\u00e9s. Une exp\u00e9rience fluide \u00e0 60 FPS vaut mieux qu&rsquo;une sc\u00e8ne magnifique mais saccad\u00e9e.<\/p>\n<div class=\"info-box\">\n<p><strong>Point cl\u00e9<\/strong> : Un bon projet Three.js \u00e9quilibre qualit\u00e9 visuelle et performance en optimisant chaque \u00e9l\u00e9ment selon son importance dans l&rsquo;exp\u00e9rience utilisateur.<\/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;\">Un projet complet n\u00e9cessite d&rsquo;int\u00e9grer harmonieusement tous les concepts Three.js tout en optimisant les performances pour une exp\u00e9rience fluide.<\/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 : Maison moderne interactive<\/h4>\n<p style=\"margin: 0; color: #333; font-size: 14px;\">Cr\u00e9ez une visualisation compl\u00e8te d&rsquo;une maison moderne avec \u00e9clairage jour\/nuit, mat\u00e9riaux vari\u00e9s et contr\u00f4les de cam\u00e9ra.<\/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;Maison moderne interactive&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        #controls {\n            position: absolute;\n            top: 10px;\n            right: 10px;\n            background: rgba(0,0,0,0.8);\n            color: white;\n            padding: 15px;\n            border-radius: 8px;\n            min-width: 200px;\n        }\n        .control-group {\n            margin-bottom: 15px;\n        }\n        label {\n            display: block;\n            margin-bottom: 5px;\n            font-size: 12px;\n        }\n        input[type=\"range\"] {\n            width: 100%;\n        }\n        button {\n            background: #3498db;\n            color: white;\n            border: none;\n            padding: 8px 12px;\n            border-radius: 4px;\n            cursor: pointer;\n            margin-right: 5px;\n        }\n        button:hover {\n            background: #2980b9;\n        }\n    &lt;\/style&gt;\n&lt;\/head&gt;\n&lt;body&gt;\n    &lt;div id=\"controls\"&gt;\n        &lt;div class=\"control-group\"&gt;\n            &lt;label&gt;Heure de la journ\u00e9e&lt;\/label&gt;\n            &lt;input type=\"range\" id=\"timeSlider\" min=\"0\" max=\"24\" value=\"12\" step=\"0.1\"&gt;\n            &lt;span id=\"timeDisplay\"&gt;12:00&lt;\/span&gt;\n        &lt;\/div&gt;\n        &lt;div class=\"control-group\"&gt;\n            &lt;button id=\"autoRotate\"&gt;Auto Rotation&lt;\/button&gt;\n            &lt;button id=\"resetView\"&gt;Reset Vue&lt;\/button&gt;\n        &lt;\/div&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;script&gt;\n        \/\/ Le code JavaScript sera ici\n    &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 });\n\nrenderer.setSize(window.innerWidth, window.innerHeight);\nrenderer.shadowMap.enabled = true;\nrenderer.shadowMap.type = THREE.PCFSoftShadowMap;\ndocument.body.appendChild(renderer.domElement);\n\n\/\/ Variables de contr\u00f4le\nlet autoRotateEnabled = false;\nlet currentTime = 12;\n\n\/\/ \u00c9clairage principal (soleil)\nconst sunLight = new THREE.DirectionalLight(0xffffff, 1);\nsunLight.castShadow = true;\nsunLight.shadow.mapSize.width = 2048;\nsunLight.shadow.mapSize.height = 2048;\nsunLight.shadow.camera.near = 0.5;\nsunLight.shadow.camera.far = 50;\nsunLight.shadow.camera.left = -10;\nsunLight.shadow.camera.right = 10;\nsunLight.shadow.camera.top = 10;\nsunLight.shadow.camera.bottom = -10;\nscene.add(sunLight);\n\n\/\/ \u00c9clairage ambiant\nconst ambientLight = new THREE.AmbientLight(0x404040, 0.3);\nscene.add(ambientLight);\n\n\/\/ Cr\u00e9ation de la maison moderne\nconst house = new THREE.Group();\n\n\/\/ Sol\/terrain\nconst groundGeometry = new THREE.PlaneGeometry(30, 30);\nconst groundMaterial = new THREE.MeshLambertMaterial({ color: 0x5d8a3a });\nconst ground = new THREE.Mesh(groundGeometry, groundMaterial);\nground.rotation.x = -Math.PI \/ 2;\nground.receiveShadow = true;\nscene.add(ground);\n\n\/\/ Structure principale\nconst mainStructure = new THREE.BoxGeometry(8, 4, 6);\nconst mainMaterial = new THREE.MeshLambertMaterial({ color: 0xf5f5f5 });\nconst mainBuilding = new THREE.Mesh(mainStructure, mainMaterial);\nmainBuilding.position.set(0, 2, 0);\nmainBuilding.castShadow = true;\nmainBuilding.receiveShadow = true;\nhouse.add(mainBuilding);\n\n\/\/ Toit moderne (plat avec l\u00e9g\u00e8re inclinaison)\nconst roofGeometry = new THREE.BoxGeometry(8.5, 0.3, 6.5);\nconst roofMaterial = new THREE.MeshLambertMaterial({ color: 0x333333 });\nconst roof = new THREE.Mesh(roofGeometry, roofMaterial);\nroof.position.set(0, 4.3, 0);\nroof.castShadow = true;\nhouse.add(roof);\n\n\/\/ Extension lat\u00e9rale\nconst extensionGeometry = new THREE.BoxGeometry(4, 3, 4);\nconst extension = new THREE.Mesh(extensionGeometry, mainMaterial);\nextension.position.set(6, 1.5, 2);\nextension.castShadow = true;\nextension.receiveShadow = true;\nhouse.add(extension);\n\n\/\/ Fen\u00eatres principales\nconst windowGeometry = new THREE.PlaneGeometry(1.5, 2);\nconst windowMaterial = new THREE.MeshPhongMaterial({ \n    color: 0x87ceeb, \n    transparent: true, \n    opacity: 0.7,\n    shininess: 100\n});\n\n\/\/ Fen\u00eatres fa\u00e7ade\nfor(let i = 0; i < 3; i++) {\n    const window = new THREE.Mesh(windowGeometry, windowMaterial);\n    window.position.set(-2.5 + i * 2.5, 2, 3.01);\n    house.add(window);\n}\n\n\/\/ Porte d'entr\u00e9e\nconst doorGeometry = new THREE.PlaneGeometry(1.2, 2.5);\nconst doorMaterial = new THREE.MeshLambertMaterial({ color: 0x4a4a4a });\nconst door = new THREE.Mesh(doorGeometry, doorMaterial);\ndoor.position.set(2, 1.25, 3.01);\nhouse.add(door);\n\n\/\/ Chemin\u00e9e moderne\nconst chimneyGeometry = new THREE.BoxGeometry(1, 2, 1);\nconst chimneyMaterial = new THREE.MeshLambertMaterial({ color: 0x666666 });\nconst chimney = new THREE.Mesh(chimneyGeometry, chimneyMaterial);\nchimney.position.set(-2, 5.5, -1);\nchimney.castShadow = true;\nhouse.add(chimney);\n\n\/\/ \u00c9clairage int\u00e9rieur (fen\u00eatres)\nconst interiorLights = [];\nfor(let i = 0; i < 3; i++) {\n    const light = new THREE.PointLight(0xffaa00, 0, 10);\n    light.position.set(-2.5 + i * 2.5, 2, 2.5);\n    house.add(light);\n    interiorLights.push(light);\n}\n\nscene.add(house);\n\n\/\/ Position initiale de la cam\u00e9ra\ncamera.position.set(15, 8, 15);\ncamera.lookAt(0, 2, 0);\n\n\/\/ Variables pour la rotation automatique\nlet cameraAngle = 0;\nconst cameraRadius = 20;\n\n\/\/ Fonction pour mettre \u00e0 jour l'\u00e9clairage selon l'heure\nfunction updateLighting(timeOfDay) {\n    \/\/ Position du soleil selon l'heure\n    const sunAngle = (timeOfDay - 6) * Math.PI \/ 12; \/\/ 6h = lever, 18h = coucher\n    sunLight.position.set(\n        Math.cos(sunAngle) * 20,\n        Math.sin(sunAngle) * 20,\n        10\n    );\n\n    \/\/ Intensit\u00e9 et couleur selon l'heure\n    let intensity, color, ambientColor;\n    \n    if (timeOfDay >= 6 && timeOfDay <= 18) {\n        \/\/ Jour\n        intensity = Math.max(0.3, Math.sin(sunAngle) * 0.8);\n        color = 0xffffff;\n        ambientColor = 0x404040;\n        \n        \/\/ \u00c9teindre les lumi\u00e8res int\u00e9rieures\n        interiorLights.forEach(light => light.intensity = 0);\n    } else {\n        \/\/ Nuit\n        intensity = 0.1;\n        color = 0x4444ff;\n        ambientColor = 0x222222;\n        \n        \/\/ Allumer les lumi\u00e8res int\u00e9rieures\n        interiorLights.forEach(light => light.intensity = 0.5);\n    }\n\n    sunLight.intensity = intensity;\n    sunLight.color.setHex(color);\n    ambientLight.color.setHex(ambientColor);\n\n    \/\/ Couleur du ciel\n    if (timeOfDay >= 5 && timeOfDay <= 19) {\n        const skyIntensity = Math.max(0.2, Math.sin((timeOfDay - 5) * Math.PI \/ 14));\n        const skyColor = new THREE.Color().setHSL(0.6, 0.8, 0.3 + skyIntensity * 0.4);\n        renderer.setClearColor(skyColor);\n    } else {\n        renderer.setClearColor(0x000011);\n    }\n}\n\n\/\/ Contr\u00f4les\ndocument.getElementById('timeSlider').addEventListener('input', function(e) {\n    currentTime = parseFloat(e.target.value);\n    updateLighting(currentTime);\n    \n    const hours = Math.floor(currentTime);\n    const minutes = Math.floor((currentTime - hours) * 60);\n    document.getElementById('timeDisplay').textContent = \n        `${hours.toString().padStart(2, '0')}:${minutes.toString().padStart(2, '0')}`;\n});\n\ndocument.getElementById('autoRotate').addEventListener('click', function() {\n    autoRotateEnabled = !autoRotateEnabled;\n    this.textContent = autoRotateEnabled ? 'Stop Rotation' : 'Auto Rotation';\n});\n\ndocument.getElementById('resetView').addEventListener('click', function() {\n    camera.position.set(15, 8, 15);\n    camera.lookAt(0, 2, 0);\n    cameraAngle = 0;\n});\n\n\/\/ Contr\u00f4les souris simples\nlet mouseX = 0;\nlet mouseY = 0;\nlet isMouseDown = false;\n\ndocument.addEventListener('mousedown', () => isMouseDown = true);\ndocument.addEventListener('mouseup', () => isMouseDown = false);\ndocument.addEventListener('mousemove', (event) => {\n    if (isMouseDown) {\n        mouseX = (event.clientX \/ window.innerWidth) * 2 - 1;\n        mouseY = -(event.clientY \/ window.innerHeight) * 2 + 1;\n        \n        camera.position.x = mouseX * 20;\n        camera.position.y = 5 + mouseY * 10;\n        camera.lookAt(0, 2, 0);\n    }\n});\n\n\/\/ Initialisation\nupdateLighting(currentTime);\n\n\/\/ Boucle d'animation\nfunction animate() {\n    requestAnimationFrame(animate);\n\n    \/\/ Rotation automatique de la cam\u00e9ra\n    if (autoRotateEnabled) {\n        cameraAngle += 0.005;\n        camera.position.x = Math.cos(cameraAngle) * cameraRadius;\n        camera.position.z = Math.sin(cameraAngle) * cameraRadius;\n        camera.lookAt(0, 2, 0);\n    }\n\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>Les trois piliers<\/strong> : Toute application Three.js repose sur une sc\u00e8ne, une cam\u00e9ra et un renderer<\/li>\n<li><strong>G\u00e9om\u00e9tries modulaires<\/strong> : Les formes de base se combinent pour cr\u00e9er des structures architecturales complexes<\/li>\n<li><strong>Mat\u00e9riaux et \u00e9clairage<\/strong> : L&rsquo;association judicieuse de mat\u00e9riaux et de sources lumineuses cr\u00e9e des rendus r\u00e9alistes<\/li>\n<li><strong>Interactivit\u00e9 fluide<\/strong> : RequestAnimationFrame et le raycasting permettent des animations et interactions naturelles<\/li>\n<li><strong>Optimisation n\u00e9cessaire<\/strong> : \u00c9quilibrer qualit\u00e9 visuelle et performance pour une exp\u00e9rience utilisateur optimale<\/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 interactifs<\/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 d\u00e9mocratise la cr\u00e9ation d&rsquo;exp\u00e9riences 3D interactives dans le navigateur. \u00c0 travers une s\u00e9rie d&rsquo;exemples graphiques progressifs, d\u00e9couvrez comment donner vie \u00e0 vos projets architecturaux et cr\u00e9er des visualisations immersives qui captivent vos utilisateurs. Module : Module 6 : Module Bonus Niveau : D\u00e9butant &#8230; <a href=\"https:\/\/lmspro.fr\/en\/premiers-pas-avec-three-js\/\" 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":645,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[183],"tags":[185,5],"class_list":["post-644","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\/644","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=644"}],"version-history":[{"count":0,"href":"https:\/\/lmspro.fr\/en\/wp-json\/wp\/v2\/posts\/644\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/lmspro.fr\/en\/wp-json\/wp\/v2\/media\/645"}],"wp:attachment":[{"href":"https:\/\/lmspro.fr\/en\/wp-json\/wp\/v2\/media?parent=644"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/lmspro.fr\/en\/wp-json\/wp\/v2\/categories?post=644"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/lmspro.fr\/en\/wp-json\/wp\/v2\/tags?post=644"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}